Move /e2e -> /e2e-tests
Этот коммит содержится в:
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
import {notShowCursor, markAsUnreadShouldBeAbsent} from './helpers';
|
||||
|
||||
describe('Channels', () => {
|
||||
let testUser;
|
||||
let testChannel;
|
||||
let testTeam;
|
||||
let post1;
|
||||
|
||||
before(() => {
|
||||
// # Enable Experimental View Archived Channels
|
||||
cy.apiUpdateConfig({
|
||||
TeamSettings: {
|
||||
ExperimentalViewArchivedChannels: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testUser = user;
|
||||
testTeam = team;
|
||||
|
||||
// # Create a test channel
|
||||
cy.apiCreateChannel(team.id, 'channel-test', 'Channel').then(({channel}) => {
|
||||
testChannel = channel;
|
||||
|
||||
// # Create second user and add him to the team
|
||||
cy.apiCreateUser().then(({user: user2}) => {
|
||||
const otherUser = user2;
|
||||
|
||||
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
|
||||
|
||||
// Another user creates posts in the channel since you can't mark your own posts unread currently
|
||||
cy.postMessageAs({sender: otherUser, message: 'post1', channelId: testChannel.id}).then((p1) => {
|
||||
post1 = p1;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('MM-T263 Mark as Unread post menu option should not be available for archived channels', () => {
|
||||
// # Login as testUser
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
|
||||
// # Click channel header to open channel menu
|
||||
cy.get('#channelHeaderTitle').should('contain', testChannel.display_name).click();
|
||||
|
||||
// * Verify that the menu is opened
|
||||
cy.get('.Menu__content').should('be.visible').within(() => {
|
||||
// # Archive the channel
|
||||
cy.findByText('Archive Channel').should('be.visible').click();
|
||||
});
|
||||
|
||||
// * Verify that the delete/archive channel modal is opened
|
||||
cy.get('#deleteChannelModal').should('be.visible').within(() => {
|
||||
// # Confirm archive
|
||||
cy.findByText('Archive').should('be.visible').click();
|
||||
});
|
||||
|
||||
// * Verify the "Mark as Unread" option is absent in post menu
|
||||
markAsUnreadShouldBeAbsent(post1.id);
|
||||
|
||||
// * Hover on the post with holding alt should show cursor
|
||||
cy.get(`#post_${post1.id}`).trigger('mouseover').type('{alt}', {release: false}).should(notShowCursor);
|
||||
|
||||
// # Mouse click on the post holding alt
|
||||
cy.get(`#post_${post1.id}`).type('{alt}', {release: false}).click();
|
||||
|
||||
// * Verify the post is not marked as unread
|
||||
cy.get('.NotificationSeparator').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
import {beUnread} from '../../../support/assertions';
|
||||
|
||||
import {markAsUnreadFromPost, verifyPostNextToNewMessageSeparator} from './helpers';
|
||||
|
||||
describe('Bot post unread message', () => {
|
||||
let newChannel;
|
||||
let botPost;
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
// # Create and visit new channel
|
||||
cy.apiInitSetup({
|
||||
promoteNewUserAsAdmin: true,
|
||||
loginAfter: true,
|
||||
}).then(({team, channel}) => {
|
||||
testTeam = team;
|
||||
newChannel = channel;
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
});
|
||||
|
||||
// # Create a bot and get userID
|
||||
cy.apiCreateBot().then(({bot}) => {
|
||||
const botUserId = bot.user_id;
|
||||
cy.apiPatchUserRoles(botUserId, ['system_user system_post_all system_admin']);
|
||||
|
||||
// # Get token from bots id
|
||||
cy.apiAccessToken(botUserId, 'Create token').then(({token}) => {
|
||||
//# Add bot to team
|
||||
cy.apiAddUserToTeam(newChannel.team_id, botUserId);
|
||||
|
||||
// # Post message as bot to the new channel
|
||||
cy.postBotMessage({token, channelId: newChannel.id, message: 'this is bot message'}).then((res) => {
|
||||
botPost = res.data;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T252 bot post unread', () => {
|
||||
// # Mark the bot post as unread
|
||||
markAsUnreadFromPost(botPost);
|
||||
|
||||
// * Verify the channel is unread in LHS
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
cy.get(`#sidebarItem_${newChannel.name}`).should(beUnread).click();
|
||||
|
||||
// * Verify the notification separator line exists and present before the unread message
|
||||
verifyPostNextToNewMessageSeparator('this is bot message');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Group: @channels @channel
|
||||
|
||||
import {beRead, beUnread} from '../../../support/assertions';
|
||||
|
||||
import {verifyPostNextToNewMessageSeparator, switchToChannel} from './helpers';
|
||||
|
||||
describe('channel unread posts', () => {
|
||||
let testUser;
|
||||
let otherUser;
|
||||
|
||||
let channelA;
|
||||
let channelB;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Create testUser added to channel
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
testUser = user;
|
||||
channelA = channel;
|
||||
|
||||
// # Create second channel and add testUser
|
||||
cy.apiCreateChannel(team.id, 'channel-b', 'Channel B').then((out) => {
|
||||
channelB = out.channel;
|
||||
cy.apiAddUserToChannel(channelB.id, testUser.id);
|
||||
});
|
||||
|
||||
// # Create otherUser, add to team, and add to both channelA and channelB
|
||||
cy.apiCreateUser().then(({user: user2}) => {
|
||||
otherUser = user2;
|
||||
|
||||
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(channelA.id, otherUser.id);
|
||||
cy.apiAddUserToChannel(channelB.id, otherUser.id);
|
||||
});
|
||||
|
||||
for (let index = 0; index < 5; index++) {
|
||||
// # Post Message as Current user
|
||||
const message = `hello from current user: ${index}`;
|
||||
|
||||
cy.postMessageAs({sender: testUser, message, channelId: channelA.id});
|
||||
}
|
||||
});
|
||||
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T246 Mark Post as Unread', () => {
|
||||
// # Login as other user
|
||||
cy.apiLogin(otherUser);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
// # Mark the last post as unread
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.uiClickPostDropdownMenu(postId, 'Mark as Unread');
|
||||
});
|
||||
|
||||
// * Verify the notification separator line exists and present before the unread message
|
||||
verifyPostNextToNewMessageSeparator('hello from current user: 4');
|
||||
|
||||
// # Switch to channelB
|
||||
switchToChannel(channelB);
|
||||
|
||||
// * Verify the channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify the channelA has does not have unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
|
||||
// * Verify the notification separator line exists and present before the unread message
|
||||
verifyPostNextToNewMessageSeparator('hello from current user: 4');
|
||||
|
||||
// # Switch to channelB
|
||||
switchToChannel(channelB);
|
||||
|
||||
// * Verify the channelA has does not have unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
});
|
||||
|
||||
it('MM-T256 Mark unread before a page of message in Channel', () => {
|
||||
// # Login as other user
|
||||
cy.apiLogin(otherUser);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
for (let index = 5; index < 40; index++) {
|
||||
// # Post Message as Current user
|
||||
const message = `hello from current user: ${index}`;
|
||||
|
||||
cy.postMessageAs({sender: testUser, message, channelId: channelA.id});
|
||||
}
|
||||
|
||||
// # Mark the post which is one page above from bottom as unread
|
||||
cy.getNthPostId(6).then((postId) => {
|
||||
cy.get(`#post_${postId}`).scrollIntoView().should('be.visible');
|
||||
cy.uiClickPostDropdownMenu(postId, 'Mark as Unread');
|
||||
});
|
||||
|
||||
// * Verify the notification separator line exists and present before the unread message
|
||||
verifyPostNextToNewMessageSeparator('hello from current user: 5');
|
||||
|
||||
// # Switch to channelB
|
||||
switchToChannel(channelB);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify the notification separator line exists and present before the unread message
|
||||
verifyPostNextToNewMessageSeparator('hello from current user: 5');
|
||||
});
|
||||
|
||||
it('MM-T259 Mark as Unread channel remains unread when receiving new message', () => {
|
||||
// # Login as other user
|
||||
cy.apiLogin(otherUser);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
// # Mark the last post as unread
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.uiClickPostDropdownMenu(postId, 'Mark as Unread');
|
||||
});
|
||||
|
||||
// * Verify the notification separator line exists and present before the unread message
|
||||
verifyPostNextToNewMessageSeparator('hello from current user: 4');
|
||||
|
||||
// * Verify the channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
for (let index = 5; index < 10; index++) {
|
||||
// # Post Message as Current user
|
||||
const message = `hello from current user: ${index}`;
|
||||
|
||||
cy.postMessageAs({sender: testUser, message, channelId: channelA.id});
|
||||
|
||||
// * Verify the channelA has unread in LHS even when the messages are coming through
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
}
|
||||
|
||||
// # Switch to channelB
|
||||
switchToChannel(channelB);
|
||||
|
||||
// * Verify the channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify the channelA has does not have unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
export function markAsUnreadFromPost(post, rhs = false) {
|
||||
const prefix = rhs ? 'rhsPost' : 'post';
|
||||
|
||||
cy.get(`#${prefix}_${post.id}`).scrollIntoView().should('be.visible');
|
||||
|
||||
cy.get('body').type('{alt}', {release: false});
|
||||
cy.get(`#${prefix}_${post.id}`).click({force: true});
|
||||
cy.get('body').type('{alt}', {release: true});
|
||||
}
|
||||
|
||||
export function markAsUnreadShouldBeAbsent(postId, prefix = 'post', location = 'CENTER') {
|
||||
cy.get(`#${prefix}_${postId}`).trigger('mouseover');
|
||||
cy.clickPostDotMenu(postId, location);
|
||||
cy.get(`#CENTER_dropdown_${postId}`).
|
||||
should('be.visible').
|
||||
within(() => {
|
||||
cy.findByText('Mark as Unread').should('not.exist');
|
||||
});
|
||||
}
|
||||
|
||||
export function switchToChannel(channel) {
|
||||
cy.get(`#sidebarItem_${channel.name}`).click();
|
||||
|
||||
cy.get('#channelHeaderTitle', {timeout: TIMEOUTS.ONE_MIN}).should('contain', channel.display_name);
|
||||
|
||||
// # Wait some time for the channel to set state
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
}
|
||||
|
||||
export function verifyPostNextToNewMessageSeparator(message) {
|
||||
cy.get('.NotificationSeparator').
|
||||
should('exist').
|
||||
parent().
|
||||
parent().
|
||||
parent().
|
||||
next().
|
||||
should('contain', message);
|
||||
}
|
||||
|
||||
export function verifyTopSpaceForNewMessage(message) {
|
||||
cy.get('.post-row__padding.top').
|
||||
should('be.visible').
|
||||
should('contain', message);
|
||||
}
|
||||
|
||||
export function verifyBottomSpaceForNewMessage(message) {
|
||||
cy.get('.post-row__padding.bottom').
|
||||
should('be.visible').
|
||||
should('contain', message);
|
||||
}
|
||||
|
||||
export function showCursor(items) {
|
||||
cy.expect(items).to.have.length(1);
|
||||
expect(items[0].className).to.match(/cursor--pointer/);
|
||||
}
|
||||
|
||||
export function notShowCursor(items) {
|
||||
cy.expect(items).to.have.length(1);
|
||||
expect(items[0].className).to.not.match(/cursor--pointer/);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
import {beRead, beUnread} from '../../../support/assertions';
|
||||
|
||||
import {markAsUnreadFromPost, switchToChannel} from './helpers';
|
||||
|
||||
describe('Leaving channel', () => {
|
||||
let testUser;
|
||||
let otherUser;
|
||||
|
||||
let channelA;
|
||||
let channelB;
|
||||
|
||||
let post1;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
testUser = user;
|
||||
channelA = channel;
|
||||
|
||||
cy.apiCreateChannel(team.id, 'channel-b', 'Channel B').then((out) => {
|
||||
channelB = out.channel;
|
||||
cy.apiAddUserToChannel(channelB.id, testUser.id);
|
||||
});
|
||||
|
||||
cy.apiCreateUser().then(({user: user2}) => {
|
||||
otherUser = user2;
|
||||
|
||||
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(channelA.id, otherUser.id);
|
||||
|
||||
cy.postMessageAs({
|
||||
sender: otherUser,
|
||||
message: 'post1',
|
||||
channelId: channelA.id,
|
||||
}).then((p1) => {
|
||||
post1 = p1;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2924_1 Channel is marked as read as soon as user leaves', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
cy.postMessageAs({sender: otherUser, message: 'post2', channelId: channelA.id});
|
||||
|
||||
switchToChannel(channelB);
|
||||
|
||||
// * Verify that channelA does not have unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
});
|
||||
|
||||
it('MM-T2924_2 Channel is left unread if post is manually marked as unread and user leaves', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
markAsUnreadFromPost(post1);
|
||||
|
||||
switchToChannel(channelB);
|
||||
|
||||
// * Verify that channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,474 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
import {beRead, beUnread} from '../../../support/assertions';
|
||||
|
||||
import {verifyPostNextToNewMessageSeparator, verifyTopSpaceForNewMessage, verifyBottomSpaceForNewMessage, switchToChannel, showCursor, notShowCursor} from './helpers';
|
||||
|
||||
describe('Mark as Unread', () => {
|
||||
let testUser;
|
||||
let team1;
|
||||
let channelA;
|
||||
let channelB;
|
||||
|
||||
let post1;
|
||||
let post2;
|
||||
let post3;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
team1 = team;
|
||||
testUser = user;
|
||||
channelA = channel;
|
||||
|
||||
cy.apiCreateChannel(team1.id, 'channel-b', 'Channel B').then((out) => {
|
||||
channelB = out.channel;
|
||||
cy.apiAddUserToChannel(channelB.id, testUser.id);
|
||||
});
|
||||
|
||||
cy.apiCreateUser().then(({user: user2}) => {
|
||||
const otherUser = user2;
|
||||
|
||||
cy.apiAddUserToTeam(team1.id, otherUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(channelA.id, otherUser.id);
|
||||
|
||||
// Another user creates posts in the channel since you can't mark your own posts unread currently
|
||||
cy.postMessageAs({
|
||||
sender: otherUser,
|
||||
message: 'post1',
|
||||
channelId: channelA.id,
|
||||
}).then((p1) => {
|
||||
post1 = p1;
|
||||
|
||||
cy.postMessageAs({
|
||||
sender: otherUser,
|
||||
message: 'post2',
|
||||
channelId: channelA.id,
|
||||
}).then((p2) => {
|
||||
post2 = p2;
|
||||
|
||||
cy.postMessageAs({
|
||||
sender: otherUser,
|
||||
message: 'post3',
|
||||
channelId: channelA.id,
|
||||
rootId: post1.id,
|
||||
}).then((post) => {
|
||||
post3 = post;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${team1.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('Channel should appear unread after switching away from channel and be read after switching back', () => {
|
||||
// Starts unread
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
switchToChannel(channelA);
|
||||
|
||||
// Then becomes read when you view the channel
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
|
||||
markAsUnreadFromPost(post2);
|
||||
|
||||
// Then becomes unread when the channel is marked as unread
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
switchToChannel(channelB);
|
||||
|
||||
// Then stays unread when switching away
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
switchToChannel(channelA);
|
||||
|
||||
// And becomes read when switching back
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
});
|
||||
|
||||
it('MM-T5223 The latest post should appear unread after marking the channel as unread', () => {
|
||||
// channelA starts unread, then becomes read after you viewed
|
||||
// and switched to channelB
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
switchToChannel(channelA);
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
switchToChannel(channelB);
|
||||
|
||||
// After mark channelA with the LHS mark as unread option, channelA
|
||||
// should appear unread
|
||||
cy.get(`#sidebarItem_${channelA.name}`).find('.SidebarMenu').click({force: true});
|
||||
cy.get(`#markAsUnread-${channelA.id}`).click();
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// After switching back to channelA,
|
||||
// the New Messages line should appear above the last post (post3)
|
||||
cy.get(`#sidebarItem_${channelA.name}`).click();
|
||||
verifyPostNextToNewMessageSeparator('post3');
|
||||
});
|
||||
|
||||
it('MM-T5224 The latest post should appear unread after marking the channel as unread with alt/option+left-click on channel sidebar item', () => {
|
||||
// channelA starts unread, then becomes read after you viewed
|
||||
// and switched to channelB
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
switchToChannel(channelA);
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
switchToChannel(channelB);
|
||||
|
||||
// After mark channelA with alt/option+left-click, channelA
|
||||
// should appear unread
|
||||
cy.get(`#sidebarItem_${channelA.name}`).type('{alt}', {release: false}).click();
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// After switching back to channelA,
|
||||
// the New Messages line should appear above the last post (post3)
|
||||
cy.get(`#sidebarItem_${channelA.name}`).click();
|
||||
verifyPostNextToNewMessageSeparator('post3');
|
||||
});
|
||||
|
||||
it('MM-T257 Mark as Unread when bringing window into focus', () => {
|
||||
// * Verify channels are unread
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
cy.get(`#sidebarItem_${channelB.name}`).should(beUnread);
|
||||
|
||||
// # Navigate to integration screen (away from chat/main screen)
|
||||
cy.visit(`/${team1.name}/integrations/`);
|
||||
|
||||
// # Navigate back to chat/main screen
|
||||
cy.visit(`/${team1.name}/channels/town-square`);
|
||||
|
||||
// * Verify channels are unread
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
cy.get(`#sidebarItem_${channelB.name}`).should(beUnread);
|
||||
|
||||
switchToChannel(channelA);
|
||||
switchToChannel(channelB);
|
||||
|
||||
// * Verify channel are read
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
cy.get(`#sidebarItem_${channelB.name}`).should(beRead);
|
||||
});
|
||||
|
||||
it('New messages line should remain after switching back to channel', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
// Starts not visible
|
||||
cy.get('.NotificationSeparator').should('not.exist');
|
||||
|
||||
markAsUnreadFromPost(post2);
|
||||
|
||||
// Then becomes visible
|
||||
cy.get('.NotificationSeparator').should('exist');
|
||||
|
||||
switchToChannel(channelB);
|
||||
switchToChannel(channelA);
|
||||
|
||||
// Then stays visible when switching back to channel
|
||||
cy.get('.NotificationSeparator').should('exist');
|
||||
|
||||
switchToChannel(channelB);
|
||||
switchToChannel(channelA);
|
||||
|
||||
// Then finally disappears when switching back a second time
|
||||
cy.get('.NotificationSeparator').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T260 Mark as Unread New Messages line extra space moves with it', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
markAsUnreadFromPost(post2);
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post2');
|
||||
|
||||
// Top separator space should appear above the selected post
|
||||
verifyTopSpaceForNewMessage('post2');
|
||||
|
||||
// Bottom separator space should appear below the post
|
||||
verifyBottomSpaceForNewMessage('post1');
|
||||
|
||||
markAsUnreadFromPost(post1);
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post1');
|
||||
|
||||
// Top separator space should appear above the selected post
|
||||
verifyTopSpaceForNewMessage('post1');
|
||||
|
||||
// Bottom separator space should appear below the post by user
|
||||
verifyBottomSpaceForNewMessage('System');
|
||||
|
||||
markAsUnreadFromPost(post3);
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post3');
|
||||
|
||||
// Top separator space should appear above the selected post
|
||||
verifyTopSpaceForNewMessage('post3');
|
||||
|
||||
// Bottom separator space should appear below the post
|
||||
verifyBottomSpaceForNewMessage('post2');
|
||||
});
|
||||
|
||||
it('Should be able to mark channel as unread by alt-clicking on RHS', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
// Show the RHS
|
||||
cy.get(`#CENTER_commentIcon_${post3.id}`).click({force: true});
|
||||
|
||||
markAsUnreadFromPost(post1, true);
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post1');
|
||||
|
||||
markAsUnreadFromPost(post3, true);
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post3');
|
||||
});
|
||||
|
||||
it('Should show cursor pointer when holding down alt', () => {
|
||||
const componentIds = [
|
||||
`#post_${post1.id}`,
|
||||
`#post_${post2.id}`,
|
||||
`#post_${post3.id}`,
|
||||
`#rhsPost_${post1.id}`,
|
||||
`#rhsPost_${post3.id}`,
|
||||
];
|
||||
|
||||
switchToChannel(channelA);
|
||||
|
||||
// Show the RHS
|
||||
cy.get(`#CENTER_commentIcon_${post3.id}`).click({force: true});
|
||||
|
||||
// Pretend that we start hovering over each and then hold alt afterwards
|
||||
for (const componentId of componentIds) {
|
||||
// * Verify that we don't show the pointer on mouseover
|
||||
cy.get(componentId).trigger('mouseover').should(notShowCursor);
|
||||
|
||||
// * Verify that we show the pointer after pressing alt
|
||||
cy.get(componentId).trigger('keydown', {altKey: true}).should(showCursor);
|
||||
|
||||
// * Verify that we stop showing the pointer after releasing alt
|
||||
cy.get(componentId).trigger('keydown', {altKey: false}).should(notShowCursor);
|
||||
|
||||
// # Move the mouse away from the post
|
||||
cy.get(componentId).trigger('mouseout');
|
||||
}
|
||||
|
||||
// Pretend that we hold down alt and then hover over each post
|
||||
for (const componentId of componentIds) {
|
||||
// * Verify that we don't show the pointer on mouseover
|
||||
cy.get(componentId).trigger('mouseover', {altKey: true}).should(showCursor);
|
||||
|
||||
// # Move the mouse away from the post
|
||||
cy.get(componentId).trigger('mouseout', {altKey: true}).should(notShowCursor);
|
||||
}
|
||||
});
|
||||
|
||||
it('Marking a channel as unread from another session while viewing channel', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
|
||||
markAsUnreadFromAnotherSession(post2, testUser);
|
||||
|
||||
// The channel should now be unread
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post2');
|
||||
|
||||
switchToChannel(channelB);
|
||||
|
||||
// Then stays unread when switching away
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
switchToChannel(channelA);
|
||||
|
||||
// And becomes read when switching back
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post2');
|
||||
});
|
||||
|
||||
it('Marking a channel as unread from another session while viewing another channel', () => {
|
||||
switchToChannel(channelA);
|
||||
switchToChannel(channelB);
|
||||
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
|
||||
markAsUnreadFromAnotherSession(post2, testUser);
|
||||
|
||||
// The channel should now be unread
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
switchToChannel(channelA);
|
||||
|
||||
// And becomes read when switching back
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post2');
|
||||
});
|
||||
|
||||
it('MM-T244 Webapp: Post menu item `Mark as Unread` appearance', () => {
|
||||
switchToChannel(channelA);
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
postMessage(post1.message);
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.clickPostDotMenu(postId);
|
||||
cy.get('ul.Menu__content.dropdown-menu').
|
||||
as('menuOptions').
|
||||
should('be.visible').
|
||||
scrollIntoView();
|
||||
|
||||
// # Post menu item `Mark as Unread` should be visible
|
||||
cy.get('@menuOptions').
|
||||
find('[aria-label="Mark as Unread"]').
|
||||
as('markAsReadElement').
|
||||
should('be.visible');
|
||||
|
||||
// # Shrink the window and verify post menu options in the mobile view
|
||||
cy.viewport('iphone-5');
|
||||
cy.get('@markAsReadElement').should('be.visible');
|
||||
|
||||
// * Verify there are no extra divider lines at the bottom of the menu for the non-admin user
|
||||
cy.findByText('Edit').should('not.exist');
|
||||
cy.findByText('Delete').should('not.exist');
|
||||
|
||||
// * Verify there are extra divider lines at the bottom
|
||||
cy.get('ul.Menu__content').find('li.MenuItem').each(($listElement) => {
|
||||
cy.wrap($listElement).find('button').then(($buttonElement) => {
|
||||
cy.wrap($buttonElement).invoke('attr', 'aria-label').then((ariaLabel) => {
|
||||
if (ariaLabel !== 'Copy Text') {
|
||||
cy.wrap($buttonElement).should('have.css', 'border-color', 'rgba(63, 67, 80, 0.12)');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to mark channel as unread from post menu', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
// # Mark post2 as unread
|
||||
cy.uiClickPostDropdownMenu(post2.id, 'Mark as Unread');
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post2');
|
||||
|
||||
// # Mark post1 as unread
|
||||
cy.uiClickPostDropdownMenu(post1.id, 'Mark as Unread');
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post1');
|
||||
|
||||
// # Mark post3 as unread
|
||||
cy.uiClickPostDropdownMenu(post3.id, 'Mark as Unread');
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post3');
|
||||
});
|
||||
|
||||
it('Should be able to mark channel as unread from RHS post menu', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
// Show the RHS
|
||||
cy.get(`#CENTER_commentIcon_${post3.id}`).click({force: true});
|
||||
|
||||
// # Mark post1 as unread in RHS as root thread
|
||||
cy.uiClickPostDropdownMenu(post1.id, 'Mark as Unread', 'RHS_ROOT');
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post1');
|
||||
|
||||
// # Mark post3 as unread in RHS as comment
|
||||
cy.uiClickPostDropdownMenu(post3.id, 'Mark as Unread', 'RHS_COMMENT');
|
||||
|
||||
// The New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post3');
|
||||
});
|
||||
|
||||
it('MM-T250 Mark as unread in the RHS', () => {
|
||||
switchToChannel(channelA);
|
||||
|
||||
// # Open RHS (reply thread)
|
||||
cy.clickPostCommentIcon(post1.id);
|
||||
|
||||
// # Mark the post as unread from RHS
|
||||
cy.uiClickPostDropdownMenu(post1.id, 'Mark as Unread', 'RHS_ROOT');
|
||||
|
||||
// * Verify the New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post1');
|
||||
|
||||
// * Verify the channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// * Verify the RHS does not have the NotificationSeparator line
|
||||
cy.get('#rhsContainer').find('.NotificationSeparator').should('not.exist');
|
||||
|
||||
// # Switch to channelB
|
||||
switchToChannel(channelB);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify the channelA does not have unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
|
||||
// * Hover on the post with holding alt should show cursor
|
||||
cy.get(`#post_${post2.id}`).trigger('mouseover').type('{alt}', {release: false}).should(showCursor);
|
||||
|
||||
// # Mouse click on the post holding alt
|
||||
cy.get(`#post_${post2.id}`).type('{alt}', {release: false}).click();
|
||||
|
||||
// * Verify the post is marked as unread
|
||||
verifyPostNextToNewMessageSeparator('post2');
|
||||
|
||||
// * Verify the channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// * Verify the RHS does not have the NotificationSeparator line
|
||||
cy.get('#rhsContainer').find('.NotificationSeparator').should('not.exist');
|
||||
|
||||
// # Switch to channelB
|
||||
switchToChannel(channelB);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify the channelA does not have unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beRead);
|
||||
});
|
||||
});
|
||||
|
||||
function markAsUnreadFromPost(post, rhs = false) {
|
||||
const prefix = rhs ? 'rhsPost' : 'post';
|
||||
|
||||
cy.get('body').type('{alt}', {release: false});
|
||||
cy.get(`#${prefix}_${post.id}`).click({force: true});
|
||||
cy.get('body').type('{alt}', {release: true});
|
||||
}
|
||||
|
||||
function markAsUnreadFromAnotherSession(post, user) {
|
||||
cy.externalRequest({
|
||||
user,
|
||||
method: 'post',
|
||||
path: `users/${user.id}/posts/${post.id}/set_unread`,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
import {beRead, beUnread} from '../../../support/assertions';
|
||||
|
||||
import {verifyPostNextToNewMessageSeparator, switchToChannel, showCursor} from './helpers';
|
||||
|
||||
describe('Mark as Unread', () => {
|
||||
let testUser;
|
||||
|
||||
let channelA;
|
||||
let channelB;
|
||||
|
||||
let post1;
|
||||
let post2;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
testUser = user;
|
||||
channelA = channel;
|
||||
|
||||
// # Create second channel and add testUser
|
||||
cy.apiCreateChannel(team.id, 'channel-b', 'Channel B').then((out) => {
|
||||
channelB = out.channel;
|
||||
cy.apiAddUserToChannel(channelB.id, testUser.id);
|
||||
});
|
||||
|
||||
// # Create second user and add him to the team
|
||||
cy.apiCreateUser().then(({user: user2}) => {
|
||||
const otherUser = user2;
|
||||
|
||||
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(channelA.id, otherUser.id);
|
||||
|
||||
// Another user creates posts in the channel since you can't mark your own posts unread currently
|
||||
cy.postMessageAs({sender: otherUser, message: 'post1', channelId: channelA.id}).then((p1) => {
|
||||
post1 = p1;
|
||||
|
||||
cy.postMessageAs({sender: otherUser, message: 'post2', channelId: channelA.id}).then((p2) => {
|
||||
post2 = p2;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${team.name}/channels/${channelA.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T251 using shortcuts to make post unread', () => {
|
||||
// * Hover on the post with holding alt should show cursor
|
||||
cy.get(`#post_${post2.id}`).trigger('mouseover').type('{alt}', {release: false}).should(showCursor);
|
||||
|
||||
// # Mouse click on the post holding alt
|
||||
cy.get(`#post_${post2.id}`).type('{alt}', {release: false}).click();
|
||||
|
||||
// * Verify the post is marked as unread
|
||||
verifyPostNextToNewMessageSeparator('post2');
|
||||
|
||||
// * Verify the channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// # Switch to channelB
|
||||
switchToChannel(channelB);
|
||||
|
||||
// # Switch to channelA
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify the channelB does not have unread in LHS
|
||||
cy.get(`#sidebarItem_${channelB.name}`).should(beRead);
|
||||
|
||||
// # Open RHS (reply thread)
|
||||
cy.clickPostCommentIcon(post1.id);
|
||||
|
||||
// # Mark the post as unread from RHS
|
||||
cy.uiClickPostDropdownMenu(post1.id, 'Mark as Unread', 'RHS_ROOT');
|
||||
|
||||
// * Verify the New Messages line should appear above the selected post
|
||||
verifyPostNextToNewMessageSeparator('post1');
|
||||
|
||||
// * Verify the channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,197 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Group: @channels @messaging
|
||||
|
||||
import {verifyPostNextToNewMessageSeparator} from './helpers';
|
||||
|
||||
describe('Mark DM post as Unread ', () => {
|
||||
beforeEach(function() {
|
||||
cy.apiAdminLogin().
|
||||
apiCreateUser().
|
||||
its('user').as('userA').
|
||||
apiInitSetup().
|
||||
then(({user, team}) => cy.
|
||||
apiAddUserToTeam(team.id, this.userA.id).
|
||||
apiCreateDirectChannel([user.id, this.userA.id]).its('channel').as('dmChannel').
|
||||
wrap(user).as('mainUser').
|
||||
wrap(team).as('team').
|
||||
wrap(`/${team.name}/messages/@${this.userA.username}`).as('link'),
|
||||
);
|
||||
});
|
||||
|
||||
it('MM-T248_1 Mark DM post as Unread', function() {
|
||||
const NUMBER_OF_USER_A_UNREAD_MESSAGES = 4;
|
||||
|
||||
// # Post initial message from main user
|
||||
cy.postMessageAs({
|
||||
sender: this.mainUser,
|
||||
message: 'Initial message',
|
||||
channelId: this.dmChannel.id,
|
||||
});
|
||||
|
||||
// # Post several messages from User A
|
||||
cy.postListOfMessages({
|
||||
numberOfMessages: 3,
|
||||
sender: this.userA,
|
||||
channelId: this.dmChannel.id,
|
||||
});
|
||||
|
||||
// # Post messages from User A meant to be marked as unread
|
||||
cy.postMessageAs({
|
||||
sender: this.userA,
|
||||
message: 'Unread from here',
|
||||
channelId: this.dmChannel.id,
|
||||
}).as('unreadFromHere');
|
||||
cy.postListOfMessages({
|
||||
numberOfMessages: NUMBER_OF_USER_A_UNREAD_MESSAGES - 1,
|
||||
sender: this.userA,
|
||||
channelId: this.dmChannel.id,
|
||||
});
|
||||
|
||||
// # Post more messages from main user
|
||||
cy.postListOfMessages({
|
||||
numberOfMessages: 3,
|
||||
sender: this.mainUser,
|
||||
channelId: this.dmChannel.id,
|
||||
});
|
||||
|
||||
// # Visit the DM channel and open the thread in RHS
|
||||
cy.apiLogin(this.mainUser).visit(this.link);
|
||||
|
||||
// # Мark the message from user A as unread
|
||||
cy.then(() => cy.uiClickPostDropdownMenu(this.unreadFromHere.id, 'Mark as Unread'));
|
||||
|
||||
// * Verify that new message separator exists above the unread messages
|
||||
cy.then(() => verifyPostNextToNewMessageSeparator(this.unreadFromHere.data.message));
|
||||
|
||||
// * Verify that DM-channel is marked as unread
|
||||
cy.then(() => verifyChannelIsMarkedUnreadInLHS(this.userA.username, {
|
||||
numberOfUnreadMessages: NUMBER_OF_USER_A_UNREAD_MESSAGES,
|
||||
}));
|
||||
|
||||
// # Leave DM-channel
|
||||
cy.get('.SidebarChannel:contains(Off-Topic)').click();
|
||||
|
||||
// * Verify that DM-channel is still marked as unread, with the same "mention bubble"
|
||||
cy.then(() => verifyChannelIsMarkedUnreadInLHS(this.userA.username, {
|
||||
numberOfUnreadMessages: NUMBER_OF_USER_A_UNREAD_MESSAGES,
|
||||
}));
|
||||
|
||||
// # Return to DM-channel
|
||||
cy.get(`.SidebarChannel:contains(${this.userA.username})`).click();
|
||||
|
||||
// * Verify that DM-channel is marked as read
|
||||
cy.then(() => verifyChannelIsMarkedReadInLHS(this.userA.username));
|
||||
|
||||
// * Verify that new message separator exists above the unread messages
|
||||
cy.then(() => verifyPostNextToNewMessageSeparator(this.unreadFromHere.data.message));
|
||||
});
|
||||
|
||||
it('MM-T248_2 Mark DM post as Unread in a reply thread', function() {
|
||||
const NUMBER_OF_USER_A_UNREAD_MESSAGES = 4;
|
||||
|
||||
// # Post initial message from main user
|
||||
cy.postMessageAs({
|
||||
sender: this.mainUser,
|
||||
message: 'Initial message',
|
||||
channelId: this.dmChannel.id,
|
||||
}).as('root');
|
||||
|
||||
// # Post several messages from User A
|
||||
cy.then(() => cy.postListOfMessages({
|
||||
numberOfMessages: 3,
|
||||
sender: this.userA,
|
||||
channelId: this.dmChannel.id,
|
||||
rootId: this.root.id,
|
||||
}));
|
||||
|
||||
// # Post messages from User A meant to be marked as unread
|
||||
cy.then(() => cy.postMessageAs({
|
||||
sender: this.userA,
|
||||
message: 'Unread from here',
|
||||
channelId: this.dmChannel.id,
|
||||
rootId: this.root.id,
|
||||
})).as('unreadFromHere');
|
||||
cy.then(() => cy.postListOfMessages({
|
||||
numberOfMessages: NUMBER_OF_USER_A_UNREAD_MESSAGES - 1,
|
||||
sender: this.userA,
|
||||
channelId: this.dmChannel.id,
|
||||
rootId: this.root.id,
|
||||
}));
|
||||
|
||||
// # Post more messages from main user
|
||||
cy.then(() => cy.postListOfMessages({
|
||||
numberOfMessages: 3,
|
||||
sender: this.mainUser,
|
||||
channelId: this.dmChannel.id,
|
||||
rootId: this.root.id,
|
||||
}));
|
||||
|
||||
// # Visit the DM channel and open the thread in RHS
|
||||
cy.apiLogin(this.mainUser).visit(this.link);
|
||||
cy.get('@root').its('id').then(cy.clickPostCommentIcon);
|
||||
|
||||
// # Мark the message from user A as unread
|
||||
cy.then(() => cy.uiClickPostDropdownMenu(this.unreadFromHere.id, 'Mark as Unread', 'RHS_COMMENT'));
|
||||
|
||||
// * Verify that new message separator exists above the unread messages
|
||||
cy.then(() => verifyPostNextToNewMessageSeparator(this.unreadFromHere.data.message));
|
||||
|
||||
// * Verify that DM-channel is marked as unread
|
||||
cy.then(() => verifyChannelIsMarkedUnreadInLHS(this.userA.username, {
|
||||
numberOfUnreadMessages: NUMBER_OF_USER_A_UNREAD_MESSAGES,
|
||||
}));
|
||||
|
||||
// # Leave DM-channel
|
||||
cy.get('.SidebarChannel:contains(Off-Topic)').click();
|
||||
|
||||
// * Verify that DM-channel is still marked as unread, with the same "mention bubble"
|
||||
cy.then(() => verifyChannelIsMarkedUnreadInLHS(this.userA.username, {
|
||||
numberOfUnreadMessages: NUMBER_OF_USER_A_UNREAD_MESSAGES,
|
||||
}));
|
||||
|
||||
// # Return to DM-channel
|
||||
cy.get(`.SidebarChannel:contains(${this.userA.username})`).click();
|
||||
|
||||
// * Verify that DM-channel is marked as read
|
||||
cy.then(() => verifyChannelIsMarkedReadInLHS(this.userA.username));
|
||||
|
||||
// * Verify that new message separator exists above the unread messages
|
||||
cy.then(() => verifyPostNextToNewMessageSeparator(this.unreadFromHere.data.message));
|
||||
});
|
||||
});
|
||||
|
||||
function verifyChannelIsMarkedUnreadInLHS(channelName, {numberOfUnreadMessages}) {
|
||||
cy.
|
||||
|
||||
// * Verify that DM-channel is marked as unread
|
||||
get('.SidebarChannelGroup_content').
|
||||
contains(channelName).
|
||||
parent().
|
||||
should('have.class', 'unread').
|
||||
|
||||
// * Verify that DM channel "mention bubble" contains number of unread messages except mainUser's ones
|
||||
find('.badge').
|
||||
should('contain.text', numberOfUnreadMessages);
|
||||
}
|
||||
|
||||
function verifyChannelIsMarkedReadInLHS(channelName) {
|
||||
cy.
|
||||
|
||||
// * Verify that DM-channel is marked as read
|
||||
get('.SidebarChannelGroup_content').
|
||||
contains(channelName).
|
||||
parent().
|
||||
should('not.have.class', 'unread').
|
||||
|
||||
// * Verify that DM channel "mention bubble" contains number of unread messages except mainUser's ones
|
||||
find('.badge').
|
||||
should('not.exist');
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
import {verifyPostNextToNewMessageSeparator} from './helpers';
|
||||
|
||||
describe('Mark as Unread', () => {
|
||||
let testUser;
|
||||
let otherUser1;
|
||||
let otherUser2;
|
||||
|
||||
before(() => {
|
||||
// # Create testUser added to channel
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testUser = user;
|
||||
|
||||
// # Create second user and add to the team
|
||||
cy.apiCreateUser({prefix: 'otherA'}).then(({user: newUser}) => {
|
||||
otherUser1 = newUser;
|
||||
|
||||
cy.apiAddUserToTeam(team.id, newUser.id);
|
||||
});
|
||||
|
||||
// # Create third user and add to the team
|
||||
cy.apiCreateUser({prefix: 'otherB'}).then(({user: newUser}) => {
|
||||
otherUser2 = newUser;
|
||||
|
||||
cy.apiAddUserToTeam(team.id, newUser.id);
|
||||
});
|
||||
|
||||
// # Login as test user and go to town square
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T249 Mark GM post as unread', () => {
|
||||
const userGroupIds = [testUser.id, otherUser1.id, otherUser2.id];
|
||||
|
||||
// # Create a group channel for 3 users
|
||||
cy.apiCreateGroupChannel(userGroupIds).then(({channel: gmChannel}) => {
|
||||
// # Visit the channel using the name using the channels route
|
||||
for (let index = 0; index < 8; index++) {
|
||||
// # Post Message as otherUser1
|
||||
cy.postMessageAs({sender: otherUser1, message: `this is from user: ${otherUser1.id}, ${index}`, channelId: gmChannel.id});
|
||||
|
||||
// # Post Message as otherUser2
|
||||
cy.postMessageAs({sender: otherUser2, message: `this is from user: ${otherUser2.id}, ${index}`, channelId: gmChannel.id});
|
||||
}
|
||||
|
||||
// # Go to the group message channel
|
||||
cy.get(`#sidebarItem_${gmChannel.name}`).click();
|
||||
cy.reload();
|
||||
|
||||
// # Mark the post to be unread
|
||||
cy.getNthPostId(-2).then((postId) => {
|
||||
cy.uiClickPostDropdownMenu(postId, 'Mark as Unread');
|
||||
});
|
||||
|
||||
// * Verify the notification separator line exists and present before the unread message
|
||||
verifyPostNextToNewMessageSeparator(`this is from user: ${otherUser1.id}, 7`);
|
||||
|
||||
// * Verify the group message in LHS is unread
|
||||
cy.get(`#sidebarItem_${gmChannel.name}`).should('have.attr', 'aria-label', `${otherUser1.username}, ${otherUser2.username} unread`);
|
||||
|
||||
// # Leave the group message channel
|
||||
cy.get('#sidebarItem_town-square').click();
|
||||
|
||||
// * Verify the group message in LHS is unread
|
||||
cy.get(`#sidebarItem_${gmChannel.name}`).should('have.attr', 'aria-label', `${otherUser1.username}, ${otherUser2.username} unread`);
|
||||
|
||||
// # Go to the group message channel
|
||||
cy.get(`#sidebarItem_${gmChannel.name}`).click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// * Verify the group message in LHS is read
|
||||
cy.get(`#sidebarItem_${gmChannel.name}`).should('exist').should('not.have.attr', 'aria-label', `${otherUser1.username}, ${otherUser2.username} unread`);
|
||||
|
||||
// * Verify the notification separator line exists and present before the unread message
|
||||
verifyPostNextToNewMessageSeparator(`this is from user: ${otherUser1.id}, 7`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,186 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
import {beUnread} from '../../../support/assertions';
|
||||
|
||||
import {verifyPostNextToNewMessageSeparator, switchToChannel} from './helpers';
|
||||
|
||||
describe('Mark post with mentions as unread', () => {
|
||||
let userA;
|
||||
let userB;
|
||||
|
||||
let channelA;
|
||||
let channelB;
|
||||
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, user, channel}) => {
|
||||
userA = user;
|
||||
channelA = channel;
|
||||
testTeam = team;
|
||||
|
||||
// # Create second channel and add userA
|
||||
cy.apiCreateChannel(team.id, 'channel-b', 'Channel B').then((out) => {
|
||||
channelB = out.channel;
|
||||
cy.apiAddUserToChannel(channelB.id, userA.id);
|
||||
});
|
||||
|
||||
// # Create a second user
|
||||
cy.apiCreateUser().then(({user: user2}) => {
|
||||
userB = user2;
|
||||
|
||||
// # Add userB to channel team and channels
|
||||
cy.apiAddUserToTeam(testTeam.id, userB.id).then(() => {
|
||||
cy.apiAddUserToChannel(channelA.id, userB.id);
|
||||
cy.apiAddUserToChannel(channelB.id, userB.id);
|
||||
});
|
||||
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T247 Marks posts with mentions as unread', () => {
|
||||
// # Login as userB
|
||||
cy.apiLogin(userB);
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
|
||||
// # Navigate to both channels, so the new messages line appears above posts
|
||||
switchToChannel(channelA);
|
||||
switchToChannel(channelB);
|
||||
|
||||
// # Mention userB in channel A as userA
|
||||
cy.postMessageAs({
|
||||
sender: userA,
|
||||
message: `@${userB.username} : hello1`,
|
||||
channelId: channelA.id,
|
||||
});
|
||||
|
||||
// * Verify that channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// * Verify that ChannelA has unread mention in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).children('#unreadMentions').should('have.text', '1');
|
||||
|
||||
// # Navigate to channel A
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify that ChannelA no longer has unread mention in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).children('#unreadMentions').should('not.exist');
|
||||
|
||||
// * Verify that new message separator exists above the unread message
|
||||
verifyPostNextToNewMessageSeparator(`@${userB.username} : hello1`);
|
||||
|
||||
// # Navigate to channel B
|
||||
switchToChannel(channelB);
|
||||
|
||||
// # Navigate back to channel A
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify that new message separator is gone
|
||||
cy.get('.NotificationSeparator').should('not.exist');
|
||||
|
||||
// # Mention userB in channel B as userA
|
||||
cy.postMessageAs({
|
||||
sender: userA,
|
||||
message: `@${userB.username} : hello2`,
|
||||
channelId: channelB.id,
|
||||
});
|
||||
|
||||
// # Navigate to channel B
|
||||
switchToChannel(channelB);
|
||||
|
||||
// * Verify that new message separator exists above the unread message
|
||||
verifyPostNextToNewMessageSeparator(`@${userB.username} : hello2`);
|
||||
|
||||
// # Refresh the page
|
||||
cy.reload();
|
||||
|
||||
// * Verify the new message separator is gone
|
||||
cy.get('.NotificationSeparator').should('not.exist');
|
||||
|
||||
// # Mention userB in channelA as userA
|
||||
cy.postMessageAs({
|
||||
sender: userA,
|
||||
message: `@${userB.username} : hello3`,
|
||||
channelId: channelA.id,
|
||||
});
|
||||
|
||||
// # Navigate back to channel A
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify the new message separator exists above the unread message
|
||||
verifyPostNextToNewMessageSeparator(`@${userB.username} : hello3`);
|
||||
|
||||
// # Get the ID of the last post
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// # Mark last post as unread from menu
|
||||
cy.uiClickPostDropdownMenu(postId, 'Mark as Unread');
|
||||
});
|
||||
|
||||
// * Verify the new message separator still exists above the unread message
|
||||
verifyPostNextToNewMessageSeparator(`@${userB.username} : hello3`);
|
||||
|
||||
// * Verify that channelA has unread in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).should(beUnread);
|
||||
|
||||
// * Verify that ChannelA has unread mention in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).children('#unreadMentions').should('have.text', '1');
|
||||
|
||||
// # Navigate to channel B
|
||||
switchToChannel(channelB);
|
||||
|
||||
// # Navigate back to channel A
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify the new message separator still exists above the unread message
|
||||
verifyPostNextToNewMessageSeparator(`@${userB.username} : hello3`);
|
||||
|
||||
// * Verify that ChannelA no longer has unread mention in LHS
|
||||
cy.get(`#sidebarItem_${channelA.name}`).children('#unreadMentions').should('not.exist');
|
||||
|
||||
// # Mention userB in channelB as userA
|
||||
cy.postMessageAs({
|
||||
sender: userA,
|
||||
message: `@${userB.username} : hello4`,
|
||||
channelId: channelB.id,
|
||||
});
|
||||
|
||||
// # Navigate to channel B
|
||||
switchToChannel(channelB);
|
||||
|
||||
// # Get the ID of the last post
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// # Mark last post as unread from menu
|
||||
cy.uiClickPostDropdownMenu(postId, 'Mark as Unread');
|
||||
});
|
||||
|
||||
// * Verify the new message separator exists above the unread message
|
||||
verifyPostNextToNewMessageSeparator(`@${userB.username} : hello4`);
|
||||
|
||||
// * Verify that ChannelB has unread mention in LHS
|
||||
cy.get(`#sidebarItem_${channelB.name}`).children('#unreadMentions').should('have.text', '1');
|
||||
|
||||
// # Refresh the page
|
||||
cy.reload();
|
||||
|
||||
// * Verify the new message separator still exists above the unread message
|
||||
verifyPostNextToNewMessageSeparator(`@${userB.username} : hello4`);
|
||||
|
||||
// # Navigate to channel A
|
||||
switchToChannel(channelA);
|
||||
|
||||
// * Verify that ChannelB no longer has unread mention in LHS
|
||||
cy.get(`#sidebarItem_${channelB.name}`).children('#unreadMentions').should('not.exist');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
import {markAsUnreadFromPost, switchToChannel} from './helpers';
|
||||
|
||||
describe('Verify unread toast appears after repeated manual marking post as unread', () => {
|
||||
let firstPost;
|
||||
let secondPost;
|
||||
|
||||
const offTopicChannel = {name: 'off-topic', display_name: 'Off-Topic'};
|
||||
let testChannel;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, user, channel}) => {
|
||||
testChannel = channel;
|
||||
|
||||
cy.apiCreateUser({prefix: 'other'}).then(({user: otherUser}) => {
|
||||
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
|
||||
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
|
||||
|
||||
// Toast only seems to appear after first visiting the channel
|
||||
// So we need to visit the channel then navigate away
|
||||
cy.apiLogin(user);
|
||||
cy.visit(`/${team.name}/channels/${testChannel.name}`);
|
||||
switchToChannel(offTopicChannel);
|
||||
|
||||
cy.postMessageAs({
|
||||
sender: otherUser,
|
||||
message: 'First message',
|
||||
channelId: testChannel.id,
|
||||
}).then((post) => {
|
||||
firstPost = post;
|
||||
|
||||
cy.postMessageAs({
|
||||
sender: otherUser,
|
||||
message: 'Second message',
|
||||
channelId: testChannel.id,
|
||||
}).then((post2) => {
|
||||
secondPost = post2;
|
||||
|
||||
// Add posts so that scroll is available
|
||||
Cypress._.times(30, (index) => {
|
||||
cy.postMessageAs({
|
||||
sender: otherUser,
|
||||
message: `${index.toString()}\nsecond line\nthird line\nfourth line`,
|
||||
channelId: testChannel.id,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1429 Toast when navigating to channel with unread messages and after repeated marking as unread', () => {
|
||||
// # Switch to town square channel that has unread messages
|
||||
switchToChannel(testChannel);
|
||||
|
||||
// * Check that the toast is visible
|
||||
cy.get('div.toast').should('be.visible');
|
||||
|
||||
// # Scroll to the bottom of the posts
|
||||
cy.get('.post-list__dynamic').scrollTo('bottom');
|
||||
|
||||
// * Check that the toast is not visible
|
||||
cy.get('div.toast').should('not.exist');
|
||||
|
||||
// # Mark the first post as unread
|
||||
markAsUnreadFromPost(firstPost);
|
||||
|
||||
// * Check that the toast is now visible
|
||||
cy.get('div.toast').should('be.visible');
|
||||
|
||||
// # Scroll to the bottom of the posts
|
||||
cy.get('.post-list__dynamic').scrollTo('bottom');
|
||||
|
||||
// * Check that the toast is not visible
|
||||
cy.get('div.toast').should('not.exist');
|
||||
|
||||
// # Mark the second post as unread
|
||||
markAsUnreadFromPost(secondPost);
|
||||
|
||||
// * Check that the toast is now visible
|
||||
cy.get('div.toast').should('be.visible');
|
||||
|
||||
// # Switch channels
|
||||
switchToChannel(offTopicChannel);
|
||||
|
||||
// * Check that the toast is not visible
|
||||
cy.get('div.toast').should('not.exist');
|
||||
|
||||
// # Switch channels back
|
||||
switchToChannel(testChannel);
|
||||
|
||||
// * Check that the toast is now visible
|
||||
cy.get('div.toast').should('be.visible');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @mark_as_unread
|
||||
|
||||
describe('Verify unread toast appears after repeated manual marking post as unread', () => {
|
||||
let currentChannel;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, channel, user}) => {
|
||||
currentChannel = channel;
|
||||
cy.apiCreateUser().then(({user: user2}) => {
|
||||
cy.apiAddUserToTeam(team.id, user2.id).then(() => {
|
||||
cy.apiAddUserToChannel(channel.id, user2.id);
|
||||
|
||||
// # Create a page full of messages
|
||||
Cypress._.times(30, (i) => {
|
||||
cy.postMessageAs({
|
||||
sender: user2,
|
||||
message: `post${i}`,
|
||||
channelId: channel.id,
|
||||
});
|
||||
});
|
||||
|
||||
// # Make a mentioned message
|
||||
cy.postMessageAs({
|
||||
sender: user2,
|
||||
message: `hi @${user.username}`,
|
||||
channelId: channel.id,
|
||||
});
|
||||
|
||||
// # Login as user
|
||||
cy.apiLogin(user);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Post a reply on RHS
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.clickPostCommentIcon(postId);
|
||||
cy.get('#rhsContainer').should('be.visible');
|
||||
const replyMessage = 'A reply to an older post';
|
||||
cy.postMessageReplyInRHS(replyMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T254 Rehydrate mention badge after post is marked as Unread', () => {
|
||||
// # Mark the first post as unread
|
||||
cy.getNthPostId(1).then((postId) => {
|
||||
cy.get(`#post_${postId}`).scrollIntoView().should('be.visible');
|
||||
cy.uiClickPostDropdownMenu(postId, 'Mark as Unread');
|
||||
});
|
||||
|
||||
// * Check that the toast is visible
|
||||
cy.get('div.toast').should('be.visible').then(() => {
|
||||
// * Check that the message is correct and all the mentions and replies are counted in toast
|
||||
cy.get('div.toast__message>span').should('be.visible').contains('30 new messages');
|
||||
|
||||
cy.get(`#sidebarItem_${currentChannel.name}`).
|
||||
scrollIntoView().
|
||||
find('#unreadMentions').
|
||||
should('be.visible').
|
||||
and('have.text', '1');
|
||||
});
|
||||
});
|
||||
});
|
||||
Ссылка в новой задаче
Block a user