Skip to content

Commit

Permalink
Playwright tests refactoring, pt.2 (blockscout#1787)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
tom2drum authored Apr 17, 2024
1 parent d1f7e16 commit 6bfc495
Show file tree
Hide file tree
Showing 45 changed files with 775 additions and 1,617 deletions.
3 changes: 2 additions & 1 deletion playwright/TestApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { WagmiProvider } from 'wagmi';

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

import config from 'configs/app';
import { AppContextProvider } from 'lib/contexts/app';
import { SocketProvider } from 'lib/socket/context';
import wagmiConfig from 'lib/web3/wagmiConfig';
Expand Down Expand Up @@ -43,7 +44,7 @@ const TestApp = ({ children, withSocket, appContext = defaultAppContext }: Props
return (
<ChakraProvider theme={ theme }>
<QueryClientProvider client={ queryClient }>
<SocketProvider url={ withSocket ? `ws://${ app.domain }:${ app.socketPort }` : undefined }>
<SocketProvider url={ withSocket ? `ws://${ config.app.host }:${ app.socketPort }` : undefined }>
<AppContextProvider { ...appContext }>
<GrowthBookProvider>
<WagmiProvider config={ wagmiConfig! }>
Expand Down
13 changes: 9 additions & 4 deletions playwright/fixtures/auth.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { BrowserContext } from '@playwright/test';
import type { BrowserContext, TestFixture } from '@playwright/test';

import config from 'configs/app';
import * as cookies from 'lib/cookies';
import { domain } from 'playwright/utils/app';

export default function authFixture(context: BrowserContext) {
context.addCookies([ { name: cookies.NAMES.API_TOKEN, value: 'foo', domain, path: '/' } ]);
export function authenticateUser(context: BrowserContext) {
context.addCookies([ { name: cookies.NAMES.API_TOKEN, value: 'foo', domain: config.app.host, path: '/' } ]);
}

export const contextWithAuth: TestFixture<BrowserContext, { context: BrowserContext }> = async({ context }, use) => {
authenticateUser(context);
use(context);
};
8 changes: 7 additions & 1 deletion playwright/fixtures/contextWithEnvs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ interface Env {
value: string;
}

// keep in mind that all passed variables here should be present in env config files (.env.pw or .env.poa)
/**
* @deprecated please use mockEnvs fixture
*
* @export
* @param {Array<Env>} envs
* @return {*} {Parameters<typeof test.extend>[0]['context']}
*/
export default function contextWithEnvsFixture(envs: Array<Env>): Parameters<typeof test.extend>[0]['context'] {
return async({ browser }, use) => {
const context = await createContextWithStorage(browser, envs);
Expand Down
7 changes: 7 additions & 0 deletions playwright/fixtures/contextWithFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ interface Feature {
value: unknown;
}

/**
* @deprecated please use mockFeatures fixture
*
* @export
* @param {Array<Feature>} envs
* @return {*} {Parameters<typeof test.extend>[0]['context']}
*/
export default function contextWithFeaturesFixture(envs: Array<Feature>): Parameters<typeof test.extend>[0]['context'] {
return async({ browser }, use) => {
const storageItems = envs.map(({ id, value }) => ({ name: `pw_feature:${ id }`, value: JSON.stringify(value) }));
Expand Down
12 changes: 10 additions & 2 deletions playwright/fixtures/createContextWithStorage.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import type { Browser } from '@playwright/test';

import * as app from 'playwright/utils/app';
import config from 'configs/app';

/**
* @deprecated please use mockEnvs or mockFeatures fixture
*
* @export
* @param {Browser} browser
* @param {Array<{ name: string; value: string }>} localStorage
* @return {*}
*/
export default async function createContextWithEnvs(browser: Browser, localStorage: Array<{ name: string; value: string }>) {
return browser.newContext({
storageState: {
origins: [
{ origin: app.url, localStorage },
{ origin: config.app.baseUrl, localStorage },
],
cookies: [],
},
Expand Down
18 changes: 18 additions & 0 deletions playwright/fixtures/injectMetaMaskProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { TestFixture, Page } from '@playwright/test';

import type { WalletProvider } from 'types/web3';

export type InjectMetaMaskProvider = () => Promise<void>;

const fixture: TestFixture<InjectMetaMaskProvider, { page: Page }> = async({ page }, use) => {
await use(async() => {
await page.evaluate(() => {
window.ethereum = {
isMetaMask: true,
_events: {},
} as WalletProvider;
});
});
};

export default fixture;
27 changes: 27 additions & 0 deletions playwright/fixtures/mockConfigResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { TestFixture, Page } from '@playwright/test';

import config from 'configs/app';
import { buildExternalAssetFilePath } from 'configs/app/utils';

export type MockConfigResponseFixture = (envName: string, envValue: string, content: string, isImage?: boolean) => Promise<void>;

const fixture: TestFixture<MockConfigResponseFixture, { page: Page }> = async({ page }, use) => {
await use(async(envName, envValue, content, isImage) => {
const url = config.app.baseUrl + buildExternalAssetFilePath(envName, envValue);

if (isImage) {
await page.route(url, (route) => route.fulfill({
status: 200,
path: content,
}));
} else {
await page.route(url, (route) => route.fulfill({
status: 200,
body: content,
}));
}

});
};

export default fixture;
30 changes: 30 additions & 0 deletions playwright/fixtures/mockEnvs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* eslint-disable max-len */
import type { TestFixture, Page } from '@playwright/test';

export type MockEnvsFixture = (envs: Array<[string, string]>) => Promise<void>;

const fixture: TestFixture<MockEnvsFixture, { page: Page }> = async({ page }, use) => {
await use(async(envs) => {
for (const [ name, value ] of envs) {
await page.evaluate(({ name, value }) => {
window.localStorage.setItem(name, value);
}, { name, value });
}
});
};

export default fixture;

export const ENVS_MAP: Record<string, Array<[string, string]>> = {
shibariumRollup: [
[ 'NEXT_PUBLIC_ROLLUP_TYPE', 'shibarium' ],
[ 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', 'https://localhost:3101' ],
],
bridgedTokens: [
[ '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/"}]' ],
[ 'NEXT_PUBLIC_BRIDGED_TOKENS_BRIDGES', '[{"type":"omni","title":"OmniBridge","short_title":"OMNI"},{"type":"amb","title":"Arbitrary Message Bridge","short_title":"AMB"}]' ],
],
userOps: [
[ 'NEXT_PUBLIC_HAS_USER_OPS', 'true' ],
],
};
16 changes: 16 additions & 0 deletions playwright/fixtures/mockFeatures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-disable max-len */
import type { TestFixture, Page } from '@playwright/test';

export type MockFeaturesFixture = (features: Array<[string, unknown]>) => Promise<void>;

const fixture: TestFixture<MockFeaturesFixture, { page: Page }> = async({ page }, use) => {
await use(async(features) => {
for (const [ name, value ] of features) {
await page.evaluate(({ name, value }) => {
window.localStorage.setItem(`pw_feature:${ name }`, JSON.stringify(value));
}, { name, value });
}
});
};

export default fixture;
40 changes: 24 additions & 16 deletions playwright/lib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,35 @@ import { test as base } from '@playwright/experimental-ct-react';

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

import type { MockApiResponseFixture } from './fixtures/mockApiResponse';
import mockApiResponseFixture from './fixtures/mockApiResponse';
import type { MockAssetResponseFixture } from './fixtures/mockAssetResponse';
import mockAssetResponseFixture from './fixtures/mockAssetResponse';
import type { RenderFixture } from './fixtures/render';
import renderFixture from './fixtures/render';
import type { CreateSocketFixture } from './fixtures/socketServer';
import { createSocket as createSocketFixture } from './fixtures/socketServer';
import * as injectMetaMaskProvider from './fixtures/injectMetaMaskProvider';
import * as mockApiResponse from './fixtures/mockApiResponse';
import * as mockAssetResponse from './fixtures/mockAssetResponse';
import * as mockConfigResponse from './fixtures/mockConfigResponse';
import * as mockEnvs from './fixtures/mockEnvs';
import * as mockFeatures from './fixtures/mockFeatures';
import * as render from './fixtures/render';
import * as socketServer from './fixtures/socketServer';

interface Fixtures {
render: RenderFixture;
mockApiResponse: MockApiResponseFixture;
mockAssetResponse: MockAssetResponseFixture;
createSocket: CreateSocketFixture;
render: render.RenderFixture;
mockApiResponse: mockApiResponse.MockApiResponseFixture;
mockAssetResponse: mockAssetResponse.MockAssetResponseFixture;
mockConfigResponse: mockConfigResponse.MockConfigResponseFixture;
mockEnvs: mockEnvs.MockEnvsFixture;
mockFeatures: mockFeatures.MockFeaturesFixture;
createSocket: socketServer.CreateSocketFixture;
injectMetaMaskProvider: injectMetaMaskProvider.InjectMetaMaskProvider;
}

const test = base.extend<Fixtures>({
render: renderFixture,
mockApiResponse: mockApiResponseFixture,
mockAssetResponse: mockAssetResponseFixture,
createSocket: createSocketFixture,
render: render.default,
mockApiResponse: mockApiResponse.default,
mockAssetResponse: mockAssetResponse.default,
mockConfigResponse: mockConfigResponse.default,
mockEnvs: mockEnvs.default,
mockFeatures: mockFeatures.default,
createSocket: socketServer.createSocket,
injectMetaMaskProvider: injectMetaMaskProvider.default,
});

test.beforeEach(async({ page }) => {
Expand Down
94 changes: 0 additions & 94 deletions playwright/mocks/banner.html

This file was deleted.

4 changes: 0 additions & 4 deletions playwright/utils/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
export const url = `${ process.env.NEXT_PUBLIC_APP_PROTOCOL }://${ process.env.NEXT_PUBLIC_APP_HOST }:${ process.env.NEXT_PUBLIC_APP_PORT }`;

export const domain = process.env.NEXT_PUBLIC_APP_HOST;

export const socketPort = 3200;
2 changes: 0 additions & 2 deletions playwright/utils/buildApiUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import config from 'configs/app';
import type { ResourceName, ResourcePathParams } from 'lib/api/resources';
import { RESOURCES } from 'lib/api/resources';

// DEPRECATED

/**
* @deprecated please use fixture mockApiResponse from playwright/lib.tsx for rendering test suite
*
Expand Down
14 changes: 0 additions & 14 deletions playwright/utils/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,6 @@ export const featureEnvs = {
{ name: 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', value: 'https://localhost:3101' },
{ name: 'NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL', value: 'https://localhost:3102' },
],
shibariumRollup: [
{ name: 'NEXT_PUBLIC_ROLLUP_TYPE', value: 'shibarium' },
{ name: 'NEXT_PUBLIC_ROLLUP_L1_BASE_URL', value: 'https://localhost:3101' },
],
bridgedTokens: [
{
name: 'NEXT_PUBLIC_BRIDGED_TOKENS_CHAINS',
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/"}]',
},
{
name: 'NEXT_PUBLIC_BRIDGED_TOKENS_BRIDGES',
value: '[{"type":"omni","title":"OmniBridge","short_title":"OMNI"},{"type":"amb","title":"Arbitrary Message Bridge","short_title":"AMB"}]',
},
],
txInterpretation: [
{ name: 'NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER', value: 'blockscout' },
],
Expand Down
2 changes: 1 addition & 1 deletion types/api/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type TokensResponse = {
items_count: number;
name: string;
market_cap: string | null;
};
} | null;
}

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

0 comments on commit 6bfc495

Please sign in to comment.