Files
Harrison HealeyandGitHub daec1283e5 MM-69003 Mostly share ESLint config between web app and E2E tests (#36767)
* Switch Cypress to use shared ESLint config

* Run --fix in Cypress

* Manually fix remaining lint issues in Cypress

* Switch Playwright to use shared ESLint config

* Run --fix in Playwright

* Manually fix remaining lint issues in Playwright

* Install and cache web app deps during Cypress CI builds

This also caches the types and client package. That isn't needed currently
since it uses prepackaged versions of those, but I imagine we might change
that at some point.

* Run e2e-tests-check when ESLint plugin is updated

* Change E2E test GHA caching to cache all of web app node_modules

* Fix mismatch between cache save and restore

* Try bumping cache keys

* Copy step to install dependencies to server.run_cypress.sh

I don't know how this must've worked before, but if this fixes the issue,
it seems like neither Cypress nor Playwright actually use the cached
depenendencies.

* Try disabling caching entirely for Cypress tests

* Try bypassing makefile?

* Try also manually building dependencies in run_specs.sh

I don't know why this appears to duplicate run_cypress.sh and
run_playwright.sh, both of which are called run_test.sh which
might not be used any more as best I can tell.

* Try installing the web app dependencies in yet another place

* Disable the extra steps in server.prepare.sh specifically for Cypress

* Revert changes to update cache key and disable web app depenedency cache on Cypress builds
2026-06-09 20:50:58 +00:00

281 lines
9.7 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {ChainableT} from '../../types';
function uiGetPostTextBox(option = {exist: true}): ChainableT<JQuery> {
if (option.exist) {
return cy.get('#post_textbox').should('be.visible');
}
return cy.get('#post_textbox').should('not.exist');
}
Cypress.Commands.add('uiGetPostTextBox', uiGetPostTextBox);
function uiGetReplyTextBox(option = {exist: true}): ChainableT<JQuery> {
if (option.exist) {
return cy.get('#reply_textbox').should('be.visible');
}
return cy.get('#reply_textbox').should('not.exist');
}
Cypress.Commands.add('uiGetReplyTextBox', uiGetReplyTextBox);
function uiGetPostProfileImage(postId: string): ChainableT<JQuery> {
return getPost(postId).within(() => {
return cy.get('.post__img').should('be.visible');
});
}
Cypress.Commands.add('uiGetPostProfileImage', uiGetPostProfileImage);
function uiGetPostHeader(postId: string): ChainableT<JQuery> {
return getPost(postId).within(() => {
return cy.get('.post__header').should('be.visible');
});
}
Cypress.Commands.add('uiGetPostHeader', uiGetPostHeader);
function uiGetPostBody(postId: string): ChainableT<JQuery> {
return getPost(postId).within(() => {
return cy.get('.post__body').should('be.visible');
});
}
Cypress.Commands.add('uiGetPostBody', uiGetPostBody);
function uiGetPostThreadFooter(postId: string): ChainableT<JQuery> {
return getPost(postId).find('.ThreadFooter');
}
Cypress.Commands.add('uiGetPostThreadFooter', uiGetPostThreadFooter);
function uiGetPostEmbedContainer(postId: string): ChainableT<JQuery> {
return cy.uiGetPostBody(postId).
find('.file-preview__button').
should('be.visible');
}
Cypress.Commands.add('uiGetPostEmbedContainer', uiGetPostEmbedContainer);
function getPost(postId: string): ChainableT<JQuery> {
if (postId) {
return cy.get(`#post_${postId}`).should('be.visible');
}
return cy.getLastPost();
}
Cypress.Commands.add('getPost', getPost);
function editLastPostWithNewMessage(message: string) {
cy.uiGetPostTextBox().type('{uparrow}');
// * Edit Post Input should appear
cy.get('#edit_textbox').should('be.visible');
// # Update the post message and click Save
cy.get('#edit_textbox').clear().type(message);
cy.get('#create_post').findByText('Save').scrollIntoView().click();
}
Cypress.Commands.add('editLastPostWithNewMessage', editLastPostWithNewMessage);
export function verifySavedPost(postId: string, message: string) {
// * Check that the center save icon has been updated correctly
cy.get(`#post_${postId}`).trigger('mouseover', {force: true});
cy.get(`#CENTER_flagIcon_${postId}`).
should('have.class', 'post-menu__item').
and('have.attr', 'aria-label', 'remove from saved');
// # Open the post-dotmenu
cy.clickPostDotMenu(postId, 'CENTER');
// * Check that the dotmenu item is changed accordingly
cy.findAllByTestId(`post-menu-${postId}`).eq(0).should('be.visible');
cy.findByText('Remove from Saved').scrollIntoView().should('be.visible');
cy.get('body').type('{esc}');
cy.get('#postListContent').within(() => {
// * Check that the post is highlighted
cy.get(`#post_${postId}`).should('have.class', 'post--pinned-or-flagged');
// * Check that the post pre-header is visible
cy.get('div.post-pre-header').should('be.visible');
// * Check that the post pre-header has the saved icon
cy.get('span.icon--post-pre-header').
should('be.visible').
within(() => {
cy.get('svg').should('have.attr', 'aria-label', 'Saved Icon');
});
// * Check that the post pre-header has the saved post link
cy.get('div.post-pre-header__text-container').
should('be.visible').
and('have.text', 'Saved').
within(() => {
cy.get('a').as('savedLink').should('be.visible');
});
});
// * Check that the saved posts list is not open in RHS before clicking the link in the post pre-header
cy.get('#searchContainer').should('not.exist');
// # Click the link
cy.get('@savedLink').click();
// * Check that the saved posts list is open in RHS
cy.get('#searchContainer').should('be.visible').within(() => {
cy.get('.sidebar--right__title').
should('be.visible').
and('have.text', 'Saved messages');
// * Check that the post pre-header is not shown for the saved message in RHS
cy.get(`#searchResult_${postId}`).within(() => {
cy.get(`#rhsPostMessageText_${postId}`).contains(message);
cy.get('div.post-pre-header').should('not.exist');
});
});
// # Close the RHS
cy.get('#searchResultsCloseButton').should('be.visible').click();
}
export function verifyUnsavedPost(postId: string) {
// * Check that the center save icon has been updated correctly
cy.get(`#post_${postId}`).trigger('mouseover', {force: true});
cy.get(`#CENTER_flagIcon_${postId}`).
should('have.class', 'post-menu__item').
and('have.attr', 'aria-label', 'save message');
// # Open the post-dotmenu
cy.clickPostDotMenu(postId, 'CENTER');
// * Check that the dotmenu item is changed accordingly
cy.findAllByTestId(`post-menu-${postId}`).eq(0).should('be.visible');
cy.findByText('Save Message').scrollIntoView().should('be.visible');
cy.get('body').type('{esc}');
cy.get('#postListContent').within(() => {
// * Check that the post is not highlighted
cy.get(`#post_${postId}`).should('not.have.class', 'post--pinned-or-flagged');
// * Check that the post pre-header is not visible
cy.get('div.post-pre-header').should('not.exist');
// * Check that the post pre-header does not have the saved icon
cy.get('span.icon--post-pre-header').
should('not.exist');
// * Check that the post pre-header does not have the saved post link
cy.get('div.post-pre-header__text-container').
should('not.exist');
});
// * Check that the saved posts list is not open in RHS before clicking the link in the post pre-header
cy.get('#searchContainer').should('not.exist');
// # Click the link
cy.uiGetSavedPostButton().click();
// * Check that the saved posts list is open in RHS
cy.get('#searchContainer').should('be.visible').within(() => {
cy.get('.sidebar--right__title').
should('be.visible').
and('have.text', 'Saved messages');
// * Check that the post pre-header is not shown for the saved message in RHS
cy.get('#search-items-container').within(() => {
cy.get(`#rhsPostMessageText_${postId}`).should('not.exist');
});
});
// # Close the RHS
cy.get('#searchResultsCloseButton').should('be.visible').click();
}
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
interface Chainable {
/**
* Edit last post with a new message
*
* @param {string} - message
*
* @example
* cy.editLastPostWithNewMessage('new message');
*/
editLastPostWithNewMessage: typeof editLastPostWithNewMessage;
/**
* Get post profile image of a given post ID or the last post if post ID is not given
*
* @param {string} - postId (optional)
*
* @example
* cy.uiGetPostProfileImage();
*/
uiGetPostProfileImage: typeof uiGetPostProfileImage;
/**
* Get post header of a given post ID or the last post if post ID is not given
*
* @param {string} - postId (optional)
*
* @example
* cy.uiGetPostHeader();
*/
uiGetPostHeader: typeof uiGetPostHeader;
/**
* Get post body of a given post ID or the last post if post ID is not given
*
* @param {string} - postId (optional)
*
* @example
* cy.uiGetPostBody();
*/
uiGetPostBody: typeof uiGetPostBody;
/**
* Get post thread footer of a given post ID or the last post if post ID is not given
*
* @param {string} - postId (optional)
*
* @example
* cy.uiGetPostThreadFooter();
*/
uiGetPostThreadFooter: typeof uiGetPostThreadFooter;
/**
* Get post embed container of a given post ID or the last post if post ID is not given
*
* @param {string} - postId (optional)
*
* @example
* cy.uiGetPostEmbedContainer();
*/
uiGetPostEmbedContainer: typeof uiGetPostEmbedContainer;
/**
* Get post textbox
*
* @param {bool} option.exist - Set to false to check whether element should not exist. Otherwise, true (default) to check visibility.
*
* @example
* cy.uiGetPostTextBox();
*/
uiGetPostTextBox: typeof uiGetPostTextBox;
/**
* Get reply textbox
*
* @param {bool} option.exist - Set to false to check whether element should not exist. Otherwise, true (default) to check visibility.
*
* @example
* cy.uiGetReplyTextBox();
*/
uiGetReplyTextBox: typeof uiGetReplyTextBox;
getPost: typeof getPost;
}
}
}