Skip to content

Commit

Permalink
fix(node): Enable e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
ndcunningham committed May 21, 2024
1 parent aedea54 commit d80fd07
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 102 deletions.
140 changes: 80 additions & 60 deletions e2e/node/src/node-server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@ import {
} from '@nx/e2e/utils';
import { join } from 'path';

xdescribe('Node Applications + webpack', () => {
describe('Node Applications + webpack', () => {
let proj: string;
beforeAll(() => {
proj = newProject({
packages: ['@nx/node'],
// npm has resolution for ajv some packages require ajv6 and some require ajv8 and npm resolves it to ajv6 (Error: Cannot find module 'ajv/dist/compile/codegen')
// - ajv@6 (fork-ts-checker-webpack-plugin, terser-webpack-plugin, webpack)
// - ajv@8 (babel-loader)
// Solution is to use pnpm or run fix it via npm ex.(npm dedupe --force)
packageManager: 'pnpm',
});
});

Expand Down Expand Up @@ -47,101 +52,116 @@ xdescribe('Node Applications + webpack', () => {
}
}

async function runE2eTests(appName: string) {
process.env.PORT = '5000';
async function runE2eTests(appName: string, port: number = 5000) {
process.env.PORT = `${port}`;
const childProcess = await runCommandUntil(`serve ${appName}`, (output) => {
return output.includes('http://localhost:5000');
return output.includes(`http://localhost:${port}`);
});
const result = runCLI(`e2e ${appName}-e2e --verbose`);
expect(result).toContain('Setting up...');
expect(result).toContain('Tearing down..');
expect(result).toContain('Successfully ran target e2e');

await promisifiedTreeKill(childProcess.pid, 'SIGKILL');
await killPort(5000);
await killPort(port);
process.env.PORT = '';
}

// Disabled due to flakiness of ajv disabled (Error: Cannot find module 'ajv/dist/compile/codegen')
// TODO: (nicholas) Re-enable when the flakiness is resolved
xit('should generate an app using webpack', async () => {
describe('frameworks', () => {
const testLib1 = uniq('test1');
const testLib2 = uniq('test2');
const expressApp = uniq('expressapp');
const fastifyApp = uniq('fastifyapp');
const koaApp = uniq('koaapp');
const nestApp = uniq('nest');

runCLI(`generate @nx/node:lib ${testLib1}`);
runCLI(`generate @nx/node:lib ${testLib2} --importPath=@acme/test2`);
runCLI(
`generate @nx/node:app ${expressApp} --framework=express --no-interactive`
);
runCLI(
`generate @nx/node:app ${fastifyApp} --framework=fastify --no-interactive`
);
runCLI(`generate @nx/node:app ${koaApp} --framework=koa --no-interactive`);
runCLI(
`generate @nx/node:app ${nestApp} --framework=nest --bundler=webpack --no-interactive`
);
beforeAll(() => {
runCLI(`generate @nx/node:lib ${testLib1}`);
runCLI(`generate @nx/node:lib ${testLib2} --importPath=@acme/test2`);
runCLI(
`generate @nx/node:app ${expressApp} --framework=express --port=7000 --no-interactive`
);
runCLI(
`generate @nx/node:app ${fastifyApp} --framework=fastify --port=7001 --no-interactive`
);
runCLI(
`generate @nx/node:app ${koaApp} --framework=koa --port=7002 --no-interactive`
);
runCLI(
`generate @nx/node:app ${nestApp} --framework=nest --port=7003 --bundler=webpack --no-interactive`
);

// Use esbuild by default
checkFilesDoNotExist(`apps/${expressApp}/webpack.config.js`);
checkFilesDoNotExist(`apps/${fastifyApp}/webpack.config.js`);
checkFilesDoNotExist(`apps/${koaApp}/webpack.config.js`);
addLibImport(expressApp, testLib1);
addLibImport(expressApp, testLib2, '@acme/test2');
addLibImport(fastifyApp, testLib1);
addLibImport(fastifyApp, testLib2, '@acme/test2');
addLibImport(koaApp, testLib1);
addLibImport(koaApp, testLib2, '@acme/test2');

// Uses only webpack
checkFilesExist(`apps/${nestApp}/webpack.config.js`);
addLibImport(nestApp, testLib1);
addLibImport(nestApp, testLib2, '@acme/test2');
});

expect(() => runCLI(`lint ${expressApp}`)).not.toThrow();
expect(() => runCLI(`lint ${fastifyApp}`)).not.toThrow();
expect(() => runCLI(`lint ${koaApp}`)).not.toThrow();
expect(() => runCLI(`lint ${nestApp}`)).not.toThrow();
it('should generate an app defaults using webpack or esbuild', async () => {
// Use esbuild by default
checkFilesDoNotExist(`apps/${expressApp}/webpack.config.js`);
checkFilesDoNotExist(`apps/${fastifyApp}/webpack.config.js`);
checkFilesDoNotExist(`apps/${koaApp}/webpack.config.js`);

expect(() => runCLI(`lint ${expressApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${fastifyApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${koaApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${nestApp}-e2e`)).not.toThrow();
// Uses only webpack
checkFilesExist(`apps/${nestApp}/webpack.config.js`);

// Only Fastify generates with unit tests since it supports them without additional libraries.
expect(() => runCLI(`test ${fastifyApp}`)).not.toThrow();
expect(() => runCLI(`lint ${expressApp}`)).not.toThrow();
expect(() => runCLI(`lint ${fastifyApp}`)).not.toThrow();
expect(() => runCLI(`lint ${koaApp}`)).not.toThrow();
expect(() => runCLI(`lint ${nestApp}`)).not.toThrow();

// https://github.com/nrwl/nx/issues/16601
const nestMainContent = readFile(`apps/${nestApp}/src/main.ts`);
updateFile(
`apps/${nestApp}/src/main.ts`,
`
expect(() => runCLI(`lint ${expressApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${fastifyApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${koaApp}-e2e`)).not.toThrow();
expect(() => runCLI(`lint ${nestApp}-e2e`)).not.toThrow();

// Only Fastify generates with unit tests since it supports them without additional libraries.
expect(() => runCLI(`test ${fastifyApp}`)).not.toThrow();

// https://github.com/nrwl/nx/issues/16601
const nestMainContent = readFile(`apps/${nestApp}/src/main.ts`);
updateFile(
`apps/${nestApp}/src/main.ts`,
`
${nestMainContent}
// Make sure this is not replaced during build time
console.log('env: ' + process.env['NODE_ENV']);
`
);
runCLI(`build ${nestApp}`);
expect(readFile(`dist/apps/${nestApp}/main.js`)).toContain(
`'env: ' + process.env['NODE_ENV']`
);
);
runCLI(`build ${nestApp}`);
expect(readFile(`dist/apps/${nestApp}/main.js`)).toContain(
`'env: ' + process.env['NODE_ENV']`
);
}, 300_000);

addLibImport(expressApp, testLib1);
addLibImport(expressApp, testLib2, '@acme/test2');
addLibImport(fastifyApp, testLib1);
addLibImport(fastifyApp, testLib2, '@acme/test2');
addLibImport(koaApp, testLib1);
addLibImport(koaApp, testLib2, '@acme/test2');
it('should e2e test express app', async () => {
await runE2eTests(expressApp, 7000);
});

it('should e2e test fastify app', async () => {
await runE2eTests(fastifyApp, 7001);
});

addLibImport(nestApp, testLib1);
addLibImport(nestApp, testLib2, '@acme/test2');
it('should e2e test koa app', async () => {
await runE2eTests(koaApp, 7002);
});

await runE2eTests(expressApp);
await runE2eTests(fastifyApp);
await runE2eTests(koaApp);
await runE2eTests(nestApp);
}, 900_000);
it('should e2e test nest app', async () => {
await runE2eTests(nestApp, 7003);
});
});

it('should generate a Dockerfile', async () => {
const expressApp = uniq('expressapp');

runCLI(
`generate @nx/node:app ${expressApp} --framework=express --docker --no-interactive`
`generate @nx/node:app ${expressApp} --framework=express --docker --no-interactive`
);

checkFilesExist(`apps/${expressApp}/Dockerfile`);
Expand Down
40 changes: 2 additions & 38 deletions packages/node/src/generators/setup-docker/setup-docker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import 'nx/src/internal-testing-utils/mock-project-graph';

import {
ProjectConfiguration,
readProjectConfiguration,
Tree,
} from '@nx/devkit';
import { readProjectConfiguration, Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { applicationGenerator } from '../application/application';

describe('setupDockerGenerator', () => {
let tree: Tree;
Expand All @@ -18,15 +15,6 @@ describe('setupDockerGenerator', () => {
describe('integrated', () => {
it('should create docker assets when --docker is passed', async () => {
const projectName = 'integreated-api';
// Since we mock the project graph, we need to mock the project configuration as well
mockReadCachedProjectConfiguration({
name: projectName,
root: projectName,
});

const { applicationGenerator } = await import(
'../application/application'
);

await applicationGenerator(tree, {
name: projectName,
Expand Down Expand Up @@ -56,11 +44,7 @@ describe('setupDockerGenerator', () => {
describe('standalone', () => {
it('should create docker assets when --docker is passed', async () => {
const projectName = 'standalone-api';
mockReadCachedProjectConfiguration({ name: projectName, root: '' });

const { applicationGenerator } = await import(
'../application/application'
);
await applicationGenerator(tree, {
name: projectName,
framework: 'fastify',
Expand All @@ -86,23 +70,3 @@ describe('setupDockerGenerator', () => {
});
});
});

const mockReadCachedProjectConfiguration = (
projectConfig: ProjectConfiguration
) => {
jest.mock('nx/src/project-graph/project-graph', () => {
return {
...jest.requireActual('nx/src/project-graph/project-graph'),
readCachedProjectConfiguration: jest.fn(() => {
return {
root: projectConfig.root,
targets: {
build: {
outputs: [`dist/${projectConfig.name}`],
},
},
};
}),
};
});
};
8 changes: 4 additions & 4 deletions packages/node/src/generators/setup-docker/setup-docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
GeneratorCallback,
joinPathFragments,
logger,
ProjectConfiguration,
readNxJson,
readProjectConfiguration,
runTasksInSerial,
Expand All @@ -15,7 +14,6 @@ import {
import { SetUpDockerOptions } from './schema';
import { join } from 'path';
import { interpolate } from 'nx/src/tasks-runner/utils';
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';

function normalizeOptions(
tree: Tree,
Expand All @@ -30,14 +28,16 @@ function normalizeOptions(
}

function addDocker(tree: Tree, options: SetUpDockerOptions) {
// Inferred targets are only available in the project graph
const projectConfig = readCachedProjectConfiguration(options.project);
const projectConfig = readProjectConfiguration(tree, options.project);

if (
!projectConfig ||
!projectConfig.targets ||
!projectConfig.targets[options.buildTarget]
) {
logger.error(
`Could not find the project ${options.project} or the build target ${options.buildTarget} in the workspace.`
);
return;
}

Expand Down

0 comments on commit d80fd07

Please sign in to comment.