Skip to content

Commit

Permalink
fix(testing): correctly set task status for failed coverage repos
Browse files Browse the repository at this point in the history
  • Loading branch information
barbados-clemens committed Dec 28, 2022
1 parent 181cde5 commit 6dcf20e
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 10 deletions.
52 changes: 51 additions & 1 deletion e2e/vite/src/vite.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
cleanupProject,
createFile,
directoryExists,
exists,
fileExists,
killPorts,
Expand Down Expand Up @@ -192,7 +193,7 @@ describe('Vite Plugin', () => {
describe('should be able to create libs that use vitest', () => {
const lib = uniq('my-lib');
beforeEach(() => {
proj = newProject();
proj = newProject({ name: uniq('vite-proj') });
}),
100_000;

Expand All @@ -206,6 +207,55 @@ describe('Vite Plugin', () => {
);
}, 100_000);

it('should collect coverage', () => {
runCLI(`generate @nrwl/react:lib ${lib} --unitTestRunner=vitest`);
updateFile(`libs/${lib}/vite.config.ts`, () => {
return `import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
server: {
port: 4200,
host: 'localhost',
},
plugins: [
react(),
viteTsConfigPaths({
root: './',
}),
],
test: {
globals: true,
cache: {
dir: './node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
coverage: {
provider: "c8",
enabled: true,
lines: 100,
statements: 100,
functions: 100,
branches: 1000,
}
},
});
`;
});

const coverageDir = `${tmpProjPath()}/coverage/libs/${lib}`;

const results = runCLI(`test ${lib} --coverage`, { silenceError: true });

expect(results).toContain(
`Running target test for project ${lib} failed`
);
expect(results).toContain(`ERROR: Coverage`);
expect(directoryExists(coverageDir)).toBeTruthy();
}, 100_000);

it('should be able to run tests with inSourceTests set to true', async () => {
runCLI(
`generate @nrwl/react:lib ${lib} --unitTestRunner=vitest --inSourceTests`
Expand Down
6 changes: 6 additions & 0 deletions packages/vite/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
"version": "15.3.4-beta.0",
"description": "Set the mode in configurations to match the configurationName.",
"factory": "./src/migrations/update-15-3-4/set-mode-in-configuration"
},
"update-test-path-placeholder-vars": {
"cli": "nx",
"version": "15.4.1-beta.0",
"description": "Update @nrwl/vite:test reportsDirectory and outputs properties to point to correct paths.",
"factory": "./src/migrations/update-15-4-1/update-report-directory"
}
},
"packageJsonUpdates": {
Expand Down
4 changes: 3 additions & 1 deletion packages/vite/src/executors/test/vitest.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ export default async function* runExecutor(
}

for await (const report of nxReporter) {
hasErrors = report.hasErrors;
// vitest sets the exitCode = 1 when code coverage isn't met
hasErrors =
report.hasErrors || (process.exitCode && process.exitCode !== 0);
}

return {
Expand Down
3 changes: 1 addition & 2 deletions packages/vite/src/generators/vitest/vitest-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
createOrEditViteConfig,
} from '../../utils/generator-utils';
import { VitestGeneratorSchema } from './schema';

import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
import initGenerator from '../init/init';
import {
Expand All @@ -41,7 +40,7 @@ export async function vitestGenerator(

addOrChangeTestTarget(tree, schema, testTarget);

const initTask = await initGenerator(tree, {
const initTask = initGenerator(tree, {
uiFramework: schema.uiFramework,
});
tasks.push(initTask);
Expand Down
32 changes: 30 additions & 2 deletions packages/vite/src/generators/vitest/vitest.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { Tree, readProjectConfiguration } from '@nrwl/devkit';
import {
Tree,
readProjectConfiguration,
updateProjectConfiguration,
} from '@nrwl/devkit';

import generator from './vitest-generator';
import { VitestGeneratorSchema } from './schema';
Expand All @@ -20,7 +24,7 @@ describe('vitest generator', () => {
appTree = createTreeWithEmptyWorkspace();
});

it('Should add the test target', async () => {
it('Should add the test target to existing test target', async () => {
mockReactAppGenerator(appTree);
await generator(appTree, options);
const config = readProjectConfiguration(appTree, 'my-test-react-app');
Expand All @@ -37,6 +41,30 @@ describe('vitest generator', () => {
`);
});

it('should add the test target if its missing', async () => {
mockReactAppGenerator(appTree);
const projectConfig = readProjectConfiguration(
appTree,
'my-test-react-app'
);
delete projectConfig.targets.test;
updateProjectConfiguration(appTree, 'my-test-react-app', projectConfig);
await generator(appTree, options);
const config = readProjectConfiguration(appTree, 'my-test-react-app');
expect(config.targets['test']).toMatchInlineSnapshot(`
Object {
"executor": "@nrwl/vite:test",
"options": Object {
"passWithNoTests": true,
"reportsDirectory": "../../coverage/apps/my-test-react-app",
},
"outputs": Array [
"coverage/apps/my-test-react-app",
],
}
`);
});

describe('tsconfig', () => {
it('should add a tsconfig.spec.json file', async () => {
mockReactAppGenerator(appTree);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import {
addProjectConfiguration,
readProjectConfiguration,
Tree,
} from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { updateReportDirectoryPlaceholders } from './update-report-directory';

describe('Update Report Directory Vitest Migration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});

it('should migrate', () => {
addVitestProjects(tree, { name: 'project' });

updateReportDirectoryPlaceholders(tree);
expect(readProjectConfiguration(tree, 'project-one').targets)
.toMatchInlineSnapshot(`
Object {
"test": Object {
"executor": "@nrwl/vite:test",
"options": Object {
"passWithNoTests": true,
"reportsDirectory": "coverge/packages/project-one",
},
"outputs": Array [
"coverage/packages/project-one",
],
},
}
`);
expect(readProjectConfiguration(tree, 'project-two').targets)
.toMatchInlineSnapshot(`
Object {
"custom-test": Object {
"configurations": Object {
"ci": Object {
"reportsDirectory": "coverge/project-two",
},
},
"executor": "@nrwl/vite:test",
"options": Object {
"passWithNoTests": true,
},
"outputs": Array [
"coverage/project-two",
"dist/coverage/else.txt",
],
},
"test": Object {
"executor": "@nrwl/vite:test",
"options": Object {
"passWithNoTests": true,
"reportsDirectory": "coverge/project-two",
},
},
}
`);
});
it('should be idempotent', () => {
addVitestProjects(tree, { name: 'project' });

const expectedProjectOneConfig = {
test: {
outputs: ['coverage/packages/project-one'],
executor: '@nrwl/vite:test',
options: {
reportsDirectory: 'coverge/packages/project-one',
passWithNoTests: true,
},
},
};

const expectedProjectTwoConfig = {
'custom-test': {
executor: '@nrwl/vite:test',
outputs: ['coverage/project-two', 'dist/coverage/else.txt'],
options: {
passWithNoTests: true,
},
configurations: {
ci: {
reportsDirectory: 'coverge/project-two',
},
},
},
test: {
executor: '@nrwl/vite:test',
options: {
reportsDirectory: 'coverge/project-two',
passWithNoTests: true,
},
},
};

updateReportDirectoryPlaceholders(tree);
const projOneConfig = readProjectConfiguration(tree, 'project-one');
expect(projOneConfig.targets).toEqual(expectedProjectOneConfig);
const projTwoConfig = readProjectConfiguration(tree, 'project-two');
expect(projTwoConfig.targets).toEqual(expectedProjectTwoConfig);
});
});

function addVitestProjects(tree: Tree, options: { name: string }) {
addProjectConfiguration(tree, options.name + '-one', {
name: options.name + '-one',
sourceRoot: `packages/${options.name}-one/src`,
root: `packages/${options.name}-one`,
targets: {
test: {
outputs: ['{projectRoot}/coverage'],
executor: '@nrwl/vite:test',
options: {
reportsDirectory: '{workspaceRoot}/coverge/{projectRoot}',
passWithNoTests: true,
},
},
},
});
addProjectConfiguration(tree, options.name + '-two', {
name: options.name + '-two',
sourceRoot: 'src',
root: '.',
targets: {
'custom-test': {
executor: '@nrwl/vite:test',
outputs: ['{projectRoot}/coverage', 'dist/coverage/else.txt'],
options: {
passWithNoTests: true,
},
configurations: {
ci: {
reportsDirectory: '{workspaceRoot}/coverge/{projectRoot}',
},
},
},
test: {
executor: '@nrwl/vite:test',
options: {
reportsDirectory: '{workspaceRoot}/coverge/{projectRoot}',
passWithNoTests: true,
},
},
},
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { getProjects, Tree, updateProjectConfiguration } from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
import { VitestExecutorOptions } from '../../executors/test/schema';

export function updateReportDirectoryPlaceholders(tree: Tree) {
const projects = getProjects(tree);
forEachExecutorOptions<VitestExecutorOptions>(
tree,
'@nrwl/vite:test',
(options, projectName, targetName, configName) => {
const projectConfig = projects.get(projectName);
const coverageOutput =
projectConfig.root === '.' ? projectName : projectConfig.root;

if (options.reportsDirectory) {
options.reportsDirectory = options.reportsDirectory
.replace('{workspaceRoot}/', '')
.replace('{projectRoot}', coverageOutput);
console.log({ options, projectName, configName, coverageOutput });
if (configName) {
projectConfig.targets[targetName].configurations[configName] =
options;
} else {
projectConfig.targets[targetName].options = options;
}
if (projectConfig.targets[targetName].outputs) {
projectConfig.targets[targetName].outputs = projectConfig.targets[
targetName
].outputs.map((output) =>
output.replace(
'{projectRoot}/coverage',
`coverage/${coverageOutput}`
)
);
}
updateProjectConfiguration(tree, projectName, projectConfig);
}
}
);
}

export default updateReportDirectoryPlaceholders;
12 changes: 8 additions & 4 deletions packages/vite/src/utils/generator-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,16 @@ export function addOrChangeTestTarget(
) {
const project = readProjectConfiguration(tree, options.project);

const coveragePath = joinPathFragments(
'coverage',
project.root === '.' ? options.project : project.root
);
const testOptions: VitestExecutorOptions = {
passWithNoTests: true,
// vitest runs in the project root so we have to offset to the workspaceRoot
reportsDirectory: joinPathFragments(
'{workspaceRoot}',
'coverage',
'{projectRoot}'
offsetFromRoot(project.root),
coveragePath
),
};

Expand All @@ -226,7 +230,7 @@ export function addOrChangeTestTarget(
}
project.targets[target] = {
executor: '@nrwl/vite:test',
outputs: ['{projectRoot}/coverage'],
outputs: [coveragePath],
options: testOptions,
};
}
Expand Down

0 comments on commit 6dcf20e

Please sign in to comment.