rebrowser-playwright-core 1.52.0 → 1.64.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/ThirdPartyNotices.txt +7 -1554
  2. package/bin/install_webkit_wsl.ps1 +33 -0
  3. package/bin/reinstall_chrome_beta_linux.sh +1 -1
  4. package/bin/reinstall_chrome_beta_mac.sh +1 -1
  5. package/bin/reinstall_chrome_stable_linux.sh +1 -1
  6. package/bin/reinstall_chrome_stable_mac.sh +1 -1
  7. package/bin/reinstall_msedge_beta_linux.sh +1 -1
  8. package/bin/reinstall_msedge_beta_mac.sh +1 -1
  9. package/bin/reinstall_msedge_dev_linux.sh +1 -1
  10. package/bin/reinstall_msedge_dev_mac.sh +1 -1
  11. package/bin/reinstall_msedge_stable_linux.sh +1 -1
  12. package/bin/reinstall_msedge_stable_mac.sh +1 -1
  13. package/browsers.json +16 -44
  14. package/cli.js +5 -1
  15. package/index.js +2 -17
  16. package/lib/bootstrap.js +149 -0
  17. package/lib/coreBundle.js +78218 -0
  18. package/lib/entry/cliDaemon.js +5 -0
  19. package/lib/entry/dashboardApp.js +3 -0
  20. package/lib/entry/mcp.js +10 -0
  21. package/lib/entry/oopBrowserDownload.js +3 -0
  22. package/lib/{server/deviceDescriptors.js → package.js} +18 -7
  23. package/lib/server/electron/loader.js +108 -14
  24. package/lib/serverRegistry.js +1939 -0
  25. package/lib/serverRegistry.js.LICENSE +65 -0
  26. package/lib/tools/cli-client/channelSessions.js +141 -0
  27. package/lib/tools/cli-client/cli.js +7 -0
  28. package/lib/tools/cli-client/help.json +808 -0
  29. package/lib/tools/cli-client/minimist.js +128 -0
  30. package/lib/tools/cli-client/output.js +352 -0
  31. package/lib/tools/cli-client/program.js +422 -0
  32. package/lib/tools/cli-client/registry.js +180 -0
  33. package/lib/tools/cli-client/session.js +261 -0
  34. package/lib/tools/dashboard/appIcon.png +0 -0
  35. package/lib/tools/skills/playwright-cli/SKILL.md +493 -0
  36. package/lib/tools/skills/playwright-cli/references/element-attributes.md +23 -0
  37. package/lib/tools/skills/playwright-cli/references/playwright-tests.md +39 -0
  38. package/lib/tools/skills/playwright-cli/references/pr-attachments.md +60 -0
  39. package/lib/tools/skills/playwright-cli/references/request-mocking.md +87 -0
  40. package/lib/tools/skills/playwright-cli/references/running-code.md +245 -0
  41. package/lib/tools/skills/playwright-cli/references/session-management.md +227 -0
  42. package/lib/tools/skills/playwright-cli/references/storage-state.md +275 -0
  43. package/lib/tools/skills/playwright-cli/references/test-generation.md +433 -0
  44. package/lib/tools/skills/playwright-cli/references/tracing.md +139 -0
  45. package/lib/tools/skills/playwright-cli/references/video-recording.md +216 -0
  46. package/lib/tools/skills/playwright-component-testing/SKILL.md +136 -0
  47. package/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
  48. package/lib/tools/skills/playwright-component-testing/references/migration.md +89 -0
  49. package/lib/tools/skills/playwright-component-testing/references/react.md +69 -0
  50. package/lib/tools/skills/playwright-component-testing/references/typing.md +173 -0
  51. package/lib/tools/skills/playwright-component-testing/references/vue.md +77 -0
  52. package/lib/tools/skills/playwright-trace/SKILL.md +174 -0
  53. package/lib/tools/utils/extension.js +112 -0
  54. package/lib/tools/utils/socketConnection.js +108 -0
  55. package/lib/utilsBundle.js +86038 -66
  56. package/lib/utilsBundle.js.LICENSE +1890 -0
  57. package/lib/vite/dashboard/assets/codeMirrorModule--QdMvsKi.css +1 -0
  58. package/lib/vite/dashboard/assets/codeMirrorModule-CQ8RZGBm.js +32 -0
  59. package/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
  60. package/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
  61. package/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
  62. package/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
  63. package/lib/vite/dashboard/assets/index-AwgwcYie.css +1 -0
  64. package/lib/vite/dashboard/assets/index-hRvO4yU2.js +12 -0
  65. package/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
  66. package/lib/vite/dashboard/index.html +29 -0
  67. package/lib/vite/dashboard/playwright-logo.svg +24 -0
  68. package/lib/vite/htmlReport/index.html +2 -61
  69. package/lib/vite/htmlReport/report.css +2 -0
  70. package/lib/vite/htmlReport/report.js +32 -0
  71. package/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
  72. package/lib/vite/recorder/assets/codeMirrorModule-DK72OMRi.js +32 -0
  73. package/lib/vite/recorder/assets/index-BZpYJZ-P.css +1 -0
  74. package/lib/vite/recorder/assets/index-Cn0mmDuv.js +129 -0
  75. package/lib/vite/recorder/index.html +3 -3
  76. package/lib/vite/traceViewer/assets/codeMirrorModule-BEB2e8M3.js +32 -0
  77. package/lib/vite/traceViewer/assets/defaultSettingsView-D-g2vrvf.js +184 -0
  78. package/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
  79. package/lib/vite/traceViewer/assets/xtermModule-B794rD2Z.js +7 -0
  80. package/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
  81. package/lib/vite/traceViewer/defaultSettingsView.C8BeHuxd.css +1 -0
  82. package/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
  83. package/lib/vite/traceViewer/index.html +9 -8
  84. package/lib/vite/traceViewer/index.oNry3Hjv.js +1 -0
  85. package/lib/vite/traceViewer/manifest.webmanifest +16 -0
  86. package/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
  87. package/lib/vite/traceViewer/snapshot.html +4 -15
  88. package/lib/vite/traceViewer/sw.bundle.js +4 -3
  89. package/lib/vite/traceViewer/uiMode.CYwC_gH1.js +5 -0
  90. package/lib/vite/traceViewer/uiMode.CyMfwkXJ.css +1 -0
  91. package/lib/vite/traceViewer/uiMode.html +6 -5
  92. package/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
  93. package/lib/webp_codec.LICENSE +173 -0
  94. package/lib/webp_codec.wasm +0 -0
  95. package/lib/{utilsBundleImpl/xdg-open → xdg-open} +338 -137
  96. package/package.json +6 -16
  97. package/types/protocol.d.ts +10495 -8030
  98. package/types/structs.d.ts +8 -1
  99. package/types/types.d.ts +9256 -4825
  100. package/lib/androidServerImpl.js +0 -63
  101. package/lib/browserServerImpl.js +0 -88
  102. package/lib/cli/driver.js +0 -97
  103. package/lib/cli/program.js +0 -567
  104. package/lib/cli/programWithTestStub.js +0 -74
  105. package/lib/client/accessibility.js +0 -49
  106. package/lib/client/android.js +0 -365
  107. package/lib/client/api.js +0 -137
  108. package/lib/client/artifact.js +0 -79
  109. package/lib/client/browser.js +0 -136
  110. package/lib/client/browserContext.js +0 -539
  111. package/lib/client/browserType.js +0 -193
  112. package/lib/client/cdpSession.js +0 -51
  113. package/lib/client/channelOwner.js +0 -205
  114. package/lib/client/clientHelper.js +0 -64
  115. package/lib/client/clientInstrumentation.js +0 -55
  116. package/lib/client/clientStackTrace.js +0 -69
  117. package/lib/client/clock.js +0 -68
  118. package/lib/client/connection.js +0 -318
  119. package/lib/client/consoleMessage.js +0 -55
  120. package/lib/client/coverage.js +0 -44
  121. package/lib/client/dialog.js +0 -56
  122. package/lib/client/download.js +0 -62
  123. package/lib/client/electron.js +0 -133
  124. package/lib/client/elementHandle.js +0 -284
  125. package/lib/client/errors.js +0 -77
  126. package/lib/client/eventEmitter.js +0 -314
  127. package/lib/client/events.js +0 -98
  128. package/lib/client/fetch.js +0 -367
  129. package/lib/client/fileChooser.js +0 -46
  130. package/lib/client/fileUtils.js +0 -34
  131. package/lib/client/frame.js +0 -386
  132. package/lib/client/harRouter.js +0 -87
  133. package/lib/client/input.js +0 -82
  134. package/lib/client/jsHandle.js +0 -105
  135. package/lib/client/jsonPipe.js +0 -39
  136. package/lib/client/localUtils.js +0 -61
  137. package/lib/client/locator.js +0 -362
  138. package/lib/client/network.js +0 -751
  139. package/lib/client/page.js +0 -709
  140. package/lib/client/platform.js +0 -74
  141. package/lib/client/playwright.js +0 -85
  142. package/lib/client/selectors.js +0 -75
  143. package/lib/client/stream.js +0 -39
  144. package/lib/client/timeoutSettings.js +0 -75
  145. package/lib/client/tracing.js +0 -114
  146. package/lib/client/types.js +0 -28
  147. package/lib/client/video.js +0 -59
  148. package/lib/client/waiter.js +0 -142
  149. package/lib/client/webError.js +0 -39
  150. package/lib/client/webSocket.js +0 -111
  151. package/lib/client/worker.js +0 -63
  152. package/lib/client/writableStream.js +0 -39
  153. package/lib/generated/clockSource.js +0 -28
  154. package/lib/generated/consoleApiSource.js +0 -28
  155. package/lib/generated/injectedScriptSource.js +0 -28
  156. package/lib/generated/pollingRecorderSource.js +0 -28
  157. package/lib/generated/utilityScriptSource.js +0 -28
  158. package/lib/generated/webSocketMockSource.js +0 -378
  159. package/lib/inProcessFactory.js +0 -59
  160. package/lib/inprocess.js +0 -3
  161. package/lib/outofprocess.js +0 -78
  162. package/lib/protocol/debug.js +0 -211
  163. package/lib/protocol/serializers.js +0 -192
  164. package/lib/protocol/validator.js +0 -2825
  165. package/lib/protocol/validatorPrimitives.js +0 -179
  166. package/lib/remote/playwrightConnection.js +0 -266
  167. package/lib/remote/playwrightServer.js +0 -139
  168. package/lib/server/accessibility.js +0 -69
  169. package/lib/server/android/android.js +0 -451
  170. package/lib/server/android/backendAdb.js +0 -179
  171. package/lib/server/artifact.js +0 -127
  172. package/lib/server/bidi/bidiBrowser.js +0 -380
  173. package/lib/server/bidi/bidiChromium.js +0 -152
  174. package/lib/server/bidi/bidiConnection.js +0 -187
  175. package/lib/server/bidi/bidiExecutionContext.js +0 -220
  176. package/lib/server/bidi/bidiFirefox.js +0 -112
  177. package/lib/server/bidi/bidiInput.js +0 -146
  178. package/lib/server/bidi/bidiNetworkManager.js +0 -320
  179. package/lib/server/bidi/bidiOverCdp.js +0 -102
  180. package/lib/server/bidi/bidiPage.js +0 -530
  181. package/lib/server/bidi/bidiPdf.js +0 -106
  182. package/lib/server/bidi/third_party/bidiCommands.d.js +0 -22
  183. package/lib/server/bidi/third_party/bidiDeserializer.js +0 -98
  184. package/lib/server/bidi/third_party/bidiKeyboard.js +0 -256
  185. package/lib/server/bidi/third_party/bidiProtocol.js +0 -152
  186. package/lib/server/bidi/third_party/bidiSerializer.js +0 -148
  187. package/lib/server/bidi/third_party/firefoxPrefs.js +0 -259
  188. package/lib/server/browser.js +0 -140
  189. package/lib/server/browserContext.js +0 -650
  190. package/lib/server/browserType.js +0 -326
  191. package/lib/server/callLog.js +0 -82
  192. package/lib/server/chromium/chromium.js +0 -376
  193. package/lib/server/chromium/chromiumSwitches.js +0 -101
  194. package/lib/server/chromium/crAccessibility.js +0 -263
  195. package/lib/server/chromium/crBrowser.js +0 -498
  196. package/lib/server/chromium/crConnection.js +0 -324
  197. package/lib/server/chromium/crCoverage.js +0 -232
  198. package/lib/server/chromium/crDevTools.js +0 -117
  199. package/lib/server/chromium/crDragDrop.js +0 -126
  200. package/lib/server/chromium/crExecutionContext.js +0 -145
  201. package/lib/server/chromium/crInput.js +0 -184
  202. package/lib/server/chromium/crNetworkManager.js +0 -666
  203. package/lib/server/chromium/crPage.js +0 -1055
  204. package/lib/server/chromium/crPdf.js +0 -121
  205. package/lib/server/chromium/crProtocolHelper.js +0 -145
  206. package/lib/server/chromium/crServiceWorker.js +0 -130
  207. package/lib/server/chromium/defaultFontFamilies.js +0 -162
  208. package/lib/server/chromium/protocol.d.js +0 -16
  209. package/lib/server/chromium/videoRecorder.js +0 -121
  210. package/lib/server/clock.js +0 -137
  211. package/lib/server/codegen/csharp.js +0 -329
  212. package/lib/server/codegen/java.js +0 -270
  213. package/lib/server/codegen/javascript.js +0 -268
  214. package/lib/server/codegen/jsonl.js +0 -51
  215. package/lib/server/codegen/language.js +0 -111
  216. package/lib/server/codegen/languages.js +0 -68
  217. package/lib/server/codegen/python.js +0 -277
  218. package/lib/server/codegen/types.js +0 -16
  219. package/lib/server/console.js +0 -53
  220. package/lib/server/cookieStore.js +0 -204
  221. package/lib/server/debugController.js +0 -185
  222. package/lib/server/debugger.js +0 -136
  223. package/lib/server/deviceDescriptorsSource.json +0 -1669
  224. package/lib/server/dialog.js +0 -72
  225. package/lib/server/dispatchers/androidDispatcher.js +0 -293
  226. package/lib/server/dispatchers/artifactDispatcher.js +0 -118
  227. package/lib/server/dispatchers/browserContextDispatcher.js +0 -328
  228. package/lib/server/dispatchers/browserDispatcher.js +0 -151
  229. package/lib/server/dispatchers/browserTypeDispatcher.js +0 -55
  230. package/lib/server/dispatchers/cdpSessionDispatcher.js +0 -44
  231. package/lib/server/dispatchers/debugControllerDispatcher.js +0 -87
  232. package/lib/server/dispatchers/dialogDispatcher.js +0 -47
  233. package/lib/server/dispatchers/dispatcher.js +0 -346
  234. package/lib/server/dispatchers/electronDispatcher.js +0 -90
  235. package/lib/server/dispatchers/elementHandlerDispatcher.js +0 -191
  236. package/lib/server/dispatchers/frameDispatcher.js +0 -224
  237. package/lib/server/dispatchers/jsHandleDispatcher.js +0 -80
  238. package/lib/server/dispatchers/jsonPipeDispatcher.js +0 -58
  239. package/lib/server/dispatchers/localUtilsDispatcher.js +0 -155
  240. package/lib/server/dispatchers/networkDispatchers.js +0 -204
  241. package/lib/server/dispatchers/pageDispatcher.js +0 -328
  242. package/lib/server/dispatchers/playwrightDispatcher.js +0 -100
  243. package/lib/server/dispatchers/selectorsDispatcher.js +0 -40
  244. package/lib/server/dispatchers/streamDispatcher.js +0 -60
  245. package/lib/server/dispatchers/tracingDispatcher.js +0 -59
  246. package/lib/server/dispatchers/webSocketRouteDispatcher.js +0 -154
  247. package/lib/server/dispatchers/writableStreamDispatcher.js +0 -73
  248. package/lib/server/dom.js +0 -869
  249. package/lib/server/download.js +0 -70
  250. package/lib/server/electron/electron.js +0 -277
  251. package/lib/server/errors.js +0 -69
  252. package/lib/server/fetch.js +0 -640
  253. package/lib/server/fileChooser.js +0 -43
  254. package/lib/server/fileUploadUtils.js +0 -84
  255. package/lib/server/firefox/ffAccessibility.js +0 -238
  256. package/lib/server/firefox/ffBrowser.js +0 -404
  257. package/lib/server/firefox/ffConnection.js +0 -147
  258. package/lib/server/firefox/ffExecutionContext.js +0 -149
  259. package/lib/server/firefox/ffInput.js +0 -159
  260. package/lib/server/firefox/ffNetworkManager.js +0 -254
  261. package/lib/server/firefox/ffPage.js +0 -501
  262. package/lib/server/firefox/firefox.js +0 -106
  263. package/lib/server/firefox/protocol.d.js +0 -16
  264. package/lib/server/formData.js +0 -147
  265. package/lib/server/frameSelectors.js +0 -137
  266. package/lib/server/frames.js +0 -1555
  267. package/lib/server/har/harRecorder.js +0 -147
  268. package/lib/server/har/harTracer.js +0 -606
  269. package/lib/server/harBackend.js +0 -157
  270. package/lib/server/helper.js +0 -100
  271. package/lib/server/index.js +0 -61
  272. package/lib/server/input.js +0 -280
  273. package/lib/server/instrumentation.js +0 -75
  274. package/lib/server/javascript.js +0 -299
  275. package/lib/server/launchApp.js +0 -110
  276. package/lib/server/localUtils.js +0 -211
  277. package/lib/server/macEditingCommands.js +0 -143
  278. package/lib/server/network.js +0 -583
  279. package/lib/server/page.js +0 -790
  280. package/lib/server/pageBinding.js +0 -88
  281. package/lib/server/pipeTransport.js +0 -89
  282. package/lib/server/playwright.js +0 -81
  283. package/lib/server/progress.js +0 -104
  284. package/lib/server/protocolError.js +0 -52
  285. package/lib/server/recorder/chat.js +0 -161
  286. package/lib/server/recorder/contextRecorder.js +0 -286
  287. package/lib/server/recorder/recorderApp.js +0 -184
  288. package/lib/server/recorder/recorderCollection.js +0 -116
  289. package/lib/server/recorder/recorderFrontend.js +0 -16
  290. package/lib/server/recorder/recorderRunner.js +0 -135
  291. package/lib/server/recorder/recorderUtils.js +0 -100
  292. package/lib/server/recorder/throttledFile.js +0 -57
  293. package/lib/server/recorder.js +0 -360
  294. package/lib/server/registry/browserFetcher.js +0 -175
  295. package/lib/server/registry/dependencies.js +0 -371
  296. package/lib/server/registry/index.js +0 -1271
  297. package/lib/server/registry/nativeDeps.js +0 -1105
  298. package/lib/server/registry/oopDownloadBrowserMain.js +0 -120
  299. package/lib/server/screenshotter.js +0 -332
  300. package/lib/server/selectors.js +0 -112
  301. package/lib/server/socksClientCertificatesInterceptor.js +0 -321
  302. package/lib/server/socksInterceptor.js +0 -95
  303. package/lib/server/storageScript.js +0 -154
  304. package/lib/server/timeoutSettings.js +0 -89
  305. package/lib/server/trace/recorder/snapshotter.js +0 -143
  306. package/lib/server/trace/recorder/snapshotterInjected.js +0 -539
  307. package/lib/server/trace/recorder/tracing.js +0 -593
  308. package/lib/server/trace/test/inMemorySnapshotter.js +0 -87
  309. package/lib/server/trace/viewer/traceViewer.js +0 -249
  310. package/lib/server/transport.js +0 -183
  311. package/lib/server/types.js +0 -28
  312. package/lib/server/usKeyboardLayout.js +0 -145
  313. package/lib/server/utils/ascii.js +0 -44
  314. package/lib/server/utils/comparators.js +0 -161
  315. package/lib/server/utils/crypto.js +0 -216
  316. package/lib/server/utils/debug.js +0 -47
  317. package/lib/server/utils/debugLogger.js +0 -114
  318. package/lib/server/utils/env.js +0 -68
  319. package/lib/server/utils/eventsHelper.js +0 -39
  320. package/lib/server/utils/expectUtils.js +0 -38
  321. package/lib/server/utils/fileUtils.js +0 -191
  322. package/lib/server/utils/happyEyeballs.js +0 -207
  323. package/lib/server/utils/hostPlatform.js +0 -109
  324. package/lib/server/utils/httpServer.js +0 -218
  325. package/lib/server/utils/image_tools/colorUtils.js +0 -89
  326. package/lib/server/utils/image_tools/compare.js +0 -109
  327. package/lib/server/utils/image_tools/imageChannel.js +0 -78
  328. package/lib/server/utils/image_tools/stats.js +0 -102
  329. package/lib/server/utils/linuxUtils.js +0 -71
  330. package/lib/server/utils/network.js +0 -217
  331. package/lib/server/utils/nodePlatform.js +0 -148
  332. package/lib/server/utils/pipeTransport.js +0 -84
  333. package/lib/server/utils/processLauncher.js +0 -238
  334. package/lib/server/utils/profiler.js +0 -65
  335. package/lib/server/utils/socksProxy.js +0 -511
  336. package/lib/server/utils/spawnAsync.js +0 -41
  337. package/lib/server/utils/task.js +0 -51
  338. package/lib/server/utils/userAgent.js +0 -98
  339. package/lib/server/utils/wsServer.js +0 -132
  340. package/lib/server/utils/zipFile.js +0 -74
  341. package/lib/server/utils/zones.js +0 -57
  342. package/lib/server/webkit/protocol.d.js +0 -16
  343. package/lib/server/webkit/webkit.js +0 -100
  344. package/lib/server/webkit/wkAccessibility.js +0 -237
  345. package/lib/server/webkit/wkBrowser.js +0 -312
  346. package/lib/server/webkit/wkConnection.js +0 -149
  347. package/lib/server/webkit/wkExecutionContext.js +0 -153
  348. package/lib/server/webkit/wkInput.js +0 -181
  349. package/lib/server/webkit/wkInterceptableRequest.js +0 -169
  350. package/lib/server/webkit/wkPage.js +0 -1114
  351. package/lib/server/webkit/wkProvisionalPage.js +0 -83
  352. package/lib/server/webkit/wkWorkers.js +0 -104
  353. package/lib/third_party/pixelmatch.js +0 -255
  354. package/lib/utils/isomorphic/ariaSnapshot.js +0 -384
  355. package/lib/utils/isomorphic/assert.js +0 -31
  356. package/lib/utils/isomorphic/builtins.js +0 -90
  357. package/lib/utils/isomorphic/colors.js +0 -72
  358. package/lib/utils/isomorphic/cssParser.js +0 -246
  359. package/lib/utils/isomorphic/cssTokenizer.js +0 -1051
  360. package/lib/utils/isomorphic/headers.js +0 -53
  361. package/lib/utils/isomorphic/locatorGenerators.js +0 -655
  362. package/lib/utils/isomorphic/locatorParser.js +0 -176
  363. package/lib/utils/isomorphic/locatorUtils.js +0 -81
  364. package/lib/utils/isomorphic/manualPromise.js +0 -115
  365. package/lib/utils/isomorphic/mimeType.js +0 -460
  366. package/lib/utils/isomorphic/multimap.js +0 -81
  367. package/lib/utils/isomorphic/rtti.js +0 -43
  368. package/lib/utils/isomorphic/selectorParser.js +0 -387
  369. package/lib/utils/isomorphic/semaphore.js +0 -54
  370. package/lib/utils/isomorphic/stackTrace.js +0 -158
  371. package/lib/utils/isomorphic/stringUtils.js +0 -176
  372. package/lib/utils/isomorphic/time.js +0 -44
  373. package/lib/utils/isomorphic/timeoutRunner.js +0 -67
  374. package/lib/utils/isomorphic/traceUtils.js +0 -59
  375. package/lib/utils/isomorphic/types.js +0 -16
  376. package/lib/utils/isomorphic/urlMatch.js +0 -167
  377. package/lib/utils/isomorphic/utilityScriptSerializers.js +0 -248
  378. package/lib/utils.js +0 -101
  379. package/lib/utilsBundleImpl/index.js +0 -208
  380. package/lib/vite/recorder/assets/codeMirrorModule-C3UTv-Ge.css +0 -1
  381. package/lib/vite/recorder/assets/codeMirrorModule-DVQi6prl.js +0 -24
  382. package/lib/vite/recorder/assets/index-97EUAAbk.js +0 -184
  383. package/lib/vite/recorder/assets/index-eHBmevrY.css +0 -1
  384. package/lib/vite/traceViewer/assets/codeMirrorModule-DwAiTpyC.js +0 -24
  385. package/lib/vite/traceViewer/assets/defaultSettingsView-DkkRvn5X.js +0 -265
  386. package/lib/vite/traceViewer/assets/xtermModule-BoAIEibi.js +0 -9
  387. package/lib/vite/traceViewer/codeMirrorModule.C3UTv-Ge.css +0 -1
  388. package/lib/vite/traceViewer/defaultSettingsView.QdHITyLI.css +0 -1
  389. package/lib/vite/traceViewer/index.CFOW-Ezb.css +0 -1
  390. package/lib/vite/traceViewer/index.DvtSwn6E.js +0 -2
  391. package/lib/vite/traceViewer/uiMode.BatfzHMG.css +0 -1
  392. package/lib/vite/traceViewer/uiMode.Sdytl9wc.js +0 -5
  393. package/lib/vite/traceViewer/xtermModule.Beg8tuEN.css +0 -32
  394. package/lib/zipBundle.js +0 -34
  395. package/lib/zipBundleImpl.js +0 -5
