ts-mockito icon indicating copy to clipboard operation
ts-mockito copied to clipboard

New releases (2.6.7+) break tests

Open Jank1310 opened this issue 1 year ago • 32 comments

It seems that recent releases >= 2.6.7 introduced some bugs (if used with vitest?).

For example this does not work in 2.7.1 with vitest@1 or vitest@2:

import EventEmitter from 'node:events';
import {mock} from '@typestrong/ts-mockito';
import {describe, expect, it} from 'vitest';

class EventEmitterTest extends EventEmitter {}

describe('ts-mockito-test', () => {
	const domainEventPublisherMock = mock(EventEmitterTest);
	it('should mock', () => {
		expect(domainEventPublisherMock).toBeDefined();
	});
});

Errors

 FAIL  src/mocktest.spec.ts [ src/mocktest.spec.ts ]
SyntaxError: Unexpected token (11:29)
 ❯ toParseError node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parse-error.ts:74:19
 ❯ Parser.raise node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/tokenizer/index.ts:1497:19
 ❯ Parser.unexpected node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/tokenizer/index.ts:1537:16
 ❯ Parser.parseClassMemberWithIsStatic node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/statement.ts:2062:12
 ❯ Parser.parseClassMember node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/statement.ts:1881:10
 ❯ callback node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/statement.ts:1794:14
 ❯ Parser.withSmartMixTopicForbiddingContext node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:3105:14
 ❯ Parser.parseClassBody node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/statement.ts:1766:10
 ❯ Parser.parseClass node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/statement.ts:1717:22
 ❯ Parser.parseStatementContent node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/statement.ts:474:21

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { code: 'BABEL_PARSER_SYNTAX_ERROR', reasonCode: 'UnexpectedToken', loc: { line: 11, column: 29, index: 223, constructor: 'Function<Position>' }, pos: 223, clone: 'Function<clone>', details: { expected: null } }
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯

Everything works without problems with @typestrong/[email protected]

Jank1310 avatar Jul 16 '24 09:07 Jank1310

Seems not to be related to vitest. The library tests fail too if the following test is added:

import { EventEmitter } from "events";
import { mock } from "../src/ts-mockito";

class TestEmitter extends EventEmitter {}

describe("ts-mockito-test", () => {
  const mocked = mock(TestEmitter);

  it("should mock", () => {
    expect(mocked).toBeDefined();
  });
});

Output

Summary of all failing tests
 FAIL  test/bug.spec.ts
  ● Test suite failed to run

    SyntaxError: Unexpected token (11:29)

      at constructor (node_modules/@babel/parser/src/parse-error.ts:74:19)
      at Parser.toParseError [as raise] (node_modules/@babel/parser/src/tokenizer/index.ts:1497:19)
      at Parser.raise [as unexpected] (node_modules/@babel/parser/src/tokenizer/index.ts:1537:16)
      at Parser.unexpected [as parseClassMemberWithIsStatic] (node_modules/@babel/parser/src/parser/statement.ts:2054:12)
      at Parser.parseClassMemberWithIsStatic [as parseClassMember] (node_modules/@babel/parser/src/parser/statement.ts:1873:10)
      at parseClassMember (node_modules/@babel/parser/src/parser/statement.ts:1786:14)
      at Parser.callback [as withSmartMixTopicForbiddingContext] (node_modules/@babel/parser/src/parser/expression.ts:3106:14)
      at Parser.withSmartMixTopicForbiddingContext [as parseClassBody] (node_modules/@babel/parser/src/parser/statement.ts:1758:10)
      at Parser.parseClassBody [as parseClass] (node_modules/@babel/parser/src/parser/statement.ts:1709:22)
      at Parser.parseClass [as parseStatementContent] (node_modules/@babel/parser/src/parser/statement.ts:471:21)

Jank1310 avatar Jul 16 '24 09:07 Jank1310

Yes, we changed the way we parse class code. I'll add this test to the ts-mockito test suite and verify that it works.

roypeled avatar Jul 18 '24 07:07 roypeled

I just published 2.7.2, try to see if it works for you

roypeled avatar Jul 18 '24 08:07 roypeled

Works for the given test case 🎉 Unfortunately there is another error for anonymous classes:

Serialized Error: { code: 'BABEL_PARSER_SYNTAX_ERROR', reasonCode: 'MissingClassName', loc: { line: 1, column: 6, index: 6, constructor: 'Function<Position>' }, pos: 6, clone: 'Function<clone>', details: {} }

Test case

import {mock} from '@typestrong/ts-mockito';
import {describe, expect, it} from 'vitest';

const TestClass = class {
	private readonly foo = 'abc';
};

describe('anonymous class test', () => {
	const testMock = mock(TestClass);

	it('should be defined', () => {
		expect(testMock).toBeDefined();
	});
});

Jank1310 avatar Jul 18 '24 12:07 Jank1310

I see, if you have any other cases of broken tests I’ll add them all. Thanks for being patient with this release!!

edit - this is roypeled, just on my other account

