browser-commander 0.16.1 → 0.17.0
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/.changeset/config.json +1 -1
- package/.changeset/merged-loud-river.md +7 -0
- package/.jscpd-baseline.json +257 -0
- package/.jscpd.json +1 -3
- package/.prettierignore +1 -0
- package/CHANGELOG.md +8 -0
- package/eslint.config.js +23 -1
- package/package.json +13 -24
- package/scripts/changeset-version.mjs +2 -6
- package/scripts/create-github-release.mjs +7 -8
- package/scripts/create-manual-changeset.mjs +7 -8
- package/scripts/format-github-release.mjs +6 -7
- package/scripts/format-release-notes.mjs +7 -8
- package/scripts/instant-version-bump.mjs +7 -8
- package/scripts/publish-to-npm.mjs +7 -8
- package/scripts/setup-npm.mjs +2 -6
- package/scripts/version-and-commit.mjs +7 -8
- package/src/browser/browser-cookie-credentials.js +3 -1
- package/src/browser/browser-cookies.js +6 -2
- package/src/browser/browser-profiles.js +1 -1
- package/src/browser/launch-options.js +31 -8
- package/src/browser/launcher.js +16 -0
- package/src/exports.js +34 -0
- package/src/fingerprint/apply.js +116 -0
- package/src/fingerprint/automation-parity.js +224 -0
- package/src/fingerprint/cdp-overrides.js +176 -0
- package/src/fingerprint/derive.js +104 -0
- package/src/fingerprint/init-payload.js +181 -0
- package/src/fingerprint/init-script.js +104 -0
- package/src/fingerprint/limitations.js +107 -0
- package/src/fingerprint/limitations.json +96 -0
- package/src/fingerprint/presets.js +244 -0
- package/src/fingerprint/profile.js +428 -0
- package/src/tests/index.js +2 -1
- package/tests/e2e/fingerprint-parity.e2e.test.js +212 -0
- package/tests/helpers/mocks.js +4 -2
- package/tests/helpers/repo.js +74 -0
- package/tests/unit/browser/launch-options.test.js +9 -1
- package/tests/unit/experiments/fingerprint-parity-harness.test.js +97 -0
- package/tests/unit/fingerprint/apply.test.js +271 -0
- package/tests/unit/fingerprint/automation-parity.test.js +212 -0
- package/tests/unit/fingerprint/cdp-overrides.test.js +227 -0
- package/tests/unit/fingerprint/derive.test.js +105 -0
- package/tests/unit/fingerprint/init-script.test.js +357 -0
- package/tests/unit/fingerprint/limitations.test.js +184 -0
- package/tests/unit/fingerprint/presets.test.js +135 -0
- package/tests/unit/fingerprint/profile.test.js +282 -0
- package/tests/unit/scripts/check-pipeline-status.test.js +133 -0
- package/tests/unit/scripts/check-web-archive.test.js +191 -0
- package/tests/unit/scripts/ci-timeout-budgets.test.js +311 -0
- package/tests/unit/scripts/ci-workflow-policy.test.js +193 -157
- package/tests/unit/scripts/debug-print.test.js +67 -0
- package/tests/unit/scripts/jscpd-config.test.js +141 -0
- package/tests/unit/scripts/pre-commit-config.test.js +209 -0
- package/tests/unit/scripts/read-manifest.test.js +194 -0
- package/tests/unit/scripts/run-with-budget-warning.test.js +115 -0
- package/tests/unit/scripts/use-module-adoption.test.js +74 -0
- package/tests/unit/scripts/use-module-integration.test.js +64 -0
- package/tests/unit/scripts/use-module.test.js +182 -0
- package/.husky/pre-commit +0 -1
- package/.prettierrc +0 -10
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wrapper that gives a long step its own deadline.
|
|
3
|
+
*
|
|
4
|
+
* A job killed by `timeout-minutes` is reported as cancelled, which is not a
|
|
5
|
+
* failure; a step that owns its budget exits non-zero instead, so the overrun
|
|
6
|
+
* turns a check red and names the deadline it blew. These tests pin the three
|
|
7
|
+
* properties the workflows depend on: the command's own exit status is passed
|
|
8
|
+
* through untouched, an overrun exits 124 with an error annotation, and the
|
|
9
|
+
* whole process tree is killed rather than just the direct child.
|
|
10
|
+
*
|
|
11
|
+
* See docs/CI-TIMEOUT-BUDGETS.md.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import assert from 'node:assert/strict';
|
|
15
|
+
import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
16
|
+
import { tmpdir } from 'node:os';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { describe, it } from 'node:test';
|
|
19
|
+
|
|
20
|
+
import { BASH_AVAILABLE, repoPath, runBashScript } from '../../helpers/repo.js';
|
|
21
|
+
|
|
22
|
+
const SCRIPT = repoPath('scripts/run-with-budget-warning.sh');
|
|
23
|
+
|
|
24
|
+
function runWrapper(args, env = {}) {
|
|
25
|
+
return runBashScript(SCRIPT, args, {
|
|
26
|
+
env: { BUDGET_GRACE_SECONDS: '1', ...env },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('run-with-budget-warning.sh', { skip: !BASH_AVAILABLE }, () => {
|
|
31
|
+
it('passes a successful command through', () => {
|
|
32
|
+
const { status, output } = runWrapper(['5', 'quick step', 'true']);
|
|
33
|
+
|
|
34
|
+
assert.equal(status, 0);
|
|
35
|
+
assert.match(
|
|
36
|
+
output,
|
|
37
|
+
/quick step finished in \d+s of its 5s budget \(exit 0\)/
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("passes a failing command's own exit status through", () => {
|
|
42
|
+
const { status } = runWrapper([
|
|
43
|
+
'5',
|
|
44
|
+
'failing step',
|
|
45
|
+
'bash',
|
|
46
|
+
'-c',
|
|
47
|
+
'exit 7',
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
assert.equal(status, 7);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('exits 124 and annotates the overrun', () => {
|
|
54
|
+
const { status, output } = runWrapper(['1', 'slow step', 'sleep', '30']);
|
|
55
|
+
|
|
56
|
+
assert.equal(status, 124);
|
|
57
|
+
assert.match(
|
|
58
|
+
output,
|
|
59
|
+
/::error title=slow step exceeded its execution budget::/
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('kills the whole process group, not just the direct child', async () => {
|
|
64
|
+
// Test runners spawn workers; killing only the direct child leaves orphans
|
|
65
|
+
// holding the runner, which is why timeout(1) is not sufficient here. The
|
|
66
|
+
// worker is watched through the file it writes rather than through
|
|
67
|
+
// `kill -0`, which also succeeds for a killed-but-unreaped zombie.
|
|
68
|
+
const directory = mkdtempSync(path.join(tmpdir(), 'budget-wrapper-'));
|
|
69
|
+
const tickFile = path.join(directory, 'ticks');
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const { status } = runWrapper([
|
|
73
|
+
'1',
|
|
74
|
+
'step with a worker',
|
|
75
|
+
'bash',
|
|
76
|
+
'-c',
|
|
77
|
+
`while true; do echo tick >> ${JSON.stringify(tickFile)}; sleep 0.2; done & wait`,
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
assert.equal(status, 124);
|
|
81
|
+
|
|
82
|
+
const ticksAtTermination = readFileSync(tickFile, 'utf8').length;
|
|
83
|
+
|
|
84
|
+
assert.ok(ticksAtTermination > 0, 'the worker never started');
|
|
85
|
+
|
|
86
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
87
|
+
|
|
88
|
+
assert.equal(
|
|
89
|
+
readFileSync(tickFile, 'utf8').length,
|
|
90
|
+
ticksAtTermination,
|
|
91
|
+
'the worker outlived the budget termination'
|
|
92
|
+
);
|
|
93
|
+
} finally {
|
|
94
|
+
rmSync(directory, { force: true, recursive: true });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('warns before the budget expires', () => {
|
|
99
|
+
const { status, output } = runWrapper(['10', 'warned step', 'sleep', '2'], {
|
|
100
|
+
BUDGET_WARN_PERCENT: '10',
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
assert.equal(status, 0);
|
|
104
|
+
assert.match(
|
|
105
|
+
output,
|
|
106
|
+
/::warning title=warned step is approaching its execution budget::/
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('rejects a budget that is not a positive number of seconds', () => {
|
|
111
|
+
assert.equal(runWrapper(['soon', 'bad budget', 'true']).status, 2);
|
|
112
|
+
assert.equal(runWrapper(['0', 'bad budget', 'true']).status, 2);
|
|
113
|
+
assert.equal(runWrapper(['5']).status, 2);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guard that keeps every pipeline script on the use-m interop shim.
|
|
3
|
+
*
|
|
4
|
+
* A raw `const { $ } = await use('command-stream')` yields `undefined` on Node
|
|
5
|
+
* 23+ because of the synthetic `module.exports` CommonJS export, so the script
|
|
6
|
+
* dies with `TypeError: $ is not a function` inside a release job — which is
|
|
7
|
+
* exactly how the JS Release and Rust Auto Release jobs failed on 2026-09-04.
|
|
8
|
+
* Loading through scripts/use-module.mjs normalises that namespace, and this
|
|
9
|
+
* test covers both language directories so the fix cannot be reintroduced in
|
|
10
|
+
* only one of them.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
14
|
+
import { dirname, join } from 'node:path';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
import assert from 'node:assert/strict';
|
|
17
|
+
import { describe, it } from 'node:test';
|
|
18
|
+
|
|
19
|
+
const repositoryRoot = join(
|
|
20
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
21
|
+
'..',
|
|
22
|
+
'..',
|
|
23
|
+
'..',
|
|
24
|
+
'..'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Every directory holding release automation that loads packages through use-m.
|
|
28
|
+
const SCRIPT_DIRECTORIES = ['js/scripts', 'rust/scripts', 'scripts'];
|
|
29
|
+
const SHIM = 'use-module.mjs';
|
|
30
|
+
|
|
31
|
+
function scriptSources() {
|
|
32
|
+
return SCRIPT_DIRECTORIES.flatMap((directory) =>
|
|
33
|
+
readdirSync(join(repositoryRoot, directory))
|
|
34
|
+
.filter((name) => name.endsWith('.mjs') && name !== SHIM)
|
|
35
|
+
.map((name) => ({
|
|
36
|
+
name: `${directory}/${name}`,
|
|
37
|
+
source: readFileSync(join(repositoryRoot, directory, name), 'utf8'),
|
|
38
|
+
}))
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe('pipeline scripts load use-m through the interop shim', () => {
|
|
43
|
+
it('finds the scripts it is meant to guard', () => {
|
|
44
|
+
assert.ok(scriptSources().length > 10);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('never destructures a package straight off use()', () => {
|
|
48
|
+
const offenders = scriptSources()
|
|
49
|
+
.filter(({ source }) =>
|
|
50
|
+
/const\s*\{[^}]*\}\s*=\s*await\s+use\(/.test(source)
|
|
51
|
+
)
|
|
52
|
+
.map(({ name }) => name);
|
|
53
|
+
assert.deepEqual(offenders, []);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('never fetches and evals use.js inline', () => {
|
|
57
|
+
const offenders = scriptSources()
|
|
58
|
+
.filter(({ source }) =>
|
|
59
|
+
/eval\(\s*\n?\s*await\s*\(await\s*fetch\(/.test(source)
|
|
60
|
+
)
|
|
61
|
+
.map(({ name }) => name);
|
|
62
|
+
assert.deepEqual(offenders, []);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('routes every shim consumer through scripts/use-module.mjs', () => {
|
|
66
|
+
const offenders = scriptSources()
|
|
67
|
+
.filter(({ source }) =>
|
|
68
|
+
/load(CommandStream|LinoArguments)\(/.test(source)
|
|
69
|
+
)
|
|
70
|
+
.filter(({ source }) => !source.includes(SHIM))
|
|
71
|
+
.map(({ name }) => name);
|
|
72
|
+
assert.deepEqual(offenders, []);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end guard for the use-m interop shim.
|
|
3
|
+
*
|
|
4
|
+
* use-module.test.js pins the namespace shapes we normalise; this file loads
|
|
5
|
+
* `command-stream` through the real, unpinned use-m on the same Node version
|
|
6
|
+
* the release jobs run (`node-version: '24.x'`) and asserts `$` is callable.
|
|
7
|
+
* Without it the interop breakage only surfaces on `main`, inside a job that
|
|
8
|
+
* pushes tags and publishes to npm.
|
|
9
|
+
*
|
|
10
|
+
* The test needs network access. When the fetch of use.js or the package
|
|
11
|
+
* install fails, it logs the reason and passes, so offline development and
|
|
12
|
+
* sandboxed runs are not blocked by an unreachable CDN.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import assert from 'node:assert/strict';
|
|
16
|
+
import { describe, it } from 'node:test';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
loadCommandStream,
|
|
20
|
+
USE_M_URL,
|
|
21
|
+
} from '../../../../scripts/use-module.mjs';
|
|
22
|
+
|
|
23
|
+
async function hasNetwork() {
|
|
24
|
+
try {
|
|
25
|
+
return (await fetch(USE_M_URL, { method: 'HEAD' })).ok;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe('use-m loads command-stream on this Node version', () => {
|
|
32
|
+
it('exposes a callable $ from command-stream', async (t) => {
|
|
33
|
+
if (process.platform === 'win32') {
|
|
34
|
+
// use-m imports the resolved file by its bare absolute path, which the
|
|
35
|
+
// Windows ESM loader rejects with ERR_UNSUPPORTED_ESM_URL_SCHEME. That is
|
|
36
|
+
// an upstream loader bug, independent of the namespace shape this shim
|
|
37
|
+
// normalises; the Linux and macOS runs still cover the interop.
|
|
38
|
+
return t.skip('use-m cannot import absolute paths on Windows');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!(await hasNetwork())) {
|
|
42
|
+
return t.skip(
|
|
43
|
+
`${USE_M_URL} is unreachable, so use-m cannot be evaluated`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let commandStream;
|
|
48
|
+
try {
|
|
49
|
+
commandStream = await loadCommandStream();
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (
|
|
52
|
+
/fetch|network|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|registry/i.test(
|
|
53
|
+
error.message
|
|
54
|
+
)
|
|
55
|
+
) {
|
|
56
|
+
return t.skip(error.message);
|
|
57
|
+
}
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log(`Loaded command-stream on ${process.version}`);
|
|
62
|
+
assert.equal(typeof commandStream.$, 'function');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
describeModule,
|
|
6
|
+
loadCommandStream,
|
|
7
|
+
loadLinoArguments,
|
|
8
|
+
loadUse,
|
|
9
|
+
resolveNamedExport,
|
|
10
|
+
USE_M_URL,
|
|
11
|
+
} from '../../../../scripts/use-module.mjs';
|
|
12
|
+
|
|
13
|
+
const dollar = () => {};
|
|
14
|
+
|
|
15
|
+
function commandStreamExports() {
|
|
16
|
+
return Object.assign(() => {}, { $: dollar, sh: () => {}, run: () => {} });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Namespace `import()` produces for a CommonJS file on Node < 23. use-m unwraps
|
|
21
|
+
* it because `default` is the only key, so `const { $ }` works. Measured on
|
|
22
|
+
* node v20.20.2 and v22.21.1.
|
|
23
|
+
*/
|
|
24
|
+
function nodeTwentyTwoNamespace() {
|
|
25
|
+
return { default: commandStreamExports() };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The same file on Node 23+: the synthetic `module.exports` key makes use-m
|
|
30
|
+
* skip the unwrap and hand the raw namespace to the caller. Measured on
|
|
31
|
+
* node v24.20.0, the version every workflow in this repository requests.
|
|
32
|
+
*/
|
|
33
|
+
function nodeTwentyFourNamespace() {
|
|
34
|
+
return {
|
|
35
|
+
default: commandStreamExports(),
|
|
36
|
+
'module.exports': commandStreamExports(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function textResponse(
|
|
41
|
+
body,
|
|
42
|
+
{ ok = true, status = 200, statusText = 'OK' } = {}
|
|
43
|
+
) {
|
|
44
|
+
return {
|
|
45
|
+
ok,
|
|
46
|
+
status,
|
|
47
|
+
statusText,
|
|
48
|
+
async text() {
|
|
49
|
+
return body;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe('use-module interop shim', () => {
|
|
55
|
+
it('reproduces the Node 24 namespace that breaks destructuring', () => {
|
|
56
|
+
// This is the CI failure verbatim: `$` is undefined, so the first tagged
|
|
57
|
+
// template threw `TypeError: $ is not a function` in the release jobs.
|
|
58
|
+
const { $ } = nodeTwentyFourNamespace();
|
|
59
|
+
assert.equal($, undefined);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('resolves $ from the Node 23+ CommonJS namespace', () => {
|
|
63
|
+
const resolved = resolveNamedExport(
|
|
64
|
+
nodeTwentyFourNamespace(),
|
|
65
|
+
'$',
|
|
66
|
+
'command-stream'
|
|
67
|
+
);
|
|
68
|
+
assert.equal(typeof resolved.$, 'function');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('resolves $ from the Node < 23 CommonJS namespace', () => {
|
|
72
|
+
const resolved = resolveNamedExport(
|
|
73
|
+
nodeTwentyTwoNamespace(),
|
|
74
|
+
'$',
|
|
75
|
+
'command-stream'
|
|
76
|
+
);
|
|
77
|
+
assert.equal(typeof resolved.$, 'function');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('resolves $ when use-m already unwrapped the module', () => {
|
|
81
|
+
const resolved = resolveNamedExport(
|
|
82
|
+
commandStreamExports(),
|
|
83
|
+
'$',
|
|
84
|
+
'command-stream'
|
|
85
|
+
);
|
|
86
|
+
assert.equal(typeof resolved.$, 'function');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('resolves $ from a real ES module namespace with named exports', () => {
|
|
90
|
+
const namespace = { $: dollar, sh: () => {}, default: dollar };
|
|
91
|
+
assert.equal(
|
|
92
|
+
resolveNamedExport(namespace, '$', 'command-stream'),
|
|
93
|
+
namespace
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('resolves a double-wrapped default', () => {
|
|
98
|
+
const resolved = resolveNamedExport(
|
|
99
|
+
{ default: { default: commandStreamExports() } },
|
|
100
|
+
'$',
|
|
101
|
+
'command-stream'
|
|
102
|
+
);
|
|
103
|
+
assert.equal(typeof resolved.$, 'function');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('names the observed keys when no candidate exposes the export', () => {
|
|
107
|
+
assert.throws(
|
|
108
|
+
() => resolveNamedExport({ nope: 1 }, '$', 'command-stream'),
|
|
109
|
+
(error) =>
|
|
110
|
+
error.message.includes("use('command-stream')") &&
|
|
111
|
+
error.message.includes('keys [nope]')
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('reports the received value when use-m resolved nothing', () => {
|
|
116
|
+
assert.throws(
|
|
117
|
+
() => resolveNamedExport(undefined, '$', 'command-stream'),
|
|
118
|
+
/Received undefined/
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('describes null, primitives and objects', () => {
|
|
123
|
+
assert.equal(describeModule(null), 'null');
|
|
124
|
+
assert.equal(describeModule(7), 'number');
|
|
125
|
+
assert.equal(describeModule({ a: 1, b: 2 }), 'object with keys [a, b]');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('loads command-stream through an injected use() implementation', async () => {
|
|
129
|
+
const calls = [];
|
|
130
|
+
const use = async (name) => {
|
|
131
|
+
calls.push(name);
|
|
132
|
+
return nodeTwentyFourNamespace();
|
|
133
|
+
};
|
|
134
|
+
const module = await loadCommandStream(use);
|
|
135
|
+
assert.deepEqual(calls, ['command-stream']);
|
|
136
|
+
assert.equal(typeof module.$, 'function');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('loads lino-arguments through an injected use() implementation', async () => {
|
|
140
|
+
const calls = [];
|
|
141
|
+
const use = async (name) => {
|
|
142
|
+
calls.push(name);
|
|
143
|
+
return { default: { makeConfig: () => ({}) } };
|
|
144
|
+
};
|
|
145
|
+
const module = await loadLinoArguments(use);
|
|
146
|
+
assert.deepEqual(calls, ['lino-arguments']);
|
|
147
|
+
assert.equal(typeof module.makeConfig, 'function');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('points at the unpinned use-m entry point', () => {
|
|
151
|
+
assert.equal(USE_M_URL, 'https://unpkg.com/use-m/use.js');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('reports the HTTP status when use.js cannot be fetched', async () => {
|
|
155
|
+
// Without this the error page would be eval'd and surface as a SyntaxError.
|
|
156
|
+
await assert.rejects(
|
|
157
|
+
loadUse({
|
|
158
|
+
fetchImpl: async () =>
|
|
159
|
+
textResponse('<html>Not Found</html>', {
|
|
160
|
+
ok: false,
|
|
161
|
+
status: 404,
|
|
162
|
+
statusText: 'Not Found',
|
|
163
|
+
}),
|
|
164
|
+
}),
|
|
165
|
+
/404 Not Found/
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('reports a use.js payload that exposes no callable use()', async () => {
|
|
170
|
+
await assert.rejects(
|
|
171
|
+
loadUse({ fetchImpl: async () => textResponse('({ nope: 1 })') }),
|
|
172
|
+
/did not export a callable "use"/
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('evaluates a well-formed use.js payload', async () => {
|
|
177
|
+
const use = await loadUse({
|
|
178
|
+
fetchImpl: async () => textResponse('({ use: async () => ({}) })'),
|
|
179
|
+
});
|
|
180
|
+
assert.equal(typeof use, 'function');
|
|
181
|
+
});
|
|
182
|
+
});
|
package/.husky/pre-commit
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
npx lint-staged
|