@@ -0,0 +1,139 @@
1
+ # Tracing
2
+
3
+ Capture detailed execution traces for debugging and analysis. Traces include DOM snapshots, screenshots, network activity, and console logs.
4
+
5
+ ## Basic Usage
6
+
7
+ ```bash
8
+ # Start trace recording
9
+ playwright-cli tracing-start
10
+
11
+ # Perform actions
12
+ playwright-cli open https://example.com
13
+ playwright-cli click e1
14
+ playwright-cli fill e2 "test"
15
+
16
+ # Stop trace recording
17
+ playwright-cli tracing-stop
18
+ ```
19
+
20
+ ## Trace Output Files
21
+
22
+ When you start tracing, Playwright creates a `.playwright-cli/traces/` directory with several files:
23
+
24
+ ### `trace-{timestamp}.trace`
25
+
26
+ **Action log** - The main trace file containing:
27
+ - Every action performed (clicks, fills, navigations)
28
+ - DOM snapshots before and after each action
29
+ - Screenshots at each step
30
+ - Timing information
31
+ - Console messages
32
+ - Source locations
33
+
34
+ ### `trace-{timestamp}.network`
35
+
36
+ **Network log** - Complete network activity:
37
+ - All HTTP requests and responses
38
+ - Request headers and bodies
39
+ - Response headers and bodies
40
+ - Timing (DNS, connect, TLS, TTFB, download)
41
+ - Resource sizes
42
+ - Failed requests and errors
43
+
44
+ ### `resources/`
45
+
46
+ **Resources directory** - Cached resources:
47
+ - Images, fonts, stylesheets, scripts
48
+ - Response bodies for replay
49
+ - Assets needed to reconstruct page state
50
+
51
+ ## What Traces Capture
52
+
53
+ | Category | Details |
54
+ |----------|---------|
55
+ | **Actions** | Clicks, fills, hovers, keyboard input, navigations |
56
+ | **DOM** | Full DOM snapshot before/after each action |
57
+ | **Screenshots** | Visual state at each step |
58
+ | **Network** | All requests, responses, headers, bodies, timing |
59
+ | **Console** | All console.log, warn, error messages |
60
+ | **Timing** | Precise timing for each operation |
61
+
62
+ ## Use Cases
63
+
64
+ ### Debugging Failed Actions
65
+
66
+ ```bash
67
+ playwright-cli tracing-start
68
+ playwright-cli open https://app.example.com
69
+
70
+ # This click fails - why?
71
+ playwright-cli click e5
72
+
73
+ playwright-cli tracing-stop
74
+ # Open trace to see DOM state when click was attempted
75
+ ```
76
+
77
+ ### Analyzing Performance
78
+
79
+ ```bash
80
+ playwright-cli tracing-start
81
+ playwright-cli open https://slow-site.com
82
+ playwright-cli tracing-stop
83
+
84
+ # View network waterfall to identify slow resources
85
+ ```
86
+
87
+ ### Capturing Evidence
88
+
89
+ ```bash
90
+ # Record a complete user flow for documentation
91
+ playwright-cli tracing-start
92
+
93
+ playwright-cli open https://app.example.com/checkout
94
+ playwright-cli fill e1 "4111111111111111"
95
+ playwright-cli fill e2 "12/25"
96
+ playwright-cli fill e3 "123"
97
+ playwright-cli click e4
98
+
99
+ playwright-cli tracing-stop
100
+ # Trace shows exact sequence of events
101
+ ```
102
+
103
+ ## Trace vs Video vs Screenshot
104
+
105
+ | Feature | Trace | Video | Screenshot |
106
+ |---------|-------|-------|------------|
107
+ | **Format** | .trace file | .webm video | .png/.jpeg image |
108
+ | **DOM inspection** | Yes | No | No |
109
+ | **Network details** | Yes | No | No |
110
+ | **Step-by-step replay** | Yes | Continuous | Single frame |
111
+ | **File size** | Medium | Large | Small |
112
+ | **Best for** | Debugging | Demos | Quick capture |
113
+
114
+ ## Best Practices
115
+
116
+ ### 1. Start Tracing Before the Problem
117
+
118
+ ```bash
119
+ # Trace the entire flow, not just the failing step
120
+ playwright-cli tracing-start
121
+ playwright-cli open https://example.com
122
+ # ... all steps leading to the issue ...
123
+ playwright-cli tracing-stop
124
+ ```
125
+
126
+ ### 2. Clean Up Old Traces
127
+
128
+ Traces can consume significant disk space:
129
+
130
+ ```bash
131
+ # Remove traces older than 7 days
132
+ find .playwright-cli/traces -mtime +7 -delete
133
+ ```
134
+
135
+ ## Limitations
136
+
137
+ - Traces add overhead to automation
138
+ - Large traces can consume significant disk space
139
+ - Some dynamic content may not replay perfectly
@@ -0,0 +1,216 @@
1
+ # Video Recording
2
+
3
+ Capture browser automation sessions as video for debugging, documentation, or verification. Produces WebM (VP8/VP9 codec).
4
+
5
+ ## Basic Recording
6
+
7
+ ```bash
8
+ # Open browser first
9
+ playwright-cli open
10
+
11
+ # Start recording, --cursor renders an animated mouse cursor that travels to each action point
12
+ # and paces actions by 800ms so that it has time to travel
13
+ playwright-cli video-start demo.webm --cursor --fps=60
14
+
15
+ # Add a chapter marker for section transitions
16
+ playwright-cli video-chapter "Getting Started" --description="Opening the homepage" --duration=2000
17
+
18
+ # Navigate and perform actions
19
+ playwright-cli goto https://example.com
20
+ playwright-cli snapshot
21
+ playwright-cli click e1
22
+
23
+ # Add another chapter
24
+ playwright-cli video-chapter "Filling Form" --description="Entering test data" --duration=2000
25
+ playwright-cli fill e2 "test input"
26
+
27
+ # Stop and save
28
+ playwright-cli video-stop
29
+ ```
30
+
31
+ ## Cursor, Target Highlight and Click Point
32
+
33
+ Three decorations can be drawn for each action: the mouse **cursor**, a **highlight** box around the
34
+ target element and a **point** marker at the click point. A **title** callout naming the action comes
35
+ with `video-show-actions`. The cursor is the only one `video-start --cursor` turns on; the rest are
36
+ opt-in and styled with plain CSS declarations, so they look exactly the way you want.
37
+
38
+ ```bash
39
+ # Cursor only, nothing else on screen
40
+ playwright-cli video-start demo.webm --cursor
41
+
42
+ # Action callout, plus a red click point and a dark frame around the target
43
+ playwright-cli video-show-actions --duration=800 --position=top-right \
44
+ --point-style="width: 20px; height: 20px; border-radius: 50%; background: rgba(255,0,0,.7)" \
45
+ --highlight-style="outline: 2px solid #333; background: rgba(0,128,255,.15)" \
46
+ --title-style="font-size: 16px"
47
+
48
+ # Stop annotating actions
49
+ playwright-cli video-hide-actions
50
+ ```
51
+
52
+ The same options are available programmatically, which is the better choice for hero scripts:
53
+
54
+ ```js
55
+ await page.screencast.showActions({
56
+ // 'pointer' (default) animates the cursor from the previous action point, 'none' hides it.
57
+ cursor: 'pointer',
58
+ // How long decorations stay on screen. Actions are paced by this delay, 500ms by default.
59
+ duration: 800,
60
+ // Where the action title goes: top-left, top, top-right, bottom-left, bottom, bottom-right.
61
+ position: 'top-right',
62
+ style: {
63
+ // Marker at the click point. The element is zero-sized and centered on the point,
64
+ // so give it a size, or draw around the point with box-shadow. Hidden when omitted.
65
+ point: 'width: 20px; height: 20px; border-radius: 50%; background: rgba(255, 0, 0, .7)',
66
+ // Box that covers the target element. Hidden when omitted.
67
+ // Prefer `outline` over `border`, it does not shrink the box.
68
+ highlight: 'outline: 2px solid #333; background: rgba(0, 128, 255, .15)',
69
+ // The action title. Use 'display: none' to keep the cursor but drop the callout.
70
+ title: 'font-size: 16px',
71
+ },
72
+ });
73
+ ```
74
+
75
+ Notes:
76
+ - All decorations fade out over `duration`. Override `animation` in a style to do something else.
77
+ - The cursor stays on screen at the last action point between actions and across navigations,
78
+ and travels along a slightly curved path, so it reads as a hand moving a mouse.
79
+ - Call `page.screencast.hideActions()` to stop annotating and hide the cursor.
80
+
81
+ ## Best Practices
82
+
83
+ ### 1. Use Descriptive Filenames
84
+
85
+ ```bash
86
+ # Include context in filename
87
+ playwright-cli video-start recordings/login-flow-2024-01-15.webm
88
+ playwright-cli video-start recordings/checkout-test-run-42.webm
89
+ ```
90
+
91
+ ### 2. Record entire hero scripts.
92
+
93
+ 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.
94
+ It allows inserting appropriate pauses between the actions and annotating the video. There are new Playwright APIs for that.
95
+
96
+ 1) Perform scenario using CLI and take note of all locators and actions. You'll need those locators to request their bounding boxes for highlight.
97
+ 2) Create a file with the intended script for video (below). Use pressSequentially w/ delay for nice typing, make reasonable pauses.
98
+ 3) Use playwright-cli run-code --filename your-script.js
99
+
100
+ **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.
101
+
102
+ ```js
103
+ async page => {
104
+ await page.screencast.start({ path: 'video.webm', size: { width: 1280, height: 800 }, fps: 60 });
105
+ // Show the cursor and mark the click point, and pace actions by 800ms.
106
+ await page.screencast.showActions({
107
+ duration: 800,
108
+ style: {
109
+ point: 'width: 20px; height: 20px; border-radius: 50%; background: rgba(255, 0, 0, .7)',
110
+ title: 'display: none',
111
+ },
112
+ });
113
+ await page.goto('https://demo.playwright.dev/todomvc');
114
+
115
+ // Show a chapter card — blurs the page and shows a dialog.
116
+ // Blocks until duration expires, then auto-removes.
117
+ // Use this for simple use cases, but always feel free to hand-craft your own beautiful
118
+ // overlay via await page.screencast.showOverlay().
119
+ await page.screencast.showChapter('Adding Todo Items', {
120
+ description: 'We will add several items to the todo list.',
121
+ duration: 2000,
122
+ });
123
+
124
+ // Perform action
125
+ await page.getByRole('textbox', { name: 'What needs to be done?' }).pressSequentially('Walk the dog', { delay: 60 });
126
+ await page.getByRole('textbox', { name: 'What needs to be done?' }).press('Enter');
127
+ await page.waitForTimeout(1000);
128
+
129
+ // Show next chapter
130
+ await page.screencast.showChapter('Verifying Results', {
131
+ description: 'Checking the item appeared in the list.',
132
+ duration: 2000,
133
+ });
134
+
135
+ // Add a sticky annotation that stays while you perform actions.
136
+ // Overlays are pointer-events: none, so they won't block clicks.
137
+ const annotation = await page.screencast.showOverlay(`
138
+ <div style="position: absolute; top: 8px; right: 8px;
139
+ padding: 6px 12px; background: rgba(0,0,0,0.7);
140
+ border-radius: 8px; font-size: 13px; color: white;">
141
+ ✓ Item added successfully
142
+ </div>
143
+ `);
144
+
145
+ // Perform more actions while the annotation is visible
146
+ await page.getByRole('textbox', { name: 'What needs to be done?' }).pressSequentially('Buy groceries', { delay: 60 });
147
+ await page.getByRole('textbox', { name: 'What needs to be done?' }).press('Enter');
148
+ await page.waitForTimeout(1500);
149
+
150
+ // Remove the annotation when done
151
+ await annotation.dispose();
152
+
153
+ // You can also highlight relevant locators and provide contextual annotations.
154
+ const bounds = await page.getByText('Walk the dog').boundingBox();
155
+ await page.screencast.showOverlay(`
156
+ <div style="position: absolute;
157
+ top: ${bounds.y}px;
158
+ left: ${bounds.x}px;
159
+ width: ${bounds.width}px;
160
+ height: ${bounds.height}px;
161
+ border: 1px solid red;">
162
+ </div>
163
+ <div style="position: absolute;
164
+ top: ${bounds.y + bounds.height + 5}px;
165
+ left: ${bounds.x + bounds.width / 2}px;
166
+ transform: translateX(-50%);
167
+ padding: 6px;
168
+ background: #808080;
169
+ border-radius: 10px;
170
+ font-size: 14px;
171
+ color: white;">Check it out, it is right above this text
172
+ </div>
173
+ `, { duration: 2000 });
174
+
175
+ await page.screencast.stop();
176
+ }
177
+ ```
178
+
179
+ Embrace creativity, overlays are powerful.
180
+
181
+ ### Overlay API Summary
182
+
183
+ | Method | Use Case |
184
+ |--------|----------|
185
+ | `page.screencast.showChapter(title, { description?, duration?, styleSheet? })` | Full-screen chapter card with blurred backdrop — ideal for section transitions |
186
+ | `page.screencast.showOverlay(html, { duration? })` | Custom HTML overlay — use for callouts, labels, highlights |
187
+ | `disposable.dispose()` | Remove a sticky overlay added without duration |
188
+ | `page.screencast.hideOverlays()` / `page.screencast.showOverlays()` | Temporarily hide/show all overlays |
189
+ | `page.screencast.showActions({ cursor, duration, position, style })` | Cursor, click point, target highlight and action title |
190
+ | `page.screencast.hideActions()` | Stop annotating actions and hide the cursor |
191
+
192
+ ### 3. Attach the recording to the pull request
193
+
194
+ A hero script recording is the best proof of work for a user-facing change. GitHub accepts WebM as is, so once the recording looks right, attach it with `gh` 2.99+ instead of describing the flow in words:
195
+
196
+ ```bash
197
+ gh pr create --title "feat(todo): add items inline" --body-file body.md --attach ./demo.webm
198
+ gh pr comment 123 --body "Walkthrough of the new flow." --attach ./demo.webm
199
+ gh issue comment 456 --body "Recording of the repro steps." --attach ./repro.webm
200
+ ```
201
+
202
+ `gh` appends unreferenced attachments to the end of the body, which is the right place for a walkthrough. Videos are limited to 10 MB on free plans and 100 MB on paid plans, so keep the script focused, record at a modest size such as 1280x800 and drop chapters that do not add to the story. See [pr-attachments.md](pr-attachments.md) for the full set of commands, including attaching test artifacts from CI.
203
+
204
+ ## Tracing vs Video
205
+
206
+ | Feature | Video | Tracing |
207
+ |---------|-------|---------|
208
+ | Output | WebM file | Trace file (viewable in Trace Viewer) |
209
+ | Shows | Visual recording | DOM snapshots, network, console, actions |
210
+ | Use case | Demos, documentation | Debugging, analysis |
211
+ | Size | Larger | Smaller |
212
+
213
+ ## Limitations
214
+
215
+ - Recording adds slight overhead to automation
216
+ - Large recordings can consume significant disk space
@@ -0,0 +1,136 @@
1
+ ---
2
+ name: playwright-component-testing
3
+ description: Set up component testing with Playwright using a story gallery — scaffold stories and a gallery dev page driven by the built-in mount fixture, no dedicated component-testing runtime. Use when asked to test React or Vue components in isolation with Playwright, or to migrate off @playwright/experimental-ct-react / -vue.
4
+ ---
5
+
6
+ # Component Testing with Playwright
7
+
8
+ Test components with regular Playwright e2e tests against a small **story gallery** page hosted by the app's own dev server. No extra test runner, bundler integration or npm packages are required.
9
+
10
+ ## Concept
11
+
12
+ - A **story** is a tiny wrapper component that embeds the component under test in one specific scenario: hard-coded props, mock data, providers, recorded callbacks. Stories live next to the component in `*.story.tsx` (or `.ts`/`.jsx`/`.js`/`.vue`) files; each named export is one story.
13
+ - The **gallery** is a single page you implement to `references/gallery-spec.md`: it exposes `window.mount(params)` / `window.unmount()` that render a story — resolved from your story files (e.g. with `import.meta.glob`) — into `#root`. It is framework-specific and yours to own — there is no template to copy for it.
14
+ - Tests are plain Playwright tests. The built-in **`mount(storyId, props?)` fixture** (from `@playwright/test`) drives the gallery's `window.mount` and returns a `Locator` for the gallery root (`#root`). Scope the queries from there — `component.getByRole('button').click()`, not `component.click()`. Nothing to scaffold for it.
15
+
16
+ Everything the component needs must be set up *inside the story* (it runs in the browser); everything the test asserts must be observable *through the page* (DOM, URL, network). Where the component takes callbacks, the story creates the state, provides the callbacks and records the state into a hidden form for the test to assert on. `mount(id, props)` passes plain serializable `props` to the story.
17
+
18
+ ## Setup workflow
19
+
20
+ 1. **Detect the framework and bundler.** React vs Vue decides the framework notes and example story to follow. Then:
21
+ - **App runs on Vite** (has `vite.config.*`): the gallery is served by the existing dev server at `/playwright/gallery/index.html` — Vite serves any `.html` file under the project root, the app's plugins/aliases/CSS apply automatically, and `vite build` ignores it. No extra server needed.
22
+ - **Anything else** (Next.js, webpack, no dev server): run a small standalone dev server (e.g. Vite) that serves the gallery page, and point `baseURL` at it. Requires `vite` and the framework plugin as devDependencies.
23
+ 2. **Implement the gallery** to `references/gallery-spec.md`: a page at `<project>/playwright/gallery/` that renders the requested story into `#root`. Start from the worked example in the spec and the framework notes in `references/react.md` / `references/vue.md`. Keep story discovery (`import.meta.glob`) and the framework mount here — this is the only framework-specific glue, so keep it small. Import the app's global CSS the same way the app's own entry does.
24
+ 3. **Configure Playwright** — add to `playwright.config.ts`:
25
+
26
+ ```ts
27
+ projects: [
28
+ {
29
+ name: 'components',
30
+ testDir: './tests/components',
31
+ use: { ...devices['Desktop Chrome'], baseURL: 'http://localhost:5173/playwright/gallery/index.html', serviceWorkers: 'block', reuseContext: true },
32
+ },
33
+ ],
34
+ webServer: {
35
+ command: 'npm run dev', // or: npx vite --config playwright/vite.config.ts
36
+ url: 'http://localhost:5173/playwright/gallery/index.html', // standalone server: http://localhost:3100/playwright/gallery/index.html
37
+ reuseExistingServer: !process.env.CI,
38
+ },
39
+ ```
40
+
41
+ Match the port to the dev server. `mount` navigates to `baseURL`, so set `baseURL` to the gallery's URL. `serviceWorkers: 'block'` keeps the app's own service worker from serving cached responses that would shadow your `page.route()` mocks. `reuseContext: true` reuses the browser context across tests in a worker (as the old component-testing runtime did) — a large speedup for component suites. If the config already has projects/webServer, merge instead of replacing.
42
+ 4. **Write a first story** next to an existing component, modeled on `templates/<react|vue>/Button.story.*`.
43
+ 5. **Write a first spec**, modeled on `templates/react/button.spec.ts`, importing `test`/`expect` from `@playwright/test`.
44
+ 6. **Run**: `npx playwright test --project=components`. Open `http://localhost:5173/playwright/gallery/index.html` in a browser to eyeball all stories.
45
+
46
+ ## Conventions
47
+
48
+ - Story id: path under `src/` without the `.story.*` extension, plus the export name — `src/components/Button.story.tsx` export `Primary` → `components/Button/Primary`. Any unique suffix works too: `mount('Button/Primary')`. A `.story.vue` single-file component is one story, addressable by its path alone (its `default` export). With gallery types (`references/typing.md`) ids are prefixed with the package name: `acme-ui/components/Button/Primary`.
49
+ - One export per scenario. Prefer a new story export over parameterizing an existing one — stories are greppable, reviewable documentation of component states.
50
+
51
+ ## Testing patterns
52
+
53
+ Examples are React; the Vue equivalents differ only in story syntax.
54
+
55
+ ### Callbacks and events
56
+
57
+ **The story owns the state and provides the callbacks.** Where the component takes callbacks, create the state inside the story, wire the callbacks to it, and record the state into a hidden form next to the component. Tests perform operations and assert on the recorded values:
58
+
59
+ ```tsx
60
+ export const Stateful = () => {
61
+ const [expanded, setExpanded] = useState(false);
62
+ return <>
63
+ <Expandable expanded={expanded} setExpanded={setExpanded} title="Title">Details</Expandable>
64
+ <form hidden><input data-testid="expanded" readOnly value={String(expanded)} /></form>
65
+ </>;
66
+ };
67
+ ```
68
+
69
+ ```ts
70
+ test('click should expand', async ({ mount }) => {
71
+ const component = await mount('components/Expandable/Stateful');
72
+ await component.locator('.codicon-chevron-right').click();
73
+ await expect(component.getByTestId('expanded')).toHaveValue('true');
74
+ });
75
+ ```
76
+
77
+ This keeps the whole scenario in the browser: no callback marshalling, the story doubles as documentation, and the recorded state is visible when eyeballing the gallery. Record each observed value in its own `data-testid` input (`String(...)` or `JSON.stringify(...)` for payloads) and assert with `toHaveValue()` — a web-first assertion that retries until the state lands. The negative direction works the same way: perform the operation, then assert the value did **not** change.
78
+
79
+ ### Per-test props
80
+
81
+ When a scenario is genuinely parametric (e.g. a boundary-value sweep), pass props as the second argument to `mount`; the gallery hands them to the story as its props. Keep props to plain serializable data — callbacks belong inside the story.
82
+
83
+ ```tsx
84
+ export const WithTitle = ({ title = 'Default' }: { title?: string }) =>
85
+ <Button title={title} />;
86
+ ```
87
+
88
+ ```ts
89
+ const component = await mount('components/Button/WithTitle', { title: 'Hello' });
90
+ ```
91
+
92
+ Props are type-checked in two optional ways, see `references/typing.md`: pass the story type as a template argument (`mount<typeof WithTitle>('components/Button/WithTitle', { title: 'Hello' })`, no setup), or generate gallery types with a small Vite plugin so the id itself is typed (`mount('acme-ui/components/Button/WithTitle', { title: 'Hello' })`, with autocomplete and rename safety). Vue stories must additionally declare the props at runtime — see the `Typed props` sections in `references/react.md` / `references/vue.md`.
93
+
94
+ ### Prop transitions with `update()`
95
+
96
+ To test how a component reacts to a prop change **without remounting** (state preserved), call `component.update(newProps)` — it re-renders the same story with new props on the existing root:
97
+
98
+ ```ts
99
+ const component = await mount('components/Counter/Default', { value: 1 });
100
+ await expect(component.getByTestId('value')).toHaveText('1');
101
+ await component.update({ value: 2 });
102
+ await expect(component.getByTestId('value')).toHaveText('2');
103
+ ```
104
+
105
+ This requires the gallery to reuse its root/instance (`references/gallery-spec.md`); state survives as long as the story stays the same.
106
+
107
+ ### Multiple states in one test
108
+
109
+ Each `mount()` navigates fresh, so tests are fully isolated and mounting several stories in one test is cheap:
110
+
111
+ ```ts
112
+ await expect(await mount('Button/Primary')).toHaveScreenshot('primary.png');
113
+ await expect(await mount('Button/Disabled')).toHaveScreenshot('disabled.png');
114
+ ```
115
+
116
+ For visual comparison, screenshot the returned root locator (as above), not the page, to avoid asserting on browser chrome.
117
+
118
+ ### Network mocking
119
+
120
+ Use `page.route()` as usual — register routes before `mount()`, since mounting navigates. `serviceWorkers: 'block'` (set in the config above) keeps the app's own service worker from serving cached responses that shadow the routes. Teams with MSW handler libraries can start the worker inside a story or decorator instead.
121
+
122
+ ### Debugging stories
123
+
124
+ Open your gallery URL (`baseURL`) in a browser and call `await window.mount({ story: 'components/Button/Primary' })` from the devtools console — that is exactly what the `mount` fixture does. An unknown story rejects `window.mount`, which surfaces as the test's `mount()` throwing with a real stack. To browse without the console, give your gallery an optional index page.
125
+
126
+ ## Decision points
127
+
128
+ - **Monorepos / non-`src` layouts**: change the glob and the id derivation in your gallery (`references/gallery-spec.md`) to match, and prefix ids with the package name (`references/typing.md`).
129
+ - **Global providers** (theme, i18n, store, router): create a shared `decorator` helper next to the gallery and wrap components in stories; see `references/react.md` / `references/vue.md`.
130
+ ## References
131
+
132
+ - `references/gallery-spec.md` — the gallery endpoint contract to implement (**start here**).
133
+ - `references/typing.md` — optional typing for `mount`: explicit story types vs generated gallery types, with the Vite plugin.
134
+ - `references/react.md` — React walkthrough: providers, StrictMode, CSS.
135
+ - `references/vue.md` — Vue walkthrough: `.story.ts` and `.story.vue` stories, plugins.
136
+ - `references/migration.md` — migrating off `@playwright/experimental-ct-react` / `-vue`.
@@ -0,0 +1,144 @@
1
+ # Gallery contract
2
+
3
+ The **gallery** is a single page, served by your dev server at the URL you set as `baseURL` in your
4
+ Playwright config, that exposes two methods on `window` for Playwright to drive:
5
+
6
+ - `window.mount(params)` — render a story.
7
+ - `window.unmount()` — unmount the current story.
8
+
9
+ The built-in `mount` fixture navigates to the gallery, then calls `window.mount` via
10
+ `page.evaluate()`. Keep props to plain serializable data — where the component takes callbacks,
11
+ the story creates the state, provides the callbacks and records the state into a hidden form for
12
+ the test to assert on.
13
+
14
+ ## `window.mount(params)`
15
+
16
+ `params` is `{ story, props }`, straight from the test's `mount(story, props)` call:
17
+
18
+ - `story` — the story id (string). Resolve it (see id grammar) to a component.
19
+ - `props` — the plain serializable props object passed to the component.
20
+
21
+ Render the resolved component with `props` into `#root`. Return a `Promise` that resolves once the
22
+ component is mounted and **rejects on failure** (unknown story, render throw). The rejection
23
+ surfaces as the test's `await mount(...)` throwing, with a real stack — there is no HTTP-status or
24
+ DOM-attribute signalling.
25
+
26
+ **Reuse the root across calls.** The test's `component.update(props)` calls `window.mount` again
27
+ with the same story and new props, **without navigating**. If you render into the same root /
28
+ instance rather than recreating it, the framework reconciles and component-internal state is
29
+ preserved — that is CT's `update()`. Recreating the root each call (or navigating) resets state, so
30
+ reuse it: create it on first mount and render into it on every call. The framework reconciles,
31
+ remounting on its own only when the story (component type) changes.
32
+
33
+ **`window.mount` is your setup/teardown hook.** It is the browser-side equivalent of CT's
34
+ `beforeMount` / `afterMount`: install providers or plugins, seed a store, start an in-browser mock
35
+ server *before* you render, and run post-render work *after* — all inside this one function,
36
+ branched on the `story` / `props` the test passed. There is no separate hook registry; the function
37
+ you own is the hook.
38
+
39
+ ## `window.unmount()`
40
+
41
+ Unmount the current story from `#root` and return a `Promise`. The test calls it via
42
+ `component.unmount()`. Needed only to assert teardown/cleanup effects — each `mount` navigates
43
+ fresh, so tests are already isolated.
44
+
45
+ ## `#root`
46
+
47
+ Render the component into an element with `id="root"`. `mount` returns a `Locator` for `#root`
48
+ itself, so tests scope their queries from there — `component.getByRole('button').click()`, not
49
+ `component.click()`. Stories are free to render fragments, e.g. the component plus a hidden form
50
+ recording its state.
51
+
52
+ ## Story id grammar (recommended)
53
+
54
+ The gallery owns resolution; `mount` passes the id through untouched. Recommended scheme:
55
+
56
+ - `<path under src, without the .story.* extension>/<ExportName>` — e.g.
57
+ `src/components/Button.story.tsx` export `Primary` → `components/Button/Primary`.
58
+ - Any unique trailing suffix resolves too: `Button/Primary`.
59
+ - A single-file-component story (`Button.story.vue`) is one story, addressed by its path alone
60
+ (its default export): `components/Button`.
61
+
62
+ ## Worked example (React + Vite SPA)
63
+
64
+ An illustration of the contract, **not** a file to copy — implement the equivalent for your stack.
65
+ `import.meta.glob` stays inline here: Vite analyzes it statically, relative to this file, so it
66
+ cannot be moved into shared/shipped code. That is exactly why the gallery is yours to own.
67
+
68
+ ```tsx
69
+ // playwright/gallery/main.tsx
70
+ import { flushSync } from 'react-dom';
71
+ import { createRoot, type Root } from 'react-dom/client';
72
+
73
+ const stories = import.meta.glob('../../src/**/*.story.{tsx,jsx}');
74
+ const id = (f: string) => f.replace(/^(\.\.\/)+src\//, '').replace(/\.story\.\w+$/, '');
75
+
76
+ async function resolve(storyId: string) {
77
+ const sep = storyId.lastIndexOf('/');
78
+ const [path, name] = [storyId.slice(0, sep), storyId.slice(sep + 1)];
79
+ const file = Object.keys(stories).find(f => id(f) === path || id(f).endsWith('/' + path));
80
+ const mod = (file && await stories[file]()) as Record<string, any> | undefined;
81
+ return mod?.[name] ?? mod?.default;
82
+ }
83
+
84
+ const rootEl = document.getElementById('root')!;
85
+ let root: Root | undefined;
86
+
87
+ (window as any).mount = async ({ story, props }: { story: string, props?: Record<string, any> }) => {
88
+ const Story = await resolve(story);
89
+ if (!Story)
90
+ throw new Error(`Unknown story: ${story}`);
91
+ root ??= createRoot(rootEl); // reuse the root so update() reconciles and preserves state
92
+ // flushSync so a render error rejects the promise instead of being swallowed.
93
+ flushSync(() => root!.render(<Story {...props} />));
94
+ };
95
+
96
+ (window as any).unmount = async () => {
97
+ root?.unmount();
98
+ root = undefined;
99
+ };
100
+ ```
101
+
102
+ ```html
103
+ <!-- playwright/gallery/index.html -->
104
+ <!DOCTYPE html>
105
+ <div id="root"></div>
106
+ <script type="module" src="./main.tsx"></script>
107
+ ```
108
+
109
+ ## Vue variant (state-preserving)
110
+
111
+ Vue's `createApp(...).mount()` builds a fresh instance each call, so mount a small **reactive host**
112
+ once and update its refs — updating them re-renders in place, which is what preserves state across
113
+ `update()`:
114
+
115
+ ```ts
116
+ // playwright/gallery/main.ts
117
+ import { createApp, h, shallowRef, type App, type Component } from 'vue';
118
+
119
+ // resolve() and the import.meta.glob are the same as the React example.
120
+ const story = shallowRef<Component | null>(null);
121
+ const props = shallowRef<Record<string, any>>({});
122
+ const host = { render: () => (story.value ? h(story.value, props.value) : null) };
123
+ let app: App | undefined;
124
+
125
+ (window as any).mount = async ({ story: id, props: next }: { story: string, props?: Record<string, any> }) => {
126
+ const resolved = await resolve(id);
127
+ if (!resolved)
128
+ throw new Error(`Unknown story: ${id}`);
129
+ story.value = resolved;
130
+ props.value = next ?? {};
131
+ if (!app) { // mount once; the ref updates above re-render in place
132
+ app = createApp(host);
133
+ app.mount('#root');
134
+ }
135
+ };
136
+
137
+ (window as any).unmount = async () => {
138
+ app?.unmount();
139
+ app = undefined;
140
+ };
141
+ ```
142
+
143
+ Keep the story-resolution glob and the framework mount in this file; everything
144
+ else lives in your stories and tests.