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

Amazing new locators in 2.1 beta don't seem to work with the interactivity API #6449

Open
6 tasks done
xeger opened this issue Sep 3, 2024 · 12 comments · Fixed by #6480
Open
6 tasks done

Amazing new locators in 2.1 beta don't seem to work with the interactivity API #6449

xeger opened this issue Sep 3, 2024 · 12 comments · Fixed by #6480
Labels
feat: browser Issues and PRs related to the browser runner p4-important Violate documented behavior or significantly improves performance (priority)

Comments

@xeger
Copy link

xeger commented Sep 3, 2024

Describe the bug

Also filed as vitest/vitest-browser-react#1 but I am cross posting here for visibility purposes.

It seems that @vitest/browser/context isn't properly coordinating with vitest-browser-react. The React rendering and verification work well by themselves, but when I try to fire any user events, the userEvent imported from @vitest/browser/context fails with an error.

Seems like the two pieces of @vitest/browser aren't communicating with ech other. (I know that vitest-browser-react is a separate package, but it integrates tightly with @vitest/browser, and in this case, the integration seems to be not quite right.)

Troubleshooting

👎 Tried swapping the order of render vs. setup
👎 Tried const user = userEvent; in case the setup is unnecessary

Reproduction

import { page, userEvent } from '@vitest/browser/context';
import { beforeEach, describe, expect, test } from 'vitest';

test('reproduction', () => {
  const user = userEvent.setup();
  const screen = page.render(<span>hello, world</span>);
  await user.hover(page.getByRole('button'));
});

This results in:

reproduction
Error: Could not determine window of node. Node was [object Object]
 - /src/__tests__/reproduction.test.tsx:7:2

System Info

System:
    OS: macOS 14.6.1
    CPU: (12) arm64 Apple M3 Pro
    Memory: 1.79 GB / 36.00 GB
    Shell: 3.7.0 - /opt/homebrew/bin/fish
  Binaries:
    Node: 20.11.0 - ~/.asdf/installs/nodejs/20.11.0/bin/node
    npm: 10.8.2 - ~/.asdf/plugins/nodejs/shims/npm
  Browsers:
    Chrome: 128.0.6613.114
    Chrome Canary: 130.0.6694.0
    Safari: 17.6
  npmPackages:
    @vitejs/plugin-react: ^4.2.1 => 4.3.1 
    @vitest/browser: 2.1.0-beta.6 => 2.1.0-beta.6 
    @vitest/coverage-istanbul: 2.1.0-beta.6 => 2.1.0-beta.6 
    @vitest/runner: 2.1.0-beta.6 => 2.1.0-beta.6 
    vite: ^5.2.0 => 5.4.2 
    vitest: 2.1.0-beta.6 => 2.1.0-beta.6

Used Package Manager

npm

Validations

@sheremet-va
Copy link
Member

await user.hover(page.getByRole('button'));

There is no button in your reproduction. The error I get is different:

TimeoutError: locator.hover: Timeout 1000ms exceeded.

Please, provide a runnable reproduction (code repo or stackblitz link)

Copy link

github-actions bot commented Sep 6, 2024

Hello @xeger. Please provide a minimal reproduction using a GitHub repository or StackBlitz (you can also use examples). Issues marked with needs reproduction will be closed if they have no activity within 3 days.

@xeger
Copy link
Author

xeger commented Sep 9, 2024

I am unable to create a standalone reproduction of the exact error.

Here's a gist that produces another, also seemingly valid issue.

While creating the reproduction I gained some insight into the original reported issue.
I am converting my package from vitest-2.0 + @testing-library/react to the new vitest-2.1 API.
If @testing-library has been imported into the project and used with other tests, the original error reproduces (but only in my repository, which is a large package that has a few dozen test files, only one of which is using the new API).

I will troubleshoot the original issue in situ; it seems there is some crosstalk between your API and testing-library. (My goal is to eliminate use of testing-library but it would be nice to support a gradual migration.)

@sheremet-va
Copy link
Member

Here's a gist that produces another, also seemingly valid issue.

Please, if you can publish it as a repository, that would be wonderful. I can't even open the link because the files are just too big.

@xeger
Copy link
Author

xeger commented Sep 9, 2024

Whoops, sorry about that. Here's the same thing in repo form.

To save you time, in case I am being a bonehead, I updated the reproduction to find a button and click it:

  const screen = page.render(<button>hello, world</button>);

  expect(page.getByRole('button')).toBeDefined();
  expect(screen.getByRole('button')).toBeDefined();

  await userEvent.click(page.getByRole('button'));
  await userEvent.click(screen.getByRole('button'));

I expected to reproduce Could not determine window of node but instead, I see:

VitestBrowserElementError: Cannot find element with locator: getByRole('button')

Which is similar, but not identical to the original issue -- I use vitest to find a locator, verify the locator binds to an element with an expect, but when I try to use the same locator with vitest userEvent, it gets confused.

If I switch to using the playwright vitest driver (see branch playwright of repro repo) the test is green.

This second error may be more relevant to you, since I believe vitest's intention is to support a single locators, verification & interactivity API that works with all drivers (❤️).

@sheremet-va
Copy link
Member

expect(page.getByRole('button')).toBeDefined();

This doesn't do anything, getByRole always returns another locator. If you need to compare elements, you need to call .element() or await expect.element(locator)

@xeger
Copy link
Author

