Skip to content

Commit b80255b

Browse files
authored
fix(testing): fix tests for Windows (#165)
In this PR, I identified and fixed various issue while running tests in the Windows environment: - shell needs to be specified to run programs in command shell on Windows, as described [here](https://stackoverflow.com/questions/60386867/node-spawn-child-process-not-working-in-windows) - path notation on Windows is different - JSON formatting is different for UNIX and Windows - writing into files replaced by echo command which works seamlessly on Windows - glob patterns require extra quotation marks for argument expansion on Linux - recreating tmp folder caused issues for me so I partially fixed it via adding the recursive option Note: This is the same scope as #131. Unfortunately, merging changes from the test refactor did not go well so I started off a clean branch and re-applied the changes.
1 parent 7c81f81 commit b80255b

29 files changed

+200
-1160
lines changed

e2e/cli-e2e/tests/__snapshots__/collect.spec.ts.snap

-1,002
Large diffs are not rendered by default.

e2e/cli-e2e/tests/collect.spec.ts

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { join } from 'path';
12
import { afterEach, beforeEach, vi } from 'vitest';
23
import { PluginReport, Report, reportSchema } from '@code-pushup/models';
34
import { executeProcess, readJsonFile, readTextFile } from '@code-pushup/utils';
@@ -21,18 +22,21 @@ describe('CLI collect', () => {
2122
plugins: report.plugins.map(omitVariableData) as PluginReport[],
2223
});
2324

25+
const cliPath = join('..', '..', 'dist', 'packages', 'cli');
26+
2427
beforeEach(async () => {
2528
vi.clearAllMocks();
2629
cleanFolderPutGitKeep();
2730
});
31+
2832
afterEach(() => {
2933
cleanFolderPutGitKeep();
3034
});
3135

3236
it('should run ESLint plugin and create report.json', async () => {
3337
const { code, stderr } = await executeProcess({
3438
command: 'npx',
35-
args: ['../../dist/packages/cli', 'collect'],
39+
args: [cliPath, 'collect'],
3640
cwd: 'examples/react-todos-app',
3741
});
3842

@@ -48,7 +52,7 @@ describe('CLI collect', () => {
4852
it('should create report.md', async () => {
4953
const { code, stderr } = await executeProcess({
5054
command: 'npx',
51-
args: ['../../dist/packages/cli', 'collect', '--persist.format=md'],
55+
args: [cliPath, 'collect', '--persist.format=md'],
5256
cwd: 'examples/react-todos-app',
5357
});
5458

@@ -65,12 +69,7 @@ describe('CLI collect', () => {
6569
it('should print report summary to stdout', async () => {
6670
const { code, stdout, stderr } = await executeProcess({
6771
command: 'npx',
68-
args: [
69-
'../../dist/packages/cli',
70-
'collect',
71-
'--verbose',
72-
'--persist.format=stdout',
73-
],
72+
args: [cliPath, 'collect', '--verbose', '--persist.format=stdout'],
7473
cwd: 'examples/react-todos-app',
7574
});
7675

packages/cli/code-pushup.config.ts renamed to packages/cli/code-pushup.config.mock.ts

+22-28
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { join } from 'path';
2+
import { echoRunnerConfig } from '../models/test/fixtures/echo-runner-config.mock';
3+
14
const outputDir = 'tmp';
25

36
export default {
@@ -37,35 +40,26 @@ export default {
3740
docsUrl: 'http://www.my-docs.dev?slug=dummy-audit-3',
3841
},
3942
],
40-
runner: {
41-
command: 'node',
42-
args: [
43-
'-e',
44-
`require('fs').writeFileSync('${outputDir}/dummy-plugin-output.json', '${JSON.stringify(
45-
[
46-
{
47-
title: 'Dummy Audit 1',
48-
slug: 'dummy-audit-1',
49-
value: 420,
50-
score: 0.42,
51-
},
52-
{
53-
title: 'Dummy Audit 2',
54-
slug: 'dummy-audit-2',
55-
value: 80,
56-
score: 0,
57-
},
58-
{
59-
title: 'Dummy Audit 3',
60-
slug: 'dummy-audit-3',
61-
value: 12,
62-
score: 0.12,
63-
},
64-
],
65-
)}')`,
43+
runner: echoRunnerConfig(
44+
[
45+
{
46+
slug: 'dummy-audit-1',
47+
value: 420,
48+
score: 0.42,
49+
},
50+
{
51+
slug: 'dummy-audit-2',
52+
value: 80,
53+
score: 0,
54+
},
55+
{
56+
slug: 'dummy-audit-3',
57+
value: 12,
58+
score: 0.12,
59+
},
6660
],
67-
outputFile: `${outputDir}/dummy-plugin-output.json`,
68-
},
61+
join(outputDir, 'dummy-plugin-output.json'),
62+
),
6963
},
7064
],
7165
categories: [

packages/cli/src/lib/implementation/config-middleware.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ describe('applyConfigMiddleware', () => {
4242
});
4343

4444
it('should throw with invalid config', async () => {
45-
const invalidConfig = 'wrong/path/to/config';
45+
const invalidConfig = join('wrong', 'path', 'to', 'config');
4646
let error: Error = new Error();
4747
await configMiddleware({ config: invalidConfig }).catch(e => (error = e));
4848
expect(error?.message).toContain(invalidConfig);

packages/cli/test/fs.mock.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function cleanFolder<T extends object>(
66
content?: { [key in keyof T]: string },
77
) {
88
rmSync(dirName, { recursive: true, force: true });
9-
mkdirSync(dirName);
9+
mkdirSync(dirName, { recursive: true });
1010
if (content) {
1111
for (const fileName in content) {
1212
writeFileSync(join(dirName, fileName), content[fileName]);
@@ -19,7 +19,7 @@ export function cleanFolderPutGitKeep<T extends object>(
1919
content?: { [key in keyof T]: string },
2020
) {
2121
rmSync(dirName, { recursive: true, force: true });
22-
mkdirSync(dirName);
22+
mkdirSync(dirName, { recursive: true });
2323
writeFileSync(join(dirName, '.gitkeep'), '');
2424
if (content) {
2525
for (const fileName in content) {

packages/core/src/lib/implementation/execute-plugin.spec.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { join } from 'path';
12
import { beforeEach, describe, expect, it } from 'vitest';
23
import {
34
AuditReport,
@@ -6,8 +7,8 @@ import {
67
} from '@code-pushup/models';
78
import {
89
auditReport,
10+
echoRunnerConfig,
911
pluginConfig,
10-
runnerConfig,
1112
} from '@code-pushup/models/testing';
1213
import { cleanFolder } from '../../../test';
1314
import { executePlugin, executePlugins } from './execute-plugin';
@@ -45,7 +46,7 @@ describe('executePlugin', () => {
4546
{ p: 42 } as unknown as AuditReport,
4647
];
4748
const pluginCfg = pluginConfig([auditReport()], {
48-
runner: runnerConfig(invalidAuditOutputs),
49+
runner: echoRunnerConfig(invalidAuditOutputs, join('tmp', 'out.json')),
4950
});
5051
await expect(() => executePlugin(pluginCfg)).rejects.toThrowError(
5152
'Plugin output of plugin with slug mock-plugin-slug',

packages/core/test/fs.mock.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function cleanFolder<T extends object>(
66
content?: { [key in keyof T]: string },
77
) {
88
rmSync(dirName, { recursive: true, force: true });
9-
mkdirSync(dirName);
9+
mkdirSync(dirName, { recursive: true });
1010
if (content) {
1111
for (const fileName in content) {
1212
writeFileSync(join(dirName, fileName), content[fileName]);
@@ -19,7 +19,7 @@ export function cleanFolderPutGitKeep<T extends object>(
1919
content?: { [key in keyof T]: string },
2020
) {
2121
rmSync(dirName, { recursive: true, force: true });
22-
mkdirSync(dirName);
22+
mkdirSync(dirName, { recursive: true });
2323
writeFileSync(join(dirName, '.gitkeep'), '');
2424
if (content) {
2525
for (const fileName in content) {

packages/models/test/fixtures/code-pushup.config.mock.cjs

+12-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { join } from 'path';
2+
import { echoRunnerConfig } from './echo-runner-config.mock';
3+
14
const outputDir = 'tmp';
25
module.exports = {
36
upload: {
@@ -17,23 +20,16 @@ module.exports = {
1720
docsUrl: 'http://www.my-docs.dev',
1821
},
1922
],
20-
runner: {
21-
command: 'node',
22-
args: [
23-
'-e',
24-
`require('fs').writeFileSync('${outputDir}/out.json', '${JSON.stringify(
25-
[
26-
{
27-
title: 'dummy-title',
28-
slug: 'command-object-audit-slug',
29-
value: 0,
30-
score: 0,
31-
},
32-
],
33-
)}')`,
23+
runner: echoRunnerConfig(
24+
[
25+
{
26+
slug: 'command-object-audit-slug',
27+
value: 0,
28+
score: 0,
29+
},
3430
],
35-
outputFile: `${outputDir}/out.json`,
36-
},
31+
join(outputDir, 'out.json'),
32+
),
3733
groups: [],
3834
slug: 'command-object-plugin',
3935
title: 'command-object plugin',

packages/models/test/fixtures/code-pushup.config.mock.js

+12-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { join } from 'path';
2+
import { echoRunnerConfig } from './echo-runner-config.mock';
3+
14
const outputDir = 'tmp';
25
export default {
36
upload: {
@@ -17,23 +20,16 @@ export default {
1720
docsUrl: 'http://www.my-docs.dev',
1821
},
1922
],
20-
runner: {
21-
command: 'node',
22-
args: [
23-
'-e',
24-
`require('fs').writeFileSync('${outputDir}/out.json', '${JSON.stringify(
25-
[
26-
{
27-
title: 'dummy-title',
28-
slug: 'command-object-audit-slug',
29-
value: 0,
30-
score: 0,
31-
},
32-
],
33-
)}')`,
23+
runner: echoRunnerConfig(
24+
[
25+
{
26+
slug: 'command-object-audit-slug',
27+
value: 0,
28+
score: 0,
29+
},
3430
],
35-
outputFile: `${outputDir}/out.json`,
36-
},
31+
join(outputDir, 'out.json'),
32+
),
3733
groups: [],
3834
slug: 'command-object-plugin',
3935
title: 'command-object plugin',

packages/models/test/fixtures/code-pushup.config.mock.mjs

+12-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { join } from 'path';
2+
import { echoRunnerConfig } from './echo-runner-config.mock';
3+
14
const outputDir = 'tmp';
25
export default {
36
upload: {
@@ -17,23 +20,16 @@ export default {
1720
docsUrl: 'http://www.my-docs.dev',
1821
},
1922
],
20-
runner: {
21-
command: 'node',
22-
args: [
23-
'-e',
24-
`require('fs').writeFileSync('${outputDir}/out.json', '${JSON.stringify(
25-
[
26-
{
27-
title: 'dummy-title',
28-
slug: 'command-object-audit-slug',
29-
value: 0,
30-
score: 0,
31-
},
32-
],
33-
)}')`,
23+
runner: echoRunnerConfig(
24+
[
25+
{
26+
slug: 'command-object-audit-slug',
27+
value: 0,
28+
score: 0,
29+
},
3430
],
35-
outputFile: `${outputDir}/out.json`,
36-
},
31+
join(outputDir, 'out.json'),
32+
),
3733
groups: [],
3834
slug: 'command-object-plugin',
3935
title: 'command-object plugin',

packages/models/test/fixtures/code-pushup.config.mock.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { join } from 'path';
12
import { CoreConfig } from '../../src';
3+
import { echoRunnerConfig } from './echo-runner-config.mock';
24
import { auditReport } from './plugin-config.mock';
3-
import { runnerConfig } from './runner.mock';
45

56
const outputDir = 'tmp';
67
export default {
@@ -21,7 +22,7 @@ export default {
2122
docsUrl: 'http://www.my-docs.dev',
2223
},
2324
],
24-
runner: runnerConfig([auditReport()], `${outputDir}/out.json`),
25+
runner: echoRunnerConfig([auditReport()], join(outputDir, 'out.json')),
2526
groups: [],
2627
slug: 'command-object-plugin',
2728
title: 'command-object plugin',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { platform } from 'os';
2+
import { AuditOutput, RunnerConfig } from '../../src';
3+
4+
export function echoRunnerConfig(
5+
output: AuditOutput[],
6+
outputFile: string,
7+
): RunnerConfig {
8+
const auditOutput =
9+
platform() === 'win32'
10+
? JSON.stringify(output)
11+
: "'" + JSON.stringify(output) + "'";
12+
return {
13+
command: 'echo',
14+
args: [auditOutput, '>', outputFile],
15+
outputFile,
16+
};
17+
}

packages/models/test/fixtures/eslint-plugin.mock.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import type {
55
PluginConfig,
66
PluginReport,
77
} from '../../src';
8+
import { echoRunnerConfig } from './echo-runner-config.mock';
89
import { ESLINT_AUDITS_MAP } from './eslint-audits.mock';
9-
import { runnerConfig } from './runner.mock';
1010

1111
const eslintMeta = {
1212
slug: 'eslint',
@@ -29,7 +29,7 @@ export function eslintPluginConfig(outputDir = 'tmp'): PluginConfig {
2929
);
3030
return {
3131
...eslintMeta,
32-
runner: runnerConfig(
32+
runner: echoRunnerConfig(
3333
Object.values(ESLINT_AUDITS_MAP),
3434
join(outputDir, 'eslint-out.json'),
3535
),

packages/models/test/fixtures/lighthouse-plugin.mock.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { join } from 'path';
12
import type { AuditGroup, PluginReport } from '../../src';
23
import { Audit, PluginConfig } from '../../src';
4+
import { echoRunnerConfig } from './echo-runner-config.mock';
35
import { LIGHTHOUSE_AUDIT_REPORTS_MAP } from './lighthouse-audits.mock';
4-
import { runnerConfig } from './runner.mock';
56

67
const PLUGIN_GROUP_PERFORMANCE: AuditGroup = {
78
slug: 'performance',
@@ -50,9 +51,9 @@ export function lighthousePluginConfig(outputDir = 'tmp'): PluginConfig {
5051
);
5152
return {
5253
...lighthousePluginMeta,
53-
runner: runnerConfig(
54+
runner: echoRunnerConfig(
5455
Object.values(LIGHTHOUSE_AUDIT_REPORTS_MAP),
55-
`${outputDir}/lighthouse-out.json`,
56+
join(outputDir, 'lighthouse-out.json'),
5657
),
5758
audits,
5859
groups: [PLUGIN_GROUP_PERFORMANCE],

packages/models/test/fixtures/plugin-config.mock.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { join } from 'node:path';
22
import { Audit, AuditReport, PluginConfig } from '../../src';
3-
import { runnerConfig } from './runner.mock';
3+
import { echoRunnerConfig } from './echo-runner-config.mock';
44

55
export function pluginConfig(
66
auditOutputs: AuditReport[],
@@ -15,7 +15,7 @@ export function pluginConfig(
1515
description: 'Plugin description',
1616
docsUrl: 'https://my-plugin.docs.dev?1',
1717
audits: auditOutputs.map(auditOutput => auditConfig(auditOutput)),
18-
runner: runnerConfig(auditOutputs, pluginOutputPath),
18+
runner: echoRunnerConfig(auditOutputs, pluginOutputPath),
1919
...(opt || {}),
2020
} satisfies PluginConfig;
2121
}

0 commit comments

Comments
 (0)