Skip to content

Commit

Permalink
fix(compiler): update SourceFile with correct file content (#765)
Browse files Browse the repository at this point in the history
Previously SourceFile.text was the old contents of the file - however the file was during startup. This change updates the SourceFile text so that emit() receives the changed file contents.

Closes #764 

Co-authored-by: Ahn <anhpnnd@gmail.com>
  • Loading branch information
johncrim and ahnpnl authored Jan 29, 2021
1 parent 2bbc45d commit c54e20a
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 6 deletions.
44 changes: 44 additions & 0 deletions src/__tests__/__snapshots__/ng-jest-compiler.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,50 @@ export { AppComponent };
//# "
`;

exports[`NgJestCompiler with isolatedModule false should compile new code when file changes: from hasErrorFileContent 1`] = `
"\\"use strict\\";
Object.defineProperty(exports, \\"__esModule\\", { value: true });
exports.AppComponent = void 0;
const tslib_1 = require(\\"tslib\\");
const core_1 = require(\\"@angular/core\\");
let = class {
constructor() {
this. = ;
}
};
= tslib_1.__decorate([
core_1.Component({
selector: 'app-root',
template: require(\\"./app.component.html\\"),
styles: []
})
], );
exports.AppComponent = ;
//# "
`;

exports[`NgJestCompiler with isolatedModule false should compile new code when file changes: from noErrorFileContent 1`] = `
"\\"use strict\\";
Object.defineProperty(exports, \\"__esModule\\", { value: true });
exports.AppComponent = void 0;
const tslib_1 = require(\\"tslib\\");
const core_1 = require(\\"@angular/core\\");
let AppComponent = class AppComponent {
constructor() {
this.title = 'test-app-v10';
}
};
AppComponent = tslib_1.__decorate([
core_1.Component({
selector: 'app-root',
template: require(\\"./app.component.html\\"),
styles: []
})
], AppComponent);
exports.AppComponent = AppComponent;
//# "
`;

exports[`NgJestCompiler with isolatedModule false should throw diagnostics error for new file which is: known by Program 1`] = `"src/__tests__/__mocks__/foo.component.ts(8,3): error TS2322: Type 'string' is not assignable to type 'number'."`;

exports[`NgJestCompiler with isolatedModule false should throw diagnostics error for new file which is: not known by Program 1`] = `"src/__tests__/__mocks__/foo.component.ts(8,3): error TS2322: Type 'string' is not assignable to type 'number'."`;
18 changes: 18 additions & 0 deletions src/__tests__/ng-jest-compiler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,24 @@ describe('NgJestCompiler', () => {
},
);

test('should compile new code when file changes', () => {
const ngJestConfig = new NgJestConfig(jestCfgStub);
const compiler = new NgJestCompiler(ngJestConfig, new Map());

// Compile the same file with 2 versions of content: noErrorFileContent and hasErrorFileContent
const fileName = noErrorFileName;
const emittedResult1 = compiler.getCompiledOutput(fileName, noErrorFileContent, true);
expect(emittedResult1.substring(0, emittedResult1.indexOf(SOURCE_MAPPING_PREFIX))).toMatchSnapshot(
'from noErrorFileContent',
);
const emittedResult2 = compiler.getCompiledOutput(fileName, hasErrorFileContent, true);
expect(emittedResult2.substring(0, emittedResult2.indexOf(SOURCE_MAPPING_PREFIX))).toMatchSnapshot(
'from hasErrorFileContent',
);

expect(emittedResult1).not.toEqual(emittedResult2);
});

test('should compile codes with useESM true', () => {
const ngJestConfig = new NgJestConfig({
...jestCfgStub,
Expand Down
21 changes: 15 additions & 6 deletions src/compiler/ng-jest-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,27 @@ export class NgJestCompiler implements CompilerInstance {
esModuleInterop,
module: moduleKind,
};

if (this._program) {
const allDiagnostics: ts.Diagnostic[] = [];
if (!this._rootNames.includes(fileName)) {
this._logger.debug({ fileName }, 'getCompiledOutput: update memory host, rootFiles and Program');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this._tsHost!.updateMemoryHost(fileName, fileContent);

let sourceFile: ts.SourceFile | undefined;
if (!this._rootNames.includes(fileName)) {
this._logger.debug({ fileName }, 'getCompiledOutput: adding file to rootNames and updating Program');
this._rootNames = [...this._rootNames, fileName];
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this._tsHost!.updateMemoryHost(fileName, fileContent);
this._createOrUpdateProgram();
sourceFile = this._program.getSourceFile(fileName);
} else {
sourceFile = this._program.getSourceFile(fileName);
if (sourceFile) {
const replaceSpan: ts.TextSpan = { start: 0, length: sourceFile.text.length };
sourceFile.update(fileContent, { span: replaceSpan, newLength: fileContent.length });
}
}

this._logger.debug({ fileName }, 'getCompiledOutput: compiling using Program');

const sourceFile = this._program.getSourceFile(fileName);
const emitResult = this._program.emit(sourceFile, undefined, undefined, undefined, {
...customTransformers,
before: [
Expand All @@ -98,8 +105,10 @@ export class NgJestCompiler implements CompilerInstance {
replaceResources(this.isAppPath, this._program.getTypeChecker),
],
});

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const compiledOutput: [string, string] = this._tsHost!.getEmittedResult();
const allDiagnostics: ts.Diagnostic[] = [];
if (this.ngJestConfig.shouldReportDiagnostics(fileName)) {
this._logger.debug({ fileName }, 'getCompiledOutput: getting diagnostics');

Expand Down

0 comments on commit c54e20a

Please sign in to comment.