rezoled avatar Jul 18 '24 12:07 rezoled

I will, thank you for your great work! :)

Jank1310 avatar Jul 18 '24 13:07 Jank1310

@rezoled You're doing an amazing work! Unfortunately I'm not using the lib myself anymore (career changes) my attention is low, so your recent contributions are the best thing happened since the fork! 🙏

LironHazan avatar Jul 20 '24 07:07 LironHazan

Works for the given test case 🎉 Unfortunately there is another error for anonymous classes:

Serialized Error: { code: 'BABEL_PARSER_SYNTAX_ERROR', reasonCode: 'MissingClassName', loc: { line: 1, column: 6, index: 6, constructor: 'Function<Position>' }, pos: 6, clone: 'Function<clone>', details: {} }

Test case

import {mock} from '@typestrong/ts-mockito';
import {describe, expect, it} from 'vitest';

const TestClass = class {
	private readonly foo = 'abc';
};

describe('anonymous class test', () => {
	const testMock = mock(TestClass);

	it('should be defined', () => {
		expect(testMock).toBeDefined();
	});
});

Hay @Jank1310, would you mind placing a breakpoint at the const testMock = mock(TestClass); line and print here to compiled code for the TestClass? I'm trying to run this code locally and it works, probably because you are using vitest and I'm using Jest. If I could get the compiled code than I would be able to understand what went wrong.

In the meanwhile I'm testing other solutions

roypeled avatar Jul 21 '24 08:07 roypeled

@Jank1310 can you try the latest version?

roypeled avatar Jul 21 '24 13:07 roypeled

I'm not sure what you exactly need, but here is the value for TestClass

class {
  constructor() {
    this.foo = "abc";
  }
}

You can test it on master with the following steps:

  • npm i vitest
  • Add anonymous test case
  • npx vitest ./test/anonymous.spec.ts

=> Still throws A class name is required

Anonymous test case

import { describe, it } from "vitest";
import { mock } from "../src/ts-mockito";
const TestClass = class {
  private readonly foo = "abc";
};

describe("anonymous class test", () => {
  const testMock = mock(TestClass);

  it("should be defined", () => {
    expect(testMock).toBeDefined();
  });
});

The latest version throws the following error for several test cases in my project (not exactly sure why this happens 😕 ):

SyntaxError: Unexpected token, expected "," (73:47)
 ❯ toParseError node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parse-error.ts:74:19
 ❯ Parser.raise node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/tokenizer/index.ts:1497:19
 ❯ Parser.unexpected node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/tokenizer/index.ts:1537:16
 ❯ Parser.expect node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/util.ts:150:28
 ❯ Parser.parseObjectLike node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:2070:14
 ❯ Parser.parseExprAtom node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:1193:21
 ❯ Parser.parseExprSubscripts node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:709:23
 ❯ Parser.parseUpdate node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:686:21
 ❯ Parser.parseMaybeUnary node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:649:23
 ❯ Parser.parseMaybeUnaryOrPrivate node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:390:14

Jank1310 avatar Jul 22 '24 08:07 Jank1310

With the latest release (2.7.3), we are also seeing errors in our Jest tests:

