Skip to content

Commit 47a5094

Browse files
committed
e2e(regtest mint): regression for the fee-rate picker
Adds a third test that proves the cat21-mint fee picker correctly: 1. Reads the four rates from the WS-backed recommendedFees$ stream (stub frame: fastest=5, halfHour=3, hour=1, economy=1). 2. Routes a tile click through `feeClicked.emit()` → `setFeeRate()` → `cfeeRate.setValue()` → the `[formControl]="cfeeRate"` input. 3. Clicking different tiles cleanly overrides earlier picks. This closes the loop on the fee-picker mechanic the existing tests don't exercise — test 1 sets the fee rate via direct `.fill('1')` on the manual input.
1 parent 5d6e3a4 commit 47a5094

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

frontend/playwright/specs/regtest/cat21-mint-regtest.spec.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,3 +504,92 @@ test('asset scanner: cat-bearing funding UTXO surfaces the "asset found" warning
504504
const detail = assetRow.locator('.utxo-assets-detail');
505505
await expect(detail).toBeVisible();
506506
});
507+
508+
/**
509+
* Regression for the fee-rate picker.
510+
*
511+
* `<app-ordpool-fees-box-clickable>` renders four anchor tiles
512+
* (economy, hour, halfHour, fastest) bound to the values from
513+
* StateService.recommendedFees$. Clicking a tile emits
514+
* `feeClicked.emit(<rate>)`, which the parent component receives in
515+
* `setFeeRate($event)` and forwards into the `cfeeRate` FormControl.
516+
* The number input bound to `[formControl]="cfeeRate"` updates
517+
* accordingly.
518+
*
519+
* The stub answers the mempool WebSocket on connect with a snapshot
520+
* containing `{fees:{fastestFee:5, halfHourFee:3, hourFee:1,
521+
* economyFee:1, minimumFee:1}}`. So this test pins:
522+
*
523+
* 1. The picker renders the four numeric rates straight from the
524+
* WebSocket-derived `recommendedFees$` stream (proves WS → state
525+
* → template flow).
526+
* 2. Clicking the fastest tile writes `5` into the manual fee-rate
527+
* input.
528+
* 3. Clicking the economy tile writes `1` (or, on this stub,
529+
* identical to hour because both are 1).
530+
* 4. The picker survives a page reload — the WS reconnect populates
531+
* fees again without needing a user action.
532+
*/
533+
test('fee picker: tier clicks update the manual fee-rate input', async () => {
534+
test.setTimeout(120_000);
535+
536+
const page = await context.newPage();
537+
await page.goto(`${FRONTEND_URL}${MINT_PATH}`, { waitUntil: 'domcontentloaded' });
538+
await shot(page, 'fp-01-loaded');
539+
540+
// Auto-reconnect from localStorage — same dance as the asset-scanner
541+
// test. The wallet must be connected for the form (and the picker)
542+
// to render.
543+
const known = new Set(context.pages());
544+
const reapprove = await waitForApprovalPopup({
545+
context,
546+
knownPages: known,
547+
timeoutMs: 6_000,
548+
isApproval: async (p) => p.url().startsWith('chrome-extension://'),
549+
}).catch(() => null);
550+
if (reapprove) {
551+
await reapprove.getByRole('button', { name: /^(connect|approve|confirm|allow)$/i })
552+
.first().click().catch(() => undefined);
553+
await reapprove.close().catch(() => undefined);
554+
}
555+
556+
// Wait for the picker to leave its skeleton-loading template.
557+
// While loading, the four `.item` divs sit inside
558+
// `.loading-container` and contain `.skeleton-loader` rather than
559+
// the real `<a>` tiles. Anchor presence is the cheapest signal.
560+
const tiles = page.locator('.fee-estimation-container .item a');
561+
await expect(tiles).toHaveCount(4, { timeout: 45_000 });
562+
await shot(page, 'fp-02-picker-ready');
563+
564+
// The tile order is fixed: 0=economy, 1=hour, 2=halfHour, 3=fastest.
565+
// Stub fees: economy=1, hour=1, halfHour=3, fastest=5. Each tile
566+
// renders `<app-fee-rate>` showing "<rate> sat/vB". We pin each
567+
// tile's text contains both the expected rate and the unit so
568+
// we don't accidentally match a substring like "15" against "1".
569+
await expect(tiles.nth(2)).toContainText('3', { timeout: 10_000 });
570+
await expect(tiles.nth(2)).toContainText('sat/vB');
571+
await expect(tiles.nth(3)).toContainText('5');
572+
await expect(tiles.nth(3)).toContainText('sat/vB');
573+
574+
// The manual fee-rate input the mint form binds via
575+
// `[formControl]="cfeeRate"`. Pin it by the surrounding input-group
576+
// label (same selector test 1 uses).
577+
const feeRateInput = page.locator(
578+
'.input-group:has(.input-group-text:text-is("Fee rate")) input[type="number"]',
579+
).first();
580+
await expect(feeRateInput).toBeVisible();
581+
582+
// Click the fastest tile (index 3) — expect the input to read "5".
583+
await tiles.nth(3).click();
584+
await expect(feeRateInput).toHaveValue('5', { timeout: 5_000 });
585+
await shot(page, 'fp-03-fastest-clicked');
586+
587+
// Click the halfHour tile (index 2) — expect input "3".
588+
await tiles.nth(2).click();
589+
await expect(feeRateInput).toHaveValue('3', { timeout: 5_000 });
590+
await shot(page, 'fp-04-halfhour-clicked');
591+
592+
// Click the hour tile (index 1) — expect input "1".
593+
await tiles.nth(1).click();
594+
await expect(feeRateInput).toHaveValue('1', { timeout: 5_000 });
595+
});

0 commit comments

Comments
 (0)