Issue 1:
System info

Playwright Version: [v1.35]

Operating System: [Windows]

Browser: [Edge]

Other info:

Source code

I provided exact source code that allows reproducing the issue locally.

The code of a simple page

<html>
<body>
THING
<img src="api/myImage.png"/>
</body>
</html>

That end up with the following image in playwright because I try to mock my api and it's not up

with my following test, only a 404 explaining my image can't be found (normal)

test("TEST", async ({ page }) => {
await page.goto('index.html');
})

Link to the GitHub repository with the repro

[https://github.com/your_profile/playwright_issue_title]

or

Config file

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
projects: [
{
name: 'Microsoft Edge',
use: { ...devices['Desktop Edge'], channel: 'msedge', baseURL: 'http://localhost:4200/' },
}
});

Test file (self-contained)

import { test } from '@playwright/test';

test("TEST", async ({ page }) => {
await page.route(`/api/myImage.png`, async route => {

await route.fulfill({
status: 200,
path: "screenshot.png",
});
});

await page.goto('index.html');
})

Steps

[Run the test]

[...]

Expected

The image is mocked and screenshot.png is displayed on the interface

Actual

The image is not displayed on my interface, and the interface of my web app doesn't display anymore

page.goto: Navigation failed because page was closed!

navigating to "http://localhost:8080/index.html", waiting until "load"

Issue 2:
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?