-
Notifications
You must be signed in to change notification settings - Fork 12k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(@angular-devkit/build-angular): additional unit tests for esbuil…
…d builder The following unit tests have been ported over to test the experimental esbuild-based browser application builder: * `baseHref` option * `crossOrigin` option * TypeScript path mapping behavior
- Loading branch information
1 parent
54cc8d4
commit 4c53c8f
Showing
3 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
109 changes: 109 additions & 0 deletions
109
...build_angular/src/builders/browser-esbuild/tests/behavior/typescript-path-mapping_spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import { buildEsbuildBrowser } from '../../index'; | ||
import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup'; | ||
|
||
describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { | ||
describe('Behavior: "TypeScript Path Mapping"', () => { | ||
it('should resolve TS files when imported with a path mapping', async () => { | ||
// Change main module import to use path mapping | ||
await harness.modifyFile('src/main.ts', (content) => | ||
content.replace(`'./app/app.module'`, `'@root/app.module'`), | ||
); | ||
|
||
// Add a path mapping for `@root` | ||
await harness.modifyFile('tsconfig.json', (content) => { | ||
const tsconfig = JSON.parse(content); | ||
tsconfig.compilerOptions.paths = { | ||
'@root/*': ['./src/app/*'], | ||
}; | ||
|
||
return JSON.stringify(tsconfig); | ||
}); | ||
|
||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
|
||
expect(result?.success).toBe(true); | ||
}); | ||
|
||
it('should fail to resolve if no path mapping for an import is present', async () => { | ||
// Change main module import to use path mapping | ||
await harness.modifyFile('src/main.ts', (content) => | ||
content.replace(`'./app/app.module'`, `'@root/app.module'`), | ||
); | ||
|
||
// Add a path mapping for `@not-root` | ||
await harness.modifyFile('tsconfig.json', (content) => { | ||
const tsconfig = JSON.parse(content); | ||
tsconfig.compilerOptions.paths = { | ||
'@not-root/*': ['./src/app/*'], | ||
}; | ||
|
||
return JSON.stringify(tsconfig); | ||
}); | ||
|
||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
}); | ||
|
||
const { result, logs } = await harness.executeOnce({ outputLogsOnFailure: false }); | ||
|
||
expect(result?.success).toBe(false); | ||
expect(logs).toContain( | ||
jasmine.objectContaining({ | ||
message: jasmine.stringMatching('Could not resolve "@root/app.module"'), | ||
}), | ||
); | ||
}); | ||
|
||
it('should resolve JS files when imported with a path mapping', async () => { | ||
// Change main module import to use path mapping | ||
await harness.modifyFile('src/main.ts', (content) => | ||
content.replace(`'./app/app.module'`, `'app-module'`), | ||
); | ||
|
||
await harness.writeFiles({ | ||
'a.js': `export * from './src/app/app.module';\n\nconsole.log('A');`, | ||
'a.d.ts': `export * from './src/app/app.module';`, | ||
}); | ||
|
||
// Add a path mapping for `@root` | ||
await harness.modifyFile('tsconfig.json', (content) => { | ||
const tsconfig = JSON.parse(content); | ||
tsconfig.compilerOptions.paths = { | ||
'app-module': ['a.js'], | ||
}; | ||
|
||
return JSON.stringify(tsconfig); | ||
}); | ||
|
||
// app.module needs to be manually included since it is not referenced via a TS file | ||
// with the test path mapping in place. | ||
await harness.modifyFile('src/tsconfig.app.json', (content) => { | ||
const tsconfig = JSON.parse(content); | ||
tsconfig.files.push('app/app.module.ts'); | ||
|
||
return JSON.stringify(tsconfig); | ||
}); | ||
|
||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
|
||
expect(result?.success).toBe(true); | ||
harness.expectFile('dist/main.js').content.toContain(`console.log("A")`); | ||
}); | ||
}); | ||
}); |
113 changes: 113 additions & 0 deletions
113
...angular_devkit/build_angular/src/builders/browser-esbuild/tests/options/base-href_spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import { buildEsbuildBrowser } from '../../index'; | ||
import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup'; | ||
|
||
describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { | ||
describe('Option: "baseHref"', () => { | ||
beforeEach(async () => { | ||
// Application code is not needed for asset tests | ||
await harness.writeFile('src/main.ts', 'console.log("TEST");'); | ||
}); | ||
|
||
it('should update the base element href attribute when option is set', async () => { | ||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
baseHref: '/abc', | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness.expectFile('dist/index.html').content.toContain('<base href="/abc">'); | ||
}); | ||
|
||
it('should update the base element with no href attribute when option is set', async () => { | ||
await harness.writeFile( | ||
'src/index.html', | ||
` | ||
<html> | ||
<head><base></head> | ||
<body></body> | ||
</html> | ||
`, | ||
); | ||
|
||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
baseHref: '/abc', | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness.expectFile('dist/index.html').content.toContain('<base href="/abc">'); | ||
}); | ||
|
||
it('should add the base element href attribute when option is set', async () => { | ||
await harness.writeFile( | ||
'src/index.html', | ||
` | ||
<html> | ||
<head></head> | ||
<body></body> | ||
</html> | ||
`, | ||
); | ||
|
||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
baseHref: '/abc', | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness.expectFile('dist/index.html').content.toContain('<base href="/abc">'); | ||
}); | ||
|
||
it('should update the base element href attribute when option is set to an empty string', async () => { | ||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
baseHref: '', | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness.expectFile('dist/index.html').content.toContain('<base href="">'); | ||
}); | ||
|
||
it('should not update the base element href attribute when option is not present', async () => { | ||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness.expectFile('dist/index.html').content.toContain('<base href="/">'); | ||
}); | ||
|
||
it('should not change the base element href attribute when option is not present', async () => { | ||
await harness.writeFile( | ||
'src/index.html', | ||
` | ||
<html> | ||
<head><base href="."></head> | ||
<body></body> | ||
</html> | ||
`, | ||
); | ||
|
||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness.expectFile('dist/index.html').content.toContain('<base href=".">'); | ||
}); | ||
}); | ||
}); |
103 changes: 103 additions & 0 deletions
103
...ular_devkit/build_angular/src/builders/browser-esbuild/tests/options/cross-origin_spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
import { buildEsbuildBrowser } from '../../index'; | ||
import { CrossOrigin } from '../../schema'; | ||
import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup'; | ||
|
||
describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => { | ||
describe('Option: "crossOrigin"', () => { | ||
beforeEach(async () => { | ||
// Application code is not needed for asset tests | ||
await harness.writeFile('src/main.ts', 'console.log("TEST");'); | ||
|
||
// Add a global stylesheet to test link elements | ||
await harness.writeFile('src/styles.css', '// Global styles'); | ||
|
||
// Reduce the input index HTML to a single line to simplify comparing | ||
await harness.writeFile( | ||
'src/index.html', | ||
'<html><head><base href="/"></head><body><app-root></app-root></body></html>', | ||
); | ||
}); | ||
|
||
it('should add the use-credentials crossorigin attribute when option is set to use-credentials', async () => { | ||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
styles: ['src/styles.css'], | ||
crossOrigin: CrossOrigin.UseCredentials, | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness | ||
.expectFile('dist/index.html') | ||
.content.toEqual( | ||
`<html><head><base href="/"><link rel="stylesheet" href="styles.css" crossorigin="use-credentials"></head>` + | ||
`<body><app-root></app-root>` + | ||
`<script src="main.js" type="module" crossorigin="use-credentials"></script></body></html>`, | ||
); | ||
}); | ||
|
||
it('should add the anonymous crossorigin attribute when option is set to anonymous', async () => { | ||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
styles: ['src/styles.css'], | ||
crossOrigin: CrossOrigin.Anonymous, | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness | ||
.expectFile('dist/index.html') | ||
.content.toEqual( | ||
`<html><head><base href="/">` + | ||
`<link rel="stylesheet" href="styles.css" crossorigin="anonymous"></head>` + | ||
`<body><app-root></app-root>` + | ||
`<script src="main.js" type="module" crossorigin="anonymous"></script></body></html>`, | ||
); | ||
}); | ||
|
||
it('should not add a crossorigin attribute when option is set to none', async () => { | ||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
styles: ['src/styles.css'], | ||
crossOrigin: CrossOrigin.None, | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness | ||
.expectFile('dist/index.html') | ||
.content.toEqual( | ||
`<html><head><base href="/">` + | ||
`<link rel="stylesheet" href="styles.css"></head>` + | ||
`<body><app-root></app-root>` + | ||
`<script src="main.js" type="module"></script></body></html>`, | ||
); | ||
}); | ||
|
||
it('should not add a crossorigin attribute when option is not present', async () => { | ||
harness.useTarget('build', { | ||
...BASE_OPTIONS, | ||
styles: ['src/styles.css'], | ||
}); | ||
|
||
const { result } = await harness.executeOnce(); | ||
expect(result?.success).toBe(true); | ||
harness | ||
.expectFile('dist/index.html') | ||
.content.toEqual( | ||
`<html><head><base href="/">` + | ||
`<link rel="stylesheet" href="styles.css"></head>` + | ||
`<body><app-root></app-root>` + | ||
`<script src="main.js" type="module"></script></body></html>`, | ||
); | ||
}); | ||
}); | ||
}); |