fix(@angular-devkit/build-angular): handle windows spec collisions · angular/angular-cli@23667ed · GitHub
Skip to content

Commit 23667ed

Browse files
hybristalan-agius4
authored andcommitted
fix(@angular-devkit/build-angular): handle windows spec collisions
(cherry picked from commit 9e2d3fb)
1 parent 4a5c5e4 commit 23667ed

4 files changed

Lines changed: 118 additions & 25 deletions

File tree

packages/angular_devkit/build_angular/src/builders/karma/application_builder.ts

Lines changed: 2 additions & 23 deletions

packages/angular_devkit/build_angular/src/builders/karma/find-tests.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,39 @@ export async function findTests(
2626
return [...new Set(files.flat())];
2727
}
2828

29+
interface TestEntrypointsOptions {
30+
projectSourceRoot: string;
31+
workspaceRoot: string;
32+
}
33+
34+
/** Generate unique bundle names for a set of test files. */
35+
export function getTestEntrypoints(
36+
testFiles: string[],
37+
{ projectSourceRoot, workspaceRoot }: TestEntrypointsOptions,
38+
): Map<string, string> {
39+
const seen = new Set<string>();
40+
41+
return new Map(
42+
Array.from(testFiles, (testFile) => {
43+
const relativePath = removeRoots(testFile, [projectSourceRoot, workspaceRoot])
44+
// Strip leading dots and path separators.
45+
.replace(/^[./\\]+/, '')
46+
// Replace any path separators with dashes.
47+
.replace(/[/\\]/g, '-');
48+
const baseName = `spec-${basename(relativePath, extname(relativePath))}`;
49+
let uniqueName = baseName;
50+
let suffix = 2;
51+
while (seen.has(uniqueName)) {
52+
uniqueName = `${baseName}-${suffix}`.replace(/([^\w](?:spec|test))-([\d]+)$/, '-$2$1');
53+
++suffix;
54+
}
55+
seen.add(uniqueName);
56+
57+
return [uniqueName, testFile];
58+
}),
59+
);
60+
}
61+
2962
const normalizePath = (path: string): string => path.replace(/\\/g, '/');
3063

3164
const removeLeadingSlash = (pattern: string): string => {
@@ -44,6 +77,16 @@ const removeRelativeRoot = (path: string, root: string): string => {
4477
return path;
4578
};
4679

80+
function removeRoots(path: string, roots: string[]): string {
81+
for (const root of roots) {
82+
if (path.startsWith(root)) {
83+
return path.substring(root.length);
84+
}
85+
}
86+
87+
return basename(path);
88+
}
89+
4790
async function findMatchingTests(
4891
pattern: string,
4992
ignore: string[],
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { getTestEntrypoints } from './find-tests';
10+
11+
const UNIX_ENTRYPOINTS_OPTIONS = {
12+
pathSeparator: '/',
13+
workspaceRoot: '/my/workspace/root',
14+
projectSourceRoot: '/my/workspace/root/src-root',
15+
};
16+
17+
const WINDOWS_ENTRYPOINTS_OPTIONS = {
18+
pathSeparator: '\\',
19+
workspaceRoot: 'C:\\my\\workspace\\root',
20+
projectSourceRoot: 'C:\\my\\workspace\\root\\src-root',
21+
};
22+
23+
describe('getTestEntrypoints', () => {
24+
for (const options of [UNIX_ENTRYPOINTS_OPTIONS, WINDOWS_ENTRYPOINTS_OPTIONS]) {
25+
describe(`with path separator "${options.pathSeparator}"`, () => {
26+
function joinWithSeparator(base: string, rel: string) {
27+
return `${base}${options.pathSeparator}${rel.replace(/\//g, options.pathSeparator)}`;
28+
}
29+
30+
function getEntrypoints(workspaceRelative: string[], sourceRootRelative: string[] = []) {
31+
return getTestEntrypoints(
32+
[
33+
...workspaceRelative.map((p) => joinWithSeparator(options.workspaceRoot, p)),
34+
...sourceRootRelative.map((p) => joinWithSeparator(options.projectSourceRoot, p)),
35+
],
36+
options,
37+
);
38+
}
39+
40+
it('returns an empty map without test files', () => {
41+
expect(getEntrypoints([])).toEqual(new Map());
42+
});
43+
44+
it('strips workspace root and/or project source root', () => {
45+
expect(getEntrypoints(['a/b.spec.js'], ['c/d.spec.js'])).toEqual(
46+
new Map<string, string>([
47+
['spec-a-b.spec', joinWithSeparator(options.workspaceRoot, 'a/b.spec.js')],
48+
['spec-c-d.spec', joinWithSeparator(options.projectSourceRoot, 'c/d.spec.js')],
49+
]),
50+
);
51+
});
52+
53+
it('adds unique prefixes to distinguish between similar names', () => {
54+
expect(getEntrypoints(['a/b/c/d.spec.js', 'a-b/c/d.spec.js'], ['a/b-c/d.spec.js'])).toEqual(
55+
new Map<string, string>([
56+
['spec-a-b-c-d.spec', joinWithSeparator(options.workspaceRoot, 'a/b/c/d.spec.js')],
57+
['spec-a-b-c-d-2.spec', joinWithSeparator(options.workspaceRoot, 'a-b/c/d.spec.js')],
58+
[
59+
'spec-a-b-c-d-3.spec',
60+
joinWithSeparator(options.projectSourceRoot, 'a/b-c/d.spec.js'),
61+
],
62+
]),
63+
);
64+
});
65+
});
66+
}
67+
});

packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/specs_spec.ts

Lines changed: 6 additions & 2 deletions

0 commit comments

Comments
 (0)