Slide 1

Slide 1 text

WebdriverIO Component Testing in the Browser

Slide 2

Slide 2 text

HolΓ  πŸ‘‹ I am Christian! Lead maintainer of the WebdriverIO Project. Cross Council Project Member at OpenJS Foundation Open Source and Open Standard Advocate Working with the awesome folks over at @bromann | mastodon.social/@bromann

Slide 3

Slide 3 text

Contents 01 What are Web Components? 🧱 What are Web Components and why do they matter? How do they look like when using React, Svelte, Vue etc.? 02 Testing Principles πŸ“œ How can we improve the stability of our tests and increase test coverage by shifting to smaller test units? 03 Status Quo πŸ“ What are people already using today and why the heck should I care? 04 WebdriverIO Setup πŸ›  How to get started with WebdriverIO and component / unit testing in my project? 05 Live Coding 󰳕 Let’s see WebdriverIO component tests in action and check out features like mocking to test coverage reporting. 06 What’s Next? πŸš€ An outlook into the WebdriverIO roadmap in regards to web-component testing @bromann | mastodon.social/@bromann

Slide 4

Slide 4 text

What are Web Components? 🧱 What are Web Components and why do they matter? How do they look like when using React, Svelte, Vue etc.?

Slide 5

Slide 5 text

p { color: #00B56C }

Hello !

class HelloWorld extends HTMLElement { connectedCallback() { const shadow = this.attachShadow({ mode: 'closed' }) const template = document.getElementById('hello-world') shadow.append(template.content.cloneNode(true)); } } customElements.define('hello-world', HelloWorld);

Hello World!

Selenium Conf @bromann | mastodon.social/@bromann

Slide 6

Slide 6 text

import { LitElement, html, css } from "https://esm.sh/[email protected]"; class HelloWorld extends LitElement { static get styles() { return css`p { color: #00B56C }`; } render () { return html` <p> Hello <slot></slot>! </p> ` } } customElements.define('hello-world', HelloWorld);

Hello World!

Selenium Conf @bromann | mastodon.social/@bromann

Slide 7

Slide 7 text

import React from 'react'; import ReactDOM from 'react-dom/client'; export function HelloWorld(props) { return (

Hello {props.children}

); } export function App(props) { return (Selenium Conf) } ReactDOM.createRoot( document.querySelector('#root') ).render() @bromann | mastodon.social/@bromann

Slide 8

Slide 8 text

Testing Principles πŸ“œ How can we improve the stability of our tests and increase test coverage by shifting to smaller test units?

Slide 9

Slide 9 text

The Testing Pyramid Picture from https://www.headspin.io/blog/the-testing-pyramid-simplified-for-one-and-all

Slide 10

Slide 10 text

The Testing Trophy Source: https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications End to End A helper robot that behaves like a user to click around the app and verify that it functions correctly. Integration Verify that several units work together in harmony. Unit Verify that individual, isolated parts work as expected. Static Catch typos and type errors as you write the code. High Confidence Low Confidence Slow Execution Fast Execution

Slide 11

Slide 11 text

UI Component Dependencies UI Component Backend Database @bromann | mastodon.social/@bromann

Slide 12

Slide 12 text

Status Quo πŸ“ What are people already using today and why the heck should I care?

Slide 13

Slide 13 text

β€œJest is a JavaScript test runner that lets you access the DOM via jsdom. While jsdom is only an approximation of how the browser works, it is often good enough for testing React components.” reactjs.org @bromann | mastodon.social/@bromann

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

@bromann | mastodon.social/@bromann

Slide 16

Slide 16 text

@bromann | mastodon.social/@bromann

Slide 17

Slide 17 text

JSDOM Caveats ● Interactions with components can only be imitated via JavaScript ● Missing Web APIs β—‹ Module scripts (ESM) β—‹ Fetch API β—‹ CORS β—‹ … ● Canvas support requires additional dependencies and has limitations ● May behave different than Web APIs implemented in actual browsers ● No element pseudo states, e.g. :hover or :active @bromann | mastodon.social/@bromann

Slide 18

Slide 18 text

JSDOM Caveats @bromann | mastodon.social/@bromann

Slide 19

Slide 19 text

πŸ™ˆπŸ™‰ πŸ™Š @bromann | mastodon.social/@bromann

Slide 20

Slide 20 text

πŸ™ˆπŸ™‰ πŸ™Š .btn { visibility: hidden } ❌ Button Click Fails Button Clicked @bromann | mastodon.social/@bromann

Slide 21

Slide 21 text

πŸ™ˆπŸ™‰ πŸ™Š .btn { height: 0px } ❌ Button Click Fails Button Clicked @bromann | mastodon.social/@bromann

Slide 22

Slide 22 text

πŸ™ˆπŸ™‰ πŸ™Š .forgotEmailOrPassword { transform: translateY(-50px) } ❌ Button Click Fails Button Clicked @bromann | mastodon.social/@bromann

Slide 23

Slide 23 text

πŸ™ˆπŸ™‰ πŸ™Š .forgotEmailOrPassword { transform: translateX(10000px) } ❌ Button Click Fails Button Clicked ⁉ @bromann | mastodon.social/@bromann

Slide 24

Slide 24 text

πŸ™ˆπŸ™‰ πŸ™Š ❌ Scroll Action ❌ User Pinch Zoom @bromann | mastodon.social/@bromann

Slide 25

Slide 25 text

import { render } from '@testing-library/react' import { mock, fn } from '@wdio/browser-runner' // or import { vi } from 'vitest' const mock = vi.mock const fn = vi.fn import { InstantSearchComponent } from './InstantSearch' mock('algoliasearch/lite', () => ({ default: fn().mockReturnValue({ search: fn().mockImplementation(async () => { const fixture = await import('./__fixtures__/algolia.json') return Promise.resolve(fixture) }), searchForFacetValues: fn(), addAlgoliaAgent: fn(), clearCache: fn() }) })) mock('../constants', () => ({ HEADING: 'mocked out' })) describe('InstantSearch Component', () => { before(() => { // render component render() }) it('...', async () => { // ... }) }) Mocking ❌ Dependencies Modules @bromann | mastodon.social/@bromann

Slide 26

Slide 26 text

❌ @bromann | mastodon.social/@bromann Hidden Element Zero Height Overlaying Element Out of Viewport Support Scroll Action Support Pinch Zoom Support Mocking ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ Overview

Slide 27

Slide 27 text

WebdriverIO Setup πŸ›  How to get started with WebdriverIO and component / unit testing in my project?

Slide 28

Slide 28 text

@bromann | mastodon.social/@bromann Component Testing with WebdriverIO

Slide 29

Slide 29 text

Component Testing with WebdriverIO @bromann | mastodon.social/@bromann

Slide 30

Slide 30 text

Component Testing with WebdriverIO @bromann | mastodon.social/@bromann

Slide 31

Slide 31 text

Live Coding 󰳕 Let’s see WebdriverIO component tests in action and check out features like mocking to test coverage reporting. https://github.com/christian-bromann/seconf-2023-demo

Slide 32

Slide 32 text

React Preact Vue Pick Your Framework πŸ€” Svelte Lit Solid @bromann | mastodon.social/@bromann

Slide 33

Slide 33 text

What’s Next? πŸš€ An outlook into the WebdriverIO roadmap in regards to web-component testing

Slide 34

Slide 34 text

● Improved mocking capabilities / fixing known issues ● Support for more testrunner, e.g. Jasmine or Cucumber ● Snapshot testing support for images and DOM nodes const component = render() await expect($(component)).toMatchSnapshot() ● Improve support for more frameworks, e.g. AngularJS ● What else? @bromann | mastodon.social/@bromann Component Testing with WebdriverIO

Slide 35

Slide 35 text

Thank You! @bromann mastodon.social/@bromann