Skip to content

[Feature] Allow custom mount fixture for component testing #14345

@mlmmn

Description

@mlmmn

It would be great to be able to use pattern well adopted in React Testing Library tests - a custom render function which contains wrappers required by each component (ie. providers). Let's take a look at the example:

// Button.test.tsx
import { test as base, expect } from '@playwright/experimental-ct-react';
import { CustomWrapper } from 'src/CustomWrapper';
import { Button } from './Button';

const test = base.extend({
  mount: async ({ mount: baseMount }, use) => {
    const mount: typeof baseMount = (component) => baseMount(<CustomWrapper>{component}</CustomWrapper>);

    await use(mount);
  }
})

test('works', async ({ mount }) => {
  const component = await mount(<Button>a button</Button>);

  await expect(await component.screenshot()).toMatchSnapshot();
})

The above example works, because everything is implemented within the test module. This pattern, however, is not working when extracting extended test object to a separate module like so:

// componentTest.tsx
import { test as base } from '@playwright/experimental-ct-react';
import { CustomWrapper } from 'src/CustomWrapper';

const test = base.extend({
  mount: async ({ mount: baseMount }, use) => {
    const mount: typeof baseMount = (component) => baseMount(<CustomWrapper>{component}</CustomWrapper>);

    await use(mount);
  }
})

export * from '@playwright/experimental-ct-react';
export { test };
// Button.test.tsx
import { test, expect } from 'src/componentTest'; // <----- this imports resolve to strings
import { Button } from './Button';

test('works', async ({ mount }) => {
  const component = await mount(<Button>a button</Button>);

  await expect(await component.screenshot()).toMatchSnapshot();
})

I assume this is due to custom tsxTransform.ts that keeps track of every component/jsx module that is imported within test module.

SIDE NOTE: Even though I can't really figure out if it's possible to easily workaround this, in order to actually be able to test I found a hacky way to achieve this result by monkey-patching react-dom like so:

// react-dom.patched.tsx
import _ReactDOM from '../node_modules/react-dom';
import { CustomWrapper } from './CustomWrapper';

const ReactDOM = Object.create(_ReactDOM);

ReactDOM.render = (children, el) => _ReactDOM.render(<CustomWrapper>{children}</CustomWrapper>, el);

export default ReactDOM;

and then I alias react-dom in Vite configuration that is passed to Playwright.

What do you guys think about it?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions