Coder Social home page Coder Social logo

preact-testing-library's Introduction

Preact Testing Library

poodle

Simple and complete Preact DOM testing utilities that encourage good testing practices.

Inspired completely by react-testing-library

Build Status Code Coverage All Contributors PRs Welcome Code of Conduct version downloads MIT License Preact Slack Community Commitzen Discord


Table of Contents

The Problem

You want to write tests for your Preact components so that they avoid including implementation details, and are maintainable in the long run.

The Solution

The Preact Testing Library is a very lightweight solution for testing Preact components. It provides light utility functions on top of preact/test-utils, in a way that encourages better testing practices. Its primary guiding principle is:

The more your tests resemble the way your software is used, the more confidence they can give you.

Installation

This module is distributed via npm which is bundled with node and should be installed as one of your project's devDependencies:

npm install --save-dev @testing-library/preact

This library has peerDependencies listings for preact >= 10.

๐Ÿ’ก You may also be interested in installing @testing-library/jest-dom so you can use the custom jest matchers.

๐Ÿ“ This library supports Preact X (10.x). It takes advantage of the act test utility in preact/test-utils to enable both Preact Hook and Class components to be easily tested.

๐Ÿ“ If you're looking for a solution for Preact 8.x then install preact-testing-library.

Docs

See the docs over at the Testing Library website.

Issues

Looking to contribute? Look for the Good First Issue label.

๐Ÿ› Bugs

Please file an issue for bugs, missing documentation, or unexpected behavior.

See Bugs

๐Ÿ’ก Feature Requests

Please file an issue to suggest new features. Vote on feature requests by adding a ๐Ÿ‘. This helps maintainers prioritize what to work on.

See Feature Requests

โ“ Questions

For questions related to using the library, please visit a support community instead of filing an issue on GitHub.

Contributors

Thanks goes to these people (emoji key):

Kent C. Dodds
Kent C. Dodds

๐Ÿ’ป ๐Ÿ“– โš ๏ธ
Ants Martian
Ants Martian

๐Ÿ’ป ๐Ÿ“– โš ๏ธ
Rahim Alwer
Rahim Alwer

๐Ÿ’ป ๐Ÿ“– โš ๏ธ ๐Ÿš‡

This project follows the all-contributors specification. Contributions of any kind welcome!

LICENSE

MIT

preact-testing-library's People

Contributors

aduth avatar danielmaczak avatar filipw01 avatar imgbot[bot] avatar jovidecroock avatar maxbeatty avatar michaeldeboey avatar mihar-22 avatar mikerob215 avatar mischnic avatar nickserv avatar rschristian avatar stephenpitchford avatar swissspidy avatar vbabel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

preact-testing-library's Issues

fireEvent() does not wait for rerender when imported as native ESM in Node v12

  • preact-testing-library version: 2.0.0
  • preact version: 10.4.8
  • node version: 12.18.3
  • npm version: 6.14.8

Code that runs in Node.js v12 (saved as app.mjs):

import { Component, h } from "preact";
import htm from "htm";
import TLP from "@testing-library/preact";
import jsdomGlobal from "jsdom-global";

const { fireEvent, render } = TLP;
const html = htm.bind(h);

class App extends Component {
  constructor() {
    super();
    this.state = { clickCount: 0 };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log(
      `App.handleClick() called, clickCount == ${this.state.clickCount}`
    );
    this.setState((state) => ({ clickCount: state.clickCount + 1 }));
  }

  render() {
    console.log(`App.render() called, clickCount == ${this.state.clickCount}`);
    return html`
      <div>
        <button onClick="${this.handleClick}">
          Click count: ${this.state.clickCount}
        </button>
      </div>
    `;
  }
}

jsdomGlobal();

const { getByRole } = render(h(App));
const button = getByRole("button");

console.log("Before fireEvent");
fireEvent.click(button);
console.log("After fireEvent");

Equivalent code in browser: https://codesandbox.io/s/aged-pine-33292

What you did:

I am using Testing Library and Preact in Node.js, using JSDOM to simulate a browser environment. I ran node --experimental-modules ./app.mjs.

What happened:

When I run the script above in Node.js, the following log appears:

(node:4788) ExperimentalWarning: The ESM module loader is experimental.
App.render() called, clickCount == 0
Before fireEvent
App.handleClick() called, clickCount == 0
After fireEvent
App.render() called, clickCount == 1

Here, fireEvent() returned before the second App.render() call.

When I run the (almost) same code in browser:

App.render() called, clickCount == 0 
Before fireEvent
App.handleClick() called, clickCount == 0 
App.render() called, clickCount == 1 
After fireEvent

Here, fireEvent() returned after the second App.render() call.

A curious discovery: fireEvent() behaves as expected under Node.js v10: https://codesandbox.io/s/frosty-blackwell-7686y . I assume that something is going haywire w.r.t. the "exports" field in package.json of Preact--since Node.js v12 supports it, but Node.js v10 does not.

Some observations:

  • Preact uses the "exports" field in package.json to export both ESM and CJS bundles.
  • Preact Testing Library does not use the "exports" field, and therefore only exports CJS bundles.
  • Only Node.js >= 12 can understand the "exports" field.
  • Node.js uses separate loaders for ESM and CJS.
  • When Node.js is running in native ESM mode, it can load both CJS and ESM modules.
    • ESM modules are loaded as-is
    • CJS modules are loaded through some compatibility magic provided by Node.js

