🚀 Auto-deploy: BotVPS atualizado em 02/05/2026 15:37:40
This commit is contained in:
6
node_modules/playwright-core/lib/tools/cli-client/cli.js
generated
vendored
Normal file
6
node_modules/playwright-core/lib/tools/cli-client/cli.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
"use strict";
|
||||
var import_program = require("./program");
|
||||
(0, import_program.program)().catch((e) => {
|
||||
console.error(e.message);
|
||||
process.exit(1);
|
||||
});
|
||||
399
node_modules/playwright-core/lib/tools/cli-client/help.json
generated
vendored
Normal file
399
node_modules/playwright-core/lib/tools/cli-client/help.json
generated
vendored
Normal file
@@ -0,0 +1,399 @@
|
||||
{
|
||||
"global": "Usage: playwright-cli <command> [args] [options]\nUsage: playwright-cli -s=<session> <command> [args] [options]\n\nCore:\n open [url] open the browser\n attach <name> attach to a running playwright browser\n close close the browser\n goto <url> navigate to a url\n type <text> type text into editable element\n click <target> [button] perform click on a web page\n dblclick <target> [button] perform double click on a web page\n fill <target> <text> fill text into editable element\n drag <startElement> <endElement> perform drag and drop between two elements\n hover <target> hover over element on page\n select <target> <val> select an option in a dropdown\n upload <file> upload one or multiple files\n check <target> check a checkbox or radio button\n uncheck <target> uncheck a checkbox or radio button\n snapshot [element] capture page snapshot to obtain element ref\n eval <func> [element] evaluate javascript expression on page or element\n dialog-accept [prompt] accept a dialog\n dialog-dismiss dismiss a dialog\n resize <w> <h> resize the browser window\n delete-data delete session data\n\nNavigation:\n go-back go back to the previous page\n go-forward go forward to the next page\n reload reload the current page\n\nKeyboard:\n press <key> press a key on the keyboard, `a`, `arrowleft`\n keydown <key> press a key down on the keyboard\n keyup <key> press a key up on the keyboard\n\nMouse:\n mousemove <x> <y> move mouse to a given position\n mousedown [button] press mouse down\n mouseup [button] press mouse up\n mousewheel <dx> <dy> scroll mouse wheel\n\nSave as:\n screenshot [target] screenshot of the current page or element\n pdf save page as pdf\n\nTabs:\n tab-list list all tabs\n tab-new [url] create a new tab\n tab-close [index] close a browser tab\n tab-select <index> select a browser tab\n\nStorage:\n state-load <filename> loads browser storage (authentication) state from a file\n state-save [filename] saves the current storage (authentication) state to a file\n cookie-list list all cookies (optionally filtered by domain/path)\n cookie-get <name> get a specific cookie by name\n cookie-set <name> <value> set a cookie with optional flags\n cookie-delete <name> delete a specific cookie\n cookie-clear clear all cookies\n localstorage-list list all localstorage key-value pairs\n localstorage-get <key> get a localstorage item by key\n localstorage-set <key> <value> set a localstorage item\n localstorage-delete <key> delete a localstorage item\n localstorage-clear clear all localstorage\n sessionstorage-list list all sessionstorage key-value pairs\n sessionstorage-get <key> get a sessionstorage item by key\n sessionstorage-set <key> <value> set a sessionstorage item\n sessionstorage-delete <key> delete a sessionstorage item\n sessionstorage-clear clear all sessionstorage\n\nNetwork:\n route <pattern> mock network requests matching a url pattern\n route-list list all active network routes\n unroute [pattern] remove routes matching a pattern (or all routes)\n network-state-set <state> set the browser network state to online or offline\n\nDevTools:\n console [min-level] list console messages\n run-code [code] run playwright code snippet\n network list all network requests since loading the page\n tracing-start start trace recording\n tracing-stop stop trace recording\n video-start [filename] start video recording\n video-stop stop video recording\n video-chapter <title> add a chapter marker to the video recording\n show show browser devtools\n pause-at <location> run the test up to a specific location and pause there\n resume resume the test execution\n step-over step over the next call in the test\n\nInstall:\n install initialize workspace\n install-browser [browser] install browser\n\nBrowser sessions:\n list list browser sessions\n close-all close all browser sessions\n kill-all forcefully kill all browser sessions (for stale/zombie processes)\n\nGlobal options:\n --help [command] print help\n --version print version",
|
||||
"commands": {
|
||||
"open": {
|
||||
"help": "playwright-cli open [url]\n\nOpen the browser\n\nArguments:\n [url] the url to navigate to\nOptions:\n --browser browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.\n --config path to the configuration file, defaults to .playwright/cli.config.json\n --extension connect to browser extension\n --headed run browser in headed mode\n --persistent use persistent browser profile\n --profile use persistent browser profile, store profile in specified directory.",
|
||||
"flags": {
|
||||
"browser": "string",
|
||||
"config": "string",
|
||||
"extension": "boolean",
|
||||
"headed": "boolean",
|
||||
"persistent": "boolean",
|
||||
"profile": "string"
|
||||
}
|
||||
},
|
||||
"attach": {
|
||||
"help": "playwright-cli attach <name>\n\nAttach to a running Playwright browser\n\nArguments:\n <name> name or endpoint of the browser to attach to\nOptions:\n --config path to the configuration file, defaults to .playwright/cli.config.json\n --session session name alias (defaults to the attach target name)",
|
||||
"flags": {
|
||||
"config": "string",
|
||||
"session": "string"
|
||||
}
|
||||
},
|
||||
"close": {
|
||||
"help": "playwright-cli close \n\nClose the browser\n",
|
||||
"flags": {}
|
||||
},
|
||||
"goto": {
|
||||
"help": "playwright-cli goto <url>\n\nNavigate to a URL\n\nArguments:\n <url> the url to navigate to",
|
||||
"flags": {}
|
||||
},
|
||||
"type": {
|
||||
"help": "playwright-cli type <text>\n\nType text into editable element\n\nArguments:\n <text> text to type into the element\nOptions:\n --submit whether to submit entered text (press enter after)",
|
||||
"flags": {
|
||||
"submit": "boolean"
|
||||
}
|
||||
},
|
||||
"click": {
|
||||
"help": "playwright-cli click <target> [button]\n\nPerform click on a web page\n\nArguments:\n <target> exact target element reference from the page snapshot, or a unique element selector\n [button] button to click, defaults to left\nOptions:\n --modifiers modifier keys to press",
|
||||
"flags": {
|
||||
"modifiers": "string"
|
||||
}
|
||||
},
|
||||
"dblclick": {
|
||||
"help": "playwright-cli dblclick <target> [button]\n\nPerform double click on a web page\n\nArguments:\n <target> exact target element reference from the page snapshot, or a unique element selector\n [button] button to click, defaults to left\nOptions:\n --modifiers modifier keys to press",
|
||||
"flags": {
|
||||
"modifiers": "string"
|
||||
}
|
||||
},
|
||||
"fill": {
|
||||
"help": "playwright-cli fill <target> <text>\n\nFill text into editable element\n\nArguments:\n <target> exact target element reference from the page snapshot, or a unique element selector\n <text> text to fill into the element\nOptions:\n --submit whether to submit entered text (press enter after)",
|
||||
"flags": {
|
||||
"submit": "boolean"
|
||||
}
|
||||
},
|
||||
"drag": {
|
||||
"help": "playwright-cli drag <startElement> <endElement>\n\nPerform drag and drop between two elements\n\nArguments:\n <startElement> exact source element reference from the page snapshot, or a unique element selector\n <endElement> exact target element reference from the page snapshot, or a unique element selector",
|
||||
"flags": {}
|
||||
},
|
||||
"hover": {
|
||||
"help": "playwright-cli hover <target>\n\nHover over element on page\n\nArguments:\n <target> exact target element reference from the page snapshot, or a unique element selector",
|
||||
"flags": {}
|
||||
},
|
||||
"select": {
|
||||
"help": "playwright-cli select <target> <val>\n\nSelect an option in a dropdown\n\nArguments:\n <target> exact target element reference from the page snapshot, or a unique element selector\n <val> value to select in the dropdown",
|
||||
"flags": {}
|
||||
},
|
||||
"upload": {
|
||||
"help": "playwright-cli upload <file>\n\nUpload one or multiple files\n\nArguments:\n <file> the absolute paths to the files to upload",
|
||||
"flags": {}
|
||||
},
|
||||
"check": {
|
||||
"help": "playwright-cli check <target>\n\nCheck a checkbox or radio button\n\nArguments:\n <target> exact target element reference from the page snapshot, or a unique element selector",
|
||||
"flags": {}
|
||||
},
|
||||
"uncheck": {
|
||||
"help": "playwright-cli uncheck <target>\n\nUncheck a checkbox or radio button\n\nArguments:\n <target> exact target element reference from the page snapshot, or a unique element selector",
|
||||
"flags": {}
|
||||
},
|
||||
"snapshot": {
|
||||
"help": "playwright-cli snapshot [element]\n\nCapture page snapshot to obtain element ref\n\nArguments:\n [element] element selector of the root element to capture a partial snapshot instead of the whole page\nOptions:\n --filename save snapshot to markdown file instead of returning it in the response.\n --depth limit snapshot depth, unlimited by default.",
|
||||
"flags": {
|
||||
"filename": "string",
|
||||
"depth": "string"
|
||||
}
|
||||
},
|
||||
"eval": {
|
||||
"help": "playwright-cli eval <func> [element]\n\nEvaluate JavaScript expression on page or element\n\nArguments:\n <func> () => { /* code */ } or (element) => { /* code */ } when element is provided\n [element] exact target element reference from the page snapshot, or a unique element selector\nOptions:\n --filename save evaluation result to a file instead of returning it in the response.",
|
||||
"flags": {
|
||||
"filename": "string"
|
||||
}
|
||||
},
|
||||
"console": {
|
||||
"help": "playwright-cli console [min-level]\n\nList console messages\n\nArguments:\n [min-level] level of the console messages to return. each level includes the messages of more severe levels. defaults to \"info\".\nOptions:\n --clear whether to clear the console list",
|
||||
"flags": {
|
||||
"clear": "boolean"
|
||||
}
|
||||
},
|
||||
"dialog-accept": {
|
||||
"help": "playwright-cli dialog-accept [prompt]\n\nAccept a dialog\n\nArguments:\n [prompt] the text of the prompt in case of a prompt dialog.",
|
||||
"flags": {}
|
||||
},
|
||||
"dialog-dismiss": {
|
||||
"help": "playwright-cli dialog-dismiss \n\nDismiss a dialog\n",
|
||||
"flags": {}
|
||||
},
|
||||
"resize": {
|
||||
"help": "playwright-cli resize <w> <h>\n\nResize the browser window\n\nArguments:\n <w> width of the browser window\n <h> height of the browser window",
|
||||
"flags": {}
|
||||
},
|
||||
"run-code": {
|
||||
"help": "playwright-cli run-code [code]\n\nRun Playwright code snippet\n\nArguments:\n [code] a javascript function containing playwright code to execute. it will be invoked with a single argument, page, which you can use for any page interaction.\nOptions:\n --filename load code from the specified file.",
|
||||
"flags": {
|
||||
"filename": "string"
|
||||
}
|
||||
},
|
||||
"delete-data": {
|
||||
"help": "playwright-cli delete-data \n\nDelete session data\n",
|
||||
"flags": {}
|
||||
},
|
||||
"go-back": {
|
||||
"help": "playwright-cli go-back \n\nGo back to the previous page\n",
|
||||
"flags": {}
|
||||
},
|
||||
"go-forward": {
|
||||
"help": "playwright-cli go-forward \n\nGo forward to the next page\n",
|
||||
"flags": {}
|
||||
},
|
||||
"reload": {
|
||||
"help": "playwright-cli reload \n\nReload the current page\n",
|
||||
"flags": {}
|
||||
},
|
||||
"press": {
|
||||
"help": "playwright-cli press <key>\n\nPress a key on the keyboard, `a`, `ArrowLeft`\n\nArguments:\n <key> name of the key to press or a character to generate, such as `arrowleft` or `a`",
|
||||
"flags": {}
|
||||
},
|
||||
"keydown": {
|
||||
"help": "playwright-cli keydown <key>\n\nPress a key down on the keyboard\n\nArguments:\n <key> name of the key to press or a character to generate, such as `arrowleft` or `a`",
|
||||
"flags": {}
|
||||
},
|
||||
"keyup": {
|
||||
"help": "playwright-cli keyup <key>\n\nPress a key up on the keyboard\n\nArguments:\n <key> name of the key to press or a character to generate, such as `arrowleft` or `a`",
|
||||
"flags": {}
|
||||
},
|
||||
"mousemove": {
|
||||
"help": "playwright-cli mousemove <x> <y>\n\nMove mouse to a given position\n\nArguments:\n <x> x coordinate\n <y> y coordinate",
|
||||
"flags": {}
|
||||
},
|
||||
"mousedown": {
|
||||
"help": "playwright-cli mousedown [button]\n\nPress mouse down\n\nArguments:\n [button] button to press, defaults to left",
|
||||
"flags": {}
|
||||
},
|
||||
"mouseup": {
|
||||
"help": "playwright-cli mouseup [button]\n\nPress mouse up\n\nArguments:\n [button] button to press, defaults to left",
|
||||
"flags": {}
|
||||
},
|
||||
"mousewheel": {
|
||||
"help": "playwright-cli mousewheel <dx> <dy>\n\nScroll mouse wheel\n\nArguments:\n <dx> x delta\n <dy> y delta",
|
||||
"flags": {}
|
||||
},
|
||||
"screenshot": {
|
||||
"help": "playwright-cli screenshot [target]\n\nscreenshot of the current page or element\n\nArguments:\n [target] exact target element reference from the page snapshot, or a unique element selector.\nOptions:\n --filename file name to save the screenshot to. defaults to `page-{timestamp}.{png|jpeg}` if not specified.\n --full-page when true, takes a screenshot of the full scrollable page, instead of the currently visible viewport.",
|
||||
"flags": {
|
||||
"filename": "string",
|
||||
"full-page": "boolean"
|
||||
}
|
||||
},
|
||||
"pdf": {
|
||||
"help": "playwright-cli pdf \n\nSave page as PDF\n\nOptions:\n --filename file name to save the pdf to. defaults to `page-{timestamp}.pdf` if not specified.",
|
||||
"flags": {
|
||||
"filename": "string"
|
||||
}
|
||||
},
|
||||
"tab-list": {
|
||||
"help": "playwright-cli tab-list \n\nList all tabs\n",
|
||||
"flags": {}
|
||||
},
|
||||
"tab-new": {
|
||||
"help": "playwright-cli tab-new [url]\n\nCreate a new tab\n\nArguments:\n [url] the url to navigate to in the new tab. if omitted, the new tab will be blank.",
|
||||
"flags": {}
|
||||
},
|
||||
"tab-close": {
|
||||
"help": "playwright-cli tab-close [index]\n\nClose a browser tab\n\nArguments:\n [index] tab index. if omitted, current tab is closed.",
|
||||
"flags": {}
|
||||
},
|
||||
"tab-select": {
|
||||
"help": "playwright-cli tab-select <index>\n\nSelect a browser tab\n\nArguments:\n <index> tab index",
|
||||
"flags": {}
|
||||
},
|
||||
"state-load": {
|
||||
"help": "playwright-cli state-load <filename>\n\nLoads browser storage (authentication) state from a file\n\nArguments:\n <filename> file name to load the storage state from.",
|
||||
"flags": {}
|
||||
},
|
||||
"state-save": {
|
||||
"help": "playwright-cli state-save [filename]\n\nSaves the current storage (authentication) state to a file\n\nArguments:\n [filename] file name to save the storage state to.",
|
||||
"flags": {}
|
||||
},
|
||||
"cookie-list": {
|
||||
"help": "playwright-cli cookie-list \n\nList all cookies (optionally filtered by domain/path)\n\nOptions:\n --domain filter cookies by domain\n --path filter cookies by path",
|
||||
"flags": {
|
||||
"domain": "string",
|
||||
"path": "string"
|
||||
}
|
||||
},
|
||||
"cookie-get": {
|
||||
"help": "playwright-cli cookie-get <name>\n\nGet a specific cookie by name\n\nArguments:\n <name> cookie name",
|
||||
"flags": {}
|
||||
},
|
||||
"cookie-set": {
|
||||
"help": "playwright-cli cookie-set <name> <value>\n\nSet a cookie with optional flags\n\nArguments:\n <name> cookie name\n <value> cookie value\nOptions:\n --domain cookie domain\n --path cookie path\n --expires cookie expiration as unix timestamp\n --httpOnly whether the cookie is http only\n --secure whether the cookie is secure\n --sameSite cookie samesite attribute",
|
||||
"flags": {
|
||||
"domain": "string",
|
||||
"path": "string",
|
||||
"expires": "string",
|
||||
"httpOnly": "boolean",
|
||||
"secure": "boolean",
|
||||
"sameSite": "string"
|
||||
}
|
||||
},
|
||||
"cookie-delete": {
|
||||
"help": "playwright-cli cookie-delete <name>\n\nDelete a specific cookie\n\nArguments:\n <name> cookie name",
|
||||
"flags": {}
|
||||
},
|
||||
"cookie-clear": {
|
||||
"help": "playwright-cli cookie-clear \n\nClear all cookies\n",
|
||||
"flags": {}
|
||||
},
|
||||
"localstorage-list": {
|
||||
"help": "playwright-cli localstorage-list \n\nList all localStorage key-value pairs\n",
|
||||
"flags": {}
|
||||
},
|
||||
"localstorage-get": {
|
||||
"help": "playwright-cli localstorage-get <key>\n\nGet a localStorage item by key\n\nArguments:\n <key> key to get",
|
||||
"flags": {}
|
||||
},
|
||||
"localstorage-set": {
|
||||
"help": "playwright-cli localstorage-set <key> <value>\n\nSet a localStorage item\n\nArguments:\n <key> key to set\n <value> value to set",
|
||||
"flags": {}
|
||||
},
|
||||
"localstorage-delete": {
|
||||
"help": "playwright-cli localstorage-delete <key>\n\nDelete a localStorage item\n\nArguments:\n <key> key to delete",
|
||||
"flags": {}
|
||||
},
|
||||
"localstorage-clear": {
|
||||
"help": "playwright-cli localstorage-clear \n\nClear all localStorage\n",
|
||||
"flags": {}
|
||||
},
|
||||
"sessionstorage-list": {
|
||||
"help": "playwright-cli sessionstorage-list \n\nList all sessionStorage key-value pairs\n",
|
||||
"flags": {}
|
||||
},
|
||||
"sessionstorage-get": {
|
||||
"help": "playwright-cli sessionstorage-get <key>\n\nGet a sessionStorage item by key\n\nArguments:\n <key> key to get",
|
||||
"flags": {}
|
||||
},
|
||||
"sessionstorage-set": {
|
||||
"help": "playwright-cli sessionstorage-set <key> <value>\n\nSet a sessionStorage item\n\nArguments:\n <key> key to set\n <value> value to set",
|
||||
"flags": {}
|
||||
},
|
||||
"sessionstorage-delete": {
|
||||
"help": "playwright-cli sessionstorage-delete <key>\n\nDelete a sessionStorage item\n\nArguments:\n <key> key to delete",
|
||||
"flags": {}
|
||||
},
|
||||
"sessionstorage-clear": {
|
||||
"help": "playwright-cli sessionstorage-clear \n\nClear all sessionStorage\n",
|
||||
"flags": {}
|
||||
},
|
||||
"route": {
|
||||
"help": "playwright-cli route <pattern>\n\nMock network requests matching a URL pattern\n\nArguments:\n <pattern> url pattern to match (e.g., \"**/api/users\")\nOptions:\n --status http status code (default: 200)\n --body response body (text or json string)\n --content-type content-type header\n --header header to add in \"name: value\" format (repeatable)\n --remove-header comma-separated header names to remove",
|
||||
"flags": {
|
||||
"status": "string",
|
||||
"body": "string",
|
||||
"content-type": "string",
|
||||
"header": "string",
|
||||
"remove-header": "string"
|
||||
}
|
||||
},
|
||||
"route-list": {
|
||||
"help": "playwright-cli route-list \n\nList all active network routes\n",
|
||||
"flags": {}
|
||||
},
|
||||
"unroute": {
|
||||
"help": "playwright-cli unroute [pattern]\n\nRemove routes matching a pattern (or all routes)\n\nArguments:\n [pattern] url pattern to unroute (omit to remove all)",
|
||||
"flags": {}
|
||||
},
|
||||
"network-state-set": {
|
||||
"help": "playwright-cli network-state-set <state>\n\nSet the browser network state to online or offline\n\nArguments:\n <state> set to \"offline\" to simulate offline mode, \"online\" to restore network connectivity",
|
||||
"flags": {}
|
||||
},
|
||||
"config-print": {
|
||||
"help": "playwright-cli config-print \n\nPrint the final resolved config after merging CLI options, environment variables and config file.\n",
|
||||
"flags": {}
|
||||
},
|
||||
"install": {
|
||||
"help": "playwright-cli install \n\nInitialize workspace\n\nOptions:\n --skills install skills to \".claude\" (default) or \".agents\" dir",
|
||||
"flags": {
|
||||
"skills": "string"
|
||||
}
|
||||
},
|
||||
"install-browser": {
|
||||
"help": "playwright-cli install-browser [browser]\n\nInstall browser\n\nArguments:\n [browser] browser to install\nOptions:\n --with-deps install system dependencies for browsers\n --dry-run do not execute installation, only print information\n --list prints list of browsers from all playwright installations\n --force force reinstall of already installed browsers\n --only-shell only install headless shell when installing chromium\n --no-shell do not install chromium headless shell",
|
||||
"flags": {
|
||||
"with-deps": "boolean",
|
||||
"dry-run": "boolean",
|
||||
"list": "boolean",
|
||||
"force": "boolean",
|
||||
"only-shell": "boolean",
|
||||
"no-shell": "boolean"
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"help": "playwright-cli network \n\nList all network requests since loading the page\n\nOptions:\n --static whether to include successful static resources like images, fonts, scripts, etc. defaults to false.\n --request-body whether to include request body. defaults to false.\n --request-headers whether to include request headers. defaults to false.\n --filter only return requests whose url matches this regexp (e.g. \"/api/.*user\").\n --clear whether to clear the network list",
|
||||
"flags": {
|
||||
"static": "boolean",
|
||||
"request-body": "boolean",
|
||||
"request-headers": "boolean",
|
||||
"filter": "string",
|
||||
"clear": "boolean"
|
||||
}
|
||||
},
|
||||
"tracing-start": {
|
||||
"help": "playwright-cli tracing-start \n\nStart trace recording\n",
|
||||
"flags": {}
|
||||
},
|
||||
"tracing-stop": {
|
||||
"help": "playwright-cli tracing-stop \n\nStop trace recording\n",
|
||||
"flags": {}
|
||||
},
|
||||
"video-start": {
|
||||
"help": "playwright-cli video-start [filename]\n\nStart video recording\n\nArguments:\n [filename] filename to save the video.\nOptions:\n --size video frame size, e.g. \"800x600\". if not specified, the size of the recorded video will fit 800x800.",
|
||||
"flags": {
|
||||
"size": "string"
|
||||
}
|
||||
},
|
||||
"video-stop": {
|
||||
"help": "playwright-cli video-stop \n\nStop video recording\n",
|
||||
"flags": {}
|
||||
},
|
||||
"video-chapter": {
|
||||
"help": "playwright-cli video-chapter <title>\n\nAdd a chapter marker to the video recording\n\nArguments:\n <title> chapter title.\nOptions:\n --description chapter description.\n --duration duration in milliseconds to show the chapter card.",
|
||||
"flags": {
|
||||
"description": "string",
|
||||
"duration": "string"
|
||||
}
|
||||
},
|
||||
"show": {
|
||||
"help": "playwright-cli show \n\nShow browser DevTools\n",
|
||||
"flags": {}
|
||||
},
|
||||
"pause-at": {
|
||||
"help": "playwright-cli pause-at <location>\n\nRun the test up to a specific location and pause there\n\nArguments:\n <location> location to pause at. format is <file>:<line>, e.g. \"example.spec.ts:42\".",
|
||||
"flags": {}
|
||||
},
|
||||
"resume": {
|
||||
"help": "playwright-cli resume \n\nResume the test execution\n",
|
||||
"flags": {}
|
||||
},
|
||||
"step-over": {
|
||||
"help": "playwright-cli step-over \n\nStep over the next call in the test\n",
|
||||
"flags": {}
|
||||
},
|
||||
"list": {
|
||||
"help": "playwright-cli list \n\nList browser sessions\n\nOptions:\n --all list all browser sessions across all workspaces",
|
||||
"flags": {
|
||||
"all": "boolean"
|
||||
}
|
||||
},
|
||||
"close-all": {
|
||||
"help": "playwright-cli close-all \n\nClose all browser sessions\n",
|
||||
"flags": {}
|
||||
},
|
||||
"kill-all": {
|
||||
"help": "playwright-cli kill-all \n\nForcefully kill all browser sessions (for stale/zombie processes)\n",
|
||||
"flags": {}
|
||||
},
|
||||
"tray": {
|
||||
"help": "playwright-cli tray \n\nRun tray\n",
|
||||
"flags": {}
|
||||
}
|
||||
},
|
||||
"booleanOptions": [
|
||||
"extension",
|
||||
"headed",
|
||||
"persistent",
|
||||
"submit",
|
||||
"clear",
|
||||
"full-page",
|
||||
"httpOnly",
|
||||
"secure",
|
||||
"with-deps",
|
||||
"dry-run",
|
||||
"list",
|
||||
"force",
|
||||
"only-shell",
|
||||
"no-shell",
|
||||
"static",
|
||||
"request-body",
|
||||
"request-headers",
|
||||
"all"
|
||||
]
|
||||
}
|
||||
128
node_modules/playwright-core/lib/tools/cli-client/minimist.js
generated
vendored
Normal file
128
node_modules/playwright-core/lib/tools/cli-client/minimist.js
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var minimist_exports = {};
|
||||
__export(minimist_exports, {
|
||||
minimist: () => minimist
|
||||
});
|
||||
module.exports = __toCommonJS(minimist_exports);
|
||||
function minimist(args, opts) {
|
||||
if (!opts)
|
||||
opts = {};
|
||||
const bools = {};
|
||||
const strings = {};
|
||||
for (const key of toArray(opts.boolean))
|
||||
bools[key] = true;
|
||||
for (const key of toArray(opts.string))
|
||||
strings[key] = true;
|
||||
const argv = { _: [] };
|
||||
function setArg(key, val) {
|
||||
if (argv[key] === void 0 || bools[key] || typeof argv[key] === "boolean")
|
||||
argv[key] = val;
|
||||
else if (Array.isArray(argv[key]))
|
||||
argv[key].push(val);
|
||||
else
|
||||
argv[key] = [argv[key], val];
|
||||
}
|
||||
let notFlags = [];
|
||||
const doubleDashIndex = args.indexOf("--");
|
||||
if (doubleDashIndex !== -1) {
|
||||
notFlags = args.slice(doubleDashIndex + 1);
|
||||
args = args.slice(0, doubleDashIndex);
|
||||
}
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
let key;
|
||||
let next;
|
||||
if (/^--.+=/.test(arg)) {
|
||||
const m = arg.match(/^--([^=]+)=([\s\S]*)$/);
|
||||
key = m[1];
|
||||
if (bools[key])
|
||||
throw new Error(`boolean option '--${key}' should not be passed with '=value', use '--${key}' or '--no-${key}' instead`);
|
||||
setArg(key, m[2]);
|
||||
} else if (/^--no-.+/.test(arg)) {
|
||||
key = arg.match(/^--no-(.+)/)[1];
|
||||
setArg(key, false);
|
||||
} else if (/^--.+/.test(arg)) {
|
||||
key = arg.match(/^--(.+)/)[1];
|
||||
next = args[i + 1];
|
||||
if (next !== void 0 && !/^(-|--)[^-]/.test(next) && !bools[key]) {
|
||||
setArg(key, next);
|
||||
i += 1;
|
||||
} else if (/^(true|false)$/.test(next)) {
|
||||
setArg(key, next === "true");
|
||||
i += 1;
|
||||
} else {
|
||||
setArg(key, strings[key] ? "" : true);
|
||||
}
|
||||
} else if (/^-[^-]+/.test(arg)) {
|
||||
const letters = arg.slice(1, -1).split("");
|
||||
let broken = false;
|
||||
for (let j = 0; j < letters.length; j++) {
|
||||
next = arg.slice(j + 2);
|
||||
if (next === "-") {
|
||||
setArg(letters[j], next);
|
||||
continue;
|
||||
}
|
||||
if (/[A-Za-z]/.test(letters[j]) && next[0] === "=") {
|
||||
setArg(letters[j], next.slice(1));
|
||||
broken = true;
|
||||
break;
|
||||
}
|
||||
if (/[A-Za-z]/.test(letters[j]) && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
|
||||
setArg(letters[j], next);
|
||||
broken = true;
|
||||
break;
|
||||
}
|
||||
if (letters[j + 1] && letters[j + 1].match(/\W/)) {
|
||||
setArg(letters[j], arg.slice(j + 2));
|
||||
broken = true;
|
||||
break;
|
||||
} else {
|
||||
setArg(letters[j], strings[letters[j]] ? "" : true);
|
||||
}
|
||||
}
|
||||
key = arg.slice(-1)[0];
|
||||
if (!broken && key !== "-") {
|
||||
if (args[i + 1] && !/^(-|--)[^-]/.test(args[i + 1]) && !bools[key]) {
|
||||
setArg(key, args[i + 1]);
|
||||
i += 1;
|
||||
} else if (args[i + 1] && /^(true|false)$/.test(args[i + 1])) {
|
||||
setArg(key, args[i + 1] === "true");
|
||||
i += 1;
|
||||
} else {
|
||||
setArg(key, strings[key] ? "" : true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
argv._.push(arg);
|
||||
}
|
||||
}
|
||||
for (const k of notFlags)
|
||||
argv._.push(k);
|
||||
return argv;
|
||||
}
|
||||
function toArray(value) {
|
||||
if (!value)
|
||||
return [];
|
||||
return Array.isArray(value) ? value : [value];
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
minimist
|
||||
});
|
||||
350
node_modules/playwright-core/lib/tools/cli-client/program.js
generated
vendored
Normal file
350
node_modules/playwright-core/lib/tools/cli-client/program.js
generated
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var program_exports = {};
|
||||
__export(program_exports, {
|
||||
calculateSha1: () => calculateSha1,
|
||||
program: () => program
|
||||
});
|
||||
module.exports = __toCommonJS(program_exports);
|
||||
var import_child_process = require("child_process");
|
||||
var import_crypto = __toESM(require("crypto"));
|
||||
var import_os = __toESM(require("os"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_registry = require("./registry");
|
||||
var import_session = require("./session");
|
||||
var import_serverRegistry = require("../../serverRegistry");
|
||||
var import_minimist = require("./minimist");
|
||||
const globalOptions = [
|
||||
"endpoint",
|
||||
"browser",
|
||||
"config",
|
||||
"extension",
|
||||
"headed",
|
||||
"help",
|
||||
"persistent",
|
||||
"profile",
|
||||
"session",
|
||||
"version"
|
||||
];
|
||||
const booleanOptions = [
|
||||
"all",
|
||||
"help",
|
||||
"version"
|
||||
];
|
||||
async function program(options) {
|
||||
const clientInfo = (0, import_registry.createClientInfo)();
|
||||
const help = require("./help.json");
|
||||
const argv = process.argv.slice(2);
|
||||
const boolean = [...help.booleanOptions, ...booleanOptions];
|
||||
const args = (0, import_minimist.minimist)(argv, { boolean, string: ["_"] });
|
||||
if (args.s) {
|
||||
args.session = args.s;
|
||||
delete args.s;
|
||||
}
|
||||
const commandName = args._?.[0];
|
||||
if (args.version || args.v) {
|
||||
console.log(options?.embedderVersion ?? clientInfo.version);
|
||||
process.exit(0);
|
||||
}
|
||||
const command = commandName && help.commands[commandName];
|
||||
if (args.help || args.h) {
|
||||
if (command) {
|
||||
console.log(command.help);
|
||||
} else {
|
||||
console.log("playwright-cli - run playwright mcp commands from terminal\n");
|
||||
console.log(help.global);
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
if (!command) {
|
||||
console.error(`Unknown command: ${commandName}
|
||||
`);
|
||||
console.log(help.global);
|
||||
process.exit(1);
|
||||
}
|
||||
validateFlags(args, command);
|
||||
const registry = await import_registry.Registry.load();
|
||||
const sessionName = (0, import_registry.resolveSessionName)(args.session);
|
||||
switch (commandName) {
|
||||
case "list": {
|
||||
await listSessions(registry, clientInfo, !!args.all);
|
||||
return;
|
||||
}
|
||||
case "close-all": {
|
||||
const entries = registry.entries(clientInfo);
|
||||
for (const entry of entries)
|
||||
await new import_session.Session(entry).stop(true);
|
||||
return;
|
||||
}
|
||||
case "delete-data": {
|
||||
const entry = registry.entry(clientInfo, sessionName);
|
||||
if (!entry) {
|
||||
console.log(`No user data found for browser '${sessionName}'.`);
|
||||
return;
|
||||
}
|
||||
await new import_session.Session(entry).deleteData();
|
||||
return;
|
||||
}
|
||||
case "kill-all": {
|
||||
await killAllDaemons();
|
||||
return;
|
||||
}
|
||||
case "open": {
|
||||
await startSession(sessionName, registry, clientInfo, args);
|
||||
return;
|
||||
}
|
||||
case "attach": {
|
||||
const attachTarget = args._[1];
|
||||
const attachSessionName = (0, import_registry.explicitSessionName)(args.session) ?? attachTarget;
|
||||
args.endpoint = attachTarget;
|
||||
args.session = attachSessionName;
|
||||
await startSession(attachSessionName, registry, clientInfo, args);
|
||||
return;
|
||||
}
|
||||
case "close":
|
||||
const closeEntry = registry.entry(clientInfo, sessionName);
|
||||
const session = closeEntry ? new import_session.Session(closeEntry) : void 0;
|
||||
if (!session || !await session.canConnect()) {
|
||||
console.log(`Browser '${sessionName}' is not open.`);
|
||||
return;
|
||||
}
|
||||
await session.stop();
|
||||
return;
|
||||
case "install":
|
||||
await runInitWorkspace(args);
|
||||
return;
|
||||
case "install-browser":
|
||||
await installBrowser();
|
||||
return;
|
||||
case "show": {
|
||||
const daemonScript = require.resolve("../dashboard/dashboardApp.js");
|
||||
const child = (0, import_child_process.spawn)(process.execPath, [daemonScript], {
|
||||
detached: true,
|
||||
stdio: "ignore"
|
||||
});
|
||||
child.unref();
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
const entry = registry.entry(clientInfo, sessionName);
|
||||
if (!entry) {
|
||||
console.log(`The browser '${sessionName}' is not open, please run open first`);
|
||||
console.log("");
|
||||
console.log(` playwright-cli${sessionName !== "default" ? ` -s=${sessionName}` : ""} open [params]`);
|
||||
process.exit(1);
|
||||
}
|
||||
await runInSession(entry, clientInfo, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function startSession(sessionName, registry, clientInfo, args) {
|
||||
const entry = registry.entry(clientInfo, sessionName);
|
||||
if (entry)
|
||||
await new import_session.Session(entry).stop(true);
|
||||
await import_session.Session.startDaemon(clientInfo, args);
|
||||
const newEntry = await registry.loadEntry(clientInfo, sessionName);
|
||||
await runInSession(newEntry, clientInfo, args);
|
||||
}
|
||||
async function runInSession(entry, clientInfo, args) {
|
||||
for (const globalOption of globalOptions)
|
||||
delete args[globalOption];
|
||||
const session = new import_session.Session(entry);
|
||||
const result = await session.run(clientInfo, args);
|
||||
console.log(result.text);
|
||||
}
|
||||
async function runInitWorkspace(args) {
|
||||
const cliPath = require.resolve("../cli-daemon/program.js");
|
||||
const daemonArgs = [cliPath, "--init-workspace", ...args.skills ? ["--init-skills", String(args.skills)] : []];
|
||||
await new Promise((resolve, reject) => {
|
||||
const child = (0, import_child_process.spawn)(process.execPath, daemonArgs, {
|
||||
stdio: "inherit",
|
||||
cwd: process.cwd()
|
||||
});
|
||||
child.on("close", (code) => {
|
||||
if (code === 0)
|
||||
resolve();
|
||||
else
|
||||
reject(new Error(`Workspace initialization failed with exit code ${code}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
async function installBrowser() {
|
||||
const { program: program2 } = require("../../cli/program");
|
||||
const argv = process.argv.map((arg) => arg === "install-browser" ? "install" : arg);
|
||||
program2.parse(argv);
|
||||
}
|
||||
async function killAllDaemons() {
|
||||
const platform = import_os.default.platform();
|
||||
let killed = 0;
|
||||
try {
|
||||
if (platform === "win32") {
|
||||
const result = (0, import_child_process.execSync)(
|
||||
`powershell -NoProfile -NonInteractive -Command "Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*run-mcp-server*' -or $_.CommandLine -like '*run-cli-server*' -or $_.CommandLine -like '*cli-daemon*' -or $_.CommandLine -like '*dashboardApp.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue; $_.ProcessId }"`,
|
||||
{ encoding: "utf-8" }
|
||||
);
|
||||
const pids = result.split("\n").map((line) => line.trim()).filter((line) => /^\d+$/.test(line));
|
||||
for (const pid of pids)
|
||||
console.log(`Killed daemon process ${pid}`);
|
||||
killed = pids.length;
|
||||
} else {
|
||||
const result = (0, import_child_process.execSync)("ps aux", { encoding: "utf-8" });
|
||||
const lines = result.split("\n");
|
||||
for (const line of lines) {
|
||||
if (line.includes("run-mcp-server") || line.includes("run-cli-server") || line.includes("cli-daemon") || line.includes("dashboardApp.js")) {
|
||||
const parts = line.trim().split(/\s+/);
|
||||
const pid = parts[1];
|
||||
if (pid && /^\d+$/.test(pid)) {
|
||||
try {
|
||||
process.kill(parseInt(pid, 10), "SIGKILL");
|
||||
console.log(`Killed daemon process ${pid}`);
|
||||
killed++;
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
if (killed === 0)
|
||||
console.log("No daemon processes found.");
|
||||
else if (killed > 0)
|
||||
console.log(`Killed ${killed} daemon process${killed === 1 ? "" : "es"}.`);
|
||||
}
|
||||
async function listSessions(registry, clientInfo, all) {
|
||||
console.log("### Browsers");
|
||||
let count = 0;
|
||||
const runningSessions = /* @__PURE__ */ new Set();
|
||||
const entries = registry.entryMap();
|
||||
for (const [workspace, list] of entries) {
|
||||
if (!all && workspace !== clientInfo.workspaceDir)
|
||||
continue;
|
||||
count += await gcAndPrintSessions(clientInfo, list.map((entry) => new import_session.Session(entry)), all ? `${import_path.default.relative(process.cwd(), workspace) || "/"}:` : void 0, runningSessions);
|
||||
}
|
||||
const serverEntries = await import_serverRegistry.serverRegistry.list();
|
||||
const filteredServerEntries = /* @__PURE__ */ new Map();
|
||||
for (const [workspace, list] of serverEntries) {
|
||||
if (!all && workspace !== clientInfo.workspaceDir)
|
||||
continue;
|
||||
const unattached = list.filter((d) => !runningSessions.has(d.title));
|
||||
if (unattached.length)
|
||||
filteredServerEntries.set(workspace, unattached);
|
||||
}
|
||||
if (filteredServerEntries.size) {
|
||||
if (count)
|
||||
console.log("");
|
||||
console.log("### Browser servers available for attach");
|
||||
}
|
||||
for (const [workspace, list] of filteredServerEntries)
|
||||
count += await gcAndPrintBrowserSessions(workspace, list);
|
||||
if (!count)
|
||||
console.log(" (no browsers)");
|
||||
}
|
||||
async function gcAndPrintSessions(clientInfo, sessions, header, runningSessions) {
|
||||
const running = [];
|
||||
const stopped = [];
|
||||
for (const session of sessions) {
|
||||
const canConnect = await session.canConnect();
|
||||
if (canConnect) {
|
||||
running.push(session);
|
||||
runningSessions?.add(session.name);
|
||||
} else {
|
||||
if (session.config.cli.persistent)
|
||||
stopped.push(session);
|
||||
else
|
||||
await session.deleteSessionConfig();
|
||||
}
|
||||
}
|
||||
if (header && (running.length || stopped.length))
|
||||
console.log(header);
|
||||
for (const session of running)
|
||||
console.log(await renderSessionStatus(clientInfo, session));
|
||||
for (const session of stopped)
|
||||
console.log(await renderSessionStatus(clientInfo, session));
|
||||
return running.length + stopped.length;
|
||||
}
|
||||
async function gcAndPrintBrowserSessions(workspace, list) {
|
||||
if (!list.length)
|
||||
return 0;
|
||||
if (workspace)
|
||||
console.log(`${import_path.default.relative(process.cwd(), workspace) || "/"}:`);
|
||||
for (const descriptor of list) {
|
||||
const text = [];
|
||||
text.push(`- browser "${descriptor.title}":`);
|
||||
text.push(` - browser: ${descriptor.browser.browserName}`);
|
||||
text.push(` - version: v${descriptor.playwrightVersion}`);
|
||||
text.push(` - status: ${descriptor.canConnect ? "open" : "closed"}`);
|
||||
if (descriptor.browser.userDataDir)
|
||||
text.push(` - data-dir: ${descriptor.browser.userDataDir}`);
|
||||
else
|
||||
text.push(` - data-dir: <in-memory>`);
|
||||
text.push(` - run \`playwright-cli attach "${descriptor.title}"\` to attach`);
|
||||
console.log(text.join("\n"));
|
||||
}
|
||||
return list.length;
|
||||
}
|
||||
async function renderSessionStatus(clientInfo, session) {
|
||||
const text = [];
|
||||
const config = session.config;
|
||||
const canConnect = await session.canConnect();
|
||||
text.push(`- ${session.name}:`);
|
||||
text.push(` - status: ${canConnect ? "open" : "closed"}`);
|
||||
if (canConnect && !session.isCompatible(clientInfo))
|
||||
text.push(` - version: v${config.version} [incompatible please re-open]`);
|
||||
if (config.browser)
|
||||
text.push(...(0, import_session.renderResolvedConfig)(config));
|
||||
return text.join("\n");
|
||||
}
|
||||
function validateFlags(args, command) {
|
||||
const unknownFlags = [];
|
||||
for (const key of Object.keys(args)) {
|
||||
if (key === "_")
|
||||
continue;
|
||||
if (globalOptions.includes(key))
|
||||
continue;
|
||||
if (!(key in command.flags))
|
||||
unknownFlags.push(key);
|
||||
}
|
||||
if (unknownFlags.length) {
|
||||
console.error(`Unknown option${unknownFlags.length > 1 ? "s" : ""}: ${unknownFlags.map((f) => `--${f}`).join(", ")}`);
|
||||
console.log("");
|
||||
console.log(command.help);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
function calculateSha1(buffer) {
|
||||
const hash = import_crypto.default.createHash("sha1");
|
||||
hash.update(buffer);
|
||||
return hash.digest("hex");
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
calculateSha1,
|
||||
program
|
||||
});
|
||||
176
node_modules/playwright-core/lib/tools/cli-client/registry.js
generated
vendored
Normal file
176
node_modules/playwright-core/lib/tools/cli-client/registry.js
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var registry_exports = {};
|
||||
__export(registry_exports, {
|
||||
Registry: () => Registry,
|
||||
baseDaemonDir: () => baseDaemonDir,
|
||||
createClientInfo: () => createClientInfo,
|
||||
explicitSessionName: () => explicitSessionName,
|
||||
resolveSessionName: () => resolveSessionName
|
||||
});
|
||||
module.exports = __toCommonJS(registry_exports);
|
||||
var import_crypto = __toESM(require("crypto"));
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_os = __toESM(require("os"));
|
||||
var import_path = __toESM(require("path"));
|
||||
class Registry {
|
||||
constructor(files) {
|
||||
this._files = files;
|
||||
}
|
||||
entry(clientInfo, sessionName) {
|
||||
const key = clientInfo.workspaceDir || clientInfo.workspaceDirHash;
|
||||
const entries = this._files.get(key) || [];
|
||||
return entries.find((entry) => entry.config.name === sessionName);
|
||||
}
|
||||
entries(clientInfo) {
|
||||
const key = clientInfo.workspaceDir || clientInfo.workspaceDirHash;
|
||||
return this._files.get(key) || [];
|
||||
}
|
||||
entryMap() {
|
||||
return this._files;
|
||||
}
|
||||
async loadEntry(clientInfo, sessionName) {
|
||||
const entry = await Registry._loadSessionEntry(clientInfo.daemonProfilesDir, sessionName + ".session");
|
||||
if (!entry)
|
||||
throw new Error(`Could not start the session "${sessionName}"`);
|
||||
const key = clientInfo.workspaceDir || clientInfo.workspaceDirHash;
|
||||
let list = this._files.get(key);
|
||||
if (!list) {
|
||||
list = [];
|
||||
this._files.set(key, list);
|
||||
}
|
||||
const oldIndex = list.findIndex((e) => e.config.name === sessionName);
|
||||
if (oldIndex !== -1)
|
||||
list.splice(oldIndex, 1);
|
||||
list.push(entry);
|
||||
return entry;
|
||||
}
|
||||
static async _loadSessionEntry(daemonDir, file) {
|
||||
try {
|
||||
const fileName = import_path.default.join(daemonDir, file);
|
||||
const data = await import_fs.default.promises.readFile(fileName, "utf-8");
|
||||
const config = JSON.parse(data);
|
||||
if (!config.name)
|
||||
config.name = import_path.default.basename(file, ".session");
|
||||
if (!config.timestamp)
|
||||
config.timestamp = 0;
|
||||
return { file: fileName, config, daemonDir };
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
static async load() {
|
||||
const sessions = /* @__PURE__ */ new Map();
|
||||
const hashDirs = await import_fs.default.promises.readdir(baseDaemonDir).catch(() => []);
|
||||
for (const workspaceDirHash of hashDirs) {
|
||||
const daemonDir = import_path.default.join(baseDaemonDir, workspaceDirHash);
|
||||
const stat = await import_fs.default.promises.stat(daemonDir);
|
||||
if (!stat.isDirectory())
|
||||
continue;
|
||||
const files = await import_fs.default.promises.readdir(daemonDir).catch(() => []);
|
||||
for (const file of files) {
|
||||
if (!file.endsWith(".session"))
|
||||
continue;
|
||||
const entry = await Registry._loadSessionEntry(daemonDir, file);
|
||||
if (!entry)
|
||||
continue;
|
||||
const key = entry.config.workspaceDir || workspaceDirHash;
|
||||
let list = sessions.get(key);
|
||||
if (!list) {
|
||||
list = [];
|
||||
sessions.set(key, list);
|
||||
}
|
||||
list.push(entry);
|
||||
}
|
||||
}
|
||||
return new Registry(sessions);
|
||||
}
|
||||
}
|
||||
const baseDaemonDir = (() => {
|
||||
if (process.env.PLAYWRIGHT_DAEMON_SESSION_DIR)
|
||||
return process.env.PLAYWRIGHT_DAEMON_SESSION_DIR;
|
||||
let localCacheDir;
|
||||
if (process.platform === "linux")
|
||||
localCacheDir = process.env.XDG_CACHE_HOME || import_path.default.join(import_os.default.homedir(), ".cache");
|
||||
if (process.platform === "darwin")
|
||||
localCacheDir = import_path.default.join(import_os.default.homedir(), "Library", "Caches");
|
||||
if (process.platform === "win32")
|
||||
localCacheDir = process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local");
|
||||
if (!localCacheDir)
|
||||
throw new Error("Unsupported platform: " + process.platform);
|
||||
return import_path.default.join(localCacheDir, "ms-playwright", "daemon");
|
||||
})();
|
||||
function createClientInfo() {
|
||||
const packageLocation = require.resolve("../../../package.json");
|
||||
const packageJSON = require(packageLocation);
|
||||
const workspaceDir = findWorkspaceDir(process.cwd());
|
||||
const version = process.env.PLAYWRIGHT_CLI_VERSION_FOR_TEST || packageJSON.version;
|
||||
const hash = import_crypto.default.createHash("sha1");
|
||||
hash.update(workspaceDir || packageLocation);
|
||||
const workspaceDirHash = hash.digest("hex").substring(0, 16);
|
||||
return {
|
||||
version,
|
||||
workspaceDir,
|
||||
workspaceDirHash,
|
||||
daemonProfilesDir: daemonProfilesDir(workspaceDirHash)
|
||||
};
|
||||
}
|
||||
function findWorkspaceDir(startDir) {
|
||||
let dir = startDir;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (import_fs.default.existsSync(import_path.default.join(dir, ".playwright")))
|
||||
return dir;
|
||||
const parentDir = import_path.default.dirname(dir);
|
||||
if (parentDir === dir)
|
||||
break;
|
||||
dir = parentDir;
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
const daemonProfilesDir = (workspaceDirHash) => {
|
||||
return import_path.default.join(baseDaemonDir, workspaceDirHash);
|
||||
};
|
||||
function explicitSessionName(sessionName) {
|
||||
return sessionName || process.env.PLAYWRIGHT_CLI_SESSION;
|
||||
}
|
||||
function resolveSessionName(sessionName) {
|
||||
if (sessionName)
|
||||
return sessionName;
|
||||
if (process.env.PLAYWRIGHT_CLI_SESSION)
|
||||
return process.env.PLAYWRIGHT_CLI_SESSION;
|
||||
return "default";
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
Registry,
|
||||
baseDaemonDir,
|
||||
createClientInfo,
|
||||
explicitSessionName,
|
||||
resolveSessionName
|
||||
});
|
||||
289
node_modules/playwright-core/lib/tools/cli-client/session.js
generated
vendored
Normal file
289
node_modules/playwright-core/lib/tools/cli-client/session.js
generated
vendored
Normal file
@@ -0,0 +1,289 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var session_exports = {};
|
||||
__export(session_exports, {
|
||||
Session: () => Session,
|
||||
renderResolvedConfig: () => renderResolvedConfig
|
||||
});
|
||||
module.exports = __toCommonJS(session_exports);
|
||||
var import_child_process = require("child_process");
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_net = __toESM(require("net"));
|
||||
var import_os = __toESM(require("os"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_socketConnection = require("../utils/socketConnection");
|
||||
var import_registry = require("./registry");
|
||||
class Session {
|
||||
constructor(sessionFile) {
|
||||
this.config = sessionFile.config;
|
||||
this.name = this.config.name;
|
||||
this._sessionFile = sessionFile;
|
||||
}
|
||||
isCompatible(clientInfo) {
|
||||
return (0, import_socketConnection.compareSemver)(clientInfo.version, this.config.version) >= 0;
|
||||
}
|
||||
async run(clientInfo, args) {
|
||||
if (!this.isCompatible(clientInfo))
|
||||
throw new Error(`Client is v${clientInfo.version}, session '${this.name}' is v${this.config.version}. Run
|
||||
|
||||
playwright-cli${this.name !== "default" ? ` -s=${this.name}` : ""} open
|
||||
|
||||
to restart the browser session.`);
|
||||
const { socket } = await this._connect();
|
||||
if (!socket)
|
||||
throw new Error(`Browser '${this.name}' is not open. Run
|
||||
|
||||
playwright-cli${this.name !== "default" ? ` -s=${this.name}` : ""} open
|
||||
|
||||
to start the browser session.`);
|
||||
return await SocketConnectionClient.sendAndClose(socket, "run", { args, cwd: process.cwd() });
|
||||
}
|
||||
async stop(quiet = false) {
|
||||
if (!await this.canConnect()) {
|
||||
if (!quiet)
|
||||
console.log(`Browser '${this.name}' is not open.`);
|
||||
return;
|
||||
}
|
||||
await this._stopDaemon();
|
||||
if (!quiet)
|
||||
console.log(`Browser '${this.name}' closed
|
||||
`);
|
||||
}
|
||||
async deleteData() {
|
||||
await this.stop();
|
||||
const dataDirs = await import_fs.default.promises.readdir(this._sessionFile.daemonDir).catch(() => []);
|
||||
const matchingEntries = dataDirs.filter((file) => file === `${this.name}.session` || file.startsWith(`ud-${this.name}-`));
|
||||
if (matchingEntries.length === 0) {
|
||||
console.log(`No user data found for browser '${this.name}'.`);
|
||||
return;
|
||||
}
|
||||
for (const entry of matchingEntries) {
|
||||
const userDataDir = import_path.default.resolve(this._sessionFile.daemonDir, entry);
|
||||
for (let i = 0; i < 5; i++) {
|
||||
try {
|
||||
await import_fs.default.promises.rm(userDataDir, { recursive: true });
|
||||
if (entry.startsWith("ud-"))
|
||||
console.log(`Deleted user data for browser '${this.name}'.`);
|
||||
break;
|
||||
} catch (e) {
|
||||
if (e.code === "ENOENT") {
|
||||
console.log(`No user data found for browser '${this.name}'.`);
|
||||
break;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
||||
if (i === 4)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
async _connect() {
|
||||
return await new Promise((resolve) => {
|
||||
const socket = import_net.default.createConnection(this.config.socketPath, () => {
|
||||
resolve({ socket });
|
||||
});
|
||||
socket.on("error", (error) => {
|
||||
if (import_os.default.platform() !== "win32")
|
||||
void import_fs.default.promises.unlink(this.config.socketPath).catch(() => {
|
||||
}).then(() => resolve({ error }));
|
||||
else
|
||||
resolve({ error });
|
||||
});
|
||||
});
|
||||
}
|
||||
async canConnect() {
|
||||
const { socket } = await this._connect();
|
||||
if (socket) {
|
||||
socket.destroy();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static async startDaemon(clientInfo, cliArgs) {
|
||||
await import_fs.default.promises.mkdir(clientInfo.daemonProfilesDir, { recursive: true });
|
||||
const cliPath = require.resolve("../cli-daemon/program.js");
|
||||
const sessionName = (0, import_registry.resolveSessionName)(cliArgs.session);
|
||||
const errLog = import_path.default.join(clientInfo.daemonProfilesDir, sessionName + ".err");
|
||||
const err = import_fs.default.openSync(errLog, "w");
|
||||
const args = [
|
||||
cliPath,
|
||||
sessionName
|
||||
];
|
||||
if (cliArgs.headed)
|
||||
args.push("--headed");
|
||||
if (cliArgs.extension)
|
||||
args.push("--extension");
|
||||
if (cliArgs.browser)
|
||||
args.push(`--browser=${cliArgs.browser}`);
|
||||
if (cliArgs.persistent)
|
||||
args.push("--persistent");
|
||||
if (cliArgs.profile)
|
||||
args.push(`--profile=${cliArgs.profile}`);
|
||||
if (cliArgs.config)
|
||||
args.push(`--config=${cliArgs.config}`);
|
||||
if (cliArgs.endpoint || process.env.PLAYWRIGHT_CLI_SESSION)
|
||||
args.push(`--endpoint=${cliArgs.endpoint || process.env.PLAYWRIGHT_CLI_SESSION}`);
|
||||
const child = (0, import_child_process.spawn)(process.execPath, args, {
|
||||
detached: true,
|
||||
stdio: ["ignore", "pipe", err],
|
||||
cwd: process.cwd()
|
||||
// Will be used as root.
|
||||
});
|
||||
let signalled = false;
|
||||
const sigintHandler = () => {
|
||||
signalled = true;
|
||||
child.kill("SIGINT");
|
||||
};
|
||||
const sigtermHandler = () => {
|
||||
signalled = true;
|
||||
child.kill("SIGTERM");
|
||||
};
|
||||
process.on("SIGINT", sigintHandler);
|
||||
process.on("SIGTERM", sigtermHandler);
|
||||
let outLog = "";
|
||||
await new Promise((resolve, reject) => {
|
||||
child.stdout.on("data", (data) => {
|
||||
outLog += data.toString();
|
||||
if (!outLog.includes("<EOF>"))
|
||||
return;
|
||||
const errorMatch = outLog.match(/### Error\n([\s\S]*)<EOF>/);
|
||||
const error = errorMatch ? errorMatch[1].trim() : void 0;
|
||||
if (error) {
|
||||
const errLogContent = import_fs.default.readFileSync(errLog, "utf-8");
|
||||
const message = error + (errLogContent ? "\n" + errLogContent : "");
|
||||
reject(new Error(message));
|
||||
}
|
||||
const successMatch = outLog.match(/### Success\nDaemon listening on (.*)\n<EOF>/);
|
||||
if (successMatch)
|
||||
resolve();
|
||||
});
|
||||
child.on("close", (code) => {
|
||||
if (!signalled) {
|
||||
const errLogContent = import_fs.default.readFileSync(errLog, "utf-8");
|
||||
const message = `Daemon process exited with code ${code}` + (errLogContent ? "\n" + errLogContent : "");
|
||||
reject(new Error(message));
|
||||
}
|
||||
});
|
||||
});
|
||||
process.off("SIGINT", sigintHandler);
|
||||
process.off("SIGTERM", sigtermHandler);
|
||||
child.stdout.destroy();
|
||||
child.unref();
|
||||
if (cliArgs["endpoint"]) {
|
||||
console.log(`### Session \`${sessionName}\` created, attached to \`${cliArgs["endpoint"]}\`.`);
|
||||
console.log(`Run commands with: playwright-cli --session=${sessionName} <command>`);
|
||||
} else {
|
||||
console.log(`### Browser \`${sessionName}\` opened with pid ${child.pid}.`);
|
||||
}
|
||||
}
|
||||
async _stopDaemon() {
|
||||
const { socket, error: socketError } = await this._connect();
|
||||
if (!socket) {
|
||||
console.log(`Browser '${this.name}' is not open.${socketError ? " Error: " + socketError.message : ""}`);
|
||||
return;
|
||||
}
|
||||
let error;
|
||||
await SocketConnectionClient.sendAndClose(socket, "stop", {}).catch((e) => error = e);
|
||||
if (error && !error?.message?.includes("Session closed"))
|
||||
throw error;
|
||||
}
|
||||
async deleteSessionConfig() {
|
||||
await import_fs.default.promises.rm(this._sessionFile.file).catch(() => {
|
||||
});
|
||||
}
|
||||
}
|
||||
function renderResolvedConfig(config) {
|
||||
const channel = config.browser.launchOptions.channel ?? config.browser.browserName;
|
||||
const lines = [];
|
||||
if (channel)
|
||||
lines.push(` - browser-type: ${channel}`);
|
||||
if (!config.cli.persistent)
|
||||
lines.push(` - user-data-dir: <in-memory>`);
|
||||
else
|
||||
lines.push(` - user-data-dir: ${config.browser.userDataDir}`);
|
||||
lines.push(` - headed: ${!config.browser.launchOptions.headless}`);
|
||||
return lines;
|
||||
}
|
||||
class SocketConnectionClient {
|
||||
constructor(socket) {
|
||||
this._nextMessageId = 1;
|
||||
this._callbacks = /* @__PURE__ */ new Map();
|
||||
this._connection = new import_socketConnection.SocketConnection(socket);
|
||||
this._connection.onmessage = (message) => this._onMessage(message);
|
||||
this._connection.onclose = () => this._rejectCallbacks();
|
||||
}
|
||||
async send(method, params = {}) {
|
||||
const messageId = this._nextMessageId++;
|
||||
const message = {
|
||||
id: messageId,
|
||||
method,
|
||||
params
|
||||
};
|
||||
const responsePromise = new Promise((resolve, reject) => {
|
||||
this._callbacks.set(messageId, { resolve, reject, method, params });
|
||||
});
|
||||
const [result] = await Promise.all([responsePromise, this._connection.send(message)]);
|
||||
return result;
|
||||
}
|
||||
static async sendAndClose(socket, method, params = {}) {
|
||||
const connection = new SocketConnectionClient(socket);
|
||||
try {
|
||||
return await connection.send(method, params);
|
||||
} finally {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
close() {
|
||||
this._connection.close();
|
||||
}
|
||||
_onMessage(object) {
|
||||
if (object.id && this._callbacks.has(object.id)) {
|
||||
const callback = this._callbacks.get(object.id);
|
||||
this._callbacks.delete(object.id);
|
||||
if (object.error)
|
||||
callback.reject(new Error(object.error));
|
||||
else
|
||||
callback.resolve(object.result);
|
||||
} else if (object.id) {
|
||||
throw new Error(`Unexpected message id: ${object.id}`);
|
||||
} else {
|
||||
throw new Error(`Unexpected message without id: ${JSON.stringify(object)}`);
|
||||
}
|
||||
}
|
||||
_rejectCallbacks() {
|
||||
for (const callback of this._callbacks.values())
|
||||
callback.reject(new Error("Session closed"));
|
||||
this._callbacks.clear();
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
Session,
|
||||
renderResolvedConfig
|
||||
});
|
||||
328
node_modules/playwright-core/lib/tools/cli-client/skill/SKILL.md
generated
vendored
Normal file
328
node_modules/playwright-core/lib/tools/cli-client/skill/SKILL.md
generated
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
---
|
||||
name: playwright-cli
|
||||
description: Automate browser interactions, test web pages and work with Playwright tests.
|
||||
allowed-tools: Bash(playwright-cli:*) Bash(npx:*) Bash(npm:*)
|
||||
---
|
||||
|
||||
# Browser Automation with playwright-cli
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
# open new browser
|
||||
playwright-cli open
|
||||
# navigate to a page
|
||||
playwright-cli goto https://playwright.dev
|
||||
# interact with the page using refs from the snapshot
|
||||
playwright-cli click e15
|
||||
playwright-cli type "page.click"
|
||||
playwright-cli press Enter
|
||||
# take a screenshot (rarely used, as snapshot is more common)
|
||||
playwright-cli screenshot
|
||||
# close the browser
|
||||
playwright-cli close
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### Core
|
||||
|
||||
```bash
|
||||
playwright-cli open
|
||||
# open and navigate right away
|
||||
playwright-cli open https://example.com/
|
||||
playwright-cli goto https://playwright.dev
|
||||
playwright-cli type "search query"
|
||||
playwright-cli click e3
|
||||
playwright-cli dblclick e7
|
||||
# --submit presses Enter after filling the element
|
||||
playwright-cli fill e5 "user@example.com" --submit
|
||||
playwright-cli drag e2 e8
|
||||
playwright-cli hover e4
|
||||
playwright-cli select e9 "option-value"
|
||||
playwright-cli upload ./document.pdf
|
||||
playwright-cli check e12
|
||||
playwright-cli uncheck e12
|
||||
playwright-cli snapshot
|
||||
playwright-cli eval "document.title"
|
||||
playwright-cli eval "el => el.textContent" e5
|
||||
# get element id, class, or any attribute not visible in the snapshot
|
||||
playwright-cli eval "el => el.id" e5
|
||||
playwright-cli eval "el => el.getAttribute('data-testid')" e5
|
||||
playwright-cli dialog-accept
|
||||
playwright-cli dialog-accept "confirmation text"
|
||||
playwright-cli dialog-dismiss
|
||||
playwright-cli resize 1920 1080
|
||||
playwright-cli close
|
||||
```
|
||||
|
||||
### Navigation
|
||||
|
||||
```bash
|
||||
playwright-cli go-back
|
||||
playwright-cli go-forward
|
||||
playwright-cli reload
|
||||
```
|
||||
|
||||
### Keyboard
|
||||
|
||||
```bash
|
||||
playwright-cli press Enter
|
||||
playwright-cli press ArrowDown
|
||||
playwright-cli keydown Shift
|
||||
playwright-cli keyup Shift
|
||||
```
|
||||
|
||||
### Mouse
|
||||
|
||||
```bash
|
||||
playwright-cli mousemove 150 300
|
||||
playwright-cli mousedown
|
||||
playwright-cli mousedown right
|
||||
playwright-cli mouseup
|
||||
playwright-cli mouseup right
|
||||
playwright-cli mousewheel 0 100
|
||||
```
|
||||
|
||||
### Save as
|
||||
|
||||
```bash
|
||||
playwright-cli screenshot
|
||||
playwright-cli screenshot e5
|
||||
playwright-cli screenshot --filename=page.png
|
||||
playwright-cli pdf --filename=page.pdf
|
||||
```
|
||||
|
||||
### Tabs
|
||||
|
||||
```bash
|
||||
playwright-cli tab-list
|
||||
playwright-cli tab-new
|
||||
playwright-cli tab-new https://example.com/page
|
||||
playwright-cli tab-close
|
||||
playwright-cli tab-close 2
|
||||
playwright-cli tab-select 0
|
||||
```
|
||||
|
||||
### Storage
|
||||
|
||||
```bash
|
||||
playwright-cli state-save
|
||||
playwright-cli state-save auth.json
|
||||
playwright-cli state-load auth.json
|
||||
|
||||
# Cookies
|
||||
playwright-cli cookie-list
|
||||
playwright-cli cookie-list --domain=example.com
|
||||
playwright-cli cookie-get session_id
|
||||
playwright-cli cookie-set session_id abc123
|
||||
playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
|
||||
playwright-cli cookie-delete session_id
|
||||
playwright-cli cookie-clear
|
||||
|
||||
# LocalStorage
|
||||
playwright-cli localstorage-list
|
||||
playwright-cli localstorage-get theme
|
||||
playwright-cli localstorage-set theme dark
|
||||
playwright-cli localstorage-delete theme
|
||||
playwright-cli localstorage-clear
|
||||
|
||||
# SessionStorage
|
||||
playwright-cli sessionstorage-list
|
||||
playwright-cli sessionstorage-get step
|
||||
playwright-cli sessionstorage-set step 3
|
||||
playwright-cli sessionstorage-delete step
|
||||
playwright-cli sessionstorage-clear
|
||||
```
|
||||
|
||||
### Network
|
||||
|
||||
```bash
|
||||
playwright-cli route "**/*.jpg" --status=404
|
||||
playwright-cli route "https://api.example.com/**" --body='{"mock": true}'
|
||||
playwright-cli route-list
|
||||
playwright-cli unroute "**/*.jpg"
|
||||
playwright-cli unroute
|
||||
```
|
||||
|
||||
### DevTools
|
||||
|
||||
```bash
|
||||
playwright-cli console
|
||||
playwright-cli console warning
|
||||
playwright-cli network
|
||||
playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])"
|
||||
playwright-cli run-code --filename=script.js
|
||||
playwright-cli tracing-start
|
||||
playwright-cli tracing-stop
|
||||
playwright-cli video-start video.webm
|
||||
playwright-cli video-chapter "Chapter Title" --description="Details" --duration=2000
|
||||
playwright-cli video-stop
|
||||
```
|
||||
|
||||
## Open parameters
|
||||
```bash
|
||||
# Use specific browser when creating session
|
||||
playwright-cli open --browser=chrome
|
||||
playwright-cli open --browser=firefox
|
||||
playwright-cli open --browser=webkit
|
||||
playwright-cli open --browser=msedge
|
||||
# Connect to browser via extension
|
||||
playwright-cli open --extension
|
||||
|
||||
# Use persistent profile (by default profile is in-memory)
|
||||
playwright-cli open --persistent
|
||||
# Use persistent profile with custom directory
|
||||
playwright-cli open --profile=/path/to/profile
|
||||
|
||||
# Start with config file
|
||||
playwright-cli open --config=my-config.json
|
||||
|
||||
# Close the browser
|
||||
playwright-cli close
|
||||
# Delete user data for the default session
|
||||
playwright-cli delete-data
|
||||
```
|
||||
|
||||
## Snapshots
|
||||
|
||||
After each command, playwright-cli provides a snapshot of the current browser state.
|
||||
|
||||
```bash
|
||||
> playwright-cli goto https://example.com
|
||||
### Page
|
||||
- Page URL: https://example.com/
|
||||
- Page Title: Example Domain
|
||||
### Snapshot
|
||||
[Snapshot](.playwright-cli/page-2026-02-14T19-22-42-679Z.yml)
|
||||
```
|
||||
|
||||
You can also take a snapshot on demand using `playwright-cli snapshot` command. All the options below can be combined as needed.
|
||||
|
||||
```bash
|
||||
# default - save to a file with timestamp-based name
|
||||
playwright-cli snapshot
|
||||
|
||||
# save to file, use when snapshot is a part of the workflow result
|
||||
playwright-cli snapshot --filename=after-click.yaml
|
||||
|
||||
# snapshot an element instead of the whole page
|
||||
playwright-cli snapshot "#main"
|
||||
|
||||
# limit snapshot depth for efficiency, take a partial snapshot afterwards
|
||||
playwright-cli snapshot --depth=4
|
||||
playwright-cli snapshot e34
|
||||
```
|
||||
|
||||
## Targeting elements
|
||||
|
||||
By default, use refs from the snapshot to interact with page elements.
|
||||
|
||||
```bash
|
||||
# get snapshot with refs
|
||||
playwright-cli snapshot
|
||||
|
||||
# interact using a ref
|
||||
playwright-cli click e15
|
||||
```
|
||||
|
||||
You can also use css selectors or Playwright locators.
|
||||
|
||||
```bash
|
||||
# css selector
|
||||
playwright-cli click "#main > button.submit"
|
||||
|
||||
# role locator
|
||||
playwright-cli click "getByRole('button', { name: 'Submit' })"
|
||||
|
||||
# test id
|
||||
playwright-cli click "getByTestId('submit-button')"
|
||||
```
|
||||
|
||||
## Browser Sessions
|
||||
|
||||
```bash
|
||||
# create new browser session named "mysession" with persistent profile
|
||||
playwright-cli -s=mysession open example.com --persistent
|
||||
# same with manually specified profile directory (use when requested explicitly)
|
||||
playwright-cli -s=mysession open example.com --profile=/path/to/profile
|
||||
playwright-cli -s=mysession click e6
|
||||
playwright-cli -s=mysession close # stop a named browser
|
||||
playwright-cli -s=mysession delete-data # delete user data for persistent session
|
||||
|
||||
playwright-cli list
|
||||
# Close all browsers
|
||||
playwright-cli close-all
|
||||
# Forcefully kill all browser processes
|
||||
playwright-cli kill-all
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
If global `playwright-cli` command is not available, try a local version via `npx playwright-cli`:
|
||||
|
||||
```bash
|
||||
npx --no-install playwright-cli --version
|
||||
```
|
||||
|
||||
When local version is available, use `npx playwright-cli` in all commands. Otherwise, install `playwright-cli` as a global command:
|
||||
|
||||
```bash
|
||||
npm install -g @playwright/cli@latest
|
||||
```
|
||||
|
||||
## Example: Form submission
|
||||
|
||||
```bash
|
||||
playwright-cli open https://example.com/form
|
||||
playwright-cli snapshot
|
||||
|
||||
playwright-cli fill e1 "user@example.com"
|
||||
playwright-cli fill e2 "password123"
|
||||
playwright-cli click e3
|
||||
playwright-cli snapshot
|
||||
playwright-cli close
|
||||
```
|
||||
|
||||
## Example: Multi-tab workflow
|
||||
|
||||
```bash
|
||||
playwright-cli open https://example.com
|
||||
playwright-cli tab-new https://example.com/other
|
||||
playwright-cli tab-list
|
||||
playwright-cli tab-select 0
|
||||
playwright-cli snapshot
|
||||
playwright-cli close
|
||||
```
|
||||
|
||||
## Example: Debugging with DevTools
|
||||
|
||||
```bash
|
||||
playwright-cli open https://example.com
|
||||
playwright-cli click e4
|
||||
playwright-cli fill e7 "test"
|
||||
playwright-cli console
|
||||
playwright-cli network
|
||||
playwright-cli close
|
||||
```
|
||||
|
||||
```bash
|
||||
playwright-cli open https://example.com
|
||||
playwright-cli tracing-start
|
||||
playwright-cli click e4
|
||||
playwright-cli fill e7 "test"
|
||||
playwright-cli tracing-stop
|
||||
playwright-cli close
|
||||
```
|
||||
|
||||
## Specific tasks
|
||||
|
||||
* **Running and Debugging Playwright tests** [references/playwright-tests.md](references/playwright-tests.md)
|
||||
* **Request mocking** [references/request-mocking.md](references/request-mocking.md)
|
||||
* **Running Playwright code** [references/running-code.md](references/running-code.md)
|
||||
* **Browser session management** [references/session-management.md](references/session-management.md)
|
||||
* **Storage state (cookies, localStorage)** [references/storage-state.md](references/storage-state.md)
|
||||
* **Test generation** [references/test-generation.md](references/test-generation.md)
|
||||
* **Tracing** [references/tracing.md](references/tracing.md)
|
||||
* **Video recording** [references/video-recording.md](references/video-recording.md)
|
||||
* **Inspecting element attributes** [references/element-attributes.md](references/element-attributes.md)
|
||||
23
node_modules/playwright-core/lib/tools/cli-client/skill/references/element-attributes.md
generated
vendored
Normal file
23
node_modules/playwright-core/lib/tools/cli-client/skill/references/element-attributes.md
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# Inspecting Element Attributes
|
||||
|
||||
When the snapshot doesn't show an element's `id`, `class`, `data-*` attributes, or other DOM properties, use `eval` to inspect them.
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
playwright-cli snapshot
|
||||
# snapshot shows a button as e7 but doesn't reveal its id or data attributes
|
||||
|
||||
# get the element's id
|
||||
playwright-cli eval "el => el.id" e7
|
||||
|
||||
# get all CSS classes
|
||||
playwright-cli eval "el => el.className" e7
|
||||
|
||||
# get a specific attribute
|
||||
playwright-cli eval "el => el.getAttribute('data-testid')" e7
|
||||
playwright-cli eval "el => el.getAttribute('aria-label')" e7
|
||||
|
||||
# get a computed style property
|
||||
playwright-cli eval "el => getComputedStyle(el).display" e7
|
||||
```
|
||||
39
node_modules/playwright-core/lib/tools/cli-client/skill/references/playwright-tests.md
generated
vendored
Normal file
39
node_modules/playwright-core/lib/tools/cli-client/skill/references/playwright-tests.md
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Running Playwright Tests
|
||||
|
||||
To run Playwright tests, use the `npx playwright test` command, or a package manager script. To avoid opening the interactive html report, use `PLAYWRIGHT_HTML_OPEN=never` environment variable.
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
PLAYWRIGHT_HTML_OPEN=never npx playwright test
|
||||
|
||||
# Run all tests through a custom npm script
|
||||
PLAYWRIGHT_HTML_OPEN=never npm run special-test-command
|
||||
```
|
||||
|
||||
# Debugging Playwright Tests
|
||||
|
||||
To debug a failing Playwright test, run it with `--debug=cli` option. This command will pause the test at the start and print the debugging instructions.
|
||||
|
||||
**IMPORTANT**: run the command in the background and check the output until "Debugging Instructions" is printed.
|
||||
|
||||
Once instructions containing a session name are printed, use `playwright-cli` to attach the session and explore the page.
|
||||
|
||||
```bash
|
||||
# Run the test
|
||||
PLAYWRIGHT_HTML_OPEN=never npx playwright test --debug=cli
|
||||
# ...
|
||||
# ... debugging instructions for "tw-abcdef" session ...
|
||||
# ...
|
||||
|
||||
# Attach to the test
|
||||
playwright-cli attach tw-abcdef
|
||||
```
|
||||
|
||||
Keep the test running in the background while you explore and look for a fix.
|
||||
The test is paused at the start, so you should step over or pause at a particular location
|
||||
where the problem is most likely to be.
|
||||
|
||||
Every action you perform with `playwright-cli` generates corresponding Playwright TypeScript code.
|
||||
This code appears in the output and can be copied directly into the test. Most of the time, a specific locator or an expectation should be updated, but it could also be a bug in the app. Use your judgement.
|
||||
|
||||
After fixing the test, stop the background test run. Rerun to check that test passes.
|
||||
87
node_modules/playwright-core/lib/tools/cli-client/skill/references/request-mocking.md
generated
vendored
Normal file
87
node_modules/playwright-core/lib/tools/cli-client/skill/references/request-mocking.md
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
# Request Mocking
|
||||
|
||||
Intercept, mock, modify, and block network requests.
|
||||
|
||||
## CLI Route Commands
|
||||
|
||||
```bash
|
||||
# Mock with custom status
|
||||
playwright-cli route "**/*.jpg" --status=404
|
||||
|
||||
# Mock with JSON body
|
||||
playwright-cli route "**/api/users" --body='[{"id":1,"name":"Alice"}]' --content-type=application/json
|
||||
|
||||
# Mock with custom headers
|
||||
playwright-cli route "**/api/data" --body='{"ok":true}' --header="X-Custom: value"
|
||||
|
||||
# Remove headers from requests
|
||||
playwright-cli route "**/*" --remove-header=cookie,authorization
|
||||
|
||||
# List active routes
|
||||
playwright-cli route-list
|
||||
|
||||
# Remove a route or all routes
|
||||
playwright-cli unroute "**/*.jpg"
|
||||
playwright-cli unroute
|
||||
```
|
||||
|
||||
## URL Patterns
|
||||
|
||||
```
|
||||
**/api/users - Exact path match
|
||||
**/api/*/details - Wildcard in path
|
||||
**/*.{png,jpg,jpeg} - Match file extensions
|
||||
**/search?q=* - Match query parameters
|
||||
```
|
||||
|
||||
## Advanced Mocking with run-code
|
||||
|
||||
For conditional responses, request body inspection, response modification, or delays:
|
||||
|
||||
### Conditional Response Based on Request
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
await page.route('**/api/login', route => {
|
||||
const body = route.request().postDataJSON();
|
||||
if (body.username === 'admin') {
|
||||
route.fulfill({ body: JSON.stringify({ token: 'mock-token' }) });
|
||||
} else {
|
||||
route.fulfill({ status: 401, body: JSON.stringify({ error: 'Invalid' }) });
|
||||
}
|
||||
});
|
||||
}"
|
||||
```
|
||||
|
||||
### Modify Real Response
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
await page.route('**/api/user', async route => {
|
||||
const response = await route.fetch();
|
||||
const json = await response.json();
|
||||
json.isPremium = true;
|
||||
await route.fulfill({ response, json });
|
||||
});
|
||||
}"
|
||||
```
|
||||
|
||||
### Simulate Network Failures
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
await page.route('**/api/offline', route => route.abort('internetdisconnected'));
|
||||
}"
|
||||
# Options: connectionrefused, timedout, connectionreset, internetdisconnected
|
||||
```
|
||||
|
||||
### Delayed Response
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
await page.route('**/api/slow', async route => {
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
route.fulfill({ body: JSON.stringify({ data: 'loaded' }) });
|
||||
});
|
||||
}"
|
||||
```
|
||||
231
node_modules/playwright-core/lib/tools/cli-client/skill/references/running-code.md
generated
vendored
Normal file
231
node_modules/playwright-core/lib/tools/cli-client/skill/references/running-code.md
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
# Running Custom Playwright Code
|
||||
|
||||
Use `run-code` to execute arbitrary Playwright code for advanced scenarios not covered by CLI commands.
|
||||
|
||||
## Syntax
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
// Your Playwright code here
|
||||
// Access page.context() for browser context operations
|
||||
}"
|
||||
```
|
||||
|
||||
## Geolocation
|
||||
|
||||
```bash
|
||||
# Grant geolocation permission and set location
|
||||
playwright-cli run-code "async page => {
|
||||
await page.context().grantPermissions(['geolocation']);
|
||||
await page.context().setGeolocation({ latitude: 37.7749, longitude: -122.4194 });
|
||||
}"
|
||||
|
||||
# Set location to London
|
||||
playwright-cli run-code "async page => {
|
||||
await page.context().grantPermissions(['geolocation']);
|
||||
await page.context().setGeolocation({ latitude: 51.5074, longitude: -0.1278 });
|
||||
}"
|
||||
|
||||
# Clear geolocation override
|
||||
playwright-cli run-code "async page => {
|
||||
await page.context().clearPermissions();
|
||||
}"
|
||||
```
|
||||
|
||||
## Permissions
|
||||
|
||||
```bash
|
||||
# Grant multiple permissions
|
||||
playwright-cli run-code "async page => {
|
||||
await page.context().grantPermissions([
|
||||
'geolocation',
|
||||
'notifications',
|
||||
'camera',
|
||||
'microphone'
|
||||
]);
|
||||
}"
|
||||
|
||||
# Grant permissions for specific origin
|
||||
playwright-cli run-code "async page => {
|
||||
await page.context().grantPermissions(['clipboard-read'], {
|
||||
origin: 'https://example.com'
|
||||
});
|
||||
}"
|
||||
```
|
||||
|
||||
## Media Emulation
|
||||
|
||||
```bash
|
||||
# Emulate dark color scheme
|
||||
playwright-cli run-code "async page => {
|
||||
await page.emulateMedia({ colorScheme: 'dark' });
|
||||
}"
|
||||
|
||||
# Emulate light color scheme
|
||||
playwright-cli run-code "async page => {
|
||||
await page.emulateMedia({ colorScheme: 'light' });
|
||||
}"
|
||||
|
||||
# Emulate reduced motion
|
||||
playwright-cli run-code "async page => {
|
||||
await page.emulateMedia({ reducedMotion: 'reduce' });
|
||||
}"
|
||||
|
||||
# Emulate print media
|
||||
playwright-cli run-code "async page => {
|
||||
await page.emulateMedia({ media: 'print' });
|
||||
}"
|
||||
```
|
||||
|
||||
## Wait Strategies
|
||||
|
||||
```bash
|
||||
# Wait for network idle
|
||||
playwright-cli run-code "async page => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
}"
|
||||
|
||||
# Wait for specific element
|
||||
playwright-cli run-code "async page => {
|
||||
await page.locator('.loading').waitFor({ state: 'hidden' });
|
||||
}"
|
||||
|
||||
# Wait for function to return true
|
||||
playwright-cli run-code "async page => {
|
||||
await page.waitForFunction(() => window.appReady === true);
|
||||
}"
|
||||
|
||||
# Wait with timeout
|
||||
playwright-cli run-code "async page => {
|
||||
await page.locator('.result').waitFor({ timeout: 10000 });
|
||||
}"
|
||||
```
|
||||
|
||||
## Frames and Iframes
|
||||
|
||||
```bash
|
||||
# Work with iframe
|
||||
playwright-cli run-code "async page => {
|
||||
const frame = page.locator('iframe#my-iframe').contentFrame();
|
||||
await frame.locator('button').click();
|
||||
}"
|
||||
|
||||
# Get all frames
|
||||
playwright-cli run-code "async page => {
|
||||
const frames = page.frames();
|
||||
return frames.map(f => f.url());
|
||||
}"
|
||||
```
|
||||
|
||||
## File Downloads
|
||||
|
||||
```bash
|
||||
# Handle file download
|
||||
playwright-cli run-code "async page => {
|
||||
const downloadPromise = page.waitForEvent('download');
|
||||
await page.getByRole('link', { name: 'Download' }).click();
|
||||
const download = await downloadPromise;
|
||||
await download.saveAs('./downloaded-file.pdf');
|
||||
return download.suggestedFilename();
|
||||
}"
|
||||
```
|
||||
|
||||
## Clipboard
|
||||
|
||||
```bash
|
||||
# Read clipboard (requires permission)
|
||||
playwright-cli run-code "async page => {
|
||||
await page.context().grantPermissions(['clipboard-read']);
|
||||
return await page.evaluate(() => navigator.clipboard.readText());
|
||||
}"
|
||||
|
||||
# Write to clipboard
|
||||
playwright-cli run-code "async page => {
|
||||
await page.evaluate(text => navigator.clipboard.writeText(text), 'Hello clipboard!');
|
||||
}"
|
||||
```
|
||||
|
||||
## Page Information
|
||||
|
||||
```bash
|
||||
# Get page title
|
||||
playwright-cli run-code "async page => {
|
||||
return await page.title();
|
||||
}"
|
||||
|
||||
# Get current URL
|
||||
playwright-cli run-code "async page => {
|
||||
return page.url();
|
||||
}"
|
||||
|
||||
# Get page content
|
||||
playwright-cli run-code "async page => {
|
||||
return await page.content();
|
||||
}"
|
||||
|
||||
# Get viewport size
|
||||
playwright-cli run-code "async page => {
|
||||
return page.viewportSize();
|
||||
}"
|
||||
```
|
||||
|
||||
## JavaScript Execution
|
||||
|
||||
```bash
|
||||
# Execute JavaScript and return result
|
||||
playwright-cli run-code "async page => {
|
||||
return await page.evaluate(() => {
|
||||
return {
|
||||
userAgent: navigator.userAgent,
|
||||
language: navigator.language,
|
||||
cookiesEnabled: navigator.cookieEnabled
|
||||
};
|
||||
});
|
||||
}"
|
||||
|
||||
# Pass arguments to evaluate
|
||||
playwright-cli run-code "async page => {
|
||||
const multiplier = 5;
|
||||
return await page.evaluate(m => document.querySelectorAll('li').length * m, multiplier);
|
||||
}"
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```bash
|
||||
# Try-catch in run-code
|
||||
playwright-cli run-code "async page => {
|
||||
try {
|
||||
await page.getByRole('button', { name: 'Submit' }).click({ timeout: 1000 });
|
||||
return 'clicked';
|
||||
} catch (e) {
|
||||
return 'element not found';
|
||||
}
|
||||
}"
|
||||
```
|
||||
|
||||
## Complex Workflows
|
||||
|
||||
```bash
|
||||
# Login and save state
|
||||
playwright-cli run-code "async page => {
|
||||
await page.goto('https://example.com/login');
|
||||
await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
|
||||
await page.getByRole('textbox', { name: 'Password' }).fill('secret');
|
||||
await page.getByRole('button', { name: 'Sign in' }).click();
|
||||
await page.waitForURL('**/dashboard');
|
||||
await page.context().storageState({ path: 'auth.json' });
|
||||
return 'Login successful';
|
||||
}"
|
||||
|
||||
# Scrape data from multiple pages
|
||||
playwright-cli run-code "async page => {
|
||||
const results = [];
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
await page.goto(\`https://example.com/page/\${i}\`);
|
||||
const items = await page.locator('.item').allTextContents();
|
||||
results.push(...items);
|
||||
}
|
||||
return results;
|
||||
}"
|
||||
```
|
||||
169
node_modules/playwright-core/lib/tools/cli-client/skill/references/session-management.md
generated
vendored
Normal file
169
node_modules/playwright-core/lib/tools/cli-client/skill/references/session-management.md
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
# Browser Session Management
|
||||
|
||||
Run multiple isolated browser sessions concurrently with state persistence.
|
||||
|
||||
## Named Browser Sessions
|
||||
|
||||
Use `-s` flag to isolate browser contexts:
|
||||
|
||||
```bash
|
||||
# Browser 1: Authentication flow
|
||||
playwright-cli -s=auth open https://app.example.com/login
|
||||
|
||||
# Browser 2: Public browsing (separate cookies, storage)
|
||||
playwright-cli -s=public open https://example.com
|
||||
|
||||
# Commands are isolated by browser session
|
||||
playwright-cli -s=auth fill e1 "user@example.com"
|
||||
playwright-cli -s=public snapshot
|
||||
```
|
||||
|
||||
## Browser Session Isolation Properties
|
||||
|
||||
Each browser session has independent:
|
||||
- Cookies
|
||||
- LocalStorage / SessionStorage
|
||||
- IndexedDB
|
||||
- Cache
|
||||
- Browsing history
|
||||
- Open tabs
|
||||
|
||||
## Browser Session Commands
|
||||
|
||||
```bash
|
||||
# List all browser sessions
|
||||
playwright-cli list
|
||||
|
||||
# Stop a browser session (close the browser)
|
||||
playwright-cli close # stop the default browser
|
||||
playwright-cli -s=mysession close # stop a named browser
|
||||
|
||||
# Stop all browser sessions
|
||||
playwright-cli close-all
|
||||
|
||||
# Forcefully kill all daemon processes (for stale/zombie processes)
|
||||
playwright-cli kill-all
|
||||
|
||||
# Delete browser session user data (profile directory)
|
||||
playwright-cli delete-data # delete default browser data
|
||||
playwright-cli -s=mysession delete-data # delete named browser data
|
||||
```
|
||||
|
||||
## Environment Variable
|
||||
|
||||
Set a default browser session name via environment variable:
|
||||
|
||||
```bash
|
||||
export PLAYWRIGHT_CLI_SESSION="mysession"
|
||||
playwright-cli open example.com # Uses "mysession" automatically
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Concurrent Scraping
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Scrape multiple sites concurrently
|
||||
|
||||
# Start all browsers
|
||||
playwright-cli -s=site1 open https://site1.com &
|
||||
playwright-cli -s=site2 open https://site2.com &
|
||||
playwright-cli -s=site3 open https://site3.com &
|
||||
wait
|
||||
|
||||
# Take snapshots from each
|
||||
playwright-cli -s=site1 snapshot
|
||||
playwright-cli -s=site2 snapshot
|
||||
playwright-cli -s=site3 snapshot
|
||||
|
||||
# Cleanup
|
||||
playwright-cli close-all
|
||||
```
|
||||
|
||||
### A/B Testing Sessions
|
||||
|
||||
```bash
|
||||
# Test different user experiences
|
||||
playwright-cli -s=variant-a open "https://app.com?variant=a"
|
||||
playwright-cli -s=variant-b open "https://app.com?variant=b"
|
||||
|
||||
# Compare
|
||||
playwright-cli -s=variant-a screenshot
|
||||
playwright-cli -s=variant-b screenshot
|
||||
```
|
||||
|
||||
### Persistent Profile
|
||||
|
||||
By default, browser profile is kept in memory only. Use `--persistent` flag on `open` to persist the browser profile to disk:
|
||||
|
||||
```bash
|
||||
# Use persistent profile (auto-generated location)
|
||||
playwright-cli open https://example.com --persistent
|
||||
|
||||
# Use persistent profile with custom directory
|
||||
playwright-cli open https://example.com --profile=/path/to/profile
|
||||
```
|
||||
|
||||
## Default Browser Session
|
||||
|
||||
When `-s` is omitted, commands use the default browser session:
|
||||
|
||||
```bash
|
||||
# These use the same default browser session
|
||||
playwright-cli open https://example.com
|
||||
playwright-cli snapshot
|
||||
playwright-cli close # Stops default browser
|
||||
```
|
||||
|
||||
## Browser Session Configuration
|
||||
|
||||
Configure a browser session with specific settings when opening:
|
||||
|
||||
```bash
|
||||
# Open with config file
|
||||
playwright-cli open https://example.com --config=.playwright/my-cli.json
|
||||
|
||||
# Open with specific browser
|
||||
playwright-cli open https://example.com --browser=firefox
|
||||
|
||||
# Open in headed mode
|
||||
playwright-cli open https://example.com --headed
|
||||
|
||||
# Open with persistent profile
|
||||
playwright-cli open https://example.com --persistent
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Name Browser Sessions Semantically
|
||||
|
||||
```bash
|
||||
# GOOD: Clear purpose
|
||||
playwright-cli -s=github-auth open https://github.com
|
||||
playwright-cli -s=docs-scrape open https://docs.example.com
|
||||
|
||||
# AVOID: Generic names
|
||||
playwright-cli -s=s1 open https://github.com
|
||||
```
|
||||
|
||||
### 2. Always Clean Up
|
||||
|
||||
```bash
|
||||
# Stop browsers when done
|
||||
playwright-cli -s=auth close
|
||||
playwright-cli -s=scrape close
|
||||
|
||||
# Or stop all at once
|
||||
playwright-cli close-all
|
||||
|
||||
# If browsers become unresponsive or zombie processes remain
|
||||
playwright-cli kill-all
|
||||
```
|
||||
|
||||
### 3. Delete Stale Browser Data
|
||||
|
||||
```bash
|
||||
# Remove old browser data to free disk space
|
||||
playwright-cli -s=oldsession delete-data
|
||||
```
|
||||
275
node_modules/playwright-core/lib/tools/cli-client/skill/references/storage-state.md
generated
vendored
Normal file
275
node_modules/playwright-core/lib/tools/cli-client/skill/references/storage-state.md
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
# Storage Management
|
||||
|
||||
Manage cookies, localStorage, sessionStorage, and browser storage state.
|
||||
|
||||
## Storage State
|
||||
|
||||
Save and restore complete browser state including cookies and storage.
|
||||
|
||||
### Save Storage State
|
||||
|
||||
```bash
|
||||
# Save to auto-generated filename (storage-state-{timestamp}.json)
|
||||
playwright-cli state-save
|
||||
|
||||
# Save to specific filename
|
||||
playwright-cli state-save my-auth-state.json
|
||||
```
|
||||
|
||||
### Restore Storage State
|
||||
|
||||
```bash
|
||||
# Load storage state from file
|
||||
playwright-cli state-load my-auth-state.json
|
||||
|
||||
# Reload page to apply cookies
|
||||
playwright-cli open https://example.com
|
||||
```
|
||||
|
||||
### Storage State File Format
|
||||
|
||||
The saved file contains:
|
||||
|
||||
```json
|
||||
{
|
||||
"cookies": [
|
||||
{
|
||||
"name": "session_id",
|
||||
"value": "abc123",
|
||||
"domain": "example.com",
|
||||
"path": "/",
|
||||
"expires": 1735689600,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "Lax"
|
||||
}
|
||||
],
|
||||
"origins": [
|
||||
{
|
||||
"origin": "https://example.com",
|
||||
"localStorage": [
|
||||
{ "name": "theme", "value": "dark" },
|
||||
{ "name": "user_id", "value": "12345" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Cookies
|
||||
|
||||
### List All Cookies
|
||||
|
||||
```bash
|
||||
playwright-cli cookie-list
|
||||
```
|
||||
|
||||
### Filter Cookies by Domain
|
||||
|
||||
```bash
|
||||
playwright-cli cookie-list --domain=example.com
|
||||
```
|
||||
|
||||
### Filter Cookies by Path
|
||||
|
||||
```bash
|
||||
playwright-cli cookie-list --path=/api
|
||||
```
|
||||
|
||||
### Get Specific Cookie
|
||||
|
||||
```bash
|
||||
playwright-cli cookie-get session_id
|
||||
```
|
||||
|
||||
### Set a Cookie
|
||||
|
||||
```bash
|
||||
# Basic cookie
|
||||
playwright-cli cookie-set session abc123
|
||||
|
||||
# Cookie with options
|
||||
playwright-cli cookie-set session abc123 --domain=example.com --path=/ --httpOnly --secure --sameSite=Lax
|
||||
|
||||
# Cookie with expiration (Unix timestamp)
|
||||
playwright-cli cookie-set remember_me token123 --expires=1735689600
|
||||
```
|
||||
|
||||
### Delete a Cookie
|
||||
|
||||
```bash
|
||||
playwright-cli cookie-delete session_id
|
||||
```
|
||||
|
||||
### Clear All Cookies
|
||||
|
||||
```bash
|
||||
playwright-cli cookie-clear
|
||||
```
|
||||
|
||||
### Advanced: Multiple Cookies or Custom Options
|
||||
|
||||
For complex scenarios like adding multiple cookies at once, use `run-code`:
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
await page.context().addCookies([
|
||||
{ name: 'session_id', value: 'sess_abc123', domain: 'example.com', path: '/', httpOnly: true },
|
||||
{ name: 'preferences', value: JSON.stringify({ theme: 'dark' }), domain: 'example.com', path: '/' }
|
||||
]);
|
||||
}"
|
||||
```
|
||||
|
||||
## Local Storage
|
||||
|
||||
### List All localStorage Items
|
||||
|
||||
```bash
|
||||
playwright-cli localstorage-list
|
||||
```
|
||||
|
||||
### Get Single Value
|
||||
|
||||
```bash
|
||||
playwright-cli localstorage-get token
|
||||
```
|
||||
|
||||
### Set Value
|
||||
|
||||
```bash
|
||||
playwright-cli localstorage-set theme dark
|
||||
```
|
||||
|
||||
### Set JSON Value
|
||||
|
||||
```bash
|
||||
playwright-cli localstorage-set user_settings '{"theme":"dark","language":"en"}'
|
||||
```
|
||||
|
||||
### Delete Single Item
|
||||
|
||||
```bash
|
||||
playwright-cli localstorage-delete token
|
||||
```
|
||||
|
||||
### Clear All localStorage
|
||||
|
||||
```bash
|
||||
playwright-cli localstorage-clear
|
||||
```
|
||||
|
||||
### Advanced: Multiple Operations
|
||||
|
||||
For complex scenarios like setting multiple values at once, use `run-code`:
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
await page.evaluate(() => {
|
||||
localStorage.setItem('token', 'jwt_abc123');
|
||||
localStorage.setItem('user_id', '12345');
|
||||
localStorage.setItem('expires_at', Date.now() + 3600000);
|
||||
});
|
||||
}"
|
||||
```
|
||||
|
||||
## Session Storage
|
||||
|
||||
### List All sessionStorage Items
|
||||
|
||||
```bash
|
||||
playwright-cli sessionstorage-list
|
||||
```
|
||||
|
||||
### Get Single Value
|
||||
|
||||
```bash
|
||||
playwright-cli sessionstorage-get form_data
|
||||
```
|
||||
|
||||
### Set Value
|
||||
|
||||
```bash
|
||||
playwright-cli sessionstorage-set step 3
|
||||
```
|
||||
|
||||
### Delete Single Item
|
||||
|
||||
```bash
|
||||
playwright-cli sessionstorage-delete step
|
||||
```
|
||||
|
||||
### Clear sessionStorage
|
||||
|
||||
```bash
|
||||
playwright-cli sessionstorage-clear
|
||||
```
|
||||
|
||||
## IndexedDB
|
||||
|
||||
### List Databases
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
return await page.evaluate(async () => {
|
||||
const databases = await indexedDB.databases();
|
||||
return databases;
|
||||
});
|
||||
}"
|
||||
```
|
||||
|
||||
### Delete Database
|
||||
|
||||
```bash
|
||||
playwright-cli run-code "async page => {
|
||||
await page.evaluate(() => {
|
||||
indexedDB.deleteDatabase('myDatabase');
|
||||
});
|
||||
}"
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Authentication State Reuse
|
||||
|
||||
```bash
|
||||
# Step 1: Login and save state
|
||||
playwright-cli open https://app.example.com/login
|
||||
playwright-cli snapshot
|
||||
playwright-cli fill e1 "user@example.com"
|
||||
playwright-cli fill e2 "password123"
|
||||
playwright-cli click e3
|
||||
|
||||
# Save the authenticated state
|
||||
playwright-cli state-save auth.json
|
||||
|
||||
# Step 2: Later, restore state and skip login
|
||||
playwright-cli state-load auth.json
|
||||
playwright-cli open https://app.example.com/dashboard
|
||||
# Already logged in!
|
||||
```
|
||||
|
||||
### Save and Restore Roundtrip
|
||||
|
||||
```bash
|
||||
# Set up authentication state
|
||||
playwright-cli open https://example.com
|
||||
playwright-cli eval "() => { document.cookie = 'session=abc123'; localStorage.setItem('user', 'john'); }"
|
||||
|
||||
# Save state to file
|
||||
playwright-cli state-save my-session.json
|
||||
|
||||
# ... later, in a new session ...
|
||||
|
||||
# Restore state
|
||||
playwright-cli state-load my-session.json
|
||||
playwright-cli open https://example.com
|
||||
# Cookies and localStorage are restored!
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Never commit storage state files containing auth tokens
|
||||
- Add `*.auth-state.json` to `.gitignore`
|
||||
- Delete state files after automation completes
|
||||
- Use environment variables for sensitive data
|
||||
- By default, sessions run in-memory mode which is safer for sensitive operations
|
||||
88
node_modules/playwright-core/lib/tools/cli-client/skill/references/test-generation.md
generated
vendored
Normal file
88
node_modules/playwright-core/lib/tools/cli-client/skill/references/test-generation.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# Test Generation
|
||||
|
||||
Generate Playwright test code automatically as you interact with the browser.
|
||||
|
||||
## How It Works
|
||||
|
||||
Every action you perform with `playwright-cli` generates corresponding Playwright TypeScript code.
|
||||
This code appears in the output and can be copied directly into your test files.
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```bash
|
||||
# Start a session
|
||||
playwright-cli open https://example.com/login
|
||||
|
||||
# Take a snapshot to see elements
|
||||
playwright-cli snapshot
|
||||
# Output shows: e1 [textbox "Email"], e2 [textbox "Password"], e3 [button "Sign In"]
|
||||
|
||||
# Fill form fields - generates code automatically
|
||||
playwright-cli fill e1 "user@example.com"
|
||||
# Ran Playwright code:
|
||||
# await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
|
||||
|
||||
playwright-cli fill e2 "password123"
|
||||
# Ran Playwright code:
|
||||
# await page.getByRole('textbox', { name: 'Password' }).fill('password123');
|
||||
|
||||
playwright-cli click e3
|
||||
# Ran Playwright code:
|
||||
# await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
```
|
||||
|
||||
## Building a Test File
|
||||
|
||||
Collect the generated code into a Playwright test:
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('login flow', async ({ page }) => {
|
||||
// Generated code from playwright-cli session:
|
||||
await page.goto('https://example.com/login');
|
||||
await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
|
||||
await page.getByRole('textbox', { name: 'Password' }).fill('password123');
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
|
||||
// Add assertions
|
||||
await expect(page).toHaveURL(/.*dashboard/);
|
||||
});
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Semantic Locators
|
||||
|
||||
The generated code uses role-based locators when possible, which are more resilient:
|
||||
|
||||
```typescript
|
||||
// Generated (good - semantic)
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
|
||||
// Avoid (fragile - CSS selectors)
|
||||
await page.locator('#submit-btn').click();
|
||||
```
|
||||
|
||||
### 2. Explore Before Recording
|
||||
|
||||
Take snapshots to understand the page structure before recording actions:
|
||||
|
||||
```bash
|
||||
playwright-cli open https://example.com
|
||||
playwright-cli snapshot
|
||||
# Review the element structure
|
||||
playwright-cli click e5
|
||||
```
|
||||
|
||||
### 3. Add Assertions Manually
|
||||
|
||||
Generated code captures actions but not assertions. Add expectations in your test:
|
||||
|
||||
```typescript
|
||||
// Generated action
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
|
||||
// Manual assertion
|
||||
await expect(page.getByText('Success')).toBeVisible();
|
||||
```
|
||||
139
node_modules/playwright-core/lib/tools/cli-client/skill/references/tracing.md
generated
vendored
Normal file
139
node_modules/playwright-core/lib/tools/cli-client/skill/references/tracing.md
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
# Tracing
|
||||
|
||||
Capture detailed execution traces for debugging and analysis. Traces include DOM snapshots, screenshots, network activity, and console logs.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```bash
|
||||
# Start trace recording
|
||||
playwright-cli tracing-start
|
||||
|
||||
# Perform actions
|
||||
playwright-cli open https://example.com
|
||||
playwright-cli click e1
|
||||
playwright-cli fill e2 "test"
|
||||
|
||||
# Stop trace recording
|
||||
playwright-cli tracing-stop
|
||||
```
|
||||
|
||||
## Trace Output Files
|
||||
|
||||
When you start tracing, Playwright creates a `traces/` directory with several files:
|
||||
|
||||
### `trace-{timestamp}.trace`
|
||||
|
||||
**Action log** - The main trace file containing:
|
||||
- Every action performed (clicks, fills, navigations)
|
||||
- DOM snapshots before and after each action
|
||||
- Screenshots at each step
|
||||
- Timing information
|
||||
- Console messages
|
||||
- Source locations
|
||||
|
||||
### `trace-{timestamp}.network`
|
||||
|
||||
**Network log** - Complete network activity:
|
||||
- All HTTP requests and responses
|
||||
- Request headers and bodies
|
||||
- Response headers and bodies
|
||||
- Timing (DNS, connect, TLS, TTFB, download)
|
||||
- Resource sizes
|
||||
- Failed requests and errors
|
||||
|
||||
### `resources/`
|
||||
|
||||
**Resources directory** - Cached resources:
|
||||
- Images, fonts, stylesheets, scripts
|
||||
- Response bodies for replay
|
||||
- Assets needed to reconstruct page state
|
||||
|
||||
## What Traces Capture
|
||||
|
||||
| Category | Details |
|
||||
|----------|---------|
|
||||
| **Actions** | Clicks, fills, hovers, keyboard input, navigations |
|
||||
| **DOM** | Full DOM snapshot before/after each action |
|
||||
| **Screenshots** | Visual state at each step |
|
||||
| **Network** | All requests, responses, headers, bodies, timing |
|
||||
| **Console** | All console.log, warn, error messages |
|
||||
| **Timing** | Precise timing for each operation |
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Debugging Failed Actions
|
||||
|
||||
```bash
|
||||
playwright-cli tracing-start
|
||||
playwright-cli open https://app.example.com
|
||||
|
||||
# This click fails - why?
|
||||
playwright-cli click e5
|
||||
|
||||
playwright-cli tracing-stop
|
||||
# Open trace to see DOM state when click was attempted
|
||||
```
|
||||
|
||||
### Analyzing Performance
|
||||
|
||||
```bash
|
||||
playwright-cli tracing-start
|
||||
playwright-cli open https://slow-site.com
|
||||
playwright-cli tracing-stop
|
||||
|
||||
# View network waterfall to identify slow resources
|
||||
```
|
||||
|
||||
### Capturing Evidence
|
||||
|
||||
```bash
|
||||
# Record a complete user flow for documentation
|
||||
playwright-cli tracing-start
|
||||
|
||||
playwright-cli open https://app.example.com/checkout
|
||||
playwright-cli fill e1 "4111111111111111"
|
||||
playwright-cli fill e2 "12/25"
|
||||
playwright-cli fill e3 "123"
|
||||
playwright-cli click e4
|
||||
|
||||
playwright-cli tracing-stop
|
||||
# Trace shows exact sequence of events
|
||||
```
|
||||
|
||||
## Trace vs Video vs Screenshot
|
||||
|
||||
| Feature | Trace | Video | Screenshot |
|
||||
|---------|-------|-------|------------|
|
||||
| **Format** | .trace file | .webm video | .png/.jpeg image |
|
||||
| **DOM inspection** | Yes | No | No |
|
||||
| **Network details** | Yes | No | No |
|
||||
| **Step-by-step replay** | Yes | Continuous | Single frame |
|
||||
| **File size** | Medium | Large | Small |
|
||||
| **Best for** | Debugging | Demos | Quick capture |
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Start Tracing Before the Problem
|
||||
|
||||
```bash
|
||||
# Trace the entire flow, not just the failing step
|
||||
playwright-cli tracing-start
|
||||
playwright-cli open https://example.com
|
||||
# ... all steps leading to the issue ...
|
||||
playwright-cli tracing-stop
|
||||
```
|
||||
|
||||
### 2. Clean Up Old Traces
|
||||
|
||||
Traces can consume significant disk space:
|
||||
|
||||
```bash
|
||||
# Remove traces older than 7 days
|
||||
find .playwright-cli/traces -mtime +7 -delete
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- Traces add overhead to automation
|
||||
- Large traces can consume significant disk space
|
||||
- Some dynamic content may not replay perfectly
|
||||
143
node_modules/playwright-core/lib/tools/cli-client/skill/references/video-recording.md
generated
vendored
Normal file
143
node_modules/playwright-core/lib/tools/cli-client/skill/references/video-recording.md
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
# Video Recording
|
||||
|
||||
Capture browser automation sessions as video for debugging, documentation, or verification. Produces WebM (VP8/VP9 codec).
|
||||
|
||||
## Basic Recording
|
||||
|
||||
```bash
|
||||
# Open browser first
|
||||
playwright-cli open
|
||||
|
||||
# Start recording
|
||||
playwright-cli video-start demo.webm
|
||||
|
||||
# Add a chapter marker for section transitions
|
||||
playwright-cli video-chapter "Getting Started" --description="Opening the homepage" --duration=2000
|
||||
|
||||
# Navigate and perform actions
|
||||
playwright-cli goto https://example.com
|
||||
playwright-cli snapshot
|
||||
playwright-cli click e1
|
||||
|
||||
# Add another chapter
|
||||
playwright-cli video-chapter "Filling Form" --description="Entering test data" --duration=2000
|
||||
playwright-cli fill e2 "test input"
|
||||
|
||||
# Stop and save
|
||||
playwright-cli video-stop
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Descriptive Filenames
|
||||
|
||||
```bash
|
||||
# Include context in filename
|
||||
playwright-cli video-start recordings/login-flow-2024-01-15.webm
|
||||
playwright-cli video-start recordings/checkout-test-run-42.webm
|
||||
```
|
||||
|
||||
### 2. Record entire hero scripts.
|
||||
|
||||
When recording a video for the user or as a proof of work, it is best to create a code snippet and execute it with run-code.
|
||||
It allows pulling appropriate pauses between the actions and annotating the video. There are new Playwright APIs for that.
|
||||
|
||||
1) Perform scenario using CLI and take note of all locators and actions. You'll need those locators to request thier bounding boxes for highlight.
|
||||
2) Create a file with the intended script for video (below). Use pressSequentially w/ delay for nice typing, make reasonable pauses.
|
||||
3) Use playwright-cli run-code --file your-script.js
|
||||
|
||||
**Important**: Overlays are `pointer-events: none` — they do not interfere with page interactions. You can safely keep sticky overlays visible while clicking, filling, or performing any actions on the page.
|
||||
|
||||
```js
|
||||
async page => {
|
||||
await page.screencast.start({ path: 'video.webm', size: { width: 1280, height: 800 } });
|
||||
await page.goto('https://demo.playwright.dev/todomvc');
|
||||
|
||||
// Show a chapter card — blurs the page and shows a dialog.
|
||||
// Blocks until duration expires, then auto-removes.
|
||||
// Use this for simple use cases, but always feel free to hand-craft your own beautiful
|
||||
// overlay via await page.screencast.showOverlay().
|
||||
await page.screencast.showChapter('Adding Todo Items', {
|
||||
description: 'We will add several items to the todo list.',
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
// Perform action
|
||||
await page.getByRole('textbox', { name: 'What needs to be done?' }).pressSequentially('Walk the dog', { delay: 60 });
|
||||
await page.getByRole('textbox', { name: 'What needs to be done?' }).press('Enter');
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Show next chapter
|
||||
await page.screencast.showChapter('Verifying Results', {
|
||||
description: 'Checking the item appeared in the list.',
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
// Add a sticky annotation that stays while you perform actions.
|
||||
// Overlays are pointer-events: none, so they won't block clicks.
|
||||
const annotation = await page.screencast.showOverlay(`
|
||||
<div style="position: absolute; top: 8px; right: 8px;
|
||||
padding: 6px 12px; background: rgba(0,0,0,0.7);
|
||||
border-radius: 8px; font-size: 13px; color: white;">
|
||||
✓ Item added successfully
|
||||
</div>
|
||||
`);
|
||||
|
||||
// Perform more actions while the annotation is visible
|
||||
await page.getByRole('textbox', { name: 'What needs to be done?' }).pressSequentially('Buy groceries', { delay: 60 });
|
||||
await page.getByRole('textbox', { name: 'What needs to be done?' }).press('Enter');
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
// Remove the annotation when done
|
||||
await annotation.dispose();
|
||||
|
||||
// You can also highlight relevant locators and provide contextual annotations.
|
||||
const bounds = await page.getByText('Walk the dog').boundingBox();
|
||||
await page.screencast.showOverlay(`
|
||||
<div style="position: absolute;
|
||||
top: ${bounds.y}px;
|
||||
left: ${bounds.x}px;
|
||||
width: ${bounds.width}px;
|
||||
height: ${bounds.height}px;
|
||||
border: 1px solid red;">
|
||||
</div>
|
||||
<div style="position: absolute;
|
||||
top: ${bounds.y + bounds.height + 5}px;
|
||||
left: ${bounds.x + bounds.width / 2}px;
|
||||
transform: translateX(-50%);
|
||||
padding: 6px;
|
||||
background: #808080;
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
color: white;">Check it out, it is right above this text
|
||||
</div>
|
||||
`, { duration: 2000 });
|
||||
|
||||
await page.screencast.stop();
|
||||
}
|
||||
```
|
||||
|
||||
Embrace creativity, overlays are powerful.
|
||||
|
||||
### Overlay API Summary
|
||||
|
||||
| Method | Use Case |
|
||||
|--------|----------|
|
||||
| `page.screencast.showChapter(title, { description?, duration?, styleSheet? })` | Full-screen chapter card with blurred backdrop — ideal for section transitions |
|
||||
| `page.screencast.showOverlay(html, { duration? })` | Custom HTML overlay — use for callouts, labels, highlights |
|
||||
| `disposable.dispose()` | Remove a sticky overlay added without duration |
|
||||
| `page.screencast.hideOverlays()` / `page.screencast.showOverlays()` | Temporarily hide/show all overlays |
|
||||
|
||||
## Tracing vs Video
|
||||
|
||||
| Feature | Video | Tracing |
|
||||
|---------|-------|---------|
|
||||
| Output | WebM file | Trace file (viewable in Trace Viewer) |
|
||||
| Shows | Visual recording | DOM snapshots, network, console, actions |
|
||||
| Use case | Demos, documentation | Debugging, analysis |
|
||||
| Size | Larger | Smaller |
|
||||
|
||||
## Limitations
|
||||
|
||||
- Recording adds slight overhead to automation
|
||||
- Large recordings can consume significant disk space
|
||||
Reference in New Issue
Block a user