kempo-testing-framework 1.4.8 → 1.4.10

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/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "kempo-testing-framework",
3
- "version": "1.4.8",
3
+ "version": "1.4.10",
4
4
  "description": "The Kempo Testing Framework is a simple testing framework built on the principle that code intended to be ran in the browser should be tested in the browser, code intended to be ran in Node should be tested in Node, and code intended to be ran in both should be tested in both. No mocking, no complexity—just testing.",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "kempo-test": "./index.js"
8
8
  },
9
9
  "scripts": {
10
- "test": "npx kempo-test",
11
- "test:gui": "npx kempo-test --gui"
10
+ "test": "npx kempo-test -t 90000",
11
+ "test:gui": "npx kempo-test -t 90000 --gui"
12
12
  },
13
13
  "keywords": [],
14
14
  "author": "",
@@ -16,7 +16,7 @@
16
16
  "type": "module",
17
17
  "dependencies": {
18
18
  "kempo-css": "^2.1.9",
19
- "puppeteer": "^24.9.0"
19
+ "puppeteer": "^25.6.0"
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",
@@ -1,8 +1,15 @@
1
1
  import http from 'http';
2
2
  import { startServer, stopServer } from '../../src/browserTestServer.js';
3
3
 
4
+ /*
5
+ agent: false opts out of the global agent's connection pool. Node keeps that pool alive by
6
+ default, so a socket left over from an earlier test survives the server being stopped, and the
7
+ next test — which restarts a server on the same port — reuses a connection the previous server
8
+ already destroyed. The result is an intermittent "socket hang up" that has nothing to do with
9
+ what is being tested.
10
+ */
4
11
  const get = (port, path) => new Promise((resolve, reject) => {
5
- const req = http.request({ hostname: 'localhost', port, path, method: 'GET' }, (res) => {
12
+ const req = http.request({ hostname: 'localhost', port, path, method: 'GET', agent: false }, (res) => {
6
13
  let data = '';
7
14
  res.on('data', chunk => { data += chunk.toString(); });
8
15
  res.on('end', () => resolve({ status: res.statusCode, body: data }));
@@ -2,28 +2,58 @@ import { spawn } from 'child_process';
2
2
 
3
3
  const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, '');
4
4
 
5
- const run = (args, timeoutMs = 10000) => new Promise((resolve) => {
5
+ /*
6
+ Resolves with { out, timedOut }. The distinction matters: this used to resolve with whatever had
7
+ been printed so far when the timer fired, so a run that was merely slow failed as though the CLI
8
+ had printed the wrong thing. Callers can now tell "did not finish" apart from "finished and said
9
+ something unexpected", and only retry the former.
10
+ */
11
+ const run = (args, timeoutMs = 25000) => new Promise((resolve) => {
6
12
  const child = spawn(process.execPath, ['index.js', ...args], {
7
13
  cwd: process.cwd(),
8
14
  stdio: ['ignore', 'pipe', 'pipe']
9
15
  });
10
16
  let out = '';
11
- const finish = () => { try { child.kill('SIGTERM'); } catch {} resolve(out); };
17
+ let settled = false;
18
+ const finish = (timedOut) => {
19
+ if(settled) return;
20
+ settled = true;
21
+ clearTimeout(timer);
22
+ try { child.kill('SIGTERM'); } catch {}
23
+ resolve({ out, timedOut });
24
+ };
25
+ const timer = setTimeout(() => finish(true), timeoutMs);
12
26
  child.stdout.on('data', c => { out += c.toString(); });
13
27
  child.stderr.on('data', c => { out += c.toString(); });
14
- child.on('exit', finish);
15
- setTimeout(finish, timeoutMs);
28
+ child.on('exit', () => finish(false));
16
29
  });
17
30
 
18
31
  export default {
32
+ /*
33
+ The post-test log only prints once the in-page run has reported results, so this depends on a
34
+ headful Chromium completing a full round trip. That normally takes ~2.5s but occasionally
35
+ stalls past the runner's own 30s page timeout, at which point the CLI legitimately never gets
36
+ there. One retry covers that, and only when the run did not finish — output that came back
37
+ wrong is a real failure and is never retried.
38
+ */
19
39
  'passes delay to browser runner and prints delay logs in verbose': async ({ pass, fail }) => {
20
- const out = await run(['-b', '-w', '-l', 'verbose', '-d', '200', 'counter']);
40
+ /*
41
+ A port of its own. The child starts a browser test server, and the suite running this test
42
+ starts one too — both defaulted to 3000, so whichever bound second died with EADDRINUSE and
43
+ took the whole run down.
44
+ */
45
+ const args = ['-b', '-w', '-l', 'verbose', '-d', '200', '-p', '3211', 'counter'];
46
+ let { out, timedOut } = await run(args);
47
+ if(timedOut) ({ out, timedOut } = await run(args));
48
+ if(timedOut) return fail('CLI did not finish within 25s on two consecutive attempts');
49
+
21
50
  const txt = stripAnsi(out);
22
51
  const ok = /Applying pre-test browser delay: 200ms/.test(txt) && /Applying post-test browser delay: 200ms/.test(txt);
23
- ok ? pass('CLI printed verbose delay logs for browser run') : fail(`Unexpected CLI output:\n${out}`);
52
+ ok ? pass('CLI printed verbose delay logs for browser run') : fail(`Unexpected CLI output:\n${out}`);
24
53
  },
25
54
  'node-only ignores delay and still runs filtered tests': async ({ pass, fail }) => {
26
- const out = await run(['-n', '-l', 'minimal', 'example']);
55
+ const { out, timedOut } = await run(['-n', '-l', 'minimal', '-p', '3212', 'example']);
56
+ if(timedOut) return fail('CLI did not finish within 25s');
27
57
  const txt = stripAnsi(out);
28
58
  const hasSummary = /=== Test Summary ===/.test(txt) && /Total Tests:\s*\d+/.test(txt);
29
59
  const noBrowser = !/=== Browser Test Results ===/.test(txt) && !/Running Browser test:/.test(txt);