xeger commented Sep 10, 2024

My apologies; Playwright + locators are completely new to me, and it's clear that I should slow down and learn about locators vs. assuming they work just like @testing-library did. Still, it would be good to validate that the 2.1 beta will work in my environment and help find any bugs.

I created a playwright branch where I switch to using the playwright driver of vitest, and on that branch, all tests are passing after correcting my mistake and using expect.element for the verification.

Interestingly, the userEvent.click() call accepts a locator, resolves it to an element and clicks the button -- presumably this is part of its async API, to accept a locator and resolve before generating the DOM event.

The same test on the main branch (using webdriverio) continues to throw VitestBrowserElementError when I userEvent.click. It prints some HTML associated with the test failure or the exception:

<body>
  <div />
</body>

Which reinforces the idea that userEvent when using webdriverio is somehow not seeing the same DOM that page and screen are seeing.

When using the preview driver with either branch, I continue to receive the original reported error:

Error: Could not determine window of node. Node was [object Object]
 - /reproduction.test.tsx:12:2

I also tried copying the verbatim example test from vitest-browser-react README; you can find it in the reproduction repo as documented.test.tsx.

It seems to me that userEvent works quite differently between drivers, and/or that there is a bug in properly rendering the DOM with vitest-browser-react using webdriverio or preview drivers.

The vision of a single browser testing API that works with vitest both in preview + headless mode, and is similar to the API used in (playwright) E2E tests, is very compelling to me -- which is why I persist in troubleshooting. ❤️

@sheremet-va
Copy link
Member

I created a playwright branch where I switch to using the playwright driver of vitest, and on that branch, all tests are passing after correcting my mistake and using expect.element for the verification.

Sorry, but your tests are still not correct. Please refer to the documentation for how poll and element work (element is just a wrapper around poll, so they work the same way): https://vitest.dev/api/expect.html#poll

test('using screen', async () => {
  let clicked = false;
  const screen = page.render(<button onClick={() => {clicked = true}}>hello, world</button>);
-  expect.element(screen.getByRole('button'));
+  await expect.element(screen.getByRole('button')).toBeDefined();
  await userEvent.click(screen.getByRole('button'));
-  expect.poll(() => clicked).toBe(true);
+  await expect.poll(() => clicked).toBe(true);
});

I am looking into differences between providers right now.

@sheremet-va sheremet-va added p4-important Violate documented behavior or significantly improves performance (priority) feat: browser Issues and PRs related to the browser runner and removed pending triage labels Sep 12, 2024
@xeger
Copy link
Author

xeger commented Sep 12, 2024

Thank you for looking into it. I've upgraded the reproduction repository to 2.1.0 and corrected my tests; both the corrected test and the documented example from vitest-browser-react fail when using userEvent with webdriverio or preview drivers -- same issue, where the DOM seems to be empty to userEvent.

I will continue to troubleshoot it on my own & open a new issue if I find a root cause.

@sheremet-va
Copy link
Member

both the corrected test and the documented example from vitest-browser-react fail when using userEvent with webdriverio or preview drivers -- same issue, where the DOM seems to be empty to userEvent

I'll reopen the issue then. Both examples worked previously

@sheremet-va sheremet-va reopened this Sep 12, 2024
@xeger
Copy link
Author

xeger commented Sep 12, 2024

Small correction: there is one test case succeeding now with the preview driver!

If we capture the render result and use it (and not the imported page) as the factory for locators, then userEvent works with playwright + preview.

If I'm using page to create locators, then the tests only pass with the playwright driver.

I've amended my reproduction to have an NPM command for each driver, and shown that the vitest-browser-react example passes once we modify it to use const screen = page.render.

I will try to reproduce this success in the project where I was encountering trouble. Your fix has definitely improved things with preview mode! (I am not opinionated about webdriverio vs. playwright for headless tests, but of course I want to help ensure vitest remains flexible as advertised.)

npm run test:playwright
 ✓ documented.test.tsx (2)
 ✓ reproduction.test.tsx (2)

npm run test:preview
 ❯ reproduction.test.tsx (2)
   ✓ using screen
   × using page
 ❯ documented.test.tsx (2)
   × example from vitest-dev/vitest-browser-react
   ✓ modified example

npm run test:webdriverio
 ❯ documented.test.tsx (2) 1355ms
   × example from vitest-dev/vitest-browser-react
   × modified example 1272ms
 ❯ reproduction.test.tsx (2) 1336ms
   × using screen 1270ms
   × using page

@xeger
Copy link
Author

xeger commented Sep 29, 2024

Quick update on some more troubleshooting steps that I have tried.

  1. Upgrade to vitest 2.1.1 & friends (see vitest-2.1.1 branch)
  2. Also switch to PNPM as package manager (see pnpm branch)

The switch to PNPM revealed a missing direct dependency on react-dom, which I added. No change to the outcome.

The playwright driver continues to work well in all cases; the preview and WDIO drivers continue to be extremely flakey.

I also noticed that the playwright driver can run in headed mode and the vitest UI is available.

I appreciate that browsers and frontend are hell. I may just switch my private repository to use playwright and commit to using it in the future, as it is the only stable option. Maybe vitest should do the same thing, as a project. If the dream of vendor nenutrality is impossible to achieve, that's not your fault!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat: browser Issues and PRs related to the browser runner p4-important Violate documented behavior or significantly improves performance (priority)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants