Repository: skovhus/jest-codemods
Pull request #617 (2024-09-12 11:17:18)

fix(jasmine): move wrongly placed jasmine matchers from expect file to jasmine-globals file
…

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/skovhus/jest-codemods/pull/617?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kenneth+Skovhus) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 95.18%. Comparing base [(`a94e2b5`)](https://app.codecov.io/gh/skovhus/jest-codemods/commit/a94e2b561fed619cbebf0b9c28e0a919c44aa4e3?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kenneth+Skovhus) to head [(`70a93b3`)](https://app.codecov.io/gh/skovhus/jest-codemods/commit/70a93b381cf25ca2092bec48b87d85f94aad9436?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kenneth+Skovhus).
> Report is 75 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #617      +/-   ##
==========================================
+ Coverage   92.38%   95.18%   +2.79%     
==========================================
  Files          26       27       +1     
  Lines        1944     2075     +131     
  Branches      405      430      +25     
==========================================
+ Hits         1796     1975     +179     
+ Misses        102       92      -10     
+ Partials       46        8      -38     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/skovhus/jest-codemods/pull/617?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kenneth+Skovhus).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kenneth+Skovhus).


Patch:
diff --git a/src/transformers/expect.ts b/src/transformers/expect.ts
index 41e9f5e..8cdc9e6 100644
--- a/src/transformers/expect.ts
+++ b/src/transformers/expect.ts
@@ -207,95 +207,6 @@ ${keys}.forEach(e => {
           }
           break
         }
-
-        case 'toBeTrue': {
-          matcherArgs[0] = j.literal(true)
-          matcher.name = 'toBe'
-          break
-        }
-
-        case 'toBeFalse': {
-          matcherArgs[0] = j.literal(false)
-          matcher.name = 'toBe'
-          break
-        }
-
-        case 'toBePositiveInfinity': {
-          matcherArgs[0] = j.literal(Infinity)
-          matcher.name = 'toBe'
-          break
-        }
-
-        case 'toBeNegativeInfinity': {
-          matcherArgs[0] = j.literal(-Infinity)
-          matcher.name = 'toBe'
-          break
-        }
-
-        case 'toHaveSize': {
-          matcher.name = 'toHaveLength'
-          break
-        }
-
-        case 'toHaveBeenCalledOnceWith': {
-          expectArgs[0] = j.memberExpression(
-            j.memberExpression(expectArgs[0], j.identifier('mock')),
-            j.identifier('calls')
-          )
-          matcher.name = 'toEqual'
-
-          matcherNode.arguments = [j.arrayExpression([j.arrayExpression(matcherArgs)])]
-          break
-        }
-
-        case 'toHaveBeenCalledBefore': {
-          const getMinInvocationOrder = (spy) =>
-            j.callExpression(
-              j.memberExpression(j.identifier('Math'), j.identifier('min')),
-              [
-                j.spreadElement(
-                  j.memberExpression(
-                    j.memberExpression(spy, j.identifier('mock')),
-                    j.identifier('invocationOrder')
-                  )
-                ),
-              ]
-            )
-
-          expectArgs[0] = getMinInvocationOrder(expectArgs[0])
-          matcherArgs[0] = getMinInvocationOrder(matcherArgs[0])
-          matcher.name = 'toBeLessThan'
-          break
-        }
-
-        case 'toHaveSpyInteractions': {
-          expectArgs[0] = j.callExpression(
-            j.memberExpression(
-              j.callExpression(
-                j.memberExpression(j.identifier('Object'), j.identifier('values')),
-                [expectArgs[0]]
-              ),
-              j.identifier('some')
-            ),
-            [
-              j.arrowFunctionExpression(
-                [j.identifier('spy')],
-                j.optionalMemberExpression(
-                  j.optionalMemberExpression(
-                    j.memberExpression(j.identifier('spy'), j.identifier('mock')),
-                    j.identifier('calls'),
-                    false,
-                    true
-                  ),
-                  j.identifier('length')
-                )
-              ),
-            ]
-          )
-          matcherArgs[0] = j.literal(true)
-          matcher.name = 'toBe'
-          break
-        }
       }
 
       balanceMatcherNodeArguments(matcherNode, matcher, path)
