@wdio/nightwatch-devtools 1.5.0 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/nightwatch-devtools",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Nightwatch adapter for WebdriverIO DevTools - reuses existing backend, UI, and capture infrastructure",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -46,17 +46,17 @@
46
46
  "ws": "^8.21.0",
47
47
  "xpath": "^0.0.34",
48
48
  "yazl": "^2.5.1",
49
- "@wdio/devtools-backend": "1.8.0",
50
- "@wdio/devtools-script": "1.6.0"
49
+ "@wdio/devtools-backend": "1.9.0",
50
+ "@wdio/devtools-script": "1.7.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/node": "25.9.3",
54
54
  "@types/ws": "^8.18.1",
55
- "chromedriver": "^148.0.4",
55
+ "chromedriver": "^150.0.0",
56
56
  "nightwatch": "^3.16.0",
57
57
  "tsup": "^8.5.1",
58
58
  "typescript": "^6.0.3",
59
- "@wdio/devtools-core": "^1.0.0",
59
+ "@wdio/devtools-core": "^1.0.1",
60
60
  "@wdio/devtools-shared": "^1.0.0"
61
61
  },
62
62
  "peerDependencies": {
@@ -68,6 +68,7 @@
68
68
  "watch": "tsup src/index.ts --format esm --dts --sourcemap --watch",
69
69
  "clean": "rm -rf dist",
70
70
  "lint": "eslint .",
71
- "example": "nightwatch -c ../../examples/nightwatch/nightwatch.conf.cjs"
71
+ "example": "nightwatch -c ../../examples/nightwatch/nightwatch.conf.cjs",
72
+ "example:retry": "nightwatch -c ../../examples/nightwatch/nightwatch.conf.cjs --retries 1"
72
73
  }
