Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 47 additions & 2 deletions e2e/nx-forge-e2e/src/application.generator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ const describeDirectoryTree = (directory: string, depth = 0): string => {
.join('\n');
};

const parseJsonOutput = (output: string) => {
const jsonStart = output.indexOf('{');

if (jsonStart === -1) {
throw new Error(`Expected JSON output, received:\n${output}`);
}

return JSON.parse(output.slice(jsonStart));
};

const expectWebpackBuildOutput = async (
workspaceDirectory: string,
appName: string
Expand Down Expand Up @@ -105,7 +115,7 @@ const configureWebpackTaskInference = (
const enableWebpackTaskInference = async (workspaceDirectory: string) => {
configureWebpackTaskInference(workspaceDirectory, true);
await runNxCommandAsync(
'generate @nx/webpack:init --addPlugin=true --interactive=false',
'generate @nx/webpack:init --addPlugin=true --skipPackageJson=true --interactive=false',
{
cwd: workspaceDirectory,
}
Expand Down Expand Up @@ -148,6 +158,41 @@ describe('Forge application generator', () => {
expect(
existsSync(join(workspaceDirectory, 'apps', appName, 'src', 'index.ts'))
).toBe(true);

const project = JSON.parse(
readFileSync(
join(workspaceDirectory, 'apps', appName, 'project.json'),
'utf8'
)
);
expect(project.targets?.lint).toBeUndefined();

const resolvedProject = parseJsonOutput(
(
await runNxCommandAsync(`show project ${appName} --json`, {
cwd: workspaceDirectory,
})
).stdout
);
expect(resolvedProject.targets.lint).toMatchObject({
cache: true,
executor: 'nx:run-commands',
outputs: ['{options.outputFile}'],
options: {
command: 'eslint .',
cwd: `apps/${appName}`,
},
});

await runNxCommandAsync(
`run ${appName}:lint --output-file=lint-results.json --format=json`,
{
cwd: workspaceDirectory,
}
);
expect(
existsSync(join(workspaceDirectory, 'apps', appName, 'lint-results.json'))
).toBe(true);
});

describe('--directory', () => {
Expand Down Expand Up @@ -221,7 +266,7 @@ describe('Forge application generator', () => {
const appName = await generateForgeApp({
cwd: workspaceDirectory,
directory: 'apps',
options: '--bundler=webpack',
options: '--bundler=webpack --linter=none --unitTestRunner=none',
});
expect(
readFileSync(
Expand Down
26 changes: 19 additions & 7 deletions e2e/nx-forge-e2e/src/utils/generate-forge-app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { runNxCommandAsync } from './async-commands';
import { formatCommandResult, runNxCommandAsync } from './async-commands';

const uniqueAppName = () =>
`nx-forge-test-app-${Date.now()}-${Math.floor(Math.random() * 100000)}`;
Expand All @@ -22,11 +22,23 @@ export const generateForgeApp = async ({
options?: string;
}): Promise<string> => {
const appName = uniqueAppName();
await runNxCommandAsync(
`generate @toolsplus/nx-forge:application ${directory}/${appName} ${
options ?? ''
}`,
{ cwd }
);
const command = `generate @toolsplus/nx-forge:application ${directory}/${appName} ${
options ?? ''
}`;
const result = await runNxCommandAsync(command, { cwd });

if (
`${result.stdout}\n${result.stderr}`.includes(
'deprecated `@nx/eslint:lint` executor'
)
) {
throw new Error(
[
'Generated application used the deprecated ESLint executor.',
formatCommandResult(`nx ${command}`, result),
].join('\n\n')
);
}

return appName;
};
4 changes: 2 additions & 2 deletions e2e/nx-forge-e2e/src/utils/test-workspace.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { execSync } from 'node:child_process';
import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { workspaceRoot } from '@nx/devkit';
import { NX_VERSION, workspaceRoot } from '@nx/devkit';

const TEST_WORKSPACES_ROOT = join(workspaceRoot, 'tmp');

Expand Down Expand Up @@ -41,7 +41,7 @@ export const createTestWorkspace = (
});

runCommand(
`npx -y create-nx-workspace@latest ${workspaceName} --preset=apps --nxCloud=skip --packageManager=npm --no-interactive`,
`npx -y create-nx-workspace@${NX_VERSION} ${workspaceName} --preset=apps --nxCloud=skip --packageManager=npm --no-interactive`,
TEST_WORKSPACES_ROOT
);

Expand Down
47 changes: 21 additions & 26 deletions nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,12 @@
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"targetDefaults": {
"build": {
"dependsOn": [
"^build"
],
"inputs": [
"production",
"^production"
],
"dependsOn": ["^build"],
"inputs": ["production", "^production"],
"cache": true
},
"@nx/jest:jest": {
"inputs": [
"default",
"^production",
"{workspaceRoot}/jest.preset.js"
],
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
"cache": true,
"options": {
"passWithNoTests": true
Expand All @@ -32,32 +23,27 @@
}
}
},
"@nx/eslint:lint": {
"lint": {
"inputs": [
"default",
"^default",
"{workspaceRoot}/.eslintrc.json",
"{workspaceRoot}/eslint.config.mjs",
"{workspaceRoot}/tools/eslint-rules/**/*"
"{workspaceRoot}/tools/eslint-rules/**/*",
{
"externalDependencies": ["eslint"]
}
],
"cache": true
},
"@nx/js:tsc": {
"cache": true,
"dependsOn": [
"^build"
],
"inputs": [
"production",
"^production"
]
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
}
},
"namedInputs": {
"default": [
"{projectRoot}/**/*",
"sharedGlobals"
],
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"sharedGlobals": [],
"production": [
"default",
Expand All @@ -70,5 +56,14 @@
]
},
"defaultBase": "main",
"analytics": false
"analytics": false,
"plugins": [
{
"plugin": "@nx/eslint/plugin",
"options": {
"targetName": "lint"
},
"include": ["packages/nx-forge/**/*", "tools/docs/**/*"]
}
]
}
4 changes: 0 additions & 4 deletions packages/nx-forge/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@
]
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/nx-forge"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { readNxJson, readProjectConfiguration, Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';

import './test-utils/mock-plugin-inference.spec-helper';

import { applicationGenerator } from './generator';

describe('application generator ESLint inference', () => {
let tree: Tree;
let nxAddPlugins: string | undefined;

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
nxAddPlugins = process.env.NX_ADD_PLUGINS;
delete process.env.NX_ADD_PLUGINS;
});

afterEach(() => {
if (nxAddPlugins === undefined) {
delete process.env.NX_ADD_PLUGINS;
} else {
process.env.NX_ADD_PLUGINS = nxAddPlugins;
}
});

it('uses the inferred lint target by default', async () => {
await applicationGenerator(tree, {
directory: 'my-forge-app',
skipFormat: true,
});

const nxJson = readNxJson(tree);
expect(nxJson.plugins).toContainEqual({
plugin: '@nx/eslint/plugin',
options: { targetName: 'lint' },
});

const project = readProjectConfiguration(tree, 'my-forge-app');
expect(project.targets?.lint).toBeUndefined();
expect(project.targets?.build?.executor).toBe('@nx/webpack:webpack');
expect(project.targets?.test?.executor).toBe('@nx/jest:jest');
expect(tree.exists('my-forge-app/eslint.config.mjs')).toBe(true);
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {
logger,
readNxJson,
readProjectConfiguration,
Tree,
updateNxJson,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';

import './test-utils/mock-plugin-inference.spec-helper';
import { applicationGenerator } from './generator';

describe('application generator (legacy)', () => {
Expand All @@ -21,6 +23,8 @@ describe('application generator (legacy)', () => {
await applicationGenerator(tree, {
directory: 'my-forge-app',
bundler: 'webpack',
linter: 'none',
unitTestRunner: 'none',
addPlugin: false,
});
const project = readProjectConfiguration(tree, 'my-forge-app');
Expand Down Expand Up @@ -55,4 +59,25 @@ describe('application generator (legacy)', () => {
expect(webpackConfig).toContain(`composePlugins`);
expect(webpackConfig).toContain(`target: 'node'`);
});

it('supports an explicit lint executor with a deprecation warning', async () => {
const warn = jest.spyOn(logger, 'warn').mockImplementation();

await applicationGenerator(tree, {
directory: 'my-forge-app',
bundler: 'esbuild',
unitTestRunner: 'none',
addPlugin: false,
skipFormat: true,
});

const project = readProjectConfiguration(tree, 'my-forge-app');
expect(project.targets?.lint).toEqual({ executor: '@nx/eslint:lint' });
expect(warn).toHaveBeenCalledTimes(1);
expect(warn).toHaveBeenCalledWith(
expect.stringContaining(
'Generating a target that uses the deprecated `@nx/eslint:lint` executor.'
)
);
});
});
Loading
Loading