test: migrate apps folder to playwright (#1201)

This commit is contained in:
Rıdvan Akca
2023-08-09 18:38:49 +03:00
committed by Rıdvan Akca
parent 1c8e9fac7c
commit 69297c2dd8
12 changed files with 161 additions and 38 deletions

View File

@@ -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

View File

@@ -2,3 +2,4 @@ node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
/output

View File

@@ -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 });
}
}

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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"
}
}

View File

@@ -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,
// },
});

View File

@@ -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();
});
});
});

View File

@@ -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/);
});

View File

@@ -101,7 +101,9 @@ export default function AddNewAppConnection(
</InputAdornment>
}
label={formatMessage('apps.searchApp')}
data-test="search-for-app-text-field"
inputProps={{
'data-test': 'search-for-app-text-field',
}}
/>
</FormControl>
</Box>
@@ -109,7 +111,10 @@ export default function AddNewAppConnection(
<DialogContent>
<List sx={{ pt: 2, width: '100%' }}>
{loading && (
<CircularProgress sx={{ display: 'block', margin: '20px auto' }} />
<CircularProgress
data-test="search-for-app-loader"
sx={{ display: 'block', margin: '20px auto' }}
/>
)}
{!loading &&

View File

@@ -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,
}}
/>
)}
/>

View File

@@ -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"