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

Can't mock dependency of dependency #1336

Closed
6 tasks done
christian-bromann opened this issue May 19, 2022 · 12 comments
Closed
6 tasks done

Can't mock dependency of dependency #1336

christian-bromann opened this issue May 19, 2022 · 12 comments

Comments

@christian-bromann
Copy link
Contributor

christian-bromann commented May 19, 2022

Describe the bug

Given I have packageA that depends on packageB which depends on packageC. If I write tests for packageA I can't mock packageC, e.g.:

// package B
import got from 'got'
export default got
// packageA
import packageB from 'packageB'
export default request (url: string) {
    return packageB(url)
}

Now If I want to write tests for packageA I want to be able to mock the dependency of packageB rather than the whole package:

import { vi, ... } from 'vitest'
import packageA from '../src/index.ts'

vi.mock('got', () => { ... })

describe(() => {
    // ...
})

Unfortunately it is impossible to mock got in this case. In Jest however this is possible.

Reproduction

In this example I mock loglevel which is a direct dependency of @wdio/logger. The test should throw an error because the dependency was mocked out with an undefined value but the test passes.

System Info

n/a

Used Package Manager

npm

Validations

@sheremet-va
Copy link
Member

You need to inline that dependency, using deps.inline config option.

It is not inlined by default because of performance reasons.

@christian-bromann
Copy link
Contributor Author

@sheremet-va thanks for the quick response, are you saying doing something like this:

export default defineConfig({
  test: {
    deps: {
      inline: ['loglevel'],
    },
    /* for example, use global to avoid globals imports (describe, test, expect): */
    // globals: true,
  },
});

?

@sheremet-va
Copy link
Member

sheremet-va commented May 19, 2022

@sheremet-va thanks for the quick response, are you saying doing something like this:

You need to inline the dependency that you are using. So, according to you example, you need to inline @wdio/logger.

If you don't inline dependency, it doesn't go through Vite pipeline and can't benefit from our mock system, because it relies on it.

@christian-bromann
Copy link
Contributor Author

I tried this in the Stackblitz example without success.

@sheremet-va
Copy link
Member

They don't bundle ESM, so we cannot mock their call to loglevel. require mocks are not supported in Vitest, because our module resolution is asynchronous.

@christian-bromann
Copy link
Contributor Author

That makes sense. Thanks for the clarification.

@christian-bromann
Copy link
Contributor Author

@sheremet-va ok, I found now what the problem was. The dependency was dynamically imported, so e.g. ModuleA depends on ModuleB which depends on ModuleC or ModuleD depending on whether we run in the browser or Node.js environment. If we then have something like this:

if (!EnvRequestLib) {
    EnvRequestLib = process?.versions?.node
        ? (await import('./node')).default
        : (await import('./browser')).default
}

return new EnvRequestLib(method, endpoint, body, isHubCommand)

Then vitest is not able to mock neither ModuleC nor ModuleD. Is this something you think vitest should/can support?

@sheremet-va
Copy link
Member

Vitest supports mocking dynamic modules

@christian-bromann
Copy link
Contributor Author

Vitest supports mocking dynamic modules

But not if they are inlined dependencies. I am trying to build a reproducible but it is quite difficult.

@sheremet-va
Copy link
Member

Vitest supports mocking dynamic modules

But not if they are inlined dependencies. I am trying to build a reproducible but it is quite difficult.

Mocking only works with files, that are processed by Vitest. Usually, node modules are not processed. If you use “deps.inline”, then every import inside that dependency will work with mocking system.

@christian-bromann
Copy link
Contributor Author

@sheremet-va I kindly request to re-open the issue. I went a long way to figure out the problem: you are right that using deps.inline helps to mock a dependency of a dependency. I made a stackblitz example of that here with the original package sources here.

However for some reason this was still not working in my project and and seems to be relative with linking NPM packages when working in Monorepos, e.g. Lerna. Even if setting deps.inline: true it won't be able to resolve the mock and an import returns the original package. So in the example from above if a-vitest-test-modulea would be linked into node_modules the test would fail.

@christian-bromann
Copy link
Contributor Author

Nevermind, it started to work for random reasons after debugging vitest. Not sure what has changed.

@github-actions github-actions bot locked and limited conversation to collaborators Jun 17, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants