Search code examples
typescriptvue.jsdependency-injectionpiniavitest

Use dependency Injection with vue / vitest


  1. My Setup
  • Vue 3 application
  • Pinia stores
  • In my main.ts : app.use(myPlugin)
  • In MyPlugin.ts : I conditionally create and provide a repository (MyRepo) to the application based on some environment conditions. This repository can either interact with an API or provide fake data for development and testing purposes.
  • In myStore.ts :
defineStore('myStore', () => {
  const repo = inject<MyRepoInterface>('myRepo');
  // ....
})
  1. My problem

I'm facing an issue when writing tests that depend on a store which itself depends on myStore. When the inject function is called within my test, I receive the following warning: [Vue warn]: inject() can only be used inside setup() or functional components. Additionally, the repo is undefined, resulting in errors.

  1. My question

I'm looking for a solution to provide the repository during the setup of my testing framework (Vitest). This way, I can inject it into my code both during normal application runtime and when running tests. How can I achieve this?


Any criticism about the way I'm trying to achieve Dependency Injection is welcome. Thank you !


Solution

  • Pinia stores are singletons that are instantiated on the first call of store function. That inject is used in Pinia store setup function means that the first usage should be inside Vue component setup or contemporary lifecycle hooks, while there's no such limitation for Pinia stores in general.

    It also would be impossible to define a store this way with store options instead of function, while they are generally interchangeable.

    A more flexible and test-friendly way is to use explicit dependency injection in store method:

    let repo = ref(null as unknown as MyRepoInterface);
    
    let init = (cfg: { repo: MyRepoInterface }) => {
      repo.value = cfg.repo;
    })
    

    And in App component:

    useMyStore().init({
      repo: inject<MyRepoInterface>('myRepo')
    })