My conjecture:

  1. When I import Preact directly, Node.js v12 loads it through the ESM loader
    1. This causes Node.js to load the ESM bundle for Preact.
  2. When I import Preact Testing Library, Node.js loads it through the CJS loader.
    1. Because of this, PTL's dependencies are also loaded through the CJS loader.
    2. Because of this, PTL loads the CJS bundle for Preact.
  3. Node.js treats the ESM and CJS bundles of Preact as separate modules.
  4. Because of this, fireEvent() uses act() from the wrong copy of Preact, making it ineffective

Reproduction repository:

Problem description:

Suggested solution:

Perhaps Preact Testing Library could also provide an ESM bundle via the "exports" field? Since Node.js v12 is here to stay, we can expect the "exports" field to cause further headache unless it is addressed.

Release 0.2.0 does not have a dist directory

Freshly installed using NPM and Yarn, version 0.2.0 of the package does not include the dist directory. Also, the typings directory (which is included) does not have the latest version of the index.d.ts file.

FireEvent on a submit button doesn't trigger a re-render

  • react-testing-library version: 0.3.0
  • node version: v8.12.0
  • npm (or yarn) version: v6.4.1

Relevant code or config

class App extends Component {
  state = {
    data: []
  };

  handleSubmit = e => {
    e.preventDefault();
    this.setState({
      data: ["asd", "asdads"]
    });
  };
  render(props, { data }) {
    return (
      <div>
        <h1>Example</h1>
        <form onSubmit={this.handleSubmit} data-testid="form">
          <button type="submit">Submit</button>
        </form>
        <h2>Results</h2>
        <div class="list">
          {data.map((result, i) => (
            <div key={i}>{result}</div>
          ))}
        </div>
      </div>
    );
  }
}
// Test is green
test("Render messages on submit", () => {
  debounceRenderingOff(); //turns off the debounce, no need for any waits
  const { getByText, getByTestId } = render(<App />);
  fireEvent.submit(getByTestId("form"));
  expect(getByText("asd")).not.toBeNull();
  expect(getByText("asdads")).not.toBeNull();
});
// Test is red :(
test("Render messages on click submit", () => {
  debounceRenderingOff(); //turns off the debounce, no need for any waits
  const { getByText, getByTestId } = render(<App />);
  fireEvent.click(getByText("Submit"));
  expect(getByText("asd")).not.toBeNull();
  expect(getByText("asdads")).not.toBeNull();
});

What you did:

This is a simplified version of an actual component. Basically I wanted to verify that on submit my messages will be displayed on the page. I removed all the business logic from it. It's just a simple component now.

What happened:

Simulate a click on a submit button doesn't trigger a re-render.
But if I fireEvent.submit(getByTestId("form")); it will trigger setState()

Error

Unable to find an element with the text: asd.

Maybe I'm doing something wrong but it seems strange that clicking on a submit button does't trigger the form

How to reproduce

https://codesandbox.io/s/7wyr0x6mxj?fontsize=14&previewwindow=tests

Thanks for this library by the way! If you need help or looking for contributors let me know. Happy to help :)

fireEvent.animationEnd does not call preact-registered listener

  • preact-testing-library version: 3.2.2
  • preact version: 10.11.0
  • node version: 16.17.0
  • npm (or yarn) version: yarn 3.2.3

Relevant code or config

export interface TestComponentProps {
  onNextClick?: () => void;
}

export const TestComponent: FunctionComponent<TestComponentProps> = ({
  onNextClick,
}) => {
  return (
    <div data-countdown onAnimationEnd={onNextClick}>
      FOO
    </div>
  );
};

and the corresponding test

  it("should call onNextClick on animation end", async () => {
    //given
    const props = {
      onNextClick: jest.fn(),
    };

    //when
    const { container } = render(<TestComponent {...props} />);

    fireEvent.animationEnd(
      container.querySelector("[data-countdown]") as HTMLElement
    );

    //then
    expect(props.onNextClick).toHaveBeenCalledTimes(1);
  });

What you did:

in a jest test calling

  const divElement = container.querySelector("[data-countdown]") as HTMLElement;
  fireEvent.animationEnd(divElement);

What happened:

The callback in

<div onAnimationEnd={onNextClick}>

is not being called.

The test will report the following


  โ— test-component โ€บ should call onNextClick on animation end

    expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      19 |
      20 |     //then
    > 21 |     expect(props.onNextClick).toHaveBeenCalledTimes(1);
         |                               ^
      22 |   });
      23 | });
      24 |

      at Object.<anonymous> (src/components/__tests__/test.spec.tsx:21:31)
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
      at runJest (node_modules/@jest/core/build/runJest.js:404:19)
      at _run10000 (node_modules/@jest/core/build/cli/index.js:320:7)
      at runCLI (node_modules/@jest/core/build/cli/index.js:173:3)

Reproduction repository:
https://github.com/rburgst/preact-testing-animation-bug/

Problem description:

The problem appears that the listeners in jsdom are registered with AnimationEnd while the event being fired is animationend.

