Repository: skovhus/jest-codemods
Pull request #184 (2019-10-16 23:21:03)

Add any type to test context (for TypeScript)
When running the transform that converts `this` usage into `testContext` it inserts `let testContext`.

If running in a TypeScript codebase with the compiler option [`noImplicitAny`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) enabled this will result in compiler errors.

This pull request will add the `any` type annotation to `let testContext` to explicitly define this value as `any`:

```typescript
let testContext: any;
```

It's probably unrealistic that the correct typings could be automatically generated.

This is done by checking if the `parser` option is `tsx` or `ts`.

This also fixes a type issue introduced in https://github.com/skovhus/jest-codemods/pull/183.


Patch:
diff --git a/src/transformers/jasmine-this.ts b/src/transformers/jasmine-this.ts
index ad929c0..8259889 100644
--- a/src/transformers/jasmine-this.ts
+++ b/src/transformers/jasmine-this.ts
@@ -130,7 +130,15 @@ const jasmineThis: jscodeshift.Transform = (fileInfo, api, options) => {
       )
       body.unshift(
         j.variableDeclaration('let', [
-          j.variableDeclarator(j.identifier(contextName), null),
+          j.variableDeclarator(
+            j.identifier.from({
+              name: contextName,
+              typeAnnotation: ['ts', 'tsx'].includes(options.parser)
+                ? j.typeAnnotation(j.anyTypeAnnotation())
+                : null,
+            }),
+            null
+          ),
         ])
       )
     }


Test patch:
diff --git a/src/transformers/jasmine-this.test.ts b/src/transformers/jasmine-this.test.ts
index 42f9aa0..8910f04 100644
--- a/src/transformers/jasmine-this.test.ts
+++ b/src/transformers/jasmine-this.test.ts
@@ -7,9 +7,9 @@ import plugin from './jasmine-this'
 chalk.enabled = false
 const wrappedPlugin = wrapPlugin(plugin)
 
-function testChanged(msg, source, expectedOutput) {
+function testChanged(msg, source, expectedOutput, options = {}) {
   test(msg, () => {
-    const result = wrappedPlugin(source)
+    const result = wrappedPlugin(source, options)
     expect(result).toBe(expectedOutput)
   })
 }
@@ -455,3 +455,85 @@ describe('foo', () => {
 });
 `
 )
+
+testChanged(
+  'adds any type to the test context with typescript (tsx)',
+  `
+  beforeEach(function () {
+      this.hello = 'hi';
+  });
+
+  afterEach(function () {
+      console.log(this.hello);
+  });
+
+  describe('context', () => {
+      it('should work', function () {
+          console.log(this.hello);
+      });
+  });
+  `,
+  `
+  let testContext: any;
+
+  beforeEach(() => {
+      testContext = {};
+  });
+
+  beforeEach(() => {
+      testContext.hello = 'hi';
+  });
+
+  afterEach(() => {
+      console.log(testContext.hello);
+  });
+
+  describe('context', () => {
+      it('should work', () => {
+          console.log(testContext.hello);
+      });
+  });
+  `,
+  { parser: 'tsx' }
+)
+
+testChanged(
+  'adds any type to the test context with typescript (ts)',
+  `
+beforeEach(function () {
+    this.hello = 'hi';
+});
+
+afterEach(function () {
+    console.log(this.hello);
+});
+
+describe('context', () => {
+    it('should work', function () {
+        console.log(this.hello);
+    });
+});
+`,
+  `
+let testContext: any;
+
+beforeEach(() => {
+    testContext = {};
+});
+
+beforeEach(() => {
+    testContext.hello = 'hi';
+});
+
+afterEach(() => {
+    console.log(testContext.hello);
+});
+
+describe('context', () => {
+    it('should work', () => {
+        console.log(testContext.hello);
+    });
+});
+`,
+  { parser: 'ts' }
+)
diff --git a/src/transformers/mocha.test.ts b/src/transformers/mocha.test.ts
index 7fee987..26be2e9 100644
--- a/src/transformers/mocha.test.ts
+++ b/src/transformers/mocha.test.ts
@@ -10,9 +10,9 @@ beforeEach(() => {
   console.warn = v => consoleWarnings.push(v)
 })
 
-function testChanged(msg, source, expectedOutput) {
+function testChanged(msg, source, expectedOutput, options = {}) {
   test(msg, () => {
-    const result = wrappedPlugin(source)
+    const result = wrappedPlugin(source, options)
     expect(result).toBe(expectedOutput)
     expect(consoleWarnings).toEqual([])
   })
@@ -162,3 +162,77 @@ describe('suite', () => {
 })
     `
 )
+
+testChanged(
+  'adds any type to the test context with typescript (tsx)',
+  `
+describe('describe', function () {
+  beforeEach(function () {
+    this.hello = 'hi';
+  });
+
+  context('context', () => {
+    it('it', function () {
+      console.log(this.hello);
+    });
+  })
+})
+`,
+  `
+describe('describe', () => {
+  let testContext: any;
+
+  beforeEach(() => {
+    testContext = {};
+  });
+
+  beforeEach(() => {
+    testContext.hello = 'hi';
+  });
+
+  describe('context', () => {
+    test('it', () => {
+      console.log(testContext.hello);
+    });
+  })
+})
+`,
+  { parser: 'tsx' }
+)
+
+testChanged(
+  'adds any type to the test context with typescript (ts)',
+  `
+describe('describe', function () {
+  beforeEach(function () {
+    this.hello = 'hi';
+  });
+
+  context('context', () => {
+    it('it', function () {
+      console.log(this.hello);
+    });
+  })
+})
+`,
+  `
+describe('describe', () => {
+  let testContext: any;
+
+  beforeEach(() => {
+    testContext = {};
+  });
+
+  beforeEach(() => {
+    testContext.hello = 'hi';
+  });
+
+  describe('context', () => {
+    test('it', () => {
+      console.log(testContext.hello);
+    });
+  })
+})
+`,
+  { parser: 'ts' }
+)
diff --git a/src/utils/test-helpers.ts b/src/utils/test-helpers.ts
index 747a5f7..9fab150 100644
--- a/src/utils/test-helpers.ts
+++ b/src/utils/test-helpers.ts
@@ -15,5 +15,5 @@ export function runPlugin(plugin: jscodeshift.Transform, source: string, options
 }
 
 export function wrapPlugin(plugin: jscodeshift.Transform) {
-  return (source: string, options = {}) => runPlugin(plugin, source, options)
+  return (source: string, options = {}) => runPlugin(plugin, source, options) || null
 }