Skip to content

Commit 767746d

Browse files
ashley-hunterclaude
andcommitted
test(linker): use inline fixtures instead of Angular 21 node_modules
Replace tests that read from the e2e app's @angular/common installation with self-contained inline fixtures using minimal partial declarations. This removes the fragile dependency on a specific Angular version being installed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5878a53 commit 767746d

File tree

1 file changed

+112
-54
lines changed

1 file changed

+112
-54
lines changed

napi/angular-compiler/test/linker.test.ts

Lines changed: 112 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,141 @@
1-
import { readFileSync } from 'node:fs'
2-
import { resolve } from 'node:path'
31
import { describe, it, expect } from 'vitest'
42

53
import { linkAngularPackageSync } from '../index.js'
64

75
/**
8-
* Resolve the path to an Angular 21 package file.
9-
* The e2e app has Angular 21.2.2 installed with chunk files.
6+
* Minimal Angular partial declaration fixtures that simulate the structure
7+
* of FESM bundle files (including Angular 21+ chunk files).
8+
* Uses actual Unicode ɵ (U+0275) characters as they appear in real Angular packages.
109
*/
11-
function resolveAngular21File(subpath: string): string {
12-
return resolve(__dirname, '../e2e/app/node_modules/@angular', subpath)
10+
const INJECTABLE_CHUNK = `
11+
import * as i0 from '@angular/core';
12+
13+
class PlatformLocation {
14+
historyGo(relativePosition) {
15+
throw new Error('Not implemented');
16+
}
17+
static \u0275fac = i0.\u0275\u0275ngDeclareFactory({
18+
minVersion: "12.0.0",
19+
version: "21.0.0",
20+
ngImport: i0,
21+
type: PlatformLocation,
22+
deps: [],
23+
target: i0.\u0275\u0275FactoryTarget.Injectable
24+
});
25+
static \u0275prov = i0.\u0275\u0275ngDeclareInjectable({
26+
minVersion: "12.0.0",
27+
version: "21.0.0",
28+
ngImport: i0,
29+
type: PlatformLocation,
30+
providedIn: "platform",
31+
useClass: undefined
32+
});
1333
}
1434
15-
describe('Angular linker - chunk file support', () => {
16-
it('should link ɵɵngDeclare calls in _platform_location-chunk.mjs', () => {
17-
const filepath = resolveAngular21File('common/fesm2022/_platform_location-chunk.mjs')
18-
const code = readFileSync(filepath, 'utf8')
35+
export { PlatformLocation };
36+
`
37+
38+
const NG_MODULE_CHUNK = `
39+
import * as i0 from '@angular/core';
40+
41+
class CommonModule {
42+
static \u0275fac = i0.\u0275\u0275ngDeclareFactory({
43+
minVersion: "12.0.0",
44+
version: "21.0.0",
45+
ngImport: i0,
46+
type: CommonModule,
47+
deps: [],
48+
target: i0.\u0275\u0275FactoryTarget.NgModule
49+
});
50+
static \u0275mod = i0.\u0275\u0275ngDeclareNgModule({
51+
minVersion: "14.0.0",
52+
version: "21.0.0",
53+
ngImport: i0,
54+
type: CommonModule,
55+
imports: [],
56+
exports: []
57+
});
58+
static \u0275inj = i0.\u0275\u0275ngDeclareInjector({
59+
minVersion: "12.0.0",
60+
version: "21.0.0",
61+
ngImport: i0,
62+
type: CommonModule
63+
});
64+
}
65+
66+
export { CommonModule };
67+
`
68+
69+
const PIPE_CHUNK = `
70+
import * as i0 from '@angular/core';
71+
72+
class AsyncPipe {
73+
constructor(ref) {
74+
this._ref = ref;
75+
}
76+
static \u0275fac = i0.\u0275\u0275ngDeclareFactory({
77+
minVersion: "12.0.0",
78+
version: "21.0.0",
79+
ngImport: i0,
80+
type: AsyncPipe,
81+
deps: [{ token: i0.ChangeDetectorRef }],
82+
target: i0.\u0275\u0275FactoryTarget.Pipe
83+
});
84+
static \u0275pipe = i0.\u0275\u0275ngDeclarePipe({
85+
minVersion: "14.0.0",
86+
version: "21.0.0",
87+
ngImport: i0,
88+
type: AsyncPipe,
89+
isStandalone: false,
90+
name: "async",
91+
pure: false
92+
});
93+
}
1994
20-
// Verify the chunk file has unlinked declarations
21-
expect(code).toContain('\u0275\u0275ngDeclare')
95+
export { AsyncPipe };
96+
`
2297

23-
const result = linkAngularPackageSync(code, filepath)
98+
describe('Angular linker - chunk file linking', () => {
99+
it('should link \u0275\u0275ngDeclareFactory and \u0275\u0275ngDeclareInjectable', () => {
100+
const result = linkAngularPackageSync(
101+
INJECTABLE_CHUNK,
102+
'node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs',
103+
)
24104

25105
expect(result.linked).toBe(true)
26106
expect(result.code).not.toContain('\u0275\u0275ngDeclare')
27107
})
28108

29-
it('should link ɵɵngDeclare calls in _location-chunk.mjs', () => {
30-
const filepath = resolveAngular21File('common/fesm2022/_location-chunk.mjs')
31-
const code = readFileSync(filepath, 'utf8')
32-
33-
// Verify the chunk file has unlinked declarations
34-
expect(code).toContain('\u0275\u0275ngDeclare')
35-
36-
const result = linkAngularPackageSync(code, filepath)
109+
it('should link \u0275\u0275ngDeclareNgModule and \u0275\u0275ngDeclareInjector', () => {
110+
const result = linkAngularPackageSync(
111+
NG_MODULE_CHUNK,
112+
'node_modules/@angular/common/fesm2022/_common_module-chunk.mjs',
113+
)
37114

38115
expect(result.linked).toBe(true)
39116
expect(result.code).not.toContain('\u0275\u0275ngDeclare')
40117
})
41118

42-
it('should link ɵɵngDeclare calls in _common_module-chunk.mjs', () => {
43-
const filepath = resolveAngular21File('common/fesm2022/_common_module-chunk.mjs')
44-
const code = readFileSync(filepath, 'utf8')
45-
46-
// Verify the chunk file has unlinked declarations
47-
expect(code).toContain('\u0275\u0275ngDeclare')
48-
49-
const result = linkAngularPackageSync(code, filepath)
119+
it('should link \u0275\u0275ngDeclarePipe', () => {
120+
const result = linkAngularPackageSync(
121+
PIPE_CHUNK,
122+
'node_modules/@angular/common/fesm2022/_pipes-chunk.mjs',
123+
)
50124

51125
expect(result.linked).toBe(true)
52126
expect(result.code).not.toContain('\u0275\u0275ngDeclare')
53127
})
54128

55-
it('should link all Angular 21 chunk files in @angular/common', () => {
56-
const { readdirSync } = require('node:fs')
57-
const dir = resolveAngular21File('common/fesm2022')
58-
const files = readdirSync(dir) as string[]
59-
const chunkFiles = files.filter(
60-
(f: string) => f.startsWith('_') && f.endsWith('-chunk.mjs'),
129+
it('should return linked: false for files without declarations', () => {
130+
const code = `
131+
export function helper() { return 42; }
132+
`
133+
const result = linkAngularPackageSync(
134+
code,
135+
'node_modules/@angular/common/fesm2022/_utils-chunk.mjs',
61136
)
62137

63-
expect(chunkFiles.length).toBeGreaterThan(0)
64-
65-
for (const chunkFile of chunkFiles) {
66-
const filepath = resolve(dir, chunkFile)
67-
const code = readFileSync(filepath, 'utf8')
68-
69-
if (!code.includes('\u0275\u0275ngDeclare')) {
70-
continue // Skip chunks without declarations
71-
}
72-
73-
const result = linkAngularPackageSync(code, filepath)
74-
75-
expect(result.linked, `${chunkFile} should be linked`).toBe(true)
76-
expect(
77-
result.code.includes('\u0275\u0275ngDeclare'),
78-
`${chunkFile} should not contain unlinked declarations`,
79-
).toBe(false)
80-
}
138+
expect(result.linked).toBe(false)
81139
})
82140
})
83141

@@ -91,7 +149,7 @@ describe('NODE_MODULES_JS_REGEX filter matching', () => {
91149
).toBe(true)
92150
})
93151

94-
it('should match Angular 21 chunk files', () => {
152+
it('should match chunk files', () => {
95153
expect(
96154
NODE_MODULES_JS_REGEX.test(
97155
'node_modules/@angular/common/fesm2022/_platform_location-chunk.mjs',

0 commit comments

Comments
 (0)