Skip to content

Commit 5ae45ab

Browse files
authored
test: [POM] Migrate bitcoin send e2e tests to POM (#29515)
## **Description** - Migrate send transaction e2e tests with bitcoin account to POM - Create related Bitcoin transaction page class and methods. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27155?quickstart=1) ## **Related issues** ## **Manual testing steps** Check code readability, make sure tests pass. ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
1 parent 2d335c6 commit 5ae45ab

File tree

6 files changed

+197
-120
lines changed

6 files changed

+197
-120
lines changed

test/e2e/flask/btc/btc-send.spec.ts

+52-114
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,51 @@
11
import { strict as assert } from 'assert';
22
import { Suite } from 'mocha';
3-
import { Driver } from '../../webdriver/driver';
43
import { DEFAULT_BTC_ACCOUNT, DEFAULT_BTC_BALANCE } from '../../constants';
5-
import {
6-
getTransactionRequest,
7-
SendFlowPlaceHolders,
8-
withBtcAccountSnap,
9-
} from './common-btc';
10-
11-
export async function startSendFlow(driver: Driver, recipient?: string) {
12-
// Wait a bit so the MultichainRatesController is able to fetch BTC -> USD rates.
13-
await driver.delay(1000);
14-
15-
// Start the send flow.
16-
const sendButton = await driver.waitForSelector({
17-
text: 'Send',
18-
tag: 'button',
19-
css: '[data-testid="coin-overview-send"]',
20-
});
21-
// FIXME: Firefox test is flaky without this delay. The send flow doesn't start properly.
22-
if (driver.browser === 'firefox') {
23-
await driver.delay(1000);
24-
}
25-
await sendButton.click();
26-
27-
// See the review button is disabled by default.
28-
await driver.waitForSelector({
29-
text: 'Review',
30-
tag: 'button',
31-
css: '[disabled]',
32-
});
33-
34-
if (recipient) {
35-
// Set the recipient address (if any).
36-
await driver.pasteIntoField(
37-
`input[placeholder="${SendFlowPlaceHolders.RECIPIENT}"]`,
38-
recipient,
39-
);
40-
}
41-
}
4+
import ActivityListPage from '../../page-objects/pages/home/activity-list';
5+
import BitcoinSendPage from '../../page-objects/pages/send/bitcoin-send-page';
6+
import BitcoinHomepage from '../../page-objects/pages/home/bitcoin-homepage';
7+
import BitcoinReviewTxPage from '../../page-objects/pages/send/bitcoin-review-tx-page';
8+
import { getTransactionRequest, withBtcAccountSnap } from './common-btc';
429

4310
describe('BTC Account - Send', function (this: Suite) {
44-
it('can send complete the send flow', async function () {
11+
it('can complete the send flow', async function () {
4512
await withBtcAccountSnap(
4613
{ title: this.test?.fullTitle() },
4714
async (driver, mockServer) => {
48-
await startSendFlow(driver, DEFAULT_BTC_ACCOUNT);
15+
const homePage = new BitcoinHomepage(driver);
16+
await homePage.check_pageIsLoaded();
17+
await homePage.check_isExpectedBitcoinBalanceDisplayed(
18+
DEFAULT_BTC_BALANCE,
19+
);
20+
await homePage.startSendFlow();
4921

22+
// Set the recipient address and amount
23+
const bitcoinSendPage = new BitcoinSendPage(driver);
24+
await bitcoinSendPage.check_pageIsLoaded();
25+
await bitcoinSendPage.fillRecipientAddress(DEFAULT_BTC_ACCOUNT);
5026
// TODO: Remove delay here. There is a race condition if the amount and address are set too fast.
5127
await driver.delay(1000);
52-
53-
// Set the amount to send.
5428
const mockAmountToSend = '0.5';
55-
await driver.pasteIntoField(
56-
`input[placeholder="${SendFlowPlaceHolders.AMOUNT}"]`,
57-
mockAmountToSend,
58-
);
59-
60-
// From here, the "summary panel" should have some information about the fees and total.
61-
await driver.waitForSelector({
62-
text: 'Total',
63-
tag: 'p',
64-
});
29+
await bitcoinSendPage.fillAmount(mockAmountToSend);
6530

66-
// The review button will become available.
67-
const snapReviewButton = await driver.findClickableElement({
68-
text: 'Review',
69-
tag: 'button',
70-
css: '.snap-ui-renderer__footer-button',
71-
});
72-
assert.equal(await snapReviewButton.isEnabled(), true);
73-
await snapReviewButton.click();
31+
// Click the review button
32+
await bitcoinSendPage.clickReviewButton();
7433

7534
// TODO: There isn't any check for the fees and total amount. This requires calculating the vbytes used in a transaction dynamically.
7635
// We already have unit tests for these calculations on the Snap.
77-
7836
// ------------------------------------------------------------------------------
7937
// From here, we have moved to the confirmation screen (second part of the flow).
8038

81-
// We should be able to send the transaction right away.
82-
const snapSendButton = await driver.waitForSelector({
83-
text: 'Send',
84-
tag: 'button',
85-
css: '.snap-ui-renderer__footer-button',
86-
});
87-
assert.equal(await snapSendButton.isEnabled(), true);
88-
await snapSendButton.click();
89-
90-
// Check that we are selecting the "Activity tab" right after the send.
91-
await driver.waitForSelector({
92-
tag: 'div',
93-
text: 'Bitcoin activity is not supported',
94-
});
39+
// Click the send transaction button
40+
const bitcoinReviewTxPage = new BitcoinReviewTxPage(driver);
41+
await bitcoinReviewTxPage.check_pageIsLoaded();
42+
await bitcoinReviewTxPage.clickSendButton();
9543

44+
// Check that we are on the activity list page and the warning message is displayed
45+
await homePage.check_pageIsLoaded();
46+
await new ActivityListPage(driver).check_warningMessage(
47+
'Bitcoin activity is not supported',
48+
);
9649
const transaction = await getTransactionRequest(mockServer);
9750
assert(transaction !== undefined);
9851
},
@@ -103,58 +56,43 @@ describe('BTC Account - Send', function (this: Suite) {
10356
await withBtcAccountSnap(
10457
{ title: this.test?.fullTitle() },
10558
async (driver, mockServer) => {
106-
await startSendFlow(driver, DEFAULT_BTC_ACCOUNT);
59+
const homePage = new BitcoinHomepage(driver);
60+
await homePage.check_pageIsLoaded();
61+
await homePage.check_isExpectedBitcoinBalanceDisplayed(
62+
DEFAULT_BTC_BALANCE,
63+
);
64+
await homePage.startSendFlow();
10765

66+
// Use the max spendable amount of that account
67+
const bitcoinSendPage = new BitcoinSendPage(driver);
68+
await bitcoinSendPage.check_pageIsLoaded();
69+
await bitcoinSendPage.fillRecipientAddress(DEFAULT_BTC_ACCOUNT);
10870
// TODO: Remove delay here. There is a race condition if the amount and address are set too fast.
10971
await driver.delay(1000);
110-
111-
// Use the max spendable amount of that account.
112-
await driver.clickElement({
113-
text: 'Max',
114-
tag: 'button',
115-
});
72+
await bitcoinSendPage.selectMaxAmount();
73+
await bitcoinSendPage.check_amountIsDisplayed(
74+
`${DEFAULT_BTC_BALANCE} BTC`,
75+
);
11676

11777
// From here, the "summary panel" should have some information about the fees and total.
118-
await driver.waitForSelector({
119-
text: 'Total',
120-
tag: 'p',
121-
});
122-
123-
await driver.waitForSelector({
124-
text: `${DEFAULT_BTC_BALANCE} BTC`,
125-
tag: 'p',
126-
});
127-
128-
// The review button will become available.
129-
const snapReviewButton = await driver.findClickableElement({
130-
text: 'Review',
131-
tag: 'button',
132-
css: '.snap-ui-renderer__footer-button',
133-
});
134-
assert.equal(await snapReviewButton.isEnabled(), true);
135-
await snapReviewButton.click();
78+
await bitcoinSendPage.clickReviewButton();
13679

13780
// TODO: There isn't any check for the fees and total amount. This requires calculating the vbytes used in a transaction dynamically.
13881
// We already have unit tests for these calculations on the snap.
13982

14083
// ------------------------------------------------------------------------------
14184
// From here, we have moved to the confirmation screen (second part of the flow).
14285

143-
// We should be able to send the transaction right away.
144-
const snapSendButton = await driver.waitForSelector({
145-
text: 'Send',
146-
tag: 'button',
147-
css: '.snap-ui-renderer__footer-button',
148-
});
149-
assert.equal(await snapSendButton.isEnabled(), true);
150-
await snapSendButton.click();
151-
152-
// Check that we are selecting the "Activity tab" right after the send.
153-
await driver.waitForSelector({
154-
tag: 'div',
155-
text: 'Bitcoin activity is not supported',
156-
});
86+
// Click the send transaction button
87+
const bitcoinReviewTxPage = new BitcoinReviewTxPage(driver);
88+
await bitcoinReviewTxPage.check_pageIsLoaded();
89+
await bitcoinReviewTxPage.clickSendButton();
15790

91+
// Check that we are on the activity list page and the warning message is displayed
92+
await homePage.check_pageIsLoaded();
93+
await new ActivityListPage(driver).check_warningMessage(
94+
'Bitcoin activity is not supported',
95+
);
15896
const transaction = await getTransactionRequest(mockServer);
15997
assert(transaction !== undefined);
16098
},

test/e2e/flask/btc/common-btc.ts

-6
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@ import HeaderNavbar from '../../page-objects/pages/header-navbar';
1818

1919
const QUICKNODE_URL_REGEX = /^https:\/\/.*\.btc.*\.quiknode\.pro(\/|$)/u;
2020

21-
export enum SendFlowPlaceHolders {
22-
AMOUNT = 'Enter amount to send',
23-
RECIPIENT = 'Enter receiving address',
24-
LOADING = 'Preparing transaction',
25-
}
26-
2721
export function btcToSats(btc: number): number {
2822
// Watchout, we're not using BigNumber(s) here (but that's ok for test purposes)
2923
return btc * SATS_IN_1_BTC;

test/e2e/page-objects/pages/home/activity-list.ts

+17
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ class ActivityListPage {
151151
async check_noTxInActivity(): Promise<void> {
152152
await this.driver.assertElementNotPresent(this.completedTransactions);
153153
}
154+
155+
/**
156+
* Verifies that a specific warning message is displayed on the activity list.
157+
*
158+
* @param warningText - The expected warning text to validate against.
159+
* @returns A promise that resolves if the warning message matches the expected text.
160+
* @throws Assertion error if the warning message does not match the expected text.
161+
*/
162+
async check_warningMessage(warningText: string): Promise<void> {
163+
console.log(
164+
`Check warning message "${warningText}" is displayed on activity list`,
165+
);
166+
await this.driver.waitForSelector({
167+
tag: 'div',
168+
text: warningText,
169+
});
170+
}
154171
}
155172

156173
export default ActivityListPage;

test/e2e/page-objects/pages/home/bitcoin-homepage.ts

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class BitcoinHomepage extends HomePage {
2828
console.log('Bitcoin homepage is loaded');
2929
}
3030

31+
async startSendFlow(): Promise<void> {
32+
await this.driver.clickElement(this.sendButton);
33+
}
34+
3135
/**
3236
* Checks if the bridge button is enabled on bitcoin account homepage.
3337
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Driver } from '../../../webdriver/driver';
2+
3+
class BitcoinReviewTxPage {
4+
private driver: Driver;
5+
6+
private readonly reviewPageTitle = {
7+
text: 'Review',
8+
tag: 'h4',
9+
};
10+
11+
private readonly sendButton = {
12+
text: 'Send',
13+
tag: 'span',
14+
};
15+
16+
constructor(driver: Driver) {
17+
this.driver = driver;
18+
}
19+
20+
async check_pageIsLoaded(): Promise<void> {
21+
try {
22+
await this.driver.waitForMultipleSelectors([
23+
this.reviewPageTitle,
24+
this.sendButton,
25+
]);
26+
} catch (e) {
27+
console.log(
28+
'Timeout while waiting for bitcoin review tx page to be loaded',
29+
e,
30+
);
31+
throw e;
32+
}
33+
console.log('Bitcoin review tx page is loaded');
34+
}
35+
36+
async clickSendButton() {
37+
console.log('Click send button on bitcoin review tx page');
38+
await this.driver.clickElementAndWaitToDisappear(this.sendButton);
39+
}
40+
}
41+
42+
export default BitcoinReviewTxPage;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { Driver } from '../../../webdriver/driver';
2+
3+
class BitcoinSendPage {
4+
private driver: Driver;
5+
6+
private readonly amountInputField = `input[placeholder="Enter amount to send"]`;
7+
8+
private readonly maxAmountButton = {
9+
text: 'Max',
10+
tag: 'button',
11+
};
12+
13+
private readonly recipientInputField = `input[placeholder="Enter receiving address"]`;
14+
15+
private readonly reviewButton = {
16+
text: 'Review',
17+
tag: 'span',
18+
};
19+
20+
private readonly totalFee = {
21+
text: 'Total',
22+
tag: 'p',
23+
};
24+
25+
constructor(driver: Driver) {
26+
this.driver = driver;
27+
}
28+
29+
async check_pageIsLoaded(): Promise<void> {
30+
try {
31+
await this.driver.waitForMultipleSelectors([
32+
this.recipientInputField,
33+
this.amountInputField,
34+
]);
35+
} catch (e) {
36+
console.log(
37+
'Timeout while waiting for bitcoin send page to be loaded',
38+
e,
39+
);
40+
throw e;
41+
}
42+
console.log('Bitcoin send page is loaded');
43+
}
44+
45+
async clickReviewButton() {
46+
console.log('Click review button on send bitcoin screen');
47+
await this.driver.waitForSelector(this.totalFee);
48+
await this.driver.clickElement(this.reviewButton);
49+
}
50+
51+
async fillAmount(amount: string): Promise<void> {
52+
console.log(`Fill amount input with ${amount} on send bitcoin screen`);
53+
await this.driver.pasteIntoField(this.amountInputField, amount);
54+
}
55+
56+
async fillRecipientAddress(recipient: string) {
57+
console.log(
58+
`Fill recipient address with ${recipient} on send bitcoin screen`,
59+
);
60+
await this.driver.pasteIntoField(this.recipientInputField, recipient);
61+
}
62+
63+
async selectMaxAmount() {
64+
console.log('Select max amount on send bitcoin screen');
65+
await this.driver.clickElement(this.maxAmountButton);
66+
}
67+
68+
/**
69+
* Verifies that a specific amount is displayed on the send bitcoin screen.
70+
*
71+
* @param amount - The expected amount to validate.
72+
*/
73+
async check_amountIsDisplayed(amount: string) {
74+
console.log(`Check amount ${amount} is displayed on send bitcoin screen`);
75+
await this.driver.waitForSelector({
76+
text: amount,
77+
tag: 'p',
78+
});
79+
}
80+
}
81+
82+
export default BitcoinSendPage;

0 commit comments

Comments
 (0)