Skip to content

Commit c9de9b0

Browse files
authored
Merge pull request #7 from stakefish/sync-repo
Sync repo
2 parents 0b39f97 + 2b755c5 commit c9de9b0

File tree

101 files changed

+3673
-880
lines changed

Some content is hidden

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

101 files changed

+3673
-880
lines changed

.env.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
NEXT_PUBLIC_API_URL=/
2+
NEXT_PUBLIC_NETWORK=mainnet
3+
NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES=false
4+
NEXT_PUBLIC_FIXED_STAKING_TERM=true
5+
NEXT_BUILD_E2E=true
6+
NEXT_PUBLIC_BBN_GAS_PRICE=0.007
7+
NEXT_PUBLIC_DEFAULT_FP_FILTER=inactive
8+
NEXT_PUBLIC_BABY_RPC_URL=/
9+
NEXT_PUBLIC_BABY_LCD_URL=/

docker/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ ENV NEXT_PUBLIC_FIXED_STAKING_TERM=${NEXT_PUBLIC_FIXED_STAKING_TERM}
4242
ARG NEXT_PUBLIC_BBN_GAS_PRICE
4343
ENV NEXT_PUBLIC_BBN_GAS_PRICE=${NEXT_PUBLIC_BBN_GAS_PRICE}
4444

45+
ARG NEXT_PUBLIC_DISABLED_WALLETS
46+
ENV NEXT_PUBLIC_DISABLED_WALLETS=${NEXT_PUBLIC_DISABLED_WALLETS}
47+
4548
ARG NEXT_PUBLIC_SIDECAR_API_URL
4649
ENV NEXT_PUBLIC_SIDECAR_API_URL=${NEXT_PUBLIC_SIDECAR_API_URL}
4750

e2e/balanceAddress.spec.ts

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

e2e/fixtures/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from "./page_navigation";
2+
export * from "./wallet_balance";
3+
export * from "./wallet_connect";

