@brillout/test-e2e 0.3.0 → 0.3.2

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/dist/Logs.d.ts CHANGED
@@ -6,8 +6,8 @@ export declare const Logs: {
6
6
  hasErrorLogs: typeof hasErrorLogs;
7
7
  flushEagerly: boolean;
8
8
  };
9
- declare type LogSource = 'stdout' | 'stderr' | 'Browser Error' | 'Browser Warning' | 'Browser Log' | 'Playwright' | 'run()' | 'run() failure' | 'test()' | 'Connection Error';
10
- declare type LogEntry = {
9
+ type LogSource = 'stdout' | 'stderr' | 'Browser Error' | 'Browser Warning' | 'Browser Log' | 'Playwright' | 'run()' | 'run() failure' | 'test()' | 'Connection Error';
10
+ type LogEntry = {
11
11
  logSource: LogSource;
12
12
  logText: string;
13
13
  logTimestamp: string;
package/dist/buildTs.js CHANGED
@@ -19,7 +19,7 @@ async function buildTs(entry, outfile) {
19
19
  format: 'esm',
20
20
  target: 'es2020',
21
21
  bundle: true,
22
- external: ['./node_modules/*', '@brillout/test-e2e'],
22
+ packages: 'external',
23
23
  minify: false,
24
24
  });
25
25
  {
@@ -1,9 +1,10 @@
1
+ /// <reference types="chai-subset" />
1
2
  export type { ChaiPlugin };
2
3
  export type { Expect };
3
4
  import type { use as chaiUse } from 'chai';
4
- declare type FirstFunctionArgument<T> = T extends (arg: infer A) => unknown ? A : never;
5
- declare type ChaiPlugin = FirstFunctionArgument<typeof chaiUse>;
6
- declare type Assertion = Chai.Assertion & {
5
+ type FirstFunctionArgument<T> = T extends (arg: infer A) => unknown ? A : never;
6
+ type ChaiPlugin = FirstFunctionArgument<typeof chaiUse>;
7
+ type Assertion = Chai.Assertion & {
7
8
  not: Assertion;
8
9
  toContain: Assertion['contain'];
9
10
  toMatch: Assertion['match'];
@@ -12,4 +13,4 @@ declare type Assertion = Chai.Assertion & {
12
13
  toBeTruthy(): void;
13
14
  toBee: Assertion['equal'];
14
15
  };
15
- declare type Expect = (value: any) => Assertion;
16
+ type Expect = (value: any) => Assertion;
@@ -1,6 +1,6 @@
1
1
  export { getConfig };
2
2
  export { loadConfig };
3
- declare type Config = {
3
+ type Config = {
4
4
  tolerateError?: Function;
5
5
  };
6
6
  declare function getConfig(): Config;
@@ -2,7 +2,7 @@ export { getCurrentTest };
2
2
  export { getCurrentTestOptional };
3
3
  export { setCurrentTest };
4
4
  import type { Page } from 'playwright-chromium';
5
- declare type TestInfo = {
5
+ type TestInfo = {
6
6
  testFile: string;
7
7
  testName: string;
8
8
  tests?: {
package/dist/index.d.ts CHANGED
@@ -2,3 +2,5 @@ export * from './setup';
2
2
  export { expect } from './chai/expect';
3
3
  export { test } from './test';
4
4
  export { page } from './page';
5
+ export { editFile, editFileRevert } from './editFile';
6
+ export { testScreenshotFixture } from './testScreenshotFixture';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.page = exports.test = exports.expect = void 0;
17
+ exports.testScreenshotFixture = exports.editFileRevert = exports.editFile = exports.page = exports.test = exports.expect = void 0;
18
18
  __exportStar(require("./setup"), exports);
19
19
  var expect_1 = require("./chai/expect");
20
20
  Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return expect_1.expect; } });
@@ -22,3 +22,8 @@ var test_1 = require("./test");
22
22
  Object.defineProperty(exports, "test", { enumerable: true, get: function () { return test_1.test; } });
23
23
  var page_1 = require("./page");
24
24
  Object.defineProperty(exports, "page", { enumerable: true, get: function () { return page_1.page; } });
25
+ var editFile_1 = require("./editFile");
26
+ Object.defineProperty(exports, "editFile", { enumerable: true, get: function () { return editFile_1.editFile; } });
27
+ Object.defineProperty(exports, "editFileRevert", { enumerable: true, get: function () { return editFile_1.editFileRevert; } });
28
+ var testScreenshotFixture_1 = require("./testScreenshotFixture");
29
+ Object.defineProperty(exports, "testScreenshotFixture", { enumerable: true, get: function () { return testScreenshotFixture_1.testScreenshotFixture; } });
package/dist/setup.d.ts CHANGED
@@ -14,7 +14,6 @@ export { isWindows };
14
14
  export { isMac };
15
15
  export { sleep };
16
16
  export { getServerUrl };
17
- export { editFile, editFileRevert } from './editFile';
18
17
  declare function skip(reason: string): void;
19
18
  declare function run(cmd: string, { additionalTimeout, serverIsReadyMessage, serverIsReadyDelay, inspect, cwd, doNotFailOnWarning, serverUrl, }?: {
20
19
  additionalTimeout?: number;
package/dist/setup.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.editFileRevert = exports.editFile = exports.getServerUrl = exports.sleep = exports.isMac = exports.isWindows = exports.isLinux = exports.isGithubAction = exports.isMinNodeVersion = exports.skip = exports.run = exports.expectError = exports.fetch = exports.fetchHtml = exports.autoRetry = exports.partRegex = void 0;
6
+ exports.getServerUrl = exports.sleep = exports.isMac = exports.isWindows = exports.isLinux = exports.isGithubAction = exports.isMinNodeVersion = exports.skip = exports.run = exports.expectError = exports.fetch = exports.fetchHtml = exports.autoRetry = exports.partRegex = void 0;
7
7
  const child_process_1 = require("child_process");
8
8
  const path_1 = require("path");
9
9
  const utils_1 = require("./utils");
@@ -23,9 +23,6 @@ var part_regex_1 = require("@brillout/part-regex");
23
23
  Object.defineProperty(exports, "partRegex", { enumerable: true, get: function () { return part_regex_1.partRegex; } });
24
24
  var Logs_2 = require("./Logs");
25
25
  Object.defineProperty(exports, "expectError", { enumerable: true, get: function () { return Logs_2.expectError; } });
26
- var editFile_2 = require("./editFile");
27
- Object.defineProperty(exports, "editFile", { enumerable: true, get: function () { return editFile_2.editFile; } });
28
- Object.defineProperty(exports, "editFileRevert", { enumerable: true, get: function () { return editFile_2.editFileRevert; } });
29
26
  const serverUrlDefault = 'http://localhost:3000';
30
27
  const TIMEOUT_NPM_SCRIPT = 2 * 60 * 1000;
31
28
  const TIMEOUT_TEST_FUNCTION = 60 * 1000 * (!(0, utils_1.isGithubAction)() ? 1 : (0, utils_1.isWindows)() ? 5 : 3);
@@ -0,0 +1,2 @@
1
+ export { testScreenshotFixture };
2
+ declare function testScreenshotFixture(): Promise<void>;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.testScreenshotFixture = void 0;
7
+ // Reference implementation: https://playwright.dev/docs/test-snapshots
8
+ const pixelmatch_1 = __importDefault(require("pixelmatch"));
9
+ const pngjs_1 = require("pngjs");
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const utils_1 = require("./utils");
13
+ const getCurrentTest_1 = require("./getCurrentTest");
14
+ const expect_1 = require("./chai/expect");
15
+ async function testScreenshotFixture() {
16
+ const { pngFixturPath, pngExpectPath, pngActualPath, pngDifferPath } = getPngPaths();
17
+ if (!fs_1.default.existsSync(pngFixturPath)) {
18
+ const pngActual = await takeScreenshot();
19
+ const fileContent = pngjs_1.PNG.sync.write(pngActual);
20
+ fs_1.default.writeFileSync(pngFixturPath, fileContent);
21
+ fs_1.default.writeFileSync(pngExpectPath, fileContent);
22
+ throw new Error([
23
+ 'Screenshot fixture missing. Screenshot fixture created at following paths:',
24
+ ` - ${pngFixturPath}`,
25
+ ` - ${pngExpectPath}`,
26
+ ].join('\n'));
27
+ }
28
+ const pngExpect = pngjs_1.PNG.sync.read(fs_1.default.readFileSync(pngFixturPath));
29
+ const pngActual = await takeScreenshot();
30
+ (0, expect_1.expect)(pngExpect.width).toBe(pngActual.width);
31
+ (0, expect_1.expect)(pngExpect.height).toBe(pngActual.height);
32
+ const { width, height } = pngExpect;
33
+ const pngDiffer = new pngjs_1.PNG({ width, height });
34
+ const numDiffPixels = (0, pixelmatch_1.default)(pngExpect.data, pngActual.data, pngDiffer.data, width, height, { threshold: 0.1 });
35
+ try {
36
+ (0, expect_1.expect)(numDiffPixels).toBe(0);
37
+ }
38
+ catch (err) {
39
+ {
40
+ console.log('Actual image written at', pngActualPath);
41
+ fs_1.default.writeFileSync(pngActualPath, pngjs_1.PNG.sync.write(pngActual));
42
+ }
43
+ {
44
+ console.log('Expect image written at', pngExpectPath);
45
+ fs_1.default.writeFileSync(pngExpectPath, pngjs_1.PNG.sync.write(pngExpect));
46
+ }
47
+ {
48
+ console.log('Differ image written at', pngDifferPath);
49
+ fs_1.default.writeFileSync(pngDifferPath, pngjs_1.PNG.sync.write(pngDiffer));
50
+ }
51
+ throw err;
52
+ }
53
+ }
54
+ exports.testScreenshotFixture = testScreenshotFixture;
55
+ async function takeScreenshot() {
56
+ const { page } = (0, getCurrentTest_1.getCurrentTest)();
57
+ (0, utils_1.assert)(page);
58
+ let screenshotCurr;
59
+ let screenshotPrev;
60
+ let attemps = 30;
61
+ while (attemps-- > 0) {
62
+ screenshotPrev = screenshotCurr;
63
+ screenshotCurr = pngjs_1.PNG.sync.read(await page.screenshot());
64
+ if (screenshotPrev) {
65
+ const { width, height } = screenshotCurr;
66
+ const numDiffPixels = (0, pixelmatch_1.default)(screenshotPrev.data, screenshotCurr.data, null, width, height, {
67
+ threshold: 0.1,
68
+ });
69
+ if (numDiffPixels === 0) {
70
+ return screenshotCurr;
71
+ }
72
+ }
73
+ await (0, utils_1.sleep)(300);
74
+ }
75
+ throw new Error("Couldn't take a stable screenshot. The UI seems to be continously changing.");
76
+ }
77
+ function getPngPaths() {
78
+ const cwd = getTestFileDir();
79
+ const pngFixturPath = path_1.default.join(cwd, './.test-screenshot-fixture.png');
80
+ const pngExpectPath = path_1.default.join(cwd, './test-screenshot-expect.png');
81
+ const pngActualPath = path_1.default.join(cwd, './test-screenshot-actual.png');
82
+ const pngDifferPath = path_1.default.join(cwd, './test-screenshot-differ.png');
83
+ return { pngFixturPath, pngExpectPath, pngActualPath, pngDifferPath };
84
+ }
85
+ function getTestFileDir() {
86
+ const { testFile, runInfo } = (0, getCurrentTest_1.getCurrentTest)();
87
+ const cwd = path_1.default.dirname(testFile);
88
+ (0, utils_1.assert)(runInfo.cwd === cwd);
89
+ return cwd;
90
+ }
@@ -1,7 +1,7 @@
1
1
  export { findFiles };
2
2
  export { findFilesParseCliArgs };
3
3
  export type { FindFilter };
4
- declare type FindFilter = {
4
+ type FindFilter = {
5
5
  terms: string[];
6
6
  exclude: boolean;
7
7
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brillout/test-e2e",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "bin": "./bin.js",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -15,11 +15,13 @@
15
15
  "dependencies": {
16
16
  "@brillout/part-regex": "^0.1.2",
17
17
  "chai": "^4.3.6",
18
- "esbuild": "^0.15.9",
18
+ "esbuild": "^0.16.5",
19
19
  "fast-glob": "^3.2.12",
20
20
  "node-fetch": "^2.6.1",
21
21
  "picocolors": "^1.0.0",
22
+ "pixelmatch": "^5.3.0",
22
23
  "playwright-chromium": "^1.22.2",
24
+ "pngjs": "^6.0.0",
23
25
  "source-map-support": "^0.5.21",
24
26
  "strip-ansi": "^6.0.1"
25
27
  },
@@ -27,6 +29,8 @@
27
29
  "@types/chai": "^4.3.3",
28
30
  "@types/node": "^15.6.1",
29
31
  "@types/node-fetch": "^2.5.12",
32
+ "@types/pixelmatch": "^5.2.4",
33
+ "@types/pngjs": "^6.0.1",
30
34
  "@types/source-map-support": "^0.5.6",
31
35
  "typescript": "^4.8.3"
32
36
  },