Note that this worked in @testing-library/preact": "^2.0.1" but fails with the current version 3.2.2.

Suggested solution:

I guess this problem is similar to #51

container is always empty

I recently switched from React to Preact. And also I changed the test-library to this one. However, some tests that I had now are failing. And I noticed that the container is always empty:

import React from 'react'
import { render } from '@testing-library/preact'

function Component() {
  return (
    <div>
      <div>Content</div>
    </div>
  )
}

describe('Failing example', () => {
  test('example', async () => {
    const { container } = await render(<Component />)

    expect(container.textContent).toBe('Content')
    /**
     *   expect(received).toBe(expected) // Object.is equality
     *
     * Expected: "Content"
     * Received: ""
     *
     *  15 |       const { container } = await render(<Component />)
     *  16 |
     * > 17 |       expect(container.textContent).toBe('Content')
     *     |                                     ^
     *  18 |     })
     *  19 |   })
     *  20 | })
     */
  })
})

Can not test fireEvent.touchStart side effects

  • preact-testing-library version: 1.0.2
  • preact version: 10.3.2
  • node version: 13.9.0
  • npm (or yarn) version: 6.13.7

Relevant code or config
Button.js

const Button = ({myHandler}) => (
    <button data-testid='my-button' onTouchStart={myHandler}>Click me</button>
)

export default Button;

Button.test.js

import { render, fireEvent } from '@testing-library/preact';
import Button from './Button';

describe('Button behavior test:', () => {
   it('Should call myHandler on touchStart', () => {
        const mockFn = jest.fn();
        const { getByTestId } = render(<Button myHandler={mockFn} />);
        fireEvent.touchStart(getByTestId('my-button'));
        expect(mockFn).toHaveBeenCalled();
   });
});

What you did:
Simple button component with onTouchStart event that triggers a prop method.

What happened:
I can not test it due to fireEvent.touchStart is not triggering the event and not creating side effects on my component.

Problem description:
I need to unit test the side effects of onTouchStart / onTouchEnd events on my components.

Compatibility with preact v10.16

Hi all!
Some time ago we decided to update our preact version to 10.16. And we faced with unexpected behaviour of preact-testing-library.
To test the components which use the Redux store, we created a simple utility function which renders the component inside the Redux store provider. And now our unit tests which use this utility function fail. If we run our test components without the provider - they work fine.
We strongly suspect that the problem is caused by the new preact version. They added some changes there, and now their render function has another arguments (they removed the replacingElement arg). And the render function inside the preact-testing-library uses the old syntax. This problem appears ONLY in case when we use the provider (when we call the render from preact-testing-library with passed Wrapper parameter).
Thanks in advance!

  • preact-testing-library version: 3.2.2
  • preact version: 10.16
  • node version: 16.13.0
  • npm (or yarn) version: yarn 1.22.18

Relevant code or config
This is the code fragment from the preact-testing-library dist, seems that it causes the problem with wrapped components.

  const wrapUiIfNeeded = innerElement => WrapperComponent ? (0, _preact.h)(WrapperComponent, null, innerElement) : innerElement;

What you did:

What happened:
Screenshot 2023-11-01 at 18 26 06

Reproduction repository:

Problem description:
The test components rendered with the render function with passed Wrapper argument fail.

Suggested solution:

It seems that current published version 0.0.3 is older than the source code here

  • react-testing-library version: 0.0.3
  • node version: 10.15.3
  • yarn version: 1.15.2

Relevant code (example from readme):

import {render} from 'preact-testing-library'

const {rerender} = render(<NumberDisplay number={1} />)

// re-render the same component with different props
rerender(<NumberDisplay number={2} />)

Problem description:
I basically wanted to use the rerender method but it's undefined. Then I digged into the dist/index.js file and it looks for me that that compiled code is basically before #4 was merged. Also other render() return values are mssing. Since version 0.0.3 was released after #4 I guess that this version was somehow built with old code in dist repository.

Suggested solution:
Republish latest code with a new version.

`global is not defined` from pretty-format (@testing-library/dom dependency update needed)

First of all, Iโ€™d like to say thanks to everyone involved for this great library.

This issue is related to these errors in @testing-library/dom:
testing-library/dom-testing-library#756
testing-library/dom-testing-library#985

This problem is fixed in @testing-library/dom 8.x but people are still running into this problem because several tools still depend on 7.x.

I ran into this known problem twice this week in a Karma + Preact + @testing-library/preact context as well as in a Karma + Angular + Spectator context. Someone seems to have this problem with @testing-library/vue as well.

The old @testing-library/dom depends on pretty-format which assumes a Node context and

  • accesses the global global
  • accesses process.env(.PTL_SKIP_AUTO_CLEANUP)

both of which are not present in the browser environment.

The exeption is:

ReferenceError: global is not defined
node_modules/@testing-library/preact/node_modules/pretty-format/build/plugins/AsymmetricMatcher.js:10:14
node_modules/@testing-library/preact/node_modules/pretty-format/build/index.js:8:3
node_modules/@testing-library/preact/node_modules/@testing-library/dom/dist/pretty-dom.js:17:44
node_modules/@testing-library/preact/node_modules/@testing-library/dom/dist/config.js:11:18
node_modules/@testing-library/preact/node_modules/@testing-library/dom/dist/queries/label-text.js:8:15
node_modules/@testing-library/preact/node_modules/@testing-library/dom/dist/queries/index.js:7
node_modules/@testing-library/preact/node_modules/@testing-library/dom/dist/get-queries-for-element.js:8
node_modules/@testing-library/preact/node_modules/@testing-library/dom/dist/index.js:61
node_modules/@testing-library/preact/dist/pure.js:20
node_modules/@testing-library/preact/dist/index.js:7

Iโ€™ve created a minimal demo that triggers the bug:

https://github.com/molily/karma-dom-testing-library

Direct use of @testing-library/dom 8.11.1 in Component.test.js does not trigger the exception on its own. The exception is triggered when importing @testing-library/preact in PreactComponent.test.jsx which depends on @testing-library/dom ^7.16.2.

The obvious solution is to bump the dependency (see also #45). Iโ€™m mostly posting this issue for reference for others who run into this problem across the @testing-library/* ecosystem.

A temporary fix is to put this in a test helper:

globalThis.global = globalThis;
globalThis.process = { env: { PTL_SKIP_AUTO_CLEANUP: false } };

(You can also use window instead of globalThis since this code runs in the browser.)

For reference:

@testing-library/preact depends on @testing-library/dom ^7.16.2
@ngneat/spectator depends on @testing-library/dom 7.26.5
@testing-library/vue depends on @testing-library/dom ^7.26.6

Thanks everyone. ๐Ÿ˜Š

Possible collaboration?

Problem description

I rewrote a new version of preact-testing-library that's up-to-date and inline with the react version. It includes tests, documentation and support for Hooks by wrapping all rendering and events with the act test utility.

Library differences

Repository is here: preact-testing-library

  • Supports Preact X but I think it should be pretty easy to add support for Preact 8.x+. Only difference I believe is that act is not available in 8.x and possibly hydrate.
  • My library doesn't include debounceRenderingOff and flushPromises. Easy to add in for backwards support.
  • More argument/return values for render function. Only additive, no issues.
  • Adds automatic cleanups. No issues.
  • Adds new fireEvent export. No issues.
  • Exports @testing-library/dom with the dtl alias. Will cause issues and needs a solution. It was causing problems with rollup cjs bundling.
  • Build tools and everything are different but this won't cause any issues. It still uses Travis CI and semantic releases. The script commands that matter are the same like setupand validate.

Suggested solution

Solve issues above and merge my library into this one and I can help with maintaining it.

Either way I thought I'd leave it as a suggestion here. If there's any issues then no worries, I can also just keep a separate library available for anyone who needs it.

Missing TypeScript declarations

The project is missing up-to-date TypeScript declarations for the cleanup, debounceRenderingOff, and flushPromises functions as well as all the dependencies inherited from dom-testing-library (like fireEvent and so forth).

"SyntaxError: Cannot use import statement outside a module" running jest

  • @testing-library/preact version: 3.2.3
  • preact version: 10.13.2
  • node version: 18.14.0
  • npm version: 9.3.1

What happened:

Starting with v3.1.0 i have problems running my tests with jest.

When running jest i get following error:

.../node_modules/@testing-library/preact/dist/esm/index.mjs:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { cleanup } from "./pure.mjs";
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module
// jest.config.js

const config = {
  testEnvironment: 'jsdom',
  transform: {
    '\\.[jt]sx?$': ['@swc/jest']
  }
}

Stale DOM with fake timers in jest 27.x

  • preact-testing-library version: 2.0.1
  • preact version: 10.5.15
  • node version: 16.11.1
  • npm (or yarn) version: 8.0.0

Relevant code or config

What you did:

What happened:

Reproduction repository:

const { h } = require("preact"); /** @jsx h */
const { useState, useEffect } = require("preact/hooks");
const { render, waitFor, screen } = require("@testing-library/preact");

jest.useFakeTimers();

const apiCall = () => {
  return new Promise((resolve, reject) => {
    resolve();
  });
};

function Comp() {
  const [val, setVal] = useState("original value");

  useEffect(() => {
    const interval = setInterval(() => {
      apiCall().then(() => {
        setVal("timeout value");
      });
    }, 300); // <- 300ms delay
    console.log("call eff");
    apiCall().then(() => {
      console.log("resolve eff");
      setVal("effect value");
    });
    return () => {
      clearInterval(interval);
    };
  }, []);

  console.log("render", val);

  return <div>{val}</div>;
}

it("fails", async () => {
  const wrapper = render(<Comp />);
  const { container } = wrapper;

  expect(container.textContent).toEqual("original value");

  await waitFor(() => {
    console.log("check", container.textContent);
    expect(container.textContent).toEqual("effect value");
  });
  jest.advanceTimersByTime(1000);

  await waitFor(() => {
    expect(container.textContent).toEqual("timeout value");
  });
});

Problem description:

Due to the fake timers usage the first waitFor call times out. The DOM value is stale and never updated, despite the component correctly being re-rendered.

Suggested solution:

This issue is resolved by forcefully updating the dependency on @testing-library/dom to the latest version 8.10.1.

Preact X testing not working

  • react-testing-library version: latest
  • node version: 10.15.2
  • npm (or yarn) version: 6.4.1

When testing the new Preact X API hooks it fails because MessageChannel is undefined. Should this repo provide a mock for that or? Don't really know where's the best spot to open this issue.

`fireEvent` updates in 3.0.2 introduced a regression

  • preact-testing-library version: 3.0.2 onward
  • preact version: 10.7.2
  • node version: 16.15.0
  • npm (or yarn) version: 8.5.5

Relevant code or config

...
import { fireEvent } from 'testing-library/preact'

test('fireEvent passes on event init', () => {
  const handler = jest.fn()
  document.body.addEventListener('keydown', handler)

  const init = { key: 'Escape' }
  fireEvent.click(document.body, init)

  expect(handler).toHaveBeenCalledWith(expect.objectContaining(init))
})

What you did:

Upgraded @testing-library/preact from 3.0.1 to 3.2.0

What happened:

Tests passing event init to fireEvent imported from @testing-library/preact now failing.

Reproduction repository:

See this commit in my fork: vbabel@3df9d42

These tests fail without the fix.

Problem description:

fireEvent updates introduced a regression.

Suggested solution:

Handle event init in the preact specific fireEvent.

queryByText where string starts/ends with space returns null

  • @testing-library/preact version: 2.0.1
  • preact version: 10.5.13
  • node version: v14.15.1
  • yarn version: 1.22.10

Relevant code or config

// title.tsx
type TitleProps = {
  title?: string;
};

export function Title({ title }: TitleProps) {
  return (
    <div>
      <h2 data-e2e="title">{title || `No title`}</h2>
    </div>
  );
}

// title.spec.tsx
import { Title } from './title';
import { render } from '@testing-library/preact';

describe(Title.name, () => {
  it('should display title when it starts with space', () => {
    const title = ' Some sick title';
  
    const { queryByText } = render(<Title title={title} />);
  
    expect(queryByText(title)).not.toBeNull();
  });
});

What you did:

Run the test above.

What happened:

Calling queryByText(title) returns null when title starts or ends with space.

Problem description:

When using queryByText and the string I am searching for starts or ends with space, the result will be null. If I print the content of the container

const { queryByText, container } = render(<Title title={title} />);

console.log(container.innerHtml);

The console shows the expected output <div><h2 data-e2e="title"> Some sick title</h2></div>. It works perfectly fine if I trim the string I am searching for. (e.g. expect(queryByText(title.trim())).not.toBeNull(); will pass)

Join testing-library org?

Hi ๐Ÿ‘‹ would you like to join @testing-library and move this over to that org? May help make this more official and you could also rename the module to @testing-library/preact if you're interested. Let me know!

A custom container does not get rendered inside baseElement

  • preact-testing-library version: 2.0.1
  • preact version: 10.5.15
  • node version: 16.13.0
  • npm (or yarn) version: 8.1.0

Relevant code or config

What you did:

I'm trying to render my application with a custom container attached to it.

What happened:

The custom container is never appended to baseElement (as is the case with the React testing library).
I think this should not be the case by default as it breaks any DOM interaction happening inside of the app.

Reproduction repository:

https://codesandbox.io/s/x2rfj

Problem description:

Seeing as by default the application gets rendered inside the baseElement, passing a custom container should still be rendered inside the baseElement.

Suggested solution:

Feature: Support native ESM

  • preact-testing-library version: 2.0.1
  • preact version: 10.5.13
  • node version: 14.16.0
  • npm (or yarn) version: yarn 1.22.10

Relevant code or config

import { render, screen } from '@testing-library/preact';

What you did:

Tried to import from @testing-library/preact'

What happened:

SyntaxError: The requested module '@testing-library/preact' does not provide an export named 'render'

      at jasmine2 (node_modules/jest-jasmine2/build/index.js:228:5)

Problem description:

Currently @testing-library/preact does not offer ESM output, which makes it unsuitable for testing in a native ESM environment. This will begin to be a problem especially now that Node 10 is EOL ("type": "module" was first valid in v12.0.0, the now oldest support version of Node).

@testing-library/react does however support ESM, so preact here is behind. Edit: Apparently not. Apparently Jest doesn't even follow the widely used practice of the module key: jestjs/jest#2702 (comment)

Suggested solution:

Offer ESM output. Will just take an alteration of the build script.

Support testing hooks in isolation

  • preact-testing-library version: any
  • preact version: X
  • node version: v12.13.1
  • npm (or yarn) version: yarn - 1.22.4

Hi! My team got into the situation where we needed to test some preact hooks, and we were looking for a way to do this in isolation and we tried the @testing-library/react-hooks library. Due to the reliance on react-test-renderer the react hooks testing library will probably never be compatible with preact.

With that being said, we decided to port the current @testing-library/react-hooks implementation to use preact, and we open sourced it on npm under @trivago/preact-hooks-testing-library.

Github Repo: https://github.com/trivago/preact-hooks-testing-library
npm: https://www.npmjs.com/package/@trivago/preact-hooks-testing-library

The big question at this point, is whether or not this library would be a good candidate to include under the @testing-library namespace?

๐Ÿ› onChange Event Misfiring

๐Ÿ› Bugs:
File an issue for bugs, missing documentation, or unexpected behavior.

  • preact-testing-library version: v2.0.1
  • preact version: v10.5.5
  • node version: v14.15.5
  • npm version: v6.14.11

What you did:

What happened:

The fireEvent.change didn't decorate the event the necessary way.

Reproduction repository:

https://github.com/bayleedev/preact-change-issue

Problem description:

This is what the docs suggest trying

// test.js:36
-  if (false) {
+ {
    const field = await screen.getByRole('textbox', { name: 'Comment Body' });
    fireEvent.change(field, {
      value: 'user123', // the docs just suggest setting this one
    });
    expect(field.value).toEqual('user123'); // Received: "default_value"
  }

Suggested solution:

I made a few modifications to get it working, but it's reaching in kinda deep:

// test.js:44
  // Change, working
  {
    const field = await screen.getByRole('textbox', { name: 'Comment Body' });
    const changeEvent = createEvent.change(field, {
      value: 'user123', // BROKE, possibly decorated in the library
      target: { value: 'user234' }, // ADD
    });
    changeEvent.inputType = 'insertText'; // ADD, required to get it to work
    await act(() => {
      return field.l.inputfalse(changeEvent);
      // return field.dispatchEvent(changeEvent) // DEL, this didn't work
    });
    // Assertion
    const textarea = screen.getByRole('textbox', { name: 'Comment Body' });
    expect(textarea.value).toEqual('on_change_value'); // SUCCESS!

    // Double assertion, to see if `body` was updated.
    const bodyData = screen.getByTestId('body-data');
    expect(bodyData.textContent).toEqual('on_change_value'); // SUCCESS!
  }

The test stops when the function passed from the component is called in the fireEvent action handler

  • preact-testing-library version: 2.0.1
  • preact version: 10.5.13
  • node version: 14.3.0
  • npm (or yarn) version: My npm's version is 7.11.1

Relevant code or config
I have defined a drag module to be used in the app.

This drag module receives the callback function defined in the component.

// apps/calendar/src/components/hooks/drag.ts
function useDrag({
  onDragStart = noop,
  onDrag = noop,
  onDragEnd = noop,
  onClick = noop,
  onCancel = noop,
}: DragListeners) {
  /*...*/
  const onMouseMove = (e: MouseEvent) => {
    /* ... */
    if (distance < DISTANCE) { // DISTANCE is 3
      distance += 1;

      return;
    }

    if (!isDragStartFired) {
      isDragStartFired = true;
      onDragStart(e); // 
Call the callback function passed from the component

      return;
    }

    onDrag(e); 
Call the callback function passed from the component
  };

  return {
    onMouseDown,
    onMouseMove,
    onMouseUp,
    onKeydown: onKeydownESC,
  };
}
// apps/calendar/test/app/components/daygrid/dayGrid.spec.tsx
  it('should create a guide element for the mouse event', () => {
    const getBoundingClientRectSpy = jest.fn(
      () =>
        ({
          width: 70,
          height: 100,
          left: 0,
          top: 0,
        } as DOMRect)
    );
    panel.getBoundingClientRect = getBoundingClientRectSpy;

    const { container } = render(
      <DayGrid
        options={option}
        calendar={calendar}
        appContainer={{ current: appContainer }}
        getMousePositionData={getMousePositionData(calendar, grids, panel)}
      />,
      { wrapper: StoreProvider }
    );

    const mouseArea = container.firstChild;

    if (!mouseArea) {
      return;
    }

    fireEvent.mouseDown(mouseArea, { clientX: 9, clientY: 20, button: 0 });
    fireEvent.mouseMove(document, { clientX: 15, clientY: 20 }); // distance 0
    fireEvent.mouseMove(document, { clientX: 15, clientY: 20 }); // distance 1
    fireEvent.mouseMove(document, { clientX: 15, clientY: 20 }); // distance 2

    
    fireEvent.mouseMove(document, { clientX: 15, clientY: 20 }); // # 1. onDragStart() callback function call
    fireEvent.mouseMove(document, { clientX: 15, clientY: 20 }); // # 2. onDrop() callback function call
    fireEvent.mouseUp(document, { clientX: 15, clientY: 40, button: 0 });

    // const guide = screen.getByTestId('creation-guide');
    // @TODO: Check the style of the guide element
    // expect(guide).toBeDefined();
  });

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2021-05-25 19 37 48

If you include the logic to call the component's callback function, the test will not run at all.

Reproduction repository:
https://github.com/nhn/tui.calendar/tree/test/daygrid-ui-test

$ git clone https://github.com/nhn/tui.calendar.git
$ cd tui.calendar
$ git co -b test/daygrid-ui-test origin/test/daygrid-ui-test 
$ npm i --legacy-peer-deps (using npm 7)
$ npm run test

Problem description:

  • disable following code

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2021-05-25 19 53 14

* enable following code

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2021-05-25 19 54 25

Suggested solution:
TC should work fine.

`eventWrapper` for dom-testing-library shouldn't be async

  • preact-testing-library version: 2.0.0
  • preact version: 10.4.8
  • node version: 14.10.0
  • npm (or yarn) version: Yarn 1.22.5

Relevant code or config

// fails:
import React from "preact/compat";
import { act, render, fireEvent } from "@testing-library/preact";

// works:
// import React from "react";
// import { act, render, fireEvent } from "@testing-library/react";

import userEvent from "@testing-library/user-event";

function ComboBox() {
  let inputRef = React.useRef();

  let buttonProps = {
    onMouseDown: (e) => {
      e.preventDefault();
    },
  };

  return (
    <div>
      <input ref={inputRef} />
      <button {...buttonProps} />
    </div>
  );
}

test("test", () => {
  const { getAllByRole, queryByRole } = render(<ComboBox />);

  let button = queryByRole("button");
  let combobox = queryByRole("combobox");
  expect(document.activeElement).toBe(document.body);
  act(() => {
    userEvent.click(button);
  });
  expect(document.activeElement).toBe(document.body);
});

What you did:

Call preventDefault on an onMouseDown event to (among other things) prevent the button being focused.

What happened:

preventDefault() doesn't prevent focussing.

Problem description:

Behaves differently compared to a browser.

Suggested solution:

The eventWrapper is async,

eventWrapper: async cb => {
let result
await act(() => {
result = cb()
})
return result
}

unlike react-testing-library: https://github.com/testing-library/react-testing-library/blob/693228ce10f23e2b695730ea88dbdaa35506e00e/src/pure.js#L11-L26

this causes fireEvent.mouseDown to return a promise, breaking @testing-library/user-event:

https://github.com/testing-library/user-event/blob/986e06aec056a99f26c9b119be78268d9605573a/src/click.js#L65

https://github.com/testing-library/dom-testing-library/blob/65024555ee18bb765ae62fb1ba9cf4e6dc7b9f0c/src/events.js#L6

Firing event by react-testing-library and handling it in onInput event

Hi all!
Need a help with react-testing-library. I use Preact in my project, and use preact-testing-library wrapper for RTL.
The problem is in the onInput event. The project is big and there are many controlled inputs. These inputs don't have onChange event handler, but they have onInput handler instead.
I'm trying to write a simple test for my component:

it('First test', async () => {
  const field = await screen.findByLabelText('label');
  // type in the field
  fireEvent.input(field,  { target: { value: 'BADBADBAD12345' }});
});

And this is a code fragment of my component:

<input
    type="tel"
    autoComplete="tel"
    id={id}
    title={title}
    name={name}
    className={classes}
    onPaste={this.pasteHandler}
    onInput={this.inputHandler}
    onBlur={this.blur}
    onFocus={this.focused}
    onKeyDown={this.keyDown}
    onChange={(e) => {console.log('changed ', e.target.value)}}
    value={this.state.value}
    required={required}
  />

When I call the fireEvent.change method, the onChange handler called. But no method (fireEvent.change, fireEvent.input) does not fire the onInput handler.
I tried to use @testing-library/user-event, and call userEvent.type, but still no effect.
Can somebody help with this issue?
I don't have any option to change the onInput to onChange.

"SecurityError: localStorage is not available for opaque origins" when testing

Newer versions of jsdom will throw a "SecurityError: localStorage is not available for opaque origins" error unless a test URL is provided.

 FAIL  src/__tests__/preact-redux.js
  โ— Test suite failed to run
    SecurityError: localStorage is not available for opaque origins
      
      at Window.get localStorage [as localStorage] (node_modules/jsdom/lib/jsdom/browser/Window.js:257:15)
          at Array.forEach (<anonymous>)

I don't know how to get around it using this project's stack. If using jsdom through Jest, this is the fix: jestjs/jest#6766 (comment)

touch events (onTouchEnter) do not work in jest jsdom

  • preact-testing-library version: 2.0.1
  • preact version: 10.7.0
  • node version: 16.14.2
  • npm (or yarn) version: yarn 1.22.17

Relevant code or config

https://github.com/rburgst/preact-testing-lib-pointer-events-bug

Problem description:

The following does not work

interface TestComponentProps {
    onPointerEnter: () => void
    onClick: () => void
}
export const TestComponent : FunctionComponent<TestComponentProps> = ({onPointerEnter, onClick}) => {
    return <div onPointerEnter={onPointerEnter} onClick={onClick} data-testid="test-div">My Div</div>
}

and the corresponding test

interface TestComponentProps {
    onPointerEnter: () => void
    onClick: () => void
}
export const TestComponent : FunctionComponent<TestComponentProps> = ({onPointerEnter, onClick}) => {
    return <div onPointerEnter={onPointerEnter} onClick={onClick} data-testid="test-div">My Div</div>
}

The problem appears that the listeners in jsdom are registered with PointerEnter while the event being fired is pointerenter.

Reproduction repository:

https://github.com/rburgst/preact-testing-lib-pointer-events-bug

Suggested solution:

It looks to me as if the listeners in jsdom should be registered all lowercase.

`autoFocus` not being applied

  • preact-testing-library version: 2.0.0
  • preact version: 10.4.7
  • node version: 14
  • npm (or yarn) version: .22.4

Relevant code or config

import React from "preact/compat";
import { render, fireEvent } from "@testing-library/preact";

// works:
// import React from "react";
// import { render, fireEvent } from "@testing-library/react";

test("test", () => {
  const { getByTestId } = render(
    <div>
      <input data-testid="input" autoFocus />
    </div>
  );

  expect(document.activeElement).toBe(getByTestId("input"));
});

What you did:

See code

What happened:

 FAIL  ./test.js
  โœ• test (25 ms)

  โ— test

    expect(received).toBe(expected) // Object.is equality

    - Expected  - 0
    + Received  + 6

    + <body>
    +   <div>
    +     <div>
            <input
              autofocus="true"
              data-testid="input"
            />
    +     </div>
    +   </div>
    + </body>

      12 |   );
      13 |
    > 14 |   expect(document.activeElement).toBe(getByTestId("input"));
         |                                  ^
      15 | });
      16 |

      at Object.<anonymous> (test.js:14:34)