e2e/fixtures/page_navigation.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Page } from "@playwright/test";
2+
3+
import { injectBBNQueries } from "../mocks/blockchain";
4+
5+
export class PageNavigationActions {
6+
constructor(private page: Page) {}
7+
8+
async navigateToHomePage(page: Page) {
9+
await injectBBNQueries(page);
10+
await this.page.goto("/");
11+
await this.waitForPageLoad();
12+
}
13+
14+
async waitForPageLoad() {
15+
await this.page.waitForLoadState("domcontentloaded");
16+
await this.page.waitForLoadState("networkidle");
17+
}
18+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Note: These should be replaced by data-testid selectors
2+
3+
export const SPINNER_SELECTOR =
4+
'[data-testid="staked-balance"] .bbn-loader, [data-testid="stakable-balance"] .bbn-loader, [data-testid="baby-balance"] .bbn-loader, [data-testid="baby-rewards"] .bbn-loader';
5+
export const STAKED_BALANCE_ITEM_SELECTOR =
6+
'.bbn-list-item:has-text("Staked Balance")';
7+
export const STAKED_BALANCE_VALUE_SELECTOR =
8+
'.bbn-list-item:has-text("Staked Balance") .bbn-list-value';
9+
export const STAKABLE_BALANCE_VALUE_SELECTOR =
10+
'.bbn-list-item:has-text("Stakable Balance") .bbn-list-value';
11+
export const BABY_BALANCE_VALUE_SELECTOR =
12+
'.bbn-list-item:has-text("BABY Balance") .bbn-list-value';
13+
export const BABY_REWARDS_VALUE_SELECTOR =
14+
'.bbn-list-item:has-text("BABY Rewards") .bbn-list-value';

e2e/fixtures/wallet_balance.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Page } from "@playwright/test";
2+
3+
import {
4+
BABY_BALANCE_VALUE_SELECTOR,
5+
BABY_REWARDS_VALUE_SELECTOR,
6+
SPINNER_SELECTOR,
7+
STAKABLE_BALANCE_VALUE_SELECTOR,
8+
STAKED_BALANCE_ITEM_SELECTOR,
9+
STAKED_BALANCE_VALUE_SELECTOR,
10+
} from "./wallet_balance.selectors";
11+
12+
export class WalletBalanceActions {
13+
constructor(private page: Page) {}
14+
15+
async waitForBalanceLoadingComplete() {
16+
await this.page.waitForFunction(
17+
(sel) => document.querySelectorAll(sel).length === 0,
18+
SPINNER_SELECTOR,
19+
{ timeout: 30_000 },
20+
);
21+
22+
try {
23+
await this.page.waitForSelector(STAKED_BALANCE_ITEM_SELECTOR, {
24+
timeout: 30000,
25+
state: "attached",
26+
});
27+
} catch (error: unknown) {
28+
await this.page.reload({ waitUntil: "domcontentloaded" });
29+
await this.page.waitForLoadState("networkidle");
30+
await this.page.waitForTimeout(10000);
31+
}
32+
}
33+
34+
async getStakedBalance(): Promise<string | null> {
35+
const stakedBalance = this.page.locator(STAKED_BALANCE_VALUE_SELECTOR);
36+
return stakedBalance.textContent();
37+
}
38+
39+
async getStakableBalance(): Promise<string | null> {
40+
return this.page.locator(STAKABLE_BALANCE_VALUE_SELECTOR).textContent();
41+
}
42+
43+
async getBabyBalance(): Promise<string | null> {
44+
return this.page.locator(BABY_BALANCE_VALUE_SELECTOR).textContent();
45+
}
46+
47+
async getBabyRewards(): Promise<string | null> {
48+
return this.page.locator(BABY_REWARDS_VALUE_SELECTOR).textContent();
49+
}
50+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Note: These should be replaced by data-testid selectors
2+
3+
export const CONNECT_BUTTON_SELECTOR = 'button:has-text("Connect")';
4+
5+
export const DIALOG_SELECTORS = {
6+
TERMS_DIALOG_HEADER: '[class*="bbn-dialog-header"]',
7+
ANY_DIALOG: 'dialog, [role="dialog"]',
8+
ERROR_DIALOG: '[role="dialog"]:has-text("The wallet cannot be connected")',
9+
ERROR_DIALOG_DONE_BUTTON:
10+
'[role="dialog"]:has-text("The wallet cannot be connected") button:has-text("Done")',
11+
};
12+
13+
export const BUTTON_SELECTORS = {
14+
NEXT: 'button:has-text("Next")',
15+
ACCEPT: 'button:has-text("Accept")',
16+
CONTINUE: 'button:has-text("Continue")',
17+
OK: 'button:has-text("OK")',
18+
SAVE: '.bbn-dialog-footer button:has-text("Save")',
19+
DONE: '.bbn-dialog-footer button:has-text("Done")',
20+
};
21+
22+
export const CHECKBOX_SELECTOR = '.bbn-switcher-input[type="checkbox"]';
23+
24+
export const WALLET_SELECTORS = {
25+
BITCOIN: 'button:has-text("Select Bitcoin Wallet")',
26+
OKX: [
27+
'button:has-text("OKX")',
28+
'div[role="button"]:has-text("OKX")',
29+
'[data-testid="wallet-option-okx"]',
30+
'button:has-img[alt="OKX"]',
31+
],
32+
BABYLON: [
33+
'button:has-text("Select Babylon Chain Wallet")',
34+
'button:has-img[alt="Babylon Chain"]',
35+
"button:has(.bbn-avatar)",
36+
],
37+
};
38+
39+
export const createGenericWalletSelector = (walletType: string) =>
40+
`button:has(.h-10.w-10.object-contain):has-text("${walletType}")`;

e2e/fixtures/wallet_connect.ts

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import { Page } from "@playwright/test";
2+
3+
import { injectBBNWallet, injectBTCWallet } from "../mocks/blockchain";
4+
import { mockVerifyBTCAddress } from "../mocks/handlers";
5+
6+
import {
7+
BUTTON_SELECTORS,
8+
CHECKBOX_SELECTOR,
9+
CONNECT_BUTTON_SELECTOR,
10+
DIALOG_SELECTORS,
11+
WALLET_SELECTORS,
12+
createGenericWalletSelector,
13+
} from "./wallet_connect.selectors";
14+
15+
export class WalletConnectActions {
16+
constructor(private page: Page) {}
17+
18+
async clickConnectButton() {
19+
await this.page.waitForSelector(CONNECT_BUTTON_SELECTOR, {
20+
state: "visible",
21+
timeout: 3000,
22+
});
23+
24+
const connectButtons = await this.page
25+
.locator(CONNECT_BUTTON_SELECTOR)
26+
.all();
27+
28+
for (const button of connectButtons) {
29+
const isDisabled = await button.isDisabled();
30+
if (!isDisabled) {
31+
await button.click({ force: true });
32+
return;
33+
}
34+
}
35+
36+
if (connectButtons.length > 0) {
37+
await connectButtons[0].click({ force: true });
38+
}
39+
}
40+
41+
async acceptTermsAndConditions() {
42+
await Promise.race([
43+
this.page
44+
.locator(DIALOG_SELECTORS.TERMS_DIALOG_HEADER)
45+
.waitFor({ state: "visible", timeout: 3000 })
46+
.catch(() => {}),
47+
this.page
48+
.locator(DIALOG_SELECTORS.ANY_DIALOG)
49+
.first()
50+
.waitFor({ state: "visible", timeout: 3000 })
51+
.catch(() => {}),
52+
]);
53+
54+
const termsDialogVisible = await this.page
55+
.locator(DIALOG_SELECTORS.TERMS_DIALOG_HEADER)
56+
.isVisible()
57+
.catch(() => false);
58+
59+
if (!termsDialogVisible) {
60+
await this.handleAlternativeDialog();
61+
return;
62+
}
63+
64+
const checkboxes = this.page.locator(CHECKBOX_SELECTOR);
65+
const count = await checkboxes.count();
66+
67+
for (let i = 0; i < count; i++) {
68+
await checkboxes.nth(i).click();
69+
}
70+
71+
await this.page.locator(BUTTON_SELECTORS.NEXT).click();
72+
}
73+
74+
private async handleAlternativeDialog() {
75+
const anyDialog = await this.page
76+
.locator(DIALOG_SELECTORS.ANY_DIALOG)
77+
.first()
78+
.isVisible()
79+
.catch(() => false);
80+
81+
if (!anyDialog) return;
82+
83+
const buttonSelectorsList = [
84+
BUTTON_SELECTORS.NEXT,
85+
BUTTON_SELECTORS.ACCEPT,
86+
BUTTON_SELECTORS.CONTINUE,
87+
BUTTON_SELECTORS.OK,
88+
];
89+
90+
for (const selector of buttonSelectorsList) {
91+
const button = this.page.locator(selector).first();
92+
if (await button.isVisible().catch(() => false)) {
93+
await button
94+
.click()
95+
.catch((e) => console.error(`Error clicking ${selector}:`, e));
96+
return;
97+
}
98+
}
99+
100+
const anyButton = this.page
101+
.locator(`${DIALOG_SELECTORS.ANY_DIALOG} button`)
102+
.first();
103+
if (await anyButton.isVisible().catch(() => false)) {
104+
await anyButton
105+
.click()
106+
.catch((e) => console.error("Error clicking dialog button:", e));
107+
}
108+
}
109+
110+
async clickInjectableWalletButton() {
111+
const bitcoinWalletButton = this.page
112+
.locator(WALLET_SELECTORS.BITCOIN)
113+
.first();
114+
115+
await bitcoinWalletButton.waitFor({ state: "visible", timeout: 10_000 });
116+
await bitcoinWalletButton.click();
117+
}
118+
119+
async clickConnectWalletButton() {
120+
const saveButton = this.page.locator(BUTTON_SELECTORS.SAVE);
121+
await saveButton.waitFor({ state: "visible", timeout: 3000 });
122+
await saveButton.click();
123+
}
124+
125+
async clickOKXWalletButton() {
126+
for (const selector of WALLET_SELECTORS.OKX) {
127+
const okxButton = this.page.locator(selector).first();
128+
if (await okxButton.isVisible().catch(() => false)) {
129+
await okxButton.click();
130+
break;
131+
}
132+
}
133+
134+
await this.clickConnectWalletButton();
135+
}
136+
137+
async clickBabylonChainWalletButton() {
138+
for (const selector of WALLET_SELECTORS.BABYLON) {
139+
const babylonButton = this.page.locator(selector).first();
140+
if (await babylonButton.isVisible().catch(() => false)) {
141+
await babylonButton.click();
142+
break;
143+
}
144+
}
145+
}
146+
147+
async clickGenericWalletButton(walletType: string = "Leap") {
148+
const walletSelector = createGenericWalletSelector(walletType);
149+
const walletButton = this.page.locator(walletSelector);
150+
await walletButton.waitFor({ state: "visible", timeout: 3000 });
151+
await walletButton.click();
152+
}
153+
154+
async clickDoneButton() {
155+
const doneButton = this.page.locator(BUTTON_SELECTORS.DONE);
156+
await doneButton.waitFor({ state: "visible", timeout: 3000 });
157+
await doneButton.click();
158+
}
159+
160+
async setupMocks() {
161+
await mockVerifyBTCAddress(this.page);
162+
}
163+
164+
async handleVerificationErrorIfPresent() {
165+
await this.page
166+
.locator(DIALOG_SELECTORS.ERROR_DIALOG)
167+
.waitFor({
168+
state: "visible",
169+
timeout: 1000,
170+
})
171+
.catch(() => {});
172+
173+
const isErrorVisible = await this.page
174+
.locator(DIALOG_SELECTORS.ERROR_DIALOG)
175+
.isVisible()
176+
.catch(() => false);
177+
178+
if (isErrorVisible) {
179+
const doneButton = this.page.locator(
180+
DIALOG_SELECTORS.ERROR_DIALOG_DONE_BUTTON,
181+
);
182+
183+
if (await doneButton.isVisible().catch(() => false)) {
184+
await doneButton.click();
185+
186+
await this.page
187+
.locator(DIALOG_SELECTORS.ERROR_DIALOG)
188+
.waitFor({
189+
state: "hidden",
190+
timeout: 1000,
191+
})
192+
.catch(() => {});
193+
}
194+
}
195+
}
196+
197+
async setupWalletConnection() {
198+
await this.setupMocks();
199+
await injectBTCWallet(this.page);
200+
await injectBBNWallet(this.page);
201+
await this.clickConnectButton();
202+
await this.acceptTermsAndConditions();
203+
await this.clickInjectableWalletButton();
204+
await this.clickOKXWalletButton();
205+
await this.handleVerificationErrorIfPresent();
206+
await this.clickBabylonChainWalletButton();
207+
await this.clickGenericWalletButton();
208+
await this.clickDoneButton();
209+
}
210+
}

0 commit comments

Comments
 (0)