Skip to content

Commit

Permalink
feat(testing): add ability to split jest tests
Browse files Browse the repository at this point in the history
  • Loading branch information
FrozenPandaz committed Apr 5, 2024
1 parent 640c61d commit 9612793
Show file tree
Hide file tree
Showing 9 changed files with 437 additions and 638 deletions.
52 changes: 51 additions & 1 deletion docs/generated/packages/jest/documents/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ description: The Nx Plugin for Jest contains executors and generators that suppo
### Installation

{% callout type="note" title="Keep Nx Package Versions In Sync" %}
Make sure to install the `@nx/jest` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync).
Make sure to install the `@nx/jest` version that matches the version of `nx` in your repository. If the version numbers
get out of sync, you can encounter some difficult to debug errors. You
can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync).
{% /callout %}

In any Nx workspace, you can install `@nx/jest` by running the following command:
Expand Down Expand Up @@ -62,6 +64,54 @@ The `@nx/jest/plugin` is configured in the `plugins` array in `nx.json`.

- The `targetName` option controls the name of the inferred Jest tasks. The default name is `test`.

#### Configuring @nx/jest/plugin for both E2E and Unit Tests

While Jest is most often used for unit tests, there are cases where it can be used for e2e tests as well as unit tests
within the same workspace. In this case, you can configure the `@nx/jest/plugin` twice for the different cases.

```json {% fileName="nx.json" %}
{
"plugins": [
{
"plugin": "@nx/jest/plugin",
"exclude": ["e2e/**/*"],
"options": {
"targetName": "test"
}
},
{
"plugin": "@nx/jest/plugin",
"include": ["e2e/**/*"],
"options": {
"targetName": "e2e-local",
"ciTargetName": "e2e-ci"
}
}
]
}
```

### Splitting E2E Tests

If Jest is used to run E2E tests, you can enable [splitting the tasks](/ci/features/split-e2e-tasks) by file to get
improved caching, distribution, and retrying flaky tests. Enable this, by providing a `ciTargetName`. This will create a
target with that name which can be used in CI to run the tests for each file in a distributed fashion.

```json {% fileName="nx.json" %}
{
"plugins": [
{
"plugin": "@nx/jest/plugin",
"include": ["e2e/**/*"],
"options": {
"targetName": "e2e-local",
"ciTargetName": "e2e-ci"
}
}
]
}
```

{% /tab %}
{% tab label="Nx < 18" %}

Expand Down
12 changes: 10 additions & 2 deletions docs/nx-cloud/features/split-e2e-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ You could manually address these problems by splitting your e2e tests into small

## Set up