Reproduction repository:

https://codesandbox.io/s/beautiful-cannon-gw4ee?file=/src/index.test.js

Problem description:

Apparently, the <input autoFocus> element isn't focused. The example works when changing out the imports to use React.

Suggested solution:

Autofocus the element....

Add ESM support

  • preact-testing-library version: 2.0.1
  • preact version: any
  • node version: any
  • npm (or yarn) version: any

Problem description:

This package doesn't have ESM support. This is needed for vitest to properly load ESM version of preact: related issue

Suggested solution:

Bundle ESM and add it to exports field, so Node can resolve it automatically.

Remove react from package.json

Currently, react is part of package.json, we should remove this. Removing actually throwing the document not defined issue when running test cases, have to fix this.

Working with preact/compat

  • preact-testing-library version: 1.0.2
  • preact version: 10.4.4
  • node version: 12.16.3
  • npm (or yarn) version: yarn 1.22.4

Relevant code or config

// jest.config.js
moduleNameMapper: {
    '^react$': 'preact/compat',
    '^react-dom/test-utils$': 'preact/test-utils',
    '^react-dom$': 'preact/compat',
    '^@testing-library/react$': '@testing-library/preact',

What you did:
Tried to alias @testing-library/react to @testing-library/preact because we're aliasing react and react-dom to preact/compat.

What happened:
Fails with an error that it cannot find waitFor, but I also suspect there may be other differences in the api's of both the libraries.

Reproduction repository:

Problem description:
We'd like our jest tests to run against preact and not react as long as we are using the preact/compat alias so that we know our tests(and hence implementations) work in preact.

Suggested solution:
Firstly, update the @testing-library/dom package to the latest version, and secondly, match any other mismatches in the library apis.

Is this project dead?

It's been 3 years since the last meaningful commits to master, PRs that fix critical defects remain unmerged and new issues are left unattended for weeks or months. This appears to have all the signs of a dead project.

Are there plans to transfer ownership to new maintainers?

state updates do not trigger render after rerender() call

  • preact-testing-library version: 2.0.0
  • preact version: 10.5.2
  • node version: 14.8.0
  • yarn version: 1.22.4

If rerender() was called and then component's (function or class) state gets updated (for example with 'setTimeout'), component will not render.

Relevant code or config

// src/test.js
const { h } = require('preact')
const { useState, useEffect } = require('preact/hooks')
const { render, waitFor } = require('@testing-library/preact')

function Comp({}) {
	const [val, setVal] = useState('original value')
	useEffect(() => {
		setTimeout(() => setVal('new value'), 300) // <- 300ms delay
	}, [])
	return <div>{val}</div>
}

it('fails', async () => {
	const { container, rerender } = render(<Comp />)
	rerender(<Comp />) // <- cause
	// await new Promise(r => setTimeout(r, 350)) // <- fix
	await waitFor(() => {
		expect(container.textContent).toEqual('new value')
	})
})
// babel.config.js
module.exports = {
	plugins: [['@babel/plugin-transform-react-jsx', { pragma: 'h' }]],
}

What I did:

Run test with ./node_modules/.bin/jest

What happened:

    Expected: "new value"
    Received: "original value"

Same happens for class components https://github.com/3bl3gamer/preact-testing-library-bug-example/blob/master/src/test.js#L13

Same happens even if rerender() was called in different test https://github.com/3bl3gamer/preact-testing-library-bug-example/blob/master/src/test.js#L38-L54

If rerender() is removed, test passes.

If test is manually paused with setTimeout until update has happened, it passes. Despite container.textContent still returns old value just before waitFor:

await new Promise(r => setTimeout(r, 350))
console.log(container.textContent) // <-- 'original value'
await waitFor(() => {

If preact is replaced with react (and @testing-library/react), test also passes.

Reproduction repository: https://github.com/3bl3gamer/preact-testing-library-bug-example

Full failure output:

 FAIL  src/test.js
  โœ• fails (1016 ms)

  โ— fails

    expect(received).toEqual(expected) // deep equality

    Expected: "new value"
    Received: "original value"

    <html>
      <head />
      <body>
        <div>
          <div>
            original value
          </div>
        </div>
      </body>
    </html>

      31 | 	// await new Promise(r => setTimeout(r, 350)) // <- fix
      32 | 	await waitFor(() => {
    > 33 | 		expect(container.textContent).toEqual('new value')
         | 		                              ^
      34 | 	})
      35 | })
      36 | 

      at src/test.js:33:33
      at runWithExpensiveErrorDiagnosticsDisabled (node_modules/@testing-library/dom/dist/config.js:51:12)
      at checkCallback (node_modules/@testing-library/dom/dist/wait-for.js:102:75)
      at Timeout.task [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:391:19)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.425 s
Ran all test suites.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.