Skip to content

React Testing Library API types prevent usage of SVG elements #830

Closed
@joebobmiles

Description

@joebobmiles
  • @testing-library/react version: 11.1.1
  • Testing Framework and version: jest 25.1.0
  • DOM Environment: jsdom

Relevant code or config:

import * as React from "react";
import { render } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";

test("Is a circle", () => {
  const { container } = render(
    <circle cx=0 cy=0 />,
    {
      container:
        document.body.appendChild(
          document.createElementNS("http://www.w3.org/2000/svg", "svg")),
    });

  expect(container.firstChild.nodeName).toBe("circle");
});

What you did:

Trying to set SVG as the container element for testing SVG React components.

What happened:

Typescript threw a type error stating that render() requires an HTMLElement.

Reproduction:

I created a repository illustrating my problem.

Problem description:

React allows components to use HTML and SVG tags. SVG tags do not work properly in an HTML context, and consequently must be rendered inside an SVG context. This can be only done by using an SVG tag as the containing element. Since the API's types disallow this, users have to wrap all their SVG based components in SVG tags manually and introducing unnecessary nesting to the render output.

Suggested solution:

Propose the following patch to @testing-library/react/types/index.d.ts:

// TypeScript Version: 3.8

import {OptionsReceived as PrettyFormatOptions} from 'pretty-format'
import {queries, Queries, BoundFunction} from '@testing-library/dom'
import {act as reactAct} from 'react-dom/test-utils'

export * from '@testing-library/dom'

type DOMElement = HTMLElement | SVGElement;

export type RenderResult<Q extends Queries = typeof queries> = {
  container: DOMElement
  baseElement: DOMElement
  debug: (
    baseElement?:
      | DOMElement
      | DocumentFragment
      | Array<DOMElement | DocumentFragment>,
    maxLength?: number,
    options?: PrettyFormatOptions,
  ) => void
  rerender: (ui: React.ReactElement) => void
  unmount: () => boolean
  asFragment: () => DocumentFragment
} & {[P in keyof Q]: BoundFunction<Q[P]>}

export interface RenderOptions<Q extends Queries = typeof queries> {
  container?: DOMElement
  baseElement?: DOMElement
  hydrate?: boolean
  queries?: Q
  wrapper?: React.ComponentType
}

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

/**
 * Render into a container which is appended to document.body. It should be used with cleanup.
 */
export function render(
  ui: React.ReactElement,
  options?: Omit<RenderOptions, 'queries'>,
): RenderResult
export function render<Q extends Queries>(
  ui: React.ReactElement,
  options: RenderOptions<Q>,
): RenderResult<Q>

/**
 * Unmounts React trees that were mounted with render.
 */
export function cleanup(): void

/**
 * Simply calls ReactDOMTestUtils.act(cb)
 * If that's not available (older version of react) then it
 * simply calls the given callback immediately
 */
export const act: typeof reactAct extends undefined
  ? (callback: () => void) => void
  : typeof reactAct

I've implemented this patch locally in my project where I discovered the bug and it solves the issue. However, I'm having difficulty committing my patch to react-testing-library due to dtslint commit hook rejecting the types in the React dependency.

Metadata

Metadata

Assignees

No one assigned

    Labels

    TypeScriptRelated to TypeScript. Note: only certain maintainers handle TypeScript labeled issues.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions