From 69297c2dd8cac55ea47b08a8207e0ea95395b4f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20Akca?= <43352493+ridvanakca@users.noreply.github.com> Date: Wed, 9 Aug 2023 18:38:49 +0300 Subject: [PATCH] test: migrate apps folder to playwright (#1201) --- .github/workflows/playwright.yml | 6 +- packages/e2e-tests/.gitignore | 1 + .../e2e-tests/fixtures/applications-page.js | 12 ++++ packages/e2e-tests/fixtures/base-page.js | 34 ++++++++++ packages/e2e-tests/fixtures/index.js | 9 +++ packages/e2e-tests/package.json | 6 +- packages/e2e-tests/playwright.config.js | 27 ++++---- .../e2e-tests/tests/apps/list-apps.spec.js | 66 +++++++++++++++++++ packages/e2e-tests/tests/example.spec.js | 19 ------ .../components/AddNewAppConnection/index.tsx | 9 ++- .../web/src/components/TextField/index.tsx | 5 ++ yarn.lock | 5 ++ 12 files changed, 161 insertions(+), 38 deletions(-) create mode 100644 packages/e2e-tests/fixtures/applications-page.js create mode 100644 packages/e2e-tests/fixtures/base-page.js create mode 100644 packages/e2e-tests/fixtures/index.js create mode 100644 packages/e2e-tests/tests/apps/list-apps.spec.js delete mode 100644 packages/e2e-tests/tests/example.spec.js diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 87b433e5..9e6fad51 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,9 +1,7 @@ name: Automatisch UI Test on: - push: - branches: [main] - pull_request: - branches: [main] + schedule: + - cron: '0 12 * * *' jobs: test: timeout-minutes: 60 diff --git a/packages/e2e-tests/.gitignore b/packages/e2e-tests/.gitignore index 75e854d8..16bda59e 100644 --- a/packages/e2e-tests/.gitignore +++ b/packages/e2e-tests/.gitignore @@ -2,3 +2,4 @@ node_modules/ /test-results/ /playwright-report/ /playwright/.cache/ +/output diff --git a/packages/e2e-tests/fixtures/applications-page.js b/packages/e2e-tests/fixtures/applications-page.js new file mode 100644 index 00000000..19934035 --- /dev/null +++ b/packages/e2e-tests/fixtures/applications-page.js @@ -0,0 +1,12 @@ +const path = require('node:path'); +const { BasePage } = require('./base-page'); + +export class ApplicationsPage extends BasePage { + async screenshot(options = {}) { + const { path: plainPath, ...restOptions } = options; + + const computedPath = path.join('applications', plainPath); + + return await super.screenshot({ path: computedPath, ...restOptions }); + } +} diff --git a/packages/e2e-tests/fixtures/base-page.js b/packages/e2e-tests/fixtures/base-page.js new file mode 100644 index 00000000..d6396184 --- /dev/null +++ b/packages/e2e-tests/fixtures/base-page.js @@ -0,0 +1,34 @@ +const path = require('node:path'); + +export class BasePage { + /** + * @param {import('@playwright/test').Page} page + */ + constructor(page) { + this.page = page; + } + + async clickAway() { + await this.page.locator('body').click({ position: { x: 0, y: 0 } }); + } + + async screenshot(options = {}) { + const { path: plainPath, ...restOptions } = options; + + const computedPath = path.join('output/screenshots', plainPath); + + return await this.page.screenshot({ path: computedPath, ...restOptions }); + } + + async login() { + await this.page.goto('/login'); + await this.page + .getByTestId('email-text-field') + .fill(process.env.LOGIN_EMAIL); + await this.page + .getByTestId('password-text-field') + .fill(process.env.LOGIN_PASSWORD); + + await this.page.getByTestId('login-button').click(); + } +} diff --git a/packages/e2e-tests/fixtures/index.js b/packages/e2e-tests/fixtures/index.js new file mode 100644 index 00000000..4c0aedbb --- /dev/null +++ b/packages/e2e-tests/fixtures/index.js @@ -0,0 +1,9 @@ +const base = require('@playwright/test'); +const { ApplicationsPage } = require('./applications-page'); + +exports.test = base.test.extend({ + applicationsPage: async ({ page }, use) => { + await use(new ApplicationsPage(page)); + }, +}); +exports.expect = base.expect; diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 873c1dca..e0fef4b7 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -5,7 +5,8 @@ "private": true, "description": "The open source Zapier alternative. Build workflow automation without spending time and money.", "scripts": { - "open": "cypress open" + "open": "cypress open", + "playwright": "playwright test" }, "contributors": [ { @@ -24,5 +25,8 @@ "devDependencies": { "@playwright/test": "^1.36.2", "cypress": "^10.9.0" + }, + "dependencies": { + "dotenv": "^16.3.1" } } diff --git a/packages/e2e-tests/playwright.config.js b/packages/e2e-tests/playwright.config.js index b15af2e1..4b7ef3e6 100644 --- a/packages/e2e-tests/playwright.config.js +++ b/packages/e2e-tests/playwright.config.js @@ -5,7 +5,7 @@ const { defineConfig, devices } = require('@playwright/test'); * Read environment variables from file. * https://github.com/motdotla/dotenv */ -// require('dotenv').config(); +require('dotenv').config(); /** * @see https://playwright.dev/docs/test-configuration @@ -21,14 +21,18 @@ module.exports = defineConfig({ /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'html', + reporter: process.env.CI ? 'github' : 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://127.0.0.1:3000', + baseURL: process.env.CI + ? 'https://sandbox.automatisch.io' + : 'http://localhost:3001', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', + testIdAttribute: 'data-test', + viewport: { width: 1280, height: 720 }, }, /* Configure projects for major browsers */ @@ -38,15 +42,15 @@ module.exports = defineConfig({ use: { ...devices['Desktop Chrome'] }, }, - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] }, + // }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, /* Test against mobile viewports. */ // { @@ -76,4 +80,3 @@ module.exports = defineConfig({ // reuseExistingServer: !process.env.CI, // }, }); - diff --git a/packages/e2e-tests/tests/apps/list-apps.spec.js b/packages/e2e-tests/tests/apps/list-apps.spec.js new file mode 100644 index 00000000..5b356733 --- /dev/null +++ b/packages/e2e-tests/tests/apps/list-apps.spec.js @@ -0,0 +1,66 @@ +const { test, expect } = require('../../fixtures/index'); + +test.describe('Apps page', () => { + test.beforeEach(async ({ page, applicationsPage }) => { + await applicationsPage.login(); + await page.getByTestId('apps-page-drawer-link').click(); + }); + + test('displays applications', async ({ page, applicationsPage }) => { + await page.getByTestId('apps-loader').waitFor({ + state: 'detached', + }); + await expect(page.getByTestId('app-row')).not.toHaveCount(0); + + await applicationsPage.screenshot({ + path: 'Applications.png', + }); + }); + + test.describe('can add connection', () => { + test.beforeEach(async ({ page }) => { + await expect(page.getByTestId('add-connection-button')).toBeVisible(); + await page.getByTestId('add-connection-button').click(); + await page + .getByTestId('search-for-app-loader') + .waitFor({ state: 'detached' }); + }); + + test('lists applications', async ({ page, applicationsPage }) => { + const appListItemCount = await page.getByTestId('app-list-item').count(); + expect(appListItemCount).toBeGreaterThan(10); + + await applicationsPage.clickAway(); + }); + + test('searches an application', async ({ page, applicationsPage }) => { + await page.getByTestId('search-for-app-text-field').fill('DeepL'); + await expect(page.getByTestId('app-list-item')).toHaveCount(1); + + await applicationsPage.clickAway(); + }); + + test('goes to app page to create a connection', async ({ + page, + applicationsPage, + }) => { + await page.getByTestId('app-list-item').first().click(); + await expect(page).toHaveURL('/app/deepl/connections/add'); + await expect(page.getByTestId('add-app-connection-dialog')).toBeVisible(); + + await applicationsPage.clickAway(); + }); + + test('closes the dialog on backdrop click', async ({ + page, + applicationsPage, + }) => { + await page.getByTestId('app-list-item').first().click(); + await expect(page).toHaveURL('/app/deepl/connections/add'); + await expect(page.getByTestId('add-app-connection-dialog')).toBeVisible(); + await applicationsPage.clickAway(); + await expect(page).toHaveURL('/app/deepl/connections'); + await expect(page.getByTestId('add-app-connection-dialog')).toBeHidden(); + }); + }); +}); diff --git a/packages/e2e-tests/tests/example.spec.js b/packages/e2e-tests/tests/example.spec.js deleted file mode 100644 index 6f0c5b5d..00000000 --- a/packages/e2e-tests/tests/example.spec.js +++ /dev/null @@ -1,19 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); - -test('has title', async ({ page }) => { - await page.goto('https://playwright.dev/'); - - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle(/Playwright/); -}); - -test('get started link', async ({ page }) => { - await page.goto('https://playwright.dev/'); - - // Click the get started link. - await page.getByRole('link', { name: 'Get started' }).click(); - - // Expects the URL to contain intro. - await expect(page).toHaveURL(/.*intro/); -}); diff --git a/packages/web/src/components/AddNewAppConnection/index.tsx b/packages/web/src/components/AddNewAppConnection/index.tsx index bbd95d86..694c80a1 100644 --- a/packages/web/src/components/AddNewAppConnection/index.tsx +++ b/packages/web/src/components/AddNewAppConnection/index.tsx @@ -101,7 +101,9 @@ export default function AddNewAppConnection( } label={formatMessage('apps.searchApp')} - data-test="search-for-app-text-field" + inputProps={{ + 'data-test': 'search-for-app-text-field', + }} /> @@ -109,7 +111,10 @@ export default function AddNewAppConnection( {loading && ( - + )} {!loading && diff --git a/packages/web/src/components/TextField/index.tsx b/packages/web/src/components/TextField/index.tsx index bec00d9b..6865d149 100644 --- a/packages/web/src/components/TextField/index.tsx +++ b/packages/web/src/components/TextField/index.tsx @@ -14,6 +14,7 @@ type TextFieldProps = { name: string; clickToCopy?: boolean; readOnly?: boolean; + 'data-test'?: string; } & MuiTextFieldProps; const createCopyAdornment = ( @@ -44,6 +45,7 @@ export default function TextField(props: TextFieldProps): React.ReactElement { disabled = false, onBlur, onChange, + 'data-test': dataTest, ...textFieldProps } = props; @@ -82,6 +84,9 @@ export default function TextField(props: TextFieldProps): React.ReactElement { readOnly, endAdornment: clickToCopy ? createCopyAdornment(inputRef) : null, }} + inputProps={{ + 'data-test': dataTest, + }} /> )} /> diff --git a/yarn.lock b/yarn.lock index fd4fe551..4d2f8971 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7971,6 +7971,11 @@ dotenv@^10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== +dotenv@^16.3.1: + version "16.3.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" + integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"