Skip to content

Commit

Permalink
feat(nx-plugin): add schematic to setup Vitest for existing Angular p…
Browse files Browse the repository at this point in the history
…rojects (#787)
  • Loading branch information
brandonroberts authored Dec 8, 2023
1 parent dc9c37f commit 5deadfc
Show file tree
Hide file tree
Showing 15 changed files with 399 additions and 26 deletions.
129 changes: 105 additions & 24 deletions apps/docs-app/docs/features/testing/vitest.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,71 @@ import TabItem from '@theme/TabItem';

[Vitest](https://vitest.dev) can be added to existing Angular workspaces with a few steps.

## Installation
## Using a Schematic/Generator

To add Vitest, install the necessary packages:
Vitest can be installed and setup using a schematic/generator for Angular CLI or Nx workspaces.

First, install the `@analogjs/platform` package:

<Tabs groupId="package-manager">
<TabItem value="npm">

```shell
npm install @analogjs/vite-plugin-angular @analogjs/platform jsdom vite-tsconfig-paths @nx/vite --save-dev
npm install @analogjs/platform --save-dev
```

</TabItem>

<TabItem label="Yarn" value="yarn">

```shell
yarn add @analogjs/vite-plugin-angular @analogjs/platform jsdom vite-tsconfig-paths @nx/vite --dev
yarn add @analogjs/platform --dev
```

</TabItem>

<TabItem value="pnpm">

```shell
pnpm install -w @analogjs/vite-plugin-angular @analogjs/platform jsdom vite-tsconfig-paths @nx/vite
pnpm install -w @analogjs/platform
```

</TabItem>
</Tabs>

Next, run the schematic to set up the Vite config, test configuration files, and update the test configuration.

```shell
ng g @analogjs/platform:setup-vitest --project [your-project-name]
```

Next, go to [running tests](#running-tests)

## Manual Installation

To add Vitest manually, install the necessary packages:

<Tabs groupId="package-manager">
<TabItem value="npm">

```shell
npm install @analogjs/vite-plugin-angular @analogjs/platform jsdom @nx/vite --save-dev
```

</TabItem>

<TabItem label="Yarn" value="yarn">

```shell
yarn add @analogjs/vite-plugin-angular @analogjs/platform jsdom @nx/vite --dev
```

</TabItem>

<TabItem value="pnpm">

```shell
pnpm install -w @analogjs/vite-plugin-angular @analogjs/platform jsdom @nx/vite
```

</TabItem>
Expand All @@ -44,18 +84,12 @@ To setup Vitest, create a `vite.config.ts` at the root of your project:
import { defineConfig } from 'vite';

import angular from '@analogjs/vite-plugin-angular';
import viteTsConfigPaths from 'vite-tsconfig-paths';

export default defineConfig(({ mode }) => ({
plugins: [
angular(),
viteTsConfigPaths({
root: './',
}),
],
plugins: [angular()],
test: {
globals: true,
setupFiles: ['src/test.ts'],
setupFiles: ['src/test-setup.ts'],
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
Expand All @@ -65,7 +99,7 @@ export default defineConfig(({ mode }) => ({
}));
```

Next, define a `src/test.ts` file to setup the `TestBed`:
Next, define a `src/test-setup.ts` file to setup the `TestBed`:

```ts
import '@analogjs/vite-plugin-angular/setup-vitest';
Expand Down Expand Up @@ -107,7 +141,7 @@ Next, update the `test` target in the `angular.json` to use the `@analogjs/platf

> You can also add a new target and name it `vitest` to run alongside your `test` target.
Lastly, add the `src/test.ts` to `files` array in the `tsconfig.spec.json` in the root of your project, and update the `types`.
Lastly, add the `src/test-setup.ts` to `files` array in the `tsconfig.spec.json` in the root of your project, set the `target` to `es2016`, and update the `types`.

```json
{
Expand All @@ -117,11 +151,13 @@ Lastly, add the `src/test.ts` to `files` array in the `tsconfig.spec.json` in th
"target": "es2016",
"types": ["vitest/globals", "node"]
},
"files": ["src/test.ts"],
"files": ["src/test-setup.ts"],
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}
```

Next, go to [running tests](#running-tests)

## Setup for Running Tests in the Browser

If you prefer to run your tests in a browser, Vitest has experimental support for browser testing also.
Expand Down Expand Up @@ -166,18 +202,12 @@ Update the `test` object in the `vite.config.ts`.
import { defineConfig } from 'vite';

import angular from '@analogjs/vite-plugin-angular';
import viteTsConfigPaths from 'vite-tsconfig-paths';

export default defineConfig(({ mode }) => ({
plugins: [
angular(),
viteTsConfigPaths({
root: './',
}),
],
plugins: [angular()],
test: {
globals: true,
setupFiles: ['src/test.ts'],
setupFiles: ['src/test-setup.ts'],
// environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
// Vitest browser config
Expand Down Expand Up @@ -223,3 +253,54 @@ pnpm test

</TabItem>
</Tabs>

## Using TypeScript Config Path Aliases

If you are using `paths` in your `tsconfig.json`, support for those aliases can be added to the `vite.config.ts`.

First, install the `vite-tsconfig-paths` package.

<Tabs groupId="package-manager">
<TabItem value="npm">

```shell
npm install vite-tsconfig-paths --save-dev
```

</TabItem>

<TabItem label="Yarn" value="yarn">

```shell
yarn add vite-tsconfig-paths --dev
```

</TabItem>

<TabItem value="pnpm">

```shell
pnpm install -w vite-tsconfig-paths
```

</TabItem>
</Tabs>

Next, add the plugin to the `plugins` array in the `vite.config.ts` with the `root` set as the relative path to the root of the project.

```ts
/// <reference types="vitest" />
import { defineConfig } from 'vite';

import angular from '@analogjs/vite-plugin-angular';
import viteTsConfigPaths from 'vite-tsconfig-paths';

export default defineConfig(({ mode }) => ({
plugins: [
angular(),
viteTsConfigPaths({
root: './',
}),
],
}));
```
10 changes: 10 additions & 0 deletions packages/nx-plugin/generators.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
"schema": "./src/generators/page/schema.json",
"description": "Creates a new Analog page in the given or default project.",
"aliases": ["p"]
},
"setup-vitest": {
"factory": "./src/generators/setup-vitest/generator",
"schema": "./src/generators/setup-vitest/schema.json",
"description": "Setup the Vitest configuration."
}
},
"schematics": {
Expand All @@ -33,6 +38,11 @@
"schema": "./src/generators/page/schema.json",
"description": "Creates a new Analog page in the given or default project.",
"aliases": ["p"]
},
"setup-vitest": {
"factory": "./src/generators/setup-vitest/compat",
"schema": "./src/generators/setup-vitest/schema.json",
"description": "Setup the Vitest configuration."
}
}
}
5 changes: 5 additions & 0 deletions packages/nx-plugin/src/generators/setup-vitest/compat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { convertNxGenerator } from '@nx/devkit';

import setupVitestGenerator from './generator';

export default convertNxGenerator(setupVitestGenerator);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import '@analogjs/vite-plugin-angular/setup-vitest';

import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';
import { getTestBed } from '@angular/core/testing';

getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// <reference types="vitest" />

import analog from '@analogjs/platform';
import { defineConfig } from 'vite';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
return {
plugins: [analog()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['src/test-setup.ts'],
include: ['**/*.spec.ts'],
},
define: {
'import.meta.vitest': mode !== 'production',
},
};
});
53 changes: 53 additions & 0 deletions packages/nx-plugin/src/generators/setup-vitest/generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
formatFiles,
generateFiles,
getProjects,
installPackagesTask,
Tree,
} from '@nx/devkit';
import * as path from 'path';

import { getInstalledPackageVersion } from '../../utils/version-utils';
import { addAnalogDependencies } from './lib/add-analog-dependencies';
import { updateTsConfig } from './lib/update-tsconfig';
import { updateTestTarget } from './lib/update-test-target';
import { SetupVitestGeneratorSchema } from './schema';

function addFiles(tree: Tree, options: SetupVitestGeneratorSchema) {
const projects = getProjects(tree);

const projectConfig = projects.get(options.project);

const templateOptions = {
...options,
template: '',
};

generateFiles(
tree,
path.join(__dirname, 'files'),
projectConfig.root || '.',
templateOptions
);
}

export async function setupVitestGenerator(
tree: Tree,
options: SetupVitestGeneratorSchema
) {
const angularVersion = getInstalledPackageVersion(tree, '@angular/core');

addAnalogDependencies(tree, angularVersion);
updateTsConfig(tree, options);
updateTestTarget(tree, options);

addFiles(tree, options);

await formatFiles(tree);

return () => {
installPackagesTask(tree);
};
}

export default setupVitestGenerator;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { addDependenciesToPackageJson, Tree } from '@nx/devkit';

import { getAnalogDevDependencies } from '../versions/dev-dependencies';

export function addAnalogDependencies(tree: Tree, angularVersion: string) {
const devDependencies = getAnalogDevDependencies(angularVersion);

addDependenciesToPackageJson(tree, {}, devDependencies);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
Tree,
getProjects,
updateJson,
updateProjectConfiguration,
} from '@nx/devkit';

import { SetupVitestGeneratorSchema } from '../schema';

export function updateTestTarget(
tree: Tree,
schema: SetupVitestGeneratorSchema
) {
const angularJsonPath = '/angular.json';

if (tree.exists(angularJsonPath)) {
updateJson(
tree,
angularJsonPath,
(json) => {
json.projects[schema.project].architect.test = {
builder: '@analogjs/platform:vitest',
};

return json;
},
{ expectComments: true, allowTrailingComma: true }
);
} else {
const projects = getProjects(tree);

const projectConfig = projects.get(schema.project);

projectConfig.targets.test = {
executor: '@analogjs/platform:vitest',
};

updateProjectConfiguration(tree, schema.project, projectConfig);
}
}
Loading

0 comments on commit 5deadfc

Please sign in to comment.