Repository: skovhus/jest-codemods
Pull request #621 (2024-09-17 08:32:07)

fix(jasmine): negated jasmine matchers should be handled

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/skovhus/jest-codemods/pull/621?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.21%. 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 [(`5d53edd`)](https://app.codecov.io/gh/skovhus/jest-codemods/commit/5d53edd55ecc171b694f2c952453f40d80923269?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Kenneth+Skovhus).
> Report is 79 commits behind head on main.

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


```diff
@@            Coverage Diff             @@
##             main     #621      +/-   ##
==========================================
+ Coverage   92.38%   95.21%   +2.82%     
==========================================
  Files          26       27       +1     
  Lines        1944     2089     +145     
  Branches      405      439      +34     
==========================================
+ Hits         1796     1989     +193     
+ 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/621?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/jasmine-globals.ts b/src/transformers/jasmine-globals.ts
index 5692704..65a25b7 100644
--- a/src/transformers/jasmine-globals.ts
+++ b/src/transformers/jasmine-globals.ts
@@ -23,13 +23,19 @@ export default function jasmineGlobals(fileInfo, api, options) {
       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
+      const isNegatedMatcher = path.node.property.name === 'not'
+      const matcher = isNegatedMatcher ? path.parent.node.property : path.node.property
 
-      switch (matcherName) {
+      const expectArgs = isNegatedMatcher
+        ? path.parent.node.object.object.arguments
+        : path.node.object.arguments
+
+      const matcherNode = isNegatedMatcher
+        ? path.parent.parentPath.node
+        : path.parentPath.node
+      const matcherArgs = matcherNode.arguments ?? []
+
+      switch (matcher.name) {
         case 'toBeTrue': {
           matcherArgs[0] = j.literal(true)
           matcher.name = 'toBe'


Test patch:
diff --git a/src/transformers/jasmine-globals.test.ts b/src/transformers/jasmine-globals.test.ts
index bdd39b1..6e1b215 100644
--- a/src/transformers/jasmine-globals.test.ts
+++ b/src/transformers/jasmine-globals.test.ts
@@ -18,50 +18,110 @@ describe('jasmine matchers', () => {
   test('toBeTrue', () =>
     expectTransformation('expect(stuff).toBeTrue()', 'expect(stuff).toBe(true)'))
 
+  test('not.toBeTrue', () =>
+    expectTransformation('expect(stuff).not.toBeTrue()', 'expect(stuff).not.toBe(true)'))
+
   test('toBeFalse', () =>
     expectTransformation('expect(stuff).toBeFalse()', 'expect(stuff).toBe(false)'))
 
+  test('not.toBeFalse', () =>
+    expectTransformation(
+      'expect(stuff).not.toBeFalse()',
+      'expect(stuff).not.toBe(false)'
+    ))
+
   test('toBePositiveInfinity', () =>
     expectTransformation(
       'expect(foo).toBePositiveInfinity()',
       'expect(foo).toBe(Infinity)'
     ))
 
+  test('not.toBePositiveInfinity', () =>
+    expectTransformation(
+      'expect(foo).not.toBePositiveInfinity()',
+      'expect(foo).not.toBe(Infinity)'
+    ))
+
   test('toBeNegativeInfinity', () =>
     expectTransformation(
       'expect(foo).toBeNegativeInfinity()',
       'expect(foo).toBe(-Infinity)'
     ))
 
+  test('not.toBeNegativeInfinity', () =>
+    expectTransformation(
+      'expect(foo).not.toBeNegativeInfinity()',
+      'expect(foo).not.toBe(-Infinity)'
+    ))
+
   test('toHaveSize', () =>
     expectTransformation(
       'expect([1, 2]).toHaveSize(2)',
       'expect([1, 2]).toHaveLength(2)'
     ))
 
+  test('not.toHaveSize', () =>
+    expectTransformation(
+      'expect([1]).not.toHaveSize(2)',
+      'expect([1]).not.toHaveLength(2)'
+    ))
+
   test('toHaveClass', () =>
     expectTransformation(
       `expect(element).toHaveClass('active')`,
       `expect(element.classList.contains('active')).toBe(true)`
     ))
 
+  test('not.toHaveClass', () =>
+    expectTransformation(
+      `expect(element).not.toHaveClass('danger')`,
+      `expect(element.classList.contains('danger')).not.toBe(true)`
+    ))
+
   test('toHaveBeenCalledOnceWith', () =>
     expectTransformation(
       `expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar')`,
       `expect(mySpy.mock.calls).toEqual([['foo', 'bar']])`
     ))
 
+  test('not.toHaveBeenCalledOnceWith', () =>
+    expectTransformation(
+      `expect(mySpy).not.toHaveBeenCalledOnceWith('foo', 'bar')`,
+      `expect(mySpy.mock.calls).not.toEqual([['foo', 'bar']])`
+    ))
+
   test('toHaveBeenCalledBefore', () =>
     expectTransformation(
       'expect(mySpy).toHaveBeenCalledBefore(myOtherSpy)',
       'expect(Math.min(...mySpy.mock.invocationOrder)).toBeLessThan(Math.min(...myOtherSpy.mock.invocationOrder))'
     ))
 
+  test('not.toHaveBeenCalledBefore', () =>
+    expectTransformation(
+      'expect(mySpy).not.toHaveBeenCalledBefore(myOtherSpy)',
+      'expect(Math.min(...mySpy.mock.invocationOrder)).not.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('not.toHaveSpyInteractions', () =>
+    expectTransformation(
+      'expect(mySpyObj).not.toHaveSpyInteractions()',
+      'expect(Object.values(mySpyObj).some(spy => spy.mock?.calls?.length)).not.toBe(true)'
+    ))
+
+  test.each([
+    ['toHaveBeenCalled', 'expect(spy).not.toHaveBeenCalled()'],
+    ['toBeNull', 'expect(result).not.toBeNull()'],
+    ['toBe', `expect(foo).not.toBe('')`],
+    ['toEqual', 'expect(foo).not.toEqual(expectedState)'],
+  ])('not.%s', (_name, defaultMatcherStatement) => {
+    expectTransformation(defaultMatcherStatement, defaultMatcherStatement)
+  })
 })
 
 test('spyOn', () => {