diff --git a/src/transformers/jasmine-globals.ts b/src/transformers/jasmine-globals.ts
index 95130d2..1f52f12 100644
--- a/src/transformers/jasmine-globals.ts
+++ b/src/transformers/jasmine-globals.ts
@@ -14,6 +14,126 @@ export default function jasmineGlobals(fileInfo, api, options) {
 
   const logWarning = (msg, path) => logger(fileInfo, msg, path)
 
+  root
+    .find(j.MemberExpression, {
+      object: {
+        type: 'CallExpression',
+        callee: { type: 'Identifier', name: 'expect' },
+      },
+      property: { type: 'Identifier' },
+    })
+    .forEach((path) => {
+      const matcher = path.node.property
+      const matcherName = matcher.name
+      const matcherNode = path.parentPath.node
+      const matcherArgs = matcherNode.arguments
+      const expectArgs = path.node.object.arguments
+
+      switch (matcherName) {
+        case 'toBeTrue': {
+          matcherArgs[0] = j.literal(true)
+          matcher.name = 'toBe'
+          break
+        }
+
+        case 'toBeFalse': {
+          matcherArgs[0] = j.literal(false)
+          matcher.name = 'toBe'
+          break
+        }
+
+        case 'toBePositiveInfinity': {
+          matcherArgs[0] = j.literal(Infinity)
+          matcher.name = 'toBe'
+          break
+        }
+
+        case 'toBeNegativeInfinity': {
+          matcherArgs[0] = j.literal(-Infinity)
+          matcher.name = 'toBe'
+          break
+        }
+
+        case 'toHaveSize': {
+          matcher.name = 'toHaveLength'
+          break
+        }
+
+        case 'toHaveClass': {
+          expectArgs[0] = j.callExpression(
+            j.memberExpression(
+              j.memberExpression(expectArgs[0], j.identifier('classList')),
+              j.identifier('contains')
+            ),
+            [...matcherArgs]
+          )
+          matcherArgs[0] = j.literal(true)
+          matcher.name = 'toBe'
+          break
+        }
+
+        case 'toHaveBeenCalledOnceWith': {
+          expectArgs[0] = j.memberExpression(
+            j.memberExpression(expectArgs[0], j.identifier('mock')),
+            j.identifier('calls')
+          )
+          matcher.name = 'toEqual'
+
+          matcherNode.arguments = [j.arrayExpression([j.arrayExpression(matcherArgs)])]
+          break
+        }
+
+        case 'toHaveBeenCalledBefore': {
+          const getMinInvocationOrder = (spy) =>
+            j.callExpression(
+              j.memberExpression(j.identifier('Math'), j.identifier('min')),
+              [
+                j.spreadElement(
+                  j.memberExpression(
+                    j.memberExpression(spy, j.identifier('mock')),
+                    j.identifier('invocationOrder')
+                  )
+                ),
+              ]
+            )
+
+          expectArgs[0] = getMinInvocationOrder(expectArgs[0])
+          matcherArgs[0] = getMinInvocationOrder(matcherArgs[0])
+          matcher.name = 'toBeLessThan'
+          break
+        }
+
+        case 'toHaveSpyInteractions': {
+          expectArgs[0] = j.callExpression(
+            j.memberExpression(
+              j.callExpression(
+                j.memberExpression(j.identifier('Object'), j.identifier('values')),
+                [expectArgs[0]]
+              ),
+              j.identifier('some')
+            ),
+            [
+              j.arrowFunctionExpression(
+                [j.identifier('spy')],
+                j.optionalMemberExpression(
+                  j.optionalMemberExpression(
+                    j.memberExpression(j.identifier('spy'), j.identifier('mock')),
+                    j.identifier('calls'),
+                    false,
+                    true
+                  ),
+                  j.identifier('length')
+                )
+              ),
+            ]
+          )
+          matcherArgs[0] = j.literal(true)
+          matcher.name = 'toBe'
+          break
+        }
+      }
+    })
+
   root
     .find(j.CallExpression, {
       // find `jasmine.createSpy(*).and.*()` expressions


Test patch:
diff --git a/src/transformers/expect.test.ts b/src/transformers/expect.test.ts
index d6b0e72..5441374 100644
--- a/src/transformers/expect.test.ts
+++ b/src/transformers/expect.test.ts
@@ -65,13 +65,11 @@ test('maps expect matchers', () => {
       expect(stuff).toExist('message');
       expect(stuff).toBeTruthy();
       expect(stuff).toBeTruthy('message');
-      expect(stuff).toBeTrue();
 
       expect(stuff).toNotExist();
       expect(stuff).toNotExist('message');
       expect(stuff).toBeFalsy();
       expect(stuff).toBeFalsy('message');
-      expect(stuff).toBeFalse();
 
       expect(stuff).toBe(null);
       expect(stuff).toBe(null, 'message');
@@ -96,14 +94,9 @@ test('maps expect matchers', () => {
       expect(stuff).toBeAn(Array);
       expect(new Stuff).toBeAn(Stuff, 'Message');
 
-      expect([1, 2]).toHaveSize(2);
-
       expect(stuff).toNotBeA(Number);
       expect(stuff).toNotBeAn(Array);
 
-      expect(foo).toBePositiveInfinity();
-      expect(foo).toBeNegativeInfinity();
-
       expect(stuff).toMatch({foo: 'bar'});
       expect(stuff).toMatch({foo: 'bar'}, 'message');
       expect(stuff).toMatch('a string');
@@ -118,10 +111,6 @@ test('maps expect matchers', () => {
       expect(stuff).toNotHaveBeenCalled();
       expect(stuff).toNotHaveBeenCalled('msg');
       expect(stuff).toHaveBeenCalledWith('foo', 'bar');
-
-      expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar');
-      expect(mySpy).toHaveBeenCalledBefore(myOtherSpy);
-      expect(mySpyObj).toHaveSpyInteractions()
     });
     `,
     `
@@ -130,13 +119,11 @@ test('maps expect matchers', () => {
       expect(stuff).toBeTruthy();
       expect(stuff).toBeTruthy();
       expect(stuff).toBeTruthy();
-      expect(stuff).toBe(true);
 
       expect(stuff).toBeFalsy();
       expect(stuff).toBeFalsy();
       expect(stuff).toBeFalsy();
       expect(stuff).toBeFalsy();
-      expect(stuff).toBe(false);
 
       expect(stuff).toBe(null);
       expect(stuff).toBe(null);
@@ -161,14 +148,9 @@ test('maps expect matchers', () => {
       expect(stuff).toBeInstanceOf(Array);
       expect(new Stuff).toBeInstanceOf(Stuff);
 
-      expect([1, 2]).toHaveLength(2);
-
       expect(stuff).not.toBeInstanceOf(Number);
       expect(stuff).not.toBeInstanceOf(Array);
 
-      expect(foo).toBe(Infinity);
-      expect(foo).toBe(-Infinity);
-
       expect(stuff).toMatchObject({foo: 'bar'});
       expect(stuff).toMatchObject({foo: 'bar'});
       expect(stuff).toMatch('a string');
@@ -183,10 +165,6 @@ test('maps expect matchers', () => {
       expect(stuff).not.toHaveBeenCalled();
       expect(stuff).not.toHaveBeenCalled();
       expect(stuff).toHaveBeenCalledWith('foo', 'bar');
-
-      expect(mySpy.mock.calls).toEqual([['foo', 'bar']]);
-      expect(Math.min(...mySpy.mock.invocationOrder)).toBeLessThan(Math.min(...myOtherSpy.mock.invocationOrder));
-      expect(Object.values(mySpyObj).some(spy => spy.mock?.calls?.length)).toBe(true)
     });
     `
   )
diff --git a/src/transformers/jasmine-globals.test.ts b/src/transformers/jasmine-globals.test.ts
index 84c419e..58537af 100644
--- a/src/transformers/jasmine-globals.test.ts
+++ b/src/transformers/jasmine-globals.test.ts
@@ -1,5 +1,5 @@
 /* eslint-env jest */
-import { describe } from '@jest/globals'
+import { describe, test } from '@jest/globals'
 import chalk from 'chalk'
 
 import { wrapPlugin } from '../utils/test-helpers'
@@ -14,6 +14,56 @@ beforeEach(() => {
   jest.spyOn(console, 'warn').mockImplementation((v) => consoleWarnings.push(v))
 })
 
+describe('jasmine matchers', () => {
+  test('toBeTrue', () =>
+    expectTransformation('expect(stuff).toBeTrue()', 'expect(stuff).toBe(true)'))
+
+  test('toBeFalse', () =>
+    expectTransformation('expect(stuff).toBeFalse()', 'expect(stuff).toBe(false)'))
+
+  test('toBePositiveInfinity', () =>
+    expectTransformation(
+      'expect(foo).toBePositiveInfinity()',
+      'expect(foo).toBe(Infinity)'
+    ))
+
+  test('toBeNegativeInfinity', () =>
+    expectTransformation(
+      'expect(foo).toBeNegativeInfinity()',
+      'expect(foo).toBe(-Infinity)'
+    ))
+
+  test('toHaveSize', () =>
+    expectTransformation(
+      'expect([1, 2]).toHaveSize(2)',
+      'expect([1, 2]).toHaveLength(2)'
+    ))
+
+  test('toHaveClass', () =>
+    expectTransformation(
+      `expect(element).toHaveClass('active')`,
+      `expect(element.classList.contains('active')).toBe(true)`
+    ))
+
+  test('toHaveBeenCalledOnceWith', () =>
+    expectTransformation(
+      `expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar')`,
+      `expect(mySpy.mock.calls).toEqual([['foo', 'bar']])`
+    ))
+
+  test('toHaveBeenCalledBefore', () =>
+    expectTransformation(
+      'expect(mySpy).toHaveBeenCalledBefore(myOtherSpy)',
+      'expect(Math.min(...mySpy.mock.invocationOrder)).toBeLessThan(Math.min(...myOtherSpy.mock.invocationOrder))'
+    ))
+
+  test('toHaveSpyInteractions', () =>
+    expectTransformation(
+      'expect(mySpyObj).toHaveSpyInteractions()',
+      'expect(Object.values(mySpyObj).some(spy => spy.mock?.calls?.length)).toBe(true)'
+    ))
+})
+
 test('spyOn', () => {
   expectTransformation(
     `