@tramvai/test-pw 3.4.1 → 3.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,50 +6,92 @@ Set of helpers for using [playwright](https://playwright.dev) in the integration
6
6
 
7
7
  ## Installation
8
8
 
9
- ```bash
10
- npm i --save-dev @tramvai/test-pw
9
+ ```bash npm2yarn
10
+ npm install --save-dev @tramvai/test-pw
11
11
  ```
12
12
 
13
- ## How To
13
+ ## Usage
14
14
 
15
- ### Tests in browser
15
+ ### Configuration
16
16
 
17
- `Playwright` runs tests in headless Chrome browser, documentation can be found on [official site](https://pptr.dev/)
17
+ Create file `playwright.config.ts` with defaults from `@tramvai/test-pw` package:
18
+
19
+ ```ts title="playwright.config.ts"
20
+ import { createPlaywrightConfig } from '@tramvai/test-pw';
21
+
22
+ export default createPlaywrightConfig();
23
+ ```
24
+
25
+ You can always extend default config, here is `createPlaywrightConfig` type definition:
18
26
 
19
27
  ```ts
20
- import { startCli } from '@tramvai/test-integration';
21
- import { initPlaywright, wrapPlaywrightPage } from '@tramvai/test-pw';
28
+ // passed configuration object will be merged with defaults
29
+ type createPlaywrightConfig = (config: PlaywrightTestConfig) => PlaywrightTestConfig;
30
+ ```
22
31
 
23
- beforeAll(async () => {
24
- app = await startCli('bootstrap', {
25
- env: {
26
- SOME_ENV: 'test',
27
- },
28
- });
29
- }, 80000);
32
+ ### Testing
30
33
 
31
- afterAll(() => {
32
- return app.close();
33
- });
34
+ :::tip
35
+
36
+ Use case for this section and `startAppFixture` - monorepo with many tramvai modules and example applications, where you need to test independent features.
37
+
38
+ All usage of `startAppFixture` in different workers will run development build, which might not be optimal for tests execution time, if you want to test the same app in different cases.
39
+
40
+ For real applications, prefer to run application once as [web server](https://playwright.dev/docs/test-webserver) or manually and pass `baseUrl` after.
34
41
 
35
- it('Playwright', async () => {
36
- const { browser } = await initPlaywright(app.serverUrl);
42
+ :::
37
43
 
38
- const page = await browser.newPage();
39
- const wrapper = wrapPlaywrightPage(page);
44
+ `@tramvai/test-pw` provide a useful fixture for application start (local server in development mode) and testing - `startAppFixture`. This fixture use `startCli` method from [@tramvai/test-integration](references/tramvai/test/integration.md) package.
40
45
 
41
- await page.goto(app.serverUrl);
46
+ First, you need to add and configure this fixture for application tests:
42
47
 
43
- expect(
44
- await page.$eval('.application', (node) => (node as HTMLElement).innerText)
45
- ).toMatchInlineSnapshot(`"Main Page click link"`);
48
+ ```ts title="__integration__/test-fixture.ts"
49
+ import path from 'path';
50
+ import { test as base } from '@playwright/test';
51
+ import type { StartAppTypes } from '@tramvai/test-pw';
52
+ import { startAppFixture } from '@tramvai/test-pw';
46
53
 
47
- await wrapper.router.navigate('./second');
54
+ type TestFixture = {};
48
55
 
49
- expect(
50
- await page.$eval('.application', (node) => (node as HTMLElement).innerText)
51
- ).toMatchInlineSnapshot(`"Second Page click link"`);
56
+ type WorkerFixture = {
57
+ app: StartAppTypes.TestApp;
58
+ appTarget: StartAppTypes.AppTarget;
59
+ startOptions: StartAppTypes.StartOptions;
60
+ };
52
61
 
53
- await browser.close();
62
+ export const test = base.extend<TestFixture, WorkerFixture>({
63
+ appTarget: [
64
+ // provide application name and directory
65
+ {
66
+ target: 'appName',
67
+ cwd: path.resolve(__dirname, '..'),
68
+ },
69
+ { scope: 'worker', auto: true, option: true },
70
+ ],
71
+ // any `startCli` parameters
72
+ startOptions: [{
73
+ env: {
74
+ SOME_MOCKED_API: 'xxx'
75
+ },
76
+ }, { scope: 'worker', auto: true, option: true }],
77
+
78
+ app: startAppFixture,
79
+ });
80
+ ```
81
+
82
+ Then, use the `app` object in integration tests:
83
+
84
+ ```ts title="__integration__/appName.integration.ts"
85
+ import { expect } from '@playwright/test';
86
+ import { test } from './test-fixture';
87
+
88
+ test.describe('examples/app', async () => {
89
+ test('Navigation is visible', async ({ app, page }) => {
90
+ await page.goto(app.serverUrl);
91
+
92
+ expect(page.getByRole('navigation')).toBeVisible();
93
+ });
54
94
  });
55
95
  ```
96
+
97
+ You can find more info about `app` object in our [Testing Guide](guides/testing.md#integration-tests)
@@ -0,0 +1,3 @@
1
+ import type { PlaywrightTestConfig } from '@playwright/test';
2
+ export declare const createPlaywrightConfig: (userConfig?: Partial<PlaywrightTestConfig>) => PlaywrightTestConfig & Partial<PlaywrightTestConfig>;
3
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,34 @@
1
+ import mergeDeep from '@tinkoff/utils/object/mergeDeep';
2
+ import { devices } from 'playwright-core';
3
+ import envCi from 'env-ci';
4
+
5
+ const ciInfo = envCi();
6
+ const config = {
7
+ testDir: '.',
8
+ testMatch: /.*\.(integration)\.(js|ts)/,
9
+ fullyParallel: true,
10
+ retries: ciInfo.isCi ? 2 : 0,
11
+ workers: 1,
12
+ reporter: [['list'], ['html', { open: 'never' }]],
13
+ use: {
14
+ video: 'on-first-retry',
15
+ screenshot: 'only-on-failure',
16
+ trace: ciInfo.isCi ? 'retain-on-failure' : 'on',
17
+ launchOptions: {
18
+ executablePath: process.env.PLAYWRIGHT_EXECUTABLE_PATH,
19
+ },
20
+ },
21
+ projects: [
22
+ {
23
+ name: 'chromium',
24
+ use: {
25
+ ...devices['Desktop Chrome'],
26
+ },
27
+ },
28
+ ],
29
+ };
30
+ const createPlaywrightConfig = (userConfig = {}) => {
31
+ return mergeDeep({}, config, userConfig);
32
+ };
33
+
34
+ export { createPlaywrightConfig };
package/lib/config.js ADDED
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var mergeDeep = require('@tinkoff/utils/object/mergeDeep');
6
+ var playwrightCore = require('playwright-core');
7
+ var envCi = require('env-ci');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ var mergeDeep__default = /*#__PURE__*/_interopDefaultLegacy(mergeDeep);
12
+ var envCi__default = /*#__PURE__*/_interopDefaultLegacy(envCi);
13
+
14
+ const ciInfo = envCi__default["default"]();
15
+ const config = {
16
+ testDir: '.',
17
+ testMatch: /.*\.(integration)\.(js|ts)/,
18
+ fullyParallel: true,
19
+ retries: ciInfo.isCi ? 2 : 0,
20
+ workers: 1,
21
+ reporter: [['list'], ['html', { open: 'never' }]],
22
+ use: {
23
+ video: 'on-first-retry',
24
+ screenshot: 'only-on-failure',
25
+ trace: ciInfo.isCi ? 'retain-on-failure' : 'on',
26
+ launchOptions: {
27
+ executablePath: process.env.PLAYWRIGHT_EXECUTABLE_PATH,
28
+ },
29
+ },
30
+ projects: [
31
+ {
32
+ name: 'chromium',
33
+ use: {
34
+ ...playwrightCore.devices['Desktop Chrome'],
35
+ },
36
+ },
37
+ ],
38
+ };
39
+ const createPlaywrightConfig = (userConfig = {}) => {
40
+ return mergeDeep__default["default"]({}, config, userConfig);
41
+ };
42
+
43
+ exports.createPlaywrightConfig = createPlaywrightConfig;
@@ -0,0 +1,33 @@
1
+ import type { WorkerFixture } from '@playwright/test';
2
+ import type { StartCliOptions, StartCliResult } from '@tramvai/test-integration';
3
+ import type { ApplicationConfigEntry, ConvertToSchema } from '@tramvai/cli';
4
+ export declare namespace StartAppTypes {
5
+ type TestApp = StartCliResult;
6
+ type AppTarget = {
7
+ name: string;
8
+ cwd: string;
9
+ config?: Partial<ConvertToSchema<ApplicationConfigEntry>>;
10
+ } | {
11
+ target: string;
12
+ cwd: string;
13
+ name?: string;
14
+ };
15
+ type StartOptions = StartCliOptions;
16
+ }
17
+ /**
18
+ * Фикстура запускает приложение с помощью метода `startCli` из `@tramvai/test-integration`
19
+ * @param appTarget указывает какое приложение запускать (может как указывать на существующее приложение с tramvai.json конфигом так и принимать полный конфиг)
20
+ * @param startOptions дополнительные параметры метода `startCli` (например env переменные для запущенного приложения)
21
+ * @returns возвращает свойства приложения (например адрес запущенного сервера на локалхосте) и удобные тестовые методы (например обертки над papi и superagent)
22
+ */
23
+ export declare const startAppFixture: [
24
+ WorkerFixture<StartAppTypes.TestApp, {
25
+ appTarget: StartAppTypes.AppTarget;
26
+ startOptions: StartAppTypes.StartOptions;
27
+ }>,
28
+ {
29
+ scope: 'worker';
30
+ timeout: number;
31
+ }
32
+ ];
33
+ //# sourceMappingURL=start-app.d.ts.map
@@ -0,0 +1,38 @@
1
+ import mergeDeep from '@tinkoff/utils/object/mergeDeep';
2
+ import path from 'path';
3
+ import { startCli } from '@tramvai/test-integration';
4
+
5
+ /**
6
+ * Фикстура запускает приложение с помощью метода `startCli` из `@tramvai/test-integration`
7
+ * @param appTarget указывает какое приложение запускать (может как указывать на существующее приложение с tramvai.json конфигом так и принимать полный конфиг)
8
+ * @param startOptions дополнительные параметры метода `startCli` (например env переменные для запущенного приложения)
9
+ * @returns возвращает свойства приложения (например адрес запущенного сервера на локалхосте) и удобные тестовые методы (например обертки над papi и superagent)
10
+ */
11
+ const startAppFixture = [
12
+ async ({ appTarget, startOptions }, use) => {
13
+ var _a;
14
+ let app;
15
+ try {
16
+ app = await startCli('target' in appTarget
17
+ ? appTarget.target
18
+ : mergeDeep(appTarget.config, {
19
+ name: appTarget.name,
20
+ type: 'application',
21
+ root: appTarget.cwd,
22
+ }), {
23
+ ...startOptions,
24
+ rootDir: (_a = appTarget.cwd) !== null && _a !== void 0 ? _a : path.dirname(path.resolve(module.parent.filename, '.')),
25
+ });
26
+ await use(app);
27
+ await app.close();
28
+ }
29
+ catch (error) {
30
+ console.error(`startApp fixture failed:`, error);
31
+ await (app === null || app === void 0 ? void 0 : app.close());
32
+ throw error;
33
+ }
34
+ },
35
+ { scope: 'worker', timeout: 60000 },
36
+ ];
37
+
38
+ export { startAppFixture };
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var mergeDeep = require('@tinkoff/utils/object/mergeDeep');
6
+ var path = require('path');
7
+ var testIntegration = require('@tramvai/test-integration');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ var mergeDeep__default = /*#__PURE__*/_interopDefaultLegacy(mergeDeep);
12
+ var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
13
+
14
+ /**
15
+ * Фикстура запускает приложение с помощью метода `startCli` из `@tramvai/test-integration`
16
+ * @param appTarget указывает какое приложение запускать (может как указывать на существующее приложение с tramvai.json конфигом так и принимать полный конфиг)
17
+ * @param startOptions дополнительные параметры метода `startCli` (например env переменные для запущенного приложения)
18
+ * @returns возвращает свойства приложения (например адрес запущенного сервера на локалхосте) и удобные тестовые методы (например обертки над papi и superagent)
19
+ */
20
+ const startAppFixture = [
21
+ async ({ appTarget, startOptions }, use) => {
22
+ var _a;
23
+ let app;
24
+ try {
25
+ app = await testIntegration.startCli('target' in appTarget
26
+ ? appTarget.target
27
+ : mergeDeep__default["default"](appTarget.config, {
28
+ name: appTarget.name,
29
+ type: 'application',
30
+ root: appTarget.cwd,
31
+ }), {
32
+ ...startOptions,
33
+ rootDir: (_a = appTarget.cwd) !== null && _a !== void 0 ? _a : path__default["default"].dirname(path__default["default"].resolve(module.parent.filename, '.')),
34
+ });
35
+ await use(app);
36
+ await app.close();
37
+ }
38
+ catch (error) {
39
+ console.error(`startApp fixture failed:`, error);
40
+ await (app === null || app === void 0 ? void 0 : app.close());
41
+ throw error;
42
+ }
43
+ },
44
+ { scope: 'worker', timeout: 60000 },
45
+ ];
46
+
47
+ exports.startAppFixture = startAppFixture;
package/lib/index.d.ts CHANGED
@@ -3,4 +3,6 @@ export * from './constants';
3
3
  export { initPlaywright } from './launch';
4
4
  export { wrapPlaywrightPage } from './wrapper';
5
5
  export * from './utils';
6
+ export { createPlaywrightConfig } from './config';
7
+ export { startAppFixture, StartAppTypes } from './fixtures/start-app';
6
8
  //# sourceMappingURL=index.d.ts.map
package/lib/index.es.js CHANGED
@@ -3,3 +3,5 @@ export { PLAYWRIGHT_DEFAULT_LAUNCH_OPTIONS } from './constants.es.js';
3
3
  export { initPlaywright } from './launch.es.js';
4
4
  export { wrapPlaywrightPage } from './wrapper.es.js';
5
5
  export { waitHydrated } from './utils.es.js';
6
+ export { createPlaywrightConfig } from './config.es.js';
7
+ export { startAppFixture } from './fixtures/start-app.es.js';
package/lib/index.js CHANGED
@@ -7,6 +7,8 @@ var constants = require('./constants.js');
7
7
  var launch = require('./launch.js');
8
8
  var wrapper = require('./wrapper.js');
9
9
  var utils = require('./utils.js');
10
+ var config = require('./config.js');
11
+ var startApp = require('./fixtures/start-app.js');
10
12
 
11
13
 
12
14
 
@@ -14,6 +16,8 @@ exports.PLAYWRIGHT_DEFAULT_LAUNCH_OPTIONS = constants.PLAYWRIGHT_DEFAULT_LAUNCH_
14
16
  exports.initPlaywright = launch.initPlaywright;
15
17
  exports.wrapPlaywrightPage = wrapper.wrapPlaywrightPage;
16
18
  exports.waitHydrated = utils.waitHydrated;
19
+ exports.createPlaywrightConfig = config.createPlaywrightConfig;
20
+ exports.startAppFixture = startApp.startAppFixture;
17
21
  Object.keys(playwrightCore).forEach(function (k) {
18
22
  if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
19
23
  enumerable: true,
package/lib/launch.d.ts CHANGED
@@ -4,6 +4,9 @@ type PWOptions = Parameters<typeof chromium.launch>[0];
4
4
  type Options = PWOptions & {
5
5
  enableLogging?: boolean;
6
6
  };
7
+ /**
8
+ * @deprecated - use Playwright directly or with `startAppFixture`
9
+ */
7
10
  export declare const initPlaywright: (serverUrl: string, { enableLogging, ...options }?: Options) => Promise<{
8
11
  browser: Browser;
9
12
  getPageWrapper: (url?: string) => Promise<{
package/lib/launch.es.js CHANGED
@@ -19,6 +19,9 @@ const enableBrowserLogger = async ({ browser, serverUrl, }) => {
19
19
  });
20
20
  await page.close();
21
21
  };
22
+ /**
23
+ * @deprecated - use Playwright directly or with `startAppFixture`
24
+ */
22
25
  const initPlaywright = async (serverUrl, { enableLogging = true, ...options } = {}) => {
23
26
  const browser = await chromium.launch({
24
27
  ...PLAYWRIGHT_DEFAULT_LAUNCH_OPTIONS,
package/lib/launch.js CHANGED
@@ -23,6 +23,9 @@ const enableBrowserLogger = async ({ browser, serverUrl, }) => {
23
23
  });
24
24
  await page.close();
25
25
  };
26
+ /**
27
+ * @deprecated - use Playwright directly or with `startAppFixture`
28
+ */
26
29
  const initPlaywright = async (serverUrl, { enableLogging = true, ...options } = {}) => {
27
30
  const browser = await playwrightCore.chromium.launch({
28
31
  ...constants.PLAYWRIGHT_DEFAULT_LAUNCH_OPTIONS,
package/lib/wrapper.d.ts CHANGED
@@ -2,6 +2,9 @@ import type { Page } from 'playwright-core';
2
2
  declare global {
3
3
  var nativeConsole: typeof console;
4
4
  }
5
+ /**
6
+ * @deprecated - use Playwright directly or with `startAppFixture`
7
+ */
5
8
  export declare const wrapPlaywrightPage: (page: Page) => {
6
9
  page: Page;
7
10
  reset: (url?: string) => Promise<import("playwright-core").Response | null>;
package/lib/wrapper.es.js CHANGED
@@ -14,6 +14,9 @@ const checkSsrErrors = (text) => {
14
14
  };
15
15
  const format = consoleWithStyle((stderr && stderr.level) || 0);
16
16
  const { nativeConsole } = global;
17
+ /**
18
+ * @deprecated - use Playwright directly or with `startAppFixture`
19
+ */
17
20
  const wrapPlaywrightPage = (page) => {
18
21
  if (page.url() && page.url() !== 'about:blank') {
19
22
  throw new Error(`You should wrap blank page before navigation, but page already has url "${page.url()}"`);
package/lib/wrapper.js CHANGED
@@ -22,6 +22,9 @@ const checkSsrErrors = (text) => {
22
22
  };
23
23
  const format = consoleWithStyle__default["default"]((supportsColor.stderr && supportsColor.stderr.level) || 0);
24
24
  const { nativeConsole } = global;
25
+ /**
26
+ * @deprecated - use Playwright directly or with `startAppFixture`
27
+ */
25
28
  const wrapPlaywrightPage = (page) => {
26
29
  if (page.url() && page.url() !== 'about:blank') {
27
30
  throw new Error(`You should wrap blank page before navigation, but page already has url "${page.url()}"`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/test-pw",
3
- "version": "3.4.1",
3
+ "version": "3.4.6",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -18,10 +18,11 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@tinkoff/utils": "^2.1.2",
21
- "@tramvai/test-integration": "3.4.1",
22
- "@tramvai/tokens-router": "3.4.1",
21
+ "@tramvai/test-integration": "3.4.6",
22
+ "@tramvai/tokens-router": "3.4.6",
23
23
  "console-with-style": "^1.1.0",
24
24
  "supports-color": "8.1.1",
25
+ "env-ci": "^5.0.2",
25
26
  "tslib": "^2.4.0"
26
27
  },
27
28
  "peerDependencies": {
@@ -29,6 +30,9 @@
29
30
  },
30
31
  "devDependencies": {
31
32
  "@types/supports-color": "^8.1.1",
33
+ "@types/env-ci": "^3.1.0",
34
+ "@tramvai/cli": "3.4.6",
35
+ "@playwright/test": "1.29.0",
32
36
  "playwright-core": "1.29.0"
33
37
  },
34
38
  "license": "Apache-2.0",