faf-taf-git 2.2.2 → 2.3.1
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/.github/workflows/ci.yml +4 -4
- package/.github/workflows/{claude-code-review.yml.disabled → claude-code-review.yml} +1 -1
- package/.github/workflows/claude.yml +1 -1
- package/CHANGELOG.md +20 -1
- package/README.md +7 -5
- package/RECEIPT-FORMAT.md +90 -0
- package/action.yml +2 -2
- package/dist/cli.js +3 -53
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1016 -346
- package/dist/index.js.map +1 -1
- package/dist/parsers/index.d.ts +6 -9
- package/dist/parsers/index.d.ts.map +1 -1
- package/dist/parsers/index.js +28 -10
- package/dist/parsers/index.js.map +1 -1
- package/dist/parsers/wjttc.d.ts +38 -0
- package/dist/parsers/wjttc.d.ts.map +1 -0
- package/dist/parsers/wjttc.js +152 -0
- package/dist/parsers/wjttc.js.map +1 -0
- package/package.json +4 -1
- package/project.faf +1 -1
- package/src/cli.ts +4 -54
- package/src/index.ts +2 -2
- package/src/parsers/index.ts +28 -10
- package/src/parsers/wjttc.ts +160 -0
- package/tests/action-bundle.test.ts +34 -0
- package/tests/action-parse-error.test.ts +47 -0
- package/tests/wjttc-parser.test.ts +116 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Action's parse error names every parser the dispatcher tries.
|
|
3
|
+
*
|
|
4
|
+
* It said "Supported: Jest, Vitest." while Bun (2.2.0) and WJTTC (2.3.0)
|
|
5
|
+
* were already live. The CLI and the Action now build the message from the
|
|
6
|
+
* same parser table that parseTestOutput walks.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as os from 'os';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
|
|
12
|
+
// Factory mocks: no real @actions/* module (or its undici network stack) loads.
|
|
13
|
+
jest.mock('@actions/core', () => ({
|
|
14
|
+
getInput: jest.fn(),
|
|
15
|
+
info: jest.fn(),
|
|
16
|
+
warning: jest.fn(),
|
|
17
|
+
debug: jest.fn(),
|
|
18
|
+
setOutput: jest.fn(),
|
|
19
|
+
setFailed: jest.fn(),
|
|
20
|
+
}));
|
|
21
|
+
jest.mock('@actions/exec', () => ({ exec: jest.fn() }));
|
|
22
|
+
|
|
23
|
+
import * as core from '@actions/core';
|
|
24
|
+
|
|
25
|
+
describe('Action: unparseable test output', () => {
|
|
26
|
+
it('fails with a message naming Bun, WJTTC, Jest and Vitest', () => {
|
|
27
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'taf-action-'));
|
|
28
|
+
const file = path.join(dir, 'test-output.txt');
|
|
29
|
+
fs.writeFileSync(file, 'no test summary here\n');
|
|
30
|
+
(core.getInput as jest.Mock).mockImplementation((name: string) =>
|
|
31
|
+
name === 'test-output-file' ? file : '',
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// src/index.ts runs the Action on load; the parse failure is reached
|
|
35
|
+
// before its first await, so setFailed has been called when this returns.
|
|
36
|
+
jest.isolateModules(() => {
|
|
37
|
+
require('../src/index');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const failures = (core.setFailed as jest.Mock).mock.calls.map((c) => String(c[0]));
|
|
41
|
+
expect(failures).toHaveLength(1);
|
|
42
|
+
for (const parser of ['Bun', 'WJTTC', 'Jest', 'Vitest']) {
|
|
43
|
+
expect(failures[0]).toContain(parser);
|
|
44
|
+
}
|
|
45
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WJTTC output parser — human log + --json suite
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { parseWjttcOutput } from '../src/parsers/wjttc';
|
|
6
|
+
import { parseTestOutput } from '../src/parsers';
|
|
7
|
+
|
|
8
|
+
describe('parseWjttcOutput', () => {
|
|
9
|
+
describe('human log', () => {
|
|
10
|
+
test('all passing', () => {
|
|
11
|
+
const output = `pc-ai WJTTC
|
|
12
|
+
----------
|
|
13
|
+
PASS VAL-01 valid-simple portfolio accepts
|
|
14
|
+
PASS OPT-01 $450 / MCC 4511
|
|
15
|
+
----------
|
|
16
|
+
2/2 passed
|
|
17
|
+
`;
|
|
18
|
+
const r = parseWjttcOutput(output);
|
|
19
|
+
expect(r).not.toBeNull();
|
|
20
|
+
expect(r!.total).toBe(2);
|
|
21
|
+
expect(r!.passed).toBe(2);
|
|
22
|
+
expect(r!.failed).toBe(0);
|
|
23
|
+
expect(r!.result).toBe('PASSED');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('mixed pass/fail uses summary and FAIL lines', () => {
|
|
27
|
+
const output = `pc-ai WJTTC
|
|
28
|
+
----------
|
|
29
|
+
PASS GATE-01 valid portfolio reaches optimize
|
|
30
|
+
FAIL DEPLOY-01 production serves the committed build
|
|
31
|
+
----------
|
|
32
|
+
1/2 passed
|
|
33
|
+
`;
|
|
34
|
+
const r = parseWjttcOutput(output);
|
|
35
|
+
expect(r).not.toBeNull();
|
|
36
|
+
expect(r!.total).toBe(2);
|
|
37
|
+
expect(r!.passed).toBe(1);
|
|
38
|
+
expect(r!.failed).toBe(1);
|
|
39
|
+
expect(r!.result).toBe('FAILED');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('rejects bare N/N passed without WJTTC banner', () => {
|
|
43
|
+
expect(parseWjttcOutput('12/12 passed\n')).toBeNull();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('--json suite', () => {
|
|
48
|
+
test('pc-ai-wjttc summary object', () => {
|
|
49
|
+
const output = JSON.stringify({
|
|
50
|
+
suite: 'pc-ai-wjttc',
|
|
51
|
+
total: 33,
|
|
52
|
+
passed: 31,
|
|
53
|
+
failed: 2,
|
|
54
|
+
results: [],
|
|
55
|
+
});
|
|
56
|
+
const r = parseWjttcOutput(output);
|
|
57
|
+
expect(r).not.toBeNull();
|
|
58
|
+
expect(r!.total).toBe(33);
|
|
59
|
+
expect(r!.passed).toBe(31);
|
|
60
|
+
expect(r!.failed).toBe(2);
|
|
61
|
+
expect(r!.result).toBe('FAILED');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('prefers results[] length when it disagrees with total (partition)', () => {
|
|
65
|
+
const output = JSON.stringify({
|
|
66
|
+
suite: 'pc-ai-wjttc',
|
|
67
|
+
total: 33,
|
|
68
|
+
passed: 33,
|
|
69
|
+
failed: 0,
|
|
70
|
+
results: [
|
|
71
|
+
{ id: 'VAL-01', ok: true },
|
|
72
|
+
{ id: 'OPT-01', ok: true },
|
|
73
|
+
{ id: 'GATE-01', ok: false },
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
const r = parseWjttcOutput(output);
|
|
77
|
+
expect(r).not.toBeNull();
|
|
78
|
+
expect(r!.total).toBe(3);
|
|
79
|
+
expect(r!.passed).toBe(2);
|
|
80
|
+
expect(r!.failed).toBe(1);
|
|
81
|
+
expect(r!.result).toBe('FAILED');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('ignores other JSON suites', () => {
|
|
85
|
+
const output = JSON.stringify({
|
|
86
|
+
suite: 'pc-ai-deployed',
|
|
87
|
+
total: 12,
|
|
88
|
+
passed: 12,
|
|
89
|
+
failed: 0,
|
|
90
|
+
});
|
|
91
|
+
expect(parseWjttcOutput(output)).toBeNull();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('dispatcher', () => {
|
|
96
|
+
test('parseTestOutput picks WJTTC human log', () => {
|
|
97
|
+
const output = `pc-ai WJTTC
|
|
98
|
+
----------
|
|
99
|
+
PASS FAF-01 project.faf claims match
|
|
100
|
+
----------
|
|
101
|
+
1/1 passed
|
|
102
|
+
`;
|
|
103
|
+
const r = parseTestOutput(output);
|
|
104
|
+
expect(r).not.toBeNull();
|
|
105
|
+
expect(r!.total).toBe(1);
|
|
106
|
+
expect(r!.result).toBe('PASSED');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('does not steal Jest Tests: line', () => {
|
|
110
|
+
const output = 'Tests: 10 passed, 10 total';
|
|
111
|
+
const r = parseTestOutput(output);
|
|
112
|
+
expect(r).not.toBeNull();
|
|
113
|
+
expect(r!.total).toBe(10);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|