• Introduction
    • Why Liquid Oxygen
    • Getting started
      • React
      • Vue
  • Guides
    • CSS vs. Web Components
    • Component assets
    • Type checking and intellisense
    • Server-side rendering
    • Event handling
    • Form validation
    • Tailwind CSS integration
    • Design tokens
    • Testing
    • Sandbox applications
    • Troubleshooting
      • Popped-out element is rendered in wrong container
      • Failed to execute removeChild on Node
    • FAQ
    • Contributing
  • Globals
    • Animations
    • Border-radius
    • Colors
    • Focus
    • Fonts
    • Shadows
    • Spacings
    • Theming
    • Typography
  • Components
    • Accordion
      • Accordion Panel
      • Accordion Section
      • Accordion Toggle
    • Background Cells
    • Badge
    • Breadcrumbs
      • Crumb
    • Button
    • Card
      • Card Stack
    • Checkbox
    • Circular Progress
    • Context Menu
      • Menu
      • Menuitem
      • Menuitem Group
    • Cookie Consent
    • Header
    • Icon
    • Input
    • Input Message
    • Label
    • Link
    • Loading Indicator
    • Modal
    • Notice
    • Notification
    • Pagination
    • Progress
    • Radio Button
    • Screen Reader Live
    • Screen Reader Only
    • Select
      • Option
      • Option Group
    • Sidenav
      • Sidenav Accordion
      • Sidenav Back
      • Sidenav Header
      • Sidenav Heading
      • Sidenav Navitem
      • Sidenav Separator
      • Sidenav Slider
      • Sidenav Subnav
      • Sidenav Toggle Outside
    • Slider
    • Stepper
      • Step
    • Switch
      • Switch Item
    • Table
      • Table Body
      • Table Caption
      • Table Cell
      • Table Colgroup
      • Table Column
      • Table Footer
      • Table Head
      • Table Header
      • Table Row
      • Table Toolbar
    • Tabs
      • Tab
      • Tab List
      • Tab Panel
      • Tab Panel List
    • Toggle
    • Tooltip
    • Typography
  • Data Visualization
    • Getting Started
Guides Testing
(external link)

Testing #

If you run unit tests in your application, which depend on the functionality of Liquid Oxygen Web Components, and you do not want to mock that functionality, you must ensure that the components have been hydrated before you execute your test code:

  1. Call defineCustomElements() imported from '@emdgroup-liquid/liquid/dist/loader' before each test.
  2. await all components to be hydrated. You can use a helper function similar to the one in the example test code below.

The following example shows how to execute unit tests with hydrated Web Components using vitest, React, and the React Testing Library.

Configure vitest to use a setup file:

// vite.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
  // ...
  test: {
    // ...
    setupFiles: './src/setupTests.ts',
  },
})

The setupTests.ts file looks like this:

// src/setupTests.ts
import { defineCustomElements } from '@emdgroup-liquid/liquid/dist/loader'
import '@testing-library/jest-dom'
import matchers from '@testing-library/jest-dom/matchers'
import { cleanup } from '@testing-library/react'
import { vi } from 'vitest'

// Extend Vitest's expect method with methods from react-testing-library.
expect.extend(matchers)

beforeAll(() => {
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  global.__LD_ASSET_PATH__ = '/' // removes CDN warning
  defineCustomElements()

  global.fetch = vi
    .fn()
    .mockReturnValue(Promise.resolve({ text: () => Promise.resolve('') }))
})

// Run a cleanup after each test case.
afterEach(() => {
  cleanup()
})

In your test file, you can now wait for the Web Components to hydrate before executing your actual test code.

// src/App.test.tsx
import App from './App'
import { render, screen, waitFor, fireEvent } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import React from 'react'

async function waitForLiquidToHydrate() {
  return waitFor(() => {
    Array.from(document.querySelectorAll('*'))
      .filter((e) => e.tagName.startsWith('LD-'))
      .forEach((component) => {
        expect(component).toHaveClass('hydrated')
      })
  })
}

test('validates input', async () => {
  render(<App />)

  await waitForLiquidToHydrate()

  const ldInputName = screen.getByPlaceholderText('e.g. Jason Parse')
  expect(ldInputName).toBeInTheDocument()

  const ldButtonSubmit = screen.getByText('Submit')
  expect(ldButtonSubmit).toBeInTheDocument()
  userEvent.click(ldButtonSubmit)

  const form = await screen.findByTestId('form')
  expect(form).toBeInTheDocument()

  fireEvent.submit(form)

  await screen.findByText('Your full name is required.')
})

Check out our React sandbox app for a full working example.