Skip to content

Broken test isolation of VueRouter instances #210

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

Closed
maxarndt opened this issue Feb 18, 2021 · 9 comments · Fixed by #239
Closed

Broken test isolation of VueRouter instances #210

maxarndt opened this issue Feb 18, 2021 · 9 comments · Fixed by #239
Labels
bug Something isn't working released

Comments

@maxarndt
Copy link

Describe the bug A clear and concise description of what the bug is.

VueRouter instances are not erased properly after completing a test case.

To Reproduce Steps to reproduce the behavior:

git clone [email protected]:maxarndt/vue-testing-library.git
npm i
npm test

Expected behavior

All tests should pass.

Screenshots

 FAIL  src/__tests__/vue-router.js
   full app rendering/navigating (51 ms)
   another app rendering/navigating (13 ms)
   setting initial route (6 ms)

   another app rendering/navigating

    TestingLibraryElementError: Unable to find an element with the text: /you are home/i. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    <body>
      <div>
        <div>
          <a
            class="router-link-active"
            data-testid="home-link"
            href="#/"
          >

        Home

          </a>

          <a
            aria-current="page"
            class="router-link-exact-active router-link-active"
            data-testid="about-link"
            href="#/about"
          >

        About

          </a>

          <div>
            You are on the about page
          </div>

          <div
            data-testid="location-display"
          >
            /about
          </div>
        </div>
      </div>
    </body>

      29 |   const {getByTestId, getByText} = render(App, {routes})
      30 |
    > 31 |   expect(getByText(/you are home/i)).toBeInTheDocument()
         |          ^
      32 |   expect(getByTestId('location-display')).toHaveTextContent('/')
      33 |
      34 |   await fireEvent.click(getByTestId('about-link'))

      at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:37:19)
      at node_modules/@testing-library/dom/dist/query-helpers.js:90:38
      at node_modules/@testing-library/dom/dist/query-helpers.js:62:17
      at getByText (node_modules/@testing-library/dom/dist/query-helpers.js:111:19)
      at _callee2$ (src/__tests__/vue-router.js:31:10)
      at tryCatch (node_modules/regenerator-runtime/runtime.js:63:40)
      at Generator.invoke [as _invoke] (node_modules/regenerator-runtime/runtime.js:293:22)
      at Generator.next (node_modules/regenerator-runtime/runtime.js:118:21)
      at asyncGeneratorStep (node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
      at _next (node_modules/@babel/runtime/helpers/asyncToGenerator.js:25:9)
      at node_modules/@babel/runtime/helpers/asyncToGenerator.js:32:7
      at Object.<anonymous> (node_modules/@babel/runtime/helpers/asyncToGenerator.js:21:12)

Related information:

  • @testing-library/vue version: HEAD at 7bef579
  • Vue version: "vue": "^2.6.12"
  • node version: v12.18.4
  • npm version: 6.14.9

Additional context

I just added two assertions to an already existent test case and duplicated the test to be executed twice in a row (see maxarndt@306550f).

Both tests should pass if the testing environment is cleaned up properly.
Unfortunately this is not the case.

@maxarndt maxarndt added the bug Something isn't working label Feb 18, 2021
@ph-fritsche
Copy link
Member

What I've found out so far:

render creates a new VueRouter.
If you inspect the currentRoute on that VueRouter it is / as expected. If you push a route onto it, everything behaves as expected.
It seems localVue passes down the route from the test before while VueRouter is initialized with a new history.

We should try to break down the behavior of VueRouter inside createLocalVue and check with them if the carry over from one local vue instance to another is by design.

@afontcu
Copy link
Member

afontcu commented Feb 22, 2021

Hi!

Yeah, this mostly looks like a bug on VTU' localVue… mind opening an issue there?

Thanks for this!

@kerryboyko
Copy link

render creates a new VueRouter.
If you inspect the currentRoute on that VueRouter it is / as expected. If you push a route onto it, everything behaves as expected.

Can you explain how to push a route on to the VueRouter created by render()? I'm trying to test a component that gets a route parameter and it currently is not working.

blimmer added a commit to blimmer/vue-testing-library that referenced this issue Jun 23, 2021
@blimmer
Copy link
Contributor

blimmer commented Jun 23, 2021

@maxarndt - I opened up #238 as a proposed solution to fix this issue. I also tested it against your fork and confirmed that this fix resolves the problem you surfaced.

Alternatively, as a quicker solution, you can set up a global beforeEach (via setupFilesAfterEnv) that resets the hash route before each test. e.g.,

// jest.config.js
module.exports = {
  setupFilesAfterEnv: ['./jest.setup.js'],
};
// ./jest.setup.js
beforeEach(() => {
  window.location.replace('http://localhost/');
});

@github-actions
Copy link

🎉 This issue has been resolved in version 5.8.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@blimmer
Copy link
Contributor

blimmer commented Jun 29, 2021

@maxarndt - I ran into something weird today with the workaround I posted above. It appears that Vue Router adds a popstate listener to the global JSDOM window in hash mode. These popstate listeners are not cleaned up between tests, which caused additional "leaking" behaviors between tests.

Because of this, I recommend passing an instantiated router that uses abstract mode instead of resetting the window.location.

@maxarndt
Copy link
Author

@blimmer thank you for your hard work on this!

I tried to use an instantiated router that uses abstract mode for my tests and stumbled across vuejs/vue-router#729.

In abstract mode, when the application boots it will be in a "nowhere" state until you explicitly tell the router where it is.

So I ended up using a custom render function to ensure my app behaves as using history or hash router mode.

import { render } from '@testing-library/vue'
import VueRouter from 'vue-router'

import { routes } from '@/src/router'
import App from '@/src/App'

export async function renderApp () {
  const router = new VueRouter({
    mode: 'abstract',
    routes,
  })

  const renderResult = render(App, {
    routes: router,
  })

  await router.push('/')
  return renderResult
}

Do you think it's worth mentioning in the FAQ section that abstract mode comes with this pitfall?

@blimmer
Copy link
Contributor

blimmer commented Jun 30, 2021

No problem! I agree that the initial push is useful for the FAQ. I opened testing-library/testing-library-docs#881 for that improvement. Additionally - I tagged you in that PR with a contribution opportunity if you have the time!

@github-actions
Copy link

github-actions bot commented Jun 8, 2022

🎉 This issue has been resolved in version 6.6.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working released
Projects
None yet
5 participants