javascriptsveltejsdomtesting-libraryvitest

How can I reset the jsdom instance when using vitest in order to test a History-based router?


I'd like to do some integration testing of my svelte + page.js-based router using vitest, but I'm running into an issue where the jsdom instance only updates correctly once per test file.

In the following setup, either test will pass when run with .only or if I split each test into its own file. But when they run in sequence, the second one will always fail. Inspecting the DOM with screen.debug() reveals that it's empty, and calls to act or tick don't seem to do anything.

I suspect it has something to do with how jsdom is interacting with the History API, but I'm not sure where to go from here.

Root.svelte

<script>
  import page from 'page'

  import SignIn from './SignIn/SignIn.svelte'
  import Upload from './Upload/Upload.svelte'
  import { authenticationToken } from './Root.stores.js'

  let currentPage

  page('/', () => {
    page.redirect('/sign-in')
  })

  page('/sign-in', () => {
    currentPage = SignIn
  })

  page('/upload', () => {
    if ($authenticationToken === null) {
      return page.redirect('/sign-in')
    }

    currentPage = Upload
  })

  page.start()
</script>

<svelte:component this={ currentPage } />

Root.svelte.test.js

import page from 'page'
import Root from './Root.svelte'
import { authenticationToken } from './Root.stores.js'

it('redirects to sign in when not authenticated', async () => {
  vi.spyOn(page, 'redirect')
  authenticationToken.set(null)

  const { act } = setupComponent(Root)
  await act(() => page('/upload'))

  expect(page.redirect).toHaveBeenCalledWith('/sign-in')
})

it('displays the upload screen when authenticated', async () => {
  authenticationToken.set('token')

  const { act } = setupComponent(Root)
  await act(() => page('/upload'))

  expect(document.getElementById('upload')).toBeInTheDocument()
})

Other Research

The issue is similar to this one in the jest project. In that issue, the recommendation was to call jsdom.reconfigure() in a beforeEach block, but I don't know how to get a hold of the jsdom instance in vitest in order to try that.

Any ideas or alternative approaches welcome, thanks!


Solution

  • Since version 1.3.0, Vitest exposes a jsdom global variable, so it should be possible to call

    jsdom.reconfigure(/* ... */)
    

    See also https://vitest.dev/config/#environment (scroll to the bottom of the section)