test(ivy): refactor Esm5Renderer tests to make them less fragile (#25534)

PR Close #25534
This commit is contained in:
Pete Bacon Darwin 2018-08-23 09:01:21 +01:00 committed by Misko Hevery
parent 73047483a1
commit e73e864f87

View File

@ -27,74 +27,85 @@ function analyze(parser: Esm5FileParser, analyzer: Analyzer, file: ts.SourceFile
return parsedFiles.map(file => analyzer.analyzeFile(file))[0]; return parsedFiles.map(file => analyzer.analyzeFile(file))[0];
} }
const PROGRAM = {
name: 'some/file.js',
contents: `
/* A copyright notice */
import {Directive} from '@angular/core';
var A = (function() {
function A() {}
A.decorators = [
{ type: Directive, args: [{ selector: '[a]' }] },
{ type: OtherA }
];
return A;
}());
var B = (function() {
function B() {}
B.decorators = [
{ type: OtherB },
{ type: Directive, args: [{ selector: '[b]' }] }
];
return B;
}());
var C = (function() {
function C() {}
C.decorators = [
{ type: Directive, args: [{ selector: '[c]' }] },
];
return C;
}());
// Some other content
export {A, B, C};`
};
describe('Esm5Renderer', () => { describe('Esm5Renderer', () => {
describe('addImports', () => { describe('addImports', () => {
it('should insert the given imports at the start of the source file', () => { it('should insert the given imports at the start of the source file', () => {
const PROGRAM = {
name: 'some/file.js',
contents: `
/* A copyright notice */
import {Directive} from '@angular/core';
var A = (function() {
function A() {}
A.decorators = [
{ type: Directive, args: [{ selector: '[a]' }] },
{ type: Other }
];
return A;
}());
// Some other content
export {A};`
};
const {renderer} = setup(PROGRAM); const {renderer} = setup(PROGRAM);
const output = new MagicString(PROGRAM.contents); const output = new MagicString(PROGRAM.contents);
renderer.addImports( renderer.addImports(
output, [{name: '@angular/core', as: 'i0'}, {name: '@angular/common', as: 'i1'}]); output, [{name: '@angular/core', as: 'i0'}, {name: '@angular/common', as: 'i1'}]);
expect(output.toString()) expect(output.toString()).toContain(`import * as i0 from '@angular/core';
.toEqual( import * as i1 from '@angular/common';
`import * as i0 from '@angular/core';\n` +
`import * as i1 from '@angular/common';\n` + PROGRAM.contents); /* A copyright notice */`);
}); });
}); });
describe('addConstants', () => {
it('should insert the given constants after imports in the source file', () => {
const {renderer, program} = setup(PROGRAM);
const file = program.getSourceFile('some/file.js');
if (file === undefined) {
throw new Error(`Could not find source file`);
}
const output = new MagicString(PROGRAM.contents);
renderer.addConstants(output, 'const x = 3;', file);
expect(output.toString()).toContain(`
import {Directive} from '@angular/core';
const x = 3;
var A = (function() {`);
});
});
describe('addDefinitions', () => { describe('addDefinitions', () => {
it('should insert the definitions directly after the class declaration', () => { it('should insert the definitions directly after the class declaration', () => {
const PROGRAM = {
name: 'some/file.js',
contents: `
/* A copyright notice */
import {Directive} from '@angular/core';
var A = (function() {
function A() {}
A.decorators = [
{ type: Directive, args: [{ selector: '[a]' }] },
{ type: Other }
];
return A;
}());
// Some other content
export {A};`
};
const {analyzer, parser, program, renderer} = setup(PROGRAM); const {analyzer, parser, program, renderer} = setup(PROGRAM);
const analyzedFile = analyze(parser, analyzer, program.getSourceFile(PROGRAM.name) !); const analyzedFile = analyze(parser, analyzer, program.getSourceFile(PROGRAM.name) !);
const output = new MagicString(PROGRAM.contents); const output = new MagicString(PROGRAM.contents);
renderer.addDefinitions(output, analyzedFile.analyzedClasses[0], 'SOME DEFINITION TEXT'); renderer.addDefinitions(output, analyzedFile.analyzedClasses[0], 'SOME DEFINITION TEXT');
expect(output.toString()).toEqual(` expect(output.toString()).toContain(`
/* A copyright notice */
import {Directive} from '@angular/core';
var A = (function() {
function A() {} function A() {}
SOME DEFINITION TEXT SOME DEFINITION TEXT
A.decorators = [ A.decorators = [
{ type: Directive, args: [{ selector: '[a]' }] }, `);
{ type: Other }
];
return A;
}());
// Some other content
export {A};`);
}); });
}); });
@ -103,120 +114,58 @@ export {A};`);
describe('removeDecorators', () => { describe('removeDecorators', () => {
it('should delete the decorator (and following comma) that was matched in the analysis', () => { it('should delete the decorator (and following comma) that was matched in the analysis', () => {
const PROGRAM = {
name: 'some/file.js',
contents: `
/* A copyright notice */
import {Directive} from '@angular/core';
var A = (function() {
function A() {}
A.decorators = [
{ type: Directive, args: [{ selector: '[a]' }] },
{ type: Other }
];
return A;
}());
// Some other content
export {A};`
};
const {analyzer, parser, program, renderer} = setup(PROGRAM); const {analyzer, parser, program, renderer} = setup(PROGRAM);
const analyzedFile = analyze(parser, analyzer, program.getSourceFile(PROGRAM.name) !); const analyzedFile = analyze(parser, analyzer, program.getSourceFile(PROGRAM.name) !);
const output = new MagicString(PROGRAM.contents); const output = new MagicString(PROGRAM.contents);
const analyzedClass = analyzedFile.analyzedClasses[0]; const analyzedClass = analyzedFile.analyzedClasses[0];
const decorator = analyzedClass.decorators[0];
const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); const decoratorsToRemove = new Map<ts.Node, ts.Node[]>();
decoratorsToRemove.set( decoratorsToRemove.set(decorator.node.parent !, [decorator.node]);
analyzedClass.decorators[0].node.parent !, [analyzedClass.decorators[0].node]);
renderer.removeDecorators(output, decoratorsToRemove); renderer.removeDecorators(output, decoratorsToRemove);
expect(output.toString()).toEqual(` expect(output.toString()).not.toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`);
/* A copyright notice */ expect(output.toString()).toContain(`{ type: OtherA }`);
import {Directive} from '@angular/core'; expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[b]' }] }`);
var A = (function() { expect(output.toString()).toContain(`{ type: OtherB }`);
function A() {} expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[c]' }] }`);
A.decorators = [
{ type: Other }
];
return A;
}());
// Some other content
export {A};`);
}); });
it('should delete the decorator (but cope with no trailing comma) that was matched in the analysis', it('should delete the decorator (but cope with no trailing comma) that was matched in the analysis',
() => { () => {
const PROGRAM = {
name: 'some/file.js',
contents: `
/* A copyright notice */
import {Directive} from '@angular/core';
var A = (function() {
function A() {}
A.decorators = [
{ type: Other },
{ type: Directive, args: [{ selector: '[a]' }] }
];
return A;
}());
// Some other content
export {A};`
};
const {analyzer, parser, program, renderer} = setup(PROGRAM); const {analyzer, parser, program, renderer} = setup(PROGRAM);
const analyzedFile = analyze(parser, analyzer, program.getSourceFile(PROGRAM.name) !); const analyzedFile = analyze(parser, analyzer, program.getSourceFile(PROGRAM.name) !);
const output = new MagicString(PROGRAM.contents); const output = new MagicString(PROGRAM.contents);
const analyzedClass = analyzedFile.analyzedClasses[0]; const analyzedClass = analyzedFile.analyzedClasses[1];
const decorator = analyzedClass.decorators[1];
const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); const decoratorsToRemove = new Map<ts.Node, ts.Node[]>();
decoratorsToRemove.set( decoratorsToRemove.set(decorator.node.parent !, [decorator.node]);
analyzedClass.decorators[0].node.parent !, [analyzedClass.decorators[1].node]);
renderer.removeDecorators(output, decoratorsToRemove); renderer.removeDecorators(output, decoratorsToRemove);
expect(output.toString()).toEqual(` expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`);
/* A copyright notice */ expect(output.toString()).toContain(`{ type: OtherA }`);
import {Directive} from '@angular/core'; expect(output.toString())
var A = (function() { .not.toContain(`{ type: Directive, args: [{ selector: '[b]' }] }`);
function A() {} expect(output.toString()).toContain(`{ type: OtherB }`);
A.decorators = [ expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[c]' }] }`);
{ type: Other },
];
return A;
}());
// Some other content
export {A};`);
}); });
it('should delete the decorator (and its container if there are not other decorators left) that was matched in the analysis', it('should delete the decorator (and its container if there are not other decorators left) that was matched in the analysis',
() => { () => {
const PROGRAM = {
name: 'some/file.js',
contents: `
/* A copyright notice */
import {Directive} from '@angular/core';
var A = (function() {
function A() {}
A.decorators = [
{ type: Directive, args: [{ selector: '[a]' }] }
];
return A;
}());
// Some other content
export {A};`
};
const {analyzer, parser, program, renderer} = setup(PROGRAM); const {analyzer, parser, program, renderer} = setup(PROGRAM);
const analyzedFile = analyze(parser, analyzer, program.getSourceFile(PROGRAM.name) !); const analyzedFile = analyze(parser, analyzer, program.getSourceFile(PROGRAM.name) !);
const output = new MagicString(PROGRAM.contents); const output = new MagicString(PROGRAM.contents);
const analyzedClass = analyzedFile.analyzedClasses[0]; const analyzedClass = analyzedFile.analyzedClasses[2];
const decorator = analyzedClass.decorators[0];
const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); const decoratorsToRemove = new Map<ts.Node, ts.Node[]>();
decoratorsToRemove.set( decoratorsToRemove.set(decorator.node.parent !, [decorator.node]);
analyzedClass.decorators[0].node.parent !, [analyzedClass.decorators[0].node]);
renderer.removeDecorators(output, decoratorsToRemove); renderer.removeDecorators(output, decoratorsToRemove);
expect(output.toString()).toEqual(` expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`);
/* A copyright notice */ expect(output.toString()).toContain(`{ type: OtherA }`);
import {Directive} from '@angular/core'; expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[b]' }] }`);
var A = (function() { expect(output.toString()).toContain(`{ type: OtherB }`);
function A() {} expect(output.toString()).not.toContain(`C.decorators = [
return A; { type: Directive, args: [{ selector: '[c]' }] },
}()); ];`);
// Some other content
export {A};`);
}); });
}); });