Skip to content

Commit 1ffadd5

Browse files
committed
test: add custom matcher for markdown table rows
1 parent b230a3d commit 1ffadd5

File tree

8 files changed

+143
-32
lines changed

8 files changed

+143
-32
lines changed

packages/core/src/lib/implementation/persist.unit.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ describe('persistReport', () => {
7171
'utf8',
7272
);
7373
expect(mdReport).toContain('Code PushUp Report');
74-
expect(mdReport).toMatch(
75-
/\|\s*🏷 Category\s*\|\s* Score\s*\|\s*🛡 Audits\s*\|/,
76-
);
74+
expect(mdReport).toContainMarkdownTableRow([
75+
'🏷 Category',
76+
'⭐ Score',
77+
'🛡 Audits',
78+
]);
7779

7880
const jsonReport: Report = JSON.parse(
7981
await readFile(path.join(MEMFS_VOLUME, 'report.json'), 'utf8'),

packages/core/vite.config.unit.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default defineConfig({
2929
'../../testing/test-setup/src/lib/reset.mocks.ts',
3030
'../../testing/test-setup/src/lib/portal-client.mock.ts',
3131
'../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
32+
'../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
3233
],
3334
},
3435
});

packages/utils/src/lib/reports/generate-md-report.unit.test.ts

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ describe('auditDetailsIssues', () => {
176176
severity: 'warning',
177177
} as Issue,
178178
])?.toString(),
179-
).toMatch(/\|\s*4-7\s*\|/);
179+
).toContainMarkdownTableRow(['⚠️ _warning_', '`index.js`', '4-7']);
180180
});
181181
});
182182

@@ -286,8 +286,8 @@ describe('auditDetails', () => {
286286
} as AuditReport).toString();
287287
expect(md).toMatch('<details>');
288288
expect(md).toMatch('#### Elements');
289-
expect(md).toMatch(/\|\s*button\s*\|/);
290-
expect(md).toMatch(/\|\s*div\s*\|/);
289+
expect(md).toContainMarkdownTableRow(['button']);
290+
expect(md).toContainMarkdownTableRow(['div']);
291291
expect(md).not.toMatch('#### Issues');
292292
});
293293

@@ -375,10 +375,13 @@ describe('auditsSection', () => {
375375
],
376376
} as ScoredReport).toString();
377377
expect(md).toMatch('#### Issues');
378-
expect(md).toMatch(
379-
/\|\s*Severity\s*\|\s*Message\s*\|\s*Source file\s*\|\s*Line\(s\)\s*\|/,
380-
);
381-
expect(md).toMatch(/\|\s*value\s*\|/);
378+
expect(md).toContainMarkdownTableRow([
379+
'Severity',
380+
'Message',
381+
'Source file',
382+
'Line(s)',
383+
]);
384+
expect(md).toContainMarkdownTableRow(['value']);
382385
});
383386

384387
it('should render audit meta information', () => {
@@ -472,12 +475,23 @@ describe('aboutSection', () => {
472475
],
473476
categories: Array.from({ length: 3 }),
474477
} as ScoredReport).toString();
475-
expect(md).toMatch(
476-
/\|\s*Commit\s*\|\s*Version\s*\|\s*Duration\s*\|\s*Plugins\s*\|\s*Categories\s*\|\s*Audits\s*\|/,
477-
);
478-
expect(md).toMatch(
479-
/\|\s*ci: update action \(535b8e9e557336618a764f3fa45609d224a62837\)\s*\|\s*`v1.0.0`\s*\|\s*4.20 s\s*\|\s*1\s*\|\s*3\s*\|\s*3\s*\|/,
480-
);
478+
479+
expect(md).toContainMarkdownTableRow([
480+
'Commit',
481+
'Version',
482+
'Duration',
483+
'Plugins',
484+
'Categories',
485+
'Audits',
486+
]);
487+
expect(md).toContainMarkdownTableRow([
488+
'ci: update action (535b8e9e557336618a764f3fa45609d224a62837)',
489+
'`v1.0.0`',
490+
'4.20 s',
491+
'1',
492+
'3',
493+
'3',
494+
]);
481495
});
482496

483497
it('should return plugins section with content', () => {
@@ -498,15 +512,25 @@ describe('aboutSection', () => {
498512
},
499513
],
500514
} as ScoredReport).toString();
501-
expect(md).toMatch(
502-
/\|\s*Plugin\s*\|\s*Audits\s*\|\s*Version\s*\|\s*Duration\s*\|/,
503-
);
504-
expect(md).toMatch(
505-
/\|\s*Lighthouse\s*\|\s*78\s*\|\s*`1.0.1`\s*\|\s*15.37 s\s*\|/,
506-
);
507-
expect(md).toMatch(
508-
/\|\s*File Size\s*\|\s*2\s*\|\s*`0.3.12`\s*\|\s*260 ms\s*\|/,
509-
);
515+
516+
expect(md).toContainMarkdownTableRow([
517+
'Plugin',
518+
'Audits',
519+
'Version',
520+
'Duration',
521+
]);
522+
expect(md).toContainMarkdownTableRow([
523+
'Lighthouse',
524+
'78',
525+
'`1.0.1`',
526+
'15.37 s',
527+
]);
528+
expect(md).toContainMarkdownTableRow([
529+
'File Size',
530+
'2',
531+
'`0.3.12`',
532+
'260 ms',
533+
]);
510534
});
511535

512536
it('should return full about section', () => {
@@ -534,19 +558,24 @@ describe('generateMdReport', () => {
534558
// report title
535559
expect(md).toMatch('# Code PushUp Report');
536560
// categories section heading
537-
expect(md).toMatch(
538-
/\|\s*🏷 Category\s*\|\s* Score\s*\|\s*🛡 Audits\s*\|/,
539-
);
561+
expect(md).toContainMarkdownTableRow([
562+
'🏷 Category',
563+
'⭐ Score',
564+
'🛡 Audits',
565+
]);
540566
// categories section heading
541567
expect(md).toMatch('## 🏷 Categories');
542568
// audits heading
543569
expect(md).toMatch('## 🛡️ Audits');
544570
// about section heading
545571
expect(md).toMatch('## About');
546572
// plugin table
547-
expect(md).toMatch(
548-
/\|\s*Plugin\s*\|\s*Audits\s*\|\s*Version\s*\|\s*Duration\s*\|/,
549-
);
573+
expect(md).toContainMarkdownTableRow([
574+
'Plugin',
575+
'Audits',
576+
'Version',
577+
'Duration',
578+
]);
550579
// made with <3
551580
expect(md).toMatch('Made with ❤ by [Code PushUp]');
552581
});

packages/utils/vite.config.unit.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export default defineConfig({
2727
'../../testing/test-setup/src/lib/console.mock.ts',
2828
'../../testing/test-setup/src/lib/reset.mocks.ts',
2929
'../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
30+
'../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
3031
],
3132
},
3233
});
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { SyncExpectationResult } from '@vitest/expect';
2+
import { expect } from 'vitest';
3+
4+
export type CustomMarkdownTableMatchers = {
5+
toContainMarkdownTableRow: (cells: string[]) => void;
6+
};
7+
8+
expect.extend({
9+
toContainMarkdownTableRow: assertMarkdownTableRow,
10+
});
11+
12+
function assertMarkdownTableRow(
13+
actual: string,
14+
expected: string[],
15+
): SyncExpectationResult {
16+
const rows = actual
17+
.split('\n')
18+
.map(line => line.trim())
19+
.filter(line => line.startsWith('|') && line.endsWith('|'))
20+
.map(line =>
21+
line
22+
.split('|')
23+
.map(cell => cell.trim())
24+
.filter(Boolean),
25+
)
26+
.filter(row => row.some(cell => /\w/.test(cell)));
27+
28+
const pass = rows.some(
29+
row =>
30+
row.length === expected.length &&
31+
row.every((cell, i) => cell === expected[i]),
32+
);
33+
return pass
34+
? {
35+
pass,
36+
message: () =>
37+
`Expected markdown not to contain a table row with cells: ${expected.join(', ')}`,
38+
}
39+
: {
40+
pass,
41+
message: () =>
42+
`Expected markdown to contain a table row with cells: ${expected.join(', ')}`,
43+
};
44+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
describe('markdown-table-matcher', () => {
4+
const markdown = `
5+
| 🏷 Category | ⭐ Score | 🛡 Audits |
6+
|--------------|-------------|-----------|
7+
| Performance | 🟡 **61** | 2 |
8+
| SEO | 🟢 **100** | 1 |
9+
| PWA | 🔴 **0** | 1 |
10+
`;
11+
12+
it('toContainMarkdownTableRow matches correctly', () => {
13+
expect(markdown).toContainMarkdownTableRow([
14+
'🏷 Category',
15+
'⭐ Score',
16+
'🛡 Audits',
17+
]);
18+
expect(markdown).toContainMarkdownTableRow([
19+
'Performance',
20+
'🟡 **61**',
21+
'2',
22+
]);
23+
expect(markdown).not.toContainMarkdownTableRow([
24+
'Non-existent cell',
25+
'Row cell',
26+
'Test cell',
27+
]);
28+
});
29+
});

testing/test-setup/src/vitest.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
/* eslint-disable @typescript-eslint/consistent-type-definitions */
2+
import type { CustomMarkdownTableMatchers } from './lib/extend/markdown-table.matcher.js';
23
import type {
34
CustomAsymmetricPathMatchers,
45
CustomPathMatchers,
56
} from './lib/extend/path.matcher.js';
67
import type { CustomUiLoggerMatchers } from './lib/extend/ui-logger.matcher.js';
78

89
declare module 'vitest' {
9-
interface Assertion extends CustomPathMatchers, CustomUiLoggerMatchers {}
10+
interface Assertion
11+
extends CustomPathMatchers,
12+
CustomUiLoggerMatchers,
13+
CustomMarkdownTableMatchers {}
1014
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
1115
interface AsymmetricMatchersContaining extends CustomAsymmetricPathMatchers {}
1216
}

testing/test-setup/vite.config.unit.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export default defineConfig({
2323
setupFiles: [
2424
'../test-setup/src/lib/reset.mocks.ts',
2525
'../test-setup/src/lib/extend/path.matcher.ts',
26+
'../test-setup/src/lib/extend/markdown-table.matcher.ts',
2627
],
2728
},
2829
});

0 commit comments

Comments
 (0)