Skip to content

Commit 222aaa9

Browse files
author
John Doe
committed
fix(nx-plugin): remove createNode v1 logic and int + unit tests
1 parent f225e90 commit 222aaa9

File tree

10 files changed

+349
-321
lines changed

10 files changed

+349
-321
lines changed

packages/nx-plugin/src/executors/cli/utils.unit.test.ts

Lines changed: 238 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1-
import { type MockInstance, describe, expect, it, vi } from 'vitest';
2-
import { osAgnosticPath } from '@code-pushup/test-utils';
1+
import { readFile } from 'node:fs/promises';
2+
import {
3+
type MockInstance,
4+
afterEach,
5+
beforeEach,
6+
describe,
7+
expect,
8+
it,
9+
vi,
10+
} from 'vitest';
11+
import { MEMFS_VOLUME, osAgnosticPath } from '@code-pushup/test-utils';
12+
import { normalizedCreateNodesV2Context } from '../../plugin/utils.js';
313
import type { Command } from '../internal/types.js';
414
import {
515
parseCliExecutorOnlyOptions,
616
parseCliExecutorOptions,
717
parsePrintConfigExecutorOptions,
818
} from './utils.js';
919

20+
vi.mock('node:fs/promises', () => ({
21+
readFile: vi.fn(),
22+
}));
23+
1024
describe('parsePrintConfigExecutorOptions', () => {
1125
it('should provide NO default output path', () => {
1226
expect(parsePrintConfigExecutorOptions({})).toStrictEqual(
@@ -203,3 +217,225 @@ describe('parseCliExecutorOptions', () => {
203217
},
204218
);
205219
});
220+
221+
describe('normalizedCreateNodesV2Context', () => {
222+
const CP_TARGET_NAME = 'code-pushup';
223+
224+
beforeEach(() => {
225+
vi.clearAllMocks();
226+
});
227+
228+
afterEach(() => {
229+
vi.restoreAllMocks();
230+
});
231+
232+
it('should normalize context with default target name', async () => {
233+
const projectJsonPath = `${MEMFS_VOLUME}/libs/my-lib/project.json`;
234+
const projectJsonContent = JSON.stringify({
235+
name: 'my-lib',
236+
root: 'libs/my-lib',
237+
targets: {},
238+
});
239+
240+
// Mock readFile
241+
vi.mocked(readFile).mockResolvedValue(Buffer.from(projectJsonContent));
242+
243+
const context = {
244+
nxJsonConfiguration: {},
245+
configFiles: [],
246+
workspaceRoot: MEMFS_VOLUME,
247+
};
248+
249+
const result = await normalizedCreateNodesV2Context(
250+
context,
251+
projectJsonPath,
252+
);
253+
254+
expect(result).toEqual({
255+
...context,
256+
projectJson: {
257+
name: 'my-lib',
258+
root: 'libs/my-lib',
259+
targets: {},
260+
},
261+
projectRoot: expect.any(String),
262+
createOptions: {
263+
targetName: CP_TARGET_NAME,
264+
},
265+
});
266+
expect(osAgnosticPath(result.projectRoot)).toBe(
267+
osAgnosticPath(`${MEMFS_VOLUME}/libs/my-lib`),
268+
);
269+
270+
expect(readFile).toHaveBeenCalledWith(projectJsonPath);
271+
});
272+
273+
it('should normalize context with custom target name', async () => {
274+
const projectJsonPath = `${MEMFS_VOLUME}/libs/my-lib/project.json`;
275+
const projectJsonContent = JSON.stringify({
276+
name: 'my-lib',
277+
root: 'libs/my-lib',
278+
targets: {},
279+
});
280+
281+
const customTargetName = 'custom-target';
282+
283+
// Mock readFile
284+
vi.mocked(readFile).mockResolvedValue(Buffer.from(projectJsonContent));
285+
286+
const context = {
287+
nxJsonConfiguration: {},
288+
configFiles: [],
289+
workspaceRoot: MEMFS_VOLUME,
290+
};
291+
292+
const result = await normalizedCreateNodesV2Context(
293+
context,
294+
projectJsonPath,
295+
{
296+
targetName: customTargetName,
297+
},
298+
);
299+
300+
expect(result).toEqual({
301+
...context,
302+
projectJson: {
303+
name: 'my-lib',
304+
root: 'libs/my-lib',
305+
targets: {},
306+
},
307+
projectRoot: expect.any(String),
308+
createOptions: {
309+
targetName: customTargetName,
310+
},
311+
});
312+
expect(osAgnosticPath(result.projectRoot)).toBe(
313+
osAgnosticPath(`${MEMFS_VOLUME}/libs/my-lib`),
314+
);
315+
});
316+
317+
it('should extract project root from project.json path', async () => {
318+
const projectJsonPath = `${MEMFS_VOLUME}/packages/utils/project.json`;
319+
const projectJsonContent = JSON.stringify({
320+
name: 'utils',
321+
root: 'packages/utils',
322+
targets: {},
323+
});
324+
325+
// Mock readFile
326+
vi.mocked(readFile).mockResolvedValue(Buffer.from(projectJsonContent));
327+
328+
const context = {
329+
nxJsonConfiguration: {},
330+
configFiles: [],
331+
workspaceRoot: MEMFS_VOLUME,
332+
};
333+
334+
const result = await normalizedCreateNodesV2Context(
335+
context,
336+
projectJsonPath,
337+
);
338+
339+
expect(osAgnosticPath(result.projectRoot)).toBe(
340+
osAgnosticPath(`${MEMFS_VOLUME}/packages/utils`),
341+
);
342+
});
343+
344+
it('should preserve all context properties', async () => {
345+
const projectJsonPath = `${MEMFS_VOLUME}/libs/my-lib/project.json`;
346+
const projectJsonContent = JSON.stringify({
347+
name: 'my-lib',
348+
root: 'libs/my-lib',
349+
targets: {},
350+
});
351+
352+
// Mock readFile
353+
vi.mocked(readFile).mockResolvedValue(Buffer.from(projectJsonContent));
354+
355+
const context = {
356+
nxJsonConfiguration: { namedInputs: { default: ['{projectRoot}/**/*'] } },
357+
workspaceRoot: MEMFS_VOLUME,
358+
};
359+
360+
const result = await normalizedCreateNodesV2Context(
361+
context,
362+
projectJsonPath,
363+
);
364+
365+
expect(result.nxJsonConfiguration).toEqual(context.nxJsonConfiguration);
366+
expect(result.workspaceRoot).toBe(context.workspaceRoot);
367+
expect(result.projectJson).toBeDefined();
368+
expect(result.projectRoot).toBeDefined();
369+
expect(result.createOptions).toBeDefined();
370+
});
371+
372+
it('should preserve createOptions properties', async () => {
373+
const projectJsonPath = `${MEMFS_VOLUME}/libs/my-lib/project.json`;
374+
const projectJsonContent = JSON.stringify({
375+
name: 'my-lib',
376+
root: 'libs/my-lib',
377+
targets: {},
378+
});
379+
380+
// Mock readFile
381+
vi.mocked(readFile).mockResolvedValue(Buffer.from(projectJsonContent));
382+
383+
const context = {
384+
nxJsonConfiguration: {},
385+
configFiles: [],
386+
workspaceRoot: MEMFS_VOLUME,
387+
};
388+
389+
const createOptions = {
390+
targetName: 'custom-target',
391+
projectPrefix: 'cli',
392+
bin: 'packages/cli/dist',
393+
};
394+
395+
const result = await normalizedCreateNodesV2Context(
396+
context,
397+
projectJsonPath,
398+
createOptions,
399+
);
400+
401+
expect(result.createOptions).toEqual({
402+
...createOptions,
403+
targetName: 'custom-target',
404+
});
405+
});
406+
407+
it('should throw error when project.json file cannot be read', async () => {
408+
const projectJsonPath = `${MEMFS_VOLUME}/libs/my-lib/project.json`;
409+
410+
// Mock readFile to throw error
411+
vi.mocked(readFile).mockRejectedValue(new Error('File not found'));
412+
413+
const context = {
414+
nxJsonConfiguration: {},
415+
configFiles: [],
416+
workspaceRoot: MEMFS_VOLUME,
417+
};
418+
419+
await expect(
420+
normalizedCreateNodesV2Context(context, projectJsonPath),
421+
).rejects.toThrow(`Error parsing project.json file ${projectJsonPath}.`);
422+
});
423+
424+
it('should throw error when project.json contains invalid JSON', async () => {
425+
const projectJsonPath = `${MEMFS_VOLUME}/libs/my-lib/project.json`;
426+
const invalidJson = '{ invalid json }';
427+
428+
// Mock readFile
429+
vi.mocked(readFile).mockResolvedValue(Buffer.from(invalidJson));
430+
431+
const context = {
432+
nxJsonConfiguration: {},
433+
configFiles: [],
434+
workspaceRoot: MEMFS_VOLUME,
435+
};
436+
437+
await expect(
438+
normalizedCreateNodesV2Context(context, projectJsonPath),
439+
).rejects.toThrow(`Error parsing project.json file ${projectJsonPath}.`);
440+
});
441+
});

packages/nx-plugin/src/index.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import { PLUGIN_NAME } from './plugin/constants.js';
2-
import { createNodes, createNodesV2 } from './plugin/index.js';
2+
import { createNodesV2 } from './plugin/index.js';
33

44
// default export for nx.json#plugins
55
const plugin = {
66
name: PLUGIN_NAME,
77
createNodesV2,
8-
// Keep for backwards compatibility with Nx < 21
9-
createNodes,
108
};
119

1210
export default plugin;
@@ -18,4 +16,4 @@ export type { ConfigurationGeneratorOptions } from './generators/configuration/s
1816
export { initGenerator, initSchematic } from './generators/init/generator.js';
1917
export { type InitGeneratorSchema } from './generators/init/schema.js';
2018
export * from './internal/versions.js';
21-
export { createNodes, createNodesV2 } from './plugin/index.js';
19+
export { createNodesV2 } from './plugin/index.js';
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export { createNodes, createNodesV2 } from './plugin.js';
1+
export { createNodesV2 } from './plugin.js';
22
export type { CreateNodesOptions } from './types.js';

packages/nx-plugin/src/plugin/plugin.ts

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import type {
2-
CreateNodes,
3-
CreateNodesContext,
42
CreateNodesContextV2,
53
CreateNodesResult,
64
CreateNodesResultV2,
@@ -10,42 +8,7 @@ import { PROJECT_JSON_FILE_NAME } from '../internal/constants.js';
108
import { PLUGIN_NAME } from './constants.js';
119
import { createTargets } from './target/targets.js';
1210
import type { CreateNodesOptions } from './types.js';
13-
import {
14-
normalizedCreateNodesContext,
15-
normalizedCreateNodesV2Context,
16-
} from './utils.js';
17-
18-
// name has to be "createNodes" to get picked up by Nx <v20
19-
/**
20-
* @deprecated
21-
*/
22-
export const createNodes: CreateNodes = [
23-
`**/${PROJECT_JSON_FILE_NAME}`,
24-
async (
25-
projectConfigurationFile: string,
26-
createNodesOptions: unknown,
27-
context: CreateNodesContext,
28-
): Promise<CreateNodesResult> => {
29-
const parsedCreateNodesOptions = createNodesOptions as CreateNodesOptions;
30-
const pluginsConfig =
31-
context.nxJsonConfiguration.pluginsConfig?.[PLUGIN_NAME] ?? {};
32-
const mergedOptions = { ...pluginsConfig, ...parsedCreateNodesOptions };
33-
34-
const normalizedContext = await normalizedCreateNodesContext(
35-
context,
36-
projectConfigurationFile,
37-
mergedOptions,
38-
);
39-
40-
return {
41-
projects: {
42-
[normalizedContext.projectRoot]: {
43-
targets: await createTargets(normalizedContext),
44-
},
45-
},
46-
};
47-
},
48-
];
11+
import { normalizedCreateNodesV2Context } from './utils.js';
4912

5013
export const createNodesV2: CreateNodesV2<CreateNodesOptions> = [
5114
`**/${PROJECT_JSON_FILE_NAME}`,

0 commit comments

Comments
 (0)