Skip to content
Open
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
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,14 @@ Options:
--debug Run tests in debug mode
(https://jestjs.io/docs/en/troubleshooting)
[boolean] [default: false]
--projectJson Path to the project JSON file (defaults to
sfdx-project.json) [string]
--help Show help [boolean]

Examples:
sfdx-lwc-jest --coverage Collect coverage and display in output
sfdx-lwc-jest -- --json All params after `--` are directly passed to Jest
sfdx-lwc-jest --coverage Collect coverage and display in output
sfdx-lwc-jest --projectJson my.json Use custom project file
sfdx-lwc-jest -- --json All params after `--` are directly passed to Jest
```

## Passing Additional Jest CLI Options
Expand All @@ -75,6 +78,22 @@ sfdx-lwc-jest -- --json

See the [Jest documentation](http://facebook.github.io/jest/docs/en/cli.html) for all CLI options.

## Custom Project Configuration

By default, `sfdx-lwc-jest` looks for `sfdx-project.json` in the current working directory to discover LWC component paths. You can specify a custom project JSON file using the `--projectJson` option:

```bash
sfdx-lwc-jest --projectJson ./configs/my-project.json
```

This is useful for:

- Projects with non-standard project file names
- Testing against multiple project configurations
- CI/CD pipelines with custom project setups

The custom project file should follow the same format as `sfdx-project.json` with `packageDirectories` containing paths to your LWC components.

## Debug Mode

Debug mode lets you easily debug your Jest tests.
Expand Down
4 changes: 2 additions & 2 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
*/
'use strict';

const { jestConfig } = require('./src/config');
module.exports = { jestConfig };
const { getJestConfig } = require('./src/config');
module.exports = { jestConfig: getJestConfig() };
46 changes: 24 additions & 22 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,28 @@ function getCoveragePaths() {
.flat();
}

const jestConfig = {
// Inherited from @lwc/jest-preset
moduleFileExtensions: jestPreset.moduleFileExtensions || ['ts', 'js', 'html'],
testEnvironment: jestPreset.testEnvironment || 'jsdom',
transform: {
...jestPreset.transform,
'^.+\\.(js|ts|html|css)$': require.resolve('@lwc/jest-transformer'),
},
setupFilesAfterEnv: jestPreset.setupFilesAfterEnv || [],
snapshotSerializers: jestPreset.snapshotSerializers || [
require.resolve('@lwc/jest-serializer'),
],
// Specific to sfdx-lwc-jest
collectCoverageFrom: getCoveragePaths(),
resolver: path.join(__dirname, './resolver.js'),
rootDir: PROJECT_ROOT,
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/test/specs/'],
transformIgnorePatterns: [
'/node_modules/(?!(.*@salesforce/sfdx-lwc-jest/src/lightning-stubs)/)',
],
};
function getJestConfig() {
return {
// Inherited from @lwc/jest-preset
moduleFileExtensions: jestPreset.moduleFileExtensions || ['ts', 'js', 'html'],
testEnvironment: jestPreset.testEnvironment || 'jsdom',
transform: {
...jestPreset.transform,
'^.+\\.(js|ts|html|css)$': require.resolve('@lwc/jest-transformer'),
},
setupFilesAfterEnv: jestPreset.setupFilesAfterEnv || [],
snapshotSerializers: jestPreset.snapshotSerializers || [
require.resolve('@lwc/jest-serializer'),
],
// Specific to sfdx-lwc-jest
collectCoverageFrom: getCoveragePaths(),
resolver: path.join(__dirname, './resolver.js'),
rootDir: PROJECT_ROOT,
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/test/specs/'],
transformIgnorePatterns: [
'/node_modules/(?!(.*@salesforce/sfdx-lwc-jest/src/lightning-stubs)/)',
],
};
}

module.exports = { jestConfig };
module.exports = { getJestConfig };
5 changes: 5 additions & 0 deletions src/options/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ const testOptions = {
description: 'Deprecated: this noop flag is kept for backward compatibility',
type: 'boolean',
},

projectJson: {
description: 'Path to the project JSON file (defaults to sfdx-project.json)',
type: 'string',
},
};

module.exports = testOptions;
1 change: 1 addition & 0 deletions src/utils/__mocks__/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ module.exports = {
return { mock: true };
},
getModulePaths: () => ['force-app/main/unix/lwc', 'force-app\\main\\windows\\lwc'],
setCustomProjectJsonPath: () => {},
};
14 changes: 12 additions & 2 deletions src/utils/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,22 @@ const fg = require('fast-glob');
const PROJECT_ROOT = fs.realpathSync(process.cwd());

let PATHS = [];
let CUSTOM_PROJECT_JSON_PATH = null;

function setCustomProjectJsonPath(customPath) {
CUSTOM_PROJECT_JSON_PATH = customPath;
// Clear cached paths when project JSON changes
PATHS = [];
}

function getSfdxProjectJson() {
const sfdxProjectJson = path.join(PROJECT_ROOT, 'sfdx-project.json');
const sfdxProjectJson = CUSTOM_PROJECT_JSON_PATH
? path.resolve(CUSTOM_PROJECT_JSON_PATH)
: path.join(PROJECT_ROOT, 'sfdx-project.json');

if (!fs.existsSync(sfdxProjectJson)) {
throw new Error(
'Could not find sfdx-project.json. Make sure `lwc-jest` is run from project root',
`Could not find ${sfdxProjectJson}. Make sure the project JSON file exists and 'lwc-jest' is run from project root`,
);
}

Expand All @@ -40,4 +49,5 @@ module.exports = {
PROJECT_ROOT,
getSfdxProjectJson,
getModulePaths,
setCustomProjectJsonPath,
};
10 changes: 8 additions & 2 deletions src/utils/test-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');

const { PROJECT_ROOT } = require('./project');
const { PROJECT_ROOT, setCustomProjectJsonPath } = require('./project');

const { info, warn } = require('../log');
const { jestConfig } = require('../config');
const { getJestConfig } = require('../config');

// List of CLI options that should be passthrough to jest.
const JEST_PASSTHROUGH_OPTIONS = new Set(['coverage', 'updateSnapshot', 'verbose', 'watch']);
Expand Down Expand Up @@ -54,13 +54,19 @@ function getJestArgs(argv) {
fs.existsSync(path.resolve(PROJECT_ROOT, 'jest.config.mjs')) ||
fs.existsSync(path.resolve(PROJECT_ROOT, 'jest.config.cjs'));
if (!hasCustomConfig) {
const jestConfig = getJestConfig();
jestArgs.unshift(`--config=${JSON.stringify(jestConfig)}`);
}

return jestArgs;
}

async function testRunner(argv) {
// Set custom project JSON path if provided
if (argv.projectJson) {
setCustomProjectJsonPath(argv.projectJson);
}

if (argv.skipApiVersionCheck !== undefined) {
warn(
'The --skipApiVersionCheck flag is deprecated and will be removed in future versions.',
Expand Down
2 changes: 2 additions & 0 deletions tests/__snapshots__/help.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Options:
[boolean] [default: false]
--skipApiVersionCheck Deprecated: this noop flag is kept for backward
compatibility [boolean]
--projectJson Path to the project JSON file (defaults to
sfdx-project.json) [string]
--help Show help [boolean]

Examples:
Expand Down
3 changes: 2 additions & 1 deletion tests/config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
'use strict';

jest.mock('../src/utils/project');
const { jestConfig } = require('../src/config');
const { getJestConfig } = require('../src/config');
const jestConfig = getJestConfig();

test('coveragePaths correctly build', () => {
expect(jestConfig.collectCoverageFrom).toStrictEqual([
Expand Down