This commit is contained in:
sand4rt 2022-08-16 20:25:55 +02:00 коммит произвёл GitHub
Родитель 93b4fa3537
Коммит e6994b5dc1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 208 добавлений и 87 удалений

Просмотреть файл

@ -1,9 +1,10 @@
<!DOCTYPE html>
<html lang="">
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>React App</title>
</head>
<body>
<div id="root"></div>

Просмотреть файл

@ -0,0 +1,10 @@
import '../src/assets/index.css';
import { beforeMount, afterMount } from '@playwright/experimental-ct-react/hooks';
beforeMount(async ({ hooksConfig }) => {
console.log(`Before mount: ${JSON.stringify(hooksConfig)}`);
});
afterMount(async ({}) => {
console.log(`After mount`);
});

Просмотреть файл

@ -1,9 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-react';
import App from './App';
test.use({ viewport: { width: 500, height: 500 } });
test('should work', async ({ mount }) => {
const component = await mount(<App></App>);
await expect(component).toContainText('Learn React');
});

Просмотреть файл

@ -1,7 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-react'
import { DelayedData } from './DelayedData';
test('toHaveText works on delayed data', async ({ mount }) => {
const component = await mount(<DelayedData data='complete' />);
await expect(component).toHaveText('complete');
});

Просмотреть файл

@ -1,14 +0,0 @@
import React, { useEffect, useState } from 'react';
export const DelayedData: React.FC<{ data: string }> = ({ data }) => {
const [status, setStatus] = useState('loading');
useEffect(() => {
const timeout = setTimeout(() => setStatus(data), 500);
return () => {
clearTimeout(timeout);
}
}, [data])
return <p>{status}</p>
};

Просмотреть файл

@ -1,14 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-react';
test('should marshall events', async ({ mount }) => {
let event: any;
const component = await mount(<button onClick={e => event = e }>Submit</button>);
await component.click();
expect(event).toEqual(expect.objectContaining({
type: 'click',
pageX: expect.any(Number),
pageY: expect.any(Number),
ctrlKey: false,
isTrusted: true,
}));
});

Просмотреть файл

@ -1,30 +0,0 @@
import { test as _test, expect } from '@playwright/experimental-ct-react'
import { Fetch } from './Fetch';
import { serverFixtures } from '../../../../tests/config/serverFixtures';
const test = _test.extend(serverFixtures);
test('components routing should go through context', async ({ mount, context, server }) => {
server.setRoute('/hello', (req, res) => {
res.write('served via server');
res.end();
});
let markRouted: (url: string) => void;
const routedViaContext = new Promise(res => markRouted = res);
await context.route('**/hello', async (route, request) => {
markRouted(`${request.method()} ${request.url()}`);
await route.fulfill({
body: 'intercepted',
});
});
const whoServedTheRequest = Promise.race([
server.waitForRequest('/hello').then((req) => `served via server: ${req.method} ${req.url}`),
routedViaContext.then(req => `served via context: ${req}`),
]);
const component = await mount(<Fetch url={server.PREFIX + '/hello'} />);
await expect.soft(whoServedTheRequest).resolves.toMatch(/served via context: GET.*\/hello.*/i);
await expect.soft(component).toHaveText('intercepted');
});

Просмотреть файл

@ -1,9 +0,0 @@
import React, { useEffect, useState } from 'react';
export const Fetch: React.FC<{ url: string }> = ({ url }) => {
const [data, setData] = useState('no response yet');
useEffect(() => {
fetch(url).then(res => res.text()).then(setData);
}, [url]);
return <p>{data}</p>;
}

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 2.6 KiB

После

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Просмотреть файл

@ -0,0 +1,7 @@
type ButtonProps = {
title: string;
onClick?(props: string): void;
}
export default function Button(props: ButtonProps) {
return <button onClick={() => props.onClick?.('hello')}>{props.title}</button>
}

Просмотреть файл

@ -0,0 +1,15 @@
type DefaultChildrenProps = {
children?: any;
}
export default function DefaultChildren(props: DefaultChildrenProps) {
return <div>
<h1>Welcome!</h1>
<main>
{props.children}
</main>
<footer>
Thanks for visiting.
</footer>
</div>
}

Просмотреть файл

@ -0,0 +1,16 @@
import { useEffect, useState } from 'react';
type DelayedData = {
data: string;
}
export default function DelayedData(props: DelayedData) {
const [status, setStatus] = useState('loading');
useEffect(() => {
const timeout = setTimeout(() => setStatus(props.data), 500);
return () => clearTimeout(timeout);
}, [props.data])
return <p>{status}</p>
};

Просмотреть файл

@ -0,0 +1,13 @@
import React, { useEffect, useState } from 'react';
type FetchProps = {
url: string;
}
export default function Fetch(props: FetchProps) {
const [data, setData] = useState('no response yet');
useEffect(() => {
fetch(props.url).then(res => res.text()).then(setData);
}, [props.url]);
return <p>{data}</p>;
}

Просмотреть файл

@ -0,0 +1,6 @@
export default function MultiRoot() {
return <>
<div>root 1</div>
<div>root 2</div>
</>
}

Просмотреть файл

@ -0,0 +1,18 @@
type MultipleChildrenProps = {
children?: [any, any, any];
}
export default function MultipleChildren(props: MultipleChildrenProps) {
return <div>
<header>
{props.children?.at(0)}
</header>
<main>
{props.children?.at(1)}
</main>
<footer>
{props.children?.at(2)}
</footer>
</div>
}

Просмотреть файл

@ -0,0 +1,118 @@
import { test, expect } from '@playwright/experimental-ct-react'
import { serverFixtures } from '../../../../tests/config/serverFixtures';
import Fetch from './components/Fetch';
import DelayedData from './components/DelayedData';
import Button from './components/Button';
import DefaultChildren from './components/DefaultChildren';
import MultipleChildren from './components/MultipleChildren';
import MultiRoot from './components/MultiRoot';
test.use({ viewport: { width: 500, height: 500 } });
test('props should work', async ({ mount }) => {
const component = await mount(<Button title="Submit" />);
await expect(component).toContainText('Submit');
});
test('callback should work', async ({ mount }) => {
const messages: string[] = []
const component = await mount(<Button title="Submit" onClick={data => {
messages.push(data)
}}></Button>)
await component.click()
expect(messages).toEqual(['hello'])
})
test('default slot should work', async ({ mount }) => {
const component = await mount(<DefaultChildren>
Main Content
</DefaultChildren>)
await expect(component).toContainText('Main Content')
})
test('multiple children should work', async ({ mount }) => {
const component = await mount(<DefaultChildren>
<div id="one">One</div>
<div id="two">Two</div>
</DefaultChildren>)
await expect(component.locator('#one')).toContainText('One')
await expect(component.locator('#two')).toContainText('Two')
})
test('named children should work', async ({ mount }) => {
const component = await mount(<MultipleChildren>
<div>Header</div>
<div>Main Content</div>
<div>Footer</div>
</MultipleChildren>);
await expect(component).toContainText('Header')
await expect(component).toContainText('Main Content')
await expect(component).toContainText('Footer')
})
test('children should callback', async ({ mount }) => {
let clickFired = false;
const component = await mount(<DefaultChildren>
<span onClick={() => clickFired = true}>Main Content</span>
</DefaultChildren>);
await component.locator('text=Main Content').click();
expect(clickFired).toBeTruthy();
})
test('should run hooks', async ({ page, mount }) => {
const messages: string[] = [];
page.on('console', m => messages.push(m.text()));
await mount(<Button title="Submit" />, {
hooksConfig: {
route: 'A'
}
});
expect(messages).toEqual(['Before mount: {\"route\":\"A\"}', 'After mount']);
});
test('should unmount', async ({ page, mount }) => {
const component = await mount(<Button title="Submit" />)
await expect(page.locator('#root')).toContainText('Submit')
await component.unmount();
await expect(page.locator('#root')).not.toContainText('Submit');
});
test('unmount a multi root component should work', async ({ mount, page }) => {
const component = await mount(<MultiRoot />)
await expect(page.locator('#root')).toContainText('root 1')
await expect(page.locator('#root')).toContainText('root 2')
await component.unmount()
await expect(page.locator('#root')).not.toContainText('root 1')
await expect(page.locator('#root')).not.toContainText('root 2')
})
test('toHaveText works on delayed data', async ({ mount }) => {
const component = await mount(<DelayedData data='complete' />);
await expect(component).toHaveText('complete');
});
const testWithServer = test.extend(serverFixtures);
testWithServer('components routing should go through context', async ({ mount, context, server }) => {
server.setRoute('/hello', (req, res) => {
res.write('served via server');
res.end();
});
let markRouted: (url: string) => void;
const routedViaContext = new Promise(res => markRouted = res);
await context.route('**/hello', async (route, request) => {
markRouted(`${request.method()} ${request.url()}`);
await route.fulfill({
body: 'intercepted',
});
});
const whoServedTheRequest = Promise.race([
server.waitForRequest('/hello').then((req) => `served via server: ${req.method} ${req.url}`),
routedViaContext.then(req => `served via context: ${req}`),
]);
const component = await mount(<Fetch url={server.PREFIX + '/hello'} />);
await expect.soft(whoServedTheRequest).resolves.toMatch(/served via context: GET.*\/hello.*/i);
await expect.soft(component).toHaveText('intercepted');
});