Skip to content

Commit 6bfc495

Browse files
authored
Playwright tests refactoring, pt.2 (blockscout#1787)
* create storageState fixture * remove auth fixture * renaming * migrate bridge tokens and shibarium rollup tests * migrate to common app config * update screenshots * re-implement fixtures for mocking envs, features and auth state * update screenshot
1 parent d1f7e16 commit 6bfc495

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+775
-1617
lines changed

playwright/TestApp.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { WagmiProvider } from 'wagmi';
66

77
import type { Props as PageProps } from 'nextjs/getServerSideProps';
88

9+
import config from 'configs/app';
910
import { AppContextProvider } from 'lib/contexts/app';
1011
import { SocketProvider } from 'lib/socket/context';
1112
import wagmiConfig from 'lib/web3/wagmiConfig';
@@ -43,7 +44,7 @@ const TestApp = ({ children, withSocket, appContext = defaultAppContext }: Props
4344
return (
4445
<ChakraProvider theme={ theme }>
4546
<QueryClientProvider client={ queryClient }>
46-
<SocketProvider url={ withSocket ? `ws://${ app.domain }:${ app.socketPort }` : undefined }>
47+
<SocketProvider url={ withSocket ? `ws://${ config.app.host }:${ app.socketPort }` : undefined }>
4748
<AppContextProvider { ...appContext }>
4849
<GrowthBookProvider>
4950
<WagmiProvider config={ wagmiConfig! }>

playwright/fixtures/auth.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
import type { BrowserContext } from '@playwright/test';
1+
import type { BrowserContext, TestFixture } from '@playwright/test';
22

3+
import config from 'configs/app';
34
import * as cookies from 'lib/cookies';
4-
import { domain } from 'playwright/utils/app';
55

6-
export default function authFixture(context: BrowserContext) {
7-
context.addCookies([ { name: cookies.NAMES.API_TOKEN, value: 'foo', domain, path: '/' } ]);
6+
export function authenticateUser(context: BrowserContext) {
7+
context.addCookies([ { name: cookies.NAMES.API_TOKEN, value: 'foo', domain: config.app.host, path: '/' } ]);
88
}
9+
10+
export const contextWithAuth: TestFixture<BrowserContext, { context: BrowserContext }> = async({ context }, use) => {
11+
authenticateUser(context);
12+
use(context);
13+
};

playwright/fixtures/contextWithEnvs.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ interface Env {
77
value: string;
88
}
99

10-
// keep in mind that all passed variables here should be present in env config files (.env.pw or .env.poa)
10+
/**
11+
* @deprecated please use mockEnvs fixture
12+
*
13+
* @export
14+
* @param {Array<Env>} envs
15+
* @return {*} {Parameters<typeof test.extend>[0]['context']}
16+
*/
1117
export default function contextWithEnvsFixture(envs: Array<Env>): Parameters<typeof test.extend>[0]['context'] {
1218
return async({ browser }, use) => {
1319
const context = await createContextWithStorage(browser, envs);

playwright/fixtures/contextWithFeatures.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ interface Feature {
77
value: unknown;
88
}
99

10+
/**
11+
* @deprecated please use mockFeatures fixture
12+
*
13+
* @export
14+
* @param {Array<Feature>} envs
15+
* @return {*} {Parameters<typeof test.extend>[0]['context']}
16+
*/
1017
export default function contextWithFeaturesFixture(envs: Array<Feature>): Parameters<typeof test.extend>[0]['context'] {
1118
return async({ browser }, use) => {
1219
const storageItems = envs.map(({ id, value }) => ({ name: `pw_feature:${ id }`, value: JSON.stringify(value) }));

playwright/fixtures/createContextWithStorage.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import type { Browser } from '@playwright/test';
22

3-
import * as app from 'playwright/utils/app';
3+
import config from 'configs/app';
44

5+
/**
6+
* @deprecated please use mockEnvs or mockFeatures fixture
7+
*
8+
* @export
9+
* @param {Browser} browser
10+
* @param {Array<{ name: string; value: string }>} localStorage
11+
* @return {*}
12+
*/
513
export default async function createContextWithEnvs(browser: Browser, localStorage: Array<{ name: string; value: string }>) {
614
return browser.newContext({
715
storageState: {
816
origins: [
9-
{ origin: app.url, localStorage },
17+
{ origin: config.app.baseUrl, localStorage },
1018
],
1119
cookies: [],
1220
},
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { TestFixture, Page } from '@playwright/test';
2+
3+
import type { WalletProvider } from 'types/web3';
4+
5+
export type InjectMetaMaskProvider = () => Promise<void>;
6+
7+
const fixture: TestFixture<InjectMetaMaskProvider, { page: Page }> = async({ page }, use) => {
8+
await use(async() => {
9+
await page.evaluate(() => {
10+
window.ethereum = {
11+
isMetaMask: true,
12+
_events: {},
13+
} as WalletProvider;
14+
});
15+
});
16+
};
17+
18+
export default fixture;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { TestFixture, Page } from '@playwright/test';
2+
3+
import config from 'configs/app';
4+
import { buildExternalAssetFilePath } from 'configs/app/utils';
5+
6+
export type MockConfigResponseFixture = (envName: string, envValue: string, content: string, isImage?: boolean) => Promise<void>;
7+
8+
const fixture: TestFixture<MockConfigResponseFixture, { page: Page }> = async({ page }, use) => {
9+
await use(async(envName, envValue, content, isImage) => {
10+
const url = config.app.baseUrl + buildExternalAssetFilePath(envName, envValue);
11+
12+
if (isImage) {
13+
await page.route(url, (route) => route.fulfill({
14+
status: 200,
15+
path: content,
16+
}));
17+
} else {
18+
await page.route(url, (route) => route.fulfill({
19+
status: 200,
20+
body: content,
21+
}));
22+
}
23+
24+
});
25+
};
26+
27+
export default fixture;

playwright/fixtures/mockEnvs.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* eslint-disable max-len */
2+
import type { TestFixture, Page } from '@playwright/test';
3+
4+
export type MockEnvsFixture = (envs: Array<[string, string]>) => Promise<void>;
5+
6+
const fixture: TestFixture<MockEnvsFixture, { page: Page }> = async({ page }, use) => {
7+
await use(async(envs) => {
8+
for (const [ name, value ] of envs) {
9+
await page.evaluate(({ name, value }) => {
10+
window.localStorage.setItem(name, value);
11+
}, { name, value });
12+
}
13+
});
14+
};
15+
16+
export default fixture;
17+
18+
export const ENVS_MAP: Record<string, Array<[string, string]>> = {
19+
shibariumRollup: [
20+
[ 'NEXT_PUBLIC_ROLLUP_TYPE', 'shibarium' ],
21+
[ 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', 'https://localhost:3101' ],
22+
],
23+
bridgedTokens: [
24+
[ 'NEXT_PUBLIC_BRIDGED_TOKENS_CHAINS', '[{"id":"1","title":"Ethereum","short_title":"ETH","base_url":"https://eth.blockscout.com/token/"},{"id":"56","title":"Binance Smart Chain","short_title":"BSC","base_url":"https://bscscan.com/token/"},{"id":"99","title":"POA","short_title":"POA","base_url":"https://blockscout.com/poa/core/token/"}]' ],
25+
[ 'NEXT_PUBLIC_BRIDGED_TOKENS_BRIDGES', '[{"type":"omni","title":"OmniBridge","short_title":"OMNI"},{"type":"amb","title":"Arbitrary Message Bridge","short_title":"AMB"}]' ],
26+
],
27+
userOps: [
28+
[ 'NEXT_PUBLIC_HAS_USER_OPS', 'true' ],
29+
],
30+
};

playwright/fixtures/mockFeatures.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* eslint-disable max-len */
2+
import type { TestFixture, Page } from '@playwright/test';
3+
4+
export type MockFeaturesFixture = (features: Array<[string, unknown]>) => Promise<void>;
5+
6+
const fixture: TestFixture<MockFeaturesFixture, { page: Page }> = async({ page }, use) => {
7+
await use(async(features) => {
8+
for (const [ name, value ] of features) {
9+
await page.evaluate(({ name, value }) => {
10+
window.localStorage.setItem(`pw_feature:${ name }`, JSON.stringify(value));
11+
}, { name, value });
12+
}
13+
});
14+
};
15+
16+
export default fixture;

playwright/lib.tsx

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,35 @@ import { test as base } from '@playwright/experimental-ct-react';
33

44
import * as textAdMock from 'mocks/ad/textAd';
55

6-
import type { MockApiResponseFixture } from './fixtures/mockApiResponse';
7-
import mockApiResponseFixture from './fixtures/mockApiResponse';
8-
import type { MockAssetResponseFixture } from './fixtures/mockAssetResponse';
9-
import mockAssetResponseFixture from './fixtures/mockAssetResponse';
10-
import type { RenderFixture } from './fixtures/render';
11-
import renderFixture from './fixtures/render';
12-
import type { CreateSocketFixture } from './fixtures/socketServer';
13-
import { createSocket as createSocketFixture } from './fixtures/socketServer';
6+
import * as injectMetaMaskProvider from './fixtures/injectMetaMaskProvider';
7+
import * as mockApiResponse from './fixtures/mockApiResponse';
8+
import * as mockAssetResponse from './fixtures/mockAssetResponse';
9+
import * as mockConfigResponse from './fixtures/mockConfigResponse';
10+
import * as mockEnvs from './fixtures/mockEnvs';
11+
import * as mockFeatures from './fixtures/mockFeatures';
12+
import * as render from './fixtures/render';
13+
import * as socketServer from './fixtures/socketServer';
1414

1515
interface Fixtures {
16-
render: RenderFixture;
17-
mockApiResponse: MockApiResponseFixture;
18-
mockAssetResponse: MockAssetResponseFixture;
19-
createSocket: CreateSocketFixture;
16+
render: render.RenderFixture;
17+
mockApiResponse: mockApiResponse.MockApiResponseFixture;
18+
mockAssetResponse: mockAssetResponse.MockAssetResponseFixture;
19+
mockConfigResponse: mockConfigResponse.MockConfigResponseFixture;
20+
mockEnvs: mockEnvs.MockEnvsFixture;
21+
mockFeatures: mockFeatures.MockFeaturesFixture;
22+
createSocket: socketServer.CreateSocketFixture;
23+
injectMetaMaskProvider: injectMetaMaskProvider.InjectMetaMaskProvider;
2024
}
2125

2226
const test = base.extend<Fixtures>({
23-
render: renderFixture,
24-
mockApiResponse: mockApiResponseFixture,
25-
mockAssetResponse: mockAssetResponseFixture,
26-
createSocket: createSocketFixture,
27+
render: render.default,
28+
mockApiResponse: mockApiResponse.default,
29+
mockAssetResponse: mockAssetResponse.default,
30+
mockConfigResponse: mockConfigResponse.default,
31+
mockEnvs: mockEnvs.default,
32+
mockFeatures: mockFeatures.default,
33+
createSocket: socketServer.createSocket,
34+
injectMetaMaskProvider: injectMetaMaskProvider.default,
2735
});
2836

2937
test.beforeEach(async({ page }) => {

playwright/mocks/banner.html

Lines changed: 0 additions & 94 deletions
This file was deleted.

playwright/utils/app.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
export const url = `${ process.env.NEXT_PUBLIC_APP_PROTOCOL }://${ process.env.NEXT_PUBLIC_APP_HOST }:${ process.env.NEXT_PUBLIC_APP_PORT }`;
2-
3-
export const domain = process.env.NEXT_PUBLIC_APP_HOST;
4-
51
export const socketPort = 3200;

playwright/utils/buildApiUrl.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import config from 'configs/app';
44
import type { ResourceName, ResourcePathParams } from 'lib/api/resources';
55
import { RESOURCES } from 'lib/api/resources';
66

7-
// DEPRECATED
8-
97
/**
108
* @deprecated please use fixture mockApiResponse from playwright/lib.tsx for rendering test suite
119
*

playwright/utils/configs.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,6 @@ export const featureEnvs = {
2020
{ name: 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', value: 'https://localhost:3101' },
2121
{ name: 'NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL', value: 'https://localhost:3102' },
2222
],
23-
shibariumRollup: [
24-
{ name: 'NEXT_PUBLIC_ROLLUP_TYPE', value: 'shibarium' },
25-
{ name: 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', value: 'https://localhost:3101' },
26-
],
27-
bridgedTokens: [
28-
{
29-
name: 'NEXT_PUBLIC_BRIDGED_TOKENS_CHAINS',
30-
value: '[{"id":"1","title":"Ethereum","short_title":"ETH","base_url":"https://eth.blockscout.com/token/"},{"id":"56","title":"Binance Smart Chain","short_title":"BSC","base_url":"https://bscscan.com/token/"},{"id":"99","title":"POA","short_title":"POA","base_url":"https://blockscout.com/poa/core/token/"}]',
31-
},
32-
{
33-
name: 'NEXT_PUBLIC_BRIDGED_TOKENS_BRIDGES',
34-
value: '[{"type":"omni","title":"OmniBridge","short_title":"OMNI"},{"type":"amb","title":"Arbitrary Message Bridge","short_title":"AMB"}]',
35-
},
36-
],
3723
txInterpretation: [
3824
{ name: 'NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER', value: 'blockscout' },
3925
],

types/api/tokens.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export type TokensResponse = {
88
items_count: number;
99
name: string;
1010
market_cap: string | null;
11-
};
11+
} | null;
1212
}
1313

1414
export type TokensFilters = { q: string; type: Array<TokenType> | undefined };

0 commit comments

Comments
 (0)