Skip to content

Commit 2d0c5d5

Browse files
committed
chore: cleans up action structure
1 parent 39ec98d commit 2d0c5d5

Some content is hidden

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

44 files changed

+700
-441
lines changed

src/helpers/actions.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Page } from 'playwright-core';
2+
import { Step, WalletOptions } from '../wallets/wallets';
23
import { getElementByContent, getInputByLabel } from './selectors';
34

45
export const waitForChromeState = async (page: Page): Promise<void> => {
@@ -47,3 +48,35 @@ export const typeOnInputField = async (
4748
await input.type(text);
4849
return true;
4950
};
51+
52+
export const performPopupAction = async (page: Page, action: (popup: Page) => Promise<void>): Promise<void> => {
53+
const popup = await page.context().waitForEvent('page'); // Wait for the popup to show up
54+
55+
await action(popup);
56+
if (!popup.isClosed()) await popup.waitForEvent('close');
57+
};
58+
59+
export const performSidepanelAction = async (page: Page, action: (sidepanel: Page) => Promise<void>): Promise<void> => {
60+
const sidepanel = page
61+
.context()
62+
.pages()
63+
.find((p) => p.url().includes('sidepanel.html'));
64+
65+
if (!sidepanel) {
66+
const pageUrls = page
67+
.context()
68+
.pages()
69+
.flatMap((p) => p.url());
70+
throw new Error('Sidepanel page not found. Current pages:\n' + pageUrls.join('\n- '));
71+
}
72+
73+
await action(sidepanel);
74+
};
75+
76+
export const performSetup =
77+
(page: Page, defaultSteps: Step<WalletOptions>[]) =>
78+
async <Options = WalletOptions>(options?: Options, steps: Step<Options>[] = defaultSteps): Promise<void> => {
79+
for (const step of steps) {
80+
await step(page, options);
81+
}
82+
};

src/wallets/coinbase/actions.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Locator, Page } from 'playwright-core';
2-
import { waitForChromeState } from '../../helpers';
2+
import { performPopupAction, waitForChromeState } from '../../helpers';
33
import { AddNetwork, AddToken, UpdateNetworkRpc } from '../../types';
4-
import { performPopupAction } from '../metamask/actions';
54
import { WalletOptions } from '../wallets';
65

