test(localize): ensure tests pass on Windows (#40952)
These tests were relying upon unix-like paths, which caused them to fail on Windows. Note that the `filegroup` Bazel rule tends not to work well on Windows, so this has been replaced with `copy_to_bin` instead. PR Close #40952
This commit is contained in:
parent
5ae28a4aa4
commit
51a79772b2
|
@ -35,7 +35,7 @@ export function makeEs5ExtractPlugin(
|
|||
// If we get a BabelParseError here then something went wrong with Babel itself
|
||||
// since there must be something wrong with the structure of the AST generated
|
||||
// by Babel parsing a TaggedTemplateExpression.
|
||||
throw buildCodeFrameError(callPath, e);
|
||||
throw buildCodeFrameError(fs, callPath, e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 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 {AbsoluteFsPath, getFileSystem, PathManipulation} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {absoluteFrom, AbsoluteFsPath, getFileSystem, PathManipulation} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {ɵisMissingTranslationError, ɵmakeTemplateObject, ɵParsedTranslation, ɵSourceLocation, ɵtranslate} from '@angular/localize';
|
||||
import {NodePath} from '@babel/traverse';
|
||||
import * as t from '@babel/types';
|
||||
|
@ -400,8 +400,19 @@ export function isBabelParseError(e: any): e is BabelParseError {
|
|||
return e.type === 'BabelParseError';
|
||||
}
|
||||
|
||||
export function buildCodeFrameError(path: NodePath, e: BabelParseError): string {
|
||||
const filename = path.hub.file.opts.filename || '(unknown file)';
|
||||
export function buildCodeFrameError(
|
||||
fs: PathManipulation, path: NodePath, e: BabelParseError): string {
|
||||
let filename = path.hub.file.opts.filename;
|
||||
if (filename) {
|
||||
filename = fs.resolve(filename);
|
||||
let cwd = path.hub.file.opts.cwd;
|
||||
if (cwd) {
|
||||
cwd = fs.resolve(cwd);
|
||||
filename = fs.relative(cwd, filename);
|
||||
}
|
||||
} else {
|
||||
filename = '(unknown file)';
|
||||
}
|
||||
const message = path.hub.file.buildCodeFrameError(e.node, e.message).message;
|
||||
return `${filename}: ${message}`;
|
||||
}
|
||||
|
@ -434,9 +445,14 @@ export function serializeLocationPosition(location: ɵSourceLocation): string {
|
|||
|
||||
function getFileFromPath(fs: PathManipulation, path: NodePath|undefined): AbsoluteFsPath|null {
|
||||
const opts = path?.hub.file.opts;
|
||||
return opts?.filename ?
|
||||
fs.resolve(opts.generatorOpts.sourceRoot ?? opts.cwd, fs.relative(opts.cwd, opts.filename)) :
|
||||
null;
|
||||
const filename = opts?.filename;
|
||||
if (!filename) {
|
||||
return null;
|
||||
}
|
||||
const relativePath = fs.relative(opts.cwd, filename);
|
||||
const root = opts.generatorOpts.sourceRoot ?? opts.cwd;
|
||||
const absPath = fs.resolve(root, relativePath);
|
||||
return absPath;
|
||||
}
|
||||
|
||||
function getLineAndColumn(loc: {line: number, column: number}): {line: number, column: number} {
|
||||
|
|
|
@ -105,7 +105,7 @@ if (require.main === module) {
|
|||
const sourceRootPath = options.r;
|
||||
const sourceFilePaths = glob.sync(options.s, {cwd: sourceRootPath, nodir: true});
|
||||
const translationFilePaths: (string|string[])[] = convertArraysFromArgs(options.t);
|
||||
const outputPathFn = getOutputPathFn(fs.resolve(options.o));
|
||||
const outputPathFn = getOutputPathFn(fs, fs.resolve(options.o));
|
||||
const diagnostics = new Diagnostics();
|
||||
const missingTranslation = options.m as DiagnosticHandlingStrategy;
|
||||
const duplicateTranslation = options.d as DiagnosticHandlingStrategy;
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
* 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 {AbsoluteFsPath} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {join} from 'path';
|
||||
import {AbsoluteFsPath, PathManipulation} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
|
||||
/**
|
||||
* A function that will return an absolute path to where a file is to be written, given a locale and
|
||||
|
@ -23,8 +22,8 @@ export interface OutputPathFn {
|
|||
* The special `{{LOCALE}}` marker will be replaced with the locale code of the current translation.
|
||||
* @param outputFolder An absolute path to the folder containing this set of translations.
|
||||
*/
|
||||
export function getOutputPathFn(outputFolder: AbsoluteFsPath): OutputPathFn {
|
||||
export function getOutputPathFn(fs: PathManipulation, outputFolder: AbsoluteFsPath): OutputPathFn {
|
||||
const [pre, post] = outputFolder.split('{{LOCALE}}');
|
||||
return post === undefined ? (_locale, relativePath) => join(pre, relativePath) :
|
||||
(locale, relativePath) => join(pre + locale + post, relativePath);
|
||||
return post === undefined ? (_locale, relativePath) => fs.join(pre, relativePath) :
|
||||
(locale, relativePath) => fs.join(pre + locale + post, relativePath);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export function makeEs2015TranslatePlugin(
|
|||
// If we get a BabelParseError here then something went wrong with Babel itself
|
||||
// since there must be something wrong with the structure of the AST generated
|
||||
// by Babel parsing a TaggedTemplateExpression.
|
||||
throw buildCodeFrameError(path, e);
|
||||
throw buildCodeFrameError(fs, path, e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export function makeEs5TranslatePlugin(
|
|||
}
|
||||
} catch (e) {
|
||||
if (isBabelParseError(e)) {
|
||||
diagnostics.error(buildCodeFrameError(callPath, e));
|
||||
diagnostics.error(buildCodeFrameError(fs, callPath, e));
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ export class SourceFileTranslationHandler implements TranslationHandler {
|
|||
makeEs2015TranslatePlugin(diagnostics, translationBundle.translations, options, this.fs),
|
||||
makeEs5TranslatePlugin(diagnostics, translationBundle.translations, options, this.fs),
|
||||
],
|
||||
cwd: sourceRoot,
|
||||
filename,
|
||||
});
|
||||
if (translated && translated.code) {
|
||||
|
|
|
@ -15,6 +15,7 @@ ts_library(
|
|||
"//packages/compiler-cli/src/ngtsc/logging/testing",
|
||||
"//packages/localize",
|
||||
"//packages/localize/src/tools",
|
||||
"//packages/localize/src/tools/test/helpers",
|
||||
"//packages/localize/src/utils",
|
||||
"@npm//@babel/core",
|
||||
"@npm//@babel/generator",
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
* 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 {absoluteFrom, getFileSystem, relativeFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
import {absoluteFrom, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {MockLogger} from '@angular/compiler-cli/src/ngtsc/logging/testing';
|
||||
|
||||
import {MessageExtractor} from '../../src/extract/extraction';
|
||||
import {runInNativeFileSystem} from '../helpers';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
runInNativeFileSystem(() => {
|
||||
describe('extractMessages', () => {
|
||||
it('should extract a message for each $localize template tag', () => {
|
||||
const fs = getFileSystem();
|
||||
|
@ -20,7 +20,7 @@ runInEachFileSystem(() => {
|
|||
const filename = 'relative/path.js';
|
||||
const file = fs.resolve(basePath, filename);
|
||||
const extractor = new MessageExtractor(fs, logger, {basePath});
|
||||
fs.ensureDir(absoluteFrom('/root/path/relative'));
|
||||
fs.ensureDir(fs.dirname(file));
|
||||
fs.writeFile(file, [
|
||||
'$localize`:meaning|description:a${1}b${2}c`;',
|
||||
'$localize(__makeTemplateObject(["a", ":custom-placeholder:b", "c"], ["a", ":custom-placeholder:b", "c"]), 1, 2);',
|
||||
|
@ -40,19 +40,19 @@ runInEachFileSystem(() => {
|
|||
{
|
||||
start: {line: 0, column: 10},
|
||||
end: {line: 0, column: 32},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
file,
|
||||
text: ':meaning|description:a',
|
||||
},
|
||||
{
|
||||
start: {line: 0, column: 36},
|
||||
end: {line: 0, column: 37},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
file,
|
||||
text: 'b',
|
||||
},
|
||||
{
|
||||
start: {line: 0, column: 41},
|
||||
end: {line: 0, column: 42},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
file,
|
||||
text: 'c',
|
||||
}
|
||||
],
|
||||
|
@ -60,18 +60,8 @@ runInEachFileSystem(() => {
|
|||
placeholderNames: ['PH', 'PH_1'],
|
||||
substitutions: jasmine.any(Object),
|
||||
substitutionLocations: {
|
||||
PH: {
|
||||
start: {line: 0, column: 34},
|
||||
end: {line: 0, column: 35},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: '1'
|
||||
},
|
||||
PH_1: {
|
||||
start: {line: 0, column: 39},
|
||||
end: {line: 0, column: 40},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: '2'
|
||||
}
|
||||
PH: {start: {line: 0, column: 34}, end: {line: 0, column: 35}, file, text: '1'},
|
||||
PH_1: {start: {line: 0, column: 39}, end: {line: 0, column: 40}, file, text: '2'}
|
||||
},
|
||||
legacyIds: [],
|
||||
location: {
|
||||
|
@ -92,19 +82,19 @@ runInEachFileSystem(() => {
|
|||
{
|
||||
start: {line: 1, column: 69},
|
||||
end: {line: 1, column: 72},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
file,
|
||||
text: '"a"',
|
||||
},
|
||||
{
|
||||
start: {line: 1, column: 74},
|
||||
end: {line: 1, column: 97},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
file,
|
||||
text: '":custom-placeholder:b"',
|
||||
},
|
||||
{
|
||||
start: {line: 1, column: 99},
|
||||
end: {line: 1, column: 102},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
file,
|
||||
text: '"c"',
|
||||
}
|
||||
],
|
||||
|
@ -112,18 +102,9 @@ runInEachFileSystem(() => {
|
|||
placeholderNames: ['custom-placeholder', 'PH_1'],
|
||||
substitutions: jasmine.any(Object),
|
||||
substitutionLocations: {
|
||||
'custom-placeholder': {
|
||||
start: {line: 1, column: 106},
|
||||
end: {line: 1, column: 107},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: '1'
|
||||
},
|
||||
PH_1: {
|
||||
start: {line: 1, column: 109},
|
||||
end: {line: 1, column: 110},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: '2'
|
||||
}
|
||||
'custom-placeholder':
|
||||
{start: {line: 1, column: 106}, end: {line: 1, column: 107}, file, text: '1'},
|
||||
PH_1: {start: {line: 1, column: 109}, end: {line: 1, column: 110}, file, text: '2'}
|
||||
},
|
||||
legacyIds: [],
|
||||
location: {
|
||||
|
@ -145,38 +126,13 @@ runInEachFileSystem(() => {
|
|||
placeholderNames: ['PH', 'PH_1'],
|
||||
substitutions: jasmine.any(Object),
|
||||
substitutionLocations: {
|
||||
PH: {
|
||||
start: {line: 2, column: 26},
|
||||
end: {line: 2, column: 27},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: '1'
|
||||
},
|
||||
PH_1: {
|
||||
start: {line: 2, column: 31},
|
||||
end: {line: 2, column: 32},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: '2'
|
||||
}
|
||||
PH: {start: {line: 2, column: 26}, end: {line: 2, column: 27}, file, text: '1'},
|
||||
PH_1: {start: {line: 2, column: 31}, end: {line: 2, column: 32}, file, text: '2'}
|
||||
},
|
||||
messagePartLocations: [
|
||||
{
|
||||
start: {line: 2, column: 10},
|
||||
end: {line: 2, column: 24},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: ':@@custom-id:a'
|
||||
},
|
||||
{
|
||||
start: {line: 2, column: 28},
|
||||
end: {line: 2, column: 29},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: 'b'
|
||||
},
|
||||
{
|
||||
start: {line: 2, column: 33},
|
||||
end: {line: 2, column: 34},
|
||||
file: absoluteFrom('/root/path/relative/path.js'),
|
||||
text: 'c'
|
||||
}
|
||||
{start: {line: 2, column: 10}, end: {line: 2, column: 24}, file, text: ':@@custom-id:a'},
|
||||
{start: {line: 2, column: 28}, end: {line: 2, column: 29}, file, text: 'b'},
|
||||
{start: {line: 2, column: 33}, end: {line: 2, column: 34}, file, text: 'c'}
|
||||
],
|
||||
legacyIds: [],
|
||||
location: {
|
||||
|
|
|
@ -15,6 +15,7 @@ ts_library(
|
|||
"//packages/compiler-cli/src/ngtsc/testing",
|
||||
"//packages/localize/src/tools",
|
||||
"//packages/localize/src/tools/test:test_lib",
|
||||
"//packages/localize/src/tools/test/helpers",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
*/
|
||||
import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, setFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {InvalidFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/src/invalid_file_system';
|
||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
import {MockLogger} from '@angular/compiler-cli/src/ngtsc/logging/testing';
|
||||
import {loadTestDirectory} from '@angular/compiler-cli/src/ngtsc/testing';
|
||||
|
||||
import {extractTranslations} from '../../../src/extract/main';
|
||||
import {FormatOptions} from '../../../src/extract/translation_files/format_options';
|
||||
import {runInNativeFileSystem} from '../../helpers';
|
||||
import {toAttributes} from '../translation_files/utils';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
runInNativeFileSystem(() => {
|
||||
let fs: FileSystem;
|
||||
let logger: MockLogger;
|
||||
let rootPath: AbsoluteFsPath;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package(default_visibility = ["//packages/localize/src/tools/test/extract/integration:__pkg__"])
|
||||
|
||||
load("@npm//typescript:index.bzl", "tsc")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
|
||||
|
||||
tsc(
|
||||
name = "compile_es5",
|
||||
|
@ -44,7 +45,8 @@ tsc(
|
|||
data = glob(["src/*.ts"]),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
# Use copy_to_bin since filegroup doesn't seem to work on Windows.
|
||||
copy_to_bin(
|
||||
name = "test_files",
|
||||
srcs = glob([
|
||||
"**/*.js",
|
||||
|
|
|
@ -6,30 +6,42 @@
|
|||
* 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 {getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
import {FileSystem, getFileSystem, PathSegment, relativeFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {ɵParsedMessage} from '@angular/localize/private';
|
||||
import {transformSync} from '@babel/core';
|
||||
|
||||
import {makeEs5ExtractPlugin} from '../../../src/extract/source_files/es5_extract_plugin';
|
||||
import {runInNativeFileSystem} from '../../helpers';
|
||||
|
||||
runInNativeFileSystem(() => {
|
||||
let fs: FileSystem;
|
||||
let testPath: PathSegment;
|
||||
|
||||
beforeEach(() => {
|
||||
fs = getFileSystem();
|
||||
testPath = relativeFrom('app/dist/test.js');
|
||||
});
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('makeEs5ExtractPlugin()', () => {
|
||||
it('should error with code-frame information if the first argument to `$localize` is not an array',
|
||||
() => {
|
||||
const input = '$localize(null, [])';
|
||||
expect(() => transformCode(input))
|
||||
.toThrowError(
|
||||
'Cannot create property \'message\' on string \'/app/dist/test.js: Unexpected messageParts for `$localize` (expected an array of strings).\n' +
|
||||
`Cannot create property 'message' on string '${testPath}: ` +
|
||||
'Unexpected messageParts for `$localize` (expected an array of strings).\n' +
|
||||
'> 1 | $localize(null, [])\n' +
|
||||
' | ^^^^\'');
|
||||
});
|
||||
|
||||
function transformCode(input: string): ɵParsedMessage[] {
|
||||
const messages: ɵParsedMessage[] = [];
|
||||
const cwd = fs.resolve('/');
|
||||
const filename = fs.resolve(cwd, testPath);
|
||||
transformSync(input, {
|
||||
plugins: [makeEs5ExtractPlugin(getFileSystem(), messages)],
|
||||
filename: '/app/dist/test.js'
|
||||
filename,
|
||||
cwd,
|
||||
})!.code!;
|
||||
return messages;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "helpers",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
["**/*.ts"],
|
||||
),
|
||||
visibility = ["//packages/localize/src/tools/test:__subpackages__"],
|
||||
deps = [
|
||||
"//packages/compiler-cli/src/ngtsc/file_system",
|
||||
"//packages/compiler-cli/src/ngtsc/file_system/testing",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @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 {setFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {InvalidFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/src/invalid_file_system';
|
||||
import {MockFileSystemNative} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
|
||||
/**
|
||||
* Only run these tests on the "native" file-system.
|
||||
*
|
||||
* Babel uses the `path.resolve()` function internally, which makes it very hard to mock out the
|
||||
* file-system from the outside. We run these tests on Unix and Windows in our CI jobs, so there is
|
||||
* test coverage.
|
||||
*/
|
||||
export function runInNativeFileSystem(callback: () => void) {
|
||||
describe(`<<FileSystem: Native>>`, () => {
|
||||
beforeEach(() => setFileSystem(new MockFileSystemNative()));
|
||||
afterEach(() => setFileSystem(new InvalidFileSystem()));
|
||||
callback();
|
||||
});
|
||||
}
|
|
@ -6,16 +6,16 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {absoluteFrom, getFileSystem, PathManipulation} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
import {ɵmakeTemplateObject} from '@angular/localize';
|
||||
import {NodePath, TransformOptions, transformSync} from '@babel/core';
|
||||
import generate from '@babel/generator';
|
||||
|
||||
import template from '@babel/template';
|
||||
import {Expression, Identifier, TaggedTemplateExpression, ExpressionStatement, CallExpression, isParenthesizedExpression, numericLiteral, binaryExpression, NumericLiteral} from '@babel/types';
|
||||
import {isGlobalIdentifier, isNamedIdentifier, isStringLiteralArray, isArrayOfExpressions, unwrapStringLiteralArray, unwrapMessagePartsFromLocalizeCall, wrapInParensIfNecessary, buildLocalizeReplacement, unwrapSubstitutionsFromLocalizeCall, unwrapMessagePartsFromTemplateLiteral, getLocation} from '../src/source_file_utils';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
import {isGlobalIdentifier, isNamedIdentifier, isStringLiteralArray, isArrayOfExpressions, unwrapStringLiteralArray, unwrapMessagePartsFromLocalizeCall, wrapInParensIfNecessary, buildLocalizeReplacement, unwrapSubstitutionsFromLocalizeCall, unwrapMessagePartsFromTemplateLiteral, getLocation} from '../src/source_file_utils';
|
||||
import {runInNativeFileSystem} from './helpers';
|
||||
|
||||
runInNativeFileSystem(() => {
|
||||
let fs: PathManipulation;
|
||||
beforeEach(() => fs = getFileSystem());
|
||||
describe('utils', () => {
|
||||
|
@ -414,7 +414,7 @@ runInEachFileSystem(() => {
|
|||
it('should return a plain object containing the start, end and file of a NodePath', () => {
|
||||
const taggedTemplate = getTaggedTemplate('const x = $localize `message`;', {
|
||||
filename: 'src/test.js',
|
||||
sourceRoot: '/root',
|
||||
sourceRoot: fs.resolve('/project'),
|
||||
});
|
||||
const location = getLocation(fs, taggedTemplate)!;
|
||||
expect(location).toBeDefined();
|
||||
|
@ -422,12 +422,12 @@ runInEachFileSystem(() => {
|
|||
expect(location.start.constructor.name).toEqual('Object');
|
||||
expect(location.end).toEqual({line: 0, column: 29});
|
||||
expect(location.end?.constructor.name).toEqual('Object');
|
||||
expect(location.file).toEqual(absoluteFrom('/root/src/test.js'));
|
||||
expect(location.file).toEqual(fs.resolve('/project/src/test.js'));
|
||||
});
|
||||
|
||||
it('should return `undefined` if the NodePath has no filename', () => {
|
||||
const taggedTemplate = getTaggedTemplate(
|
||||
'const x = $localize ``;', {sourceRoot: '/root', filename: undefined});
|
||||
'const x = $localize ``;', {sourceRoot: fs.resolve('/project'), filename: undefined});
|
||||
const location = getLocation(fs, taggedTemplate);
|
||||
expect(location).toBeUndefined();
|
||||
});
|
||||
|
@ -451,7 +451,8 @@ function getExpressions<T extends Expression>(
|
|||
const expressions: NodePath<Expression>[] = [];
|
||||
transformSync(code, {
|
||||
code: false,
|
||||
filename: '/test/file.js',
|
||||
filename: 'test/file.js',
|
||||
cwd: '/',
|
||||
plugins: [{
|
||||
visitor: {
|
||||
Expression: (path: NodePath<Expression>) => {
|
||||
|
@ -468,7 +469,8 @@ function getLocalizeCall(code: string): NodePath<CallExpression> {
|
|||
let callPaths: NodePath<CallExpression>[] = [];
|
||||
transformSync(code, {
|
||||
code: false,
|
||||
filename: '/test/file.js',
|
||||
filename: 'test/file.js',
|
||||
cwd: '/',
|
||||
plugins: [{
|
||||
visitor: {
|
||||
CallExpression(path) {
|
||||
|
|
|
@ -23,7 +23,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
beforeEach(() => {
|
||||
fs = getFileSystem();
|
||||
rootPath = absoluteFrom('/root/path');
|
||||
rootPath = absoluteFrom('/src/path');
|
||||
filePath = relativeFrom('relative/path');
|
||||
enTranslationPath = absoluteFrom('/translations/en/relative/path');
|
||||
enUSTranslationPath = absoluteFrom('/translations/en-US/relative/path');
|
||||
|
|
|
@ -12,18 +12,17 @@ ts_library(
|
|||
"//packages/compiler-cli/src/ngtsc/file_system/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/testing",
|
||||
"//packages/localize/src/tools",
|
||||
"//packages/localize/src/tools/test/helpers",
|
||||
],
|
||||
)
|
||||
|
||||
jasmine_node_test(
|
||||
name = "integration",
|
||||
bootstrap = ["//tools/testing:node_no_angular_es5"],
|
||||
data = glob(
|
||||
[
|
||||
"locales/**",
|
||||
"test_files/**",
|
||||
],
|
||||
),
|
||||
data = [
|
||||
"//packages/localize/src/tools/test/translate/integration/locales",
|
||||
"//packages/localize/src/tools/test/translate/integration/test_files",
|
||||
],
|
||||
deps = [
|
||||
":test_lib",
|
||||
"@npm//glob",
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package(default_visibility = ["//packages/localize/src/tools/test/translate/integration:__pkg__"])
|
||||
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
|
||||
|
||||
# Use copy_to_bin since filegroup doesn't seem to work on Windows.
|
||||
copy_to_bin(
|
||||
name = "locales",
|
||||
srcs = glob([
|
||||
"**/*.json",
|
||||
"**/*.xlf",
|
||||
"**/*.xtb",
|
||||
]),
|
||||
)
|
|
@ -6,15 +6,15 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
import {loadTestDirectory} from '@angular/compiler-cli/src/ngtsc/testing';
|
||||
import {resolve as realResolve} from 'path';
|
||||
|
||||
import {Diagnostics} from '../../../src/diagnostics';
|
||||
import {translateFiles} from '../../../src/translate/main';
|
||||
import {getOutputPathFn} from '../../../src/translate/output_path';
|
||||
import {runInNativeFileSystem} from '../../helpers';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
runInNativeFileSystem(() => {
|
||||
describe('translateFiles()', () => {
|
||||
let fs: FileSystem;
|
||||
let testDir: AbsoluteFsPath;
|
||||
|
@ -33,7 +33,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
it('should copy non-code files to the destination folders', () => {
|
||||
const diagnostics = new Diagnostics();
|
||||
const outputPathFn = getOutputPathFn(fs.resolve(testDir, '{{LOCALE}}'));
|
||||
const outputPathFn = getOutputPathFn(fs, fs.resolve(testDir, '{{LOCALE}}'));
|
||||
translateFiles({
|
||||
sourceRootPath: testFilesDir,
|
||||
sourceFilePaths: ['test-1.txt', 'test-2.txt'],
|
||||
|
@ -69,7 +69,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
it('should translate and copy source-code files to the destination folders', () => {
|
||||
const diagnostics = new Diagnostics();
|
||||
const outputPathFn = getOutputPathFn(fs.resolve(testDir, '{{LOCALE}}'));
|
||||
const outputPathFn = getOutputPathFn(fs, fs.resolve(testDir, '{{LOCALE}}'));
|
||||
translateFiles({
|
||||
sourceRootPath: testFilesDir,
|
||||
sourceFilePaths: ['test.js'],
|
||||
|
@ -97,7 +97,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
it('should translate and copy source-code files overriding the locales', () => {
|
||||
const diagnostics = new Diagnostics();
|
||||
const outputPathFn = getOutputPathFn(fs.resolve(testDir, '{{LOCALE}}'));
|
||||
const outputPathFn = getOutputPathFn(fs, fs.resolve(testDir, '{{LOCALE}}'));
|
||||
translateFiles({
|
||||
sourceRootPath: testFilesDir,
|
||||
sourceFilePaths: ['test.js'],
|
||||
|
@ -131,7 +131,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
it('should merge translation files, if more than one provided, and translate source-code', () => {
|
||||
const diagnostics = new Diagnostics();
|
||||
const outputPathFn = getOutputPathFn(fs.resolve(testDir, '{{LOCALE}}'));
|
||||
const outputPathFn = getOutputPathFn(fs, fs.resolve(testDir, '{{LOCALE}}'));
|
||||
translateFiles({
|
||||
sourceRootPath: testFilesDir,
|
||||
sourceFilePaths: ['test-extra.js'],
|
||||
|
@ -165,7 +165,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
it('should transform and/or copy files to the destination folders', () => {
|
||||
const diagnostics = new Diagnostics();
|
||||
const outputPathFn = getOutputPathFn(fs.resolve(testDir, '{{LOCALE}}'));
|
||||
const outputPathFn = getOutputPathFn(fs, fs.resolve(testDir, '{{LOCALE}}'));
|
||||
translateFiles({
|
||||
sourceRootPath: testFilesDir,
|
||||
sourceFilePaths: ['test-1.txt', 'test-2.txt', 'test.js'],
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package(default_visibility = ["//packages/localize/src/tools/test/translate/integration:__pkg__"])
|
||||
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
|
||||
|
||||
# Use copy_to_bin since filegroup doesn't seem to work on Windows.
|
||||
copy_to_bin(
|
||||
name = "test_files",
|
||||
srcs = glob([
|
||||
"**/*.js",
|
||||
"**/*.txt",
|
||||
]),
|
||||
)
|
|
@ -5,36 +5,39 @@
|
|||
* 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 {absoluteFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {absoluteFrom, getFileSystem, PathManipulation} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
|
||||
import {getOutputPathFn} from '../../src/translate/output_path';
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
let fs: PathManipulation;
|
||||
beforeEach(() => fs = getFileSystem());
|
||||
|
||||
describe('getOutputPathFn()', () => {
|
||||
it('should return a function that joins the `outputPath` and the `relativePath`', () => {
|
||||
const fn = getOutputPathFn(absoluteFrom('/output/path'));
|
||||
const fn = getOutputPathFn(fs, absoluteFrom('/output/path'));
|
||||
expect(fn('en', 'relative/path')).toEqual(absoluteFrom('/output/path/relative/path'));
|
||||
expect(fn('en', '../parent/path')).toEqual(absoluteFrom('/output/parent/path'));
|
||||
});
|
||||
|
||||
it('should return a function that interpolates the `{{LOCALE}}` in the middle of the `outputPath`',
|
||||
() => {
|
||||
const fn = getOutputPathFn(absoluteFrom('/output/{{LOCALE}}/path'));
|
||||
const fn = getOutputPathFn(fs, absoluteFrom('/output/{{LOCALE}}/path'));
|
||||
expect(fn('en', 'relative/path')).toEqual(absoluteFrom('/output/en/path/relative/path'));
|
||||
expect(fn('fr', 'relative/path')).toEqual(absoluteFrom('/output/fr/path/relative/path'));
|
||||
});
|
||||
|
||||
it('should return a function that interpolates the `{{LOCALE}}` in the middle of a path segment in the `outputPath`',
|
||||
() => {
|
||||
const fn = getOutputPathFn(absoluteFrom('/output-{{LOCALE}}-path'));
|
||||
const fn = getOutputPathFn(fs, absoluteFrom('/output-{{LOCALE}}-path'));
|
||||
expect(fn('en', 'relative/path')).toEqual(absoluteFrom('/output-en-path/relative/path'));
|
||||
expect(fn('fr', 'relative/path')).toEqual(absoluteFrom('/output-fr-path/relative/path'));
|
||||
});
|
||||
|
||||
it('should return a function that interpolates the `{{LOCALE}}` at the end of the `outputPath`',
|
||||
() => {
|
||||
const fn = getOutputPathFn(absoluteFrom('/output/{{LOCALE}}'));
|
||||
const fn = getOutputPathFn(fs, absoluteFrom('/output/{{LOCALE}}'));
|
||||
expect(fn('en', 'relative/path')).toEqual(absoluteFrom('/output/en/relative/path'));
|
||||
expect(fn('fr', 'relative/path')).toEqual(absoluteFrom('/output/fr/relative/path'));
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 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 {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
import {FileSystem, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {ɵcomputeMsgId, ɵparseTranslation} from '@angular/localize';
|
||||
import {ɵParsedTranslation} from '@angular/localize/private';
|
||||
import {transformSync} from '@babel/core';
|
||||
|
@ -13,8 +13,15 @@ import {transformSync} from '@babel/core';
|
|||
import {Diagnostics} from '../../../src/diagnostics';
|
||||
import {TranslatePluginOptions} from '../../../src/source_file_utils';
|
||||
import {makeEs2015TranslatePlugin} from '../../../src/translate/source_files/es2015_translate_plugin';
|
||||
import {runInNativeFileSystem} from '../../helpers';
|
||||
|
||||
runInNativeFileSystem(() => {
|
||||
let fs: FileSystem;
|
||||
|
||||
beforeEach(() => {
|
||||
fs = getFileSystem();
|
||||
});
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('makeEs2015Plugin', () => {
|
||||
describe('(no translations)', () => {
|
||||
it('should transform `$localize` tags with binary expression', () => {
|
||||
|
@ -172,9 +179,12 @@ runInEachFileSystem(() => {
|
|||
function transformCode(
|
||||
input: string, translations: Record<string, ɵParsedTranslation> = {},
|
||||
pluginOptions?: TranslatePluginOptions, diagnostics = new Diagnostics()): string {
|
||||
const cwd = fs.resolve('/');
|
||||
const filename = fs.resolve(cwd, 'app/dist/test.js');
|
||||
return transformSync(input, {
|
||||
plugins: [makeEs2015TranslatePlugin(diagnostics, translations, pluginOptions)],
|
||||
filename: '/app/dist/test.js'
|
||||
filename,
|
||||
cwd,
|
||||
})!.code!;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 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 {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
||||
import {FileSystem, getFileSystem, PathSegment, relativeFrom} from '@angular/compiler-cli/src/ngtsc/file_system';
|
||||
import {ɵcomputeMsgId, ɵparseTranslation} from '@angular/localize';
|
||||
import {ɵParsedTranslation} from '@angular/localize/private';
|
||||
import {transformSync} from '@babel/core';
|
||||
|
@ -13,8 +13,17 @@ import {transformSync} from '@babel/core';
|
|||
import {Diagnostics} from '../../../src/diagnostics';
|
||||
import {TranslatePluginOptions} from '../../../src/source_file_utils';
|
||||
import {makeEs5TranslatePlugin} from '../../../src/translate/source_files/es5_translate_plugin';
|
||||
import {runInNativeFileSystem} from '../../helpers';
|
||||
|
||||
runInNativeFileSystem(() => {
|
||||
let fs: FileSystem;
|
||||
let testPath: PathSegment;
|
||||
|
||||
beforeEach(() => {
|
||||
fs = getFileSystem();
|
||||
testPath = relativeFrom('app/dist/test.js');
|
||||
});
|
||||
|
||||
runInEachFileSystem(() => {
|
||||
describe('makeEs5Plugin', () => {
|
||||
describe('(no translations)', () => {
|
||||
it('should transform `$localize` calls with binary expression', () => {
|
||||
|
@ -142,7 +151,7 @@ runInEachFileSystem(() => {
|
|||
expect(diagnostics.hasErrors).toBe(true);
|
||||
expect(diagnostics.messages[0]).toEqual({
|
||||
type: 'error',
|
||||
message: '/app/dist/test.js: `$localize` called without any arguments.\n' +
|
||||
message: `${testPath}: \`$localize\` called without any arguments.\n` +
|
||||
'> 1 | $localize()\n' +
|
||||
' | ^^^^^^^^^^^',
|
||||
});
|
||||
|
@ -156,8 +165,7 @@ runInEachFileSystem(() => {
|
|||
expect(diagnostics.hasErrors).toBe(true);
|
||||
expect(diagnostics.messages[0]).toEqual({
|
||||
type: 'error',
|
||||
message:
|
||||
'/app/dist/test.js: Unexpected argument to `$localize` (expected an array).\n' +
|
||||
message: `${testPath}: Unexpected argument to \`$localize\` (expected an array).\n` +
|
||||
'> 1 | $localize(...x)\n' +
|
||||
' | ^^^^',
|
||||
});
|
||||
|
@ -172,7 +180,7 @@ runInEachFileSystem(() => {
|
|||
expect(diagnostics.messages[0]).toEqual({
|
||||
type: 'error',
|
||||
message:
|
||||
'/app/dist/test.js: Unexpected messageParts for `$localize` (expected an array of strings).\n' +
|
||||
`${testPath}: Unexpected messageParts for \`$localize\` (expected an array of strings).\n` +
|
||||
'> 1 | $localize(null, [])\n' +
|
||||
' | ^^^^',
|
||||
});
|
||||
|
@ -187,7 +195,7 @@ runInEachFileSystem(() => {
|
|||
expect(diagnostics.messages[0]).toEqual({
|
||||
type: 'error',
|
||||
message:
|
||||
'/app/dist/test.js: Unexpected `raw` argument to the "makeTemplateObject()" function (expected an expression).\n' +
|
||||
`${testPath}: Unexpected \`raw\` argument to the "makeTemplateObject()" function (expected an expression).\n` +
|
||||
'> 1 | $localize(__makeTemplateObject([], ...[]))\n' +
|
||||
' | ^^^^^',
|
||||
});
|
||||
|
@ -202,7 +210,7 @@ runInEachFileSystem(() => {
|
|||
expect(diagnostics.messages[0]).toEqual({
|
||||
type: 'error',
|
||||
message:
|
||||
'/app/dist/test.js: Unexpected `cooked` argument to the "makeTemplateObject()" function (expected an expression).\n' +
|
||||
`${testPath}: Unexpected \`cooked\` argument to the "makeTemplateObject()" function (expected an expression).\n` +
|
||||
'> 1 | $localize(__makeTemplateObject(...[], []))\n' +
|
||||
' | ^^^^^',
|
||||
});
|
||||
|
@ -217,7 +225,7 @@ runInEachFileSystem(() => {
|
|||
expect(diagnostics.messages[0]).toEqual({
|
||||
type: 'error',
|
||||
message:
|
||||
'/app/dist/test.js: Unexpected messageParts for `$localize` (expected an array of strings).\n' +
|
||||
`${testPath}: Unexpected messageParts for \`$localize\` (expected an array of strings).\n` +
|
||||
'> 1 | $localize(__makeTemplateObject(["a", 12, "b"], ["a", "12", "b"]))\n' +
|
||||
' | ^^^^^^^^^^^^^^',
|
||||
});
|
||||
|
@ -232,7 +240,7 @@ runInEachFileSystem(() => {
|
|||
expect(diagnostics.messages[0]).toEqual({
|
||||
type: 'error',
|
||||
message:
|
||||
'/app/dist/test.js: Unexpected messageParts for `$localize` (expected an array of strings).\n' +
|
||||
`${testPath}: Unexpected messageParts for \`$localize\` (expected an array of strings).\n` +
|
||||
'> 1 | $localize(__makeTemplateObject(["a", "12", "b"], ["a", 12, "b"]))\n' +
|
||||
' | ^^^^^^^^^^^^^^',
|
||||
});
|
||||
|
@ -247,7 +255,7 @@ runInEachFileSystem(() => {
|
|||
expect(diagnostics.messages[0]).toEqual({
|
||||
type: 'error',
|
||||
message:
|
||||
'/app/dist/test.js: Invalid substitutions for `$localize` (expected all substitution arguments to be expressions).\n' +
|
||||
`${testPath}: Invalid substitutions for \`$localize\` (expected all substitution arguments to be expressions).\n` +
|
||||
'> 1 | $localize(__makeTemplateObject(["a", "b"], ["a", "b"]), ...[])\n' +
|
||||
' | ^^^^^',
|
||||
});
|
||||
|
@ -361,9 +369,12 @@ runInEachFileSystem(() => {
|
|||
function transformCode(
|
||||
input: string, translations: Record<string, ɵParsedTranslation> = {},
|
||||
pluginOptions?: TranslatePluginOptions, diagnostics = new Diagnostics()): string {
|
||||
const cwd = fs.resolve('/');
|
||||
const filename = fs.resolve(cwd, testPath);
|
||||
return transformSync(input, {
|
||||
plugins: [makeEs5TranslatePlugin(diagnostics, translations, pluginOptions)],
|
||||
filename: '/app/dist/test.js'
|
||||
filename,
|
||||
cwd,
|
||||
})!.code!;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -23,7 +23,7 @@ runInEachFileSystem(() => {
|
|||
|
||||
beforeEach(() => {
|
||||
fs = getFileSystem();
|
||||
rootPath = absoluteFrom('/root/path');
|
||||
rootPath = absoluteFrom('/src/path');
|
||||
filePath = relativeFrom('relative/path.js');
|
||||
enTranslationPath = absoluteFrom('/translations/en/relative/path.js');
|
||||
enUSTranslationPath = absoluteFrom('/translations/en-US/relative/path.js');
|
||||
|
|
Loading…
Reference in New Issue