@brillout/test-e2e 0.4.13 → 0.4.15

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
@@ -13,13 +13,15 @@ declare type LogEntry = {
13
13
  logText: string;
14
14
  logTimestamp: string;
15
15
  isNotFailure: boolean;
16
+ loggedAfterExit: boolean;
16
17
  };
17
18
  declare function hasFailLogs(failOnWarning: boolean): boolean;
18
19
  declare function clearLogs(): void;
19
20
  declare function logErrorsAndWarnings(): void;
20
21
  declare function flushLogs(): void;
21
- declare function add({ logSource, logText }: {
22
+ declare function add({ logSource, logText, loggedAfterExit, }: {
22
23
  logSource: LogSource;
23
24
  logText: string;
25
+ loggedAfterExit?: boolean;
24
26
  }): void;
25
27
  declare function expectError(logFilter: (browserLog: LogEntry) => boolean): void;
package/dist/Logs.js CHANGED
@@ -22,15 +22,19 @@ function hasFailLogs(failOnWarning) {
22
22
  const failLogs = getErrorLogs(failOnWarning);
23
23
  return failLogs.length > 0;
24
24
  }
25
- function getErrorLogs(returnWarnings) {
26
- const errorLogs = logEntries.filter(({ logSource, isNotFailure }) => {
25
+ function getErrorLogs(includeWarnings) {
26
+ const errorLogs = logEntries.filter(({ logSource, isNotFailure, loggedAfterExit }) => {
27
27
  if (isNotFailure) {
28
- return;
28
+ return false;
29
+ }
30
+ // taskkill makes process exit with exit code `1` which makes npm emit logs on stderr
31
+ if (loggedAfterExit && (0, utils_1.isWindows)() && logSource === 'stderr') {
32
+ return false;
29
33
  }
30
34
  if (logSource === 'run() failure') {
31
35
  return true;
32
36
  }
33
- if (returnWarnings && (logSource === 'Browser Warning' || logSource === 'stderr')) {
37
+ if (includeWarnings && (logSource === 'Browser Warning' || logSource === 'stderr')) {
34
38
  return true;
35
39
  }
36
40
  if (logSource === 'Browser Error') {
@@ -52,10 +56,10 @@ function logErrorsAndWarnings() {
52
56
  }
53
57
  function flushLogs() {
54
58
  (0, logSection_1.logSection)('ALL LOGS');
55
- logEntries.forEach((logEntry) => printLog(logEntry));
59
+ logEntries.filter((logEntry) => !logEntry.loggedAfterExit).forEach((logEntry) => printLog(logEntry));
56
60
  logEntries = [];
57
61
  }
58
- function add({ logSource, logText }) {
62
+ function add({ logSource, logText, loggedAfterExit = false, }) {
59
63
  const logTimestamp = getTimestamp();
60
64
  const isNotFailure = (() => {
61
65
  const config = (0, getConfig_1.getConfig)();
@@ -72,6 +76,7 @@ function add({ logSource, logText }) {
72
76
  logText,
73
77
  logTimestamp,
74
78
  isNotFailure,
79
+ loggedAfterExit,
75
80
  };
76
81
  logEntries.push(logEntry);
77
82
  if (exports.Logs.logEagerly) {
@@ -2,12 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findTestFiles = void 0;
4
4
  const utils_1 = require("./utils");
5
- const github_action_1 = require("./github-action");
5
+ const parallel_ci_1 = require("./parallel-ci");
6
6
  // Unit tests `**/*.spec.*` are handled by Vitest
7
7
  const testFilenamePattern = '**/*.test.ts';
8
8
  async function findTestFiles(findFilter) {
9
9
  {
10
- const testFiles = (0, github_action_1.getTestFiles)();
10
+ const testFiles = (0, parallel_ci_1.getTestFilesForCurrentJob)();
11
11
  if (testFiles)
12
12
  return testFiles;
13
13
  }
@@ -1,6 +1,7 @@
1
1
  export { getCurrentTest };
2
2
  export { getCurrentTestOptional };
3
3
  export { setCurrentTest };
4
+ export type { TestInfo };
4
5
  import type { Page } from 'playwright-chromium';
5
6
  declare type TestInfo = {
6
7
  testFile: string;
@@ -0,0 +1,4 @@
1
+ export { abortIfParallelCI };
2
+ export { getTestFilesForCurrentJob };
3
+ declare function abortIfParallelCI(): void;
4
+ declare function getTestFilesForCurrentJob(): null | string[];
@@ -3,21 +3,21 @@ 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.getTestFiles = exports.abortIfGitHubAction = void 0;
6
+ exports.getTestFilesForCurrentJob = exports.abortIfParallelCI = void 0;
7
7
  const utils_1 = require("./utils");
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const cwd = process.cwd();
11
- function abortIfGitHubAction() {
12
- if (isGitHubAction()) {
11
+ function abortIfParallelCI() {
12
+ if (isParallelCI()) {
13
13
  process.exit(1);
14
14
  }
15
15
  }
16
- exports.abortIfGitHubAction = abortIfGitHubAction;
17
- function isGitHubAction() {
18
- return getTestFiles() !== null;
16
+ exports.abortIfParallelCI = abortIfParallelCI;
17
+ function isParallelCI() {
18
+ return getTestFilesForCurrentJob() !== null;
19
19
  }
20
- function getTestFiles() {
20
+ function getTestFilesForCurrentJob() {
21
21
  if (!('TEST_FILES' in process.env))
22
22
  return null;
23
23
  (0, utils_1.assert)(process.env.TEST_FILES);
@@ -27,4 +27,4 @@ function getTestFiles() {
27
27
  });
28
28
  return testFiles;
29
29
  }
30
- exports.getTestFiles = getTestFiles;
30
+ exports.getTestFilesForCurrentJob = getTestFilesForCurrentJob;
package/dist/runAll.js CHANGED
@@ -5,7 +5,7 @@ const getCurrentTest_1 = require("./getCurrentTest");
5
5
  const Logs_1 = require("./Logs");
6
6
  const utils_1 = require("./utils");
7
7
  const utils_2 = require("./utils");
8
- const github_action_1 = require("./github-action");
8
+ const parallel_ci_1 = require("./parallel-ci");
9
9
  const getCurrentTest_2 = require("./getCurrentTest");
10
10
  const getBrowser_1 = require("./getBrowser");
11
11
  const buildTs_1 = require("./buildTs");
@@ -45,6 +45,7 @@ exports.runAll = runAll;
45
45
  async function buildAndTest(testFile, browser, isSecondAttempt) {
46
46
  (0, utils_1.assert)(testFile.endsWith('.ts'));
47
47
  const testFileJs = testFile.replace('.ts', '.mjs');
48
+ (0, utils_1.assert)(testFileJs.endsWith('.mjs'));
48
49
  const cleanBuild = await (0, buildTs_1.buildTs)(testFile, testFileJs);
49
50
  (0, getCurrentTest_2.setCurrentTest)(testFile);
50
51
  try {
@@ -53,14 +54,48 @@ async function buildAndTest(testFile, browser, isSecondAttempt) {
53
54
  finally {
54
55
  cleanBuild();
55
56
  }
56
- const { success, clean } = await runTests(browser, isSecondAttempt);
57
- await clean();
57
+ const success = await runServerAndTests(browser, isSecondAttempt);
58
58
  (0, getCurrentTest_2.setCurrentTest)(null);
59
- (0, utils_1.assert)(testFileJs.endsWith('.mjs'));
60
59
  return success;
61
60
  }
62
- async function runTests(browser, isSecondAttempt) {
61
+ async function runServerAndTests(browser, isSecondAttempt) {
63
62
  const testInfo = (0, getCurrentTest_1.getCurrentTest)();
63
+ // Set when user calls `run()`
64
+ (0, utils_1.assert)(testInfo.runInfo);
65
+ (0, utils_1.assert)(testInfo.startServer);
66
+ (0, utils_1.assert)(testInfo.terminateServer);
67
+ const isFinalAttempt = isSecondAttempt || !testInfo.runInfo.isFlaky;
68
+ try {
69
+ await testInfo.startServer();
70
+ }
71
+ catch (err) {
72
+ logFailure(err, 'an error occurred while starting the server', isFinalAttempt);
73
+ return false;
74
+ }
75
+ const page = await browser.newPage();
76
+ testInfo.page = page;
77
+ let success = await runTests(testInfo, isFinalAttempt);
78
+ await testInfo.terminateServer();
79
+ await page.close();
80
+ // Check whether stderr emitted during testInfo.terminateServer()
81
+ if (success) {
82
+ const failOnWarning = true;
83
+ if (Logs_1.Logs.hasFailLogs(failOnWarning) &&
84
+ // See comments about taskkill in src/setup.ts
85
+ !(0, utils_1.isWindows)()) {
86
+ logFailure(null, `${getErrorType(failOnWarning)} occurred during server termination`, isFinalAttempt);
87
+ success = false;
88
+ }
89
+ }
90
+ if (!success && !testInfo.runInfo.isFlaky)
91
+ (0, parallel_ci_1.abortIfParallelCI)();
92
+ if (success) {
93
+ (0, logTestStatus_1.logPass)();
94
+ }
95
+ Logs_1.Logs.clearLogs();
96
+ return success;
97
+ }
98
+ async function runTests(testInfo, isFinalAttempt) {
64
99
  if (utils_1.isTTY) {
65
100
  console.log();
66
101
  console.log(testInfo.testFile);
@@ -70,35 +105,13 @@ async function runTests(browser, isSecondAttempt) {
70
105
  (0, logTestStatus_1.logWarn)(testInfo.skipped);
71
106
  (0, utils_1.assertUsage)(!testInfo.runInfo, 'You cannot call `run()` after calling `skip()`');
72
107
  (0, utils_1.assertUsage)(testInfo.tests === undefined, 'You cannot call `test()` after calling `skip()`');
73
- return { success: true, clean: async () => { } };
108
+ return true;
74
109
  }
75
- const page = await browser.newPage();
76
- testInfo.page = page;
77
110
  // Set when user calls `run()`
78
111
  (0, utils_1.assert)(testInfo.runInfo);
79
- (0, utils_1.assert)(testInfo.startServer);
80
- (0, utils_1.assert)(testInfo.terminateServer);
81
112
  (0, utils_1.assert)(testInfo.afterEach);
82
113
  // Set when user calls `test()`
83
114
  (0, utils_1.assert)(testInfo.tests);
84
- const isFinalAttempt = isSecondAttempt || !testInfo.runInfo.isFlaky;
85
- const clean = async () => {
86
- await testInfo.terminateServer?.();
87
- await page.close();
88
- };
89
- const failure = () => {
90
- (0, github_action_1.abortIfGitHubAction)();
91
- return { success: false, clean };
92
- };
93
- try {
94
- await testInfo.startServer();
95
- }
96
- catch (err) {
97
- (0, logTestStatus_1.logFail)('an error occurred while starting the server', isFinalAttempt);
98
- (0, logError_1.logError)(err);
99
- Logs_1.Logs.flushLogs();
100
- return failure();
101
- }
102
115
  for (const { testDesc, testFn } of testInfo.tests) {
103
116
  Logs_1.Logs.add({
104
117
  logSource: 'test()',
@@ -120,37 +133,28 @@ async function runTests(browser, isSecondAttempt) {
120
133
  const isFailure = err || hasErrorLog;
121
134
  if (isFailure) {
122
135
  if (err) {
123
- (0, logTestStatus_1.logFail)(`the test "${testDesc}" threw an error`, isFinalAttempt);
124
- (0, logError_1.logError)(err);
136
+ logFailure(err, `the test "${testDesc}" threw an error`, isFinalAttempt);
125
137
  }
126
138
  else if (hasErrorLog) {
127
- (0, logTestStatus_1.logFail)(`${getErrorType(failOnWarning)} occurred while running the test "${testDesc}"`, isFinalAttempt);
139
+ logFailure(null, `${getErrorType(failOnWarning)} occurred while running the test "${testDesc}"`, isFinalAttempt);
128
140
  }
129
141
  else {
130
142
  (0, utils_1.assert)(false);
131
143
  }
132
- Logs_1.Logs.logErrorsAndWarnings();
133
- Logs_1.Logs.flushLogs();
134
- return failure();
144
+ return false;
135
145
  }
136
146
  }
137
147
  Logs_1.Logs.clearLogs();
138
148
  }
139
- // Check whether stderr emitted during testInfo.terminateServer()
140
- {
141
- const failOnWarning = true;
142
- if (Logs_1.Logs.hasFailLogs(failOnWarning) &&
143
- // See comments about taskkill in src/setup.ts
144
- !(0, utils_1.isWindows)()) {
145
- (0, logTestStatus_1.logFail)(`${getErrorType(failOnWarning)} occurred during server termination`, isFinalAttempt);
146
- Logs_1.Logs.logErrorsAndWarnings();
147
- Logs_1.Logs.flushLogs();
148
- return failure();
149
- }
149
+ return true;
150
+ }
151
+ function logFailure(err, reason, isFinalAttempt) {
152
+ (0, logTestStatus_1.logFail)(reason, isFinalAttempt);
153
+ if (err) {
154
+ (0, logError_1.logError)(err);
150
155
  }
151
- Logs_1.Logs.clearLogs();
152
- (0, logTestStatus_1.logPass)();
153
- return { success: true, clean };
156
+ Logs_1.Logs.logErrorsAndWarnings();
157
+ Logs_1.Logs.flushLogs();
154
158
  }
155
159
  function getErrorType(failOnWarning) {
156
160
  return !failOnWarning ? 'error(s)' : 'error(s)/warning(s)';
package/dist/setup.js CHANGED
@@ -256,11 +256,10 @@ function stopProcess({ proc, cwd, cmd, force, }) {
256
256
  (0, child_process_1.spawn)('taskkill', ['/pid', String(proc.pid), '/f', '/t'], {
257
257
  stdio: [
258
258
  'ignore',
259
- // Ignore:
259
+ // Ignore following log to avoid polluting non-error logs. (Setting 'inherit' instead of 'ignore' attaches stdout to the root process and not to `proc` which is why the stdout of taskkill isn't intercepted by `proc.stdout.on('data', () => /* ... */)`.)
260
260
  // ```
261
261
  // SUCCESS: The process with PID 6932 (child process of PID 2744) has been terminated.
262
262
  // ```
263
- // (Setting 'inherit' instead of 'ignore' attaches stdout to the root process and not to `proc` which is why the stdout of taskkill isn't intercepted by `proc.stdout.on('data', () => /* ... */)`.
264
263
  'ignore',
265
264
  // Ignoring stderr doesn't solve the problem that taskkill makes the process exit with code 1
266
265
  'inherit', // stderr
@@ -323,14 +322,8 @@ function execRunScript({ onStdout, onFailure, onExit, }) {
323
322
  Logs_1.Logs.add({
324
323
  logSource: 'stdout',
325
324
  logText: data,
325
+ loggedAfterExit: procExited,
326
326
  });
327
- /* These assertions sometimes fail, see comments in assertNotExited()
328
- assertNotExited(data)
329
- assert(getRunInfo().cmd === cmd)
330
- /*/
331
- if (procExited)
332
- return undefined;
333
- //*/
334
327
  onStdout?.(data);
335
328
  });
336
329
  proc.stderr.on('data', async (chunk) => {
@@ -338,14 +331,8 @@ function execRunScript({ onStdout, onFailure, onExit, }) {
338
331
  Logs_1.Logs.add({
339
332
  logSource: 'stderr',
340
333
  logText: data,
334
+ loggedAfterExit: procExited,
341
335
  });
342
- /* These assertions sometimes fail, see comments in assertNotExited()
343
- assertNotExited(data)
344
- assert(getRunInfo().cmd === cmd)
345
- /*/
346
- if (procExited)
347
- return undefined;
348
- //*/
349
336
  if (data.includes('EADDRINUSE')) {
350
337
  await exitAndFail(new Error('Port conflict? Port already in use EADDRINUSE.'));
351
338
  }
@@ -375,15 +362,6 @@ function execRunScript({ onStdout, onFailure, onExit, }) {
375
362
  exitPromiseResolve();
376
363
  });
377
364
  return { terminate, processHasExited };
378
- /* Node.js seems to occasionally emit 'data' events after having the emitted 'exit' event, for example:
379
- * - `{"data":"[0] npm run serve:cdn exited with code SIGTERM\n","dataLength":48}`.
380
- function assertNotExited(data: string) {
381
- if (!procExited) return
382
- // Sometimes, a single white space is emitted after 'exit' has been emitted.
383
- if (data.trim().length === 0) return
384
- assert(false, { data, dataLength: data.length })
385
- }
386
- */
387
365
  function processHasExited() {
388
366
  return procExited;
389
367
  }
@@ -391,8 +369,12 @@ function execRunScript({ onStdout, onFailure, onExit, }) {
391
369
  let resolve;
392
370
  let reject;
393
371
  const promise = new Promise((_resolve, _reject) => {
394
- resolve = _resolve;
395
- reject = _reject;
372
+ resolve = () => {
373
+ _resolve();
374
+ };
375
+ reject = () => {
376
+ _reject();
377
+ };
396
378
  });
397
379
  const timeout = setTimeout(() => {
398
380
  const errMsg = 'Process termination timeout. Cmd: ' + cmd;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brillout/test-e2e",
3
- "version": "0.4.13",
3
+ "version": "0.4.15",
4
4
  "bin": "./bin.js",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -1,4 +0,0 @@
1
- export { abortIfGitHubAction };
2
- export { getTestFiles };
3
- declare function abortIfGitHubAction(): void;
4
- declare function getTestFiles(): null | string[];