76
const goHome = async (page: Page): Promise<void> => {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Page } from 'playwright-core';
2+
import { waitForChromeState } from '../../../helpers';
3+
4+
export const countAccounts = (page: Page) => async (): Promise<number> => {
5+
await page.getByTestId('wallet-switcher--dropdown').click();
6+
const count = await page.locator('//*[@data-testid="wallet-switcher--dropdown"]/*/*[2]/*').count();
7+
await page.getByTestId('wallet-switcher--dropdown').click();
8+
return count;
9+
};
10+
11+
export const createAccount =
12+
(page: Page) =>
13+
async (name?: string): Promise<void> => {
14+
if (name) {
15+
// eslint-disable-next-line no-console
16+
console.warn('parameter "name" is not supported for Coinbase');
17+
}
18+
19+
await page.getByTestId('portfolio-header--switcher-cell-pressable').click();
20+
await page.getByTestId('wallet-switcher--manage').click();
21+
await page.getByTestId('manage-wallets-account-item--action-cell-pressable').click();
22+
23+
// Help prompt appears once
24+
try {
25+
await page.getByTestId('add-new-wallet--continue').click({ timeout: 2000 });
26+
} catch {
27+
// Ignore missing help prompt
28+
}
29+
30+
await waitForChromeState(page);
31+
};
32+
33+
export const switchAccount =
34+
(page: Page) =>
35+
async (name: string): Promise<void> => {
36+
await page.getByTestId('portfolio-header--switcher-cell-pressable').click();
37+
38+
const nameRegex = new RegExp(`${name} \\$`);
39+
await page.getByRole('button', { name: nameRegex }).click();
40+
};
41+
42+
export const deleteAccount = async (_: string): Promise<void> => {
43+
// eslint-disable-next-line no-console
44+
console.warn('deleteAccount not implemented - Coinbase does not support importing/removing additional private keys');
45+
};
46+
47+
export const importPK = async (_: string): Promise<void> => {
48+
// eslint-disable-next-line no-console
49+
console.warn('importPK not implemented - Coinbase does not support importing/removing private keys');
50+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Page } from 'playwright-core';
2+
3+
export const goHome = async (page: Page): Promise<void> => {
4+
await page.getByTestId('portfolio-navigation-link').click();
5+
};
6+
7+
export const navigateHome = async (page: Page): Promise<void> => {
8+
await page.goto(page.url().split('?')[0]);
9+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './actions';
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export * from './account';
2+
export * from './network';
3+
export * from './setup';
4+
export * from './token';
5+
export * from './transaction';
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Page } from 'playwright-core';
2+
import { waitForChromeState } from '../../../helpers';
3+
import { AddNetwork, UpdateNetworkRpc } from '../../../types';
4+
import { goHome } from './helpers';
5+
6+
export const addNetwork =
7+
(page: Page) =>
8+
async (options: AddNetwork): Promise<void> => {
9+
await page.getByTestId('settings-navigation-link').click();
10+
await page.getByTestId('network-setting-cell-pressable').click();
11+
await page.getByTestId('add-custom-network').click();
12+
await page.getByTestId('custom-network-name-input').fill(options.networkName);
13+
await page.getByTestId('custom-network-rpc-url-input').fill(options.rpc);
14+
await page.getByTestId('custom-network-chain-id-input').fill(options.chainId.toString());
15+
await page.getByTestId('custom-network-currency-symbol-input').fill(options.symbol);
16+
await page.getByTestId('custom-network-save').click();
17+
18+
// Check for error messages
19+
let errorNode;
20+
try {
21+
errorNode = await page.waitForSelector('//span[@data-testid="text-input-error-label"]', {
22+
timeout: 50,
23+
});
24+
} catch {
25+
// No errors found
26+
}
27+
28+
if (errorNode) {
29+
const errorMessage = await errorNode.textContent();
30+
throw new SyntaxError(errorMessage);
31+
}
32+
33+
await waitForChromeState(page);
34+
await goHome(page);
35+
};
36+
37+
export const deleteNetwork =
38+
(page: Page) =>
39+
async (name: string): Promise<void> => {
40+
await page.getByTestId('settings-navigation-link').click();
41+
await page.getByTestId('network-setting-cell-pressable').click();
42+
43+
// Search for network then click on the first result
44+
await page.getByTestId('network-list-search').fill(name);
45+
await (await page.waitForSelector('//div[@data-testid="list-"][1]//button')).click();
46+
47+
await page.getByTestId('custom-network-delete').click();
48+
await goHome(page);
49+
};
50+
51+
export const hasNetwork =
52+
(page: Page) =>
53+
async (name: string): Promise<boolean> => {
54+
await page.getByTestId('settings-navigation-link').click();
55+
await page.getByTestId('network-setting').click();
56+
await page.getByTestId('network-list-search').fill(name);
57+
const networkIsListed = await page.isVisible('//div[@data-testid="list-"][1]//button');
58+
await goHome(page);
59+
return networkIsListed;
60+
};
61+
62+
export const switchNetwork = async (_: string): Promise<void> => {
63+
// eslint-disable-next-line no-console
64+
console.warn('switchNetwork not implemented');
65+
};
66+
67+
// TODO: Cannot implement until verified coinbase wallet bug is fixed.
68+
export const confirmNetworkSwitch = async (): Promise<void> => {
69+
// eslint-disable-next-line no-console
70+
console.warn('confirmNetorkSwitch not implemented');
71+
};
72+
73+
export const updateNetworkRpc = async (_: UpdateNetworkRpc): Promise<void> => {
74+
// eslint-disable-next-line no-console
75+
console.warn('updateNetworkRpc not implemented - Coinbase uses different network management');
76+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Page } from 'playwright-core';
2+
import { waitForChromeState } from '../../../helpers';
3+
import { WalletOptions } from '../../wallets';
4+
import { goHome } from './helpers';
5+
6+
export async function getStarted(
7+
page: Page,
8+
{
9+
seed = 'already turtle birth enroll since owner keep patch skirt drift any dinner',
10+
password = 'password1234!!!!',
11+
}: WalletOptions,
12+
): Promise<void> {
13+
// Welcome screen
14+
await page.getByTestId('btn-import-existing-wallet').click();
15+
16+
// Import Wallet
17+
await page.getByTestId('btn-import-recovery-phrase').click();
18+
await page.getByRole('button', { name: 'Acknowledge' }).click();
19+
await page.getByTestId('secret-input').fill(seed);
20+
await page.getByTestId('btn-import-wallet').click();
21+
await page.getByTestId('setPassword').fill(password);
22+
await page.getByTestId('setPasswordVerify').fill(password);
23+
await page.getByTestId('terms-and-privacy-policy').check();
24+
await page.getByTestId('btn-password-continue').click();
25+
26+
// Allow extension state/settings to settle
27+
await waitForChromeState(page);
28+
}
29+
30+
export const signin = async (): Promise<void> => {
31+
// eslint-disable-next-line no-console
32+
console.warn('signin not implemented');
33+
};
34+
35+
export const lock = (page: Page) => async (): Promise<void> => {
36+
await page.getByTestId('settings-navigation-link').click();
37+
await page.getByTestId('lock-wallet-button').click();
38+
};
39+
40+
export const unlock =
41+
(page: Page) =>
42+
async (password = 'password1234!!!!'): Promise<void> => {
43+
// last() because it seems to be a rendering issue of some sort
44+
await page.getByTestId('unlock-with-password').last().fill(password);
45+
await page.getByTestId('unlock-wallet-button').last().click();
46+
47+
// Go back home since wallet returns to last visited page when unlocked.
48+
await goHome(page);
49+
50+
// Wait for homescreen data to load
51+
await page.waitForSelector("//div[@data-testid='asset-list']//*[not(text='')]", { timeout: 10000 });
52+
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Locator, Page } from 'playwright-core';
2+
import { AddToken } from '../../../types';
3+
4+
export const getTokenBalance =
5+
(page: Page) =>
6+
async (tokenSymbol: string): Promise<number> => {
7+
const tokenValueRegex = new RegExp(String.raw` ${tokenSymbol}`);
8+
9+
const readFromCryptoTab = async (): Promise<Locator | undefined> => {
10+
await page.bringToFront();
11+
await page.getByTestId('portfolio-selector-nav-tabLabel--crypto').click();
12+
const tokenItem = page.getByTestId(/asset-item.*cell-pressable/).filter({
13+
hasText: tokenValueRegex,
14+
});
15+
16+
await page.waitForTimeout(500);
17+
18+
return (await tokenItem.isVisible()) ? tokenItem : null;
19+
};
20+
21+
const readFromTestnetTab = async (): Promise<Locator | undefined> => {
22+
await page.getByTestId('portfolio-selector-nav-tabLabel--testnet').click();
23+
24+
const tokenItem = page.getByTestId(/asset-item.*cell-pressable/).filter({
25+
hasText: tokenValueRegex,
26+
});
27+
28+
await page.waitForTimeout(500);
29+
30+
return (await tokenItem.isVisible()) ? tokenItem : null;
31+
};
32+
33+
const readAttempts = [readFromCryptoTab, readFromTestnetTab];
34+
35+
let button: Locator | undefined;
36+
for (const readAttempt of readAttempts) {
37+
button = await readAttempt();
38+
}
39+
40+
if (!button) throw new Error(`Token ${tokenSymbol} not found`);
41+
42+
const text = await button.textContent();
43+
const currencyAmount = text.replaceAll(/ |,/g, '').split(tokenSymbol)[2];
44+
45+
return currencyAmount ? Number(currencyAmount) : 0;
46+
};
47+
48+
export const addToken = async (_: AddToken): Promise<void> => {
49+
// eslint-disable-next-line no-console
50+
console.warn('addToken not implemented - Coinbase does not support adding custom tokens');
51+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Page } from 'playwright-core';
2+
import { performPopupAction } from '../../../helpers';
3+
4+
export const approve = (page: Page) => async (): Promise<void> => {
5+
await performPopupAction(page, async (popup: Page) => {
6+
await popup.getByTestId('allow-authorize-button').click();
7+
});
8+
};
9+
10+
export const reject = (page: Page) => async (): Promise<void> => {
11+
await performPopupAction(page, async (popup: Page) => {
12+
const denyButton = popup.getByTestId('deny-authorize-button');
13+
const cancelButton = popup.getByTestId('request-cancel-button');
14+
15+
await denyButton.or(cancelButton).click();
16+
});
17+
};
18+
19+
export const sign = (page: Page) => async (): Promise<void> => {
20+
await performPopupAction(page, async (popup: Page) => {
21+
await popup.getByTestId('sign-message').click();
22+
});
23+
};
24+
25+
export const confirmTransaction = (page: Page) => async (): Promise<void> => {
26+
await performPopupAction(page, async (popup: Page): Promise<void> => {
27+
try {
28+
// Help prompt appears once
29+
await (await popup.waitForSelector("text='Got it'", { timeout: 1000 })).click();
30+
} catch {
31+
// Ignore missing help prompt
32+
}
33+
34+
await popup.getByTestId('request-confirm-button').click();
35+
});
36+
};

0 commit comments

Comments
 (0)