73
74
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../core/src/error.ts","../../core/src/console.ts","../../core/src/net.ts"],"sourcesContent":["/** Plain-object shape of an Error after `serializeError`. */\nexport interface SerializedError {\n name: string\n message: string\n stack?: string\n}\n\n/**\n * Coerce an unknown value (caught exception, framework-supplied error\n * object, string, etc.) into an Error instance. Used at adapter command\n * boundaries where caught values can be anything — Error subclasses,\n * thrown strings, framework objects with a `.message` — and downstream\n * code wants a stable `Error` to inspect and serialize.\n */\nexport function toError(value: unknown): Error {\n if (value instanceof Error) {\n return value\n }\n if (\n value !== null &&\n typeof value === 'object' &&\n typeof (value as { message?: unknown }).message === 'string'\n ) {\n const e = new Error((value as { message: string }).message)\n const name = (value as { name?: unknown }).name\n if (typeof name === 'string') {\n e.name = name\n }\n return e\n }\n return new Error(String(value))\n}\n\n/**\n * Extract a printable message from a caught value. Equivalent to reading\n * `.message` on an Error, but degrades cleanly when the thrown value is a\n * string, a plain object, undefined, or anything else — `(err as Error).message`\n * silently returns `undefined` in those cases and yields useless log output.\n */\nexport function errorMessage(value: unknown): string {\n if (value instanceof Error) {\n return value.message\n }\n if (typeof value === 'string') {\n return value\n }\n if (\n value !== null &&\n typeof value === 'object' &&\n typeof (value as { message?: unknown }).message === 'string'\n ) {\n return (value as { message: string }).message\n }\n if (value === undefined || value === null) {\n return 'unknown error'\n }\n try {\n return String(value)\n } catch {\n return 'unknown error'\n }\n}\n\n/**\n * Normalize an Error to a plain object so its fields survive `JSON.stringify`\n * over the WS bridge. Error instances have `message`/`name`/`stack` as\n * non-enumerable, which `JSON.stringify` would drop.\n *\n * Returns `undefined` when the input is undefined so callers can pass through\n * possibly-undefined values without an extra branch.\n */\nexport function serializeError(\n error: Error | undefined\n): SerializedError | undefined {\n if (!error) {\n return undefined\n }\n return { name: error.name, message: error.message, stack: error.stack }\n}\n","import type { ConsoleLog, LogLevel, LogSource } from '@wdio/devtools-shared'\n\n/**\n * Console methods we intercept to forward test/runner-process output into the\n * UI Console tab.\n */\nexport const CONSOLE_METHODS = ['log', 'info', 'warn', 'error'] as const\n\n/**\n * Strips ANSI escape sequences (colour codes, cursor moves, etc.) from\n * terminal output so the UI Console renders plain text. The pattern accepts\n * any trailing letter, not just `m`, so cursor/style sequences are handled\n * too.\n */\nexport const ANSI_REGEX = /\\x1b\\[[?]?[0-9;]*[A-Za-z]/g\n\nexport function stripAnsi(text: string): string {\n return text.replace(ANSI_REGEX, '')\n}\n\n/**\n * Log-level detection patterns, applied in priority order (highest to\n * lowest). The first matching pattern wins.\n */\nexport const LOG_LEVEL_PATTERNS: ReadonlyArray<{\n level: 'trace' | 'debug' | 'info' | 'warn' | 'error'\n pattern: RegExp\n}> = [\n { level: 'trace', pattern: /\\btrace\\b/i },\n { level: 'debug', pattern: /\\bdebug\\b/i },\n { level: 'info', pattern: /\\binfo\\b/i },\n { level: 'warn', pattern: /\\bwarn(ing)?\\b/i },\n { level: 'error', pattern: /\\berror\\b/i }\n] as const\n\n/** Visual indicators that suggest error-level logs in unstructured output. */\nexport const ERROR_INDICATORS = ['✗', 'failed', 'failure'] as const\n\n/**\n * Matches the leading Braille spinner glyphs that runners (Nightwatch CLI,\n * Selenium tooling) emit for in-place progress updates. Adapters skip lines\n * that match this so the dashboard's Console tab isn't flooded with frames.\n */\nexport const SPINNER_RE = /^[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/u\n\n/**\n * Filter out terminal/stream lines that would feed back into the WS bridge\n * and cause an infinite forwarding loop: pino JSON output, [SESSION] markers,\n * backend logger lines, Jest console framing, and bare stack-frame lines.\n *\n * Adapters call this from their stream-patch before forwarding lines to the\n * UI Console tab. Combine with SPINNER_RE for full noise filtering.\n */\nexport function isInternalStreamLine(line: string): boolean {\n const t = line.trim()\n if (t.startsWith('{\"') || t.startsWith('[SESSION]')) {\n return true\n }\n if (t.includes('@wdio/devtools-backend')) {\n return true\n }\n if (/^console\\.(log|info|warn|error|debug|trace)$/.test(t)) {\n return true\n }\n if (/^at\\s.+:\\d+:\\d+\\)?$/.test(t)) {\n return true\n }\n return false\n}\n\n/** Enum-style accessor for the canonical LogSource values from shared. */\nexport const LOG_SOURCES = {\n BROWSER: 'browser',\n TEST: 'test',\n TERMINAL: 'terminal'\n} as const satisfies Record<string, LogSource>\n\nexport type { LogSource } from '@wdio/devtools-shared'\n\n/**\n * Classify a line of unstructured terminal output by scanning for log-level\n * keywords. Falls back to `'log'` when no pattern matches.\n */\nexport function detectLogLevel(text: string): LogLevel {\n const normalised = stripAnsi(text).toLowerCase()\n for (const { level, pattern } of LOG_LEVEL_PATTERNS) {\n if (pattern.test(normalised)) {\n return level\n }\n }\n if (ERROR_INDICATORS.some((i) => normalised.includes(i.toLowerCase()))) {\n return 'error'\n }\n return 'log'\n}\n\n/** Build a ConsoleLog entry tagged with the supplied source. */\nexport function createConsoleLogEntry(\n type: LogLevel,\n args: unknown[],\n source: LogSource = LOG_SOURCES.TEST\n): ConsoleLog {\n return { timestamp: Date.now(), type, args, source }\n}\n\n/**\n * Map raw Chrome browser-log entries (the shape returned by both\n * `driver.manage().logs().get('browser')` in selenium-webdriver and\n * `browser.getLog('browser')` in nightwatch) into the dashboard's typed\n * ConsoleLog shape, tagged as source='browser'. Each entry's Chrome level\n * (`SEVERE` / `WARNING` / `INFO` / `DEBUG`) is normalised through\n * {@link chromeLogLevelToLogLevel}.\n */\nexport function mapChromeBrowserLogs(\n entries: Array<{ level: unknown; message: string; timestamp: number }>\n): ConsoleLog[] {\n return entries.map((entry) => ({\n timestamp: entry.timestamp,\n type: chromeLogLevelToLogLevel(\n entry.level as string | { value?: number; name?: string }\n ),\n args: [entry.message],\n source: LOG_SOURCES.BROWSER\n }))\n}\n\n/**\n * Map a Chrome DevTools log-level string (or `{name, value}` object) to our\n * `LogLevel` union. Used by CDP/BiDi consumers that surface browser-side\n * console output through SEVERE/WARNING/INFO/DEBUG severity names.\n */\nexport function chromeLogLevelToLogLevel(\n level: string | { value?: number; name?: string }\n): LogLevel {\n const levelName = (\n typeof level === 'object' ? (level?.name ?? '') : (level ?? '')\n ).toUpperCase()\n switch (levelName) {\n case 'SEVERE':\n return 'error'\n case 'WARNING':\n return 'warn'\n case 'INFO':\n return 'info'\n case 'DEBUG':\n return 'debug'\n default:\n return 'log'\n }\n}\n","import * as net from 'node:net'\n\n/**\n * Return true if the given TCP port on `hostname` cannot be bound for\n * listening (already in use, or otherwise unavailable).\n */\nexport function isPortInUse(port: number, hostname: string): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer()\n server.once('error', () => resolve(true))\n server.once('listening', () => server.close(() => resolve(false)))\n server.listen(port, hostname)\n })\n}\n\n/**\n * Walk upward from `startPort` until a free port is found and return it.\n * Silent: callers that want to log retries should wrap this themselves.\n */\nexport async function findFreePort(\n startPort: number,\n hostname: string\n): Promise<number> {\n let port = startPort\n while (await isPortInUse(port, hostname)) {\n port++\n }\n return port\n}\n\n/**\n * Classify an HTTP request into the categories the dashboard's Network tab\n * uses, preferring the response `mimeType` and falling back to URL extension\n * heuristics. Unknown shapes return `'xhr'`.\n */\nexport function getRequestType(url: string, mimeType?: string): string {\n const contentType = mimeType?.toLowerCase() ?? ''\n const urlLower = url.toLowerCase()\n if (contentType.includes('text/html')) {\n return 'document'\n }\n if (contentType.includes('text/css')) {\n return 'stylesheet'\n }\n if (\n contentType.includes('javascript') ||\n contentType.includes('ecmascript')\n ) {\n return 'script'\n }\n if (contentType.includes('image/')) {\n return 'image'\n }\n if (contentType.includes('font/') || contentType.includes('woff')) {\n return 'font'\n }\n if (contentType.includes('application/json')) {\n return 'fetch'\n }\n if (urlLower.endsWith('.html') || urlLower.endsWith('.htm')) {\n return 'document'\n }\n if (urlLower.endsWith('.css')) {\n return 'stylesheet'\n }\n if (urlLower.endsWith('.js') || urlLower.endsWith('.mjs')) {\n return 'script'\n }\n if (/\\.(png|jpg|jpeg|gif|svg|webp|ico)$/.test(urlLower)) {\n return 'image'\n }\n if (/\\.(woff|woff2|ttf|eot|otf)$/.test(urlLower)) {\n return 'font'\n }\n return 'xhr'\n}\n"],"mappings":"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","names":[]}