cbrowser 7.1.1 → 7.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +37 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +798 -1
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +296 -3
- package/dist/cli.js.map +1 -1
- package/dist/types.d.ts +253 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ const daemon_js_1 = require("./daemon.js");
|
|
|
14
14
|
function showHelp() {
|
|
15
15
|
console.log(`
|
|
16
16
|
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
17
|
-
║ CBrowser CLI v7.
|
|
17
|
+
║ CBrowser CLI v7.3.0 ║
|
|
18
18
|
║ AI-powered browser automation with cross-browser visual testing ║
|
|
19
19
|
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
20
20
|
|
|
@@ -232,7 +232,7 @@ AI VISUAL REGRESSION (v7.0.0)
|
|
|
232
232
|
ai-visual show <name> Show baseline details
|
|
233
233
|
ai-visual delete <name> Delete a baseline
|
|
234
234
|
|
|
235
|
-
CROSS-BROWSER VISUAL TESTING (v7.
|
|
235
|
+
CROSS-BROWSER VISUAL TESTING (v7.3.0)
|
|
236
236
|
cross-browser <url> Compare visual rendering across browsers
|
|
237
237
|
--browsers <list> Browsers to test: chromium,firefox,webkit (default: all)
|
|
238
238
|
--width <n> Viewport width (default: 1920)
|
|
@@ -258,6 +258,68 @@ CROSS-BROWSER VISUAL TESTING (v7.1.1)
|
|
|
258
258
|
"options": { "browsers": ["chromium", "firefox"] }
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
RESPONSIVE VISUAL TESTING (v7.3.0)
|
|
262
|
+
responsive <url> Test visual rendering across viewport sizes
|
|
263
|
+
--viewports <list> Viewports to test (default: mobile,tablet,desktop)
|
|
264
|
+
--wait <ms> Wait before screenshot (ms)
|
|
265
|
+
--wait-for <selector> Wait for selector before screenshot
|
|
266
|
+
--sensitivity <level> Comparison sensitivity: low, medium, high
|
|
267
|
+
--html Generate HTML report
|
|
268
|
+
--output <file> Save JSON report to file
|
|
269
|
+
Examples:
|
|
270
|
+
cbrowser responsive "https://example.com"
|
|
271
|
+
cbrowser responsive "https://example.com" --viewports mobile,tablet,desktop-lg
|
|
272
|
+
cbrowser responsive "https://example.com" --html --output report.html
|
|
273
|
+
|
|
274
|
+
responsive suite <file.json> Run responsive test suite
|
|
275
|
+
--html Generate HTML report
|
|
276
|
+
--output <file> Save JSON report to file
|
|
277
|
+
|
|
278
|
+
responsive viewports List available viewport presets
|
|
279
|
+
|
|
280
|
+
Suite file format:
|
|
281
|
+
{
|
|
282
|
+
"name": "My Site Responsive",
|
|
283
|
+
"urls": ["https://example.com", "https://example.com/about"],
|
|
284
|
+
"options": { "viewports": ["mobile", "tablet", "desktop"] }
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
Available viewport presets:
|
|
288
|
+
mobile-sm (320x568) mobile (375x667) mobile-lg (414x896)
|
|
289
|
+
mobile-xl (428x926) tablet (768x1024) tablet-lg (1024x1366)
|
|
290
|
+
desktop-sm (1280x800) desktop (1440x900) desktop-lg (1920x1080)
|
|
291
|
+
desktop-xl (2560x1440)
|
|
292
|
+
|
|
293
|
+
A/B VISUAL COMPARISON (v7.3.0)
|
|
294
|
+
ab <urlA> <urlB> Compare two URLs visually
|
|
295
|
+
--label-a <name> Label for URL A (default: "Version A")
|
|
296
|
+
--label-b <name> Label for URL B (default: "Version B")
|
|
297
|
+
--width <n> Viewport width (default: 1920)
|
|
298
|
+
--height <n> Viewport height (default: 1080)
|
|
299
|
+
--wait <ms> Wait before screenshot (ms)
|
|
300
|
+
--wait-for <selector> Wait for selector before screenshot
|
|
301
|
+
--sensitivity <level> Comparison sensitivity: low, medium, high
|
|
302
|
+
--html Generate HTML report
|
|
303
|
+
--output <file> Save JSON report to file
|
|
304
|
+
Examples:
|
|
305
|
+
cbrowser ab "https://staging.example.com" "https://example.com"
|
|
306
|
+
cbrowser ab "https://old.site.com" "https://new.site.com" --label-a "Old Design" --label-b "New Design"
|
|
307
|
+
cbrowser ab "https://site-a.com" "https://site-b.com" --html --output comparison.html
|
|
308
|
+
|
|
309
|
+
ab suite <file.json> Run A/B comparison suite
|
|
310
|
+
--html Generate HTML report
|
|
311
|
+
--output <file> Save JSON report to file
|
|
312
|
+
|
|
313
|
+
Suite file format:
|
|
314
|
+
{
|
|
315
|
+
"name": "Staging vs Production",
|
|
316
|
+
"pairs": [
|
|
317
|
+
{ "urlA": "https://staging.example.com", "urlB": "https://example.com", "name": "Homepage" },
|
|
318
|
+
{ "urlA": "https://staging.example.com/about", "urlB": "https://example.com/about", "name": "About" }
|
|
319
|
+
],
|
|
320
|
+
"options": { "sensitivity": "medium" }
|
|
321
|
+
}
|
|
322
|
+
|
|
261
323
|
ACCESSIBILITY (v2.5.0)
|
|
262
324
|
a11y audit Run WCAG accessibility audit
|
|
263
325
|
--url <url> Navigate to URL first
|
|
@@ -2142,7 +2204,7 @@ async function main() {
|
|
|
2142
2204
|
break;
|
|
2143
2205
|
}
|
|
2144
2206
|
// =========================================================================
|
|
2145
|
-
// Cross-Browser Visual Testing (v7.
|
|
2207
|
+
// Cross-Browser Visual Testing (v7.3.0)
|
|
2146
2208
|
// =========================================================================
|
|
2147
2209
|
case "cross-browser": {
|
|
2148
2210
|
const subcommand = args[0];
|
|
@@ -2244,6 +2306,237 @@ async function main() {
|
|
|
2244
2306
|
break;
|
|
2245
2307
|
}
|
|
2246
2308
|
// =========================================================================
|
|
2309
|
+
// Responsive Visual Testing (v7.3.0)
|
|
2310
|
+
// =========================================================================
|
|
2311
|
+
case "responsive": {
|
|
2312
|
+
const subcommand = args[0];
|
|
2313
|
+
if (subcommand === "viewports") {
|
|
2314
|
+
// List viewport presets
|
|
2315
|
+
const presets = (0, browser_js_1.listViewportPresets)();
|
|
2316
|
+
console.log("\n📱 Available Viewport Presets\n");
|
|
2317
|
+
console.log("─".repeat(60));
|
|
2318
|
+
const byType = {
|
|
2319
|
+
mobile: [],
|
|
2320
|
+
tablet: [],
|
|
2321
|
+
desktop: [],
|
|
2322
|
+
};
|
|
2323
|
+
for (const preset of presets) {
|
|
2324
|
+
byType[preset.deviceType].push(preset);
|
|
2325
|
+
}
|
|
2326
|
+
for (const [type, typePresets] of Object.entries(byType)) {
|
|
2327
|
+
console.log(`\n${type.toUpperCase()}:`);
|
|
2328
|
+
for (const p of typePresets) {
|
|
2329
|
+
const touch = p.hasTouch ? " (touch)" : "";
|
|
2330
|
+
const device = p.deviceName ? ` - ${p.deviceName}` : "";
|
|
2331
|
+
console.log(` ${p.name.padEnd(15)} ${p.width}x${p.height}${touch}${device}`);
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
console.log("");
|
|
2335
|
+
}
|
|
2336
|
+
else if (subcommand === "suite") {
|
|
2337
|
+
// Responsive suite
|
|
2338
|
+
const suiteFile = args[1];
|
|
2339
|
+
if (!suiteFile) {
|
|
2340
|
+
console.error("Usage: cbrowser responsive suite <file.json> [options]");
|
|
2341
|
+
console.error(" --html Generate HTML report");
|
|
2342
|
+
console.error(" --output <file> Save report to file");
|
|
2343
|
+
process.exit(1);
|
|
2344
|
+
}
|
|
2345
|
+
const fs = await import("fs");
|
|
2346
|
+
if (!fs.existsSync(suiteFile)) {
|
|
2347
|
+
console.error(`Suite file not found: ${suiteFile}`);
|
|
2348
|
+
process.exit(1);
|
|
2349
|
+
}
|
|
2350
|
+
const suite = JSON.parse(fs.readFileSync(suiteFile, "utf-8"));
|
|
2351
|
+
const result = await (0, browser_js_1.runResponsiveSuite)(suite);
|
|
2352
|
+
// Save outputs
|
|
2353
|
+
if (options.output && !options.html) {
|
|
2354
|
+
fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
|
|
2355
|
+
console.log(`\n📄 JSON report saved to: ${options.output}`);
|
|
2356
|
+
}
|
|
2357
|
+
if (options.html) {
|
|
2358
|
+
const htmlReport = (0, browser_js_1.generateResponsiveHtmlReport)(result);
|
|
2359
|
+
const outputPath = options.output || `responsive-${Date.now()}.html`;
|
|
2360
|
+
fs.writeFileSync(outputPath, htmlReport);
|
|
2361
|
+
console.log(`\n📄 HTML report saved to: ${outputPath}`);
|
|
2362
|
+
}
|
|
2363
|
+
// Summary
|
|
2364
|
+
console.log(`\n${"═".repeat(60)}`);
|
|
2365
|
+
console.log(` Results: ${result.summary.responsive} responsive, ${result.summary.minorIssues} minor, ${result.summary.majorIssues} major`);
|
|
2366
|
+
console.log(` Total issues: ${result.summary.totalIssues}`);
|
|
2367
|
+
console.log(`${"═".repeat(60)}\n`);
|
|
2368
|
+
if (result.summary.majorIssues > 0) {
|
|
2369
|
+
process.exit(1);
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
else {
|
|
2373
|
+
// Single URL test
|
|
2374
|
+
const url = subcommand; // First arg is the URL
|
|
2375
|
+
if (!url || url.startsWith("--")) {
|
|
2376
|
+
console.error("Usage: cbrowser responsive <url> [options]");
|
|
2377
|
+
console.error(" cbrowser responsive suite <file.json>");
|
|
2378
|
+
console.error(" cbrowser responsive viewports");
|
|
2379
|
+
console.error("\nOptions:");
|
|
2380
|
+
console.error(" --viewports <list> mobile,tablet,desktop (default: mobile,tablet,desktop)");
|
|
2381
|
+
console.error(" --wait <ms> Wait before screenshot");
|
|
2382
|
+
console.error(" --wait-for <sel> Wait for selector");
|
|
2383
|
+
console.error(" --sensitivity <l> low, medium, high");
|
|
2384
|
+
console.error(" --html Generate HTML report");
|
|
2385
|
+
console.error(" --output <file> Save report");
|
|
2386
|
+
console.error("\nViewport presets: mobile-sm, mobile, mobile-lg, mobile-xl,");
|
|
2387
|
+
console.error(" tablet, tablet-lg, desktop-sm, desktop,");
|
|
2388
|
+
console.error(" desktop-lg, desktop-xl");
|
|
2389
|
+
process.exit(1);
|
|
2390
|
+
}
|
|
2391
|
+
const viewports = options.viewports
|
|
2392
|
+
? options.viewports.split(",")
|
|
2393
|
+
: undefined;
|
|
2394
|
+
const result = await (0, browser_js_1.runResponsiveTest)(url, {
|
|
2395
|
+
viewports,
|
|
2396
|
+
waitBeforeCapture: options.wait ? parseInt(options.wait) : undefined,
|
|
2397
|
+
waitForSelector: options["wait-for"],
|
|
2398
|
+
sensitivity: options.sensitivity,
|
|
2399
|
+
});
|
|
2400
|
+
// Print report
|
|
2401
|
+
console.log("\n" + (0, browser_js_1.formatResponsiveReport)(result));
|
|
2402
|
+
// Save outputs
|
|
2403
|
+
const fs = await import("fs");
|
|
2404
|
+
if (options.output && !options.html) {
|
|
2405
|
+
fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
|
|
2406
|
+
console.log(`\n📄 JSON report saved to: ${options.output}`);
|
|
2407
|
+
}
|
|
2408
|
+
if (options.html) {
|
|
2409
|
+
const suiteResult = {
|
|
2410
|
+
suite: { name: "Single URL Test", urls: [url] },
|
|
2411
|
+
results: [result],
|
|
2412
|
+
summary: {
|
|
2413
|
+
total: 1,
|
|
2414
|
+
responsive: result.overallStatus === "responsive" ? 1 : 0,
|
|
2415
|
+
minorIssues: result.overallStatus === "minor_issues" ? 1 : 0,
|
|
2416
|
+
majorIssues: result.overallStatus === "major_issues" ? 1 : 0,
|
|
2417
|
+
totalIssues: result.issues.length,
|
|
2418
|
+
},
|
|
2419
|
+
commonIssues: result.issues,
|
|
2420
|
+
duration: result.duration,
|
|
2421
|
+
timestamp: result.timestamp,
|
|
2422
|
+
};
|
|
2423
|
+
const htmlReport = (0, browser_js_1.generateResponsiveHtmlReport)(suiteResult);
|
|
2424
|
+
const outputPath = options.output || `responsive-${Date.now()}.html`;
|
|
2425
|
+
fs.writeFileSync(outputPath, htmlReport);
|
|
2426
|
+
console.log(`\n📄 HTML report saved to: ${outputPath}`);
|
|
2427
|
+
}
|
|
2428
|
+
if (result.overallStatus === "major_issues") {
|
|
2429
|
+
process.exit(1);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
break;
|
|
2433
|
+
}
|
|
2434
|
+
// =========================================================================
|
|
2435
|
+
// A/B Visual Comparison (v7.3.0)
|
|
2436
|
+
// =========================================================================
|
|
2437
|
+
case "ab": {
|
|
2438
|
+
const subcommand = args[0];
|
|
2439
|
+
if (subcommand === "suite") {
|
|
2440
|
+
// A/B suite
|
|
2441
|
+
const suiteFile = args[1];
|
|
2442
|
+
if (!suiteFile) {
|
|
2443
|
+
console.error("Usage: cbrowser ab suite <file.json> [options]");
|
|
2444
|
+
console.error(" --html Generate HTML report");
|
|
2445
|
+
console.error(" --output <file> Save report to file");
|
|
2446
|
+
process.exit(1);
|
|
2447
|
+
}
|
|
2448
|
+
const fs = await import("fs");
|
|
2449
|
+
if (!fs.existsSync(suiteFile)) {
|
|
2450
|
+
console.error(`Suite file not found: ${suiteFile}`);
|
|
2451
|
+
process.exit(1);
|
|
2452
|
+
}
|
|
2453
|
+
const suite = JSON.parse(fs.readFileSync(suiteFile, "utf-8"));
|
|
2454
|
+
const result = await (0, browser_js_1.runABSuite)(suite);
|
|
2455
|
+
// Save outputs
|
|
2456
|
+
if (options.output && !options.html) {
|
|
2457
|
+
fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
|
|
2458
|
+
console.log(`\n📄 JSON report saved to: ${options.output}`);
|
|
2459
|
+
}
|
|
2460
|
+
if (options.html) {
|
|
2461
|
+
const htmlReport = (0, browser_js_1.generateABHtmlReport)(result);
|
|
2462
|
+
const outputPath = options.output || `ab-comparison-${Date.now()}.html`;
|
|
2463
|
+
fs.writeFileSync(outputPath, htmlReport);
|
|
2464
|
+
console.log(`\n📄 HTML report saved to: ${outputPath}`);
|
|
2465
|
+
}
|
|
2466
|
+
// Summary
|
|
2467
|
+
console.log(`\n${"═".repeat(60)}`);
|
|
2468
|
+
console.log(` Results: ${result.summary.identical} identical, ${result.summary.similar} similar, ${result.summary.different} different, ${result.summary.veryDifferent} very different`);
|
|
2469
|
+
console.log(`${"═".repeat(60)}\n`);
|
|
2470
|
+
if (result.summary.veryDifferent > 0) {
|
|
2471
|
+
process.exit(1);
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
else {
|
|
2475
|
+
// Single A/B comparison: ab <urlA> <urlB>
|
|
2476
|
+
const urlA = args[0];
|
|
2477
|
+
const urlB = args[1];
|
|
2478
|
+
if (!urlA || !urlB || urlA.startsWith("--") || urlB.startsWith("--")) {
|
|
2479
|
+
console.error("Usage: cbrowser ab <urlA> <urlB> [options]");
|
|
2480
|
+
console.error(" cbrowser ab suite <file.json>");
|
|
2481
|
+
console.error("\nOptions:");
|
|
2482
|
+
console.error(" --label-a <name> Label for URL A (default: 'Version A')");
|
|
2483
|
+
console.error(" --label-b <name> Label for URL B (default: 'Version B')");
|
|
2484
|
+
console.error(" --width <n> Viewport width (default: 1920)");
|
|
2485
|
+
console.error(" --height <n> Viewport height (default: 1080)");
|
|
2486
|
+
console.error(" --wait <ms> Wait before screenshot");
|
|
2487
|
+
console.error(" --wait-for <sel> Wait for selector");
|
|
2488
|
+
console.error(" --sensitivity <l> low, medium, high");
|
|
2489
|
+
console.error(" --html Generate HTML report");
|
|
2490
|
+
console.error(" --output <file> Save report");
|
|
2491
|
+
process.exit(1);
|
|
2492
|
+
}
|
|
2493
|
+
const result = await (0, browser_js_1.runABComparison)(urlA, urlB, {
|
|
2494
|
+
labels: options["label-a"] || options["label-b"] ? {
|
|
2495
|
+
a: options["label-a"] || "Version A",
|
|
2496
|
+
b: options["label-b"] || "Version B",
|
|
2497
|
+
} : undefined,
|
|
2498
|
+
viewport: options.width || options.height ? {
|
|
2499
|
+
width: parseInt(options.width) || 1920,
|
|
2500
|
+
height: parseInt(options.height) || 1080,
|
|
2501
|
+
} : undefined,
|
|
2502
|
+
waitBeforeCapture: options.wait ? parseInt(options.wait) : undefined,
|
|
2503
|
+
waitForSelector: options["wait-for"],
|
|
2504
|
+
sensitivity: options.sensitivity,
|
|
2505
|
+
});
|
|
2506
|
+
// Print report
|
|
2507
|
+
console.log("\n" + (0, browser_js_1.formatABReport)(result));
|
|
2508
|
+
// Save outputs
|
|
2509
|
+
const fs = await import("fs");
|
|
2510
|
+
if (options.output && !options.html) {
|
|
2511
|
+
fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
|
|
2512
|
+
console.log(`\n📄 JSON report saved to: ${options.output}`);
|
|
2513
|
+
}
|
|
2514
|
+
if (options.html) {
|
|
2515
|
+
const suiteResult = {
|
|
2516
|
+
suite: { name: "Single Comparison", pairs: [{ urlA, urlB }] },
|
|
2517
|
+
results: [result],
|
|
2518
|
+
summary: {
|
|
2519
|
+
total: 1,
|
|
2520
|
+
identical: result.overallStatus === "identical" ? 1 : 0,
|
|
2521
|
+
similar: result.overallStatus === "similar" ? 1 : 0,
|
|
2522
|
+
different: result.overallStatus === "different" ? 1 : 0,
|
|
2523
|
+
veryDifferent: result.overallStatus === "very_different" ? 1 : 0,
|
|
2524
|
+
},
|
|
2525
|
+
duration: result.duration,
|
|
2526
|
+
timestamp: result.timestamp,
|
|
2527
|
+
};
|
|
2528
|
+
const htmlReport = (0, browser_js_1.generateABHtmlReport)(suiteResult);
|
|
2529
|
+
const outputPath = options.output || `ab-comparison-${Date.now()}.html`;
|
|
2530
|
+
fs.writeFileSync(outputPath, htmlReport);
|
|
2531
|
+
console.log(`\n📄 HTML report saved to: ${outputPath}`);
|
|
2532
|
+
}
|
|
2533
|
+
if (result.overallStatus === "very_different") {
|
|
2534
|
+
process.exit(1);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
break;
|
|
2538
|
+
}
|
|
2539
|
+
// =========================================================================
|
|
2247
2540
|
// Accessibility (Tier 2)
|
|
2248
2541
|
// =========================================================================
|
|
2249
2542
|
case "a11y": {
|