Skip to content

Commit 9cb1197

Browse files
committed
tests: add test for sending coins.
1 parent e27b6b4 commit 9cb1197

File tree

4 files changed

+152
-5
lines changed

4 files changed

+152
-5
lines changed

.github/workflows/playwright.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ jobs:
6060
run-tests:
6161
runs-on: ubuntu-latest
6262
needs: build-simulator
63+
strategy:
64+
matrix:
65+
attempt: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
66+
fail-fast: false
6367
steps:
6468
- uses: actions/checkout@v3
6569

@@ -89,14 +93,14 @@ jobs:
8993
- name: Restore executable permission
9094
run: chmod +x simulator-bin/simulator
9195

92-
- name: Run Playwright tests
96+
- name: Run Playwright tests (attempt ${{ matrix.attempt }})
9397
env:
9498
SIMULATOR_PATH: ${{ github.workspace }}/simulator-bin/simulator
9599
run: make webe2etest
96100

97-
- name: Upload Playwright artifacts
101+
- name: Upload Playwright artifacts (attempt ${{ matrix.attempt }})
98102
if: failure()
99103
uses: actions/upload-artifact@v4
100104
with:
101-
name: playwright-artifacts
105+
name: playwright-artifacts-${{ matrix.attempt }}
102106
path: frontends/web/test-results/*

frontends/web/src/components/transactions/transaction.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const Transaction = ({
5252
onShowDetail(internalID);
5353
}
5454
}}>
55-
<div className={styles.txContent}>
55+
<div className={styles.txContent} data-testid="transaction" tx-type={type}>
5656
<span className={styles.txIcon}>
5757
<Arrow status={status} type={type} />
5858
</span>

frontends/web/tests/helpers/regtest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export async function sendCoins(address: string, amount: number | string): Promi
7878

7979

8080
export function launchRegtest(): Promise<ChildProcess> {
81-
const PROJECT_ROOT = process.env.GITHUB_WORKSPACE || path.resolve(__dirname, '../../..');
81+
const PROJECT_ROOT = process.env.GITHUB_WORKSPACE || path.resolve(__dirname, '../../../..');
8282
// First, clean up cache and headers.
8383
try {
8484
const basePath = path.join(PROJECT_ROOT, 'appfolder.dev/cache');

frontends/web/tests/send.test.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/**
2+
* Copyright 2025 Shift Crypto AG
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { expect } from '@playwright/test';
18+
import { test } from './helpers/fixtures';
19+
import { ServeWallet } from './helpers/servewallet';
20+
import { launchRegtest, setupRegtestWallet, sendCoins, mineBlocks, cleanupRegtest } from './helpers/regtest';
21+
import { ChildProcess } from 'child_process';
22+
import { deleteAccountsFile } from './helpers/fs';
23+
24+
let servewallet: ServeWallet;
25+
let regtest: ChildProcess;
26+
27+
test('Send BTC', async ({ page, host, frontendPort, servewalletPort }) => {
28+
29+
await test.step('Start regtest and init wallet', async () => {
30+
regtest = await launchRegtest();
31+
// Give regtest some time to start
32+
await new Promise((resolve) => setTimeout(resolve, 3000));
33+
await setupRegtestWallet();
34+
});
35+
36+
37+
await test.step('Start servewallet', async () => {
38+
servewallet = new ServeWallet(page, servewalletPort, frontendPort, host, { regtest: true, testnet: false });
39+
await servewallet.start();
40+
});
41+
42+
await test.step('Verify there are no transactions yet', async () => {
43+
await page.goto('/#/account-summary');
44+
mineBlocks(12);
45+
await page.locator('td[data-label="Account name"]').nth(0).click();
46+
await expect(page.getByTestId('transaction')).toHaveCount(0);
47+
});
48+
49+
50+
let recvAdd: string;
51+
await test.step('Grab receive address', async () => {
52+
await page.getByRole('button', { name: 'Test wallet' }).click();
53+
await page.getByRole('button', { name: 'Unlock' }).click();
54+
await page.getByRole('link', { name: 'Bitcoin Regtest Bitcoin' }).click();
55+
await page.getByRole('button', { name: 'Receive RBTC' }).click();
56+
await page.getByRole('button', { name: 'Verify address on BitBox' }).click();
57+
const addressLocator = page.locator('[name="receive-address"]');
58+
recvAdd = await addressLocator.inputValue();
59+
console.log(`Receive address: ${recvAdd}`);
60+
});
61+
62+
await test.step('Add second RBTC account', async () => {
63+
await page.goto('/#/account-summary');
64+
await page.getByRole('link', { name: 'Settings' }).click();
65+
await page.getByRole('link', { name: 'Manage Accounts' }).click();
66+
await page.getByRole('button', { name: 'Add account' }).click();
67+
await page.getByRole('button', { name: 'Add account' }).click();
68+
await page.getByRole('button', { name: 'Done' }).click();
69+
});
70+
71+
await test.step('Send RBTC to receive address', async () => {
72+
await page.waitForTimeout(2000);
73+
const sendAmount = '10';
74+
sendCoins(recvAdd, sendAmount);
75+
mineBlocks(12);
76+
});
77+
78+
await test.step('Verify that the first account has a transaction', async () => {
79+
await page.goto('/#/account-summary');
80+
await page.locator('td[data-label="Account name"]').nth(0).click();
81+
await expect(page.getByTestId('transaction')).toHaveCount(1);
82+
83+
// It should be an incoming tx
84+
const tx = page.getByTestId('transaction').nth(0);
85+
await expect(tx).toHaveAttribute('tx-type', 'receive');
86+
87+
});
88+
89+
await test.step('Grab receive address for second account', async () => {
90+
await page.goto('/#/account-summary');
91+
await page.getByRole('link', { name: 'Bitcoin Regtest 2' }).click();
92+
93+
await page.getByRole('button', { name: 'Receive RBTC' }).click();
94+
await page.getByRole('button', { name: 'Verify address on BitBox' }).click();
95+
const addressLocator = page.locator('[name="receive-address"]');
96+
recvAdd = await addressLocator.inputValue();
97+
console.log(`Receive address: ${recvAdd}`);
98+
});
99+
100+
await test.step('Send RBTC to second account receive address', async () => {
101+
await page.goto('/#/account-summary');
102+
await page.getByRole('link', { name: 'Bitcoin Regtest Bitcoin' }).click();
103+
console.log('Sending RBTC to second account');
104+
await page.getByRole('link', { name: 'Send' }).click();
105+
await page.fill('#recipientAddress', recvAdd);
106+
await page.click('#sendAll');
107+
await page.getByRole('button', { name: 'Review' }).click();
108+
await page.getByRole('button', { name: 'Done' }).click();
109+
mineBlocks(12);
110+
});
111+
112+
await test.step('Verify that first account now has two transactions', async () => {
113+
await page.goto('/#/account-summary');
114+
await page.locator('td[data-label="Account name"]').nth(0).click();
115+
await expect(page.getByTestId('transaction')).toHaveCount(2);
116+
// Verify that the second one is outgoing
117+
// Txs are shown in reverse order
118+
const oldTx = page.getByTestId('transaction').nth(1);
119+
await expect(oldTx).toHaveAttribute('tx-type', 'receive');
120+
121+
const newTx = page.getByTestId('transaction').nth(0);
122+
await expect(newTx).toHaveAttribute('tx-type', 'send');
123+
});
124+
125+
await test.step('Verify that the second account has a transaction', async () => {
126+
await page.goto('/#/account-summary');
127+
await page.locator('td[data-label="Account name"]').nth(1).click();
128+
await expect(page.getByTestId('transaction')).toHaveCount(1);
129+
130+
const tx = page.getByTestId('transaction').nth(0);
131+
await expect(tx).toHaveAttribute('tx-type', 'receive');
132+
});
133+
134+
});
135+
136+
test.beforeEach(async () => {
137+
deleteAccountsFile();
138+
});
139+
140+
test.afterAll(async () => {
141+
await servewallet.stop();
142+
await cleanupRegtest(regtest);
143+
});

0 commit comments

Comments
 (0)