[2024-07-23T07:58:09.615Z]     SyntaxError: Unexpected token, expected "," (190:54)
[2024-07-23T07:58:09.615Z] 
[2024-07-23T07:58:09.615Z]       33 |
[2024-07-23T07:58:09.615Z]       34 |     beforeEach(() => {
[2024-07-23T07:58:09.615Z]     > 35 |         someVar = mock(SomeClass);
[2024-07-23T07:58:09.615Z]          |                       ^
[2024-07-23T07:58:09.615Z]     TypeError: Cannot read properties of undefined (reading '__tsmockitoMocker')
[2024-07-23T07:58:09.615Z] 
[2024-07-23T07:58:09.615Z]       38 |
[2024-07-23T07:58:09.615Z]       39 |     afterEach(() => {
[2024-07-23T07:58:09.615Z]     > 40 |         reset(someVar);
[2024-07-23T07:58:09.615Z]          |              ^

ghost91- avatar Jul 23 '24 08:07 ghost91-

Thanks for the examples everyone, I'm working on a solution for this.

roypeled avatar Jul 23 '24 16:07 roypeled

Please try version 2.7.5, sorry again for this process. We changed the way ts-mockito parses classes, and it introduces several new edge cases.

roypeled avatar Jul 23 '24 17:07 roypeled

@ghost91- , if it still doesn't work for you, can you provide the test and class being tested here?

roypeled avatar Jul 23 '24 17:07 roypeled

2.7.5 throws the following error if executed with vitest

SyntaxError: Unexpected token, expected "," (11:52)
 ❯ toParseError node_modules/@babel/parser/src/parse-error.ts:74:19
 ❯ Parser.raise node_modules/@babel/parser/src/tokenizer/index.ts:1497:19
 ❯ Parser.unexpected node_modules/@babel/parser/src/tokenizer/index.ts:1537:16
 ❯ Parser.expect node_modules/@babel/parser/src/parser/util.ts:150:28
 ❯ Parser.parseObjectLike node_modules/@babel/parser/src/parser/expression.ts:2070:14
 ❯ Parser.parseExprAtom node_modules/@babel/parser/src/parser/expression.ts:1193:21
 ❯ Parser.parseExprSubscripts node_modules/@babel/parser/src/parser/expression.ts:709:23
 ❯ Parser.parseUpdate node_modules/@babel/parser/src/parser/expression.ts:686:21
 ❯ Parser.parseMaybeUnary node_modules/@babel/parser/src/parser/expression.ts:649:23
 ❯ Parser.parseMaybeUnaryOrPrivate node_modules/@babel/parser/src/parser/expression.ts:390:14

Test Case

import { describe, expect, it } from "vitest";
import { mock } from "../src/ts-mockito";

export class SimpleClass {
  public async returnAsyncValue(): Promise<number> {
    return 0;
  }
}

describe("AsyncFunctions", () => {
  const simpleMock = mock(SimpleClass);

  it("should run", async () => {
    expect(simpleMock).toBeDefined();
  });
});

The reason seems to be the async function decleration

Jank1310 avatar Jul 24 '24 06:07 Jank1310

@Jank1310 thanks! I missed adding async functions to the tests. I'm preparing a fix

roypeled avatar Jul 24 '24 07:07 roypeled

@Jank1310 please try 2.7.6, hopefully this is the final fix for this issue!

roypeled avatar Jul 24 '24 07:07 roypeled

It fixes most errors but some errors still remain :/

Error:

SyntaxError: Unexpected token, expected "," (1282:57)
 ❯ toParseError node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parse-error.ts:74:19
 ❯ Parser.raise node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/tokenizer/index.ts:1497:19
 ❯ Parser.unexpected node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/tokenizer/index.ts:1537:16
 ❯ Parser.expect node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/util.ts:151:12
 ❯ Parser.parseObjectLike node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:2069:14
 ❯ Parser.parseExprAtom node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:1193:21
 ❯ Parser.parseExprSubscripts node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:709:23
 ❯ Parser.parseUpdate node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:686:21
 ❯ Parser.parseMaybeUnary node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:649:23
 ❯ Parser.parseMaybeUnaryOrPrivate node_modules/.pnpm/@[email protected]/node_modules/@babel/parser/src/parser/expression.ts:390:14

For the following test case

import { WorkflowClient } from "@temporalio/client";
import { describe, expect, it } from "vitest";
import { mock } from "../src/ts-mockito";

describe("Temporal WorkflowClient", () => {
  const simpleMock = mock(WorkflowClient);

  it("should run", async () => {
    expect(simpleMock).toBeDefined();
  });
});

It works if mock is changed to const simpleMock = mock<WorkflowClient>();

Jank1310 avatar Jul 24 '24 07:07 Jank1310

Testing. Probably more edge cases.

EDIT - found the bug, generator functions :) working on a fix

roypeled avatar Jul 24 '24 08:07 roypeled

Ok, try 2.7.7 please

roypeled avatar Jul 24 '24 08:07 roypeled

Looks good, no more errors 🎉

Jank1310 avatar Jul 24 '24 11:07 Jank1310

Finally! Thanks again for the patience and providing me with the edge cases!

roypeled avatar Jul 24 '24 12:07 roypeled

Still facing the issue SyntaxError: Unexpected token, expected "," with 2.7.7 and this line :

rootElement = instance(mock({}));
                           ^

meriouma avatar Jul 24 '24 20:07 meriouma

Please try @rezoled 2.7.8

roypeled avatar Jul 25 '24 07:07 roypeled

2.7.8. is still broken for us:

    TypeError: Cannot read properties of null (reading 'type')

      64 |
      65 |         beforeEach(() => {
    > 66 |             containerMock = mock(Container);
    TypeError: Cannot read properties of undefined (reading '__tsmockitoMocker')

      76 |
      77 |         afterEach(() => {
    > 78 |             reset(containerMock);
         |                  ^
      79 |             reset(contextMock);
      80 |         });
      81 |

where Container is imported from inversify.

ghost91- avatar Jul 25 '24 07:07 ghost91-

@ghost91- Try 2.7.9

roypeled avatar Jul 25 '24 09:07 roypeled

2.7.9 seems to work for the case I provided. Thanks!

meriouma avatar Jul 25 '24 14:07 meriouma

Looks good now, as far as I can tell. Thanks!

ghost91- avatar Jul 25 '24 16:07 ghost91-

Hey @roypeled,

we have found another problem: When using proxys (possibly only in combination with ts experimental decorators), we still get an error similar the above. It still works correctly in v2.6.6.

If necessary, I can try to create a minimal reproduction example.

ghost91- avatar Aug 16 '24 07:08 ghost91-

Hey @ghost91- , thanks for letting me know. I’ll take a look at proxies. If you can, would you mind posting an example of a code with proxies that you are testing? That would help my identity the problem, thanks!

roypeled avatar Aug 16 '24 08:08 roypeled