Setup Playwright #14
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.vscode/*
|
||||
node_modules
|
||||
**/.env
|
||||
845
package-lock.json
generated
845
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,8 @@
|
||||
"version": "1.0.0",
|
||||
"workspaces": [
|
||||
"api",
|
||||
"client"
|
||||
"client",
|
||||
"tests"
|
||||
],
|
||||
"scripts": {
|
||||
"format": "prettier --write \"**/src/**/*.ts\" \"**/test/**/*.ts\"",
|
||||
|
||||
0
tests/cucumber.mjs
Normal file
0
tests/cucumber.mjs
Normal file
30
tests/e2e/support/config.ts
Normal file
30
tests/e2e/support/config.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { LaunchOptions, devices } from '@playwright/test';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config({ path: '.env' });
|
||||
|
||||
const browserOptions: LaunchOptions = {
|
||||
headless: Boolean(process.env.HEADLESS) || false,
|
||||
timeout: Number(process.env.TIMEOUT) || 60000,
|
||||
args: [
|
||||
'--use-fake-ui-for-media-stream',
|
||||
'--use-fake-device-for-media-stream'
|
||||
],
|
||||
firefoxUserPrefs: {
|
||||
'media.navigator.streams.fake': true,
|
||||
'media.navigator.permission.disable': true
|
||||
},
|
||||
slowMo: Number(process.env.SLO_MO) || 0
|
||||
};
|
||||
const desktopChrome = devices['Desktop Chrome'];
|
||||
|
||||
export const config = {
|
||||
browser: process.env.BROWSER || 'chromium',
|
||||
browserOptions,
|
||||
baseUrl: process.env.BASE_URL || 'http://localhost:3000',
|
||||
username: process.env.TEST_USERNAME,
|
||||
password: process.env.TEST_PASSWORD,
|
||||
viewportHeight: process.env.VIEWPORT_HEIGHT || desktopChrome.viewport.height,
|
||||
viewportWidth: process.env.VIEWPORT_WIDTH || desktopChrome.viewport.width,
|
||||
userAgent: process.env.USER_AGENT || desktopChrome.userAgent
|
||||
};
|
||||
121
tests/e2e/support/hooks.ts
Normal file
121
tests/e2e/support/hooks.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { ICustomWorld } from './world';
|
||||
import { config } from './config';
|
||||
import {
|
||||
After,
|
||||
AfterAll,
|
||||
Before,
|
||||
BeforeAll,
|
||||
Status,
|
||||
setDefaultTimeout
|
||||
} from '@cucumber/cucumber';
|
||||
import {
|
||||
chromium,
|
||||
ChromiumBrowser,
|
||||
firefox,
|
||||
FirefoxBrowser,
|
||||
webkit,
|
||||
WebKitBrowser,
|
||||
ConsoleMessage,
|
||||
ViewportSize
|
||||
} from '@playwright/test';
|
||||
import { ITestCaseHookParameter } from '@cucumber/cucumber/lib/support_code_library_builder/types';
|
||||
import { ensureDir } from 'fs-extra';
|
||||
|
||||
const tracesDir = './e2e/results/traces';
|
||||
let browser: ChromiumBrowser | FirefoxBrowser | WebKitBrowser;
|
||||
|
||||
declare global {
|
||||
let browser: ChromiumBrowser | FirefoxBrowser | WebKitBrowser;
|
||||
}
|
||||
|
||||
setDefaultTimeout(process.env.PWDEBUG ? -1 : 60 * 100);
|
||||
|
||||
BeforeAll(async function () {
|
||||
switch (config.browser) {
|
||||
case 'firefox': {
|
||||
browser = await firefox.launch(config.browserOptions);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'webkit': {
|
||||
browser = await webkit.launch(config.browserOptions);
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
browser = await chromium.launch(config.browserOptions);
|
||||
}
|
||||
}
|
||||
|
||||
await ensureDir(tracesDir);
|
||||
});
|
||||
|
||||
Before({ tags: '@ignore' }, async function () {
|
||||
return 'skipped' as any;
|
||||
});
|
||||
|
||||
Before({ tags: '@debug' }, async function (this: ICustomWorld) {
|
||||
this.debug = true;
|
||||
});
|
||||
|
||||
Before(async function (this: ICustomWorld, { pickle }: ITestCaseHookParameter) {
|
||||
const viewportSize: ViewportSize = {
|
||||
height: Number(1080),
|
||||
width: Number(1920)
|
||||
};
|
||||
|
||||
this.startTime = new Date();
|
||||
this.testName = pickle.name.replace(/\W/g, '-');
|
||||
this.context = await browser.newContext({
|
||||
acceptDownloads: true,
|
||||
viewport: viewportSize,
|
||||
userAgent: config.userAgent
|
||||
});
|
||||
|
||||
await this.context.tracing.start({
|
||||
screenshots: true,
|
||||
snapshots: true
|
||||
});
|
||||
|
||||
this.page = await this.context.newPage();
|
||||
this.page.on('console', async (msg: ConsoleMessage) => {
|
||||
if (msg.type() === 'log') {
|
||||
await this.attach(msg.text());
|
||||
}
|
||||
});
|
||||
this.feature = pickle;
|
||||
});
|
||||
|
||||
After(async function (this: ICustomWorld, { result }: ITestCaseHookParameter) {
|
||||
if (result) {
|
||||
await this.attach(
|
||||
`Status: ${result?.status}. Duration:${result.duration?.seconds}s`
|
||||
);
|
||||
|
||||
if (result.status !== Status.PASSED) {
|
||||
const image = await this.page?.screenshot({
|
||||
path: `./e2e/results/screenshots/${this.testName}.png`,
|
||||
type: 'png'
|
||||
});
|
||||
const timePart = this.startTime
|
||||
?.toISOString()
|
||||
.split('.')[0]
|
||||
.replace(/:/g, '_');
|
||||
|
||||
if (image) {
|
||||
await this.attach(image, 'image/png');
|
||||
}
|
||||
|
||||
await this.context?.tracing.stop({
|
||||
path: `${tracesDir}/${this.testName}-${timePart}trace.zip`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await this.page?.close();
|
||||
await this.context?.close();
|
||||
});
|
||||
|
||||
AfterAll(async function () {
|
||||
await browser.close();
|
||||
});
|
||||
0
tests/e2e/support/report.ts
Normal file
0
tests/e2e/support/report.ts
Normal file
33
tests/e2e/support/world.ts
Normal file
33
tests/e2e/support/world.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { setWorldConstructor, World, IWorldOptions } from '@cucumber/cucumber';
|
||||
import * as messages from '@cucumber/messages';
|
||||
import {
|
||||
BrowserContext,
|
||||
Page,
|
||||
PlaywrightTestOptions,
|
||||
APIRequestContext
|
||||
} from '@playwright/test';
|
||||
|
||||
export interface CucumberWorldConstructorParams {
|
||||
parameters: { [key: string]: string };
|
||||
}
|
||||
|
||||
export interface ICustomWorld extends World {
|
||||
debug: boolean;
|
||||
feature?: messages.Pickle;
|
||||
context?: BrowserContext;
|
||||
page?: Page;
|
||||
testName?: string;
|
||||
startTime?: Date;
|
||||
server?: APIRequestContext;
|
||||
playwrightOptions?: PlaywrightTestOptions;
|
||||
}
|
||||
|
||||
export class CustomWorld extends World implements ICustomWorld {
|
||||
constructor(options: IWorldOptions) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
debug = false;
|
||||
}
|
||||
|
||||
setWorldConstructor(CustomWorld);
|
||||
1665
tests/package-lock.json
generated
Normal file
1665
tests/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
tests/package.json
Normal file
17
tests/package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "tests",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@cucumber/cucumber": "^10.7.0",
|
||||
"@playwright/test": "^1.44.0",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"fs-extra": "^11.2.0"
|
||||
}
|
||||
}
|
||||
20
tests/tsconfig.json
Normal file
20
tests/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"typeRoots": ["../node_modules/@types"]
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user