@vercel/devlow-bench
Advanced tools
Comparing version 0.1.3 to 0.1.4
import type { Page } from "playwright-chromium"; | ||
interface BrowserSession { | ||
close(): Promise<void>; | ||
hardNavigation(url: string, metricName?: string): Promise<Page>; | ||
hardNavigation(metricName: string, url: string): Promise<Page>; | ||
softNavigationByClick(metricName: string, selector: string): Promise<void>; | ||
@@ -6,0 +6,0 @@ reload(metricName: string): Promise<void>; |
import { chromium } from "playwright-chromium"; | ||
import { measureTime, reportMeasurement } from "./index.js"; | ||
const browserOutput = !!process.env.BROWSER_OUTPUT; | ||
async function withRequestMetrics(metricName, page, fn) { | ||
@@ -28,4 +29,43 @@ const activePromises = []; | ||
}; | ||
let errorCount = 0; | ||
let warningCount = 0; | ||
let logCount = 0; | ||
const consoleHandler = (message) => { | ||
const type = message.type(); | ||
if (type === "error") { | ||
errorCount++; | ||
} | ||
else if (type === "warning") { | ||
warningCount++; | ||
} | ||
else { | ||
logCount++; | ||
} | ||
if (browserOutput) { | ||
activePromises.push((async () => { | ||
const args = []; | ||
try { | ||
const text = message.text(); | ||
for (const arg of message.args()) { | ||
args.push(await arg.jsonValue()); | ||
} | ||
console.log(`[${type}] ${text}`, ...args); | ||
} | ||
catch { | ||
// Ignore | ||
} | ||
})()); | ||
} | ||
}; | ||
let uncaughtCount = 0; | ||
const exceptionHandler = (error) => { | ||
uncaughtCount++; | ||
if (browserOutput) { | ||
console.error(`[UNCAUGHT]`, error); | ||
} | ||
}; | ||
try { | ||
page.on("response", responseHandler); | ||
page.on("console", consoleHandler); | ||
page.on("pageerror", exceptionHandler); | ||
await fn(); | ||
@@ -45,2 +85,7 @@ await Promise.all(activePromises); | ||
reportMeasurement(`${metricName}/requests`, totalRequests, "requests"); | ||
reportMeasurement(`${metricName}/console/logs`, logCount, "messages"); | ||
reportMeasurement(`${metricName}/console/warnings`, warningCount, "messages"); | ||
reportMeasurement(`${metricName}/console/errors`, errorCount, "messages"); | ||
reportMeasurement(`${metricName}/console/uncaught`, uncaughtCount, "messages"); | ||
reportMeasurement(`${metricName}/console`, logCount + warningCount + errorCount + uncaughtCount, "messages"); | ||
} | ||
@@ -51,4 +96,4 @@ finally { | ||
} | ||
function networkIdle(page) { | ||
return new Promise((resolve) => { | ||
function networkIdle(page, delay = 300, rejectTimeout = 180000) { | ||
return new Promise((resolve, reject) => { | ||
const cleanup = () => { | ||
@@ -58,6 +103,19 @@ page.off("request", requestHandler); | ||
page.off("requestfinished", requestFinishedHandler); | ||
clearTimeout(fullTimeout); | ||
if (timeout) { | ||
clearTimeout(timeout); | ||
} | ||
}; | ||
let activeRequests = 0; | ||
let timeout = null; | ||
const requestHandler = (request) => { | ||
const requests = new Set(); | ||
const fullTimeout = setTimeout(() => { | ||
cleanup(); | ||
reject(new Error(`Timeout while waiting for network idle. These requests are still pending: ${Array.from(requests).join(", ")}}`)); | ||
}, rejectTimeout); | ||
const requestFilter = async (request) => { | ||
return (await request.headers().accept) !== "text/event-stream"; | ||
}; | ||
const requestHandler = async (request) => { | ||
requests.add(request.url()); | ||
activeRequests++; | ||
@@ -68,4 +126,15 @@ if (timeout) { | ||
} | ||
// Avoid tracking some requests, but we only know this after awaiting | ||
// so we need to do this weird stunt to ensure that | ||
if (!(await requestFilter(request))) { | ||
await requestFinishedInternal(request); | ||
} | ||
}; | ||
const requestFinishedHandler = (request) => { | ||
const requestFinishedHandler = async (request) => { | ||
if (await requestFilter(request)) { | ||
requestFinishedInternal(request); | ||
} | ||
}; | ||
const requestFinishedInternal = async (request) => { | ||
requests.delete(request.url()); | ||
activeRequests--; | ||
@@ -76,3 +145,3 @@ if (activeRequests === 0) { | ||
resolve(); | ||
}, 300); | ||
}, delay); | ||
} | ||
@@ -102,2 +171,3 @@ }; | ||
measureTime(`${metricName}/start`); | ||
const idle = networkIdle(page, 3000); | ||
await page.goto(url, { | ||
@@ -117,4 +187,5 @@ waitUntil: "commit", | ||
}); | ||
await page.waitForLoadState("networkidle"); | ||
await idle; | ||
measureTime(`${metricName}`, { | ||
offset: 3000, | ||
relativeTo: `${metricName}/start`, | ||
@@ -133,3 +204,3 @@ }); | ||
const firstResponse = new Promise((resolve) => page.once("response", () => resolve())); | ||
const idle = networkIdle(page); | ||
const idle = networkIdle(page, 3000); | ||
await page.click(selector); | ||
@@ -142,2 +213,3 @@ await firstResponse; | ||
measureTime(`${metricName}`, { | ||
offset: 3000, | ||
relativeTo: `${metricName}/start`, | ||
@@ -154,2 +226,3 @@ }); | ||
measureTime(`${metricName}/start`); | ||
const idle = networkIdle(page, 3000); | ||
await page.reload({ | ||
@@ -169,4 +242,5 @@ waitUntil: "commit", | ||
}); | ||
await page.waitForLoadState("networkidle"); | ||
await idle; | ||
measureTime(`${metricName}`, { | ||
offset: 3000, | ||
relativeTo: `${metricName}/start`, | ||
@@ -173,0 +247,0 @@ }); |
@@ -13,2 +13,3 @@ import type { ConfigFor, CurrentScenario, Scenario } from "./index.js"; | ||
props?: Record<string, string | number | null>; | ||
offset?: number; | ||
}): void; | ||
@@ -15,0 +16,0 @@ export declare function reportMeasurement(name: string, value: number, unit: string, options?: { |
@@ -60,3 +60,3 @@ import compose from "./interfaces/compose.js"; | ||
export function measureTime(name, options = {}) { | ||
const end = Date.now(); | ||
const end = Date.now() - (options.offset || 0); | ||
reportMeasurement(name, end, "ms", { relativeTo: PREVIOUS, ...options }); | ||
@@ -63,0 +63,0 @@ } |
{ | ||
"name": "@vercel/devlow-bench", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"description": "Benchmarking tool for the developer workflow", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -121,2 +121,6 @@ # devlow-bench | ||
Run with `BROWSER_OUTPUT=1` to show the output of the browser. | ||
Run with `HEADLESS=false` to show the actual browser window. | ||
## Shell operations | ||
@@ -155,2 +159,4 @@ | ||
Run with `SHELL_OUTPUT=1` to show the output of the shell commands. | ||
## File operations | ||
@@ -157,0 +163,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
64426
1148
170
1
14