chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,354 @@
|
||||
import {
|
||||
checkFilesExist,
|
||||
cleanupProject,
|
||||
getSelectedPackageManager,
|
||||
getPackageManagerCommand,
|
||||
killPorts,
|
||||
newProject,
|
||||
promisifiedTreeKill,
|
||||
readJson,
|
||||
runCLI,
|
||||
runCommand,
|
||||
runCommandUntil,
|
||||
tmpProjPath,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
reservePort,
|
||||
} from '@nx/e2e-utils';
|
||||
import { execSync } from 'child_process';
|
||||
import * as http from 'http';
|
||||
|
||||
let originalEnvPort;
|
||||
|
||||
describe('Node Applications', () => {
|
||||
const pm = getSelectedPackageManager();
|
||||
let workspaceName: string;
|
||||
|
||||
beforeAll(() => {
|
||||
originalEnvPort = process.env.PORT;
|
||||
workspaceName = newProject({
|
||||
packages: [
|
||||
'@nx/node',
|
||||
'@nx/express',
|
||||
'@nx/nest',
|
||||
'@nx/webpack',
|
||||
'@nx/jest',
|
||||
],
|
||||
preset: 'ts',
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
process.env.PORT = originalEnvPort;
|
||||
cleanupProject();
|
||||
});
|
||||
|
||||
it('should be able to generate an empty application', async () => {
|
||||
const nodeapp = uniq('nodeapp');
|
||||
const port = await reservePort();
|
||||
process.env.PORT = `${port}`;
|
||||
runCLI(
|
||||
`generate @nx/node:app apps/${nodeapp} --port=${port} --linter=eslint --unitTestRunner=jest`
|
||||
);
|
||||
|
||||
expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow();
|
||||
expect(() => runCLI(`test ${nodeapp}`)).not.toThrow();
|
||||
|
||||
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
||||
runCLI(`build ${nodeapp}`);
|
||||
|
||||
checkFilesExist(`apps/${nodeapp}/dist/main.js`);
|
||||
const result = execSync(`node apps/${nodeapp}/dist/main.js`, {
|
||||
cwd: tmpProjPath(),
|
||||
}).toString();
|
||||
expect(result).toContain('Hello World!');
|
||||
await killPorts(port);
|
||||
}, 300_000);
|
||||
|
||||
// TODO(jack): fix and re-enable
|
||||
xit('should be able to generate an express application', async () => {
|
||||
const nodeapp = uniq('nodeapp');
|
||||
const nodelib = uniq('nodelib');
|
||||
const port = await reservePort();
|
||||
process.env.PORT = `${port}`;
|
||||
runCLI(
|
||||
`generate @nx/express:app apps/${nodeapp} --port=${port} --linter=eslint --unitTestRunner=jest`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/node:lib packages/${nodelib} --linter=eslint --unitTestRunner=jest`
|
||||
);
|
||||
|
||||
// No tests are generated by default, add a stub one.
|
||||
updateFile(
|
||||
`apps/${nodeapp}/src/app/test.spec.ts`,
|
||||
`
|
||||
describe('test', () => {
|
||||
it('should work', () => {
|
||||
expect(true).toEqual(true);
|
||||
})
|
||||
})
|
||||
`
|
||||
);
|
||||
|
||||
updateFile(`apps/${nodeapp}/src/assets/file.txt`, `Test`);
|
||||
updateFile(`apps/${nodeapp}/src/main.ts`, (content) => {
|
||||
return `import { ${nodelib} } from '@${workspaceName}/${nodelib}';\n${content}\nconsole.log(${nodelib}());`;
|
||||
});
|
||||
// pnpm does not link packages unless they are deps
|
||||
// npm, yarn, and bun will link them in the root node_modules regardless
|
||||
if (pm === 'pnpm') {
|
||||
updateJson(`apps/${nodeapp}/package.json`, (json) => {
|
||||
json.dependencies = {
|
||||
[`@${workspaceName}/${nodelib}`]: 'workspace:*',
|
||||
};
|
||||
return json;
|
||||
});
|
||||
runCommand(`cd apps/${nodeapp} && ${getPackageManagerCommand().install}`);
|
||||
}
|
||||
runCLI(`sync`);
|
||||
|
||||
expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow();
|
||||
expect(() => runCLI(`test ${nodeapp}`)).not.toThrow();
|
||||
expect(() => runCLI(`build ${nodeapp}`)).not.toThrow();
|
||||
expect(() => runCLI(`typecheck ${nodeapp}`)).not.toThrow();
|
||||
expect(() => runCLI(`lint ${nodelib}`)).not.toThrow();
|
||||
expect(() => runCLI(`test ${nodelib}`)).not.toThrow();
|
||||
expect(() => runCLI(`build ${nodelib}`)).not.toThrow();
|
||||
expect(() => runCLI(`typecheck ${nodelib}`)).not.toThrow();
|
||||
|
||||
const p = await runCommandUntil(
|
||||
`serve ${nodeapp}`,
|
||||
(output) => output.includes(`Listening at http://localhost:${port}`),
|
||||
|
||||
{
|
||||
env: {
|
||||
NX_DAEMON: 'true',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let result = await getData(port);
|
||||
expect(result.message).toMatch(`Welcome to ${nodeapp}!`);
|
||||
|
||||
result = await getData(port, '/assets/file.txt');
|
||||
expect(result).toMatch(`Test`);
|
||||
|
||||
try {
|
||||
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||
expect(await killPorts(port)).toBeTruthy();
|
||||
} catch (err) {
|
||||
console.log(
|
||||
'Error during cleanup (may be expected, especially ECONNRESET):',
|
||||
err.message
|
||||
);
|
||||
}
|
||||
}, 300_000);
|
||||
|
||||
it('should be able to generate a nest application', async () => {
|
||||
const nestapp = uniq('nodeapp');
|
||||
const port = await reservePort();
|
||||
process.env.PORT = `${port}`;
|
||||
runCLI(
|
||||
`generate @nx/nest:app apps/${nestapp} --linter=eslint --unitTestRunner=jest`
|
||||
);
|
||||
|
||||
expect(() => runCLI(`lint ${nestapp}`)).not.toThrow();
|
||||
expect(() => runCLI(`test ${nestapp}`)).not.toThrow();
|
||||
|
||||
runCLI(`build ${nestapp}`);
|
||||
checkFilesExist(`apps/${nestapp}/dist/main.js`);
|
||||
|
||||
const p = await runCommandUntil(
|
||||
`serve ${nestapp}`,
|
||||
(output) =>
|
||||
output.includes(
|
||||
`Application is running on: http://localhost:${port}/api`
|
||||
),
|
||||
|
||||
{
|
||||
env: {
|
||||
NX_DAEMON: 'true',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await getData(port, '/api');
|
||||
expect(result.message).toMatch('Hello');
|
||||
|
||||
try {
|
||||
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||
expect(await killPorts(port)).toBeTruthy();
|
||||
} catch (err) {
|
||||
console.log(
|
||||
'Error during cleanup (may be expected, especially ECONNRESET):',
|
||||
err.message
|
||||
);
|
||||
}
|
||||
}, 300_000);
|
||||
|
||||
// TODO(jack): fix and re-enable
|
||||
xit('should be able to import a lib into a nest application', async () => {
|
||||
const nestApp = uniq('nestapp');
|
||||
const nestLib = uniq('nestlib');
|
||||
|
||||
const port = await reservePort();
|
||||
process.env.PORT = `${port}`;
|
||||
runCLI(`generate @nx/nest:app apps/${nestApp} --no-interactive`);
|
||||
|
||||
runCLI(`generate @nx/nest:lib packages/${nestLib} --no-interactive`);
|
||||
|
||||
updateFile(`apps/${nestApp}/src/app/app.module.ts`, (content) => {
|
||||
return `import '@${workspaceName}/${nestLib}';\n${content}\n`;
|
||||
});
|
||||
|
||||
if (pm === 'pnpm') {
|
||||
updateJson(`apps/${nestApp}/package.json`, (json) => {
|
||||
json.dependencies = {
|
||||
[`@${workspaceName}/${nestLib}`]: 'workspace:*',
|
||||
};
|
||||
return json;
|
||||
});
|
||||
runCommand(`${getPackageManagerCommand().install}`);
|
||||
}
|
||||
runCLI(`sync`);
|
||||
|
||||
runCLI(`build ${nestApp} --verbose`);
|
||||
checkFilesExist(`apps/${nestApp}/dist/main.js`);
|
||||
|
||||
const p = await runCommandUntil(
|
||||
`serve ${nestApp}`,
|
||||
(output) =>
|
||||
output.includes(
|
||||
`Application is running on: http://localhost:${port}/api`
|
||||
),
|
||||
|
||||
{
|
||||
env: {
|
||||
NX_DAEMON: 'true',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await getData(port, '/api');
|
||||
expect(result.message).toMatch('Hello');
|
||||
|
||||
try {
|
||||
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||
expect(await killPorts(port)).toBeTruthy();
|
||||
} catch (err) {
|
||||
console.log(
|
||||
'Error during cleanup (may be expected, especially ECONNRESET):',
|
||||
err.message
|
||||
);
|
||||
}
|
||||
}, 300_000);
|
||||
|
||||
// Dependencies that are not directly imported but are still required for the build to succeed
|
||||
// App -> LibA -> LibB
|
||||
// LibB is transitive, it's not imported in the app, but is required by LibA
|
||||
|
||||
it('should be able to work with transitive non-dependencies', async () => {
|
||||
const nestApp = uniq('nestApp');
|
||||
const nestLibA = uniq('nestliba');
|
||||
const nestLibB = uniq('nestlibb');
|
||||
const port = await reservePort();
|
||||
|
||||
process.env.PORT = `${port}`;
|
||||
runCLI(`generate @nx/nest:app apps/${nestApp} --no-interactive`);
|
||||
|
||||
runCLI(`generate @nx/nest:lib packages/${nestLibA} --no-interactive`);
|
||||
runCLI(`generate @nx/nest:lib packages/${nestLibB} --no-interactive`);
|
||||
|
||||
if (pm === 'pnpm') {
|
||||
updateJson(`apps/${nestApp}/package.json`, (json) => {
|
||||
json.dependencies = {
|
||||
[`@${workspaceName}/${nestLibA}`]: 'workspace:*',
|
||||
};
|
||||
return json;
|
||||
});
|
||||
|
||||
updateJson(`packages/${nestLibA}/package.json`, (json) => {
|
||||
json.dependencies = {
|
||||
[`@${workspaceName}/${nestLibB}`]: 'workspace:*',
|
||||
};
|
||||
return json;
|
||||
});
|
||||
runCommand(`${getPackageManagerCommand().install}`);
|
||||
}
|
||||
runCLI(`sync`);
|
||||
|
||||
runCLI(`build ${nestApp} --verbose`);
|
||||
checkFilesExist(`apps/${nestApp}/dist/main.js`);
|
||||
|
||||
const p = await runCommandUntil(
|
||||
`serve ${nestApp}`,
|
||||
(output) =>
|
||||
output.includes(
|
||||
`Application is running on: http://localhost:${port}/api`
|
||||
),
|
||||
|
||||
{
|
||||
env: {
|
||||
NX_DAEMON: 'true',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const result = await getData(port, '/api');
|
||||
expect(result.message).toMatch('Hello');
|
||||
|
||||
try {
|
||||
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||
expect(await killPorts(port)).toBeTruthy();
|
||||
} catch (err) {
|
||||
console.log(
|
||||
'Error during cleanup (may be expected, especially ECONNRESET):',
|
||||
err.message
|
||||
);
|
||||
}
|
||||
}, 300_000);
|
||||
|
||||
it('should respect and support generating libraries with a name different than the import path', () => {
|
||||
const nodeLib = uniq('node-lib');
|
||||
const nestLib = uniq('nest-lib');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/node:lib packages/${nodeLib} --name=${nodeLib} --buildable`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/nest:lib packages/${nestLib} --name=${nestLib} --buildable`
|
||||
);
|
||||
|
||||
const packageJson = readJson(`packages/${nodeLib}/package.json`);
|
||||
expect(packageJson.nx.name).toBe(nodeLib);
|
||||
const nestPackageJson = readJson(`packages/${nestLib}/package.json`);
|
||||
expect(nestPackageJson.nx.name).toBe(nestLib);
|
||||
|
||||
expect(runCLI(`build ${nodeLib}`)).toContain(
|
||||
`Successfully ran target build for project ${nodeLib}`
|
||||
);
|
||||
expect(runCLI(`build ${nestLib}`)).toContain(
|
||||
`Successfully ran target build for project ${nestLib}`
|
||||
);
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
function getData(port, path = '/api'): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
http.get(`http://localhost:${port}${path}`, (res) => {
|
||||
expect(res.statusCode).toEqual(200);
|
||||
let data = '';
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
res.once('end', () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (e) {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user