How to Run Component Tests with WebdriverIO
Configure WebdriverIO’s Browser Runner to render, interact with, and assert on components in a real browser, with setup examples and troubleshooting.
WebdriverIO component tests run in a real browser through the Browser Runner. The runner uses Vite to compile test code and serve a test page; framework utilities can mount components, and WebdriverIO commands interact with the rendered result. This is useful when a component depends on browser behavior that a DOM emulator may not reproduce. It tests the component in the runner’s page, not the whole deployed application.
1. Create the Browser Runner configuration
From your project directory, run the official setup wizard:
npm init wdio@latest ./
Select browser as the runner. Choose your framework preset if offered, or select Other for basic browser-based unit tests. If the project already uses Vite, decide whether its existing configuration is suitable to reuse. Review the generated WDIO configuration and adjust it to match your build setup.
The documented presets cover React, Preact, Vue, Svelte, SolidJS, and Stencil. Framework presets can require their corresponding Vite plugin. For example, React uses @vitejs/plugin-react, Vue uses @vitejs/plugin-vue, and Preact uses @preact/preset-vite. Install the framework’s rendering or testing utility as a development dependency when you plan to use it.
Example configuration shapes
The wizard generates the full configuration for your project. The relevant runner setting for React looks like this:
export const config = {
// Keep the other settings generated by the WDIO wizard.
runner: ['browser', { preset: 'react' }]
}
For Vue, use preset: 'vue'. A custom Vite configuration can also be supplied or referenced; the runner adapts it to set up its test harness. Check the generated file’s module format and preserve the rest of its required settings rather than replacing the whole file with this abbreviated example.
2. Render a component and exercise it in the browser
Testing Library’s render helpers make it convenient to mount a component and query its accessible output. WebdriverIO element commands perform the browser interaction. The React example below assumes the wizard-created React setup, @testing-library/react is installed, and the project’s test-file convention is configured by that setup.
import { render, screen } from '@testing-library/react'
import { expect } from '@wdio/globals'
import Counter from './Counter.jsx'
describe('Counter', () => {
it('increments when clicked', async () => {
render(<Counter />)
const button = screen.getByRole('button', { name: /increment/i })
await button.click()
await expect(screen.getByText('Count: 1')).toBeDisplayed()
})
})
Adapt the component import, button name, and expected content to your application. The component should expose an accessible name for the button so the test finds it by role and name rather than depending on incidental markup.
For Vue, render with @vue/test-utils or @testing-library/vue, then use WebdriverIO commands for browser interactions. The exact render and query calls depend on which utility you choose. Testing Library render helpers clean up between tests; if you mount components another way, arrange equivalent cleanup yourself.
3. Run tests locally and in CI
Run the generated configuration from the project root:
npx wdio run ./wdio.conf.js
The official React and Vue examples use this command. Confirm the configuration path and extension match the file the wizard generated.
In CI, the Browser Runner defaults to headless mode when CI is set to '1' or 'true'. The runner’s headless option controls this behavior. For remote Selenium Grid execution, configure the runner’s host so the remote browser can reach the machine serving the test files.
4. Choose the framework and Vite setup
| Framework or setup | Configuration guidance |
|---|---|
| React | Use the React preset and @vitejs/plugin-react; a React Testing Library render helper is one documented approach. |
| Vue | Use the Vue preset and @vitejs/plugin-vue; render with Vue Test Utils or Vue Testing Library. |
| Preact | Use its preset and @preact/preset-vite. |
| Svelte, SolidJS, Stencil | Choose the matching documented preset and follow its framework-specific setup. |
| Existing Vite project | Reuse its config if suitable, or pass a custom Vite configuration. Inspect the WDIO-generated runner settings. |
| Basic browser tests | Choose Other in the wizard when no listed framework preset applies. |
Keep component tests focused on rendering, browser-facing behavior, and interactions within the runner’s test page. When behavior depends on the integration of multiple application areas, routing, server state, or deployment configuration, cover that behavior with an end-to-end test as well.
5. Isolation, debugging, and runner constraints
- Isolation: Each test file or group runs in one page, and the page reloads between tests. Render utilities can clean mounted components between tests. If you do not use such a utility, remove your own test DOM between cases.
- Test framework: The component-testing overview documents Mocha support; it describes Jasmine and Cucumber as roadmap items. Verify current support in the live documentation before choosing a different framework.
- Watch mode: Use
--watchto rerun changed files during development. - Interactive debugging: The documented
debugcommand pauses execution and opens a Node.js REPL while you inspect the browser. IDE breakpoints are not recognized in the remote browser according to the guide. - Native blocking dialogs: Calls such as
alertandconfirmblock page communication. The runner provides mocks with default return values; explicitly mock them when the component’s behavior depends on a particular response. - Nuxt: The Vue guide documents Nuxt support with caveats. Code requiring a Nuxt application context may not initialize in the browser runner alone and is generally better covered end to end. Third-party composables can require manual mocks.
6. Common problems and fixes
| Symptom | Likely cause | What to do |
|---|---|---|
| The runner cannot compile framework files | The selected preset or Vite plugin does not match the project, or a required plugin is missing. | Check the runner preset, install the framework’s documented Vite plugin, and inspect the generated or custom Vite config. |
| Tests cannot find a component or query result | The component was not rendered, the query does not match its accessible output, or setup differs from the assumed test-file convention. | Confirm the render call completed, query by the component’s actual role/name or text, and check the wizard-generated test configuration. |
| One test affects the next | Custom mounting code leaves DOM or state behind. | Use a render helper that cleans up, or explicitly unmount and clear the test container. Remember the runner reloads the page between files or groups, not necessarily after every individual test. |
| A native dialog causes a hang or unexpected result | A blocking browser dialog prevents normal page communication. | Use the runner-provided mock and set the response needed by the test. |
| A remote Grid browser cannot load the test page | The browser cannot reach the host serving the files. | Set the Browser Runner’s host to an address reachable from the remote browser and verify the network path. |
| A Nuxt composable fails outside the app | It expects Nuxt application context or a module not initialized by a browser-only test page. | Mock a third-party composable where appropriate, or exercise context-dependent behavior in an end-to-end test. |
| CI opens a visible browser or behaves differently | The CI environment value or headless option differs from local settings. | Check whether CI is exactly 1 or true, then set the runner’s headless option explicitly if needed. |
7. Performance, reliability, and cost
Browser tests exercise real browser behavior, so they involve launching or connecting to a browser and loading a Vite-served page. Keep the suite efficient by testing component-level behavior here and reserving cross-application flows for end-to-end coverage. Reuse the project’s appropriate Vite setup, avoid unnecessary page work in each test, and use watch mode while iterating.
For reliable results, make tests independent, clean up mounted components, query through stable user-facing semantics, and mock external or application context that is outside the component’s responsibility. A real browser improves fidelity for browser APIs, but it does not establish that the deployed application, backend, or full navigation flow works.
WebdriverIO and its framework utilities are software dependencies; execution cost depends on the browser and CI or Grid resources you choose. The supplied documentation does not establish a fixed runtime or infrastructure price, so estimate from your own CI environment rather than assuming a benchmark.
8. Or skip the browser setup
If your goal is a screenshot of a rendered website rather than an interactive component assertion, ScreenshotNeo is a website screenshot API and MCP server for developers. A single request returns an image or PDF. See the API documentation for parameters and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' })
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`)
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`)
await Bun.write('shot.webp', res)
Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Screenshots are useful for visual review, but they do not replace component interaction assertions.
Sign up for 1,000 free screenshots a month, with no card required.
9. Frequently asked questions
Does the Browser Runner use JSDOM?
No. It runs component tests in an actual browser. This gives access to browser behavior that a DOM emulator may not reproduce.
Can I use it for a full application test?
It focuses on components rendered in the runner’s test page. Use end-to-end tests to cover integrated application behavior and deployment flows.
Do I need Testing Library?
No. It is a recommended rendering and querying option. If you use another mounting approach, provide equivalent DOM cleanup.
Can a component test use browser APIs?
Yes, the real-browser environment is useful for browser APIs. Account for runner constraints such as blocking dialogs by using the supplied mocks where needed.


