Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions packages/core/src/lib/implementation/persist.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ describe('persistReport', () => {
'utf8',
);
expect(mdReport).toContain('Code PushUp Report');
expect(mdReport).toMatch(
/\|\s*🏷 Category\s*\|\s*⭐ Score\s*\|\s*🛡 Audits\s*\|/,
);
expect(mdReport).toContainMarkdownTableRow([
'🏷 Category',
'⭐ Score',
'🛡 Audits',
]);

const jsonReport: Report = JSON.parse(
await readFile(path.join(MEMFS_VOLUME, 'report.json'), 'utf8'),
Expand Down
1 change: 1 addition & 0 deletions packages/core/vite.config.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default defineConfig({
'../../testing/test-setup/src/lib/reset.mocks.ts',
'../../testing/test-setup/src/lib/portal-client.mock.ts',
'../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
'../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
],
},
});
85 changes: 57 additions & 28 deletions packages/utils/src/lib/reports/generate-md-report.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ describe('auditDetailsIssues', () => {
severity: 'warning',
} as Issue,
])?.toString(),
).toMatch(/\|\s*4-7\s*\|/);
).toContainMarkdownTableRow(['⚠️ _warning_', '', '`index.js`', '4-7']);
});
});

Expand Down Expand Up @@ -286,8 +286,8 @@ describe('auditDetails', () => {
} as AuditReport).toString();
expect(md).toMatch('<details>');
expect(md).toMatch('#### Elements');
expect(md).toMatch(/\|\s*button\s*\|/);
expect(md).toMatch(/\|\s*div\s*\|/);
expect(md).toContainMarkdownTableRow(['button']);
expect(md).toContainMarkdownTableRow(['div']);
expect(md).not.toMatch('#### Issues');
});

Expand Down Expand Up @@ -375,10 +375,13 @@ describe('auditsSection', () => {
],
} as ScoredReport).toString();
expect(md).toMatch('#### Issues');
expect(md).toMatch(
/\|\s*Severity\s*\|\s*Message\s*\|\s*Source file\s*\|\s*Line\(s\)\s*\|/,
);
expect(md).toMatch(/\|\s*value\s*\|/);
expect(md).toContainMarkdownTableRow([
'Severity',
'Message',
'Source file',
'Line(s)',
]);
expect(md).toContainMarkdownTableRow(['value']);
});

it('should render audit meta information', () => {
Expand Down Expand Up @@ -472,12 +475,23 @@ describe('aboutSection', () => {
],
categories: Array.from({ length: 3 }),
} as ScoredReport).toString();
expect(md).toMatch(
/\|\s*Commit\s*\|\s*Version\s*\|\s*Duration\s*\|\s*Plugins\s*\|\s*Categories\s*\|\s*Audits\s*\|/,
);
expect(md).toMatch(
/\|\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*\|/,
);

expect(md).toContainMarkdownTableRow([
'Commit',
'Version',
'Duration',
'Plugins',
'Categories',
'Audits',
]);
expect(md).toContainMarkdownTableRow([
'ci: update action (535b8e9e557336618a764f3fa45609d224a62837)',
'`v1.0.0`',
'4.20 s',
'1',
'3',
'3',
]);
});

it('should return plugins section with content', () => {
Expand All @@ -498,15 +512,25 @@ describe('aboutSection', () => {
},
],
} as ScoredReport).toString();
expect(md).toMatch(
/\|\s*Plugin\s*\|\s*Audits\s*\|\s*Version\s*\|\s*Duration\s*\|/,
);
expect(md).toMatch(
/\|\s*Lighthouse\s*\|\s*78\s*\|\s*`1.0.1`\s*\|\s*15.37 s\s*\|/,
);
expect(md).toMatch(
/\|\s*File Size\s*\|\s*2\s*\|\s*`0.3.12`\s*\|\s*260 ms\s*\|/,
);

expect(md).toContainMarkdownTableRow([
'Plugin',
'Audits',
'Version',
'Duration',
]);
expect(md).toContainMarkdownTableRow([
'Lighthouse',
'78',
'`1.0.1`',
'15.37 s',
]);
expect(md).toContainMarkdownTableRow([
'File Size',
'2',
'`0.3.12`',
'260 ms',
]);
});

it('should return full about section', () => {
Expand Down Expand Up @@ -534,19 +558,24 @@ describe('generateMdReport', () => {
// report title
expect(md).toMatch('# Code PushUp Report');
// categories section heading
expect(md).toMatch(
/\|\s*🏷 Category\s*\|\s*⭐ Score\s*\|\s*🛡 Audits\s*\|/,
);
expect(md).toContainMarkdownTableRow([
'🏷 Category',
'⭐ Score',
'🛡 Audits',
]);
// categories section heading
expect(md).toMatch('## 🏷 Categories');
// audits heading
expect(md).toMatch('## 🛡️ Audits');
// about section heading
expect(md).toMatch('## About');
// plugin table
expect(md).toMatch(
/\|\s*Plugin\s*\|\s*Audits\s*\|\s*Version\s*\|\s*Duration\s*\|/,
);
expect(md).toContainMarkdownTableRow([
'Plugin',
'Audits',
'Version',
'Duration',
]);
// made with <3
expect(md).toMatch('Made with ❤ by [Code PushUp]');
});
Expand Down
1 change: 1 addition & 0 deletions packages/utils/vite.config.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default defineConfig({
'../../testing/test-setup/src/lib/console.mock.ts',
'../../testing/test-setup/src/lib/reset.mocks.ts',
'../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
'../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
],
},
});
43 changes: 43 additions & 0 deletions testing/test-setup/src/lib/extend/markdown-table.matcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { SyncExpectationResult } from '@vitest/expect';
import { expect } from 'vitest';

export type CustomMarkdownTableMatchers = {
toContainMarkdownTableRow: (cells: string[]) => void;
};

expect.extend({
toContainMarkdownTableRow: assertMarkdownTableRow,
});

function assertMarkdownTableRow(
actual: string,
expected: string[],
): SyncExpectationResult {
const rows = actual
.split('\n')
.map(line => line.trim())
.filter(line => line.startsWith('|') && line.endsWith('|'))
.map(line =>
line
.slice(1, -1)
.split(/(?<!\\)\|/)
.map(cell => cell.replace(/\\\|/g, '|').trim()),
);

const pass = rows.some(
row =>
row.length === expected.length &&
row.every((cell, i) => cell === expected[i]),
);
return pass
? {
pass,
message: () =>
`Expected markdown not to contain a table row with cells: ${expected.join(', ')}`,
}
: {
pass,
message: () =>
`Expected markdown to contain a table row with cells: ${expected.join(', ')}`,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { describe, expect, it } from 'vitest';

describe('markdown-table-matcher', () => {
it('should match header and data rows in a markdown table', () => {
const markdown = `
| 🏷 Category | ⭐ Score | 🛡 Audits |
| :-------------------------- | :-------: | :-------: |
| [Security](#security) | 🟡 **81** | 2 |
| [Performance](#performance) | 🟡 **64** | 56 |
| [SEO](#seo) | 🟡 **61** | 11 |
`;

expect(markdown).toContainMarkdownTableRow([
'🏷 Category',
'⭐ Score',
'🛡 Audits',
]);
expect(markdown).toContainMarkdownTableRow([
':--------------------------',
':-------:',
':-------:',
]);
expect(markdown).toContainMarkdownTableRow([
'[Performance](#performance)',
'🟡 **64**',
'56',
]);
expect(markdown).not.toContainMarkdownTableRow([
'Non-existent cell',
'Row cell',
'Test cell',
]);
});

it('should match table rows containing escaped pipe symbols', () => {
const markdown = `
| Package | Versions |
| :--------- | :----------------------- |
| \`eslint\` | \`^8.0.0 \\|\\| ^9.0.0\` |
`;
expect(markdown).toContainMarkdownTableRow([
'`eslint`',
'`^8.0.0 || ^9.0.0`',
]);
});

it('should match table rows with an empty cell', () => {
const markdown = `
| Severity | Message | Source file | Line(s) |
| :--------: | :------------------------ | :-------------------- | :-----: |
| 🚨 _error_ | File size is 20KB too big | \`list.component.ts\` | |
`;
expect(markdown).toContainMarkdownTableRow([
'🚨 _error_',
'File size is 20KB too big',
'`list.component.ts`',
'',
]);
});
});
6 changes: 5 additions & 1 deletion testing/test-setup/src/vitest.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import type { CustomMarkdownTableMatchers } from './lib/extend/markdown-table.matcher.js';
import type {
CustomAsymmetricPathMatchers,
CustomPathMatchers,
} from './lib/extend/path.matcher.js';
import type { CustomUiLoggerMatchers } from './lib/extend/ui-logger.matcher.js';

declare module 'vitest' {
interface Assertion extends CustomPathMatchers, CustomUiLoggerMatchers {}
interface Assertion
extends CustomPathMatchers,
CustomUiLoggerMatchers,
CustomMarkdownTableMatchers {}
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface AsymmetricMatchersContaining extends CustomAsymmetricPathMatchers {}
}
Expand Down
1 change: 1 addition & 0 deletions testing/test-setup/vite.config.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default defineConfig({
setupFiles: [
'../test-setup/src/lib/reset.mocks.ts',
'../test-setup/src/lib/extend/path.matcher.ts',
'../test-setup/src/lib/extend/markdown-table.matcher.ts',
],
},
});
Loading