To enable automatically split e2e tasks, you need to turn on [inferred tasks](/concepts/inferred-tasks#existing-nx-workspaces) for the [@nx/cypress](/nx-api/cypress) or [@nx/playwright](/nx-api/playwright) plugins. Run this command to set up inferred tasks:
To enable automatically split e2e tasks, you need to turn on [inferred tasks](/concepts/inferred-tasks#existing-nx-workspaces) for the [@nx/cypress](/nx-api/cypress), [@nx/playwright](/nx-api/playwright), or [@nx/playwright](/nx-api/jest) plugins. Run this command to set up inferred tasks:

{% tabs %}
{% tab label="Cypress" %}
Expand All @@ -27,17 +27,25 @@ nx add @nx/cypress
nx add @nx/playwright
```

{% /tab %}
{% tab label="Jest" %}

```shell {% skipRescope=true %}
nx add @nx/jest
```

{% /tab %}
{% /tabs %}

This command will register the appropriate plugin in the `plugins` array of `nx.json`.

## Manual Configuration

If you are already using the `@nx/cypress` or `@nx/playwright` plugin, you need to manually add the appropriate configuration to the `plugins` array of `nx.json`. Follow the instructions for the plugin you are using:
If you are already using the `@nx/cypress`, `@nx/playwright`, or `@nx/jest` plugin, you need to manually add the appropriate configuration to the `plugins` array of `nx.json`. Follow the instructions for the plugin you are using:

- [Configure Cypress Task Splitting](/nx-api/cypress#nxcypress-configuration)
- [Configure Playwright Task Splitting](/nx-api/playwright#nxplaywright-configuration)
- [Configure Jest Task Splitting](/nx-api/jest#splitting-e2e-tests)

## Usage

Expand Down
52 changes: 51 additions & 1 deletion docs/shared/packages/jest/jest-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ description: The Nx Plugin for Jest contains executors and generators that suppo
### Installation

{% callout type="note" title="Keep Nx Package Versions In Sync" %}
Make sure to install the `@nx/jest` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync).
Make sure to install the `@nx/jest` version that matches the version of `nx` in your repository. If the version numbers
get out of sync, you can encounter some difficult to debug errors. You
can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync).
{% /callout %}

In any Nx workspace, you can install `@nx/jest` by running the following command:
Expand Down Expand Up @@ -62,6 +64,54 @@ The `@nx/jest/plugin` is configured in the `plugins` array in `nx.json`.

- The `targetName` option controls the name of the inferred Jest tasks. The default name is `test`.

#### Configuring @nx/jest/plugin for both E2E and Unit Tests

While Jest is most often used for unit tests, there are cases where it can be used for e2e tests as well as unit tests
within the same workspace. In this case, you can configure the `@nx/jest/plugin` twice for the different cases.

```json {% fileName="nx.json" %}
{
"plugins": [
{
"plugin": "@nx/jest/plugin",
"exclude": ["e2e/**/*"],
"options": {
"targetName": "test"
}
},
{
"plugin": "@nx/jest/plugin",
"include": ["e2e/**/*"],
"options": {
"targetName": "e2e-local",
"ciTargetName": "e2e-ci"
}
}
]
}
```

### Splitting E2E Tests

If Jest is used to run E2E tests, you can enable [splitting the tasks](/ci/features/split-e2e-tasks) by file to get
improved caching, distribution, and retrying flaky tests. Enable this, by providing a `ciTargetName`. This will create a
target with that name which can be used in CI to run the tests for each file in a distributed fashion.

```json {% fileName="nx.json" %}
{
"plugins": [
{
"plugin": "@nx/jest/plugin",
"include": ["e2e/**/*"],
"options": {
"targetName": "e2e-local",
"ciTargetName": "e2e-ci"
}
}
]
}
```

{% /tab %}
{% tab label="Nx < 18" %}

Expand Down
16 changes: 16 additions & 0 deletions e2e/jest/src/jest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
runCLIAsync,
uniq,
updateFile,
updateJson,
} from '@nx/e2e/utils';

describe('Jest', () => {
Expand Down Expand Up @@ -147,4 +148,19 @@ describe('Jest', () => {
'Test Suites: 1 passed, 1 total'
);
}, 90000);

it('should be able to run e2e tests split by tasks', async () => {
const libName = uniq('lib');
runCLI(`generate @nx/js:lib ${libName} --unitTestRunner=jest`);
updateJson('nx.json', (json) => {
const jestPlugin = json.plugins.find(
(plugin) => plugin.plugin === '@nx/jest/plugin'
);

jestPlugin.options.ciTargetName = 'e2e-ci';
return json;
});

await runCLIAsync(`e2e-ci ${libName}`);
}, 90000);
});
2 changes: 1 addition & 1 deletion e2e/remix/tests/nx-remix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe('Remix E2E Tests', () => {
expect(result).toContain(`Successfully ran target test`);

const reactResult = runCLI(`test ${reactapp}`);
expect(result).toContain(`Successfully ran target test`);
expect(reactResult).toContain(`Successfully ran target test`);
}, 120_000);
});

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
"jest-environment-jsdom": "29.4.3",
"jest-environment-node": "^29.4.1",
"jest-resolve": "^29.4.1",
"jest-runtime": "^29.4.1",
"jest-util": "^29.4.1",
"js-tokens": "^4.0.0",
"js-yaml": "4.1.0",
Expand Down
112 changes: 111 additions & 1 deletion packages/jest/src/plugins/plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ describe('@nx/jest/plugin', () => {
};

await tempFs.createFiles({
'proj/jest.config.js': '',
'proj/jest.config.js': `module.exports = {}`,
'proj/src/unit.spec.ts': '',
'proj/src/ignore.spec.ts': '',
'proj/project.json': '{}',
});
});
Expand Down Expand Up @@ -64,6 +66,114 @@ describe('@nx/jest/plugin', () => {
],
},
],
"metadata": {
"description": "Run Jest Tests",
"technologies": [
"jest",
],
},
"options": {
"cwd": "proj",
},
"outputs": [
"{workspaceRoot}/coverage",
],
},
},
}
`);
});

it('should create test-ci targets based on jest.config.ts', async () => {
mockJestConfig(
{
coverageDirectory: '../coverage',
testMatch: ['**/*.spec.ts'],
testPathIgnorePatterns: ['ignore.spec.ts'],
},
context
);
const nodes = await createNodesFunction(
'proj/jest.config.js',
{
targetName: 'test',
ciTargetName: 'test-ci',
},
context
);

expect(nodes.projects.proj).toMatchInlineSnapshot(`
{
"root": "proj",
"targets": {
"test": {
"cache": true,
"command": "jest",
"inputs": [
"default",
"^production",
{
"externalDependencies": [
"jest",
],
},
],
"metadata": {
"description": "Run Jest Tests",
"technologies": [
"jest",
],
},
"options": {
"cwd": "proj",
},
"outputs": [
"{workspaceRoot}/coverage",
],
},
"test-ci": {
"cache": true,
"dependsOn": [
"test-ci--src/unit.spec.ts",
],
"executor": "nx:noop",
"inputs": [
"default",
"^production",
{
"externalDependencies": [
"jest",
],
},
],
"metadata": {
"description": "Run Jest Tests in CI",
"technologies": [
"jest",
],
},
"outputs": [
"{workspaceRoot}/coverage",
],
},
"test-ci--src/unit.spec.ts": {
"cache": true,
"command": "jest src/unit.spec.ts",
"inputs": [
"default",
"^production",
{
"externalDependencies": [
"jest",
],
},
],
"metadata": {
"description": "Run Jest Tests in src/unit.spec.ts",
"technologies": [
"jest",
],
},
"options": {
"cwd": "proj",
},
Expand Down
Loading

0 comments on commit 9612793

Please sign in to comment.