1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
import { chromium } from "@playwright/test";
const BASE = "http://localhost:5173";
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();
// Login as bob
console.log("=== Logging in as bob ===");
await page.goto(`${BASE}/login`);
await page.fill('input[name="username"]', "bob");
await page.fill('input[name="password"]', "pw");
await page.click('button[type="submit"]');
await page.waitForURL("**/bob", { timeout: 10000 });
console.log("Logged in, at:", page.url());
// Wait for page to fully settle
await page.waitForTimeout(2000);
// Now measure navigation to /invoice/lnurl
console.log("\n=== Navigating to /invoice/lnurl ===");
// Enable request interception to measure timings
const navRequests: { url: string; method: string; duration: number }[] = [];
page.on("request", (req) => {
(req as any)._startTime = Date.now();
});
page.on("response", (res) => {
const req = res.request();
const start = (req as any)._startTime;
if (start) {
navRequests.push({
url: req.url().replace(BASE, ""),
method: req.method(),
duration: Date.now() - start,
});
}
});
// Take screenshot before navigation
await page.screenshot({ path: "/tmp/perf-before.png" });
const navStart = Date.now();
// Click the Receive button on the first account (custodial/spending)
const receiveBtn = page.locator('[data-testid="account-receive"]').first();
const receiveHref = await receiveBtn.locator("..").getAttribute("href");
console.log("Receive link href:", receiveHref);
await receiveBtn.click();
// Wait for the invoice page to load
await page.waitForURL("**/invoice/**", { timeout: 10000 });
const urlReady = Date.now() - navStart;
console.log(`URL changed in ${urlReady}ms`);
// Wait for QR to appear
try {
await page.waitForSelector('.invoice img[src]', { timeout: 5000 });
const qrReady = Date.now() - navStart;
console.log(`QR img element appeared in ${qrReady}ms`);
} catch {
console.log("QR img not found within 5s");
}
// Check if QR image has actually loaded (naturalWidth > 0)
try {
await page.waitForFunction(
() => {
const img = document.querySelector(".invoice img") as HTMLImageElement;
return img && img.naturalWidth > 0;
},
{ timeout: 5000 }
);
const qrLoaded = Date.now() - navStart;
console.log(`QR image fully loaded in ${qrLoaded}ms`);
} catch {
console.log("QR image did not fully load within 5s");
}
const totalTime = Date.now() - navStart;
await page.screenshot({ path: "/tmp/perf-after.png" });
console.log(`\nTotal navigation time: ${totalTime}ms`);
console.log("\n=== Network requests during navigation ===");
for (const r of navRequests.sort((a, b) => b.duration - a.duration)) {
console.log(` ${r.method} ${r.url} - ${r.duration}ms`);
}
// Now measure a second navigation (back and forth) to see cached behavior
console.log("\n=== Going back to profile ===");
navRequests.length = 0;
await page.goBack();
await page.waitForTimeout(1000);
console.log("\n=== Second navigation to /invoice/lnurl ===");
navRequests.length = 0;
const nav2Start = Date.now();
await receiveBtn.click();
await page.waitForURL("**/invoice/**", { timeout: 10000 });
const url2Ready = Date.now() - nav2Start;
console.log(`URL changed in ${url2Ready}ms`);
try {
await page.waitForFunction(
() => {
const img = document.querySelector(".invoice img") as HTMLImageElement;
return img && img.naturalWidth > 0;
},
{ timeout: 5000 }
);
const qr2Loaded = Date.now() - nav2Start;
console.log(`QR image fully loaded in ${qr2Loaded}ms`);
} catch {
console.log("QR image did not fully load within 5s");
}
await page.screenshot({ path: "/tmp/perf-after2.png" });
console.log(`\nTotal 2nd navigation time: ${Date.now() - nav2Start}ms`);
console.log("\n=== Network requests during 2nd navigation ===");
for (const r of navRequests.sort((a, b) => b.duration - a.duration)) {
console.log(` ${r.method} ${r.url} - ${r.duration}ms`);
}
// Also capture performance entries
const perfEntries = await page.evaluate(() => {
return performance.getEntriesByType("navigation").map((e: any) => ({
name: e.name,
duration: e.duration,
domContentLoaded: e.domContentLoadedEventEnd - e.startTime,
loadEvent: e.loadEventEnd - e.startTime,
}));
});
console.log("\n=== Performance entries ===", perfEntries);
await browser.close();
})();
|