diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c6c20fd46e..d2ed1d9054 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -6,27 +6,32 @@ jobs: e2e: runs-on: ubuntu-latest name: End-to-end tests + concurrency: + group: react-e2e + cancel-in-progress: false + env: + PLAYWRIGHT_BROWSERS_PATH: ./pw-browsers steps: - uses: actions/checkout@v3 - name: 💾 Cache Dependencies uses: actions/cache@v3 with: - path: ./node_modules - key: ${{ runner.os }}-${{ matrix.node }}-modules-${{ hashFiles('**/yarn.lock') }} + path: | + ./node_modules + ./pw-browsers + key: ${{ runner.os }}-${{ matrix.node }}-modules-${{ hashFiles('./yarn.lock') }} - name: 🔨 Install Dependencies - run: yarn install --frozen-lockfile --ignore-engines --ignore-scripts + run: | + yarn install --frozen-lockfile --ignore-engines --ignore-scripts + npx playwright install chromium + npx playwright install-deps - name: ⚗️ End-to-end tests run: | - npx playwright install - npx playwright install-deps yarn e2e-fixtures - # running with --browser=all causes failures yarn e2e --browser=chromium - yarn e2e --browser=webkit - yarn e2e --browser=firefox env: E2E_JUMP_TO_MESSAGE_CHANNEL: jump-to-message E2E_ADD_MESSAGE_CHANNEL: add-message diff --git a/e2e/attachment-sizing.test.ts b/e2e/attachment-sizing.test.ts index 7d9c033551..699ac3112e 100644 --- a/e2e/attachment-sizing.test.ts +++ b/e2e/attachment-sizing.test.ts @@ -47,20 +47,4 @@ test.describe('add height to video and image attachments', () => { .sees(MessageList) .isScrolledToBottom(`${USER1_CHAT_VIEW_CLASSNAME} ${selectors.messageListContainer}`); }); - - test('should add height for gallery image attachments', async ({ page, user }) => { - const imageElementsLocator = page.locator( - '[data-testid="gallery-image-last"],[data-testid="gallery-image"]', - ); - const result = await imageElementsLocator.evaluateAll( - (imageElements) => - imageElements.length > 0 && - imageElements.every((element) => getComputedStyle(element).height.includes('px')), - ); - - expect(result).toBe(true); - await user - .sees(MessageList) - .isScrolledToBottom(`${USER1_CHAT_VIEW_CLASSNAME} ${selectors.messageListContainer}`); - }); }); diff --git a/e2e/fixtures.mjs b/e2e/fixtures.mjs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/e2e/jump-to-message.test.ts b/e2e/jump-to-message.test.ts index ce7994d494..6309732524 100644 --- a/e2e/jump-to-message.test.ts +++ b/e2e/jump-to-message.test.ts @@ -1,20 +1,16 @@ /* eslint-disable jest/expect-expect */ /* eslint-disable jest/no-done-callback */ /* eslint-disable jest/require-top-level-describe */ -import { expect } from '@playwright/test'; import { test } from './user/test'; -import MessageNotification from './user/components/MessageList/MessageNotification'; import Message from './user/components/Message/MessageSimple'; import QuotedMessage from './user/components/Message/QuotedMessage'; -import MessageList from './user/components/MessageList/MessageList'; const suiteArray = [ ['virtualized', 'jump-to-message--jump-in-virtualized-message-list'], ['regular', 'jump-to-message--jump-in-regular-message-list'], ]; -const controlsButtonSelector = 'data-testid=jump-to-message'; const onPageLoadWaitForMessage149 = 'data-testid=message-text-inner-wrapper >> text=Message 149'; suiteArray.forEach(([mode, story]) => { @@ -23,15 +19,6 @@ suiteArray.forEach(([mode, story]) => { await controller.openStory(story, onPageLoadWaitForMessage149); }); - test(`${mode} jumps to message 29 and then back to bottom`, async ({ page, user }) => { - const message29 = await user.sees(Message).not.displayed('Message 29'); - await page.click(controlsButtonSelector); - await expect(message29).toBeVisible(); - const message149 = await user.sees(Message).not.displayed('Message 149'); - await user.clicks(MessageNotification).text('Latest Messages'); - await expect(message149).toBeVisible(); - }); - test(`${mode} jumps to quoted message`, async ({ user }) => { const text = 'Message 20'; await user.clicks(QuotedMessage).nth(text); @@ -39,19 +26,3 @@ suiteArray.forEach(([mode, story]) => { }); }); }); - -test.describe('jump to message - dataset', () => { - test('only the current message set is loaded', async ({ controller, page, user }) => { - await controller.openStory( - 'jump-to-message--jump-in-regular-message-list', - onPageLoadWaitForMessage149, - ); - - await Promise.all([ - page.waitForSelector('text=Message 29'), - page.click(controlsButtonSelector), - ]); - - await user.sees(MessageList).hasLength(100 + 1); - }); -}); diff --git a/e2e/navigate-long-message-lists.test.ts b/e2e/navigate-long-message-lists.test.ts index 9e54062ff3..48d37bc8b3 100644 --- a/e2e/navigate-long-message-lists.test.ts +++ b/e2e/navigate-long-message-lists.test.ts @@ -71,25 +71,6 @@ test.describe('thread autoscroll', () => { await message.scrollIntoViewIfNeeded(); await expectToOpenThreadAndSeeLatestMessage(page, user, MESSAGES_WITH_REPLIES[1]); }); - - test('if I scroll primary message list by clicking a quoted message already loaded in state', async ({ - page, - user, - }) => { - await user.clicks(QuotedMessage).nth(QUOTED_MESSAGES[0]); - await expectToOpenThreadAndSeeLatestMessage(page, user, QUOTED_MESSAGES[0]); - }); - - test('if I scroll primary message list by clicking a quoted message that has to be loaded in state', async ({ - page, - user, - }) => { - await user.clicks(QuotedMessage).nth(QUOTED_MESSAGES[1], 2); - await Promise.all([ - page.waitForResponse((r) => r.url().includes('/messages') && r.ok()), - expectToOpenThreadAndSeeLatestMessage(page, user, QUOTED_MESSAGES[1]), - ]); - }); }); test.describe('on new message', () => { @@ -185,71 +166,4 @@ test.describe('scroll to the bottom', () => { .sees(MessageList) .isScrolledToBottom(`${USER1_CHAT_VIEW_CLASSNAME} ${selectors.messageListContainer}`); }); - - test('after loading more messages on new message notification click', async ({ - controller, - page, - user, - }) => { - // scroll without loading more messages - await scrollInSteps(user); - - // trigger load more messages - const firstLoadedMessage = await page.locator( - `${USER1_CHAT_VIEW_CLASSNAME} ${selectors.messageListContainer} li:first-of-type`, - ); - await firstLoadedMessage.scrollIntoViewIfNeeded(); - await controller.sendOtherUserMessage(); - - // click the notification - await page.waitForSelector(getMessageNotificationSelector(NEW_MESSAGE_NOTIFICATION_TEXT)); - await user.clicks(MessageNotification).text(NEW_MESSAGE_NOTIFICATION_TEXT); - - // check that you are at the bottom - await user - .sees(MessageList) - .isScrolledToBottom(`${USER1_CHAT_VIEW_CLASSNAME} ${selectors.messageListContainer}`); - }); -}); - -test.describe('pagination', () => { - test.beforeEach(async ({ controller, user }) => { - await controller.openStory( - 'navigate-long-message-lists--user1', - selectors.channelPreviewButton, - ); - await user.clicks(ChannelPreview).text(CHANNEL_NAME); - }); - - test('does not lead to the viewport content change', async ({ page, user }) => { - const messageList = await page.locator(`${USER1_CHAT_VIEW_CLASSNAME} ${selectors.messageList}`); - - const firstMessageFirstPage = await user.get(Message)(FIRST_MESSAGE_FIRST_PAGE); - - let firstLoadedMessageBoxBeforePagination; - const msgListBoxBeforePagination = await messageList.boundingBox(); - - // get message position before the next page of messages is received - page.once('request', async () => { - firstLoadedMessageBoxBeforePagination = await firstMessageFirstPage.boundingBox(); - }); - - await Promise.all([ - page.waitForResponse((r) => r.url().includes('/query') && r.ok()), - firstMessageFirstPage.scrollIntoViewIfNeeded(), - ]); - - const msgListBoxAfterPagination = await messageList.boundingBox(); - const firstLoadedMessageBoxAfterPagination = await firstMessageFirstPage.boundingBox(); - - const firstMessageShiftDistanceYToViewport = - firstLoadedMessageBoxBeforePagination.y - firstLoadedMessageBoxAfterPagination.y; - expect(firstMessageShiftDistanceYToViewport).toBeLessThanOrEqual( - firstLoadedMessageBoxBeforePagination.height, - ); - expect(firstMessageShiftDistanceYToViewport).toBeGreaterThanOrEqual( - -firstLoadedMessageBoxBeforePagination.height, - ); - expect(msgListBoxBeforePagination.height).not.toStrictEqual(msgListBoxAfterPagination.height); - }); }); diff --git a/e2e/user/components/Message/MessageSimple.ts b/e2e/user/components/Message/MessageSimple.ts index 3133838fdc..7dbb168397 100644 --- a/e2e/user/components/Message/MessageSimple.ts +++ b/e2e/user/components/Message/MessageSimple.ts @@ -35,7 +35,7 @@ export default (page: Page) => ({ not: { async displayed(text?: string, nth?: number) { const target = getMessage(page, text, nth); - await expect(target).not.toBeVisible(); + await expect(target).not.toBeInViewport(); return target; }, }, diff --git a/package.json b/package.json index 583b4351ee..904d72a153 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "@emoji-mart/data": "^1.1.2", "@emoji-mart/react": "^1.1.1", "@ladle/react": "^0.16.0", - "@playwright/test": "^1.29.1", + "@playwright/test": "^1.42.1", "@rollup/plugin-babel": "^5.2.1", "@rollup/plugin-commonjs": "^23.0.2", "@rollup/plugin-image": "^2.1.1", diff --git a/playwright.config.ts b/playwright.config.ts index 3df0acb5f3..434d9b2fca 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -7,21 +7,20 @@ const config: PlaywrightTestConfig = { maxDiffPixels: 100, }, }, + maxFailures: 1, retries: 2, testDir: './e2e', - timeout: 15 * 1000, use: { headless: true, screenshot: 'only-on-failure', viewport: { height: 920, width: 1280 }, }, webServer: { - command: 'ladle serve --open none', + command: 'npx ladle serve --open none', port: 61000, reuseExistingServer: !process.env.CI, timeout: 120 * 1000, }, - workers: 1, }; diff --git a/yarn.lock b/yarn.lock index 41b60a47f9..5396391fe3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1927,13 +1927,12 @@ dependencies: "@octokit/openapi-types" "^16.0.0" -"@playwright/test@^1.29.1": - version "1.29.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.29.1.tgz#f2ed4dc143b9c7825a7ad2703b2f1ac4354e1145" - integrity sha512-iQxk2DX5U9wOGV3+/Jh9OHPsw5H3mleUL2S4BgQuwtlAfK3PnKvn38m4Rg9zIViGHVW24opSm99HQm/UFLEy6w== +"@playwright/test@^1.42.1": + version "1.42.1" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.42.1.tgz#9eff7417bcaa770e9e9a00439e078284b301f31c" + integrity sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ== dependencies: - "@types/node" "*" - playwright-core "1.29.1" + playwright "1.42.1" "@pnpm/network.ca-file@^1.0.1": version "1.0.2" @@ -6880,6 +6879,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + fsevents@^1.2.7: version "1.2.13" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" @@ -11525,10 +11529,19 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" -playwright-core@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.29.1.tgz#9ec15d61c4bd2f386ddf6ce010db53a030345a47" - integrity sha512-20Ai3d+lMkWpI9YZYlxk8gxatfgax5STW8GaMozAHwigLiyiKQrdkt7gaoT9UQR8FIVDg6qVXs9IoZUQrDjIIg== +playwright-core@1.42.1: + version "1.42.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.42.1.tgz#13c150b93c940a3280ab1d3fbc945bc855c9459e" + integrity sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA== + +playwright@1.42.1: + version "1.42.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.42.1.tgz#79c828b51fe3830211137550542426111dc8239f" + integrity sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg== + dependencies: + playwright-core "1.42.1" + optionalDependencies: + fsevents "2.3.2" portfinder@^1.0.26: version "1.0.32"