diff --git a/e2e/test/jest-with-ts/package.json b/e2e/test/jest-with-ts/package.json index 7330158540..4487fc3949 100644 --- a/e2e/test/jest-with-ts/package.json +++ b/e2e/test/jest-with-ts/package.json @@ -3,7 +3,7 @@ "description": "A test project for using stryker with jest and jest-ts preprocessor. Inspired by the stryker-dashboard source code.", "scripts": { "test": "stryker run", - "test:original": "jest", + "test:unit": "jest", "posttest": "mocha --require ../../tasks/ts-node-register.js verify/verify.ts" }, "dependencies": { diff --git a/e2e/test/jest-with-ts/src/components/hello-component.test.ts b/e2e/test/jest-with-ts/src/components/hello-component.test.ts new file mode 100644 index 0000000000..dfad7661c0 --- /dev/null +++ b/e2e/test/jest-with-ts/src/components/hello-component.test.ts @@ -0,0 +1,15 @@ +/** + * @jest-environment jsdom + */ + +import './hello-component'; + +describe('hello-component', () => { + + fit('should show a "hello world" message', () => { + const element = document.createElement('jest-hello'); + document.body.appendChild(element); + expect(element.innerText).toEqual('hello world'); + document.body.removeChild(element); + }); +}); diff --git a/e2e/test/jest-with-ts/src/components/hello-component.ts b/e2e/test/jest-with-ts/src/components/hello-component.ts new file mode 100644 index 0000000000..cdb176a21a --- /dev/null +++ b/e2e/test/jest-with-ts/src/components/hello-component.ts @@ -0,0 +1,7 @@ + +export class HelloComponent extends HTMLElement { + connectedCallback() { + this.innerText = 'hello world'; + } +} +window.customElements.define('jest-hello', HelloComponent); diff --git a/e2e/test/jest-with-ts/stryker.conf.json b/e2e/test/jest-with-ts/stryker.conf.json index e4b0c67d86..70b571e8c1 100644 --- a/e2e/test/jest-with-ts/stryker.conf.json +++ b/e2e/test/jest-with-ts/stryker.conf.json @@ -1,7 +1,8 @@ { "$schema": "../../node_modules/@stryker-mutator/core/schema/stryker-schema.json", "mutate": [ - "src/data-access/mappers/TableStorageMapper.ts" + "src/data-access/mappers/TableStorageMapper.ts", + "src/components/hello-component.ts" ], "packageManager": "npm", "testRunner": "jest", diff --git a/e2e/test/jest-with-ts/tsconfig.json b/e2e/test/jest-with-ts/tsconfig.json index a4596e57f1..2c22ec470f 100644 --- a/e2e/test/jest-with-ts/tsconfig.json +++ b/e2e/test/jest-with-ts/tsconfig.json @@ -4,7 +4,8 @@ "esModuleInterop": true, "module": "commonjs", "lib": [ - "es2017" + "es2017", + "DOM" ], "types": [ "jest", diff --git a/e2e/test/jest-with-ts/verify/verify.ts b/e2e/test/jest-with-ts/verify/verify.ts index 2f9627c016..b25649a10e 100644 --- a/e2e/test/jest-with-ts/verify/verify.ts +++ b/e2e/test/jest-with-ts/verify/verify.ts @@ -5,8 +5,8 @@ describe('Verify stryker has ran correctly', () => { it('should report correct score', async () => { await expectMetrics({ ignored: 0, - killed: 15, - mutationScore: 53.57, + killed: 17, + mutationScore: 56.67, noCoverage: 0, survived: 13, timeout: 0, diff --git a/packages/instrumenter/src/disable-type-checks.ts b/packages/instrumenter/src/disable-type-checks.ts index 91a7fbf5b7..ead68a00a8 100644 --- a/packages/instrumenter/src/disable-type-checks.ts +++ b/packages/instrumenter/src/disable-type-checks.ts @@ -7,6 +7,7 @@ import { AstFormat, HtmlAst, JSAst, TSAst } from './syntax'; const commentDirectiveRegEx = /^(\s*)@(ts-[a-z-]+).*$/; const tsDirectiveLikeRegEx = /@(ts-[a-z-]+)/; +const startingCommentRegex = /(^\s*\/\*.*?\*\/)/gs; export async function disableTypeChecks(file: File, options: ParserOptions) { if (isJSFileWithoutTSDirectives(file)) { @@ -43,7 +44,9 @@ function prefixWithNoCheck(code: string): string { return code; } } else { - return `// @ts-nocheck\n${code}`; + // We should leave comments, like `/** @jest-env jsdom */ at the top of the file, see #2569 + const commentMatch = startingCommentRegex.exec(code); + return `${commentMatch?.[1].concat('\n') ?? ''}// @ts-nocheck\n${code.substr(commentMatch?.[1].length ?? 0)}`; } } diff --git a/packages/instrumenter/test/unit/disable-type-checks.spec.ts b/packages/instrumenter/test/unit/disable-type-checks.spec.ts index 9396d1224a..3e3bda7713 100644 --- a/packages/instrumenter/test/unit/disable-type-checks.spec.ts +++ b/packages/instrumenter/test/unit/disable-type-checks.spec.ts @@ -27,6 +27,14 @@ describe(disableTypeChecks.name, () => { }); }); + describe('with jest directive (`@jest-environment`)', () => { + it('should insert `// @ts-nocheck` after the jest directive', async () => { + const inputFile = new File('foo.js', '/**\n* @jest-environment jsdom\n*/\nfoo.bar();'); + const actual = await disableTypeChecks(inputFile, { plugins: null }); + assertions.expectTextFileEqual(actual, new File('foo.js', '/**\n* @jest-environment jsdom\n*/\n// @ts-nocheck\n\nfoo.bar();')); + }); + }); + it('should not even parse the file if "@ts-" can\'t be found anywhere in the file (performance optimization)', async () => { const createParserSpy = sinon.spy(parsers, 'createParser'); const inputFile = new File('foo.js', 'foo.bar();'); @@ -47,7 +55,7 @@ describe(disableTypeChecks.name, () => { }); it('should remove @ts directive from single line', async () => { - await arrangeActAssert('// @ts-check\nfoo.bar();', '// \nfoo.bar();'); + await arrangeActAssert('baz();// @ts-check\nfoo.bar();', 'baz();// \nfoo.bar();'); }); it('should not remove @ts comments which occur later on the comment line (since then they are not considered a directive)', async () => { @@ -55,7 +63,7 @@ describe(disableTypeChecks.name, () => { }); it('should remove @ts directive from multiline', async () => { - await arrangeActAssert('/* @ts-expect-error */\nfoo.bar();', '/* */\nfoo.bar();'); + await arrangeActAssert('baz();/* @ts-expect-error */\nfoo.bar();', 'baz();/* */\nfoo.bar();'); }); describe('with string', () => {