Skip to content

Commit 0db3190

Browse files
committed
test: add failing test cases with single file transpilation
1 parent 61727ea commit 0db3190

File tree

2 files changed

+177
-3
lines changed

2 files changed

+177
-3
lines changed

src/compiler/ng-jest-compiler.spec.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,5 +475,179 @@ describe('NgJestCompiler', () => {
475475
], MyComp);
476476
`);
477477
});
478+
479+
it.failing('should capture constructor type metadata with `emitDecoratorMetadata` enabled', () => {
480+
const { code, diagnostics } = transformCjs(
481+
`
482+
import {Directive} from '@angular/core';
483+
import {MyOtherClass} from './other-file';
484+
485+
@Directive()
486+
export class MyDir {
487+
constructor(other: MyOtherClass) {}
488+
}
489+
`,
490+
{ emitDecoratorMetadata: true },
491+
);
492+
493+
expect(diagnostics.length).toBe(0);
494+
expect(code).toContain('const other_file_1 = require("./other-file");');
495+
// This is actual output code
496+
// `
497+
// MyDir.ctorParameters = () => [
498+
// { type: other_file_1.MyOtherClass }
499+
// ];
500+
// exports.MyDir = MyDir = tslib_1.__decorate([
501+
// (0, core_1.Directive)(),
502+
// tslib_1.__metadata("design:paramtypes", [typeof (_a = typeof other_file_1.MyOtherClass !== \\"undefined\\" && other_file_1.MyOtherClass) === \\"function\\" ? _a : Object]])
503+
// ], MyDir);
504+
// `
505+
expect(code).toContain(dedent`
506+
MyDir.ctorParameters = () => [
507+
{ type: other_file_1.MyOtherClass }
508+
];
509+
exports.MyDir = MyDir = tslib_1.__decorate([
510+
(0, core_1.Directive)(),
511+
tslib_1.__metadata("design:paramtypes", Object])
512+
], MyDir);
513+
`);
514+
});
515+
516+
it.failing('should properly serialize constructor parameter with external qualified name type', () => {
517+
// This test doesn't pass because `transpileModule` can't resolve `import *`
518+
const { code, diagnostics } = transformCjs(`
519+
import {Directive} from '@angular/core';
520+
import * as externalFile from './other-file';
521+
522+
@Directive()
523+
export class MyDir {
524+
constructor(other: externalFile.MyOtherClass) {}
525+
}
526+
`);
527+
528+
expect(diagnostics.length).toBe(0);
529+
expect(code).toContain('const externalFile = require("./other-file");');
530+
// This is actual output code
531+
// `
532+
// MyDir.ctorParameters = () => [
533+
// { type: undefined }
534+
// ];
535+
// exports.MyDir = MyDir = tslib_1.__decorate([
536+
// (0, core_1.Directive)()
537+
// ], MyDir);
538+
// `
539+
expect(code).toContain(dedent`
540+
MyDir.ctorParameters = () => [
541+
{ type: externalFile.MyOtherClass }
542+
];
543+
exports.MyDir = MyDir = tslib_1.__decorate([
544+
(0, core_1.Directive)()
545+
], MyDir);
546+
`);
547+
});
548+
549+
it.failing('should not capture constructor parameter types when not resolving to a value', () => {
550+
// This test doesn't pass because `transpileModule` can't resolve `import *`
551+
const { code, diagnostics } = transformCjs(`
552+
import {Directive, Inject} from '@angular/core';
553+
import * as angular from './external';
554+
import {IOverlay, KeyCodes} from './external';
555+
import TypeFromDefaultImport from './external';
556+
557+
@Directive()
558+
export class MyDir {
559+
constructor(@Inject('$state') param: angular.IState,
560+
@Inject('$overlay') other: IOverlay,
561+
@Inject('$default') fromDefaultImport: TypeFromDefaultImport,
562+
@Inject('$keyCodes') keyCodes: KeyCodes) {}
563+
}
564+
`);
565+
566+
expect(diagnostics.length).toBe(0);
567+
// This is actual output code
568+
// `
569+
// "\\"use strict\\";
570+
// Object.defineProperty(exports, \\"__esModule\\", { value: true });
571+
// exports.MyDir = void 0;
572+
// const tslib_1 = require(\\"tslib\\");
573+
// const core_1 = require(\\"@angular/core\\");
574+
// const external_1 = require(\\"./external\\");
575+
// const external_2 = tslib_1.__importDefault(require(\\"./external\\"));
576+
// let MyDir = class MyDir {
577+
// constructor(param, other, fromDefaultImport, keyCodes) { }
578+
// };
579+
// exports.MyDir = MyDir;
580+
// MyDir.ctorParameters = () => [
581+
// { type: undefined, decorators: [{ type: core_1.Inject, args: ['$state',] }] },
582+
// { type: external_1.IOverlay, decorators: [{ type: core_1.Inject, args: ['$overlay',] }] },
583+
// { type: external_2.default, decorators: [{ type: core_1.Inject, args: ['$default',] }] },
584+
// { type: external_1.KeyCodes, decorators: [{ type: core_1.Inject, args: ['$keyCodes',] }] }
585+
// ];
586+
// exports.MyDir = MyDir = tslib_1.__decorate([
587+
// (0, core_1.Directive)()
588+
// ], MyDir);
589+
// "
590+
// `
591+
expect(code).not.toContain('external');
592+
expect(code).toContain(dedent`
593+
MyDir.ctorParameters = () => [
594+
{ type: undefined, decorators: [{ type: core_1.Inject, args: ['$state',] }] },
595+
{ type: undefined, decorators: [{ type: core_1.Inject, args: ['$overlay',] }] },
596+
{ type: undefined, decorators: [{ type: core_1.Inject, args: ['$default',] }] },
597+
{ type: undefined, decorators: [{ type: core_1.Inject, args: ['$keyCodes',] }] }
598+
];
599+
exports.MyDir = MyDir = tslib_1.__decorate([
600+
(0, core_1.Directive)()
601+
], MyDir);
602+
`);
603+
});
604+
605+
it.failing(
606+
'should allow for type-only references to be removed with `emitDecoratorMetadata` from custom decorators',
607+
() => {
608+
const { code, diagnostics } = transformCjs(
609+
`
610+
import { ExternalInterface } from './external-interface';
611+
612+
export function CustomDecorator() {
613+
return <T>(target, propertyKey, descriptor: TypedPropertyDescriptor<T>) => {}
614+
}
615+
616+
export class Foo {
617+
@CustomDecorator() static test(): ExternalInterface { return {}; }
618+
}
619+
`,
620+
{ emitDecoratorMetadata: true },
621+
);
622+
623+
expect(diagnostics.length).toBe(0);
624+
// This is actual output code
625+
// `
626+
// "\\"use strict\\";
627+
// var _a;
628+
// Object.defineProperty(exports, \\"__esModule\\", { value: true });
629+
// exports.Foo = void 0;
630+
// exports.CustomDecorator = CustomDecorator;
631+
// const tslib_1 = require(\\"tslib\\");
632+
// const external_interface_1 = require(\\"./external-interface\\");
633+
// function CustomDecorator() {
634+
// return (target, propertyKey, descriptor) => { };
635+
// }
636+
// class Foo {
637+
// static test() { return {}; }
638+
// }
639+
// exports.Foo = Foo;
640+
// tslib_1.__decorate([
641+
// CustomDecorator(),
642+
// tslib_1.__metadata(\\"design:type\\", Function),
643+
// tslib_1.__metadata(\\"design:paramtypes\\", []),
644+
// tslib_1.__metadata(\\"design:returntype\\", typeof (_a = typeof external_interface_1.ExternalInterface !== \\"undefined\\" && external_interface_1.ExternalInterface) === \\"function\\" ? _a : Object)
645+
// ], Foo, \\"test\\", null);
646+
// "
647+
// `
648+
expect(code).not.toContain('ExternalInterface');
649+
expect(code).toContain('metadata("design:returntype", Object)');
650+
},
651+
);
478652
});
479653
});

src/compiler/ng-jest-compiler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import os from 'node:os';
2-
import path from 'node:path';
1+
import os from 'os';
2+
import path from 'path';
33

44
import { type TsJestAstTransformer, TsCompiler, type ConfigSet } from 'ts-jest';
5-
import type ts from 'typescript';
5+
import type * as ts from 'typescript';
66

77
import { angularJitApplicationTransform } from '../transformers/jit_transform';
88
import { replaceResources } from '../transformers/replace-resources';

0 commit comments

Comments
 (0)