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.
@@ -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
+ });