@carecard/jwt-read 3.18.0 → 3.19.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.
@@ -0,0 +1,33 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import { runPackageTask } from './runPackageTask.mjs';
5
+
6
+ test('the complete test command runs each validation category exactly once', () => {
7
+ const executedSteps = [];
8
+
9
+ const exitCode = runPackageTask('test', taskStep => {
10
+ executedSteps.push([taskStep.command, ...(taskStep.arguments ?? [])].join(' '));
11
+ return 0;
12
+ });
13
+
14
+ assert.equal(exitCode, 0);
15
+ assert.deepEqual(executedSteps, [
16
+ 'npm run validate:audits',
17
+ 'npm run test:order',
18
+ 'tsc --noEmit',
19
+ 'mocha --require ./scripts/testOrder/randomizeTestOrder.cjs -r ts-node/register test/types.test.ts',
20
+ 'nyc node test/index.test.js',
21
+ ]);
22
+ });
23
+
24
+ test('the legacy aggregate command delegates to the complete test command once', () => {
25
+ const executedSteps = [];
26
+
27
+ runPackageTask('test:All', taskStep => {
28
+ executedSteps.push([taskStep.command, ...(taskStep.arguments ?? [])].join(' '));
29
+ return 0;
30
+ });
31
+
32
+ assert.deepEqual(executedSteps, ['npm test']);
33
+ });
@@ -0,0 +1,37 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFileSync } from 'node:fs';
3
+ import test from 'node:test';
4
+
5
+ const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
6
+ const composedCommandPattern = /&&|\|\||\bsh -c\b|\bnode -e\b/u;
7
+ const runnerCommandPattern = /^node scripts\/runPackageTask\.mjs ([A-Za-z0-9:_-]+)$/u;
8
+
9
+ async function loadPackageTaskRunner() {
10
+ return import(new URL('./runPackageTask.mjs', import.meta.url));
11
+ }
12
+
13
+ test('delegates composed package tasks to the repository runner', async () => {
14
+ const runnerCommands = Object.entries(packageJson.scripts ?? {}).filter(([, command]) =>
15
+ runnerCommandPattern.test(command),
16
+ );
17
+
18
+ for (const [scriptName, command] of Object.entries(packageJson.scripts ?? {})) {
19
+ assert.doesNotMatch(
20
+ command,
21
+ composedCommandPattern,
22
+ `${scriptName} must delegate composition to runPackageTask.mjs`,
23
+ );
24
+ }
25
+
26
+ assert.ok(runnerCommands.length > 0, 'at least one package task must use the runner');
27
+ const { packageTasks } = await loadPackageTaskRunner();
28
+ for (const [scriptName] of runnerCommands) {
29
+ assert.ok(packageTasks[scriptName], `${scriptName} must have a runner task`);
30
+ }
31
+ });
32
+
33
+ test('does not suppress command execution errors at the CLI boundary', () => {
34
+ const runnerSource = readFileSync(new URL('./runPackageTask.mjs', import.meta.url), 'utf8');
35
+
36
+ assert.doesNotMatch(runnerSource, /catch\s*\{/u);
37
+ });
@@ -1,29 +1,10 @@
1
1
  import assert from 'node:assert/strict';
2
- import { readFileSync } from 'node:fs';
3
2
  import test from 'node:test';
4
3
 
5
- const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
6
- const composedCommandPattern = /&&|\|\||\bsh -c\b|\bnode -e\b/u;
7
- const runnerCommandPattern = /^node scripts\/runPackageTask\.mjs ([A-Za-z0-9:_-]+)$/u;
8
-
9
4
  async function loadPackageTaskRunner() {
10
5
  return import(new URL('./runPackageTask.mjs', import.meta.url));
11
6
  }
12
7
 
13
- test('delegates composed package tasks to the repository runner', async () => {
14
- const runnerCommands = Object.entries(packageJson.scripts ?? {}).filter(([, command]) => runnerCommandPattern.test(command));
15
-
16
- for (const [scriptName, command] of Object.entries(packageJson.scripts ?? {})) {
17
- assert.doesNotMatch(command, composedCommandPattern, `${scriptName} must delegate composition to runPackageTask.mjs`);
18
- }
19
-
20
- assert.ok(runnerCommands.length > 0, 'at least one package task must use the runner');
21
- const { packageTasks } = await loadPackageTaskRunner();
22
- for (const [scriptName] of runnerCommands) {
23
- assert.ok(packageTasks[scriptName], `${scriptName} must have a runner task`);
24
- }
25
- });
26
-
27
8
  test('runs task steps in order and stops at the first failure', async () => {
28
9
  const { runPackageTask } = await loadPackageTaskRunner();
29
10
  const executedCommands = [];
@@ -65,17 +46,14 @@ test('runs conditional steps only when their required output is missing', async
65
46
  assert.deepEqual(executedCommands, ['execute']);
66
47
  });
67
48
 
68
- test('does not suppress command execution errors at the CLI boundary', () => {
69
- const runnerSource = readFileSync(new URL('./runPackageTask.mjs', import.meta.url), 'utf8');
70
-
71
- assert.doesNotMatch(runnerSource, /catch\s*\{/u);
72
- });
73
-
74
49
  test('merges task environment overrides without mutating inherited values', async () => {
75
50
  const { createTaskEnvironment } = await loadPackageTaskRunner();
76
51
  const inheritedEnvironment = { NODE_ENV: 'test', PATH: '/bin' };
77
52
 
78
- const environment = createTaskEnvironment({ NODE_ENV: 'production', DB_ENV: 'privileged' }, inheritedEnvironment);
53
+ const environment = createTaskEnvironment(
54
+ { NODE_ENV: 'production', DB_ENV: 'privileged' },
55
+ inheritedEnvironment,
56
+ );
79
57
 
80
58
  assert.deepEqual(environment, {
81
59
  NODE_ENV: 'production',
@@ -4,27 +4,53 @@ import { resolve } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
 
6
6
  export const packageTasks = Object.freeze({
7
+ 'validate:audits': [
8
+ { command: 'node', arguments: ['scripts/packageTaskRunner.audit.mjs'] },
9
+ { command: 'node', arguments: ['scripts/testOrder/testOrderPolicy.audit.mjs'] },
10
+ { command: 'node', arguments: ['scripts/testParallel/parallelTestPolicy.audit.mjs'] },
11
+ { command: 'mocha', arguments: ['test/config/errorWarningSuppression.audit.js'] },
12
+ { command: 'mocha', arguments: ['test/config/repositoryIsolation.audit.js'] },
13
+ { command: 'mocha', arguments: ['test/config/serverAuthEmailVerificationDocs.audit.js'] },
14
+ { command: 'mocha', arguments: ['test/config/tddGuidanceDocs.audit.js'] },
15
+ { command: 'mocha', arguments: ['test/jwtLib.audit.js'] },
16
+ ],
7
17
  test: [
18
+ { command: 'npm', arguments: ['run', 'validate:audits'] },
8
19
  { command: 'npm', arguments: ['run', 'test:order'] },
9
- { command: 'node', arguments: ['test/index.test.js'] },
20
+ { command: 'tsc', arguments: ['--noEmit'] },
21
+ {
22
+ command: 'mocha',
23
+ arguments: [
24
+ '--require',
25
+ './scripts/testOrder/randomizeTestOrder.cjs',
26
+ '-r',
27
+ 'ts-node/register',
28
+ 'test/types.test.ts',
29
+ ],
30
+ },
31
+ { command: 'nyc', arguments: ['node', 'test/index.test.js'] },
10
32
  ],
11
33
  'test:types': [
12
34
  { command: 'npm', arguments: ['run', 'test:order'] },
13
35
  { command: 'tsc', arguments: ['--noEmit'] },
14
36
  {
15
37
  command: 'mocha',
16
- arguments: ['--require', './scripts/testOrder/randomizeTestOrder.cjs', '-r', 'ts-node/register', 'test/types.test.ts'],
38
+ arguments: [
39
+ '--require',
40
+ './scripts/testOrder/randomizeTestOrder.cjs',
41
+ '-r',
42
+ 'ts-node/register',
43
+ 'test/types.test.ts',
44
+ ],
17
45
  },
18
46
  ],
19
47
  'test:coverage': [
48
+ { command: 'npm', arguments: ['run', 'validate:audits'] },
20
49
  { command: 'npm', arguments: ['run', 'test:order'] },
21
50
  { command: 'tsc', arguments: ['--noEmit'] },
22
51
  { command: 'nyc', arguments: ['node', 'test/index.test.js'] },
23
52
  ],
24
- 'test:All': [
25
- { command: 'npm', arguments: ['run', 'test'] },
26
- { command: 'npm', arguments: ['run', 'test:types'] },
27
- ],
53
+ 'test:All': [{ command: 'npm', arguments: ['test'] }],
28
54
  });
29
55
 
30
56
  export function createTaskEnvironment(overrides = {}, inheritedEnvironment = process.env) {
@@ -32,10 +58,18 @@ export function createTaskEnvironment(overrides = {}, inheritedEnvironment = pro
32
58
  }
33
59
 
34
60
  function getTaskExitCode(result) {
35
- if (result.error) throw result.error;
36
- if (typeof result.status === 'number') return result.status;
37
- if (result.signal === 'SIGINT') return 130;
38
- if (result.signal === 'SIGTERM') return 143;
61
+ if (result.error) {
62
+ throw result.error;
63
+ }
64
+ if (typeof result.status === 'number') {
65
+ return result.status;
66
+ }
67
+ if (result.signal === 'SIGINT') {
68
+ return 130;
69
+ }
70
+ if (result.signal === 'SIGTERM') {
71
+ return 143;
72
+ }
39
73
  return 1;
40
74
  }
41
75
 
@@ -57,20 +91,33 @@ function shouldRunTaskStep(taskStep, pathExists) {
57
91
  return !taskStep.whenMissing || !pathExists(taskStep.whenMissing);
58
92
  }
59
93
 
60
- export function runPackageTask(taskName, executeTask = executeTaskStep, taskDefinitions = packageTasks, pathExists = existsSync) {
94
+ export function runPackageTask(
95
+ taskName,
96
+ executeTask = executeTaskStep,
97
+ taskDefinitions = packageTasks,
98
+ pathExists = existsSync,
99
+ ) {
61
100
  const taskSteps = taskDefinitions[taskName];
62
- if (!Array.isArray(taskSteps)) throw new Error('Unknown package task.');
101
+ if (!Array.isArray(taskSteps)) {
102
+ throw new Error('Unknown package task.');
103
+ }
63
104
 
64
105
  for (const taskStep of taskSteps) {
65
- if (!shouldRunTaskStep(taskStep, pathExists)) continue;
106
+ if (!shouldRunTaskStep(taskStep, pathExists)) {
107
+ continue;
108
+ }
66
109
  const exitCode = executeTask(taskStep);
67
- if (exitCode !== 0) return exitCode;
110
+ if (exitCode !== 0) {
111
+ return exitCode;
112
+ }
68
113
  }
69
114
  return 0;
70
115
  }
71
116
 
72
117
  function isDirectExecution() {
73
- if (!process.argv[1]) return false;
118
+ if (!process.argv[1]) {
119
+ return false;
120
+ }
74
121
  return resolve(process.argv[1]) === fileURLToPath(import.meta.url);
75
122
  }
76
123
 
@@ -85,4 +132,6 @@ function runCommandLineTask() {
85
132
  process.exitCode = runPackageTask(taskName);
86
133
  }
87
134
 
88
- if (isDirectExecution()) runCommandLineTask();
135
+ if (isDirectExecution()) {
136
+ runCommandLineTask();
137
+ }
@@ -3,10 +3,16 @@
3
3
  const MAX_TEST_ORDER_SEED = 2_147_483_647;
4
4
 
5
5
  function resolveTestOrderSeed(configuredSeed) {
6
- if (configuredSeed === undefined) return undefined;
7
- if (!/^[1-9]\d*$/.test(configuredSeed)) throw new Error('TEST_ORDER_SEED must be a positive 32-bit integer.');
6
+ if (configuredSeed === undefined) {
7
+ return undefined;
8
+ }
9
+ if (!/^[1-9]\d*$/.test(configuredSeed)) {
10
+ throw new Error('TEST_ORDER_SEED must be a positive 32-bit integer.');
11
+ }
8
12
  const seed = Number(configuredSeed);
9
- if (!Number.isSafeInteger(seed) || seed > MAX_TEST_ORDER_SEED) throw new Error('TEST_ORDER_SEED must be a positive 32-bit integer.');
13
+ if (!Number.isSafeInteger(seed) || seed > MAX_TEST_ORDER_SEED) {
14
+ throw new Error('TEST_ORDER_SEED must be a positive 32-bit integer.');
15
+ }
10
16
  return seed;
11
17
  }
12
18
  function createSeededRandom(seed) {
@@ -25,14 +31,18 @@ function shuffleValues(values, random) {
25
31
  }
26
32
  }
27
33
  function shuffleSuiteTree(suite, random) {
28
- for (const childSuite of suite.suites) shuffleSuiteTree(childSuite, random);
34
+ for (const childSuite of suite.suites) {
35
+ shuffleSuiteTree(childSuite, random);
36
+ }
29
37
  shuffleValues(suite.tests, random);
30
38
  shuffleValues(suite.suites, random);
31
39
  }
32
40
  const mochaHooks = {
33
41
  beforeAll() {
34
42
  const seed = resolveTestOrderSeed(process.env.TEST_ORDER_SEED);
35
- if (seed === undefined) return;
43
+ if (seed === undefined) {
44
+ return;
45
+ }
36
46
  console.log(`Test order seed: ${seed} (reproduce with TEST_ORDER_SEED=${seed})`);
37
47
  shuffleSuiteTree(this.test.parent, createSeededRandom(seed));
38
48
  },
@@ -7,7 +7,9 @@ const TEST_ORDER_INVARIANCE_RULE =
7
7
  "Non-negotiable test order invariance rule: Every test must pass independently of which tests run before or after it, and the suite must pass in every execution order. Each test must establish the state it needs, isolate mutable state, and clean up state it owns; it must never rely on another test's setup, mutations, or cleanup. Default test, CI, and Husky commands must use the test framework's ordinary ordering and must not force randomized ordering. Random-order execution is an explicit diagnostic only, and every failure it exposes must be fixed at the root cause.";
8
8
 
9
9
  function listRepositoryFiles() {
10
- return execFileSync('git', ['ls-files', '--cached', '--others', '--exclude-standard'], { encoding: 'utf8' })
10
+ return execFileSync('git', ['ls-files', '--cached', '--others', '--exclude-standard'], {
11
+ encoding: 'utf8',
12
+ })
11
13
  .trim()
12
14
  .split('\n')
13
15
  .filter(Boolean);
@@ -43,6 +45,10 @@ test('keeps default package scripts on the test framework ordinary ordering', ()
43
45
 
44
46
  for (const [scriptName, command] of Object.entries(packageJson.scripts ?? {})) {
45
47
  assert.equal(typeof command, 'string', `${scriptName} must be a string command.`);
46
- assert.doesNotMatch(command, /--test-randomize|--test-random-seed/, `${scriptName} must not force randomized test ordering.`);
48
+ assert.doesNotMatch(
49
+ command,
50
+ /--test-randomize|--test-random-seed/,
51
+ `${scriptName} must not force randomized test ordering.`,
52
+ );
47
53
  }
48
54
  });
@@ -6,15 +6,22 @@ import test from 'node:test';
6
6
 
7
7
  const require = createRequire(import.meta.url);
8
8
  const repositoryRoot = resolve(import.meta.dirname, '../..');
9
- const packageJson = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
10
- const packageTaskRunnerSource = readFileSync(new URL('../runPackageTask.mjs', import.meta.url), 'utf8');
9
+ const packageJson = JSON.parse(
10
+ readFileSync(new URL('../../package.json', import.meta.url), 'utf8'),
11
+ );
12
+ const packageTaskRunnerSource = readFileSync(
13
+ new URL('../runPackageTask.mjs', import.meta.url),
14
+ 'utf8',
15
+ );
11
16
  const testIndexSource = readFileSync(new URL('../../test/index.test.js', import.meta.url), 'utf8');
12
17
  const { parallelTestFiles } = require('../../test/index.test.js');
13
18
 
14
19
  function listRuntimeTestFiles(directoryPath) {
15
20
  return readdirSync(directoryPath, { withFileTypes: true }).flatMap(entry => {
16
21
  const entryPath = join(directoryPath, entry.name);
17
- if (entry.isDirectory()) return listRuntimeTestFiles(entryPath);
22
+ if (entry.isDirectory()) {
23
+ return listRuntimeTestFiles(entryPath);
24
+ }
18
25
  if (!/\.test\.(?:js|mjs)$/.test(entry.name) || entry.name === 'index.test.js') {
19
26
  return [];
20
27
  }
@@ -24,20 +31,32 @@ function listRuntimeTestFiles(directoryPath) {
24
31
 
25
32
  test('keeps runtime test selection in the index and package scripts short', () => {
26
33
  assert.equal(packageJson.scripts.test, 'node scripts/runPackageTask.mjs test');
27
- assert.equal(packageJson.scripts['test:coverage'], 'node scripts/runPackageTask.mjs test:coverage');
34
+ assert.equal(
35
+ packageJson.scripts['test:coverage'],
36
+ 'node scripts/runPackageTask.mjs test:coverage',
37
+ );
28
38
  assert.match(packageTaskRunnerSource, /arguments: \['run', 'test:order'\]/);
29
- assert.match(packageTaskRunnerSource, /arguments: \['test\/index\.test\.js'\]/);
39
+ assert.match(packageTaskRunnerSource, /arguments: \['node', 'test\/index\.test\.js'\]/);
30
40
  assert.match(packageTaskRunnerSource, /command: 'nyc'/);
31
41
  assert.match(testIndexSource, /parallelTestFiles/);
32
42
  assert.match(testIndexSource, /runIndexedMochaTests/);
33
43
  assert.match(testIndexSource, /if \(require\.main === module\)/);
34
44
  });
35
45
 
36
- test('runs the parallel execution contract in the test-order gate', () => {
37
- assert.match(packageJson.scripts['test:order'], /scripts\/testParallel\/parallelTestPolicy\.test\.mjs/);
38
- assert.match(packageJson.scripts['test:order'], /scripts\/testParallel\/runIndexedMochaTests\.test\.mjs/);
46
+ test('keeps parallel behavior tests in the test-order gate and static policy checks in the audit gate', () => {
47
+ assert.match(
48
+ packageJson.scripts['test:order'],
49
+ /scripts\/testParallel\/runIndexedMochaTests\.test\.mjs/,
50
+ );
51
+ assert.equal(
52
+ packageJson.scripts['validate:audits'],
53
+ 'node scripts/runPackageTask.mjs validate:audits',
54
+ );
39
55
  });
40
56
 
41
57
  test('selects every runtime test file exactly once', () => {
42
- assert.deepEqual([...parallelTestFiles].sort(), listRuntimeTestFiles(resolve(repositoryRoot, 'test')).sort());
58
+ assert.deepEqual(
59
+ [...parallelTestFiles].sort(),
60
+ listRuntimeTestFiles(resolve(repositoryRoot, 'test')).sort(),
61
+ );
43
62
  });
@@ -15,7 +15,9 @@ function resolveParallelJobCount(
15
15
  availableJobCount = availableParallelism(),
16
16
  ) {
17
17
  const requestedJobCount =
18
- configuredJobCount === undefined ? Math.min(availableJobCount, defaultMaximum) : Number.parseInt(configuredJobCount, 10);
18
+ configuredJobCount === undefined
19
+ ? Math.min(availableJobCount, defaultMaximum)
20
+ : Number.parseInt(configuredJobCount, 10);
19
21
 
20
22
  if (!Number.isInteger(requestedJobCount) || requestedJobCount < 1) {
21
23
  throw new Error('TEST_PARALLEL_JOBS must be a positive integer.');
@@ -12,10 +12,16 @@ test('uses bounded Mocha file workers without randomized default ordering', () =
12
12
  const argumentsList = buildMochaArguments(['test/example.test.js'], 2);
13
13
 
14
14
  assert.ok(argumentsList.includes('--parallel'));
15
- assert.deepEqual(argumentsList.slice(argumentsList.indexOf('--jobs'), argumentsList.indexOf('--jobs') + 2), ['--jobs', '2']);
15
+ assert.deepEqual(
16
+ argumentsList.slice(argumentsList.indexOf('--jobs'), argumentsList.indexOf('--jobs') + 2),
17
+ ['--jobs', '2'],
18
+ );
16
19
  assert.ok(argumentsList.includes('test/example.test.js'));
17
20
  });
18
21
 
19
22
  test('rejects invalid worker configuration instead of changing execution silently', () => {
20
- assert.throws(() => resolveParallelJobCount('0', 8, 4, 12), /TEST_PARALLEL_JOBS must be a positive integer/);
23
+ assert.throws(
24
+ () => resolveParallelJobCount('0', 8, 4, 12),
25
+ /TEST_PARALLEL_JOBS must be a positive integer/,
26
+ );
21
27
  });