Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ts-jest] Error using createMock alongside createTestingModule and @Inject('token') #651

Closed
iacobus opened this issue Sep 29, 2023 · 2 comments

Comments

@iacobus
Copy link

iacobus commented Sep 29, 2023

Hi,

I'm encountering what I think is the same problem as this StackOverflow issue. A more generalized repro scenario looks like:

import { createMock } from '@golevelup/ts-jest'
import { Test, TestingModule } from '@nestjs/testing'
import { Injectable, Inject } from '@nestjs/common'

class BarProvider {}

@Injectable()
class FooService {
  constructor(
    @Inject('fooProvider') private readonly foo: string,
    private readonly bar: BarProvider
  ) {}
}

describe('TestModule', () => {
  let module: TestingModule

  beforeEach(async () => {
    module = await Test.createTestingModule({
      imports: [],
      providers: [FooService]
    })
      .useMocker(createMock)
      .compile()
  })

  it('works', () => {
    const subject = module.get(FooService)
    expect(1).toEqual(1) // ... or whatever
  })
})

Running the above yields the following error:

 TestModule
    ✕ works (11 ms)

  ● TestModule › works

    TypeError: Cannot create proxy with a non-object as target or handler

      at TestingInjector.createMock [as mocker] (../../node_modules/@golevelup/ts-jest/src/mocks.ts:67:17)
      at TestingInjector.resolveComponentInstance (../../node_modules/@nestjs/testing/testing-injector.js:24:45)
      at resolveParam (../../node_modules/@nestjs/core/injector/injector.js:120:38)
          at async Promise.all (index 0)
      at TestingInjector.resolveConstructorParams (../../node_modules/@nestjs/core/injector/injector.js:135:27)
      at TestingInjector.loadInstance (../../node_modules/@nestjs/core/injector/injector.js:61:13)
      at TestingInjector.loadProvider (../../node_modules/@nestjs/core/injector/injector.js:88:9)
      at ../../node_modules/@nestjs/core/injector/instance-loader.js:56:13
          at async Promise.all (index 3)

Notice how we inject two dependencies, one using the class reference (BarProvider), and the other using a token reference (fooProvider).
Tracking this down it simply boils down to createMock creating a Proxy object, but receiving a string as partial, and the Proxy constructor blowing up because it needs an object. In the above example, if you remove the fooProvider dependency from the FooService constructor, the test passes.

I'm not sure what's the best course of action. My expectation is that all dependencies are mocked regardless of whether they are injected via class or via token. Is that sensible? The author of the Stack Overflow issue resolves the problem by adding another provider that provides the dependency, but that seems to defeat the purpose of mocking.

Thoughts?

Thanks!

@micalevisk
Copy link

micalevisk commented Sep 30, 2023

this works:

useMocker(() => createMock())

that's because, in your example, createMock will be called like this by nestjs: createMock('fooProvider') which ends up doing new Proxy('fooProvider', ...), which leads to that error because Proxy expects a non-primitive value as a target.

@iacobus
Copy link
Author

iacobus commented Oct 25, 2023

@underfisk — sorry it took me a while to close the loop. Thanks for the tip, that's what I ended up doing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants