Skip to content

Commit ffa7b06

Browse files
author
Harsh Dev Pathak
committed
feat: Added test for web wallet
1 parent 857d371 commit ffa7b06

30 files changed

+7808
-1715
lines changed

.envrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake

.github/actions/nix.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Setup Nix
2+
description: Fast, cached Nix setup (flakes) for devimint + E2E tests
3+
4+
inputs:
5+
cachix-auth-token:
6+
description: Optional auth token to PUSH to fedimint Cachix (read-only pulls need none)
7+
required: false
8+
enable-fedimint-cache:
9+
description: 'Enable fedimint public Cachix cache (true/false)'
10+
default: 'true'
11+
required: false
12+
print-config:
13+
description: 'Print nix show-config for debugging (true/false)'
14+
default: 'false'
15+
required: false
16+
17+
runs:
18+
using: composite
19+
steps:
20+
- name: Install Nix (Determinate Systems)
21+
uses: DeterminateSystems/nix-installer-action@v12
22+
with:
23+
extra-conf: |
24+
experimental-features = nix-command flakes
25+
# Reasonable timeouts to fail fast in CI
26+
connect-timeout = 15
27+
stalled-download-timeout = 15
28+
29+
- name: Enable common binary caches (magic-nix-cache)
30+
uses: DeterminateSystems/magic-nix-cache-action@v6
31+
32+
- name: Add fedimint Cachix (pull or push)
33+
if: inputs.enable-fedimint-cache == 'true'
34+
uses: cachix/cachix-action@v15
35+
with:
36+
name: fedimint
37+
authToken: ${{ inputs.cachix-auth-token }}
38+
# Even if push fails (no token) we still want read access
39+
continue-on-error: true
40+
41+
- name: Show Nix config (optional)
42+
if: inputs.print-config == 'true'
43+
shell: bash
44+
run: |
45+
echo '--- nix show-config (filtered) ---'
46+
nix show-config | grep -E 'substituters|trusted-public-keys|experimental-features'
47+
echo '--- nix path-info devShell dry-run (if flake present) ---'
48+
if [ -f flake.nix ]; then
49+
nix build .#devShells.$(nix eval --raw --expr 'builtins.currentSystem').default --dry-run 2>&1 | sed -n '1,120p'
50+
fi
51+
52+
- name: Summary
53+
shell: bash
54+
run: |
55+
echo "Nix setup complete." >> $GITHUB_STEP_SUMMARY
56+
echo "Fedimint cache: ${{ inputs.enable-fedimint-cache }}" >> $GITHUB_STEP_SUMMARY
57+
if [ -n "${{ inputs.cachix-auth-token }}" ]; then
58+
echo "Fedimint cache push: enabled (token provided)" >> $GITHUB_STEP_SUMMARY
59+
else
60+
echo "Fedimint cache push: not enabled (no token)" >> $GITHUB_STEP_SUMMARY
61+
fi
62+

.github/dependabot.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: github-actions
4+
directory: '/'
5+
schedule:
6+
interval: daily
7+
- package-ecosystem: 'npm'
8+
directory: '/'
9+
schedule:
10+
interval: 'daily'

.github/workflows/deploy.yml

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,31 @@ concurrency:
1616
cancel-in-progress: true
1717

1818
jobs:
19+
test:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
- uses: actions/setup-node@v4
24+
with:
25+
node-version: 20
26+
cache: 'npm'
27+
- run: npm ci
28+
- run: npm test -- --ci --runInBand
29+
1930
deploy:
31+
needs: test
32+
runs-on: ubuntu-latest
2033
environment:
2134
name: github-pages
2235
url: ${{ steps.deployment.outputs.page_url }}
23-
runs-on: ubuntu-latest
2436
steps:
25-
- name: Checkout Repository
37+
- name: Checkout Repo
2638
uses: actions/checkout@v4
27-
28-
- name: Setup Node.js
39+
- name: Setup Nodejs
2940
uses: actions/setup-node@v4
3041
with:
3142
node-version: 20
32-
cache: "npm"
33-
43+
cache: 'npm'
3444
- name: Install Dependencies
3545
run: npm install
3646

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@ dist-ssr
2222
*.njsproj
2323
*.sln
2424
*.sw?
25+
26+
# Playwright
27+
/test-results/
28+
/playwright-report/
29+
/blob-report/
30+
/playwright/.cache/

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ fedimint-web-wallet/
8989

9090
- Clone the repository
9191

92-
git clone https://github.com/Harshdev098/fedimint-web-wallet.git
92+
```
93+
git clone https://github.com/Harshdev098/fedimint-web-wallet.git
94+
```
9395

9496
- Install the dependencies
9597

__mocks__/fileMock.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'test-file-stub';

e2e/faucet.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { test, expect } from '@playwright/test';
2+
import { TestFaucet } from './setupTest/TestFaucet';
3+
4+
test.describe('FaucetService', () => {
5+
test('creates a faucet invoice and returns a valid BOLT11 string', async () => {
6+
const faucet = new TestFaucet();
7+
const amountSat = 1000;
8+
9+
const invoice = await faucet.createFaucetInvoice(amountSat);
10+
11+
expect(typeof invoice).toBe('string');
12+
expect(invoice.length).toBeGreaterThan(10);
13+
expect(invoice).toMatch(/^ln[a-z0-9]+/i);
14+
});
15+
});

e2e/setupTest/TestFaucet.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
export class TestFaucet {
2+
FAUCET_URL = 'http://127.0.0.1:15243';
3+
4+
async getInviteCode() {
5+
const res = await fetch(`${this.FAUCET_URL}/connect-string`);
6+
if (res.ok) {
7+
return await res.text();
8+
} else {
9+
throw new Error(`Failed to get invite code: ${await res.text()}`);
10+
}
11+
}
12+
13+
async getFaucetGatewayApi() {
14+
const res = await fetch(`${this.FAUCET_URL}/gateway-api`);
15+
if (res.ok) {
16+
return await res.text();
17+
} else {
18+
throw new Error(`Failed to get gateway: ${await res.text()}`);
19+
}
20+
}
21+
22+
async payFaucetInvoice(invoice: string) {
23+
const res = await fetch(`${this.FAUCET_URL}/pay`, {
24+
method: 'POST',
25+
body: invoice.trim(),
26+
headers: { 'Content-Type': 'text/plain' },
27+
});
28+
if (res.ok) {
29+
return await res.text();
30+
} else {
31+
throw new Error(`Failed to pay faucet invoice: ${await res.text()}`);
32+
}
33+
}
34+
35+
async createFaucetInvoice(amount: number) {
36+
const res = await fetch(`${this.FAUCET_URL}/invoice`, {
37+
method: 'POST',
38+
body: amount.toString(),
39+
});
40+
if (res.ok) {
41+
return await res.text();
42+
} else {
43+
throw new Error(`Failed to generate faucet invoice: ${await res.text()}`);
44+
}
45+
}
46+
}

e2e/wallet.spec.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { test, expect } from '@playwright/test';
2+
import { TestFaucet } from './setupTest/TestFaucet';
3+
4+
test.setTimeout(120_000);
5+
6+
test.describe('Federation Join + Lightning Flow', () => {
7+
let faucet: TestFaucet;
8+
9+
test.beforeEach(() => {
10+
faucet = new TestFaucet();
11+
});
12+
13+
test('join federation and do a receive/send cycle', async ({ page }) => {
14+
await page.goto('/');
15+
await expect(page).toHaveTitle(/Fedimint/);
16+
17+
// Step 1: Join federation
18+
await test.step('Join federation with invite code', async () => {
19+
const inviteCode = await faucet.getInviteCode();
20+
expect(inviteCode).toBeTruthy();
21+
22+
await page.getByTestId('invite-code-input').fill(inviteCode);
23+
await page.getByTestId('continue-button').click();
24+
25+
await expect(page.getByTestId('federation-title')).toContainText('Fedi Testnet');
26+
await expect(page.getByTestId('wallet-main')).toContainText('Onchain deposit:');
27+
});
28+
29+
// Step 2: Create invoice
30+
let invoice: string;
31+
await test.step('Create invoice', async () => {
32+
await page.getByRole('button', { name: /Receive/ }).click();
33+
await page.getByTestId('amount-input').fill('2');
34+
await page.getByTestId('description-input').fill('this is an invoice');
35+
await page.getByRole('button', { name: /Create/ }).click();
36+
37+
invoice = await page.getByTestId('invoice-output').inputValue();
38+
expect(invoice).toMatch(/^ln/i);
39+
});
40+
41+
// Step 3: Pay invoice via faucet
42+
await test.step('Pay invoice using faucet', async () => {
43+
await faucet.payFaucetInvoice(invoice);
44+
await expect(page.getByText(/Payment Received/)).toBeVisible();
45+
});
46+
47+
// Step 4: Verify balance increased
48+
await test.step('Verify balance', async () => {
49+
await expect(page.getByTestId('wallet-balance')).toContainText('2');
50+
});
51+
52+
await page.getByRole('button', { name: ' Ecash' }).click();
53+
54+
await page.getByRole('textbox', { name: 'Enter amount in sat:' }).fill('1');
55+
await page.getByRole('button', { name: ' Generate & Spend' }).click();
56+
57+
const notes = await page.getByRole('textbox', { name: 'Generated notes:' }).inputValue();
58+
59+
await page.getByRole('textbox', { name: 'Enter or Scan the notes:' }).fill(notes);
60+
await page.getByRole('button', { name: ' Confirm Redeem' }).click();
61+
});
62+
});

0 commit comments

Comments
 (0)