diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c87cf53e028..b66c6355c922 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,40 @@
+
+
+# 13.0.4 (2021-12-01)
+
+### @angular/cli
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------------------------------- |
+| [ded7b5c06](https://github.com/angular/angular-cli/commit/ded7b5c069a145d1b3e264538d7c4302919ad030) | fix | exit with a non-zero error code when migration fails during `ng update` |
+| [250a58b48](https://github.com/angular/angular-cli/commit/250a58b4820a738aba7609627fa7fce0a24f10db) | fix | logic which determines which temp version of the CLI is to be download during `ng update` |
+
+### @schematics/angular
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------- |
+| [372e2e633](https://github.com/angular/angular-cli/commit/372e2e633f4bd9bf29c35d02890e1c6a70da3169) | fix | address eslint linting failures in `test.ts` |
+
+### @angular-devkit/build-angular
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------- |
+| [b835389c8](https://github.com/angular/angular-cli/commit/b835389c8a60749151039ed0baf0be025ce0932b) | fix | correctly extract messages when using cached build ([#22266](https://github.com/angular/angular-cli/pull/22266)) |
+| [647a5f0b1](https://github.com/angular/angular-cli/commit/647a5f0b18e49b2ece3f43c0a06bfb75d7caef49) | fix | don't watch nested `node_modules` when polling is enabled |
+| [4d01d4f72](https://github.com/angular/angular-cli/commit/4d01d4f72344c42f650f5495b21e6bd94069969a) | fix | transform remapped sourcemap into a plain object |
+
+### @ngtools/webpack
+
+| Commit | Type | Description |
+| --------------------------------------------------------------------------------------------------- | ---- | --------------------------------------------------------- |
+| [4d918ef99](https://github.com/angular/angular-cli/commit/4d918ef9912d53a09d73fb19fa41b121dceed37c) | fix | JIT mode CommonJS accessing inexistent `default` property |
+
+## Special Thanks
+
+Alan Agius, Billy Lando, David-Emmanuel DIVERNOIS and Derek Cormier
+
+
+
# 13.0.3 (2021-11-17)
diff --git a/package.json b/package.json
index 4f9e5f0b313f..7733f12a5f6c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@angular/devkit-repo",
- "version": "13.0.3",
+ "version": "13.0.4",
"private": true,
"description": "Software Development Kit for Angular",
"bin": {
diff --git a/packages/angular/cli/commands/new.md b/packages/angular/cli/commands/new.md
index ca3f14b8d696..135e1b2c108a 100644
--- a/packages/angular/cli/commands/new.md
+++ b/packages/angular/cli/commands/new.md
@@ -5,7 +5,7 @@ All prompts can safely be allowed to default.
- The new workspace folder is given the specified project name, and contains configuration files at the top level.
-- By default, the files for a new initial application (with the same name as the workspace) are placed in the `src/` subfolder. Corresponding end-to-end tests are placed in the `e2e/` subfolder.
+- By default, the files for a new initial application (with the same name as the workspace) are placed in the `src/` subfolder.
- The new application's configuration appears in the `projects` section of the `angular.json` workspace configuration file, under its project name.
diff --git a/packages/angular/cli/commands/update-impl.ts b/packages/angular/cli/commands/update-impl.ts
index c0c461452bd0..23aca0a5861e 100644
--- a/packages/angular/cli/commands/update-impl.ts
+++ b/packages/angular/cli/commands/update-impl.ts
@@ -37,11 +37,6 @@ import {
} from '../utilities/package-tree';
import { Schema as UpdateCommandSchema } from './update';
-const NG_VERSION_9_POST_MSG = colors.cyan(
- '\nYour project has been updated to Angular version 9!\n' +
- 'For more info, please see: https://v9.angular.io/guide/updating-to-version-9',
-);
-
const UPDATE_SCHEMATIC_COLLECTION = path.join(
__dirname,
'../src/commands/update/schematic/collection.json',
@@ -57,6 +52,8 @@ const disableVersionCheck =
disableVersionCheckEnv !== '0' &&
disableVersionCheckEnv.toLowerCase() !== 'false';
+const ANGULAR_PACKAGES_REGEXP = /^@(?:angular|nguniversal)\//;
+
export class UpdateCommand extends Command {
public override readonly allowMissingWorkspace = true;
private workflow!: NodeWorkflow;
@@ -272,19 +269,26 @@ export class UpdateCommand extends Command {
async run(options: UpdateCommandSchema & Arguments) {
await ensureCompatibleNpm(this.context.root);
- // Check if the current installed CLI version is older than the latest version.
- if (!disableVersionCheck && (await this.checkCLILatestVersion(options.verbose, options.next))) {
- this.logger.warn(
- `The installed local Angular CLI version is older than the latest ${
- options.next ? 'pre-release' : 'stable'
- } version.\n` + 'Installing a temporary version to perform the update.',
+ // Check if the current installed CLI version is older than the latest compatible version.
+ if (!disableVersionCheck) {
+ const cliVersionToInstall = await this.checkCLIVersion(
+ options['--'],
+ options.verbose,
+ options.next,
);
- return runTempPackageBin(
- `@angular/cli@${options.next ? 'next' : 'latest'}`,
- this.packageManager,
- process.argv.slice(2),
- );
+ if (cliVersionToInstall) {
+ this.logger.warn(
+ 'The installed Angular CLI version is outdated.\n' +
+ `Installing a temporary Angular CLI versioned ${cliVersionToInstall} to perform the update.`,
+ );
+
+ return runTempPackageBin(
+ `@angular/cli@${cliVersionToInstall}`,
+ this.packageManager,
+ process.argv.slice(2),
+ );
+ }
}
const logVerbose = (message: string) => {
@@ -452,8 +456,7 @@ export class UpdateCommand extends Command {
if (migrations.startsWith('../')) {
this.logger.error(
- 'Package contains an invalid migrations field. ' +
- 'Paths outside the package root are not permitted.',
+ 'Package contains an invalid migrations field. Paths outside the package root are not permitted.',
);
return 1;
@@ -479,9 +482,9 @@ export class UpdateCommand extends Command {
}
}
- let success = false;
+ let result: boolean;
if (typeof options.migrateOnly == 'string') {
- success = await this.executeMigration(
+ result = await this.executeMigration(
packageName,
migrations,
options.migrateOnly,
@@ -495,7 +498,7 @@ export class UpdateCommand extends Command {
return 1;
}
- success = await this.executeMigrations(
+ result = await this.executeMigrations(
packageName,
migrations,
from,
@@ -504,20 +507,7 @@ export class UpdateCommand extends Command {
);
}
- if (success) {
- if (
- packageName === '@angular/core' &&
- options.from &&
- +options.from.split('.')[0] < 9 &&
- (options.to || packageNode.version).split('.')[0] === '9'
- ) {
- this.logger.info(NG_VERSION_9_POST_MSG);
- }
-
- return 0;
- }
-
- return 1;
+ return result ? 0 : 1;
}
const requests: {
@@ -612,7 +602,7 @@ export class UpdateCommand extends Command {
continue;
}
- if (node.package && /^@(?:angular|nguniversal)\//.test(node.package.name)) {
+ if (node.package && ANGULAR_PACKAGES_REGEXP.test(node.package.name)) {
const { name, version } = node.package;
const toBeInstalledMajorVersion = +manifest.version.split('.')[0];
const currentMajorVersion = +version.split('.')[0];
@@ -791,17 +781,6 @@ export class UpdateCommand extends Command {
return 0;
}
}
-
- if (
- migrations.some(
- (m) =>
- m.package === '@angular/core' &&
- m.to.split('.')[0] === '9' &&
- +m.from.split('.')[0] < 9,
- )
- ) {
- this.logger.info(NG_VERSION_9_POST_MSG);
- }
}
return success ? 0 : 1;
@@ -879,14 +858,16 @@ export class UpdateCommand extends Command {
}
/**
- * Checks if the current installed CLI version is older than the latest version.
- * @returns `true` when the installed version is older.
+ * Checks if the current installed CLI version is older or newer than a compatible version.
+ * @returns the version to install or null when there is no update to install.
*/
- private async checkCLILatestVersion(verbose = false, next = false): Promise {
- const installedCLIVersion = VERSION.full;
-
- const LatestCLIManifest = await fetchPackageManifest(
- `@angular/cli@${next ? 'next' : 'latest'}`,
+ private async checkCLIVersion(
+ packagesToUpdate: string[] | undefined,
+ verbose = false,
+ next = false,
+ ): Promise {
+ const { version } = await fetchPackageManifest(
+ `@angular/cli@${this.getCLIUpdateRunnerVersion(packagesToUpdate, next)}`,
this.logger,
{
verbose,
@@ -894,7 +875,38 @@ export class UpdateCommand extends Command {
},
);
- return semver.lt(installedCLIVersion, LatestCLIManifest.version);
+ return VERSION.full === version ? null : version;
+ }
+
+ private getCLIUpdateRunnerVersion(
+ packagesToUpdate: string[] | undefined,
+ next: boolean,
+ ): string | number {
+ if (next) {
+ return 'next';
+ }
+
+ const updatingAngularPackage = packagesToUpdate?.find((r) => ANGULAR_PACKAGES_REGEXP.test(r));
+ if (updatingAngularPackage) {
+ // If we are updating any Angular package we can update the CLI to the target version because
+ // migrations for @angular/core@13 can be executed using Angular/cli@13.
+ // This is same behaviour as `npx @angular/cli@13 update @angular/core@13`.
+
+ // `@angular/cli@13` -> ['', 'angular/cli', '13']
+ // `@angular/cli` -> ['', 'angular/cli']
+ const tempVersion = coerceVersionNumber(updatingAngularPackage.split('@')[2]);
+
+ return semver.parse(tempVersion)?.major ?? 'latest';
+ }
+
+ // When not updating an Angular package we cannot determine which schematic runtime the migration should to be executed in.
+ // Typically, we can assume that the `@angular/cli` was updated previously.
+ // Example: Angular official packages are typically updated prior to NGRX etc...
+ // Therefore, we only update to the latest patch version of the installed major version of the Angular CLI.
+
+ // This is important because we might end up in a scenario where locally Angular v12 is installed, updating NGRX from 11 to 12.
+ // We end up using Angular ClI v13 to run the migrations if we run the migrations using the CLI installed major version + 1 logic.
+ return VERSION.major;
}
}
diff --git a/packages/angular/cli/lib/init.ts b/packages/angular/cli/lib/init.ts
index a48f388ba3fe..cf18b8bcd77b 100644
--- a/packages/angular/cli/lib/init.ts
+++ b/packages/angular/cli/lib/init.ts
@@ -73,7 +73,11 @@ import { isWarningEnabled } from '../utilities/config';
if (isGlobalGreater) {
// If using the update command and the global version is greater, use the newer update command
// This allows improvements in update to be used in older versions that do not have bootstrapping
- if (process.argv[2] === 'update') {
+ if (
+ process.argv[2] === 'update' &&
+ cli.VERSION &&
+ cli.VERSION.major - globalVersion.major <= 1
+ ) {
cli = await import('./cli');
} else if (await isWarningEnabled('versionMismatch')) {
// Otherwise, use local version and warn if global is newer than local
diff --git a/packages/angular/pwa/BUILD.bazel b/packages/angular/pwa/BUILD.bazel
index 5b7a218b5c96..af8b44ce7f58 100644
--- a/packages/angular/pwa/BUILD.bazel
+++ b/packages/angular/pwa/BUILD.bazel
@@ -6,6 +6,8 @@
load("@npm//@bazel/jasmine:index.bzl", "jasmine_node_test")
load("//tools:defaults.bzl", "ts_library")
load("//tools:ts_json_schema.bzl", "ts_json_schema")
+load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar")
+load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
licenses(["notice"]) # MIT
@@ -67,3 +69,18 @@ jasmine_node_test(
name = "pwa_test",
srcs = [":pwa_test_lib"],
)
+
+pkg_npm(
+ name = "npm_package",
+ deps = [
+ ":pwa",
+ ],
+)
+
+pkg_tar(
+ name = "npm_package_archive",
+ srcs = [":npm_package"],
+ extension = "tar.gz",
+ strip_prefix = "./npm_package",
+ tags = ["manual"],
+)
diff --git a/packages/angular_devkit/architect_cli/BUILD.bazel b/packages/angular_devkit/architect_cli/BUILD.bazel
index 2381827d2753..3f846ec99627 100644
--- a/packages/angular_devkit/architect_cli/BUILD.bazel
+++ b/packages/angular_devkit/architect_cli/BUILD.bazel
@@ -1,4 +1,6 @@
load("//tools:defaults.bzl", "ts_library")
+load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar")
+load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
# Copyright Google Inc. All Rights Reserved.
#
@@ -27,3 +29,18 @@ ts_library(
"@npm//rxjs",
],
)
+
+pkg_npm(
+ name = "npm_package",
+ deps = [
+ ":architect_cli",
+ ],
+)
+
+pkg_tar(
+ name = "npm_package_archive",
+ srcs = [":npm_package"],
+ extension = "tar.gz",
+ strip_prefix = "./npm_package",
+ tags = ["manual"],
+)
diff --git a/packages/angular_devkit/build_angular/src/babel/webpack-loader.ts b/packages/angular_devkit/build_angular/src/babel/webpack-loader.ts
index eae472b33ccd..d74a9e753643 100644
--- a/packages/angular_devkit/build_angular/src/babel/webpack-loader.ts
+++ b/packages/angular_devkit/build_angular/src/babel/webpack-loader.ts
@@ -239,10 +239,16 @@ export default custom(() => {
// `@ampproject/remapping` source map objects but both are compatible with Webpack.
// This method for merging is used because it provides more accurate output
// and is faster while using less memory.
- result.map = remapping(
- [result.map as SourceMapInput, inputSourceMap as SourceMapInput],
- () => null,
- ) as typeof result.map;
+ result.map = {
+ // Convert the SourceMap back to simple plain object.
+ // This is needed because otherwise code-coverage will fail with `don't know how to turn this value into a node`
+ // Which is thrown by Babel if it is invoked again from `istanbul-lib-instrument`.
+ // https://github.com/babel/babel/blob/780aa48d2a34dc55f556843074b6aed45e7eabeb/packages/babel-types/src/converters/valueToNode.ts#L115-L130
+ ...(remapping(
+ [result.map as SourceMapInput, inputSourceMap as SourceMapInput],
+ () => null,
+ ) as typeof result.map),
+ };
}
return result;
diff --git a/packages/angular_devkit/build_angular/src/builders/extract-i18n/ivy-extract-loader.ts b/packages/angular_devkit/build_angular/src/builders/extract-i18n/ivy-extract-loader.ts
index 50da54cfe7b4..4a6353662761 100644
--- a/packages/angular_devkit/build_angular/src/builders/extract-i18n/ivy-extract-loader.ts
+++ b/packages/angular_devkit/build_angular/src/builders/extract-i18n/ivy-extract-loader.ts
@@ -21,6 +21,11 @@ export default function localizeExtractLoader(
content: string,
map: LoaderSourceMap,
) {
+ // This loader is not cacheable due to how message extraction works.
+ // Extracted messages are not part of webpack pipeline and hence they cannot be retrieved from cache.
+ // TODO: We should investigate in the future on making this deterministic and more cacheable.
+ this.cacheable(false);
+
const options = this.getOptions();
const callback = this.async();
diff --git a/packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/module-cjs_spec.ts b/packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/module-cjs_spec.ts
new file mode 100644
index 000000000000..fdd972cb169c
--- /dev/null
+++ b/packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/module-cjs_spec.ts
@@ -0,0 +1,31 @@
+/**
+ * @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 { execute } from '../../index';
+import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
+
+describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
+ describe('Behavior: "module commonjs"', () => {
+ it('should work when module is commonjs', async () => {
+ harness.useTarget('test', {
+ ...BASE_OPTIONS,
+ });
+
+ await harness.modifyFile('src/tsconfig.spec.json', (content) => {
+ const tsConfig = JSON.parse(content);
+ tsConfig.compilerOptions.module = 'commonjs';
+
+ return JSON.stringify(tsConfig);
+ });
+
+ const { result } = await harness.executeOnce();
+
+ expect(result?.success).toBeTrue();
+ });
+ });
+});
diff --git a/packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts b/packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts
index fdd2b66de90f..83d202cb4317 100644
--- a/packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts
+++ b/packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts
@@ -102,7 +102,7 @@ export function getWatchOptions(
): NonNullable {
return {
poll,
- ignored: poll === undefined ? '**/$_lazy_route_resources' : 'node_modules/**',
+ ignored: poll === undefined ? '**/$_lazy_route_resources' : '**/node_modules/**',
};
}
diff --git a/packages/angular_devkit/schematics_cli/BUILD.bazel b/packages/angular_devkit/schematics_cli/BUILD.bazel
index 1d2ccc908b91..43cc1cba03bc 100644
--- a/packages/angular_devkit/schematics_cli/BUILD.bazel
+++ b/packages/angular_devkit/schematics_cli/BUILD.bazel
@@ -1,6 +1,8 @@
load("@npm//@bazel/jasmine:index.bzl", "jasmine_node_test")
load("//tools:defaults.bzl", "ts_library")
load("//tools:ts_json_schema.bzl", "ts_json_schema")
+load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar")
+load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
# Copyright Google Inc. All Rights Reserved.
#
@@ -88,3 +90,18 @@ ts_json_schema(
name = "schematic_schema",
src = "schematic/schema.json",
)
+
+pkg_npm(
+ name = "npm_package",
+ deps = [
+ ":schematics_cli",
+ ],
+)
+
+pkg_tar(
+ name = "npm_package_archive",
+ srcs = [":npm_package"],
+ extension = "tar.gz",
+ strip_prefix = "./npm_package",
+ tags = ["manual"],
+)
diff --git a/packages/ngtools/webpack/src/loaders/direct-resource.ts b/packages/ngtools/webpack/src/loaders/direct-resource.ts
index b6f2a2cae111..5c5efda6c7c9 100644
--- a/packages/ngtools/webpack/src/loaders/direct-resource.ts
+++ b/packages/ngtools/webpack/src/loaders/direct-resource.ts
@@ -6,8 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
+import { LoaderContext } from 'webpack';
+
export const DirectAngularResourceLoaderPath = __filename;
-export default function (content: string) {
- return `export default ${JSON.stringify(content)};`;
+export default function (this: LoaderContext<{ esModule?: 'true' | 'false' }>, content: string) {
+ const { esModule } = this.getOptions();
+
+ return `${esModule === 'false' ? 'module.exports =' : 'export default'} ${JSON.stringify(
+ content,
+ )};`;
}
diff --git a/packages/ngtools/webpack/src/transformers/replace_resources.ts b/packages/ngtools/webpack/src/transformers/replace_resources.ts
index 9eba2512148b..a4f47c78c805 100644
--- a/packages/ngtools/webpack/src/transformers/replace_resources.ts
+++ b/packages/ngtools/webpack/src/transformers/replace_resources.ts
@@ -146,7 +146,7 @@ function visitComponentMetadata(
styleReplacements: ts.Expression[],
directTemplateLoading: boolean,
resourceImportDeclarations: ts.ImportDeclaration[],
- moduleKind?: ts.ModuleKind,
+ moduleKind: ts.ModuleKind = ts.ModuleKind.ES2015,
inlineStyleFileExtension?: string,
): ts.ObjectLiteralElementLike | undefined {
if (!ts.isPropertyAssignment(node) || ts.isComputedPropertyName(node.name)) {
@@ -159,9 +159,10 @@ function visitComponentMetadata(
return undefined;
case 'templateUrl':
+ const loaderOptions = moduleKind < ts.ModuleKind.ES2015 ? '?esModule=false' : '';
const url = getResourceUrl(
node.initializer,
- directTemplateLoading ? `!${DirectAngularResourceLoaderPath}!` : '',
+ directTemplateLoading ? `!${DirectAngularResourceLoaderPath}${loaderOptions}!` : '',
);
if (!url) {
return node;
@@ -255,14 +256,15 @@ function createResourceImport(
nodeFactory: ts.NodeFactory,
url: string,
resourceImportDeclarations: ts.ImportDeclaration[],
- moduleKind = ts.ModuleKind.ES2015,
+ moduleKind: ts.ModuleKind,
): ts.Identifier | ts.Expression {
const urlLiteral = nodeFactory.createStringLiteral(url);
if (moduleKind < ts.ModuleKind.ES2015) {
- return nodeFactory.createPropertyAccessExpression(
- nodeFactory.createCallExpression(nodeFactory.createIdentifier('require'), [], [urlLiteral]),
- 'default',
+ return nodeFactory.createCallExpression(
+ nodeFactory.createIdentifier('require'),
+ [],
+ [urlLiteral],
);
} else {
const importName = nodeFactory.createIdentifier(
diff --git a/packages/ngtools/webpack/src/transformers/replace_resources_spec.ts b/packages/ngtools/webpack/src/transformers/replace_resources_spec.ts
index 59d554c6748b..0f09e6f7283a 100644
--- a/packages/ngtools/webpack/src/transformers/replace_resources_spec.ts
+++ b/packages/ngtools/webpack/src/transformers/replace_resources_spec.ts
@@ -102,8 +102,8 @@ describe('@ngtools/webpack transformers', () => {
AppComponent = (0, tslib_1.__decorate)([
(0, core_1.Component)({
selector: 'app-root',
- template: require("!${DirectAngularResourceLoaderPath}!./app.component.html").default,
- styles: [require("./app.component.css").default, require("./app.component.2.css").default] }) ], AppComponent);
+ template: require("!${DirectAngularResourceLoaderPath}?esModule=false!./app.component.html"),
+ styles: [require("./app.component.css"), require("./app.component.2.css")] }) ], AppComponent);
exports.AppComponent = AppComponent;
`;
diff --git a/packages/schematics/angular/application/files/src/test.ts.template b/packages/schematics/angular/application/files/src/test.ts.template
index 598d11e862e6..00025daf1720 100644
--- a/packages/schematics/angular/application/files/src/test.ts.template
+++ b/packages/schematics/angular/application/files/src/test.ts.template
@@ -9,8 +9,8 @@ import {
declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): {
- keys(): string[];
(id: string): T;
+ keys(): string[];
};
};
diff --git a/packages/schematics/angular/library/files/src/test.ts.template b/packages/schematics/angular/library/files/src/test.ts.template
index 9782baeeef23..bcca659d3122 100644
--- a/packages/schematics/angular/library/files/src/test.ts.template
+++ b/packages/schematics/angular/library/files/src/test.ts.template
@@ -10,8 +10,8 @@ import {
declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): {
- keys(): string[];
(id: string): T;
+ keys(): string[];
};
};
diff --git a/tests/legacy-cli/e2e/tests/i18n/extract-ivy-disk-cache.ts b/tests/legacy-cli/e2e/tests/i18n/extract-ivy-disk-cache.ts
new file mode 100644
index 000000000000..61a2f48e62f5
--- /dev/null
+++ b/tests/legacy-cli/e2e/tests/i18n/extract-ivy-disk-cache.ts
@@ -0,0 +1,36 @@
+import { join } from 'path';
+import { getGlobalVariable } from '../../utils/env';
+import { expectFileToMatch, rimraf, writeFile } from '../../utils/fs';
+import { installPackage, uninstallPackage } from '../../utils/packages';
+import { ng } from '../../utils/process';
+import { updateJsonFile } from '../../utils/project';
+import { readNgVersion } from '../../utils/version';
+
+export default async function () {
+ // Enable disk cache
+ updateJsonFile('angular.json', (config) => {
+ config.cli ??= {};
+ config.cli.cache = { environment: 'all' };
+ });
+
+ // Setup an i18n enabled component
+ await ng('generate', 'component', 'i18n-test');
+ await writeFile(join('src/app/i18n-test', 'i18n-test.component.html'), 'Hello world
');
+
+ // Install correct version
+ let localizeVersion = '@angular/localize@' + readNgVersion();
+ if (getGlobalVariable('argv')['ng-snapshots']) {
+ localizeVersion = require('../../ng-snapshot/package.json').dependencies['@angular/localize'];
+ }
+
+ await installPackage(localizeVersion);
+
+ for (let i = 0; i < 2; i++) {
+ // Run the extraction twice and make sure the second time round works with cache.
+ await rimraf('messages.xlf');
+ await ng('extract-i18n');
+ await expectFileToMatch('messages.xlf', 'Hello world');
+ }
+
+ await uninstallPackage('@angular/localize');
+}
diff --git a/tests/legacy-cli/e2e/tests/i18n/extract-ivy.ts b/tests/legacy-cli/e2e/tests/i18n/extract-ivy.ts
index 3693481d5ede..9c796f896c01 100644
--- a/tests/legacy-cli/e2e/tests/i18n/extract-ivy.ts
+++ b/tests/legacy-cli/e2e/tests/i18n/extract-ivy.ts
@@ -1,6 +1,6 @@
import { join } from 'path';
import { getGlobalVariable } from '../../utils/env';
-import { writeFile } from '../../utils/fs';
+import { expectFileToMatch, writeFile } from '../../utils/fs';
import { installPackage, uninstallPackage } from '../../utils/packages';
import { ng } from '../../utils/process';
import { updateJsonFile } from '../../utils/project';
@@ -31,5 +31,7 @@ export default async function () {
throw new Error('Expected no warnings to be shown');
}
+ expectFileToMatch('messages.xlf', 'Hello world');
+
await uninstallPackage('@angular/localize');
}
diff --git a/tests/legacy-cli/e2e/tests/misc/npm-7.ts b/tests/legacy-cli/e2e/tests/misc/npm-7.ts
index c2bff8ad9d34..1789210a534a 100644
--- a/tests/legacy-cli/e2e/tests/misc/npm-7.ts
+++ b/tests/legacy-cli/e2e/tests/misc/npm-7.ts
@@ -1,11 +1,12 @@
-import { rimraf, writeFile } from '../../utils/fs';
+import { rimraf } from '../../utils/fs';
import { getActivePackageManager } from '../../utils/packages';
import { ng, npm } from '../../utils/process';
+import { isPrereleaseCli } from '../../utils/project';
import { expectToFail } from '../../utils/utils';
const warningText = 'npm version 7.5.6 or higher is recommended';
-export default async function() {
+export default async function () {
// Only relevant with npm as a package manager
if (getActivePackageManager() !== 'npm') {
return;
@@ -17,12 +18,18 @@ export default async function() {
}
const currentDirectory = process.cwd();
+
+ const extraArgs = [];
+ if (isPrereleaseCli()) {
+ extraArgs.push('--next');
+ }
+
try {
// Install version >=7.5.6
await npm('install', '--global', 'npm@>=7.5.6');
// Ensure `ng update` does not show npm warning
- const { stderr: stderrUpdate1 } = await ng('update');
+ const { stderr: stderrUpdate1 } = await ng('update', ...extraArgs);
if (stderrUpdate1.includes(warningText)) {
throw new Error('ng update expected to not show npm version warning.');
}
@@ -37,7 +44,7 @@ export default async function() {
}
// Ensure `ng update` shows npm warning
- const { stderr: stderrUpdate2 } = await ng('update');
+ const { stderr: stderrUpdate2 } = await ng('update', ...extraArgs);
if (!stderrUpdate2.includes(warningText)) {
throw new Error('ng update expected to show npm version warning.');
}
@@ -85,5 +92,4 @@ export default async function() {
// Reset version back to 6.x
await npm('install', '--global', 'npm@6');
}
-
}
diff --git a/tests/legacy-cli/e2e/tests/update/update-secure-registry.ts b/tests/legacy-cli/e2e/tests/update/update-secure-registry.ts
index 263892d1d01b..f6f7621ffc9a 100644
--- a/tests/legacy-cli/e2e/tests/update/update-secure-registry.ts
+++ b/tests/legacy-cli/e2e/tests/update/update-secure-registry.ts
@@ -1,29 +1,35 @@
import { ng } from '../../utils/process';
import { createNpmConfigForAuthentication } from '../../utils/registry';
import { expectToFail } from '../../utils/utils';
+import { isPrereleaseCli } from '../../utils/project';
export default async function () {
// The environment variable has priority over the .npmrc
delete process.env['NPM_CONFIG_REGISTRY'];
const worksMessage = 'We analyzed your package.json';
+ const extraArgs = [];
+ if (isPrereleaseCli()) {
+ extraArgs.push('--next');
+ }
+
// Valid authentication token
await createNpmConfigForAuthentication(false);
- const { stdout: stdout1 } = await ng('update');
+ const { stdout: stdout1 } = await ng('update', ...extraArgs);
if (!stdout1.includes(worksMessage)) {
throw new Error(`Expected stdout to contain "${worksMessage}"`);
}
await createNpmConfigForAuthentication(true);
- const { stdout: stdout2 } = await ng('update');
+ const { stdout: stdout2 } = await ng('update', ...extraArgs);
if (!stdout2.includes(worksMessage)) {
throw new Error(`Expected stdout to contain "${worksMessage}"`);
}
// Invalid authentication token
await createNpmConfigForAuthentication(false, true);
- await expectToFail(() => ng('update'));
+ await expectToFail(() => ng('update', ...extraArgs));
await createNpmConfigForAuthentication(true, true);
- await expectToFail(() => ng('update'));
+ await expectToFail(() => ng('update', ...extraArgs));
}