Skip to content

Commit 3fc351c

Browse files
committed
fix(plugin-coverage): support non-cjs jest configs
refactored importEsmModule->importModule to be format-agnostic by default fix #726
1 parent f9718bd commit 3fc351c

File tree

7 files changed

+34
-35
lines changed

7 files changed

+34
-35
lines changed

packages/core/src/lib/implementation/read-rc-file.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
SUPPORTED_CONFIG_FILE_FORMATS,
66
coreConfigSchema,
77
} from '@code-pushup/models';
8-
import { fileExists, importEsmModule } from '@code-pushup/utils';
8+
import { fileExists, importModule } from '@code-pushup/utils';
99

1010
export class ConfigPathError extends Error {
1111
constructor(configPath: string) {
@@ -25,7 +25,7 @@ export async function readRcByPath(
2525
throw new ConfigPathError(filepath);
2626
}
2727

28-
const cfg = await importEsmModule({ filepath, tsconfig });
28+
const cfg = await importModule({ filepath, tsconfig, format: 'esm' });
2929

3030
return coreConfigSchema.parse(cfg);
3131
}

packages/plugin-coverage/src/lib/nx/coverage-paths.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { JestExecutorOptions } from '@nx/jest/src/executors/jest/schema';
88
import type { VitestExecutorOptions } from '@nx/vite/executors';
99
import chalk from 'chalk';
1010
import { isAbsolute, join } from 'node:path';
11-
import { importEsmModule, ui } from '@code-pushup/utils';
11+
import { importModule, ui } from '@code-pushup/utils';
1212
import { CoverageResult } from '../config';
1313

1414
/**
@@ -128,7 +128,7 @@ export async function getCoveragePathForVitest(
128128
);
129129
}
130130

131-
const vitestConfig = await importEsmModule<VitestCoverageConfig>({
131+
const vitestConfig = await importModule<VitestCoverageConfig>({
132132
filepath: config,
133133
format: 'esm',
134134
});
@@ -165,9 +165,8 @@ export async function getCoveragePathForJest(
165165
) {
166166
const { jestConfig } = options;
167167

168-
const testConfig = await importEsmModule<JestCoverageConfig>({
168+
const testConfig = await importModule<JestCoverageConfig>({
169169
filepath: jestConfig,
170-
format: 'cjs',
171170
});
172171
const { coverageDirectory, coverageReporters } = {
173172
...testConfig,

packages/plugin-lighthouse/src/lib/runner/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import experimentalConfig from 'lighthouse/core/config/experimental-config.js';
66
import perfConfig from 'lighthouse/core/config/perf-config.js';
77
import { Result } from 'lighthouse/types/lhr/audit-result';
88
import { AuditOutput, AuditOutputs } from '@code-pushup/models';
9-
import { importEsmModule, readJsonFile, ui } from '@code-pushup/utils';
9+
import { importModule, readJsonFile, ui } from '@code-pushup/utils';
1010
import type { LighthouseOptions } from '../types';
1111
import { logUnsupportedDetails, toAuditDetails } from './details/details';
1212
import { LighthouseCliFlags } from './types';
@@ -126,7 +126,7 @@ export async function getConfig(
126126
// Resolve the config file path relative to where cli was called.
127127
return readJsonFile<Config>(filepath);
128128
} else if (/\.(ts|js|mjs)$/.test(filepath)) {
129-
return importEsmModule<Config>({ filepath });
129+
return importModule<Config>({ filepath, format: 'esm' });
130130
} else {
131131
ui().logger.info(`Format of file ${filepath} not supported`);
132132
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = 'valid-cjs-module-export';

packages/utils/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export {
1717
fileExists,
1818
filePathToCliArg,
1919
findLineNumberInText,
20-
importEsmModule,
20+
importModule,
2121
logMultipleFileResults,
2222
pluginWorkDir,
2323
readJsonFile,
Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,41 @@
11
import { join } from 'node:path';
22
import { describe, expect, it } from 'vitest';
3-
import { importEsmModule } from './file-system';
3+
import { importModule } from './file-system';
44

5-
describe('importEsmModule', () => {
5+
describe('importModule', () => {
66
const mockDir = join(process.cwd(), 'packages', 'utils', 'mocks', 'fixtures');
77

88
it('should load a valid ES module', async () => {
99
await expect(
10-
importEsmModule({
10+
importModule({
1111
filepath: join(mockDir, 'valid-es-module-export.mjs'),
1212
}),
1313
).resolves.toBe('valid-es-module-export');
1414
});
1515

16-
it('should throw if the file does not exist', async () => {
16+
it('should load a valid CommonJS module', async () => {
1717
await expect(
18-
importEsmModule({
19-
filepath: 'path/to/non-existent-export.mjs',
18+
importModule({
19+
filepath: join(mockDir, 'valid-cjs-module-export.cjs'),
2020
}),
21-
).rejects.toThrow('non-existent-export.mjs');
21+
).resolves.toBe('valid-cjs-module-export');
2222
});
2323

24-
it('should throw if the file does not have any default export', async () => {
24+
it('should load an ES module without default export', async () => {
2525
await expect(
26-
importEsmModule({
26+
importModule({
2727
filepath: join(mockDir, 'no-default-export.mjs'),
2828
}),
29-
).rejects.toThrow('No default export found');
29+
).resolves.toEqual(
30+
expect.objectContaining({ exportedVar: 'exported-variable' }),
31+
);
32+
});
33+
34+
it('should throw if the file does not exist', async () => {
35+
await expect(
36+
importModule({
37+
filepath: 'path/to/non-existent-export.mjs',
38+
}),
39+
).rejects.toThrow('non-existent-export.mjs');
3040
});
3141
});

packages/utils/src/lib/file-system.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,13 @@ export function logMultipleFileResults(
7575
);
7676
}
7777

78-
export class NoExportError extends Error {
79-
constructor(filepath: string) {
80-
super(`No default export found in ${filepath}`);
81-
}
82-
}
83-
84-
export async function importEsmModule<T = unknown>(
85-
options: Options,
86-
): Promise<T> {
87-
const { mod } = await bundleRequire<object>({
88-
format: 'esm',
89-
...options,
90-
});
78+
export async function importModule<T = unknown>(options: Options): Promise<T> {
79+
const { mod } = await bundleRequire<object>(options);
9180

92-
if (!('default' in mod)) {
93-
throw new NoExportError(options.filepath);
81+
if (typeof mod === 'object' && 'default' in mod) {
82+
return mod.default as T;
9483
}
95-
return mod.default as T;
84+
return mod as T;
9685
}
9786

9887
export function pluginWorkDir(slug: string): string {

0 commit comments

Comments
 (0)