Compare commits

...

545 commits

Author SHA1 Message Date
Pavel Feldman 31f4a05eb6
chore: make git diff different for CI and local (#34955) 2025-02-27 14:06:13 -08:00
Pavel Feldman 7a61aa25e6
chore: provide blob name for web and html reporter tests (#34940) 2025-02-27 13:22:07 -08:00
Adam Gastineau 67d6f7f603
chore: temporarily disable floating promise warning messages (#34957) 2025-02-27 12:45:30 -08:00
Adam Gastineau b0ceed51a5
docs: Improve toHaveURL doc clarity (#34935) 2025-02-27 11:00:50 -08:00
Dmitry Gozman 08ea36caa2
chore: default reportSlowTests to 5 minutes (#34950) 2025-02-27 16:31:32 +00:00
Dmitry Gozman 70cc2b14e2
chore: apply "injected" eslint rules to "isomorphic" (#34953) 2025-02-27 16:31:05 +00:00
Playwright Service ad64f8d859
feat(chromium): roll to r1161 (#34952)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-27 17:01:07 +01:00
Simon Knott a1146fd4a3
chore: copy as prompt in ui should have codeframe (#34943)
Signed-off-by: Simon Knott <info@simonknott.de>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-02-27 15:50:46 +01:00
Dmitry Gozman 3ce9ae6a7d
chore: replace locator.visible with filter({ visible }) (#34947) 2025-02-27 13:44:53 +00:00
Simon Knott 837abfbc15
chore: document indexeddb type as "unknown" (#34944) 2025-02-27 14:29:22 +01:00
Simon Knott 10fc0ef221
chore: make indexeddb opt-in (#34942) 2025-02-27 14:27:54 +01:00
Pavel Feldman 58db3f7e3f
chore: restore pr title in html report (#34937) 2025-02-26 19:22:31 -08:00
Henrik Skupin a803e6053a
chore(bidi): use fractional coordinates for pointerAction (#34929) 2025-02-26 16:28:14 -08:00
Yury Semikhatsky b5fe029c1b
chore: remove failOnStatusCode from Browser.newContext, rename (#34936) 2025-02-26 15:03:21 -08:00
Pavel Feldman cd23a224f6
chore: another iteration on gitCommit/gitDiff props (#34926) 2025-02-26 08:40:30 -08:00
Simon Knott 17c4d8e5ec
chore: change generated filename for toMatchAriaSnapshot from .yml to .snapshot.yml (#34931)
Signed-off-by: Simon Knott <info@simonknott.de>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Dmitry Gozman <dgozman@gmail.com>
2025-02-26 16:29:56 +01:00
Simon Knott a04a93c1fd
chore: change pageSnapshot extension to .snapshot.yml (#34930) 2025-02-26 14:27:17 +01:00
Dmitry Gozman 439427c14e
chore: remove stages from TestInfoImpl (#34919) 2025-02-26 10:55:02 +00:00
Yury Semikhatsky aaac9923fd
fix: disable global timeout when debugging (#34922) 2025-02-25 11:33:15 -08:00
Pavel Feldman 411f938296
chore: clean up git commit metadata props and UI (#34867) 2025-02-25 09:21:17 -08:00
Dmitry Gozman b148cbad76
fix: remove unicode soft hyphen in normalizeWhitespace (#34920) 2025-02-25 16:54:02 +00:00
Simon Knott a9bbf4b56d
docs: recommend localhost over 127.0.0.1 (#34918) 2025-02-25 15:40:38 +01:00
Simon Knott 9e38473309
fix(runner): hide APIResponse.* calls from results (#34909) 2025-02-25 14:26:54 +01:00
Dmitry Gozman 81855d11e4
chore: add playwright-client to the list of packages (#34916) 2025-02-25 13:23:38 +00:00
Dmitry Gozman ed0bf35435
feat: locator.visible (#34905) 2025-02-25 11:48:15 +00:00
Yury Semikhatsky 9b633ddd2f
docs: touch events guide improvements (#34903) 2025-02-24 14:13:27 -08:00
Vitaliy Potapov c4be54b45c
Docs: improve docs and tests for URL glob pattern (#34899) 2025-02-24 12:22:24 -08:00
Simon Knott 1a8f00c45f
fix: don't wrap button contents in two lines (#34887) 2025-02-24 12:15:21 -08:00
Yury Semikhatsky dbbdabfd1b
chore: pass JSHandles instead of ObjectId to/from context delegate (#34895) 2025-02-24 12:11:17 -08:00
Yury Semikhatsky 954457ba9e
chore: fix firefox tests after switching to context delegate (#34898) 2025-02-22 17:12:39 -08:00
Yury Semikhatsky e091baad79
chore: make execution context delegate public (#34894) 2025-02-21 18:27:24 -08:00
Yury Semikhatsky e38099ef13
chore: getProperties can use context stored in JSHandle (#34893) 2025-02-21 17:55:02 -08:00
Yury Semikhatsky 1af59ee523
chore(bidi): do not leak utility handles (#34892) 2025-02-21 17:44:33 -08:00
Yury Semikhatsky 962a752832
chore: contain remote objects to browser-specific code (#34890) 2025-02-21 16:52:39 -08:00
Yury Semikhatsky 6486ac006e
chore: initialize utility script privately (#34812) 2025-02-21 13:59:55 -08:00
Pavel Feldman 325fe71bb9
chore: minor html report polish (#34864) 2025-02-21 13:49:23 -08:00
Yury Semikhatsky 65910c4ac5
test: unskip "should preserve cookie order from Set-Cookie header" (#34888) 2025-02-21 10:04:01 -08:00
Max Schmitt 132d93151c
test: replace setTimeout with builtinSetTimeout in UI mode test (#34885) 2025-02-21 07:38:24 -08:00
Max Schmitt af61d659cb
chore: fix roll_browser script (#34886) 2025-02-21 07:37:52 -08:00
Playwright Service 0bb5925d0d
feat(chromium): roll to r1160 (#34884)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Max Schmitt <max@schmitt.mx>
2025-02-21 15:40:18 +01:00
Max Schmitt 428f196036
test: have typed RunResult.results (#34883) 2025-02-21 14:22:59 +01:00
Simon Knott 48fb536e12
chore(screenshot): warn about visibility of masked elements (#34881) 2025-02-21 13:52:44 +01:00
Sang Nguyen e4ceac8e4c
docs: correct closing tags for option elements in HTML examples (#34874) 2025-02-21 09:38:47 +01:00
Adam Gastineau c64f0ffa1d
chore: manually add exception for esbuild vulnerability (#34875) 2025-02-20 14:47:44 -08:00
Adam Gastineau 33c0a1b0ca
chore: add floating promise warning to hooks (#34861) 2025-02-20 10:46:49 -08:00
Simon Knott bb8e914294
feat(ui): collapse repeating console lines (#34857) 2025-02-20 14:48:20 +01:00
Playwright Service e43d287d8d
feat(webkit): roll to r2140 (#34866)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-20 11:15:46 +01:00
Simon Knott aca3fb275b
fix(runner): validate config.tsconfig (#34849) 2025-02-20 09:11:50 +01:00
Pavel Feldman d5adeb3cf4
chore: build a client bundle (#34847) 2025-02-19 15:27:00 -08:00
Simon Knott 1f1e2acf9b
chore: rename prompt button (#34851) 2025-02-19 14:32:58 -08:00
Adam Gastineau f5b8cca1eb
feat: Warn on floating promises (#34845) 2025-02-19 10:11:04 -08:00
Max Schmitt 3584e72223
chore: remove 'as *' imports because of esModuleInterop: true (#34854) 2025-02-19 15:32:12 +01:00
Simon Knott a3e8788b9c
chore: hide llm chat (#34852) 2025-02-19 14:14:18 +01:00
Max Schmitt 7f7ab96893
chore: fix tsc linting error (#34853) 2025-02-19 12:18:42 +01:00
Playwright Service dcb9ed8d41
feat(webkit): roll to r2139 (#34850)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-19 11:11:40 +01:00
Playwright Service 0baadb513b
feat(chromium-tip-of-tree): roll to r1304 (#34842)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-18 16:24:09 +01:00
Bedřich Schindler 741a7079fe
docs(ct): add brief information about CSS modules into FAQ (#34677) 2025-02-18 06:44:09 -08:00
Max Schmitt 081031f50e
chore: bump vite to v6 (#34663) 2025-02-18 13:29:16 +01:00
Max Schmitt 1af4e367f4
fix(testServer): pass use options to listFiles command (#34832) 2025-02-18 00:33:45 +01:00
Playwright Service 715123afbe
feat(firefox-beta): roll to r1471 (#34796)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-17 10:04:32 +01:00
Playwright Service 060ef5562d
feat(webkit): roll to r2138 (#34814)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-17 09:34:16 +01:00
Max Schmitt 605eb0d657 Revert "devops: migrate away from merge.config.ts (#34802)"
This reverts commit df6e3f043a.
2025-02-17 09:33:20 +01:00
Pavel Feldman f70f92d5cd
chore: do not use process in client (#34816) 2025-02-15 19:49:30 -08:00
Pavel Feldman 3606a434fe
chore: pass validator into validator context (#34810) 2025-02-15 08:28:28 -08:00
Pavel Feldman 024a52821a
chore: init eventEmitter w/ platform (#34809) 2025-02-14 17:06:11 -08:00
Yury Semikhatsky 145b6bf4fe
chore: browser independent setInputFiles implementation (#34808) 2025-02-14 16:44:27 -08:00
Pavel Feldman 8b28e637c8
chrome: remove state from isomorphic utils (#34795) 2025-02-14 15:10:50 -08:00
Yury Semikhatsky be95a08c4d
feat(webkit): roll to r2137, update tests (#34806) 2025-02-14 11:25:35 -08:00
Simon Knott fe0b327770
feat(ui): llm conversation about error (#34750) 2025-02-14 16:59:26 +01:00
Max Schmitt df6e3f043a
devops: migrate away from merge.config.ts (#34802) 2025-02-14 11:58:37 +01:00
Dmitry Gozman e6b405c012
chore: show gha pull request title instead of a merge commit (#34781) 2025-02-14 09:32:06 +00:00
Playwright Service 32c299c89d
feat(chromium): roll to r1159 (#34780)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Max Schmitt <max@schmitt.mx>
2025-02-14 09:33:55 +01:00
Playwright Service e276d92dd3
feat(chromium-tip-of-tree): roll to r1303 (#34783)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-14 09:33:27 +01:00
Pavel Feldman 7f742a04b0
chore: make client compile for web (#34792) 2025-02-13 18:33:17 -08:00
Pavel Feldman 4a9b336168
chore: for not use Node's events in client (#34791) 2025-02-13 16:46:24 -08:00
Yury Semikhatsky 6833b664e3
test: update modernizr expectations with actual mobile Safari 18.3 values (#34789) 2025-02-13 16:37:15 -08:00
Pavel Feldman 163aacf4b6
chore: allow client operation w/o local utils (#34790) 2025-02-13 16:15:11 -08:00
Pavel Feldman 90ec838318
chore: move zones into platform (#34786) 2025-02-13 13:06:03 -08:00
Pavel Feldman 9ecf2f69ba
chore: move pipe transport utils to server/ (#34787) 2025-02-13 12:30:53 -08:00
Yury Semikhatsky e03402f7a7
chore(bidi): implement setInputFile(FilePayload) (#34785) 2025-02-13 12:11:05 -08:00
Playwright Service 5028fb6270
chore(driver): roll driver to recent Node.js LTS version (#34776)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-13 12:09:18 +01:00
Playwright Service ea67eca5be
feat(webkit): roll to r2134 (#34754)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-13 10:05:41 +01:00
Pavel Feldman ded909c13f
chrome: restore colors enabled/levels logic (#34767) 2025-02-12 21:13:25 -08:00
Pavel Feldman 3d760b657b
chore: move debug, env and user agent from utils/ (#34766) 2025-02-12 19:27:24 -08:00
Yury Semikhatsky 6951e6ad9d
chore(bidi): move private handle conversion to execution context (#34765) 2025-02-12 18:14:39 -08:00
Yury Semikhatsky bab197b493
test: adjust bidi browser name in browsertype-connect.spec (#34758) 2025-02-12 18:04:42 -08:00
Pavel Feldman e697b1a663
chore: remove stackTrace => path dependency (#34763) 2025-02-12 18:03:23 -08:00
Pavel Feldman c31ce783b7
chore: move event utils to server (#34761) 2025-02-12 15:22:10 -08:00
Pavel Feldman 0eeba380f2
chore: move crypto to server/util/ (#34759) 2025-02-12 14:43:52 -08:00
Yury Semikhatsky c2c336b97d
chore(bidi): implement setInputFiles (#34757) 2025-02-12 12:49:05 -08:00
Yury Semikhatsky 0bd3a99f04
tests: put filechooser and setInputFiles tests into separate files (#34756) 2025-02-12 12:28:19 -08:00
Yury Semikhatsky 148af21540
chore(bidi): implement getOwnerFrame (#34755) 2025-02-12 10:53:03 -08:00
Pavel Feldman f54478a23e
chore: move utils that are user in server to server/utils (3) (#34739) 2025-02-12 09:34:01 -08:00
Yury Semikhatsky 703ca9f851
Revert "chore(bidi): use fractional coordinates for pointerAction (#3… (#34753) 2025-02-12 09:00:01 -08:00
Dmitry Gozman 8eb816b363
fix(trace): do not save trace on failure after success in test+hooks (#34724) 2025-02-12 15:41:16 +00:00
Simon Knott 1ad7aad5fb
fix: prompt should mention contents (#34746) 2025-02-12 15:44:45 +01:00
Adam Gastineau 0501f8c132
chore(html-report): make scrollbar gutter stable (#34732) 2025-02-12 05:55:36 -08:00
Simon Knott b7785e1662
feat(runner): enable gitCommitInfo by default on GH Actions (#34743) 2025-02-12 14:51:00 +01:00
Dmitry Gozman 3e976e9f10
chore(chromium): re-enable PlzDedicatedWorker feature (#34400) 2025-02-12 13:22:35 +00:00
Max Schmitt c052627138
fix: allow empty userDataDir (#34730) 2025-02-12 14:21:57 +01:00
Pavel Feldman bd74fc4964
chore: move utils that are user in server to server/utils (2) (#34736) 2025-02-11 17:19:27 -08:00
Pavel Feldman 25a168fae5
chore: move utils that are user in server to server/utils (1) (#34734) 2025-02-11 15:40:41 -08:00
Yury Semikhatsky 934600b24b
test: reenable 2 screenshot tests on wk mac (#34735) 2025-02-11 15:21:15 -08:00
Yury Semikhatsky 6004865ee5
chore(tests): respect BIDIPATH in browsertype-connect.spec.ts (#34733) 2025-02-11 14:03:16 -08:00
JacksonLei123 5a76b17c87
feat: add failOnStatusCode option to API request context (#34346) 2025-02-11 13:23:11 -08:00
Pavel Feldman 46b048f018
chore: vendor stack utils (#34719) 2025-02-11 12:53:08 -08:00
Yury Semikhatsky 8e51be9069
chore(bidi): use fractional coordinates for pointerAction (#34675) 2025-02-11 12:09:48 -08:00
Simon Knott 8ed2f4319e
chore: add pageSnapshot option (#34669) 2025-02-11 11:04:57 -08:00
Udaiveer Pradhan d2e7e8acdb
fix(ui-mode): Watch mode button doesn't show active when test selected (#34581) 2025-02-11 10:32:39 -08:00
Playwright Service 3ae39166c2
feat(chromium-tip-of-tree): roll to r1302 (#34726)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-11 17:40:52 +01:00
Max Schmitt 416c9b3368
fix: allow relative userDataDir (#34710) 2025-02-11 17:40:00 +01:00
Pavel Feldman 72cd6f06aa
chore: prework for web ws connection (#34718) 2025-02-11 08:28:28 -08:00
Adam Gastineau 91f46bb5d0
chore(html-report): clean up git metadata display (#34713) 2025-02-11 05:16:46 -08:00
dependabot[bot] 6704370c3f
chore(deps-dev): bump esbuild from 0.18.20 to 0.25.0 (#34721)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-11 12:27:59 +01:00
Simon Knott 2eb6cbe357
chore: improve fix test prompt (#34709) 2025-02-11 08:40:46 +01:00
Pavel Feldman 51f944d16a
chore: extract pipe->connection code (#34689) 2025-02-10 15:04:33 -08:00
Pavel Feldman 2718ce7cbf
chore: short-cut localUtils usage in JS client (#34690) 2025-02-10 14:19:58 -08:00
Adam Gastineau ad6444e14c
chore(test): perform action to guarantee URL updates (#34714) 2025-02-10 12:57:25 -08:00
Adam Gastineau aeed1f5909
fix(runner): display no projects error across all test modes (#34676) 2025-02-10 12:52:53 -08:00
Playwright Service 71c7f465a0
feat(webkit): roll to r2132 (#34697) 2025-02-10 11:36:45 -08:00
Pavel Feldman 5d500dde22
chore: introduce platform for client (1) (#34683) 2025-02-10 10:22:32 -08:00
Simon Knott 0672f1ce67
feat(ui): "fix with ai" button (#34708) 2025-02-10 17:47:27 +01:00
Simon Knott 2f8d448dbb
feat(html): "copy prompt" button (#34670) 2025-02-10 15:02:19 +01:00
Max Schmitt 703e077f4b
chore: fix recorder tsconfig linting (#34704) 2025-02-10 13:23:04 +01:00
Priyanshi Saxena 76b7b52c34
docs: source section doc updated (#34627)
Co-authored-by: ankursaxena17 <32309836+ankursaxena17@users.noreply.github.com>
2025-02-10 12:22:53 +00:00
Max Schmitt 967c4f5e3b
chore: fix Locator type issues (#34705) 2025-02-10 13:05:17 +01:00
Playwright Service 4c8af0128f
feat(chromium): roll to r1158 (#34702)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Max Schmitt <max@schmitt.mx>
2025-02-10 12:33:37 +01:00
Playwright Service a95186a373
feat(firefox): roll to r1475 (#34695)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-10 09:12:50 +01:00
Playwright Service f11ed1beab
feat(chromium-tip-of-tree): roll to r1301 (#34696)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-10 09:12:07 +01:00
Pavel Feldman 88c01434c6
chore: fix locator type check (#34682) 2025-02-07 14:53:28 -08:00
Pavel Feldman d5d47f2b6e
chore: organize imports in packages (#34681) 2025-02-07 14:44:00 -08:00
Pavel Feldman 4a7f6a6ef0
chore: organize imports in playwright-core (#34680) 2025-02-07 13:54:01 -08:00
Adam Gastineau 4bc8cf0d47
feat(recorder): display primary page URL in recorder title (#34637) 2025-02-07 12:05:04 -08:00
Simon Knott 893e7bbf3b
chore: add _browserTypes helpers to playwright (#34611) 2025-02-07 15:43:08 +01:00
Max Schmitt 9e433060fe
test: keep testing React 18 (#34671) 2025-02-07 12:24:53 +01:00
Simon Knott bc8d6ce344
feat: provide commit diff to HTML reporter (#34653)
Signed-off-by: Simon Knott <info@simonknott.de>
Co-authored-by: Max Schmitt <max@schmitt.mx>
2025-02-07 10:39:08 +01:00
Simon Knott fd24521f2e
chore: add page snapshot on test end (#34573)
Signed-off-by: Simon Knott <info@simonknott.de>
Co-authored-by: Yury Semikhatsky <yurys@chromium.org>
2025-02-07 09:02:20 +01:00
Pavel Feldman 7da3be4a1a
chrome: update eslint 9 (#34666) 2025-02-06 19:48:27 -08:00
Henrik Skupin 6fddefde81
chore(bidi): pointerMove action needs to floor fractional values for x and y position (#34191) 2025-02-06 16:17:50 -08:00
Max Schmitt 8accb0ad1b
test: change ct-vite projects to type: module (#34662) 2025-02-06 23:11:06 +01:00
Yury Semikhatsky 34d9d4fc33
chore(html-report): show run duration for each retry (#34647) 2025-02-06 13:30:25 -08:00
Yury Semikhatsky 3d3154de86
chore(tracing): look up snapshot resources only in the same context (#34645) 2025-02-06 12:38:51 -08:00
Max Schmitt 427d7a22ea
Revert "chore: tidy up headless-shell hacks (#33967)" (#34659) 2025-02-06 19:17:20 +01:00
Simon Knott 902e83fe87
fix: allow opt out from IndexedDB in storagestate (#34650) 2025-02-06 16:40:14 +01:00
Dmitry Gozman 8d751cfe50
fix(fetch): filter out undefined params (#34654) 2025-02-06 15:16:45 +00:00
Simon Knott 365f411548
test(storageState): IndexedDB with keyPath (#34648) 2025-02-06 12:39:19 +01:00
Simon Knott 2b5493219b
chore: document typed array limitation (#34649) 2025-02-06 12:39:07 +01:00
Simon Knott 1c7436ec2f
chore: remove dead code (#34651) 2025-02-06 11:39:10 +01:00
Simon Knott 7aac96d780
chore: add encoded versions of IndexedDB key/value (#34630) 2025-02-06 09:48:30 +01:00
Pavel Feldman 11e1b8f30a
chore: fallback to the original code after babel transform (#34635) 2025-02-05 14:03:31 -08:00
Yury Semikhatsky 7f09ba7fa4
feat: step.attach() (#34614) 2025-02-05 12:27:44 -08:00
Pavel Feldman 4b64c47a25
chore: use explicit matcher call context (#34620) 2025-02-05 10:57:33 -08:00
Playwright Service 25ef2f1344
feat(webkit): roll to r2130 (#34631) 2025-02-05 09:05:10 -08:00
Yury Semikhatsky f1a392f844
chore: do not store empty step.attachments[] in trace (#34579) 2025-02-05 08:30:03 -08:00
Adam Gastineau cb208836b5
fix: display error when project is not found (#34577) 2025-02-05 06:58:02 -08:00
Adam Gastineau 50f22f13a4
docs: document config executing multiple times (#34576) 2025-02-05 06:10:32 -08:00
Simon Knott 311625b891
feat: recreate IndexedDB in storagestate (#34591) 2025-02-05 15:01:53 +01:00
Yury Semikhatsky fb3e8ed114
fix: reset APIRequestContext network trace between chunks (#34616) 2025-02-05 08:00:04 +00:00
Playwright Service 11913e6f39
feat(webkit): roll to r2127 (#34599) 2025-02-04 17:03:14 -08:00
Atsushi Kawamura (atzz/a2c) dc14490f13
docs: remove unnecessary hyphens in CircleCI's sharding example (#34609) 2025-02-04 15:38:39 +00:00
Playwright Service 50e1a8b55b
feat(chromium-tip-of-tree): roll to r1300 (#34610)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-04 16:06:35 +01:00
Simon Knott 5d82567346
feat: emulate prefers-contrast (#34494) 2025-02-04 11:15:51 +01:00
Max Schmitt 96d4dc1eda
docs: add backlink from WebSocket to WebSockeRoute (#34600) 2025-02-03 19:42:38 +01:00
Yury Semikhatsky f11f4a8477
docs: breaking changes in java 1.50 (#34601) 2025-02-03 09:39:33 -08:00
Adam Gastineau 5996a0df0a
Revert "Revert "chore(docs): clarify connection method via BrowserType.connect (#34560)" (#34594)" (#34595) 2025-02-03 06:21:00 -08:00
Max Schmitt 340834195b
docs: v1.50 release notes for ports (#34592)
Signed-off-by: Max Schmitt <max@schmitt.mx>
Co-authored-by: Simon Knott <info@simonknott.de>
2025-02-03 15:17:19 +01:00
Max Schmitt 3d5f85d7e4
Revert "chore(docs): clarify connection method via BrowserType.connect (#34560)" (#34594) 2025-02-03 14:24:33 +01:00
Simon Knott ebf82b0854
test: ensure that attachments are available in onStepEnd (#34590) 2025-02-03 13:54:28 +01:00
Max Schmitt 4e2d82e6c2
test: add test for color input click behavior (#34156) 2025-02-03 13:30:54 +01:00
Playwright Service 36478f250a
feat(firefox): roll to r1474 (#34587)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-03 12:04:12 +01:00
Playwright Service 162182b714
feat(firefox-beta): roll to r1470 (#34589)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-03 10:47:37 +01:00
Yury Semikhatsky cd7f3b6e65
devops: validate js code snippets in flint (#34580) 2025-01-31 16:52:55 -08:00
Yury Semikhatsky a1451c75f8
feat: conditional step.skip() (#34578) 2025-01-31 15:45:57 -08:00
Yury Semikhatsky da12af24c2
chore: harden trace file regex (#34563) 2025-01-31 15:34:53 -08:00
Playwright Service 399ba91150
feat(chromium-tip-of-tree): roll to r1299 (#34569)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-31 19:35:12 +01:00
Playwright Service 64f8689a81
feat(chromium): roll to r1157 (#34571)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-31 13:15:40 +01:00
GeneratorX16 4fa1d39c80
fix: Reverse Lumia 550 and Lumia 550 Landscape viewports (#34548) 2025-01-30 13:57:43 -08:00
Adam Gastineau 1936cfa6c3
chore(docs): clarify connection method via BrowserType.connect (#34560) 2025-01-30 12:31:59 -08:00
Debbie O'Brien d288fbcc41
docs: Improve aria snapshots documentation clarity and examples (#34509)
Signed-off-by: Debbie O'Brien <debs-obrien@users.noreply.github.com>
Co-authored-by: Dmitry Gozman <dgozman@gmail.com>
2025-01-30 20:07:48 +00:00
Dmitry Gozman ab62ef2dbb
fix(toMatchAriaSnapshot): fail test run when updating missing snapshot (#34556) 2025-01-30 19:18:07 +00:00
Adam Gastineau 5afb04b62e
fix(ui): add proper CORS header for loading traces in HMR mode (#34558) 2025-01-30 09:20:43 -08:00
Max Schmitt 833c729eb0
docs: roll follow-ups for .NET and Python (#34550) 2025-01-30 12:06:56 +01:00
Pavel Feldman eff5cd6dbb
fix(aria): disregard text area textContent (#34544) 2025-01-29 16:06:07 -08:00
Pavel Feldman 4b5b326478
chore: do not show steps in line reporter without tty (#34529) 2025-01-29 12:41:09 -08:00
Adam Gastineau f15171bcf0
fix(ui): don't display "Timed Out" when executing action (#34541) 2025-01-29 12:39:05 -08:00
Dmitry Gozman ba650161a8
feat: per-assertion snapshot path template in config (#34537) 2025-01-29 18:47:20 +00:00
Playwright Service b552637ee0
feat(chromium-tip-of-tree): roll to r1298 (#34540)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-29 18:29:23 +01:00
Dmitry Gozman 24f06ec1bf
feat(html report): show metadata (#34517) 2025-01-29 16:22:50 +00:00
Max Schmitt 6c2c90203e
devops(gha): allow workflow_dispatch in roll browser script (#34531)
Signed-off-by: Max Schmitt <max@schmitt.mx>
Co-authored-by: Dmitry Gozman <dgozman@gmail.com>
2025-01-29 17:16:50 +01:00
Dmitry Gozman 7d8265e610
Revert "Reapply "fix(har timing): record connect timing for proxied connections" (#32855) (#33003)" (#34535) 2025-01-29 14:51:31 +00:00
Andrey Lushnikov b419527aab
fix(firefox): disable fetch keep-alive for now before a proper fix (#34530) 2025-01-29 09:50:32 +00:00
Pavel Feldman 931b9f28cd
fix(codegen): attribute navigation to press/fill (#34528) 2025-01-28 17:59:16 -08:00
Pavel Feldman 391e9c4de0
fix(recorder): do not reset inspect highlight on inactivity (#34526) 2025-01-28 16:00:28 -08:00
Pavel Feldman 7060cd1bf7
chore: allow repetative application of rebaselines in the same session (#34524) 2025-01-28 14:37:47 -08:00
Pavel Feldman 7fd0c3e254
fix: follow the pseudo attr value in firefox computed style (#34525) 2025-01-28 14:37:04 -08:00
Danilo Akamine b27945d045
docs: remove duplicate reference (#34513) 2025-01-28 22:33:04 +01:00
Dmitry Gozman 7fc252fffc
test: fetch request through socks proxy over ipv4 (#34522) 2025-01-28 17:05:12 +00:00
Adam Gastineau 63f96efbe0
feat(trace-viewer): display query string in network tab (#34505) 2025-01-28 05:19:30 -08:00
Vitaliy Potapov 61d595ae48
feat: add new config prop populateGitInfo (#34329)
Co-authored-by: Yury Semikhatsky <yurys@chromium.org>
2025-01-28 07:54:31 +00:00
Pavel Feldman cea5dad686
chore: remove eslint-plugin-internal-playwright (#34510) 2025-01-27 20:13:27 -08:00
Pavel Feldman ab01dccf9d
chore: clean up tool example (#34512) 2025-01-27 20:13:18 -08:00
Pavel Feldman 2c0576ea76
chore: mark tools package as private (#34511) 2025-01-27 15:32:45 -08:00
Pavel Feldman bd2fdd0f20
chore: land experimental tools (#34503) 2025-01-27 14:49:38 -08:00
ReaZzy eaaef29dbd
fix: add validations to --shard cli parameter (#34463) (#34479) 2025-01-27 14:31:14 -08:00
Henrik Skupin d63907fc5b
chore(bidi): Disable some external services for Firefox (#34492) 2025-01-27 13:17:03 -08:00
Max Schmitt bc1a8c2191
test: add test for fetch with keepalive: true on Firefox (#34498) 2025-01-27 15:39:59 +01:00
Max Schmitt 8d716b28a1
chore(bidi): use full test title in CSV expectations (#34496) 2025-01-27 14:17:47 +01:00
Max Schmitt 52580d640d
Revert "fix(ci): Prevent workflows from automatically running on forks (#34408)" (#34488) 2025-01-27 14:03:19 +01:00
Dmitry Gozman 640e6a8aa7
chore: remove unused headers (#34491) 2025-01-27 09:58:19 +00:00
Pavel Feldman 245f4b5b86
fix: allow changed to be passed in config (#34473) 2025-01-24 15:42:58 -08:00
Playwright Service 3d9a9d2405
feat(firefox): roll to r1472 (#34455) 2025-01-24 15:17:14 -08:00
Playwright Service c815d090bc
feat(firefox-beta): roll to r1468 (#34454) 2025-01-24 15:16:18 -08:00
Alexandra Borovova 2afe287a81
Add canonical screenshots for firefox with webdriver bidi for screenshot element tests (#34289) 2025-01-24 15:15:24 -08:00
Yury Semikhatsky fb145d5ebd
test: do not check deprecated KeyboardEvent.keyCode property (#34472) 2025-01-24 15:09:39 -08:00
Adam Gastineau fccb2b0784
chore: fix codegen SIGINT test (#34468) 2025-01-24 14:21:42 -08:00
Henrik Skupin 9d91d7a1e9
chore(firefox): Don't upgrade HTTP requests to HTTPS (#34465) 2025-01-24 13:36:23 -08:00
Adam Gastineau b39c29d096
docs: remove toMatchAriaSnapshot path feature (#34471) 2025-01-24 21:16:58 +01:00
Yury Semikhatsky dcff914040
chore(bidi): make browserType.connect work (#34461) 2025-01-24 09:09:57 -08:00
Adam Gastineau c44590aa5b
chore: disable popover test on Darwin 13.7 WebKit (#34466) 2025-01-24 08:27:06 -08:00
Playwright Service bbd55587e4
feat(chromium): roll to r1156 (#34464)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-24 15:40:46 +01:00
Adam Gastineau f65dc0cee4
feat: toHaveURL predicate matcher (#34413) 2025-01-24 06:00:17 -08:00
Yury Semikhatsky f11768436a
chore: revert inadvertent test change (#34459) 2025-01-23 12:12:53 -08:00
Pavel Feldman bfb79990da
docs: issue guide (#34457) 2025-01-23 12:12:13 -08:00
Pavel Feldman 039f513744
docs: auto generate evaluate usage docs (#34458) 2025-01-23 12:11:54 -08:00
Playwright Service 04c03b998a
feat(webkit): roll to r2125 (#34453)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-23 18:37:42 +01:00
Playwright Service 2cf6153d9f
feat(chromium-tip-of-tree): roll to r1297 (#34451)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-23 16:40:15 +01:00
Debbie O'Brien 900382540a
docs: add --update-source-method option for snapshot updates in test-cli-js (#34448) 2025-01-23 14:17:23 +00:00
Dmitry Gozman ab3b4b8cd0
fix(test runner): respect updateSourceMethod from the config (#34442) 2025-01-23 12:11:26 +00:00
Playwright Service a9609ed6f2
chore(driver): roll driver to recent Node.js LTS version (#34440) 2025-01-23 11:30:12 +01:00
Henrik Skupin 34cb35859a
chore(bidi): simplify launcher tests for Firefox (#34405) 2025-01-22 13:06:24 -08:00
Adam Gastineau a06600aee9
chore: roll stable-test-runner to: 1.50.0-beta-1737557690000 (#34433) 2025-01-22 12:46:25 -08:00
Adam Gastineau a121f85ce9
chore: update browser patches to 2e93a0b95 (#34426) 2025-01-22 09:56:34 -08:00
Adam Gastineau 256dc47833
docs: switch gracefulShutdown to primarily mention SIGTERM and add Docker comment (#34430) 2025-01-22 09:49:34 -08:00
Max Schmitt 85e41f5b65
docs: update README for flakiness dashboard function update (#34424) 2025-01-22 16:33:19 +01:00
Adam Gastineau b75fc4c547
fix(ci): Prevent workflows from automatically running on forks (#34408) 2025-01-22 07:05:34 -08:00
Adam Gastineau 7e97e01505
docs: release notes for v1.50 js (#34380) 2025-01-22 06:20:24 -08:00
Adam Gastineau 49b3bbb920
docs: release notes for v1.50 js (#34380) 2025-01-22 06:17:54 -08:00
dependabot[bot] a689e534ac
chore(deps): bump vite from 5.4.6 to 5.4.14 (#34420)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-22 14:23:05 +01:00
dependabot[bot] 214b103b46
chore(deps-dev): bump undici from 5.28.4 to 5.28.5 (#34419)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-22 15:52:00 +03:00
Dmitry Gozman cf90c0f122
fix(aria snapshot): make rebase work when options are specified (#34409) 2025-01-22 07:53:53 +00:00
Playwright Service cf3bcd7d4a
feat(chromium-tip-of-tree): roll to r1296 (#34414)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-22 08:21:47 +03:00
Tasawar Hussain 6234c3b15e
docs: update test-fixtures-js.md (#34399) 2025-01-21 13:50:33 -08:00
Dmitry Gozman 888feb06be
fix(list reporter): do not break after output without trailing eol (#34410) 2025-01-21 18:30:09 +00:00
Dmitry Gozman 333e994e7d
fix(step.skip): show a skipped indicator in UI mode (#34407) 2025-01-21 18:28:41 +00:00
Dmitry Gozman e20b6d1617
feat(chromium-tip-of-tree): roll to r1295 (#34372) 2025-01-20 16:28:41 +00:00
Simon Knott 99fb188cb4
chore: move attachment link back to tree item, make it flash yellow (#34353) 2025-01-20 09:06:01 +01:00
Max Schmitt 86768b9ebc
test: add test for consistent hyphen rendering in headless/headed (#34159) 2025-01-18 19:04:56 +03:00
Yury Semikhatsky 372d4196d7
chore: step timeout improvements (#34386) 2025-01-17 21:15:47 -08:00
Pavel Feldman 9970446f51
chore: remove toMatchAriaSnapshot.path (#34379) 2025-01-17 14:35:15 -08:00
Henrik Skupin d082805ea9
chore(bidi): disable thottling of background tabs in Firefox (#34381) 2025-01-17 14:29:26 -08:00
Adam Gastineau 3c160df06a
chore: mark v1.51.0-next (#34382) 2025-01-17 12:34:59 -08:00
Pavel Feldman 1b21ec9cd8
chore: remove --save-trace codegen option (#34362) 2025-01-17 10:17:49 -08:00
Pavel Feldman b339d457e3
chore: dogfood jest-style aria snapshots (#34365) 2025-01-17 10:17:26 -08:00
Dmitry Gozman 07bcbcd1b4
feat(chromium): roll to r1155 (#34371) 2025-01-17 10:45:58 +00:00
Yury Semikhatsky 40b92eaf2a
docs: remove toMatchAriaSnapshot({path}) from language ports (#34363) 2025-01-16 16:56:13 -08:00
Yury Semikhatsky 5438814975
chore: do not fall back to previous LTS release deps for new Ubuntu LTS (#34360) 2025-01-16 15:20:40 -08:00
Yury Semikhatsky 587e778a5a
Revert "feat(aria): extend toHaveAccessibleName() to accept an array … (#34361) 2025-01-16 15:04:56 -08:00
Pavel Feldman 3cf0461a1a
chore: fix the scrollable locator tab (#34358) 2025-01-16 13:20:20 -08:00
Adam Gastineau 84bbc5fd35
feat(trace-viewer): Render context string for most actions (#34292) 2025-01-16 11:48:34 -08:00
Dmitry Gozman be6caed8df
chore: remove expectZone (#34312) 2025-01-16 18:53:32 +00:00
Pavel Feldman 08af3a2f06
chore: do not cache highlight agressively (#34349) 2025-01-16 08:27:48 -08:00
Yury Semikhatsky 00bb17751b
chore: delete recorder in traceviewer experiment (#34347) 2025-01-15 17:37:33 -08:00
Yury Semikhatsky 8d39c44b69
docs: improve toHaveClass paramter description (#34345) 2025-01-15 14:38:34 -08:00
Yury Semikhatsky 07f425434d
chore(bidi): support ControlOrMeta key (#34341) 2025-01-15 13:23:44 -08:00
Yury Semikhatsky 224d7bf847
fix(docker): install gpg on slim images (#34340) 2025-01-15 12:03:19 -08:00
Dmitry Gozman 4d55d3039a
chore: better error message when CSS selector fails to parse (#34331) 2025-01-15 11:34:51 -08:00
Dmitry Gozman aeec0c0e36
fix(test runner): esm loader in old Node versions (#34330) 2025-01-15 14:45:10 +00:00
Yury Semikhatsky 275f334b58
chore(step): remove step.fail and step.fixme, add step.skip (#34326) 2025-01-14 17:43:47 -08:00
Julian Descottes 0869195ba4
chore(bidi): Stop dividing BiDi network event timings by 1000 (#34324) 2025-01-14 15:27:49 -08:00
Yury Semikhatsky 8699d3b9c5
test(bidi): create inspected page before initializing recorder (#34323) 2025-01-14 14:57:42 -08:00
Pavel Feldman b0f0a2951a
docs: improve aria overload docs (#34319) 2025-01-13 18:25:57 -08:00
Pavel Feldman ad365c3bc3
chore: include child nodes when parsing snapshot (#34318) 2025-01-13 18:25:41 -08:00
Pavel Feldman fe96104ce2
docs: clarify updateSourceMethod (#34314) 2025-01-13 18:25:32 -08:00
Rui Figueira 9a9d22af44
feat(codegen): include framePath in jsonl format (#34310) 2025-01-13 17:32:26 -08:00
Playwright Service dfe80bb888
feat(firefox): roll to r1471 (#34309) 2025-01-13 17:26:26 -08:00
Yury Semikhatsky 2b2e84971f
chore(bidi): use original key name when computing bidi value (#34317) 2025-01-13 17:22:00 -08:00
Playwright Service d2e7ad38d5
feat(firefox-beta): roll to r1467 (#34303) 2025-01-13 13:58:34 -08:00
Julian Descottes 454b6f938d
test(bidi): Update browserName used for har file tests when using bidi (#34313) 2025-01-13 13:56:00 -08:00
Playwright Service 6b73ec6092
feat(webkit): roll to r2123 (#34260) 2025-01-13 13:53:18 -08:00
Zachary Blackwood f74a4d55cd
Fix typo "fore" -> "for" (#34315) 2025-01-13 12:30:19 -08:00
Simon Knott a33659f2a8
chore: move attachments link to step body (#34196) 2025-01-13 10:07:54 +01:00
Playwright Service 19c935cde7
feat(firefox): roll to r1470 (#34304) 2025-01-13 09:05:33 +03:00
Pavel Feldman 6179b5b1d7
chore: allow matching aria snapshot in trace viewer (#34302) 2025-01-11 10:14:21 -08:00
Pavel Feldman 0c8a6b80fb
chore: consolidate aria parser in isomorphic bundle (#34298) 2025-01-10 15:32:35 -08:00
Andrey Lushnikov 4bb464197f
test: unflake a few trace-viewer tests (#34299) 2025-01-10 14:57:50 -08:00
Andrey Lushnikov 2cd5003062
test: fix "should capture navigation" flakiness on firefox-headed (#34291) 2025-01-10 13:51:28 -08:00
Yury Semikhatsky 423005a7ab
chore(bidi): create parent dir for report.csv (#34294) 2025-01-10 13:43:43 -08:00
Dmitry Gozman f0a3a15e93
chore: explicitly reset apiZone instead of everything (#34265) 2025-01-10 20:15:05 +00:00
Dmitry Gozman 1f2eb499d2
fix(aria snapshots): normalize whitespace (#34285) 2025-01-10 19:31:47 +00:00
Julian Descottes 4f3a5e2133
chore(bidi): Fix handling of cookie headers in network.continueRequest (#34277) 2025-01-10 11:06:26 -08:00
Julian Descottes ca94291ab7
chore(bidi): Handle headers properly in BiDi network.continueRequest (#34268) 2025-01-10 10:15:38 -08:00
Henrik Skupin 89172175d6
Improve WebDriver BiDi key codes (#34286) 2025-01-10 09:19:28 -08:00
Adam Gastineau a2e2dfd446
feat: Enable snapshots for most remaining public commands (#34072) 2025-01-10 05:04:44 -08:00
Dmitry Gozman b32d546159
test: attempt to unflake vscode highlight tests (#34267) 2025-01-10 09:52:39 +00:00
Simon Knott 75d2661497
docs: fix android launchBrowser.pkg option (#34262) 2025-01-10 10:51:29 +01:00
Pavel Feldman 13bdd3c92f
feat(toBeChecked): allow indeterminate expectation (#34269) 2025-01-09 18:18:15 -08:00
Yury Semikhatsky 37c2569eb2
fix(inspector): do not start recording by default (#34276) 2025-01-09 14:58:41 -08:00
Yury Semikhatsky cd9d02faf9
chore: remove setAutoCloseAllowed (#34273) 2025-01-09 14:16:01 -08:00
Yury Semikhatsky 201fc48cf0
chore(bidi): write custom expectations only for timing out tests (#34270) 2025-01-09 11:10:14 -08:00
Alexandra Borovova c465e21161
chore(bidi): add missing canonical screenshots for tests running with Firefox and WebDriver BiDi (#34257) 2025-01-09 10:36:59 -08:00
Adam Gastineau 01ba528904
fix: Prepare CI to properly run Electron on ubuntu-latest (24.04) (#34238) 2025-01-09 06:34:59 -08:00
Playwright Service 9b58e4a93a
chore(driver): roll driver to recent Node.js LTS version (#34261) 2025-01-09 13:53:41 +03:00
Ben Hovinga 9f32c858e0
Fix typo (#34225) 2025-01-08 11:22:41 -08:00
Yury Semikhatsky edfbab2a79
fix: dispatch touch events in webkit (#34250) 2025-01-08 11:06:30 -08:00
Dmitry Gozman 7ee7e018fa
chore: update chrome extensions doc and tests (#34236) 2025-01-08 17:24:29 +00:00
JustasM d6d5944797
fix(ui): fix washed out dropdown colors in dark mode (#34186) 2025-01-08 06:14:22 -08:00
Adam Gastineau ada68cd6f0
feat(trace-viewer): Add setting for display canvas content in snapshots (#34010) 2025-01-08 05:08:00 -08:00
Yury Semikhatsky ff9242104b
docs: touch events emulation guide (#34201) 2025-01-07 16:47:00 -08:00
Yury Semikhatsky 6fb6282a9d
chore(bidi): propertly dispatch ControlRight key event (#34246) 2025-01-07 16:46:44 -08:00
Yury Semikhatsky 809225503c
docs: remove note about DataTrander limited availability (#34243) 2025-01-07 15:42:10 -08:00
Pavel Feldman 0d34369fc0
chore: include actual value in the elementState (#34245) 2025-01-07 15:31:18 -08:00
Yury Semikhatsky 0008816ee3
test: reenable "return empty content there is no iframe src" in cr and ff (#34241) 2025-01-07 11:49:14 -08:00
Pavel Feldman 7923d35e32
fix(retarget): do not unconditionally retarget to enclosing label (#34229) 2025-01-07 11:15:00 -08:00
Pavel Feldman 9514f0fb9d
fix(aria): escape leading dash in property values (#34227) 2025-01-07 11:14:45 -08:00
Playwright Service d2af88c1fe
feat(chromium-tip-of-tree): roll to r1293 (#34234)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-07 21:43:05 +03:00
Dmitry Gozman 63329a3471
chore: remove dependency from library on expectZone, straighten csi handling (#34211) 2025-01-07 13:30:04 +00:00
Simon Knott 527505e67b
docs: be more precise in what versions of Node.js are supported (#34231)
Signed-off-by: Simon Knott <info@simonknott.de>
Co-authored-by: Max Schmitt <max@schmitt.mx>
2025-01-07 14:23:27 +01:00
Yury Semikhatsky ec79f28ffe
chore(bidi): keep custom expectations only for timing out tests (#34228) 2025-01-06 17:36:49 -08:00
Yury Semikhatsky a9e6b51108
chore(bidi): implement query selector all ($$) method (#34226) 2025-01-06 16:37:11 -08:00
Pavel Feldman 4e8c83055f
chore: split output clients by capabilities and base dir (#34135) 2025-01-06 11:03:35 -08:00
Dmitry Gozman eeca68ba97
test: unflake some cookie tests in msedge (#34217) 2025-01-05 18:19:28 +00:00
Yury Semikhatsky 5a22475ea8
chore(bidi): fix signals tests (#34209) 2025-01-03 12:37:28 -08:00
Yury Semikhatsky 8b45ea6f2f
chore: properly initialize Touch arguments in TouchEvent (#34200) 2025-01-03 12:16:01 -08:00
Yury Semikhatsky dca95ba609
fix(bidi): set initial frame url from creation event (#34198) 2025-01-03 10:39:32 -08:00
Simon Knott 6bdd2694ee
feat(webserver): customize shutdown with new gracefulShutdown option (#34130)
Signed-off-by: Simon Knott <info@simonknott.de>
Co-authored-by: Dmitry Gozman <dgozman@gmail.com>
2025-01-03 11:34:34 +01:00
Simon Knott 04a3574f80
feat(reporter): report TestStep#attachments (#34037) 2025-01-02 17:48:59 +01:00
Max Schmitt 175f05cafc
test: increase page-event-crash timeout (#34178) 2025-01-02 16:04:51 +01:00
David Gahnassia acdd666d95
docs(test-fixtures): removed redundancy (#34185) 2025-01-02 06:17:22 +01:00
Playwright Service 546b7b702c
feat(webkit): roll to r2122 (#34180)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-02 06:16:46 +01:00
Playwright Service da52befea0
feat(chromium-tip-of-tree): roll to r1291 (#34182)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-02 06:16:04 +01:00
Yury Semikhatsky 7769010e6e
chore(bidi): mark test expected to timeout as fixme (#34176) 2024-12-31 13:18:25 -08:00
Max Schmitt b2cbe7f2ec
chore(roll): roll WebKit to r2121 (#34179) 2024-12-31 11:22:10 +01:00
Henrik Skupin 940230d43a
Use csvReporter as well when running BiDi tests locally (#34167) 2024-12-30 14:48:22 -08:00
Dmitry Gozman cd32d1b08c
fix(test runner): apply --last-failed after sharding (#34166) 2024-12-30 18:45:49 +00:00
Henrik Skupin cab2bc4e2a
Combine file name and test name to a single identifier for CSV export of BiDi results (#34172) 2024-12-30 10:06:00 -08:00
Dmitry Gozman 9dbe63636d
fix(routeWebSocket): should work after context reuse (#34165) 2024-12-30 10:00:10 -08:00
Max Schmitt 4819747c85
chore: keep linting generated files (#34150) 2024-12-27 10:00:59 +00:00
Pengoose 7f141b2c42
feat: expect(locator).toHaveAccessibleErrorMessage (#33904) 2024-12-27 09:54:16 +00:00
Playwright Service 3ec8ee7a9b
feat(chromium): roll to r1153 (#34118)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-27 08:51:06 +01:00
Playwright Service 08644003d2
feat(chromium-tip-of-tree): roll to r1290 (#34144)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-26 22:27:56 +01:00
Gautier Ben Aïm 1c8e6f0921
docs: fixed typo (#34129) 2024-12-21 18:59:50 +01:00
Yury Semikhatsky 03cf7429a4
chore(bidi): upload report.csv to azure (#34122) 2024-12-20 18:04:21 -08:00
Yury Semikhatsky cce8e8e0e5
chore(html): use api prefix to qualify public types (#34121) 2024-12-20 14:03:38 -08:00
Evan Cahill c89e213eff
docs: Use locator.first() in locator.or examples (#34106) 2024-12-20 13:23:01 -08:00
Yury Semikhatsky a74c488b25
docs: document --no-shell option (#34120) 2024-12-20 10:24:10 -08:00
Adam Gastineau 875436855e
chore(lint): Ensure EOL newlines (#34117) 2024-12-20 09:17:09 -08:00
Yury Semikhatsky 3bc72eb841
chore(bidi): disambiguate report.csv artifact name (#34110) 2024-12-20 08:58:15 -08:00
Adam Gastineau a8dfdc8ac5
chore(ui): Dialog UI for upcoming settings menu (#34058) 2024-12-20 08:43:12 -08:00
Adam Gastineau 05472f5ef6
feat: Add time information to Call and Network tabs in Trace Viewer (#33935) 2024-12-20 05:01:16 -08:00
Yury Semikhatsky cc98166aaa
chore(bidi): add csv report (#34107) 2024-12-19 22:59:24 -08:00
Pavel Feldman a94952b87f
chore: make ts happy with zip import (#34108) 2024-12-19 22:59:05 -08:00
Pavel Feldman 04e670c909
fix(locator): do not explode locators (#34104) 2024-12-19 15:34:54 -08:00
Max Schmitt b7a1cfd786
chore: move winldd to CDN (#34078) 2024-12-19 23:29:21 +01:00
Yury Semikhatsky d7a52347e5
chore(bidi): skip tooling tests (#34105) 2024-12-19 14:04:05 -08:00
Max Schmitt 61ce37cd53
test: use checkInstalledSoftwareOnDisk for itest (#34103) 2024-12-19 22:09:49 +01:00
Pavel Feldman 6505a3e34c
fix(yaml): escape to disambiguate yaml arrays (#34096) 2024-12-19 12:46:54 -08:00
Pavel Feldman ec1d3313c3
Revert "feat(fetch/network): add generic to json method" (#34098) 2024-12-19 12:46:39 -08:00
Henrik Skupin edd789780a
WebDriver BiDi: "browsingContext.captureScreenshot" accepts quality from 0 to 1 (#34097) 2024-12-19 12:26:01 -08:00
Adam Gastineau 7d3a188530
chore(ui): Clean up settings component for shared uses (#34090) 2024-12-19 12:14:58 -08:00
Max Schmitt 613f6c5f95
devops: run bidi tests for bidi changes (#34099) 2024-12-19 21:03:33 +01:00
Yury Semikhatsky 8e721fac85
chore(bidi): no retries on CI (#34080) 2024-12-19 11:55:10 -08:00
Volodymyr Momot 94ffbcb9c5
feat(fetch/network): add generic to json method (#34091) 2024-12-19 10:36:02 -08:00
Playwright Service 9c14cccc24
feat(chromium-tip-of-tree): roll to r1288 (#34092) 2024-12-19 17:17:29 +01:00
Playwright Service a239ab3048
feat(ffmpeg): roll to r1011 (#34079)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-19 10:17:42 +01:00
Max Schmitt 4c9a116aff
chore: move protocol to d.ts types only files (#34077) 2024-12-19 00:23:35 +01:00
Playwright Service bddbf8950e
feat(webkit): roll to r2120 (#34069) 2024-12-19 00:08:27 +01:00
Rui Figueira c2d057ba23
chore: add url option to routeFromHAR call if codegen launched with --save-har-glob (#34048) 2024-12-18 13:34:06 -08:00
Dmitry Gozman d9e5ca06bf
fix(remote server): allow local paths in extension mode (#34051) 2024-12-18 13:32:16 -08:00
Max Schmitt f7c99ee6e3
chore: update CDN endpoints (#34061) 2024-12-18 22:26:01 +01:00
Andrew Goldis c57155e30c
docs: explain globalSetup caveats for reporters (#34063) 2024-12-18 13:16:03 -08:00
Simon Knott 67bc484d8b
chore(ui): test that UI works behind proxy, take 2 (#33771) 2024-12-18 12:39:08 +01:00
Simon Knott 443b2a2bbc
fix: don't rely on requestAnimationFrame (#34065) 2024-12-18 11:41:48 +01:00
Playwright Service c9ae644e5f
feat(chromium-tip-of-tree): roll to r1287 (#34057) 2024-12-17 22:31:01 +01:00
Max Schmitt 52b2548612
chore: no @web imports from @web package (#34055) 2024-12-17 20:27:21 +01:00
Max Schmitt 43e46d63dd
chore: use recorder/html types for exported shared types (#34056) 2024-12-17 20:26:56 +01:00
Yury Semikhatsky 7ed60ccf7f
feat(test): step.fail and step.fixme modifiers (#34042) 2024-12-17 11:17:22 -08:00
Adam Gastineau aabbcbf41d
fix(trace-viewer): Fix network log flicker #33929 (#34036) 2024-12-17 05:24:22 -08:00
Yury Semikhatsky 7ce1a540bc
chore(bidi): skip only timeouts on CI (#34041) 2024-12-16 15:28:21 -08:00
Pavel Feldman 94d0fc780d
chore: make visible=false work (#34040) 2024-12-16 14:14:51 -08:00
Yury Semikhatsky b58a4762f4
docs: improve note on browser.close() behavior (#34039) 2024-12-16 13:52:17 -08:00
Yury Semikhatsky 76bb01d77c
chore: rephrase suggestion for slow test files (#34012) 2024-12-16 13:35:19 -08:00
Dmitry Gozman d4b2c966cf
fix(codegen): fallback to iframe[name/src] when failed to generate selector (#34030) 2024-12-16 17:37:53 +00:00
Simon Knott 512cb36c9b
feat(html): link from attachment step to attachment (#33267) 2024-12-16 15:25:32 +01:00
Adam Gastineau 6270918f67
docs: Moved Trace Viewer running instructions to the top of the page (#33956) 2024-12-16 05:18:54 -08:00
Dmitry Gozman aa1fe61cc9
fix(list reporter): do not print step location instead of test location (#34022) 2024-12-16 10:15:52 +00:00
Dmitry Gozman f713d3adaf
chore: simplify page initialization logic across browser types (#34002) 2024-12-14 20:15:58 +00:00
Pavel Feldman 1e4239f48d
chore: allow selecting update source type via test server (#34014) 2024-12-14 10:58:16 -08:00
Pavel Feldman 3a10c32d8a
chore: report highlight parse error to debug controller (#33984) 2024-12-13 16:10:59 -08:00
Pavel Feldman cbc809edc7
chore: recorder toolbar polish (#33983) 2024-12-13 16:10:45 -08:00
Yury Semikhatsky 369f4b76b3
fix: throw an error when object reference chain is to long to serialize (#34008) 2024-12-13 13:38:26 -08:00
Max Schmitt 91d4b82dfb
fix(pwt): custom fixture titles in UI Mode / HTML Reporter (#34009) 2024-12-13 12:31:38 -08:00
Max Schmitt e995ecd9b8
chore: add docs for experimental 'watch mode' (#33988) 2024-12-13 10:38:27 -08:00
Dmitry Gozman 258881bea1
test: fix should not transform external for newer Node versions (#34006) 2024-12-13 17:17:49 +00:00
Rui Figueira c700a8405c
feat(trace-viewer): render iframe canvas in trace viewer (#33809) 2024-12-13 16:28:06 +01:00
Max Schmitt 65688d623e
chore: update TypeScript to v5.7 (#33994) 2024-12-13 04:52:04 -08:00
Simon Knott dd36de7809
fix(html): encode all stdio attachments (#33950) 2024-12-13 12:01:20 +01:00
Playwright Service b0cec5b351
feat(chromium-tip-of-tree): roll to r1286 (#33991)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-12 19:22:48 -08:00
Playwright Service dd41930e72
feat(webkit): roll to r2119 (#33992)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-12 19:22:27 -08:00
Yury Semikhatsky 0034c6b984
fix: parse locator with empty options (#33990) 2024-12-12 17:49:48 -08:00
Yury Semikhatsky 76d46d478f
fix: text-is() should ignore comments (#33980) 2024-12-12 17:49:31 -08:00
Max Schmitt e4413f2089
docs: add docs for 'run-server' (#33989) 2024-12-12 16:23:13 -08:00
Max Schmitt 21c456b2c1
chore: remove vite default scripts in package.json's (#33986) 2024-12-12 15:37:53 -08:00
Max Schmitt 16a1552e74
chore: remove 'npx playwright debug' (#33987) 2024-12-12 15:25:13 -08:00
Max Schmitt 38758c0596
chore: tidy up headless-shell hacks (#33967) 2024-12-12 12:23:03 -08:00
Jozef Izso a4add6ebaf
Fix typo in AndroidServerLauncherImpl class when on device was found (#33973) 2024-12-12 11:12:58 -08:00
Max Schmitt aca00a4ab0
chore: update README/device descriptors after roll (#33982) 2024-12-12 11:06:14 -08:00
Playwright Service fc9f5a6f28
feat(chromium): roll to r1152 (#33977) 2024-12-12 09:04:17 -08:00
Pavel Feldman 29fd2df124
chore: send aria snapshot to the debug controller (#33969) 2024-12-12 08:21:53 -08:00
Pavel Feldman 0e2b984287
chore: prioritize role over label and placeholder (#33970) 2024-12-12 08:21:00 -08:00
Max Schmitt e3629dc1df
fix: validate ffmpeg on context creation (#33903) 2024-12-11 23:07:03 -08:00
Max Schmitt 081f455ee9
fix: headless-shell follow-up (#33968) 2024-12-11 19:28:39 -08:00
Max Schmitt 8d57b7543e
chore: introduce chromium-tip-of-tree-headless-shell (#33964) 2024-12-11 18:11:33 -08:00
Max Schmitt 217a0e9003
chore: bump https/socks proxy-agent (#33965) 2024-12-11 17:52:52 -08:00
Max Schmitt b12ede48fc
test: fix html-reporter tests after #33754 (#33966) 2024-12-11 17:49:16 -08:00
Bill Collins e4e562cac5
fix(types): Global JSX namespace is deprecated (#33949) 2024-12-11 17:09:19 -08:00
Yury Semikhatsky 22e58aa084
docs: clarify --only-shell option (#33961) 2024-12-11 13:06:48 -08:00
Yury Semikhatsky 9e683d798f
docs: clarify setDefaultTimeout with 0 value (#33959) 2024-12-11 13:06:37 -08:00
Yury Semikhatsky 856704a176
chore: run server with headless shell for connect tests (#33957) 2024-12-11 10:35:14 -08:00
Playwright Service 5a1bae0f19
feat(chromium-tip-of-tree): roll to r1285 (#33945)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-11 10:30:17 -08:00
Simon Knott 6d424875e3
fix(html): remove filter clear button (#33754) 2024-12-11 15:16:21 +01:00
Simon Knott ed2be67e47
chore(trace viewer): support HMR (#33609) 2024-12-11 13:25:52 +01:00
Adam Gastineau a14d9750b3
docs: #33837 Clarify that clock.install must precede clock operations (#33901) 2024-12-10 16:18:41 -08:00
Pavel Feldman 4bcf505e19
chore: prefer generating role with text to css with text (#33942) 2024-12-10 16:03:33 -08:00
Playwright Service 4745f64bc0
feat(webkit): roll to r2118 (#33938) 2024-12-10 14:29:30 -08:00
Pavel Feldman acf1107220
chore: ignore checkbox/radio value in aria (#33941) 2024-12-10 14:04:18 -08:00
Yury Semikhatsky 599b09c1c0
docs: sharding per file with multiple projects (#33939) 2024-12-10 14:02:13 -08:00
Yury Semikhatsky 54c595c7ed
docs: add examples for clock.install() followed by pauseAt() (#33937) 2024-12-10 11:50:51 -08:00
Pavel Feldman a25bda6950
chore: allow storing aria snapshots in files (#33919) 2024-12-10 11:45:16 -08:00
Max Schmitt 200e868b63
chore: bump nanoid to 3.3.8 (#33936) 2024-12-10 11:19:36 -08:00
jinohkang-theori 27060a0f65
fix(connect): disable context takeover in websocket transport (#33811) 2024-12-09 18:07:00 -08:00
yangsisi d029b03d9f
fix(defineConfig): fix type issue passing custom property in the seco… (#33774)
Signed-off-by: yangsisi <13655750+yangsisi0422@users.noreply.github.com>
2024-12-09 09:20:47 -08:00
Dmitry Gozman 0937d2f7b9
fix(types): update types for test.extend (#33784) 2024-12-09 08:59:01 -08:00
Playwright Service dfa24462db
feat(webkit): roll to r2117 (#33902) 2024-12-06 16:43:25 -08:00
Playwright Service 2a1a9c9452
feat(webkit): roll to r2116 (#33897)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-06 15:38:51 -08:00
Simon Knott 4914f34a83
fix(recorder): allow clearing when recording is disabled (#33821) 2024-12-06 10:17:06 -08:00
Adam Gastineau a56a5cabbd
docs: clarify use of comments in contributions (#33896) 2024-12-06 10:09:35 -08:00
Yury Semikhatsky 733f9a2926
chore: pdf generation now works in headed mode too (#33879) 2024-12-05 17:53:31 -08:00
Simon Knott 993546c1bc
chore: r1284 fixup (#33883) 2024-12-05 16:22:52 -08:00
Simon Knott f6f6a6225c
docs: locale defaults to en-us (#33840) 2024-12-05 15:44:41 -08:00
Playwright Service ee8208beda
feat(chromium-tip-of-tree): roll to r1284 (#33876)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-05 09:34:30 -08:00
Playwright Service b86725bb98
feat(chromium): roll to r1151 (#33873)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-05 09:34:16 -08:00
Playwright Service b941359fce
chore(driver): roll driver to recent Node.js LTS version (#33870) 2024-12-05 06:08:44 -08:00
Dmitry Gozman be78e9e11f
fix: do not stall waiting for pending navigations after beforeunload dismiss (#33834) 2024-12-03 15:55:45 -08:00
Playwright Service abf6916909
feat(webkit): roll to r2113 (#33807) 2024-12-03 10:05:51 -08:00
Dmitry Gozman a7f2868594
fix(codegen): do not reset current tool upon clearing highlight (#33822) 2024-12-03 09:25:14 -08:00
Playwright Service e4211ee3ac
feat(chromium-tip-of-tree): roll to r1283 (#33845)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-12-03 07:14:05 -08:00
Max Schmitt 9b5f7f77b2
docs(network): add proxy back-ref to api docs (#33839) 2024-12-02 16:20:44 -08:00
Dmitry Gozman 4e33ade287
docs: fix codegen --viewport option examples (#33816) 2024-11-29 06:13:53 -08:00
Tasawar Hussain b456ac5f8c
docs: update ci.md (#33815)
Signed-off-by: Tasawar Hussain <31658686+tasawar-hussain@users.noreply.github.com>
2024-11-29 03:36:50 -08:00
Dmitry Gozman b5bd543cc6
test: skip 'should not auto play audio' with frozen time (#33799) 2024-11-28 06:36:49 -08:00
Playwright Service fd25f3ab85
feat(chromium-tip-of-tree): roll to r1282 (#33798)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-28 14:43:45 +01:00
Simon Knott 4fb6c4ed4c
fix(trace): in indexTree check isVisible before adding to result (#33797) 2024-11-28 14:04:34 +01:00
Dmitry Gozman a84488edaa
fix(aria): escape even more yaml (#33793) 2024-11-28 03:21:52 -08:00
Playwright Service ff6c283af5
feat(webkit): roll to r2112 (#33778)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-27 16:53:22 +01:00
Segev Finer f3ae940684
fix(ct-vue): Upgrade plugin-vue to be compatible with Vite 5 (#33758) 2024-11-26 17:42:36 +01:00
Max Schmitt 84df6e3297
docs(python): add note about async fixtures (#33760) 2024-11-26 16:23:19 +01:00
Playwright Service b9c923f87c
feat(chromium-tip-of-tree): roll to r1281 (#33769)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-26 14:26:35 +01:00
Playwright Service 3fd5174b9f
feat(webkit): roll to r2111 (#33759)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-25 22:35:34 +01:00
Dmitry Gozman 39285c4667
docs: update extensions doc for new headless (#33753) 2024-11-25 01:13:20 -08:00
Max Schmitt 9d92b0d3ec
docs(dotnet): add docs for xUnit (#33742) 2024-11-25 10:09:35 +01:00
Max Schmitt e0e4da8ead
docs(cli): fix docs rendering (#33751) 2024-11-24 14:50:12 +01:00
Pavel Feldman 0d9bcd45d5
chore: pin typescript while vue-tsc is broken (#33746) 2024-11-23 11:48:34 -08:00
Pavel Feldman 35dd3dd104
chore: use diff for snapshot delta (#33739) 2024-11-23 11:39:04 -08:00
Pavel Feldman 971b5da741
chore: introduce update-source-method (#33738) 2024-11-22 18:30:35 -08:00
Pavel Feldman 66d9f3acbe
chore: introduce update-snapshots=changed (#33735) 2024-11-22 17:41:31 -08:00
Yury Semikhatsky 66f709663e
fix(webkit): do not auto play audio without user gesture (#33734) 2024-11-22 14:53:29 -08:00
Dmitry Gozman 4696dd8682
fix(chromium): race between oopif attach and context clear (#33729) 2024-11-22 09:35:35 -08:00
Dmitry Gozman 7e09aa07de
feat(trace): preserve the open state of popovers (#33728) 2024-11-22 09:35:19 -08:00
Pavel Feldman 5f85a4a419
chore: add config markers / overwrite mode (#33723) 2024-11-22 09:12:58 -08:00
Dmitry Gozman f123f7ac69
fix: isEditable/toBeEditable throw for elements that cannot be editable/readonly (#33713) 2024-11-22 03:40:43 -08:00
Max Schmitt b7e47dc0bd
docs(test-runners): restructure .NET test-runners doc (#33727) 2024-11-22 12:35:14 +01:00
Playwright Service b32fdade16
feat(chromium): roll to r1150 (#33718)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-22 12:05:16 +01:00
Pavel Feldman e0f0996bbd
chore: climb file tree to git root for patches (#33722) 2024-11-21 17:32:07 -08:00
Pavel Feldman 605df0be8f
chore: add more info about snapshot testing (#33721) 2024-11-21 16:11:01 -08:00
Max Schmitt 5da0b94357
feat(webkit): roll to r2108 (#33710)
Co-authored-by: Yury Semikhatsky <yurys@chromium.org>
2024-11-21 14:42:21 -08:00
Playwright Service c2a8375ef2
feat(chromium-tip-of-tree): roll to r1280 (#33719)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-21 22:36:39 +01:00
Max Schmitt 92436518ff
docs(python): add LocatorAssertions.NotToMatchAriaSnapshot (#33712) 2024-11-21 15:53:37 +01:00
Max Schmitt 77d82b8b07
chore: remove dead code in urlMatches (#33714) 2024-11-21 15:53:28 +01:00
Dmitry Gozman d3ffdefd50
docs: release notes for languages v1.49 (#33706) 2024-11-21 05:45:00 -08:00
Max Schmitt f43b86fea4
devops: delete .devcontainer/devcontainer.json (#33709)
Signed-off-by: Max Schmitt <max@schmitt.mx>
2024-11-21 12:22:45 +01:00
Simon Knott fc19e6e7b4
fix(test): export TestDetailsAnnotation (#33698) 2024-11-20 17:28:56 +01:00
Max Schmitt 6a32589330
test: update 'should work for canvas' test expectation (#33685) 2024-11-20 17:13:07 +01:00
Simon Knott 89f4d4ce4f
chore(html): hmr report should survive reload (#33696) 2024-11-20 16:35:39 +01:00
Simon Knott 81e28a8854
docs(aria): add demo video (#33668) 2024-11-20 15:36:51 +01:00
Simon Knott bfd64ac11b
docs: add video for 1.49 (#33693) 2024-11-20 15:36:38 +01:00
Dmitry Gozman 94776ad18a
docs: note that permissions list may change (#33690) 2024-11-20 06:08:34 -08:00
Josh Kelley 1afb56ee1b
docs: add docs for 1.49.0's new "chromium" option (#33680) 2024-11-20 01:19:39 -08:00
Simon Knott 1d3605d1fc
feat(trace viewer): add "Copy as Playwright Request" button (#33298) 2024-11-20 10:16:43 +01:00
Simon Knott f1ddd379f3
fix(html): don't conflate file names (#33600) 2024-11-20 10:16:33 +01:00
Dmitry Gozman 50c8fbf750
fix(ui mode): do not render anonymous describe (#33675) 2024-11-20 00:51:31 -08:00
Simon Knott ae10d56836
docs(fixtures): add rules of thumb for fixture usage (#33472) 2024-11-20 09:06:54 +01:00
Max Schmitt 402bb4ccf8
devops: update GitHub Actions via dependabot (#33683) 2024-11-20 08:13:35 +01:00
Pavel Feldman b40889d1a8
chore: escape more yaml values (#33686) 2024-11-19 17:09:49 -08:00
Max Schmitt 7f7b440c72
devops: deduplicate redudant information in client side changes issue (#33666) 2024-11-19 19:06:20 +01:00
Playwright Service aa0ac04d06
feat(webkit): roll to r2105 (#33679)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-19 17:56:50 +01:00
Playwright Service 4d4fa69a0a
feat(chromium-tip-of-tree): roll to r1279 (#33676)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-19 16:49:59 +01:00
Simon Knott 4979ce2b5d
chore(html): Reveal elements with Anchor abstraction (#33537) 2024-11-19 16:40:02 +01:00
Simon Knott 8c1002a98b
fix(sw): fix UI mode on codespaces by not passing server (#33664) 2024-11-19 16:39:47 +01:00
Dmitry Gozman 6e19bc341f
fix(role): ignore invalid aria-labelledby attributes (#33667) 2024-11-19 03:56:16 -08:00
Max Schmitt ecf6f27159
fix: dark-mode in UI Mode (#33662) 2024-11-19 10:29:05 +01:00
Simon Knott e047f6bc07
chore(build): typo in trace-viewer output dir (#33661) 2024-11-19 10:02:41 +01:00
Yury Semikhatsky dc91bab6cc
chore: fix npm audit (#33659) 2024-11-18 16:24:54 -08:00
Yury Semikhatsky 6d71805f4a
fix: do not send favicon request to network when interception is on (#33639) 2024-11-18 11:01:39 -08:00
Max Schmitt 150092438f
chore(recorder): support HMR (#33637) 2024-11-18 18:23:29 +01:00
Simon Knott acd862c6c9
chore(trace): remove embedded trace viewer (#33651) 2024-11-18 16:57:53 +01:00
Max Schmitt 0b312248cd
test: add test for crash on label with input file (#33654) 2024-11-18 16:56:59 +01:00
Max Schmitt 72c532846f
chore(roll): roll Firefox Beta to r1466 (#33653) 2024-11-18 16:56:49 +01:00
aairiian 7f054ef8c6
feat(aria): extend toHaveAccessibleName() to accept an array of expected accessible names (#33277) 2024-11-18 07:46:47 -08:00
Simon Knott 3fa33ca81f
chore(build): fix bug where sw changes aren't copied in watch mode (#33579) 2024-11-18 16:04:12 +01:00
Simon Knott 5e8b469c1c
fix(test): hide response.* calls from reports (#33620) 2024-11-18 13:59:40 +01:00
Max Schmitt d7d8ab62a2
chore: roll stable-test-runner to 1.49.0-beta-1731772650000 (#33648) 2024-11-18 10:21:48 +01:00
Max Schmitt 6fce5620e0
fix(ui-mode): use onChange instead of onClick for <input type='checkbox' (#33636) 2024-11-18 10:21:28 +01:00
Rui Figueira 82c77a5e9e
fix(ui-mode): prevent websocket connection leaks on reload (#33643) 2024-11-18 01:03:21 -08:00
Pavel Feldman 46321e5bf2
chore: clear highlight when performing action (#33638) 2024-11-16 07:56:33 -08:00
Pavel Feldman a98021499f
chore: add cm placeholder text (#33635) 2024-11-15 16:19:35 -08:00
Jean-François Greffier 508021362d
fix minor typos in "Getting Started" (#33613) 2024-11-15 14:45:54 -08:00
Max Schmitt 37ce53945e
fix(ui-mode): fix issue when updating state while rendering (#33634) 2024-11-15 23:45:25 +01:00
Rui Figueira c36b5a6059
fix: ensure toMatchAriaSnapshot is properly commented in javascript c… (#33593) 2024-11-15 14:44:27 -08:00
Pavel Feldman d127255881
chore: add AriaSnapshot internal type (#33631) 2024-11-15 13:48:43 -08:00
Pavel Feldman 44cd1d03cc
chore: highlight edited locator while recording (#33632) 2024-11-15 13:43:00 -08:00
Max Schmitt b91f609b14
chore: fix react attribute casing in TestErrorView (#33633) 2024-11-15 22:25:26 +01:00
Yury Semikhatsky e24780f825
chore: unshift shortest whitespace prefix only (#33618) 2024-11-15 12:47:25 -08:00
Dmitry Gozman 77dee44984
fix(rebase): do not apply multiple rebaselines to the same assertion (#33629) 2024-11-15 09:08:31 -08:00
Max Schmitt c81504c5d6
fix(codegen): document.documentElement is null on early navigation (#33627) 2024-11-15 17:14:49 +01:00
Amaechi Hope e61cea597a
docs(dotnet): fix assertion snippets (#33622) 2024-11-15 15:02:40 +01:00
Dmitry Gozman 2aa9e11a7f
fix(aria): normalize whitespace in toMatchAccessible{Name,Description} (#33619) 2024-11-15 02:49:03 -08:00
Dmitry Gozman eaf3536014
fix(trace): afterAll hook should not break tracing with reused context (#33616) 2024-11-14 13:24:02 -08:00
Yury Semikhatsky f5477d9051
docs: add ariaSnapshot.timeout for language ports (#33614) 2024-11-14 12:23:42 -08:00
Max Schmitt b3e5daff2b
cherry-pick(#33606): feat(chromium): roll to r1149 (#33612) 2024-11-14 19:40:46 +01:00
Playwright Service b61b3a5a13
feat(chromium): roll to r1149 (#33606) 2024-11-14 16:39:24 +01:00
Playwright Service 5e579cc29c
feat(chromium-tip-of-tree): roll to r1278 (#33608)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2024-11-14 16:38:56 +01:00
Max Schmitt 358fad45cd
chore: add ESRP CDN for browser downloads (#33585) 2024-11-14 16:19:42 +01:00
Max Schmitt b8f824ca6b
chore: throw if protocol can't get generated when rolling (#33607) 2024-11-14 16:12:07 +01:00
Simon Knott 445ff73c6e
chore(trace viewer): decouple test server from web server (#33542) 2024-11-14 15:27:33 +01:00
Simon Knott 25c039401d
fix(canvas snapshots): position mismatch in headless mode (#33575) 2024-11-14 15:27:09 +01:00
Dmitry Gozman 80ce205d81
docs: update docs about headless shell (#33604) 2024-11-14 05:38:16 -08:00
Dmitry Gozman 31a2b7bbdc
chore: update headless shell treatment (#33603) 2024-11-14 04:20:44 -08:00
Dmitry Gozman 9f59dbdc57
fix(merge): update error.cause location (#33583) 2024-11-14 01:15:21 -08:00
Simon Knott dc93c8a05b
chore(release): alternative headless mode release notes (#33578)
Signed-off-by: Simon Knott <info@simonknott.de>
Co-authored-by: Yury Semikhatsky <yurys@chromium.org>
2024-11-14 08:40:51 +01:00
Pavel Feldman 4817483ff2
chore: allow highlighting aria template from extension (#33594) 2024-11-13 21:33:38 -08:00
Yury Semikhatsky a8af7cc435
chore: remove macOS <=12 checks (#33591) 2024-11-13 17:21:21 -08:00
Yury Semikhatsky 5203c780ae
feat: step timeout option (#33560) 2024-11-13 11:17:54 -08:00
Max Schmitt eab6447ad9
test: add 'should show errors with causes in the error tab' (#33577) 2024-11-13 17:32:32 +01:00
Simon Knott da7639b737
chore(build): empty out dir (#33576) 2024-11-13 13:08:50 +01:00
Max Schmitt cd41404b05
chore: mark v1.50.0-next (#33572) 2024-11-13 12:51:54 +01:00
931 changed files with 53968 additions and 22393 deletions

View file

@ -1,11 +0,0 @@
{
"name": "Playwright",
"image": "mcr.microsoft.com/playwright:next",
"postCreateCommand": "npm install && npm run build && apt-get update && apt-get install -y software-properties-common && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && add-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" && apt-get install -y docker-ce-cli",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"runArgs": [
"-v", "/var/run/docker.sock:/var/run/docker.sock"
]
}

View file

@ -1,18 +0,0 @@
test/assets/modernizr.js
/tests/third_party/
/packages/*/lib/
*.js
/packages/playwright-core/src/generated/*
/packages/playwright-core/src/third_party/
/packages/playwright-core/types/*
/packages/playwright-ct-core/src/generated/*
/index.d.ts
node_modules/
**/*.d.ts
output/
test-results/
/tests/components/
/tests/installation/fixture-scripts/
DEPS
.cache/
/utils/

View file

@ -1,15 +0,0 @@
module.exports = {
extends: "./.eslintrc.js",
parserOptions: {
ecmaVersion: 9,
sourceType: "module",
project: "./tsconfig.json",
},
rules: {
"@typescript-eslint/no-base-to-string": "error",
"@typescript-eslint/no-unnecessary-boolean-literal-compare": 2,
},
parserOptions: {
project: "./tsconfig.json"
},
};

View file

@ -1,136 +0,0 @@
module.exports = {
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint", "notice"],
parserOptions: {
ecmaVersion: 9,
sourceType: "module",
},
extends: [
"plugin:react/recommended",
"plugin:react-hooks/recommended"
],
settings: {
react: { version: "18" }
},
/**
* ESLint rules
*
* All available rules: http://eslint.org/docs/rules/
*
* Rules take the following form:
* "rule-name", [severity, { opts }]
* Severity: 2 == error, 1 == warning, 0 == off.
*/
rules: {
"@typescript-eslint/no-unused-vars": [2, {args: "none"}],
"@typescript-eslint/consistent-type-imports": [2, {disallowTypeAnnotations: false}],
/**
* Enforced rules
*/
// syntax preferences
"object-curly-spacing": ["error", "always"],
"quotes": [2, "single", {
"avoidEscape": true,
"allowTemplateLiterals": true
}],
"jsx-quotes": [2, "prefer-single"],
"no-extra-semi": 2,
"@typescript-eslint/semi": [2],
"comma-style": [2, "last"],
"wrap-iife": [2, "inside"],
"spaced-comment": [2, "always", {
"markers": ["*"]
}],
"eqeqeq": [2],
"accessor-pairs": [2, {
"getWithoutSet": false,
"setWithoutGet": false
}],
"brace-style": [2, "1tbs", {"allowSingleLine": true}],
"curly": [2, "multi-or-nest", "consistent"],
"new-parens": 2,
"arrow-parens": [2, "as-needed"],
"prefer-const": 2,
"quote-props": [2, "consistent"],
"nonblock-statement-body-position": [2, "below"],
// anti-patterns
"no-var": 2,
"no-with": 2,
"no-multi-str": 2,
"no-caller": 2,
"no-implied-eval": 2,
"no-labels": 2,
"no-new-object": 2,
"no-octal-escape": 2,
"no-self-compare": 2,
"no-shadow-restricted-names": 2,
"no-cond-assign": 2,
"no-debugger": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-empty-character-class": 2,
"no-unreachable": 2,
"no-unsafe-negation": 2,
"radix": 2,
"valid-typeof": 2,
"no-implicit-globals": [2],
"no-unused-expressions": [2, { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true}],
"no-proto": 2,
// es2015 features
"require-yield": 2,
"template-curly-spacing": [2, "never"],
// spacing details
"space-infix-ops": 2,
"space-in-parens": [2, "never"],
"array-bracket-spacing": [2, "never"],
"comma-spacing": [2, { "before": false, "after": true }],
"keyword-spacing": [2, "always"],
"space-before-function-paren": [2, {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}],
"no-whitespace-before-property": 2,
"keyword-spacing": [2, {
"overrides": {
"if": {"after": true},
"else": {"after": true},
"for": {"after": true},
"while": {"after": true},
"do": {"after": true},
"switch": {"after": true},
"return": {"after": true}
}
}],
"arrow-spacing": [2, {
"after": true,
"before": true
}],
"@typescript-eslint/func-call-spacing": 2,
"@typescript-eslint/type-annotation-spacing": 2,
// file whitespace
"no-multiple-empty-lines": [2, {"max": 2}],
"no-mixed-spaces-and-tabs": 2,
"no-trailing-spaces": 2,
"linebreak-style": [ process.platform === "win32" ? 0 : 2, "unix" ],
"indent": [2, 2, { "SwitchCase": 1, "CallExpression": {"arguments": 2}, "MemberExpression": 2 }],
"key-spacing": [2, {
"beforeColon": false
}],
// copyright
"notice/notice": [2, {
"mustMatch": "Copyright",
"templateFile": require("path").join(__dirname, "utils", "copyright.js"),
}],
// react
"react/react-in-jsx-scope": 0
}
};

14
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,14 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
actions:
patterns:
- "*"

View file

@ -35,7 +35,7 @@ jobs:
exit 1
fi
- name: Audit prod NPM dependencies
run: npm audit --omit dev
run: node utils/check_audit.js
lint-snippets:
name: "Lint snippets"
runs-on: ubuntu-latest

View file

@ -27,7 +27,11 @@ jobs:
repo: context.repo.repo,
commit_sha: context.sha,
});
const commitHeader = data.message.split('\n')[0].replace(/#(\d+)/g, 'https://github.com/microsoft/playwright/pull/$1');
const commitHeader = data.message.split('\n')[0];
const prMatch = commitHeader.match(/#(\d+)/);
const formattedCommit = prMatch
? `https://github.com/microsoft/playwright/pull/${prMatch[1]}`
: `https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${context.sha} (${commitHeader})`;
const title = '[Ports]: Backport client side changes for ' + currentPlaywrightVersion;
for (const repo of ['playwright-python', 'playwright-java', 'playwright-dotnet']) {
@ -50,11 +54,11 @@ jobs:
issueBody = issueCreateData.body;
}
const newBody = issueBody.trimEnd() + `
- [ ] https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${context.sha} (${commitHeader})`;
- [ ] ${formattedCommit}`;
const data = await github.rest.issues.update({
owner: context.repo.owner,
repo: repo,
issue_number: issueNumber,
body: newBody
})
}
}

View file

@ -3,9 +3,21 @@ name: Roll Browser into Playwright
on:
repository_dispatch:
types: [roll_into_pw]
workflow_dispatch:
inputs:
browser:
description: 'Browser name, e.g. chromium'
required: true
type: string
revision:
description: 'Browser revision without v prefix, e.g. 1234'
required: true
type: string
env:
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
BROWSER: ${{ github.event.client_payload.browser || github.event.inputs.browser }}
REVISION: ${{ github.event.client_payload.revision || github.event.inputs.revision }}
permissions:
contents: write
@ -24,19 +36,19 @@ jobs:
run: npx playwright install-deps
- name: Roll to new revision
run: |
./utils/roll_browser.js ${{ github.event.client_payload.browser }} ${{ github.event.client_payload.revision }}
./utils/roll_browser.js $BROWSER $REVISION
npm run build
- name: Prepare branch
id: prepare-branch
run: |
BRANCH_NAME="roll-into-pw-${{ github.event.client_payload.browser }}/${{ github.event.client_payload.revision }}"
BRANCH_NAME="roll-into-pw-${BROWSER}/${REVISION}"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT
git config --global user.name github-actions
git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com
git checkout -b "$BRANCH_NAME"
git add .
git commit -m "feat(${{ github.event.client_payload.browser }}): roll to r${{ github.event.client_payload.revision }}"
git push origin $BRANCH_NAME
git commit -m "feat(${BROWSER}): roll to r${REVISION}"
git push origin $BRANCH_NAME --force
- name: Create Pull Request
uses: actions/github-script@v7
with:
@ -47,7 +59,7 @@ jobs:
repo: 'playwright',
head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}',
base: 'main',
title: 'feat(${{ github.event.client_payload.browser }}): roll to r${{ github.event.client_payload.revision }}',
title: 'feat(${{ env.BROWSER }}): roll to r${{ env.REVISION }}',
});
await github.rest.issues.addLabels({
owner: 'microsoft',

View file

@ -7,6 +7,8 @@ on:
- main
paths:
- .github/workflows/tests_bidi.yml
- packages/playwright-core/src/server/bidi/**
- tests/bidi/**
schedule:
# Run every day at midnight
- cron: '0 0 * * *'
@ -43,3 +45,27 @@ jobs:
run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run biditest -- --project=${{ matrix.channel }}*
env:
PWTEST_USE_BIDI_EXPECTATIONS: '1'
- name: Upload csv report to GitHub
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: csv-report-${{ matrix.channel }}
path: test-results/report.csv
retention-days: 7
- name: Azure Login
if: ${{ !cancelled() && github.ref == 'refs/heads/main' }}
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_BLOB_REPORTS_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_BLOB_REPORTS_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_BLOB_REPORTS_SUBSCRIPTION_ID }}
- name: Upload report.csv to Azure
if: ${{ !cancelled() && github.ref == 'refs/heads/main' }}
run: |
REPORT_DIR='bidi-reports'
azcopy cp "./test-results/report.csv" "https://mspwblobreport.blob.core.windows.net/\$web/$REPORT_DIR/${{ matrix.channel }}.csv"
echo "Report url: https://mspwblobreport.z1.web.core.windows.net/$REPORT_DIR/${{ matrix.channel }}.csv"
env:
AZCOPY_AUTO_LOGIN_TYPE: AZCLI

View file

@ -147,6 +147,13 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed
if: ${{ runner.os == 'Linux' }}
run: |
if grep -q "Ubuntu 24" /etc/os-release; then
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
fi
shell: bash
- uses: ./.github/actions/run-test
with:
browsers-to-install: chromium

View file

@ -215,6 +215,13 @@ jobs:
- uses: actions/checkout@v4
- run: npm install -g yarn@1
- run: npm install -g pnpm@8
- name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed
if: ${{ runner.os == 'Linux' }}
run: |
if grep -q "Ubuntu 24" /etc/os-release; then
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
fi
shell: bash
- uses: ./.github/actions/run-test
with:
command: npm run itest

View file

@ -107,6 +107,13 @@ jobs:
- uses: actions/checkout@v4
- run: npm install -g yarn@1
- run: npm install -g pnpm@8
- name: Setup Ubuntu Binary Installation # TODO: Remove when https://github.com/electron/electron/issues/42510 is fixed
if: ${{ runner.os == 'Linux' }}
run: |
if grep -q "Ubuntu 24" /etc/os-release; then
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
fi
shell: bash
- uses: ./.github/actions/run-test
with:
node-version: ${{ matrix.node_version }}
@ -234,6 +241,27 @@ jobs:
env:
PWTEST_CHANNEL: chromium-tip-of-tree
chromium_tot_headless_shell:
name: Chromium tip-of-tree headless-shell-${{ matrix.os }}
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/run-test
with:
browsers-to-install: chromium-tip-of-tree-headless-shell
command: npm run ctest
bot-name: "chromium-tip-of-tree-headless-shell-${{ matrix.os }}"
flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }}
flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }}
flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }}
env:
PWTEST_CHANNEL: chromium-tip-of-tree-headless-shell
firefox_beta:
name: Firefox Beta ${{ matrix.os }}
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
@ -268,29 +296,8 @@ jobs:
- run: npx playwright install-deps
- run: utils/build/build-playwright-driver.sh
test_linux_chromium_headless_shell:
name: Chromium Headless Shell
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
strategy:
fail-fast: false
matrix:
runs-on: [ubuntu-latest]
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/run-test
with:
browsers-to-install: chromium chromium-headless-shell
command: npm run ctest
bot-name: "headless-shell-${{ matrix.runs-on }}"
flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }}
flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }}
flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }}
env:
PWTEST_CHANNEL: chromium-headless-shell
test_chromium_next:
name: Test chromium-next channel
test_channel_chromium:
name: Test channel=chromium
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
strategy:
fail-fast: false
@ -301,11 +308,13 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/run-test
with:
# TODO: this should pass --no-shell.
# However, codegen tests do not inherit the channel and try to launch headless shell.
browsers-to-install: chromium
command: npm run ctest
bot-name: "chromium-next-${{ matrix.runs-on }}"
bot-name: "channel-chromium-${{ matrix.runs-on }}"
flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }}
flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }}
flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }}
env:
PWTEST_CHANNEL: chromium-next
PWTEST_CHANNEL: chromium

2
.gitignore vendored
View file

@ -35,4 +35,4 @@ test-results
.cache/
.eslintcache
playwright.env
firefox
/firefox/

View file

@ -26,6 +26,16 @@ npm run watch
npx playwright install
```
**Experimental dev mode with Hot Module Replacement for recorder/trace-viewer/UI Mode**
```
PW_HMR=1 npm run watch
PW_HMR=1 npx playwright show-trace
PW_HMR=1 npm run ctest -- --ui
PW_HMR=1 npx playwright codegen
PW_HMR=1 npx playwright show-report
```
Playwright is a multi-package repository that uses npm workspaces. For browser APIs, look at [`packages/playwright-core`](https://github.com/microsoft/playwright/blob/main/packages/playwright-core). For test runner, see [`packages/playwright`](https://github.com/microsoft/playwright/blob/main/packages/playwright).
Note that some files are generated by the build, so the watch process might override your changes if done in the wrong file. For example, TypeScript types for the API are generated from the [`docs/src`](https://github.com/microsoft/playwright/blob/main/docs/src).
@ -35,7 +45,7 @@ Coding style is fully defined in [.eslintrc](https://github.com/microsoft/playwr
npm run lint
```
Comments should be generally avoided. If the code would not be understood without comments, consider re-writing the code to make it self-explanatory.
Comments should have an explicit purpose and should improve readability rather than hinder it. If the code would not be understood without comments, consider re-writing the code to make it self-explanatory.
### Write documentation

35
FILING_ISSUES.md Normal file
View file

@ -0,0 +1,35 @@
# How to File a Bug Report That Actually Gets Resolved
Make sure youre on the latest Playwright release before filing. Check existing GitHub issues to avoid duplicates.
## Use the Template
Follow the **Bug Report** template. It guides you step-by-step:
- Fill it out thoroughly.
- Clearly list the steps needed to reproduce the bug.
- Provide what you expected to see versus what happened in reality.
- Include system info from `npx envinfo --preset playwright`.
## Keep Your Repro Minimal
We can't parse your entire code base. Reduce it down to the absolute essentials:
- Start a fresh project (`npm init playwright@latest new-project`).
- Add only the code/DOM needed to show the problem.
- Only use major frameworks if necessary (React, Angular, static HTTP server, etc.).
- Avoid adding extra libraries unless absolutely necessary. Note that we won't install any suspect dependencies.
## Why This Matters
- Most issues that lack a repro turn out to be misconfigurations or usage errors.
- We can't fix problems if we cant reproduce them ourselves.
- We cant debug entire private projects or handle sensitive credentials.
- Each confirmed bug will have a test in our repo, so your repro must be as clean as possible.
## More Help
- [Stack Overflows Minimal Reproducible Example Guide](https://stackoverflow.com/help/minimal-reproducible-example)
- [Playwright Debugging Tools](https://playwright.dev/docs/debug)
## Bottom Line
A well-isolated bug speeds up verification and resolution. Minimal, public repro or its unlikely we can assist.

View file

@ -1,6 +1,6 @@
# 🎭 Playwright
[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-131.0.6778.33-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-132.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-18.2-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop --> [![Join Discord](https://img.shields.io/badge/join-discord-infomational)](https://aka.ms/playwright/discord)
[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-134.0.6998.35-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-135.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-18.2-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop --> [![Join Discord](https://img.shields.io/badge/join-discord-infomational)](https://aka.ms/playwright/discord)
## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright)
@ -8,9 +8,9 @@ Playwright is a framework for Web Testing and Automation. It allows testing [Chr
| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->131.0.6778.33<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->134.0.6998.35<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->132.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->135.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Headless execution is supported for all browsers on all platforms. Check out [system requirements](https://playwright.dev/docs/intro#system-requirements) for details.

View file

@ -1,3 +1,3 @@
REMOTE_URL="https://github.com/mozilla/gecko-dev"
BASE_BRANCH="release"
BASE_REVISION="bc78b98043438d8ee2727a483b6e10dedfda883f"
BASE_REVISION="5cfa81898f6eef8fb1abe463e5253cea5bc17f3f"

View file

@ -393,7 +393,7 @@ class PageTarget {
this._videoRecordingInfo = undefined;
this._screencastRecordingInfo = undefined;
this._dialogs = new Map();
this.forcedColors = 'no-override';
this.forcedColors = 'none';
this.disableCache = false;
this.mediumOverride = '';
this.crossProcessCookie = {
@ -635,7 +635,8 @@ class PageTarget {
}
updateForcedColorsOverride(browsingContext = undefined) {
(browsingContext || this._linkedBrowser.browsingContext).forcedColorsOverride = (this.forcedColors !== 'no-override' ? this.forcedColors : this._browserContext.forcedColors) || 'no-override';
const isActive = this.forcedColors === 'active' || this._browserContext.forcedColors === 'active';
(browsingContext || this._linkedBrowser.browsingContext).forcedColorsOverride = isActive ? 'active' : 'none';
}
async setInterceptFileChooserDialog(enabled) {
@ -858,8 +859,8 @@ function fromProtocolReducedMotion(reducedMotion) {
function fromProtocolForcedColors(forcedColors) {
if (forcedColors === 'active' || forcedColors === 'none')
return forcedColors;
if (forcedColors === null)
return undefined;
if (!forcedColors)
return 'none';
throw new Error('Unknown forced colors: ' + forcedColors);
}
@ -893,7 +894,7 @@ class BrowserContext {
this.forceOffline = false;
this.disableCache = false;
this.colorScheme = 'none';
this.forcedColors = 'no-override';
this.forcedColors = 'none';
this.reducedMotion = 'none';
this.videoRecordingOptions = undefined;
this.crossProcessCookie = {

View file

@ -105,7 +105,10 @@ class Juggler {
};
// Force create hidden window here, otherwise its creation later closes the web socket!
Services.appShell.hiddenDOMWindow;
// Since https://phabricator.services.mozilla.com/D219834, hiddenDOMWindow is only available on MacOS.
if (Services.appShell.hasHiddenWindow) {
Services.appShell.hiddenDOMWindow;
}
let pipeStopped = false;
let browserHandler;

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,3 @@
REMOTE_URL="https://github.com/WebKit/WebKit.git"
BASE_BRANCH="main"
BASE_REVISION="8ceb1da47e75a488ae4c12017a861636904acd4f"
BASE_REVISION="76c95d6131edd36775a5eac01e297926fc974be8"

View file

@ -33,6 +33,7 @@
#import <WebKit/WKUserContentControllerPrivate.h>
#import <WebKit/WKWebViewConfigurationPrivate.h>
#import <WebKit/WKWebViewPrivate.h>
#import <WebKit/WKWebpagePreferencesPrivate.h>
#import <WebKit/WKWebsiteDataStorePrivate.h>
#import <WebKit/WebNSURLExtras.h>
#import <WebKit/WebKit.h>
@ -240,6 +241,8 @@ const NSActivityOptions ActivityOptions =
configuration.preferences._hiddenPageDOMTimerThrottlingAutoIncreases = NO;
configuration.preferences._pageVisibilityBasedProcessSuppressionEnabled = NO;
configuration.preferences._domTimersThrottlingEnabled = NO;
// Do not auto play audio and video with sound.
configuration.defaultWebpagePreferences._autoplayPolicy = _WKWebsiteAutoplayPolicyAllowWithoutSound;
_WKProcessPoolConfiguration *processConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
processConfiguration.forceOverlayScrollbars = YES;
configuration.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease];

File diff suppressed because it is too large Load diff

View file

@ -93,11 +93,20 @@ Element is considered stable when it has maintained the same bounding box for at
## Enabled
Element is considered enabled unless it is a `<button>`, `<select>`, `<input>` or `<textarea>` with a `disabled` property.
Element is considered enabled when it is **not disabled**.
Element is **disabled** when:
- it is a `<button>`, `<select>`, `<input>`, `<textarea>`, `<option>` or `<optgroup>` with a `[disabled]` attribute;
- it is a `<button>`, `<select>`, `<input>`, `<textarea>`, `<option>` or `<optgroup>` that is a part of a `<fieldset>` with a `[disabled]` attribute;
- it is a descendant of an element with `[aria-disabled=true]` attribute.
## Editable
Element is considered editable when it is [enabled] and does not have `readonly` property set.
Element is considered editable when it is [enabled] and is **not readonly**.
Element is **readonly** when:
- it is a `<select>`, `<input>` or `<textarea>` with a `[readonly]` attribute;
- it has an `[aria-readonly=true]` attribute and an aria role that [supports it](https://w3c.github.io/aria/#aria-readonly).
## Receives Events

View file

@ -136,7 +136,7 @@ Launches Chrome browser on the device, and returns its persistent context.
### option: AndroidDevice.launchBrowser.pkg
* since: v1.9
- `command` <[string]>
- `pkg` <[string]>
Optional package name to launch instead of default Chrome for Android.

View file

@ -21,6 +21,13 @@ Creates new instances of [APIRequestContext].
### option: APIRequest.newContext.extraHTTPHeaders = %%-context-option-extrahttpheaders-%%
* since: v1.16
### option: APIRequest.newContext.failOnStatusCode
* since: v1.51
- `failOnStatusCode` <[boolean]>
Whether to throw on response codes other than 2xx and 3xx. By default response object is returned
for all status codes.
### option: APIRequest.newContext.httpCredentials = %%-context-option-httpcredentials-%%
* since: v1.16
@ -64,6 +71,7 @@ Methods like [`method: APIRequestContext.get`] take the base URL into considerat
- `localStorage` <[Array]<[Object]>>
- `name` <[string]>
- `value` <[string]>
- `indexedDB` ?<[Array]<[unknown]>> indexedDB to set for context
Populates context with given storage state. This option can be used to initialize context with logged-in information
obtained via [`method: BrowserContext.storageState`] or [`method: APIRequestContext.storageState`]. Either a path to the

View file

@ -880,6 +880,7 @@ context cookies from the response. The method will automatically follow redirect
- `localStorage` <[Array]<[Object]>>
- `name` <[string]>
- `value` <[string]>
- `indexedDB` <[Array]<[unknown]>>
Returns storage state for this request context, contains current cookies and local storage snapshot if it was passed to the constructor.
@ -890,3 +891,9 @@ Returns storage state for this request context, contains current cookies and loc
### option: APIRequestContext.storageState.path = %%-storagestate-option-path-%%
* since: v1.16
### option: APIRequestContext.storageState.indexedDB
* since: v1.51
- `indexedDB` ?<boolean>
Set to `true` to include IndexedDB in the storage state snapshot.

View file

@ -96,7 +96,7 @@ In case this browser is connected to, clears all created contexts belonging to t
browser server.
:::note
This is similar to force quitting the browser. Therefore, you should call [`method: BrowserContext.close`] on any [BrowserContext]'s you explicitly created earlier with [`method: Browser.newContext`] **before** calling [`method: Browser.close`].
This is similar to force-quitting the browser. To close pages gracefully and ensure you receive page close events, call [`method: BrowserContext.close`] on any [BrowserContext] instances you explicitly created earlier using [`method: Browser.newContext`] **before** calling [`method: Browser.close`].
:::
The [Browser] object itself is considered to be disposed and cannot be used anymore.

View file

@ -963,9 +963,14 @@ specified.
* since: v1.8
- `permissions` <[Array]<[string]>>
A permission or an array of permissions to grant. Permissions can be one of the following values:
A list of permissions to grant.
:::danger
Supported permissions differ between browsers, and even between different versions of the same browser. Any permission may stop working after an update.
:::
Here are some permissions that may be supported by some browsers:
* `'accelerometer'`
* `'accessibility-events'`
* `'ambient-light-sensor'`
* `'background-sync'`
* `'camera'`
@ -1407,7 +1412,7 @@ This setting will change the default maximum time for all the methods accepting
* since: v1.8
- `timeout` <[float]>
Maximum time in milliseconds
Maximum time in milliseconds. Pass `0` to disable timeout.
## async method: BrowserContext.setExtraHTTPHeaders
* since: v1.8
@ -1506,8 +1511,9 @@ Whether to emulate network being offline for the browser context.
- `localStorage` <[Array]<[Object]>>
- `name` <[string]>
- `value` <[string]>
- `indexedDB` <[Array]<[unknown]>>
Returns storage state for this browser context, contains current cookies and local storage snapshot.
Returns storage state for this browser context, contains current cookies, local storage snapshot and IndexedDB snapshot.
## async method: BrowserContext.storageState
* since: v1.8
@ -1517,6 +1523,17 @@ Returns storage state for this browser context, contains current cookies and loc
### option: BrowserContext.storageState.path = %%-storagestate-option-path-%%
* since: v1.8
### option: BrowserContext.storageState.indexedDB
* since: v1.51
- `indexedDB` ?<boolean>
Set to `true` to include IndexedDB in the storage state snapshot.
If your application uses IndexedDB to store authentication tokens, like Firebase Authentication, enable this.
:::note
IndexedDBs with typed arrays are currently not supported.
:::
## property: BrowserContext.tracing
* since: v1.12
- type: <[Tracing]>

View file

@ -89,13 +89,17 @@ class BrowserTypeExamples
* since: v1.8
- returns: <[Browser]>
This method attaches Playwright to an existing browser instance. When connecting to another browser launched via `BrowserType.launchServer` in Node.js, the major and minor version needs to match the client version (1.2.3 → is compatible with 1.2.x).
This method attaches Playwright to an existing browser instance created via `BrowserType.launchServer` in Node.js.
:::note
The major and minor version of the Playwright instance that connects needs to match the version of Playwright that launches the browser (1.2.3 → is compatible with 1.2.x).
:::
### param: BrowserType.connect.wsEndpoint
* since: v1.10
- `wsEndpoint` <[string]>
A browser websocket endpoint to connect to.
A Playwright browser websocket endpoint to connect to. You obtain this endpoint via `BrowserServer.wsEndpoint`.
### option: BrowserType.connect.headers
* since: v1.11
@ -152,6 +156,10 @@ The default browser context is accessible via [`method: Browser.contexts`].
Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers.
:::
:::note
This connection is significantly lower fidelity than the Playwright protocol connection via [`method: BrowserType.connect`]. If you are experiencing issues or attempting to use advanced functionality, you probably want to use [`method: BrowserType.connect`].
:::
**Usage**
```js

View file

@ -161,6 +161,41 @@ await page.Clock.PauseAtAsync(DateTime.Parse("2020-02-02"));
await page.Clock.PauseAtAsync("2020-02-02");
```
For best results, install the clock before navigating the page and set it to a time slightly before the intended test time. This ensures that all timers run normally during page loading, preventing the page from getting stuck. Once the page has fully loaded, you can safely use [`method: Clock.pauseAt`] to pause the clock.
```js
// Initialize clock with some time before the test time and let the page load
// naturally. `Date.now` will progress as the timers fire.
await page.clock.install({ time: new Date('2024-12-10T08:00:00') });
await page.goto('http://localhost:3333');
await page.clock.pauseAt(new Date('2024-12-10T10:00:00'));
```
```python async
# Initialize clock with some time before the test time and let the page load
# naturally. `Date.now` will progress as the timers fire.
await page.clock.install(time=datetime.datetime(2024, 12, 10, 8, 0, 0))
await page.goto("http://localhost:3333")
await page.clock.pause_at(datetime.datetime(2024, 12, 10, 10, 0, 0))
```
```python sync
# Initialize clock with some time before the test time and let the page load
# naturally. `Date.now` will progress as the timers fire.
page.clock.install(time=datetime.datetime(2024, 12, 10, 8, 0, 0))
page.goto("http://localhost:3333")
page.clock.pause_at(datetime.datetime(2024, 12, 10, 10, 0, 0))
```
```java
// Initialize clock with some time before the test time and let the page load
// naturally. `Date.now` will progress as the timers fire.
SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
page.clock().install(new Clock.InstallOptions().setTime(format.parse("2024-12-10T08:00:00")));
page.navigate("http://localhost:3333");
page.clock().pauseAt(format.parse("2024-12-10T10:00:00"));
```
### param: Clock.pauseAt.time
* langs: js, java
* since: v1.45

View file

@ -206,6 +206,9 @@ Below is the HTML markup and the respective ARIA snapshot:
- link "About"
```
### option: Locator.ariaSnapshot.timeout = %%-input-timeout-%%
* since: v1.49
### option: Locator.ariaSnapshot.timeout = %%-input-timeout-js-%%
* since: v1.49
@ -630,13 +633,11 @@ properties:
You can also specify [JSHandle] as the property value if you want live objects to be passed into the event:
```js
// Note you can only create DataTransfer in Chromium and Firefox
const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
await locator.dispatchEvent('dragstart', { dataTransfer });
```
```java
// Note you can only create DataTransfer in Chromium and Firefox
JSHandle dataTransfer = page.evaluateHandle("() => new DataTransfer()");
Map<String, Object> arg = new HashMap<>();
arg.put("dataTransfer", dataTransfer);
@ -644,13 +645,11 @@ locator.dispatchEvent("dragstart", arg);
```
```python async
# note you can only create data_transfer in chromium and firefox
data_transfer = await page.evaluate_handle("new DataTransfer()")
await locator.dispatch_event("#source", "dragstart", {"dataTransfer": data_transfer})
```
```python sync
# note you can only create data_transfer in chromium and firefox
data_transfer = page.evaluate_handle("new DataTransfer()")
locator.dispatch_event("#source", "dragstart", {"dataTransfer": data_transfer})
```
@ -865,31 +864,6 @@ If [`param: expression`] throws or rejects, this method throws.
**Usage**
```js
const tweets = page.locator('.tweet .retweets');
expect(await tweets.evaluate(node => node.innerText)).toBe('10 retweets');
```
```java
Locator tweets = page.locator(".tweet .retweets");
assertEquals("10 retweets", tweets.evaluate("node => node.innerText"));
```
```python async
tweets = page.locator(".tweet .retweets")
assert await tweets.evaluate("node => node.innerText") == "10 retweets"
```
```python sync
tweets = page.locator(".tweet .retweets")
assert tweets.evaluate("node => node.innerText") == "10 retweets"
```
```csharp
var tweets = page.Locator(".tweet .retweets");
Assert.AreEqual("10 retweets", await tweets.EvaluateAsync("node => node.innerText"));
```
### param: Locator.evaluate.expression = %%-evaluate-expression-%%
* since: v1.14
@ -1116,6 +1090,9 @@ await rowLocator
### option: Locator.filter.hasNotText = %%-locator-option-has-not-text-%%
* since: v1.33
### option: Locator.filter.visible = %%-locator-option-visible-%%
* since: v1.51
## method: Locator.first
* since: v1.14
- returns: <[Locator]>
@ -1480,7 +1457,7 @@ Boolean disabled = await page.GetByRole(AriaRole.Button).IsDisabledAsync();
* since: v1.14
- returns: <[boolean]>
Returns whether the element is [editable](../actionability.md#editable).
Returns whether the element is [editable](../actionability.md#editable). If the target element is not an `<input>`, `<textarea>`, `<select>`, `[contenteditable]` and does not have a role allowing `[aria-readonly]`, this method throws an error.
:::warning[Asserting editable state]
If you need to assert that an element is editable, prefer [`method: LocatorAssertions.toBeEditable`] to avoid flakiness. See [assertions guide](../test-assertions.md) for more details.
@ -1714,16 +1691,21 @@ var banana = await page.GetByRole(AriaRole.Listitem).Nth(2);
Creates a locator matching all elements that match one or both of the two locators.
Note that when both locators match something, the resulting locator will have multiple matches and violate [locator strictness](../locators.md#strictness) guidelines.
Note that when both locators match something, the resulting locator will have multiple matches, potentially causing a [locator strictness](../locators.md#strictness) violation.
**Usage**
Consider a scenario where you'd like to click on a "New email" button, but sometimes a security settings dialog shows up instead. In this case, you can wait for either a "New email" button, or a dialog and act accordingly.
:::note
If both "New email" button and security dialog appear on screen, the "or" locator will match both of them,
possibly throwing the ["strict mode violation" error](../locators.md#strictness). In this case, you can use [`method: Locator.first`] to only match one of them.
:::
```js
const newEmail = page.getByRole('button', { name: 'New' });
const dialog = page.getByText('Confirm security settings');
await expect(newEmail.or(dialog)).toBeVisible();
await expect(newEmail.or(dialog).first()).toBeVisible();
if (await dialog.isVisible())
await page.getByRole('button', { name: 'Dismiss' }).click();
await newEmail.click();
@ -1732,7 +1714,7 @@ await newEmail.click();
```java
Locator newEmail = page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("New"));
Locator dialog = page.getByText("Confirm security settings");
assertThat(newEmail.or(dialog)).isVisible();
assertThat(newEmail.or(dialog).first()).isVisible();
if (dialog.isVisible())
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Dismiss")).click();
newEmail.click();
@ -1741,7 +1723,7 @@ newEmail.click();
```python async
new_email = page.get_by_role("button", name="New")
dialog = page.get_by_text("Confirm security settings")
await expect(new_email.or_(dialog)).to_be_visible()
await expect(new_email.or_(dialog).first).to_be_visible()
if (await dialog.is_visible()):
await page.get_by_role("button", name="Dismiss").click()
await new_email.click()
@ -1750,7 +1732,7 @@ await new_email.click()
```python sync
new_email = page.get_by_role("button", name="New")
dialog = page.get_by_text("Confirm security settings")
expect(new_email.or_(dialog)).to_be_visible()
expect(new_email.or_(dialog).first).to_be_visible()
if (dialog.is_visible()):
page.get_by_role("button", name="Dismiss").click()
new_email.click()
@ -1759,7 +1741,7 @@ new_email.click()
```csharp
var newEmail = page.GetByRole(AriaRole.Button, new() { Name = "New" });
var dialog = page.GetByText("Confirm security settings");
await Expect(newEmail.Or(dialog)).ToBeVisibleAsync();
await Expect(newEmail.Or(dialog).First).ToBeVisibleAsync();
if (await dialog.IsVisibleAsync())
await page.GetByRole(AriaRole.Button, new() { Name = "Dismiss" }).ClickAsync();
await newEmail.ClickAsync();
@ -2056,9 +2038,9 @@ Triggers a `change` and `input` event once all the provided options have been se
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
```
@ -2353,7 +2335,7 @@ This method expects [Locator] to point to an
## async method: Locator.tap
* since: v1.14
Perform a tap gesture on the element matching the locator.
Perform a tap gesture on the element matching the locator. For examples of emulating other gestures by manually dispatching touch events, see the [emulating legacy touch events](../touch-events.md) page.
**Details**

View file

@ -240,6 +240,24 @@ Expected accessible description.
### option: LocatorAssertions.NotToHaveAccessibleDescription.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.44
## async method: LocatorAssertions.NotToHaveAccessibleErrorMessage
* since: v1.50
* langs: python
The opposite of [`method: LocatorAssertions.toHaveAccessibleErrorMessage`].
### param: LocatorAssertions.NotToHaveAccessibleErrorMessage.errorMessage
* since: v1.50
- `errorMessage` <[string]|[RegExp]>
Expected accessible error message.
### option: LocatorAssertions.NotToHaveAccessibleErrorMessage.ignoreCase = %%-assertions-ignore-case-%%
* since: v1.50
### option: LocatorAssertions.NotToHaveAccessibleErrorMessage.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.50
## async method: LocatorAssertions.NotToHaveAccessibleName
* since: v1.44
@ -442,6 +460,23 @@ Expected options currently selected.
### option: LocatorAssertions.NotToHaveValues.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.23
## async method: LocatorAssertions.NotToMatchAriaSnapshot
* since: v1.49
* langs: python
The opposite of [`method: LocatorAssertions.toMatchAriaSnapshot`].
### param: LocatorAssertions.NotToMatchAriaSnapshot.expected
* since: v1.49
- `expected` <string>
### option: LocatorAssertions.NotToMatchAriaSnapshot.timeout = %%-js-assertions-timeout-%%
* since: v1.49
### option: LocatorAssertions.NotToMatchAriaSnapshot.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.49
## async method: LocatorAssertions.toBeAttached
* since: v1.33
@ -524,6 +559,16 @@ await Expect(locator).ToBeCheckedAsync();
* since: v1.18
- `checked` <[boolean]>
Provides state to assert for. Asserts for input to be checked by default.
This option can't be used when [`option: LocatorAssertions.toBeChecked.indeterminate`] is set to true.
### option: LocatorAssertions.toBeChecked.indeterminate
* since: v1.50
- `indeterminate` <[boolean]>
Asserts that the element is in the indeterminate (mixed) state. Only supported for checkboxes and radio buttons.
This option can't be true when [`option: LocatorAssertions.toBeChecked.checked`] is provided.
### option: LocatorAssertions.toBeChecked.timeout = %%-js-assertions-timeout-%%
* since: v1.18
@ -701,7 +746,7 @@ expect(locator).to_be_enabled()
```csharp
var locator = Page.Locator("button.submit");
await Expect(locator).toBeEnabledAsync();
await Expect(locator).ToBeEnabledAsync();
```
### option: LocatorAssertions.toBeEnabled.enabled
@ -1181,7 +1226,7 @@ expect(locator).to_have_accessible_description("Save results to disk")
```csharp
var locator = Page.GetByTestId("save-button");
await Expect(locator).toHaveAccessibleDescriptionAsync("Save results to disk");
await Expect(locator).ToHaveAccessibleDescriptionAsync("Save results to disk");
```
### param: LocatorAssertions.toHaveAccessibleDescription.description
@ -1200,6 +1245,56 @@ Expected accessible description.
* since: v1.44
## async method: LocatorAssertions.toHaveAccessibleErrorMessage
* since: v1.50
* langs:
- alias-java: hasAccessibleErrorMessage
Ensures the [Locator] points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage).
**Usage**
```js
const locator = page.getByTestId('username-input');
await expect(locator).toHaveAccessibleErrorMessage('Username is required.');
```
```java
Locator locator = page.getByTestId("username-input");
assertThat(locator).hasAccessibleErrorMessage("Username is required.");
```
```python async
locator = page.get_by_test_id("username-input")
await expect(locator).to_have_accessible_error_message("Username is required.")
```
```python sync
locator = page.get_by_test_id("username-input")
expect(locator).to_have_accessible_error_message("Username is required.")
```
```csharp
var locator = Page.GetByTestId("username-input");
await Expect(locator).ToHaveAccessibleErrorMessageAsync("Username is required.");
```
### param: LocatorAssertions.toHaveAccessibleErrorMessage.errorMessage
* since: v1.50
- `errorMessage` <[string]|[RegExp]>
Expected accessible error message.
### option: LocatorAssertions.toHaveAccessibleErrorMessage.timeout = %%-js-assertions-timeout-%%
* since: v1.50
### option: LocatorAssertions.toHaveAccessibleErrorMessage.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.50
### option: LocatorAssertions.toHaveAccessibleErrorMessage.ignoreCase = %%-assertions-ignore-case-%%
* since: v1.50
## async method: LocatorAssertions.toHaveAccessibleName
* since: v1.44
* langs:
@ -1231,7 +1326,7 @@ expect(locator).to_have_accessible_name("Save to disk")
```csharp
var locator = Page.GetByTestId("save-button");
await Expect(locator).toHaveAccessibleNameAsync("Save to disk");
await Expect(locator).ToHaveAccessibleNameAsync("Save to disk");
```
### param: LocatorAssertions.toHaveAccessibleName.name
@ -1336,49 +1431,48 @@ Attribute name.
* langs:
- alias-java: hasClass
Ensures the [Locator] points to an element with given CSS classes. This needs to be a full match
or using a relaxed regular expression.
Ensures the [Locator] points to an element with given CSS classes. When a string is provided, it must fully match the element's `class` attribute. To match individual classes or perform partial matches, use a regular expression:
**Usage**
```html
<div class='selected row' id='component'></div>
<div class='middle selected row' id='component'></div>
```
```js
const locator = page.locator('#component');
await expect(locator).toHaveClass(/selected/);
await expect(locator).toHaveClass('selected row');
await expect(locator).toHaveClass('middle selected row');
await expect(locator).toHaveClass(/(^|\s)selected(\s|$)/);
```
```java
assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
assertThat(page.locator("#component")).hasClass("selected row");
assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
assertThat(page.locator("#component")).hasClass("middle selected row");
```
```python async
from playwright.async_api import expect
locator = page.locator("#component")
await expect(locator).to_have_class(re.compile(r"selected"))
await expect(locator).to_have_class("selected row")
await expect(locator).to_have_class(re.compile(r"(^|\\s)selected(\\s|$)"))
await expect(locator).to_have_class("middle selected row")
```
```python sync
from playwright.sync_api import expect
locator = page.locator("#component")
expect(locator).to_have_class(re.compile(r"selected"))
expect(locator).to_have_class("selected row")
expect(locator).to_have_class(re.compile(r"(^|\\s)selected(\\s|$)"))
expect(locator).to_have_class("middle selected row")
```
```csharp
var locator = Page.Locator("#component");
await Expect(locator).ToHaveClassAsync(new Regex("selected"));
await Expect(locator).ToHaveClassAsync("selected row");
await Expect(locator).ToHaveClassAsync(new Regex("(^|\\s)selected(\\s|$)"));
await Expect(locator).ToHaveClassAsync("middle selected row");
```
Note that if array is passed as an expected value, entire lists of elements can be asserted:
When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected class values. Each element's class attribute is matched against the corresponding string or regular expression in the array:
```js
const locator = page.locator('list > .component');
@ -2122,7 +2216,7 @@ await expect(page.locator('body')).toMatchAriaSnapshot(`
```
```python async
await page.goto('https://demo.playwright.dev/todomvc/')
await page.goto("https://demo.playwright.dev/todomvc/")
await expect(page.locator('body')).to_match_aria_snapshot('''
- heading "todos"
- textbox "What needs to be done?"
@ -2130,7 +2224,7 @@ await expect(page.locator('body')).to_match_aria_snapshot('''
```
```python sync
page.goto('https://demo.playwright.dev/todomvc/')
page.goto("https://demo.playwright.dev/todomvc/")
expect(page.locator('body')).to_match_aria_snapshot('''
- heading "todos"
- textbox "What needs to be done?"
@ -2159,3 +2253,35 @@ assertThat(page.locator("body")).matchesAriaSnapshot("""
### option: LocatorAssertions.toMatchAriaSnapshot.timeout = %%-js-assertions-timeout-%%
* since: v1.49
### option: LocatorAssertions.toMatchAriaSnapshot.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.49
## async method: LocatorAssertions.toMatchAriaSnapshot#2
* since: v1.50
* langs: js
Asserts that the target element matches the given [accessibility snapshot](../aria-snapshots.md).
Snapshot is stored in a separate `.snapshot.yml` file in a location configured by `expect.toMatchAriaSnapshot.pathTemplate` and/or `snapshotPathTemplate` properties in the configuration file.
**Usage**
```js
await expect(page.locator('body')).toMatchAriaSnapshot();
await expect(page.locator('body')).toMatchAriaSnapshot({ name: 'body.snapshot.yml' });
```
### option: LocatorAssertions.toMatchAriaSnapshot#2.name
* since: v1.50
* langs: js
- `name` <[string]>
Name of the snapshot to store in the snapshot folder corresponding to this test.
Generates sequential names if not specified.
### option: LocatorAssertions.toMatchAriaSnapshot#2.timeout = %%-js-assertions-timeout-%%
* since: v1.50
### option: LocatorAssertions.toMatchAriaSnapshot#2.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.50

View file

@ -1309,6 +1309,18 @@ Emulates `'forced-colors'` media feature, supported values are `'active'` and `'
* langs: csharp, python
- `forcedColors` <[ForcedColors]<"active"|"none"|"null">>
### option: Page.emulateMedia.contrast
* since: v1.51
* langs: js, java
- `contrast` <null|[Contrast]<"no-preference"|"more">>
Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. Passing `null` disables contrast emulation.
### option: Page.emulateMedia.contrast
* since: v1.51
* langs: csharp, python
- `contrast` <[Contrast]<"no-preference"|"more"|"null">>
## async method: Page.evalOnSelector
* since: v1.9
* discouraged: This method does not wait for the element to pass actionability
@ -2762,10 +2774,6 @@ This method requires Playwright to be started in a headed mode, with a falsy [`o
Returns the PDF buffer.
:::note
Generating a pdf is currently only supported in Chromium headless.
:::
`page.pdf()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call
[`method: Page.emulateMedia`] before calling `page.pdf()`:
@ -3974,7 +3982,7 @@ This setting will change the default maximum time for all the methods accepting
* since: v1.8
- `timeout` <[float]>
Maximum time in milliseconds
Maximum time in milliseconds. Pass `0` to disable timeout.
## async method: Page.setExtraHTTPHeaders
* since: v1.8

View file

@ -296,7 +296,18 @@ Ensures the page is navigated to the given URL.
**Usage**
```js
await expect(page).toHaveURL(/.*checkout/);
// Check for the page URL to be 'https://playwright.dev/docs/intro' (including query string)
await expect(page).toHaveURL('https://playwright.dev/docs/intro');
// Check for the page URL to contain 'doc', followed by an optional 's', followed by '/'
await expect(page).toHaveURL(/docs?\//);
// Check for the predicate to be satisfied
// For example: verify query strings
await expect(page).toHaveURL(url => {
const params = url.searchParams;
return params.has('search') && params.has('options') && params.get('id') === '5';
});
```
```java
@ -323,17 +334,18 @@ expect(page).to_have_url(re.compile(".*checkout"))
await Expect(Page).ToHaveURLAsync(new Regex(".*checkout"));
```
### param: PageAssertions.toHaveURL.urlOrRegExp
### param: PageAssertions.toHaveURL.url
* since: v1.18
- `urlOrRegExp` <[string]|[RegExp]>
- `url` <[string]|[RegExp]|[function]\([URL]\):[boolean]>
Expected URL string or RegExp.
Expected URL string, RegExp, or predicate receiving [URL] to match.
When [`option: Browser.newContext.baseURL`] is provided via the context options and the `url` argument is a string, the two values are merged via the [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor and used for the comparison against the current browser URL.
### option: PageAssertions.toHaveURL.ignoreCase
* since: v1.44
- `ignoreCase` <[boolean]>
Whether to perform case-insensitive match. [`option: ignoreCase`] option takes precedence over the corresponding regular expression flag if specified.
Whether to perform case-insensitive match. [`option: ignoreCase`] option takes precedence over the corresponding regular expression parameter if specified. A provided predicate ignores this flag.
### option: PageAssertions.toHaveURL.timeout = %%-js-assertions-timeout-%%
* since: v1.18

View file

@ -4,6 +4,8 @@
The Touchscreen class operates in main-frame CSS pixels relative to the top-left corner of the viewport. Methods on the
touchscreen can only be used in browser contexts that have been initialized with `hasTouch` set to true.
This class is limited to emulating tap gestures. For examples of other gestures simulated by manually dispatching touch events, see the [emulating legacy touch events](../touch-events.md) page.
## async method: Touchscreen.tap
* since: v1.8

View file

@ -302,10 +302,10 @@ await test.step('Log in', async () => {
```java
// All actions between group and groupEnd
// will be shown in the trace viewer as a group.
page.context().tracing.group("Open Playwright.dev > API");
page.context().tracing().group("Open Playwright.dev > API");
page.navigate("https://playwright.dev/");
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("API")).click();
page.context().tracing.groupEnd();
page.context().tracing().groupEnd();
```
```python sync
@ -329,10 +329,10 @@ await page.context.tracing.group_end()
```csharp
// All actions between GroupAsync and GroupEndAsync
// will be shown in the trace viewer as a group.
await Page.Context().Tracing.GroupAsync("Open Playwright.dev > API");
await Page.Context.Tracing.GroupAsync("Open Playwright.dev > API");
await Page.GotoAsync("https://playwright.dev/");
await Page.GetByRole(AriaRole.Link, new() { Name = "API" }).ClickAsync();
await Page.Context().Tracing.GroupEndAsync();
await Page.Context.Tracing.GroupEndAsync();
```
### param: Tracing.group.name

View file

@ -1,7 +1,9 @@
# class: WebSocket
* since: v1.8
The [WebSocket] class represents websocket connections in the page.
The [WebSocket] class represents WebSocket connections within a page. It provides the ability to inspect and manipulate the data being transmitted and received.
If you want to intercept or modify WebSocket frames, consider using [WebSocketRoute].
## event: WebSocket.close
* since: v1.8

View file

@ -259,11 +259,12 @@ Specify environment variables that will be visible to the browser. Defaults to `
- `httpOnly` <[boolean]>
- `secure` <[boolean]>
- `sameSite` <[SameSiteAttribute]<"Strict"|"Lax"|"None">> sameSite flag
- `origins` <[Array]<[Object]>> localStorage to set for context
- `origins` <[Array]<[Object]>>
- `origin` <[string]>
- `localStorage` <[Array]<[Object]>>
- `localStorage` <[Array]<[Object]>> localStorage to set for context
- `name` <[string]>
- `value` <[string]>
- `indexedDB` ?<[Array]<[unknown]>> indexedDB to set for context
Learn more about [storage state and auth](../auth.md).
@ -673,6 +674,18 @@ Emulates `'forced-colors'` media feature, supported values are `'active'`, `'non
Emulates `'forced-colors'` media feature, supported values are `'active'`, `'none'`. See [`method: Page.emulateMedia`] for more details. Passing `'null'` resets emulation to system defaults. Defaults to `'none'`.
## context-option-contrast
* langs: js, java
- `contrast` <null|[ForcedColors]<"no-preference"|"more">>
Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See [`method: Page.emulateMedia`] for more details. Passing `null` resets emulation to system defaults. Defaults to `'no-preference'`.
## context-option-contrast-csharp-python
* langs: csharp, python
- `contrast` <[ForcedColors]<"no-preference"|"more"|"null">>
Emulates `'prefers-contrast'` media feature, supported values are `'no-preference'`, `'more'`. See [`method: Page.emulateMedia`] for more details. Passing `'null'` resets emulation to system defaults. Defaults to `'no-preference'`.
## context-option-logger
* langs: js
- `logger` <[Logger]>
@ -973,6 +986,8 @@ between the same pixel in compared images, between zero (strict) and one (lax),
- %%-context-option-reducedMotion-csharp-python-%%
- %%-context-option-forcedColors-%%
- %%-context-option-forcedColors-csharp-python-%%
- %%-context-option-contrast-%%
- %%-context-option-contrast-csharp-python-%%
- %%-context-option-logger-%%
- %%-context-option-videospath-%%
- %%-context-option-videosize-%%
@ -1001,7 +1016,11 @@ Additional arguments to pass to the browser instance. The list of Chromium flags
## browser-option-channel
- `channel` <[string]>
Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", "msedge-canary". Read more about using [Google Chrome and Microsoft Edge](../browsers.md#google-chrome--microsoft-edge).
Browser distribution channel.
Use "chromium" to [opt in to new headless mode](../browsers.md#chromium-new-headless-mode).
Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or "msedge-canary" to use branded [Google Chrome and Microsoft Edge](../browsers.md#google-chrome--microsoft-edge).
## browser-option-chromiumsandbox
- `chromiumSandbox` <[boolean]>
@ -1136,6 +1155,11 @@ Note that outer and inner locators must belong to the same frame. Inner locator
Matches elements that do not contain specified text somewhere inside, possibly in a child or a descendant element. When passed a [string], matching is case-insensitive and searches for a substring.
## locator-option-visible
- `visible` <[boolean]>
Only matches visible or invisible elements.
## locator-options-list-v1.14
- %%-locator-option-has-text-%%
- %%-locator-option-has-%%
@ -1186,6 +1210,7 @@ Specify screenshot type, defaults to `png`.
Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with
a pink box `#FF00FF` (customized by [`option: maskColor`]) that completely covers its bounding box.
The mask is also applied to invisible elements, see [Matching only visible elements](../locators.md#matching-only-visible-elements) to disable that.
## screenshot-option-mask-color
* since: v1.35
@ -1754,7 +1779,9 @@ await Expect(Page.GetByTitle("Issues count")).toHaveText("25 issues");
- `type` ?<[string]>
* langs: js
This option configures a template controlling location of snapshots generated by [`method: PageAssertions.toHaveScreenshot#1`] and [`method: SnapshotAssertions.toMatchSnapshot#1`].
This option configures a template controlling location of snapshots generated by [`method: PageAssertions.toHaveScreenshot#1`], [`method: LocatorAssertions.toMatchAriaSnapshot#2`] and [`method: SnapshotAssertions.toMatchSnapshot#1`].
You can configure templates for each assertion separately in [`property: TestConfig.expect`].
**Usage**
@ -1763,7 +1790,19 @@ import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests',
// Single template for all assertions
snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
// Assertion-specific templates
expect: {
toHaveScreenshot: {
pathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}',
},
toMatchAriaSnapshot: {
pathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}',
},
},
});
```
@ -1794,22 +1833,22 @@ test.describe('suite', () => {
The list of supported tokens:
* `{arg}` - Relative snapshot path **without extension**. These come from the arguments passed to the `toHaveScreenshot()` and `toMatchSnapshot()` calls; if called without arguments, this will be an auto-generated snapshot name.
* `{arg}` - Relative snapshot path **without extension**. This comes from the arguments passed to `toHaveScreenshot()`, `toMatchAriaSnapshot()` or `toMatchSnapshot()`; if called without arguments, this will be an auto-generated snapshot name.
* Value: `foo/bar/baz`
* `{ext}` - snapshot extension (with dots)
* `{ext}` - Snapshot extension (with the leading dot).
* Value: `.png`
* `{platform}` - The value of `process.platform`.
* `{projectName}` - Project's file-system-sanitized name, if any.
* Value: `''` (empty string).
* `{snapshotDir}` - Project's [`property: TestConfig.snapshotDir`].
* `{snapshotDir}` - Project's [`property: TestProject.snapshotDir`].
* Value: `/home/playwright/tests` (since `snapshotDir` is not provided in config, it defaults to `testDir`)
* `{testDir}` - Project's [`property: TestConfig.testDir`].
* Value: `/home/playwright/tests` (absolute path is since `testDir` is resolved relative to directory with config)
* `{testDir}` - Project's [`property: TestProject.testDir`].
* Value: `/home/playwright/tests` (absolute path since `testDir` is resolved relative to directory with config)
* `{testFileDir}` - Directories in relative path from `testDir` to **test file**.
* Value: `page`
* `{testFileName}` - Test file name with extension.
* Value: `page-click.spec.ts`
* `{testFilePath}` - Relative path from `testDir` to **test file**
* `{testFilePath}` - Relative path from `testDir` to **test file**.
* Value: `page/page-click.spec.ts`
* `{testName}` - File-system-sanitized test title, including parent describes but excluding file name.
* Value: `suite-test-should-work`

View file

@ -1,10 +1,134 @@
---
id: aria-snapshots
title: "Aria snapshots"
title: "Snapshot testing"
---
import LiteYouTube from '@site/src/components/LiteYouTube';
## Overview
With Playwright's Snapshot testing you can assert the accessibility tree of a page against a predefined snapshot template.
```js
await page.goto('https://playwright.dev/');
await expect(page.getByRole('banner')).toMatchAriaSnapshot(`
- banner:
- heading /Playwright enables reliable end-to-end/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- link /[\\d]+k\\+ stargazers on GitHub/
`);
```
```python sync
page.goto('https://playwright.dev/')
expect(page.query_selector('banner')).to_match_aria_snapshot("""
- banner:
- heading /Playwright enables reliable end-to-end/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- link /[\\d]+k\\+ stargazers on GitHub/
""")
```
```python async
await page.goto('https://playwright.dev/')
await expect(page.query_selector('banner')).to_match_aria_snapshot("""
- banner:
- heading /Playwright enables reliable end-to-end/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- link /[\\d]+k\\+ stargazers on GitHub/
""")
```
```java
page.navigate("https://playwright.dev/");
assertThat(page.locator("banner")).matchesAriaSnapshot("""
- banner:
- heading /Playwright enables reliable end-to-end/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- link /[\\d]+k\\+ stargazers on GitHub/
""");
```
```csharp
await page.GotoAsync("https://playwright.dev/");
await Expect(page.Locator("banner")).ToMatchAriaSnapshotAsync(@"
- banner:
- heading ""Playwright enables reliable end-to-end testing for modern web apps."" [level=1]
- link ""Get started""
- link ""Star microsoft/playwright on GitHub""
- link /[\\d]+k\\+ stargazers on GitHub/
");
```
<LiteYouTube
id="P4R6hnsE0UY"
title="Getting started with ARIA Snapshots"
/>
## Assertion testing vs Snapshot testing
Snapshot testing and assertion testing serve different purposes in test automation:
### Assertion testing
Assertion testing is a targeted approach where you assert specific values or conditions about elements or components. For instance, with Playwright, [`method: LocatorAssertions.toHaveText`]
verifies that an element contains the expected text, and [`method: LocatorAssertions.toHaveValue`]
confirms that an input field has the expected value.
Assertion tests are specific and generally check the current state of an element or property
against an expected, predefined state.
They work well for predictable, single-value checks but are limited in scope when testing the
broader structure or variations.
**Advantages**
- **Clarity**: The intent of the test is explicit and easy to understand.
- **Specificity**: Tests focus on particular aspects of functionality, making them more robust
against unrelated changes.
- **Debugging**: Failures provide targeted feedback, pointing directly to the problematic aspect.
**Disadvantages**
- **Verbose for complex outputs**: Writing assertions for complex data structures or large outputs
can be cumbersome and error-prone.
- **Maintenance overhead**: As code evolves, manually updating assertions can be time-consuming.
### Snapshot testing
Snapshot testing captures a “snapshot” or representation of the entire
state of an element, component, or data at a given moment, which is then saved for future
comparisons. When re-running tests, the current state is compared to the snapshot, and if there
are differences, the test fails. This approach is especially useful for complex or dynamic
structures, where manually asserting each detail would be too time-consuming. Snapshot testing
is broader and more holistic than assertion testing, allowing you to track more complex changes over time.
**Advantages**
- **Simplifies complex outputs**: For example, testing a UI component's rendered output can be tedious with traditional assertions. Snapshots capture the entire output for easy comparison.
- **Quick Feedback loop**: Developers can easily spot unintended changes in the output.
- **Encourages consistency**: Helps maintain consistent output as code evolves.
**Disadvantages**
- **Over-Reliance**: It can be tempting to accept changes to snapshots without fully understanding
them, potentially hiding bugs.
- **Granularity**: Large snapshots may be hard to interpret when differences arise, especially
if minor changes affect large portions of the output.
- **Suitability**: Not ideal for highly dynamic content where outputs change frequently or
unpredictably.
### When to use
- **Snapshot testing** is ideal for:
- UI testing of whole pages and components.
- Broad structural checks for complex UI components.
- Regression testing for outputs that rarely change structure.
- **Assertion testing** is ideal for:
- Core logic validation.
- Computed value testing.
- Fine-grained tests requiring precise conditions.
By combining snapshot testing for broad, structural checks and assertion testing for specific functionality, you can achieve a well-rounded testing strategy.
## Aria snapshots
In Playwright, aria snapshots provide a YAML representation of the accessibility tree of a page.
These snapshots can be stored and compared later to verify if the page structure remains consistent or meets defined
expectations.
@ -13,18 +137,6 @@ The YAML format describes the hierarchical structure of accessible elements on t
The structure follows a tree-like syntax, where each node represents an accessible element, and indentation indicates
nested elements.
Following is a simple example of an aria snapshot for the playwright.dev homepage:
```yaml
- banner:
- heading /Playwright enables reliable/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- main:
- img "Browsers (Chromium, Firefox, WebKit)"
- heading "Any browser • Any platform • One API"
```
Each accessible element in the tree is represented as a YAML node:
```yaml
@ -61,19 +173,19 @@ await expect(page.locator('body')).toMatchAriaSnapshot(`
```
```python sync
page.locator("body").to_match_aria_snapshot("""
expect(page.locator("body")).to_match_aria_snapshot("""
- heading "title"
""")
```
```python async
await page.locator("body").to_match_aria_snapshot("""
await expect(page.locator("body")).to_match_aria_snapshot("""
- heading "title"
""")
```
```java
page.locator("body").expect().toMatchAriaSnapshot("""
assertThat(page.locator("body")).matchesAriaSnapshot("""
- heading "title"
""");
```
@ -110,7 +222,7 @@ attributes.
```
In this example, the button role is matched, but the accessible name ("Submit") is not specified, allowing the test to
pass regardless of the buttons label.
pass regardless of the button's label.
<hr/>
@ -168,36 +280,34 @@ support regex patterns.
## Generating snapshots
Creating aria snapshots in Playwright helps ensure and maintain your applications structure.
Creating aria snapshots in Playwright helps ensure and maintain your application's structure.
You can generate snapshots in various ways depending on your testing setup and workflow.
### 1. Generating snapshots with the Playwright code generator
### Generating snapshots with the Playwright code generator
If youre using Playwrights [Code Generator](./codegen.md), generating aria snapshots is streamlined with its
If you're using Playwright's [Code Generator](./codegen.md), generating aria snapshots is streamlined with its
interactive interface:
- **"Assert snapshot" Action**: In the code generator, you can use the "Assert snapshot" action to automatically create
a snapshot assertion for the selected elements. This is a quick way to capture the aria snapshot as part of your
recorded test flow.
- **"Aria snapshot" Tab**: The "Aria snapshot" tab within the code generator interface visually represents the
aria snapshot for a selected locator, letting you explore, inspect, and verify element roles, attributes, and
accessible names to aid snapshot creation and review.
### 2. Updating snapshots with `@playwright/test` and the `--update-snapshots` flag
### Updating snapshots with `@playwright/test` and the `--update-snapshots` flag
* langs: js
When using the Playwright test runner (`@playwright/test`), you can automatically update snapshots by running tests with
the `--update-snapshots` flag:
When using the Playwright test runner (`@playwright/test`), you can automatically update snapshots with the `--update-snapshots` flag, `-u` for short.
Running tests with the `--update-snapshots` flag will update snapshots that did not match. Matching snapshots will not be updated.
```bash
npx playwright test --update-snapshots
```
This command regenerates snapshots for assertions, including aria snapshots, replacing outdated ones. Its
useful when application structure changes require new snapshots as a baseline. Note that Playwright will wait for the
maximum expect timeout specified in the test runner configuration to ensure the
page is settled before taking the snapshot. It might be necessary to adjust the `--timeout` if the test hits the timeout
while generating snapshots.
Updating snapshots is useful when application structure changes require new snapshots as a baseline. Note that Playwright will wait for the maximum expect timeout specified in the test runner configuration to ensure the page is settled before taking the snapshot. It might be necessary to adjust the `--timeout` if the test hits the timeout while generating snapshots.
#### Empty template for snapshot generation
@ -217,10 +327,40 @@ When updating snapshots, Playwright creates patch files that capture differences
applied, and committed to source control, allowing teams to track structural changes over time and ensure updates are
consistent with application requirements.
### 3. Using the `Locator.ariaSnapshot` method
The way source code is updated can be changed using the `--update-source-method` flag. There are several options available:
- **"patch"** (default): Generates a unified diff file that can be applied to the source code using `git apply`.
- **"3way"**: Generates merge conflict markers in your source code, allowing you to choose whether to accept changes.
- **"overwrite"**: Overwrites the source code with the new snapshot values.
```bash
npx playwright test --update-snapshots --update-source-mode=3way
```
#### Snapshots as separate files
To store your snapshots in a separate file, use the `toMatchAriaSnapshot` method with the `name` option, specifying a `.snapshot.yml` file extension.
```js
await expect(page.getByRole('main')).toMatchAriaSnapshot({ name: 'main.snapshot.yml' });
```
By default, snapshots from a test file `example.spec.ts` are placed in the `example.spec.ts-snapshots` directory. As snapshots should be the same across browsers, only one snapshot is saved even if testing with multiple browsers. Should you wish, you can customize the [snapshot path template](./api/class-testconfig#test-config-snapshot-path-template) using the following configuration:
```js
export default defineConfig({
expect: {
toMatchAriaSnapshot: {
pathTemplate: '__snapshots__/{testFilePath}/{arg}{ext}',
},
},
});
```
### Using the `Locator.ariaSnapshot` method
The [`method: Locator.ariaSnapshot`] method allows you to programmatically create a YAML representation of accessible
elements within a locators scope, especially helpful for generating snapshots dynamically during test execution.
elements within a locator's scope, especially helpful for generating snapshots dynamically during test execution.
**Example**:
@ -249,7 +389,7 @@ var snapshot = await page.Locator("body").AriaSnapshotAsync();
Console.WriteLine(snapshot);
```
This command outputs the aria snapshot within the specified locators scope in YAML format, which you can validate
This command outputs the aria snapshot within the specified locator's scope in YAML format, which you can validate
or store as needed.
## Accessibility tree examples

View file

@ -232,7 +232,7 @@ await page.goto('https://github.com/login')
# Interact with login form
await page.get_by_label("Username or email address").fill("username")
await page.get_by_label("Password").fill("password")
await page.page.get_by_role("button", name="Sign in").click()
await page.get_by_role("button", name="Sign in").click()
# Continue with the test
```
@ -266,9 +266,9 @@ existing authentication state instead.
Playwright provides a way to reuse the signed-in state in the tests. That way you can log
in only once and then skip the log in step for all of the tests.
Web apps use cookie-based or token-based authentication, where authenticated state is stored as [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) or in [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage). Playwright provides [`method: BrowserContext.storageState`] method that can be used to retrieve storage state from authenticated contexts and then create new contexts with prepopulated state.
Web apps use cookie-based or token-based authentication, where authenticated state is stored as [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), in [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) or in [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API). Playwright provides [`method: BrowserContext.storageState`] method that can be used to retrieve storage state from authenticated contexts and then create new contexts with prepopulated state.
Cookies and local storage state can be used across different browsers. They depend on your application's authentication model: some apps might require both cookies and local storage.
Cookies, local storage and IndexedDB state can be used across different browsers. They depend on your application's authentication model which may require some combination of cookies, local storage or IndexedDB.
The following code snippet retrieves state from an authenticated context and creates a new context with that state.
@ -583,7 +583,7 @@ test('admin and user', async ({ adminPage, userPage }) => {
### Session storage
Reusing authenticated state covers [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) based authentication. Rarely, [session storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) is used for storing information associated with the signed-in state. Session storage is specific to a particular domain and is not persisted across page loads. Playwright does not provide API to persist session storage, but the following snippet can be used to save/load session storage.
Reusing authenticated state covers [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) and [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) based authentication. Rarely, [session storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) is used for storing information associated with the signed-in state. Session storage is specific to a particular domain and is not persisted across page loads. Playwright does not provide API to persist session storage, but the following snippet can be used to save/load session storage.
```js
// Get session storage and store as env variable

View file

@ -338,44 +338,121 @@ dotnet test --settings:webkit.runsettings
For Google Chrome, Microsoft Edge and other Chromium-based browsers, by default, Playwright uses open source Chromium builds. Since the Chromium project is ahead of the branded browsers, when the world is on Google Chrome N, Playwright already supports Chromium N+1 that will be released in Google Chrome and Microsoft Edge a few weeks later.
Playwright ships a regular Chromium build for headed operations and a separate [Chromium headless shell](https://developer.chrome.com/blog/chrome-headless-shell) for headless mode. These two behave differently in some edge cases, but the majority of testing scenarios are not affected. Note this behavior has changed in Playwright version 1.49, see [issue #33566](https://github.com/microsoft/playwright/issues/33566) for details.
### Chromium: headless shell
#### Save on download size
Playwright ships a regular Chromium build for headed operations and a separate [chromium headless shell](https://developer.chrome.com/blog/chrome-headless-shell) for headless mode.
If you are only running tests in headless, for example on CI, you can avoid downloading a headed version of Chromium by specifying `chromium-headless-shell` during installation.
If you are only running tests in headless shell (i.e. the `channel` option is **not** specified), for example on CI, you can avoid downloading the full Chromium browser by passing `--only-shell` during installation.
```bash js
# When only running tests headlessly
npx playwright install chromium-headless-shell firefox webkit
# only running tests headlessly
npx playwright install --with-deps --only-shell
```
```bash java
# When only running tests headlessly
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install chromium-headless-shell firefox webkit"
# only running tests headlessly
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps --only-shell"
```
```bash python
# When only running tests headlessly
playwright install chromium-headless-shell firefox webkit
# only running tests headlessly
playwright install --with-deps --only-shell
```
```bash csharp
# When only running tests headlessly
pwsh bin/Debug/netX/playwright.ps1 install chromium-headless-shell firefox webkit
# only running tests headlessly
pwsh bin/Debug/netX/playwright.ps1 install --with-deps --only-shell
```
### Chromium: new headless mode
You can opt into the new headless mode by using `'chromium'` channel. As [official Chrome documentation puts it](https://developer.chrome.com/blog/chrome-headless-shell):
> New Headless on the other hand is the real Chrome browser, and is thus more authentic, reliable, and offers more features. This makes it more suitable for high-accuracy end-to-end web app testing or browser extension testing.
See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for details.
```js
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'], channel: 'chromium' },
},
],
});
```
```java
import com.microsoft.playwright.*;
public class Example {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setChannel("chromium"));
Page page = browser.newPage();
// ...
}
}
}
```
```bash python
pytest test_login.py --browser-channel chromium
```
```xml csharp
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<Playwright>
<BrowserName>chromium</BrowserName>
<LaunchOptions>
<Channel>chromium</Channel>
</LaunchOptions>
</Playwright>
</RunSettings>
```
```bash csharp
dotnet test -- Playwright.BrowserName=chromium Playwright.LaunchOptions.Channel=chromium
```
With the new headless mode, you can skip downloading the headless shell during browser installation by using the `--no-shell` option:
```bash js
# only running tests headlessly
npx playwright install --with-deps --no-shell
```
```bash java
# only running tests headlessly
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps --no-shell"
```
```bash python
# only running tests headlessly
playwright install --with-deps --no-shell
```
```bash csharp
# only running tests headlessly
pwsh bin/Debug/netX/playwright.ps1 install --with-deps --no-shell
```
### Google Chrome & Microsoft Edge
While Playwright can download and use the recent Chromium build, it can operate against the branded Google Chrome and Microsoft Edge browsers available on the machine (note that Playwright doesn't install them by default). In particular, the current Playwright version will support Stable and Beta channels of these browsers.
Available channels are `chrome`, `msedge`, `chrome-beta`, `msedge-beta` or `msedge-dev`.
Available channels are `chrome`, `msedge`, `chrome-beta`, `msedge-beta`, `chrome-dev`, `msedge-dev`, `chrome-canary`, `msedge-canary`.
:::warning
Certain Enterprise Browser Policies may impact Playwright's ability to launch and control Google Chrome and Microsoft Edge. Running in an environment with browser policies is outside of the Playwright project's scope.
:::
:::warning
Google Chrome and Microsoft Edge have switched to a [new headless mode](https://developer.chrome.com/docs/chromium/headless) implementation that is closer to a regular headed mode. This differs from [chromium headless shell](https://developer.chrome.com/blog/chrome-headless-shell) that is used in Playwright by default when running headless, so expect different behavior in some cases. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) fore details.
Google Chrome and Microsoft Edge have switched to a [new headless mode](https://developer.chrome.com/docs/chromium/headless) implementation that is closer to a regular headed mode. This differs from [chromium headless shell](https://developer.chrome.com/blog/chrome-headless-shell) that is used in Playwright by default when running headless, so expect different behavior in some cases. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for details.
:::
```js

View file

@ -9,7 +9,9 @@ title: "Chrome extensions"
Extensions only work in Chrome / Chromium launched with a persistent context. Use custom browser args at your own risk, as some of them may break Playwright functionality.
:::
The following is code for getting a handle to the [background page](https://developer.chrome.com/extensions/background_pages) of a [Manifest v2](https://developer.chrome.com/docs/extensions/mv2/) extension whose source is located in `./my-extension`:
The snippet below retrieves the [background page](https://developer.chrome.com/extensions/background_pages) of a [Manifest v2](https://developer.chrome.com/docs/extensions/mv2/) extension whose source is located in `./my-extension`.
Note the use of the `chromium` channel that allows to run extensions in headless mode. Alternatively, you can launch the browser in headed mode.
```js
const { chromium } = require('playwright');
@ -18,7 +20,7 @@ const { chromium } = require('playwright');
const pathToExtension = require('path').join(__dirname, 'my-extension');
const userDataDir = '/tmp/test-user-data-dir';
const browserContext = await chromium.launchPersistentContext(userDataDir, {
headless: false,
channel: 'chromium',
args: [
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`
@ -44,7 +46,7 @@ user_data_dir = "/tmp/test-user-data-dir"
async def run(playwright: Playwright):
context = await playwright.chromium.launch_persistent_context(
user_data_dir,
headless=False,
channel="chromium",
args=[
f"--disable-extensions-except={path_to_extension}",
f"--load-extension={path_to_extension}",
@ -78,7 +80,7 @@ user_data_dir = "/tmp/test-user-data-dir"
def run(playwright: Playwright):
context = playwright.chromium.launch_persistent_context(
user_data_dir,
headless=False,
channel="chromium",
args=[
f"--disable-extensions-except={path_to_extension}",
f"--load-extension={path_to_extension}",
@ -101,6 +103,8 @@ with sync_playwright() as playwright:
To have the extension loaded when running tests you can use a test fixture to set the context. You can also dynamically retrieve the extension id and use it to load and test the popup page for example.
Note the use of the `chromium` channel that allows to run extensions in headless mode. Alternatively, you can launch the browser in headed mode.
First, add fixtures that will load the extension:
```js title="fixtures.ts"
@ -114,7 +118,7 @@ export const test = base.extend<{
context: async ({ }, use) => {
const pathToExtension = path.join(__dirname, 'my-extension');
const context = await chromium.launchPersistentContext('', {
headless: false,
channel: 'chromium',
args: [
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`,
@ -155,7 +159,7 @@ def context(playwright: Playwright) -> Generator[BrowserContext, None, None]:
path_to_extension = Path(__file__).parent.joinpath("my-extension")
context = playwright.chromium.launch_persistent_context(
"",
headless=False,
channel="chromium",
args=[
f"--disable-extensions-except={path_to_extension}",
f"--load-extension={path_to_extension}",
@ -211,35 +215,3 @@ def test_popup_page(page: Page, extension_id: str) -> None:
page.goto(f"chrome-extension://{extension_id}/popup.html")
expect(page.locator("body")).to_have_text("my-extension popup")
```
## Headless mode
By default, Chrome's headless mode in Playwright does not support Chrome extensions. To overcome this limitation, you can run Chrome's persistent context with a new headless mode by using the following code:
```js title="fixtures.ts"
// ...
const pathToExtension = path.join(__dirname, 'my-extension');
const context = await chromium.launchPersistentContext('', {
headless: false,
args: [
`--headless=new`,
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`,
],
});
// ...
```
```python title="conftest.py"
path_to_extension = Path(__file__).parent.joinpath("my-extension")
context = playwright.chromium.launch_persistent_context(
"",
headless=False,
args=[
"--headless=new",
f"--disable-extensions-except={path_to_extension}",
f"--load-extension={path_to_extension}",
],
)
```

View file

@ -21,7 +21,7 @@ Playwright tests can be run on any CI provider. This guide covers one way of run
## Introduction
* langs: python, java, csharp
Playwright tests can be ran on any CI provider. In this section we will cover running tests on GitHub using GitHub actions. If you would like to see how to configure other CI providers check out our detailed doc on Continuous Integration.
Playwright tests can be run on any CI provider. In this section we will cover running tests on GitHub using GitHub actions. If you would like to see how to configure other CI providers check out our detailed doc on Continuous Integration.
#### You will learn
* langs: python, java, csharp

View file

@ -454,11 +454,11 @@ jobs:
### Docker
We have a [pre-built Docker image](./docker.md) which can either be used directly, or as a reference to update your existing Docker definitions.
We have a [pre-built Docker image](./docker.md) which can either be used directly or as a reference to update your existing Docker definitions.
Suggested configuration
1. Using `--ipc=host` is also recommended when using Chromium. Without it Chromium can run out of memory
and crash. Learn more about this option in [Docker docs](https://docs.docker.com/engine/reference/run/#ipc-settings---ipc).
and crash. Learn more about this option in [Docker docs](https://docs.docker.com/reference/cli/docker/container/run/#ipc).
1. Seeing other weird errors when launching Chromium? Try running your container
with `docker run --cap-add=SYS_ADMIN` when developing locally.
1. Using `--init` Docker flag or [dumb-init](https://github.com/Yelp/dumb-init) is recommended to avoid special
@ -466,7 +466,7 @@ Suggested configuration
### Azure Pipelines
For Windows or macOS agents, no additional configuration required, just install Playwright and run your tests.
For Windows or macOS agents, no additional configuration is required, just install Playwright and run your tests.
For Linux agents, you can use [our Docker container](./docker.md) with Azure
Pipelines support [running containerized
@ -804,7 +804,7 @@ Sharding in CircleCI is indexed with 0 which means that you will need to overrid
executor: pw-noble-development
parallelism: 4
steps:
- run: SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npx playwright test -- --shard=${SHARD}/${CIRCLE_NODE_TOTAL}
- run: SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npx playwright test --shard=${SHARD}/${CIRCLE_NODE_TOTAL}
```
### Jenkins

View file

@ -34,6 +34,10 @@ The recommended approach is to use `setFixedTime` to set the time to a specific
- `Event.timeStamp`
:::
:::warning
If you call `install` at any point in your test, the call _MUST_ occur before any other clock related calls (see note above for list). Calling these methods out of order will result in undefined behavior. For example, you cannot call `setInterval`, followed by `install`, then `clearInterval`, as `install` overrides the native definition of the clock functions.
:::
## Test with predefined time
Often you only need to fake `Date.now` while keeping the timers going.
@ -164,11 +168,11 @@ await Page.GotoAsync("http://localhost:3333");
await Page.Clock.PauseAtAsync(new DateTime(2024, 2, 2, 10, 0, 0));
// Assert the page state.
await Expect(Page.GetByTestId("current-time")).ToHaveText("2/2/2024, 10:00:00 AM");
await Expect(Page.GetByTestId("current-time")).ToHaveTextAsync("2/2/2024, 10:00:00 AM");
// Close the laptop lid again and open it at 10:30am.
await Page.Clock.FastForwardAsync("30:00");
await Expect(Page.GetByTestId("current-time")).ToHaveText("2/2/2024, 10:30:00 AM");
await Expect(Page.GetByTestId("current-time")).ToHaveTextAsync("2/2/2024, 10:30:00 AM");
```
## Test inactivity monitoring

View file

@ -21,7 +21,7 @@ Install the VS Code extension and generate tests directly from VS Code. The exte
### Record a New Test
To record a test click on the **Record new** button from the Testing sidebar. This will create a `test-1.spec.ts` file as well as open up a browser window.
To record a test click on the **Record new** button from the Testing sidebar. This will create a `test-1.spec.ts` file as well as open up a browser window.
<img width="1385" alt="record new in vs code" src="https://user-images.githubusercontent.com/13063165/220961665-615d0ab8-3f0b-439c-ad0b-0424d9aa154b.png" />
@ -58,16 +58,16 @@ In the test file in VS Code you will see your new generated actions added to you
### Generating locators
You can generate locators with the test generator.
- Click on the **Pick locator** button form the testing sidebar and then hover over elements in the browser window to see the [locator](./locators.md) highlighted underneath each element.
- Click the element you require and it will now show up in the **Pick locator** box in VS Code.
You can generate locators with the test generator.
- Click on the **Pick locator** button form the testing sidebar and then hover over elements in the browser window to see the [locator](./locators.md) highlighted underneath each element.
- Click the element you require and it will now show up in the **Pick locator** box in VS Code.
- Press <kbd>Enter</kbd> on your keyboard to copy the locator into the clipboard and then paste anywhere in your code. Or press 'escape' if you want to cancel.
<img width="1641" alt="Pick locators in VS code" src="https://user-images.githubusercontent.com/13063165/220958368-95b03620-3c9b-40a8-be74-01c96ba03cad.png" />
## Generate tests with the Playwright Inspector
When running the `codegen` command two windows will be opened, a browser window where you interact with the website you wish to test and the Playwright Inspector window where you can record your tests and then copy them into your editor.
When running the `codegen` command two windows will be opened, a browser window where you interact with the website you wish to test and the Playwright Inspector window where you can record your tests and then copy them into your editor.
### Running Codegen
@ -128,10 +128,10 @@ When you have finished interacting with the page, press the **record** button to
Use the **clear** button to clear the code to start recording again. Once finished, close the Playwright inspector window or stop the terminal command.
### Generating locators
You can generate [locators](/locators.md) with the test generator.
You can generate [locators](/locators.md) with the test generator.
* Press the `'Record'` button to stop the recording and the `'Pick Locator'` button will appear.
* Click on the `'Pick Locator'` button and then hover over elements in the browser window to see the locator highlighted underneath each element.
* Click on the `'Pick Locator'` button and then hover over elements in the browser window to see the locator highlighted underneath each element.
* To choose a locator, click on the element you would like to locate and the code for that locator will appear in the field next to the Pick Locator button.
* You can then edit the locator in this field to fine tune it or use the copy button to copy it and paste it into your code.
@ -164,19 +164,19 @@ You can use the test generator to generate tests using emulation so as to genera
Playwright opens a browser window with its viewport set to a specific width and height and is not responsive as tests need to be run under the same conditions. Use the `--viewport` option to generate tests with a different viewport size.
```bash js
npx playwright codegen --viewport-size=800,600 playwright.dev
npx playwright codegen --viewport-size="800,600" playwright.dev
```
```bash java
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="codegen --viewport-size=800,600 playwright.dev"
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="codegen --viewport-size='800,600' playwright.dev"
```
```bash python
playwright codegen --viewport-size=800,600 playwright.dev
playwright codegen --viewport-size="800,600" playwright.dev
```
```bash csharp
pwsh bin/Debug/netX/playwright.ps1 codegen --viewport-size=800,600 playwright.dev
pwsh bin/Debug/netX/playwright.ps1 codegen --viewport-size="800,600" playwright.dev
```
######
* langs: js
@ -325,7 +325,7 @@ pwsh bin/Debug/netX/playwright.ps1 codegen --timezone="Europe/Rome" --geolocatio
### Preserve authenticated state
Run `codegen` with `--save-storage` to save [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) at the end of the session. This is useful to separately record an authentication step and reuse it later when recording more tests.
Run `codegen` with `--save-storage` to save [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) data at the end of the session. This is useful to separately record an authentication step and reuse it later when recording more tests.
```bash js
npx playwright codegen github.com/microsoft/playwright --save-storage=auth.json
@ -367,7 +367,7 @@ pwsh bin/Debug/netX/playwright.ps1 codegen github.com/microsoft/playwright --sav
#### Login
After performing authentication and closing the browser, `auth.json` will contain the storage state which you can then reuse in your tests.
After performing authentication and closing the browser, `auth.json` will contain the storage state which you can then reuse in your tests.
<img width="1394" alt="login to GitHub screen" src="https://user-images.githubusercontent.com/13063165/220561688-04b2b984-4ba6-4446-8b0a-8058876e2a02.png" />
@ -375,7 +375,7 @@ Make sure you only use the `auth.json` locally as it contains sensitive informat
#### Load authenticated state
Run with `--load-storage` to consume the previously loaded storage from the `auth.json`. This way, all [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) will be restored, bringing most web apps to the authenticated state without the need to login again. This means you can continue generating tests from the logged in state.
Run with `--load-storage` to consume the previously loaded storage from the `auth.json`. This way, all [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) data will be restored, bringing most web apps to the authenticated state without the need to login again. This means you can continue generating tests from the logged in state.
```bash js
npx playwright codegen --load-storage=auth.json github.com/microsoft/playwright

View file

@ -103,6 +103,88 @@ Using `--ipc=host` is recommended when using Chrome ([Docker docs](https://docs.
See our [Continuous Integration guides](./ci.md) for sample configs.
### Remote Connection
You can run Playwright Server in Docker while keeping your tests running on the host system or another machine. This is useful for running tests on unsupported Linux distributions or remote execution scenarios.
#### Running the Playwright Server
Start the Playwright Server in Docker:
```bash
docker run -p 3000:3000 --rm --init -it --workdir /home/pwuser --user pwuser mcr.microsoft.com/playwright:v%%VERSION%%-noble /bin/sh -c "npx -y playwright@%%VERSION%% run-server --port 3000 --host 0.0.0.0"
```
#### Connecting to the Server
* langs: js
There are two ways to connect to the remote Playwright server:
1. Using environment variable with `@playwright/test`:
```bash
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:3000/ npx playwright test
```
2. Using the [`method: BrowserType.connect`] API for other applications:
```js
const browser = await playwright['chromium'].connect('ws://127.0.0.1:3000/');
```
#### Connecting to the Server
* langs: python, csharp, java
```python sync
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.connect("ws://127.0.0.1:3000/")
```
```python async
from playwright.async_api import async_playwright
async with async_playwright() as p:
browser = await p.chromium.connect("ws://127.0.0.1:3000/")
```
```csharp
using Microsoft.Playwright;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.ConnectAsync("ws://127.0.0.1:3000/");
```
```java
package org.example;
import com.microsoft.playwright.*;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().connect("ws://127.0.0.1:3000/");
}
}
}
```
#### Network Configuration
If you need to access local servers from within the Docker container:
```bash
docker run --add-host=hostmachine:host-gateway -p 3000:3000 --rm --init -it --workdir /home/pwuser --user pwuser mcr.microsoft.com/playwright:v%%VERSION%%-noble /bin/sh -c "npx -y playwright@%%VERSION%% run-server --port 3000 --host 0.0.0.0"
```
This makes `hostmachine` point to the host's localhost. Your tests should use `hostmachine` instead of `localhost` when accessing local servers.
:::note
When running tests remotely, ensure the Playwright version in your tests matches the version running in the Docker container.
:::
## Image tags
See [all available image tags].
@ -132,7 +214,7 @@ Browser builds for Firefox and WebKit are built for the [glibc](https://en.wikip
You can use the [.NET install script](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script) in order to install different SDK versions:
```bash
curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --install-dir /usr/share/dotnet --channel 6.0
curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --install-dir /usr/share/dotnet --channel 9.0
```
## Build your own image

View file

@ -217,7 +217,7 @@ await page.getByText('Item').click({ button: 'right' });
// Shift + click
await page.getByText('Item').click({ modifiers: ['Shift'] });
// Ctrl + click or Windows and Linux
// Ctrl + click on Windows and Linux
// Meta + click on macOS
await page.getByText('Item').click({ modifiers: ['ControlOrMeta'] });
@ -241,7 +241,7 @@ page.getByText("Item").click(new Locator.ClickOptions().setButton(MouseButton.RI
// Shift + click
page.getByText("Item").click(new Locator.ClickOptions().setModifiers(Arrays.asList(KeyboardModifier.SHIFT)));
// Ctrl + click or Windows and Linux
// Ctrl + click on Windows and Linux
// Meta + click on macOS
page.getByText("Item").click(new Locator.ClickOptions().setModifiers(Arrays.asList(KeyboardModifier.CONTROL_OR_META)));
@ -265,7 +265,7 @@ await page.get_by_text("Item").click(button="right")
# Shift + click
await page.get_by_text("Item").click(modifiers=["Shift"])
# Ctrl + click or Windows and Linux
# Ctrl + click on Windows and Linux
# Meta + click on macOS
await page.get_by_text("Item").click(modifiers=["ControlOrMeta"])
@ -309,7 +309,7 @@ await page.GetByText("Item").ClickAsync(new() { Button = MouseButton.Right });
// Shift + click
await page.GetByText("Item").ClickAsync(new() { Modifiers = new[] { KeyboardModifier.Shift } });
// Ctrl + click or Windows and Linux
// Ctrl + click on Windows and Linux
// Meta + click on macOS
await page.GetByText("Item").ClickAsync(new() { Modifiers = new[] { KeyboardModifier.ControlOrMeta } });

View file

@ -7,7 +7,7 @@ title: "Installation"
Playwright was created specifically to accommodate the needs of end-to-end testing. Playwright supports all modern rendering engines including Chromium, WebKit, and Firefox. Test on Windows, Linux, and macOS, locally or on CI, headless or headed with native mobile emulation.
You can choose to use [MSTest base classes](./test-runners.md#mstest) or [NUnit base classes](./test-runners.md#nunit) that Playwright provides to write end-to-end tests. These classes support running tests on multiple browser engines, parallelizing tests, adjusting launch/context options and getting a [Page]/[BrowserContext] instance per test out of the box. Alternatively you can use the [library](./library.md) to manually write the testing infrastructure.
You can choose to use MSTest, NUnit, or xUnit [base classes](./test-runners.md) that Playwright provides to write end-to-end tests. These classes support running tests on multiple browser engines, parallelizing tests, adjusting launch/context options and getting a [Page]/[BrowserContext] instance per test out of the box. Alternatively you can use the [library](./library.md) to manually write the testing infrastructure.
1. Start by creating a new project with `dotnet new`. This will create the `PlaywrightTests` directory which includes a `UnitTest1.cs` file:
@ -17,6 +17,7 @@ You can choose to use [MSTest base classes](./test-runners.md#mstest) or [NUnit
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -34,6 +35,14 @@ dotnet new mstest -n PlaywrightTests
cd PlaywrightTests
```
</TabItem>
<TabItem value="xunit">
```bash
dotnet new xunit -n PlaywrightTests
cd PlaywrightTests
```
</TabItem>
</Tabs>
@ -45,6 +54,7 @@ cd PlaywrightTests
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -60,6 +70,13 @@ dotnet add package Microsoft.Playwright.NUnit
dotnet add package Microsoft.Playwright.MSTest
```
</TabItem>
<TabItem value="xunit">
```bash
dotnet add package Microsoft.Playwright.Xunit
```
</TabItem>
</Tabs>
@ -87,6 +104,7 @@ Edit the `UnitTest1.cs` file with the code below to create an example end-to-end
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -164,6 +182,41 @@ public class ExampleTest : PageTest
```
</TabItem>
<TabItem value="xunit">
```csharp title="UnitTest1.cs"
using System.Text.RegularExpressions;
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
namespace PlaywrightTests;
public class UnitTest1: PageTest
{
[Fact]
public async Task HasTitle()
{
await Page.GotoAsync("https://playwright.dev");
// Expect a title "to contain" a substring.
await Expect(Page).ToHaveTitleAsync(new Regex("Playwright"));
}
[Fact]
public async Task GetStartedLink()
{
await Page.GotoAsync("https://playwright.dev");
// Click the get started link.
await Page.GetByRole(AriaRole.Link, new() { Name = "Get started" }).ClickAsync();
// Expects page to have a heading with the name of Installation.
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Installation" })).ToBeVisibleAsync();
}
}
```
</TabItem>
</Tabs>
## Running the Example Tests
@ -190,4 +243,4 @@ See our doc on [Running and Debugging Tests](./running-tests.md) to learn more a
- [Generate tests with Codegen](./codegen-intro.md)
- [See a trace of your tests](./trace-viewer-intro.md)
- [Run tests on CI](./ci-intro.md)
- [Learn more about the MSTest and NUnit base classes](./test-runners.md)
- [Learn more about the MSTest, NUnit, and xUnit base classes](./test-runners.md)

View file

@ -80,7 +80,7 @@ The `tests` folder contains a basic example test to help you get started with te
## Running the Example Test
By default tests will be run on all 3 browsers, chromium, firefox and webkit using 3 workers. This can be configured in the [playwright.config file](./test-configuration.md). Tests are run in headless mode meaning no browser will open up when running the tests. Results of the tests and test logs will be shown in the terminal.
By default tests will be run on all 3 browsers, Chromium, Firefox and WebKit using 3 workers. This can be configured in the [playwright.config file](./test-configuration.md). Tests are run in headless mode meaning no browser will open up when running the tests. Results of the tests and test logs will be shown in the terminal.
<Tabs
defaultValue="npm"
@ -286,7 +286,7 @@ pnpm exec playwright --version
## System requirements
- Node.js 18+
- Latest version of Node.js 18, 20 or 22.
- Windows 10+, Windows Server 2016+ or Windows Subsystem for Linux (WSL).
- macOS 13 Ventura, or later.
- Debian 12, Ubuntu 22.04, Ubuntu 24.04, on x86-64 and arm64 architecture.

View file

@ -30,7 +30,7 @@ You can choose any testing framework such as JUnit or TestNG based on your proje
## .NET
Playwright for .NET comes with [MSTest base classes](https://playwright.dev/dotnet/docs/test-runners#mstest) and [NUnit base classes](https://playwright.dev/dotnet/docs/test-runners#nunit) for writing end-to-end tests.
Playwright for .NET comes with MSTest, NUnit, and xUnit [base classes](https://playwright.dev/dotnet/docs/test-runners) for writing end-to-end tests.
* [Documentation](https://playwright.dev/dotnet/docs/intro)
* [GitHub repo](https://github.com/microsoft/playwright-dotnet)

View file

@ -5,7 +5,7 @@ title: "Getting started - Library"
## Introduction
Playwright can either be used with the [MSTest](./test-runners.md#mstest) or [NUnit](./test-runners.md#nunit), or as a Playwright Library (this guide). If you are working on an application that utilizes Playwright capabilities or you are using Playwright with another test runner, read on.
Playwright can either be used with the [MSTest, NUnit, or xUnit base classes](./test-runners.md) or as a Playwright Library (this guide). If you are working on an application that utilizes Playwright capabilities or you are using Playwright with another test runner, read on.
## Usage

View file

@ -751,10 +751,10 @@ page.locator("x-details", new Page.LocatorOptions().setHasText("Details"))
.click();
```
```python async
await page.locator("x-details", has_text="Details" ).click()
await page.locator("x-details", has_text="Details").click()
```
```python sync
page.locator("x-details", has_text="Details" ).click()
page.locator("x-details", has_text="Details").click()
```
```csharp
await page
@ -1310,19 +1310,19 @@ Consider a page with two buttons, the first invisible and the second [visible](.
* This will only find a second button, because it is visible, and then click it.
```js
await page.locator('button').locator('visible=true').click();
await page.locator('button').filter({ visible: true }).click();
```
```java
page.locator("button").locator("visible=true").click();
page.locator("button").filter(new Locator.FilterOptions.setVisible(true)).click();
```
```python async
await page.locator("button").locator("visible=true").click()
await page.locator("button").filter(visible=True).click()
```
```python sync
page.locator("button").locator("visible=true").click()
page.locator("button").filter(visible=True).click()
```
```csharp
await page.Locator("button").Locator("visible=true").ClickAsync();
await page.Locator("button").Filter(new() { Visible = true }).ClickAsync();
```
## Lists

View file

@ -115,8 +115,7 @@ await page.GotoAsync("https://example.com");
You can configure pages to load over the HTTP(S) proxy or SOCKSv5. Proxy can be either set globally
for the entire browser, or for each browser context individually.
You can optionally specify username and password for HTTP(S) proxy, you can also specify hosts to
bypass proxy for.
You can optionally specify username and password for HTTP(S) proxy, you can also specify hosts to bypass the [`option: Browser.newContext.proxy`] for.
Here is an example of a global proxy:
@ -709,9 +708,13 @@ Playwright uses simplified glob patterns for URL matching in network interceptio
- A double `**` matches any characters including `/`
1. Question mark `?` matches any single character except `/`
1. Curly braces `{}` can be used to match a list of options separated by commas `,`
1. Square brackets `[]` can be used to match a set of characters
1. Backslash `\` can be used to escape any of special characters (note to escape backslash itself as `\\`)
Examples:
- `https://example.com/*.js` matches `https://example.com/file.js` but not `https://example.com/path/file.js`
- `https://example.com/\\?page=1` matches `https://example.com/?page=1` but not `https://example.com`
- `**/v[0-9]*` matches `https://example.com/v1/` but not `https://example.com/vote/`
- `**/*.js` matches both `https://example.com/file.js` and `https://example.com/path/file.js`
- `**/*.{png,jpg,jpeg}` matches all image requests

View file

@ -4,6 +4,122 @@ title: "Release notes"
toc_max_heading_level: 2
---
## Version 1.50
### Support for Xunit
* Support for xUnit 2.8+ via [Microsoft.Playwright.Xunit](https://www.nuget.org/packages/Microsoft.Playwright.Xunit). Follow our [Getting Started](./intro.md) guide to learn more.
### Miscellaneous
* Added method [`method: LocatorAssertions.toHaveAccessibleErrorMessage`] to assert the Locator points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage).
### UI updates
* New button in Codegen for picking elements to produce aria snapshots.
* Additional details (such as keys pressed) are now displayed alongside action API calls in traces.
* Display of `canvas` content in traces is error-prone. Display is now disabled by default, and can be enabled via the `Display canvas content` UI setting.
* `Call` and `Network` panels now display additional time information.
### Breaking
* [`method: LocatorAssertions.toBeEditable`] and [`method: Locator.isEditable`] now throw if the target element is not `<input>`, `<select>`, or a number of other editable elements.
### Browser Versions
* Chromium 133.0.6943.16
* Mozilla Firefox 134.0
* WebKit 18.2
This version was also tested against the following stable channels:
* Google Chrome 132
* Microsoft Edge 132
## Version 1.49
### Aria snapshots
New assertion [`method: LocatorAssertions.toMatchAriaSnapshot`] verifies page structure by comparing to an expected accessibility tree, represented as YAML.
```csharp
await page.GotoAsync("https://playwright.dev");
await Expect(page.Locator("body")).ToMatchAriaSnapshotAsync(@"
- banner:
- heading /Playwright enables reliable/ [level=1]
- link ""Get started""
- link ""Star microsoft/playwright on GitHub""
- main:
- img ""Browsers (Chromium, Firefox, WebKit)""
- heading ""Any browser • Any platform • One API""
");
```
You can generate this assertion with [Test Generator](./codegen) or by calling [`method: Locator.ariaSnapshot`].
Learn more in the [aria snapshots guide](./aria-snapshots).
### Tracing groups
New method [`method: Tracing.group`] allows you to visually group actions in the trace viewer.
```csharp
// All actions between GroupAsync and GroupEndAsync
// will be shown in the trace viewer as a group.
await Page.Context.Tracing.GroupAsync("Open Playwright.dev > API");
await Page.GotoAsync("https://playwright.dev/");
await Page.GetByRole(AriaRole.Link, new() { Name = "API" }).ClickAsync();
await Page.Context.Tracing.GroupEndAsync();
```
### Breaking: `chrome` and `msedge` channels switch to new headless mode
This change affects you if you're using one of the following channels in your `playwright.config.ts`:
- `chrome`, `chrome-dev`, `chrome-beta`, or `chrome-canary`
- `msedge`, `msedge-dev`, `msedge-beta`, or `msedge-canary`
After updating to Playwright v1.49, run your test suite. If it still passes, you're good to go. If not, you will probably need to update your snapshots, and adapt some of your test code around PDF viewers and extensions. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for more details.
### Try new Chromium headless
You can opt into the new headless mode by using `'chromium'` channel. As [official Chrome documentation puts it](https://developer.chrome.com/blog/chrome-headless-shell):
> New Headless on the other hand is the real Chrome browser, and is thus more authentic, reliable, and offers more features. This makes it more suitable for high-accuracy end-to-end web app testing or browser extension testing.
See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for the list of possible breakages you could encounter and more details on Chromium headless. Please file an issue if you see any problems after opting in.
```xml csharp title="runsettings.xml"
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<Playwright>
<BrowserName>chromium</BrowserName>
<LaunchOptions>
<Channel>chromium</Channel>
</LaunchOptions>
</Playwright>
</RunSettings>
```
```bash csharp
dotnet test -- Playwright.BrowserName=chromium Playwright.LaunchOptions.Channel=chromium
```
### Miscellaneous
- There will be no more updates for WebKit on Ubuntu 20.04 and Debian 11. We recommend updating your OS to a later version.
- `<canvas>` elements inside a snapshot now draw a preview.
### Browser Versions
- Chromium 131.0.6778.33
- Mozilla Firefox 132.0
- WebKit 18.2
This version was also tested against the following stable channels:
- Google Chrome 130
- Microsoft Edge 130
## Version 1.48
@ -708,9 +824,9 @@ This version was also tested against the following stable channels:
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
```
@ -788,7 +904,7 @@ All the same methods are also available on [Locator], [FrameLocator] and [Frame]
- [`method: LocatorAssertions.toHaveAttribute`] with an empty value does not match missing attribute anymore. For example, the following snippet will succeed when `button` **does not** have a `disabled` attribute.
```csharp
await Expect(Page.GetByRole(AriaRole.Button)).ToHaveAttribute("disabled", "");
await Expect(Page.GetByRole(AriaRole.Button)).ToHaveAttributeAsync("disabled", "");
```
### Browser Versions

View file

@ -4,6 +4,107 @@ title: "Release notes"
toc_max_heading_level: 2
---
## Version 1.50
### Miscellaneous
* Added method [`method: LocatorAssertions.toHaveAccessibleErrorMessage`] to assert the Locator points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage).
### UI updates
* New button in Codegen for picking elements to produce aria snapshots.
* Additional details (such as keys pressed) are now displayed alongside action API calls in traces.
* Display of `canvas` content in traces is error-prone. Display is now disabled by default, and can be enabled via the `Display canvas content` UI setting.
* `Call` and `Network` panels now display additional time information.
### Breaking
* [`method: LocatorAssertions.toBeEditable`] and [`method: Locator.isEditable`] now throw if the target element is not `<input>`, `<select>`, or a number of other editable elements.
### Browser Versions
* Chromium 133.0.6943.16
* Mozilla Firefox 134.0
* WebKit 18.2
This version was also tested against the following stable channels:
* Google Chrome 132
* Microsoft Edge 132
## Version 1.49
### Aria snapshots
New assertion [`method: LocatorAssertions.toMatchAriaSnapshot`] verifies page structure by comparing to an expected accessibility tree, represented as YAML.
```java
page.navigate("https://playwright.dev");
assertThat(page.locator("body")).matchesAriaSnapshot("""
- banner:
- heading /Playwright enables reliable/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- main:
- img "Browsers (Chromium, Firefox, WebKit)"
- heading "Any browser • Any platform • One API"
""");
```
You can generate this assertion with [Test Generator](./codegen) or by calling [`method: Locator.ariaSnapshot`].
Learn more in the [aria snapshots guide](./aria-snapshots).
### Tracing groups
New method [`method: Tracing.group`] allows you to visually group actions in the trace viewer.
```java
// All actions between group and groupEnd
// will be shown in the trace viewer as a group.
page.context().tracing().group("Open Playwright.dev > API");
page.navigate("https://playwright.dev/");
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("API")).click();
page.context().tracing().groupEnd();
```
### Breaking: `chrome` and `msedge` channels switch to new headless mode
This change affects you if you're using one of the following channels in your `playwright.config.ts`:
- `chrome`, `chrome-dev`, `chrome-beta`, or `chrome-canary`
- `msedge`, `msedge-dev`, `msedge-beta`, or `msedge-canary`
After updating to Playwright v1.49, run your test suite. If it still passes, you're good to go. If not, you will probably need to update your snapshots, and adapt some of your test code around PDF viewers and extensions. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for more details.
### Try new Chromium headless
You can opt into the new headless mode by using `'chromium'` channel. As [official Chrome documentation puts it](https://developer.chrome.com/blog/chrome-headless-shell):
> New Headless on the other hand is the real Chrome browser, and is thus more authentic, reliable, and offers more features. This makes it more suitable for high-accuracy end-to-end web app testing or browser extension testing.
See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for the list of possible breakages you could encounter and more details on Chromium headless. Please file an issue if you see any problems after opting in.
```java
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setChannel("chromium"));
```
### Miscellaneous
- There will be no more updates for WebKit on Ubuntu 20.04 and Debian 11. We recommend updating your OS to a later version.
- `<canvas>` elements inside a snapshot now draw a preview.
### Browser Versions
- Chromium 131.0.6778.33
- Mozilla Firefox 132.0
- WebKit 18.2
This version was also tested against the following stable channels:
- Google Chrome 130
- Microsoft Edge 130
## Version 1.48
### WebSocket routing
@ -787,9 +888,9 @@ This version was also tested against the following stable channels:
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
```

View file

@ -6,8 +6,82 @@ toc_max_heading_level: 2
import LiteYouTube from '@site/src/components/LiteYouTube';
## Version 1.50
### Test runner
* New option [`option: Test.step.timeout`] allows specifying a maximum run time for an individual test step. A timed-out step will fail the execution of the test.
```js
test('some test', async ({ page }) => {
await test.step('a step', async () => {
// This step can time out separately from the test
}, { timeout: 1000 });
});
```
* New method [`method: Test.step.skip`] to disable execution of a test step.
```js
test('some test', async ({ page }) => {
await test.step('before running step', async () => {
// Normal step
});
await test.step.skip('not yet ready', async () => {
// This step is skipped
});
await test.step('after running step', async () => {
// This step still runs even though the previous one was skipped
});
});
```
* Expanded [`method: LocatorAssertions.toMatchAriaSnapshot#2`] to allow storing of aria snapshots in separate YAML files.
* Added method [`method: LocatorAssertions.toHaveAccessibleErrorMessage`] to assert the Locator points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage).
* Option [`property: TestConfig.updateSnapshots`] added the configuration enum `changed`. `changed` updates only the snapshots that have changed, whereas `all` now updates all snapshots, regardless of whether there are any differences.
* New option [`property: TestConfig.updateSourceMethod`] defines the way source code is updated when [`property: TestConfig.updateSnapshots`] is configured. Added `overwrite` and `3-way` modes that write the changes into source code, on top of existing `patch` mode that creates a patch file.
```bash
npx playwright test --update-snapshots=changed --update-source-method=3way
```
* Option [`property: TestConfig.webServer`] added a `gracefulShutdown` field for specifying a process kill signal other than the default `SIGKILL`.
* Exposed [`property: TestStep.attachments`] from the reporter API to allow retrieval of all attachments created by that step.
* New option `pathTemplate` for `toHaveScreenshot` and `toMatchAriaSnapshot` assertions in the [`property: TestConfig.expect`] configuration.
### UI updates
* Updated default HTML reporter to improve display of attachments.
* New button in Codegen for picking elements to produce aria snapshots.
* Additional details (such as keys pressed) are now displayed alongside action API calls in traces.
* Display of `canvas` content in traces is error-prone. Display is now disabled by default, and can be enabled via the `Display canvas content` UI setting.
* `Call` and `Network` panels now display additional time information.
### Breaking
* [`method: LocatorAssertions.toBeEditable`] and [`method: Locator.isEditable`] now throw if the target element is not `<input>`, `<select>`, or a number of other editable elements.
* Option [`property: TestConfig.updateSnapshots`] now updates all snapshots when set to `all`, rather than only the failed/changed snapshots. Use the new enum `changed` to keep the old functionality of only updating the changed snapshots.
### Browser Versions
* Chromium 133.0.6943.16
* Mozilla Firefox 134.0
* WebKit 18.2
This version was also tested against the following stable channels:
* Google Chrome 132
* Microsoft Edge 132
## Version 1.49
<LiteYouTube
id="S5wCft-ImKk"
title="Playwright 1.49"
/>
### Aria snapshots
New assertion [`method: LocatorAssertions.toMatchAriaSnapshot`] verifies page structure by comparing to an expected accessibility tree, represented as YAML.
@ -38,53 +112,15 @@ Learn more in the [aria snapshots guide](./aria-snapshots).
- Added "previous" and "next" buttons to the HTML report to quickly switch between test cases.
- New properties [`property: TestInfoError.cause`] and [`property: TestError.cause`] mirroring [`Error.cause`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause).
### Breaking: channels `chrome`, `msedge` and similar switch to new headless
### Breaking: `chrome` and `msedge` channels switch to new headless mode
Prior to this release, Playwright was running the old established implementation of [Chromium headless mode](https://developer.chrome.com/docs/chromium/headless). However, Chromium had entirely **switched to the new headless mode**, and **removed the old one**.
This change affects you if you're using one of the following channels in your `playwright.config.ts`:
- `chrome`, `chrome-dev`, `chrome-beta`, or `chrome-canary`
- `msedge`, `msedge-dev`, `msedge-beta`, or `msedge-canary`
![Chromium Headless](https://github.com/user-attachments/assets/2829e86a-dfe2-4743-a6d4-2aa65beea890)
#### What do I need to do?
If you are using a browser channel, for example `'chrome'` or `'msedge'`, the headless mode switch **will affect you**. Most likely, you will have to update some of your tests and all of your screenshot expectations. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for more details.
#### Chromium headless shell
Starting with this release, Playwright downloads and runs two different browser builds - one is a regular headed chromium and the other is a chromium headless shell. This should be transparent to you, **no action is needed**. You can learn more in [issue #33566](https://github.com/microsoft/playwright/issues/33566).
If you are only running tests in headless, for example on CI, you can avoid downloading a headed version of Chromium by specifying `chromium-headless-shell` during installation.
```bash
# only running tests headlessly
npx playwright install chromium-headless-shell firefox webkit
```
Playwright will skip downloading headed chromium build, and will use `chromium-headless-shell` when running headless.
#### Opt-in to new headless
We encourage everyone to try and switch to the new headless by using the `chromium-next` channel.
First, install this channel prior to running tests. Make sure to list all the browsers that you use.
```bash
npx playwright install chromium-next firefox webkit
```
Then update your config file to specify `'chromium-next'` channel.
```js
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
channel: 'chromium-next',
},
},
],
});
```
After updating to Playwright v1.49, run your test suite. If it still passes, you're good to go. If not, you will probably need to update your snapshots, and adapt some of your test code around PDF viewers and extensions. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for more details.
### Other breaking changes
@ -92,6 +128,27 @@ export default defineConfig({
- Package `@playwright/experimental-ct-vue2` will no longer be updated.
- Package `@playwright/experimental-ct-solid` will no longer be updated.
### Try new Chromium headless
You can opt into the new headless mode by using `'chromium'` channel. As [official Chrome documentation puts it](https://developer.chrome.com/blog/chrome-headless-shell):
> New Headless on the other hand is the real Chrome browser, and is thus more authentic, reliable, and offers more features. This makes it more suitable for high-accuracy end-to-end web app testing or browser extension testing.
See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for the list of possible breakages you could encounter and more details on Chromium headless. Please file an issue if you see any problems after opting in.
```js
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'], channel: 'chromium' },
},
],
});
```
### Miscellaneous
- `<canvas>` elements inside a snapshot now draw a preview.
@ -1441,9 +1498,9 @@ This version was also tested against the following stable channels:
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
```

View file

@ -4,6 +4,112 @@ title: "Release notes"
toc_max_heading_level: 2
---
## Version 1.50
### Async Pytest Plugin
* [Playwright's Pytest plugin](./test-runners.md) now has support for [Async Fixtures](https://playwright.dev/python/docs/test-runners#async-fixtures).
### Miscellaneous
* Added method [`method: LocatorAssertions.toHaveAccessibleErrorMessage`] to assert the Locator points to an element with a given [aria errormessage](https://w3c.github.io/aria/#aria-errormessage).
### UI updates
* New button in Codegen for picking elements to produce aria snapshots.
* Additional details (such as keys pressed) are now displayed alongside action API calls in traces.
* Display of `canvas` content in traces is error-prone. Display is now disabled by default, and can be enabled via the `Display canvas content` UI setting.
* `Call` and `Network` panels now display additional time information.
### Breaking
* [`method: LocatorAssertions.toBeEditable`] and [`method: Locator.isEditable`] now throw if the target element is not `<input>`, `<select>`, or a number of other editable elements.
### Browser Versions
* Chromium 133.0.6943.16
* Mozilla Firefox 134.0
* WebKit 18.2
This version was also tested against the following stable channels:
* Google Chrome 132
* Microsoft Edge 132
## Version 1.49
### Aria snapshots
New assertion [`method: LocatorAssertions.toMatchAriaSnapshot`] verifies page structure by comparing to an expected accessibility tree, represented as YAML.
```python
page.goto("https://playwright.dev")
expect(page.locator('body')).to_match_aria_snapshot('''
- banner:
- heading /Playwright enables reliable/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- main:
- img "Browsers (Chromium, Firefox, WebKit)"
- heading "Any browser • Any platform • One API"
''')
```
You can generate this assertion with [Test Generator](./codegen) or by calling [`method: Locator.ariaSnapshot`].
Learn more in the [aria snapshots guide](./aria-snapshots).
### Tracing groups
New method [`method: Tracing.group`] allows you to visually group actions in the trace viewer.
```python
# All actions between group and group_end
# will be shown in the trace viewer as a group.
page.context.tracing.group("Open Playwright.dev > API")
page.goto("https://playwright.dev/")
page.get_by_role("link", name="API").click()
page.context.tracing.group_end()
```
### Breaking: `chrome` and `msedge` channels switch to new headless mode
This change affects you if you're using one of the following channels in your `playwright.config.ts`:
- `chrome`, `chrome-dev`, `chrome-beta`, or `chrome-canary`
- `msedge`, `msedge-dev`, `msedge-beta`, or `msedge-canary`
After updating to Playwright v1.49, run your test suite. If it still passes, you're good to go. If not, you will probably need to update your snapshots, and adapt some of your test code around PDF viewers and extensions. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for more details.
### Try new Chromium headless
You can opt into the new headless mode by using `'chromium'` channel. As [official Chrome documentation puts it](https://developer.chrome.com/blog/chrome-headless-shell):
> New Headless on the other hand is the real Chrome browser, and is thus more authentic, reliable, and offers more features. This makes it more suitable for high-accuracy end-to-end web app testing or browser extension testing.
See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for the list of possible breakages you could encounter and more details on Chromium headless. Please file an issue if you see any problems after opting in.
```bash python
pytest test_login.py --browser-channel chromium
```
### Miscellaneous
- There will be no more updates for WebKit on Ubuntu 20.04 and Debian 11. We recommend updating your OS to a later version.
- `<canvas>` elements inside a snapshot now draw a preview.
- Python 3.8 is not supported anymore.
### Browser Versions
- Chromium 131.0.6778.33
- Mozilla Firefox 132.0
- WebKit 18.2
This version was also tested against the following stable channels:
- Google Chrome 130
- Microsoft Edge 130
## Version 1.48
### WebSocket routing
@ -694,9 +800,9 @@ This version was also tested against the following stable channels:
```html
<select multiple>
<option value="red">Red</div>
<option value="green">Green</div>
<option value="blue">Blue</div>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
```

View file

@ -113,6 +113,7 @@ dotnet test --filter "Name~GetStartedLink"
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -128,6 +129,19 @@ dotnet test -- NUnit.NumberOfTestWorkers=5
dotnet test -- MSTest.Parallelize.Workers=5
```
</TabItem>
<TabItem value="xunit">
```bash
dotnet test -- xUnit.MaxParallelThreads=5
```
See [here](https://xunit.net/docs/running-tests-in-parallel.html) for more information to run tests in parallel with xUnit.
:::note
We recommend xUnit 2.8+ which uses the [`conservative` parallelism algorithm](https://xunit.net/docs/running-tests-in-parallel.html#algorithms) by default.
:::
</TabItem>
</Tabs>

View file

@ -33,7 +33,7 @@ npx playwright test --ui
![UI Mode](https://github.com/microsoft/playwright/assets/13063165/c5b501cc-4f5d-485a-87cc-66044c651786)
Check out or [detailed guide on UI Mode](./test-ui-mode.md) to learn more about it's features.
Check out or [detailed guide on UI Mode](./test-ui-mode.md) to learn more about its features.
### Run tests in headed mode
@ -112,11 +112,11 @@ npx playwright test --ui
![showing errors in ui mode](https://github.com/microsoft/playwright/assets/13063165/ffca2fd1-5349-41fb-ade9-ace143bb2c58)
While debugging you can use the Pick Locator button to select an element on the page and see the locator that Playwright would use to find that element. You can also edit the locator in the locator playground and see it highlighting live on the Browser window. Use the Copy Locator button to copy the locator to your clipboard and then paste it into you test.
While debugging you can use the Pick Locator button to select an element on the page and see the locator that Playwright would use to find that element. You can also edit the locator in the locator playground and see it highlighting live on the Browser window. Use the Copy Locator button to copy the locator to your clipboard and then paste it into your test.
![pick locator in ui mode](https://github.com/microsoft/playwright/assets/13063165/9e7eeb84-bd26-4010-8614-75e24b56c716)
Check out our [detailed guide on UI Mode](./test-ui-mode.md) to learn more about it's features.
Check out our [detailed guide on UI Mode](./test-ui-mode.md) to learn more about its features.
### Debug tests with the Playwright Inspector

View file

@ -93,8 +93,8 @@ See [`property: TestConfig.reporter`].
## property: FullConfig.reportSlowTests
* since: v1.10
- type: <[null]|[Object]>
- `max` <[int]> The maximum number of slow test files to report. Defaults to `5`.
- `threshold` <[float]> Test duration in milliseconds that is considered slow. Defaults to 15 seconds.
- `max` <[int]> The maximum number of slow test files to report.
- `threshold` <[float]> Test file duration in milliseconds that is considered slow.
See [`property: TestConfig.reportSlowTests`].
@ -114,10 +114,16 @@ See [`property: TestConfig.shard`].
## property: FullConfig.updateSnapshots
* since: v1.10
- type: <[UpdateSnapshots]<"all"|"none"|"missing">>
- type: <[UpdateSnapshots]<"all"|"changed"|"missing"|"none">>
See [`property: TestConfig.updateSnapshots`].
## property: FullConfig.updateSourceMethod
* since: v1.50
- type: <[UpdateSourceMethod]<"overwrite"|"3way"|"patch">>
See [`property: TestConfig.updateSourceMethod`].
## property: FullConfig.version
* since: v1.20
- type: <[string]>

View file

@ -1751,7 +1751,7 @@ Step name.
### param: Test.step.body
* since: v1.10
- `body` <[function]\(\):[Promise]<[any]>>
- `body` <[function]\([TestStepInfo]\):[Promise]<[any]>>
Step body.
@ -1767,6 +1767,63 @@ Whether to box the step in the report. Defaults to `false`. When the step is box
Specifies a custom location for the step to be shown in test reports and trace viewer. By default, location of the [`method: Test.step`] call is shown.
## async method: Test.step.skip
* since: v1.50
- returns: <[void]>
Mark a test step as "skip" to temporarily disable its execution, useful for steps that are currently failing and planned for a near-term fix. Playwright will not run the step.
**Usage**
You can declare a skipped step, and Playwright will not run it.
```js
import { test, expect } from '@playwright/test';
test('my test', async ({ page }) => {
// ...
await test.step.skip('not yet ready', async () => {
// ...
});
});
```
### param: Test.step.skip.title
* since: v1.50
- `title` <[string]>
Step name.
### param: Test.step.skip.body
* since: v1.50
- `body` <[function]\(\):[Promise]<[any]>>
Step body.
### option: Test.step.skip.box
* since: v1.50
- `box` <boolean>
Whether to box the step in the report. Defaults to `false`. When the step is boxed, errors thrown from the step internals point to the step call site. See below for more details.
### option: Test.step.skip.location
* since: v1.50
- `location` <[Location]>
Specifies a custom location for the step to be shown in test reports and trace viewer. By default, location of the [`method: Test.step`] call is shown.
### option: Test.step.skip.timeout
* since: v1.50
- `timeout` <[float]>
Maximum time in milliseconds for the step to finish. Defaults to `0` (no timeout).
### option: Test.step.timeout
* since: v1.50
- `timeout` <[float]>
The maximum time, in milliseconds, allowed for the step to complete. If the step does not complete within the specified timeout, the [`method: Test.step`] method will throw a [TimeoutError]. Defaults to `0` (no timeout).
## method: Test.use
* since: v1.10

View file

@ -48,6 +48,9 @@ export default defineConfig({
- `scale` ?<[ScreenshotScale]<"css"|"device">> See [`option: Page.screenshot.scale`] in [`method: Page.screenshot`]. Defaults to `"css"`.
- `stylePath` ?<[string]|[Array]<[string]>> See [`option: Page.screenshot.style`] in [`method: Page.screenshot`].
- `threshold` ?<[float]> An acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and `1` (lax). `"pixelmatch"` comparator computes color difference in [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`.
- `pathTemplate` ?<[string]> A template controlling location of the screenshots. See [`property: TestConfig.snapshotPathTemplate`] for details.
- `toMatchAriaSnapshot` ?<[Object]> Configuration for the [`method: LocatorAssertions.toMatchAriaSnapshot#2`] method.
- `pathTemplate` ?<[string]> A template controlling location of the aria snapshots. See [`property: TestConfig.snapshotPathTemplate`] for details.
- `toMatchSnapshot` ?<[Object]> Configuration for the [`method: SnapshotAssertions.toMatchSnapshot#1`] method.
- `maxDiffPixels` ?<[int]> An acceptable amount of pixels that could be different, unset by default.
- `maxDiffPixelRatio` ?<[float]> An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
@ -234,7 +237,12 @@ export default defineConfig({
* since: v1.10
- type: ?<[Metadata]>
Metadata that will be put directly to the test report serialized as JSON.
Metadata contains key-value pairs to be included in the report. For example, HTML report will display it as key-value pairs, and JSON report will include metadata serialized as json.
* Providing `gitCommit: 'generate'` property will populate it with the git commit details.
* Providing `gitDiff: 'generate'` property will populate it with the git diff details.
On selected CI providers, both will be generated automatically. Specifying values will prevent the automatic generation.
**Usage**
@ -242,7 +250,7 @@ Metadata that will be put directly to the test report serialized as JSON.
import { defineConfig } from '@playwright/test';
export default defineConfig({
metadata: 'acceptance tests',
metadata: { title: 'acceptance tests' },
});
```
@ -421,7 +429,7 @@ export default defineConfig({
* since: v1.10
- type: ?<[null]|[Object]>
- `max` <[int]> The maximum number of slow test files to report. Defaults to `5`.
- `threshold` <[float]> Test duration in milliseconds that is considered slow. Defaults to 15 seconds.
- `threshold` <[float]> Test file duration in milliseconds that is considered slow. Defaults to 5 minutes.
Whether to report slow test files. Pass `null` to disable this feature.
@ -570,12 +578,13 @@ export default defineConfig({
## property: TestConfig.updateSnapshots
* since: v1.10
- type: ?<[UpdateSnapshots]<"all"|"none"|"missing">>
- type: ?<[UpdateSnapshots]<"all"|"changed"|"missing"|"none">>
Whether to update expected snapshots with the actual results produced by the test run. Defaults to `'missing'`.
* `'all'` - All tests that are executed will update snapshots that did not match. Matching snapshots will not be updated.
* `'none'` - No snapshots are updated.
* `'all'` - All tests that are executed will update snapshots.
* `'changed'` - All tests that are executed will update snapshots that did not match. Matching snapshots will not be updated.
* `'missing'` - Missing snapshots are created, for example when authoring a new test and running it for the first time. This is the default.
* `'none'` - No snapshots are updated.
Learn more about [snapshots](../test-snapshots.md).
@ -589,6 +598,15 @@ export default defineConfig({
});
```
## property: TestConfig.updateSourceMethod
* since: v1.50
- type: ?<[UpdateSourceMethod]<"overwrite"|"3way"|"patch">>
Defines how to update snapshots in the source code.
* `'patch'` - Create a unified diff file that can be used to update the source code later. This is the default.
* `'3way'` - Generate merge conflict markers in source code. This allows user to manually pick relevant changes, as if they are resolving a merge conflict in the IDE.
* `'overwrite'` - Overwrite the source code with the new snapshot values.
## property: TestConfig.use
* since: v1.10
- type: ?<[TestOptions]>
@ -619,6 +637,9 @@ export default defineConfig({
- `stdout` ?<["pipe"|"ignore"]> If `"pipe"`, it will pipe the stdout of the command to the process stdout. If `"ignore"`, it will ignore the stdout of the command. Default to `"ignore"`.
- `stderr` ?<["pipe"|"ignore"]> Whether to pipe the stderr of the command to the process stderr or ignore it. Defaults to `"pipe"`.
- `timeout` ?<[int]> How long to wait for the process to start up and be available in milliseconds. Defaults to 60000.
- `gracefulShutdown` ?<[Object]> How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: 'SIGTERM', timeout: 500 }`, the process group is sent a `SIGTERM` signal, followed by `SIGKILL` if it doesn't exit within 500ms. You can also use `SIGINT` as the signal instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't support `SIGTERM` and `SIGINT` signals, so this option is ignored on Windows. Note that shutting down a Docker container requires `SIGTERM`.
- `signal` <["SIGINT"|"SIGTERM"]>
- `timeout` <[int]>
- `url` ?<[string]> The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is checked. Either `port` or `url` should be specified.
Launch a development web server (or multiple) during the tests.
@ -642,7 +663,7 @@ import { defineConfig } from '@playwright/test';
export default defineConfig({
webServer: {
command: 'npm run start',
url: 'http://127.0.0.1:3000',
url: 'http://localhost:3000',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
},
@ -671,19 +692,19 @@ export default defineConfig({
webServer: [
{
command: 'npm run start',
url: 'http://127.0.0.1:3000',
url: 'http://localhost:3000',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
},
{
command: 'npm run backend',
url: 'http://127.0.0.1:3333',
url: 'http://localhost:3333',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
}
],
use: {
baseURL: 'http://127.0.0.1:3000',
baseURL: 'http://localhost:3000',
},
});
```

View file

@ -392,8 +392,11 @@ export default defineConfig({
});
```
## property: TestOptions.locale = %%-context-option-locale-%%
## property: TestOptions.locale
* since: v1.10
- type: <[string]>
Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, `Accept-Language` request header value as well as number and date formatting rules. Defaults to `en-US`. Learn more about emulation in our [emulation guide](../emulation.md#locale--timezone).
**Usage**
@ -504,6 +507,27 @@ export default defineConfig({
Learn more about [automatic screenshots](../test-use-options.md#recording-options).
## property: TestOptions.pageSnapshot
* since: v1.51
- type: <[PageSnapshotMode]<"off"|"on"|"only-on-failure">>
Whether to automatically capture a ARIA snapshot of the page after each test. Defaults to `'only-on-failure'`.
* `'off'`: Do not capture page snapshots.
* `'on'`: Capture page snapshot after each test.
* `'only-on-failure'`: Capture page snapshot after each test failure.
**Usage**
```js title="playwright.config.ts"
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
pageSnapshot: 'on',
},
});
```
## property: TestOptions.storageState = %%-js-python-context-option-storage-state-%%
* since: v1.10

View file

@ -98,6 +98,9 @@ export default defineConfig({
- `caret` ?<[ScreenshotCaret]<"hide"|"initial">> See [`option: Page.screenshot.caret`] in [`method: Page.screenshot`]. Defaults to `"hide"`.
- `scale` ?<[ScreenshotScale]<"css"|"device">> See [`option: Page.screenshot.scale`] in [`method: Page.screenshot`]. Defaults to `"css"`.
- `stylePath` ?<[string]|[Array]<[string]>> See [`option: Page.screenshot.style`] in [`method: Page.screenshot`].
- `pathTemplate` ?<[string]> A template controlling location of the screenshots. See [`property: TestProject.snapshotPathTemplate`] for details.
- `toMatchAriaSnapshot` ?<[Object]> Configuration for the [`method: LocatorAssertions.toMatchAriaSnapshot#2`] method.
- `pathTemplate` ?<[string]> A template controlling location of the aria snapshots. See [`property: TestProject.snapshotPathTemplate`] for details.
- `toMatchSnapshot` ?<[Object]> Configuration for the [`method: SnapshotAssertions.toMatchSnapshot#1`] method.
- `threshold` ?<[float]> an acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and `1` (lax). `"pixelmatch"` comparator computes color difference in [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`.
- `maxDiffPixels` ?<[int]> an acceptable amount of pixels that could be different, unset by default.
@ -180,6 +183,10 @@ Metadata that will be put directly to the test report serialized as JSON.
Project name is visible in the report and during test execution.
:::warning
Playwright executes the configuration file multiple times. Do not dynamically produce non-stable values in your configuration.
:::
## property: TestProject.snapshotDir
* since: v1.10
- type: ?<[string]>

View file

@ -0,0 +1,103 @@
# class: TestStepInfo
* since: v1.51
* langs: js
`TestStepInfo` contains information about currently running test step. It is passed as an argument to the step function. `TestStepInfo` provides utilities to control test step execution.
```js
import { test, expect } from '@playwright/test';
test('basic test', async ({ page, browserName }, TestStepInfo) => {
await test.step('check some behavior', async step => {
await step.skip(browserName === 'webkit', 'The feature is not available in WebKit');
// ... rest of the step code
await page.check('input');
});
});
```
## async method: TestStepInfo.attach
* since: v1.51
Attach a value or a file from disk to the current test step. Some reporters show test step attachments. Either [`option: path`] or [`option: body`] must be specified, but not both. Calling this method will attribute the attachment to the step, as opposed to [`method: TestInfo.attach`] which stores all attachments at the test level.
For example, you can attach a screenshot to the test step:
```js
import { test, expect } from '@playwright/test';
test('basic test', async ({ page }) => {
await page.goto('https://playwright.dev');
await test.step('check page rendering', async step => {
const screenshot = await page.screenshot();
await step.attach('screenshot', { body: screenshot, contentType: 'image/png' });
});
});
```
Or you can attach files returned by your APIs:
```js
import { test, expect } from '@playwright/test';
import { download } from './my-custom-helpers';
test('basic test', async ({}) => {
await test.step('check download behavior', async step => {
const tmpPath = await download('a');
await step.attach('downloaded', { path: tmpPath });
});
});
```
:::note
[`method: TestStepInfo.attach`] automatically takes care of copying attached files to a
location that is accessible to reporters. You can safely remove the attachment
after awaiting the attach call.
:::
### param: TestStepInfo.attach.name
* since: v1.51
- `name` <[string]>
Attachment name. The name will also be sanitized and used as the prefix of file name
when saving to disk.
### option: TestStepInfo.attach.body
* since: v1.51
- `body` <[string]|[Buffer]>
Attachment body. Mutually exclusive with [`option: path`].
### option: TestStepInfo.attach.contentType
* since: v1.51
- `contentType` <[string]>
Content type of this attachment to properly present in the report, for example `'application/json'` or `'image/png'`. If omitted, content type is inferred based on the [`option: path`], or defaults to `text/plain` for [string] attachments and `application/octet-stream` for [Buffer] attachments.
### option: TestStepInfo.attach.path
* since: v1.51
- `path` <[string]>
Path on the filesystem to the attached file. Mutually exclusive with [`option: body`].
## method: TestStepInfo.skip#1
* since: v1.51
Unconditionally skip the currently running step. Test step is immediately aborted. This is similar to [`method: Test.step.skip`].
## method: TestStepInfo.skip#2
* since: v1.51
Conditionally skips the currently running step with an optional description. This is similar to [`method: Test.step.skip`].
### param: TestStepInfo.skip#2.condition
* since: v1.51
- `condition` <[boolean]>
A skip condition. Test step is skipped when the condition is `true`.
### param: TestStepInfo.skip#2.description
* since: v1.51
- `description` ?<[string]>
Optional description that will be reflected in a test report.

View file

@ -81,6 +81,7 @@ expect.set_options(timeout=10_000)
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -127,6 +128,24 @@ public class UnitTest1 : PageTest
}
```
</TabItem>
<TabItem value="xunit">
```csharp title="UnitTest1.cs"
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
namespace PlaywrightTests;
public class UnitTest1: PageTest
{
UnitTest1()
{
SetDefaultExpectTimeout(10_000);
}
// ...
}
```
</TabItem>
</Tabs>

View file

@ -76,33 +76,41 @@ Here are the most common options available in the command line.
Complete set of Playwright Test options is available in the [configuration file](./test-use-options.md). Following options can be passed to a command line and take priority over the configuration file:
<!-- // Note: packages/playwright/src/program.ts is the source of truth. -->
| Option | Description |
| :- | :- |
| Non-option arguments | Each argument is treated as a regular expression matched against the full test file path. Only tests from the files matching the pattern will be executed. Special symbols like `$` or `*` should be escaped with `\`. In many shells/terminals you may need to quote the arguments. |
| `-c <file>` or `--config <file>`| Configuration file. If not passed, defaults to `playwright.config.ts` or `playwright.config.js` in the current directory. |
| `--debug`| Run tests with Playwright Inspector. Shortcut for `PWDEBUG=1` environment variable and `--timeout=0 --max-failures=1 --headed --workers=1` options.|
| `--fail-on-flaky-tests` | Fails test runs that contain flaky tests. By default flaky tests count as successes. |
| `--forbid-only` | Whether to disallow `test.only`. Useful on CI.|
| `--global-timeout <number>` | Total timeout for the whole test run in milliseconds. By default, there is no global timeout. Learn more about [various timeouts](./test-timeouts.md).|
| `-g <grep>` or `--grep <grep>` | Only run tests matching this regular expression. For example, this will run `'should add to cart'` when passed `-g "add to cart"`. The regular expression will be tested against the string that consists of the project name, test file name, `test.describe` titles if any, test title and all test tags, separated by spaces, e.g. `chromium my-test.spec.ts my-suite my-test @smoke`. The filter does not apply to the tests from dependency projects, i.e. Playwright will still run all tests from [project dependencies](./test-projects.md#dependencies). |
| `--grep-invert <grep>` | Only run tests **not** matching this regular expression. The opposite of `--grep`. The filter does not apply to the tests from dependency projects, i.e. Playwright will still run all tests from [project dependencies](./test-projects.md#dependencies).|
| `--headed` | Run tests in headed browsers. Useful for debugging. |
| `--ignore-snapshots` | Whether to ignore [snapshots](./test-snapshots.md). Use this when snapshot expectations are known to be different, e.g. running tests on Linux against Windows screenshots. |
| `--last-failed` | Only re-run the failures.|
| `--list` | list all the tests, but do not run them.|
| `--max-failures <N>` or `-x`| Stop after the first `N` test failures. Passing `-x` stops after the first failure.|
| `--no-deps` | Ignore the dependencies between projects and behave as if they were not specified. |
| `--output <dir>` | Directory for artifacts produced by tests, defaults to `test-results`. |
| `--only-changed [ref]` | Only run test files that have been changed between working tree and "ref". Defaults to running all uncommitted changes with ref=HEAD. Only supports Git. |
| `--pass-with-no-tests` | Allows the test suite to pass when no files are found. |
| `--project <name>` | Only run tests from the specified [projects](./test-projects.md), supports '*' wildcard. Defaults to running all projects defined in the configuration file.|
| `--quiet` | Whether to suppress stdout and stderr from the tests. |
| `--repeat-each <N>` | Run each test `N` times, defaults to one. |
| `--reporter <reporter>` | Choose a reporter: minimalist `dot`, concise `line` or detailed `list`. See [reporters](./test-reporters.md) for more information. You can also pass a path to a [custom reporter](./test-reporters.md#custom-reporters) file. |
| `--retries <number>` | The maximum number of [retries](./test-retries.md#retries) for flaky tests, defaults to zero (no retries). |
| `--shard <shard>` | [Shard](./test-parallel.md#shard-tests-between-multiple-machines) tests and execute only selected shard, specified in the form `current/all`, 1-based, for example `3/5`.|
| `--timeout <number>` | Maximum timeout in milliseconds for each test, defaults to 30 seconds. Learn more about [various timeouts](./test-timeouts.md).|
| `--trace <mode>` | Force tracing mode, can be `on`, `off`, `on-first-retry`, `on-all-retries`, `retain-on-failure` |
| `--tsconfig <path>` | Path to a single tsconfig applicable to all imported files. See [tsconfig resolution](./test-typescript.md#tsconfig-resolution) for more details. |
| `--update-snapshots` or `-u` | Whether to update [snapshots](./test-snapshots.md) with actual results instead of comparing them. Use this when snapshot expectations have changed.|
| `--workers <number>` or `-j <number>`| The maximum number of concurrent worker processes that run in [parallel](./test-parallel.md). |
| Non-option arguments | Each argument is treated as a regular expression matched against the full test file path. Only tests from files matching the pattern will be executed. Special symbols like `$` or `*` should be escaped with `\`. In many shells/terminals you may need to quote the arguments. |
| `-c <file>` or `--config <file>` | Configuration file, or a test directory with optional "playwright.config.&#123;m,c&#125;?&#123;js,ts&#125;". Defaults to `playwright.config.ts` or `playwright.config.js` in the current directory. |
| `--debug` | Run tests with Playwright Inspector. Shortcut for `PWDEBUG=1` environment variable and `--timeout=0 --max-failures=1 --headed --workers=1` options. |
| `--fail-on-flaky-tests` | Fail if any test is flagged as flaky (default: false). |
| `--forbid-only` | Fail if `test.only` is called (default: false). Useful on CI. |
| `--fully-parallel` | Run all tests in parallel (default: false). |
| `--global-timeout <timeout>` | Maximum time this test suite can run in milliseconds (default: unlimited). |
| `-g <grep>` or `--grep <grep>` | Only run tests matching this regular expression (default: ".*"). |
| `-gv <grep>` or `--grep-invert <grep>` | Only run tests that do not match this regular expression. |
| `--headed` | Run tests in headed browsers (default: headless). |
| `--ignore-snapshots` | Ignore screenshot and snapshot expectations. |
| `--last-failed` | Only re-run the failures. |
| `--list` | Collect all the tests and report them, but do not run. |
| `--max-failures <N>` or `-x` | Stop after the first `N` failures. Passing `-x` stops after the first failure. |
| `--no-deps` | Do not run project dependencies. |
| `--output <dir>` | Folder for output artifacts (default: "test-results"). |
| `--only-changed [ref]` | Only run test files that have been changed between 'HEAD' and 'ref'. Defaults to running all uncommitted changes. Only supports Git. |
| `--pass-with-no-tests` | Makes test run succeed even if no tests were found. |
| `--project <project-name...>` | Only run tests from the specified list of projects, supports '*' wildcard (default: run all projects). |
| `--quiet` | Suppress stdio. |
| `--repeat-each <N>` | Run each test `N` times (default: 1). |
| `--reporter <reporter>` | Reporter to use, comma-separated, can be "dot", "line", "list", or others (default: "list"). You can also pass a path to a custom reporter file. |
| `--retries <retries>` | Maximum retry count for flaky tests, zero for no retries (default: no retries). |
| `--shard <shard>` | Shard tests and execute only the selected shard, specified in the form "current/all", 1-based, e.g., "3/5". |
| `--timeout <timeout>` | Specify test timeout threshold in milliseconds, zero for unlimited (default: 30 seconds). |
| `--trace <mode>` | Force tracing mode, can be "on", "off", "on-first-retry", "on-all-retries", "retain-on-failure", "retain-on-first-failure". |
| `--tsconfig <path>` | Path to a single tsconfig applicable to all imported files (default: look up tsconfig for each imported file separately). |
| `--ui` | Run tests in interactive UI mode. |
| `--ui-host <host>` | Host to serve UI on; specifying this option opens UI in a browser tab. |
| `--ui-port <port>` | Port to serve UI on, 0 for any free port; specifying this option opens UI in a browser tab. |
| `-u` or `--update-snapshots [mode]` | Update snapshots with actual results. Possible values are "all", "changed", "missing", and "none". Running tests without the flag defaults to "missing"; running tests with the flag but without a value defaults to "changed". |
| `--update-source-method [mode]` | Update snapshots with actual results. Possible values are "patch" (default), "3way" and "overwrite". "Patch" creates a unified diff file that can be used to update the source code later. "3way" generates merge conflict markers in source code. "Overwrite" overwrites the source code with the new snapshot values.|
| `-j <workers>` or `--workers <workers>` | Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker (default: 50%). |
| `-x` | Stop after the first failure. |

View file

@ -853,6 +853,14 @@ export default defineConfig({
});
```
### How do I use CSS imports?
If you have a component that imports CSS, Vite will handle it automatically. You can also use CSS pre-processors such as Sass, Less, or Stylus, and Vite will handle them as well without any additional configuration. However, corresponding CSS pre-processor needs to be installed.
Vite has a hard requirement that all CSS Modules are named `*.module.[css extension]`. If you have a custom build config for your project normally and have imports of the form `import styles from 'styles.css'` you must rename your files to properly indicate they are to be treated as modules. You could also write a Vite plugin to handle this for you.
Check [Vite documentation](https://vite.dev/guide/features#css) for more details.
### How can I test components that uses Pinia?
Pinia needs to be initialized in `playwright/index.{js,ts,jsx,tsx}`. If you do this inside a `beforeMount` hook, the `initialState` can be overwritten on a per-test basis:

View file

@ -35,7 +35,7 @@ export default defineConfig({
use: {
// Base URL to use in actions like `await page.goto('/')`.
baseURL: 'http://127.0.0.1:3000',
baseURL: 'http://localhost:3000',
// Collect trace when retrying the failed test.
trace: 'on-first-retry',
@ -50,7 +50,7 @@ export default defineConfig({
// Run your local dev server before starting the tests.
webServer: {
command: 'npm run start',
url: 'http://127.0.0.1:3000',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
});

View file

@ -115,8 +115,8 @@ test.describe('todo tests', () => {
### With fixtures
Fixtures have a number of advantages over before/after hooks:
- Fixtures **encapsulate** setup and teardown in the same place so it is easier to write.
- Fixtures are **reusable** between test files - you can define them once and use in all your tests. That's how Playwright's built-in `page` fixture works.
- Fixtures **encapsulate** setup and teardown in the same place so it is easier to write. So if you have an after hook that tears down what was created in a before hook, consider turning them into a fixture.
- Fixtures are **reusable** between test files - you can define them once and use in all your tests. That's how Playwright's built-in `page` fixture works. So if you have a helper function that is used in multiple tests, consider turning it into a fixture.
- Fixtures are **on-demand** - you can define as many fixtures as you'd like, and Playwright Test will setup only the ones needed by your test and nothing else.
- Fixtures are **composable** - they can depend on each other to provide complex behaviors.
- Fixtures are **flexible**. Tests can use any combinations of the fixtures to tailor precise environment they need, without affecting other tests.
@ -407,8 +407,8 @@ Automatic fixtures are set up for each test/worker, even when the test does not
Here is an example fixture that automatically attaches debug logs when the test fails, so we can later review the logs in the reporter. Note how it uses [TestInfo] object that is available in each test/fixture to retrieve metadata about the test being run.
```js title="my-test.ts"
import * as debug from 'debug';
import * as fs from 'fs';
import debug from 'debug';
import fs from 'fs';
import { test as base } from '@playwright/test';
export const test = base.extend<{ saveLogs: void }>({
@ -695,7 +695,7 @@ test('passes', async ({ database, page, a11y }) => {
## Box fixtures
Usually, custom fixtures are reported as separate steps in in the UI mode, Trace Viewer and various test reports. They also appear in error messages from the test runner. For frequently-used fixtures, this can mean lots of noise. You can stop the fixtures steps from being shown in the UI by "boxing" it.
Usually, custom fixtures are reported as separate steps in the UI mode, Trace Viewer and various test reports. They also appear in error messages from the test runner. For frequently-used fixtures, this can mean lots of noise. You can stop the fixtures steps from being shown in the UI by "boxing" it.
```js
import { test as base } from '@playwright/test';

View file

@ -129,7 +129,13 @@ You can use the `globalSetup` option in the [configuration file](./test-configur
Similarly, use `globalTeardown` to run something once after all the tests. Alternatively, let `globalSetup` return a function that will be used as a global teardown. You can pass data such as port number, authentication tokens, etc. from your global setup to your tests using environment variables.
:::note
Using `globalSetup` and `globalTeardown` will not produce traces or artifacts, and options like `headless` or `testIdAttribute` specified in the config file are not applied. If you want to produce traces and artifacts and respect config options, use [project dependencies](#option-1-project-dependencies).
Beware of `globalSetup` and `globalTeardown` caveats:
- These methods will not produce traces or artifacts unless explictly enabled, as described in [Capturing trace of failures during global setup](#capturing-trace-of-failures-during-global-setup).
- Options sush as `headless` or `testIdAttribute` specified in the config file are not applied,
- An uncaught exception thrown in `globalSetup` will prevent Playwright from running tests, and no test results will appear in reporters.
Consider using [project dependencies](#option-1-project-dependencies) to produce traces, artifacts, respect config options and get test results in reporters even in case of a setup failure.
:::
```js title="playwright.config.ts"

View file

@ -50,6 +50,24 @@ Start time of this particular test step.
List of steps inside this step.
## property: TestStep.annotations
* since: v1.51
- type: <[Array]<[Object]>>
- `type` <[string]> Annotation type, for example `'skip'`.
- `description` ?<[string]> Optional description.
The list of annotations applicable to the current test step.
## property: TestStep.attachments
* since: v1.50
- type: <[Array]<[Object]>>
- `name` <[string]> Attachment name.
- `contentType` <[string]> Content type of this attachment to properly present in the report, for example `'application/json'` or `'image/png'`.
- `path` ?<[string]> Optional path on the filesystem to the attached file.
- `body` ?<[Buffer]> Optional attachment body used instead of a file.
The list of files or buffers attached in the step execution through [`method: TestInfo.attach`].
## property: TestStep.title
* since: v1.10
- type: <[string]>

View file

@ -5,19 +5,64 @@ title: "Test Runners"
## Introduction
While Playwright for .NET isn't tied to a particular test runner or testing framework, in our experience the easiest way of getting started is by using the base classes we provide for [MSTest](#mstest) and [NUnit](#nunit). These classes support running tests on multiple browser engines, adjusting launch/context options and getting a [Page]/[BrowserContext] instance per test out of the box.
While Playwright for .NET isn't tied to a particular test runner or testing framework, in our experience the easiest way of getting started is by using the base classes we provide for MSTest, NUnit, or xUnit. These classes support running tests on multiple browser engines, adjusting launch/context options and getting a [Page]/[BrowserContext] instance per test out of the box.
Playwright and Browser instances will be reused between tests for better performance. We
recommend running each test case in a new BrowserContext, this way browser state will be
isolated between the tests.
## MSTest
<Tabs
groupId="test-runners"
defaultValue="mstest"
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
Playwright provides base classes to write tests with NUnit via the [`Microsoft.Playwright.NUnit`](https://www.nuget.org/packages/Microsoft.Playwright.NUnit) package.
</TabItem>
<TabItem value="mstest">
Playwright provides base classes to write tests with MSTest via the [`Microsoft.Playwright.MSTest`](https://www.nuget.org/packages/Microsoft.Playwright.MSTest) package.
</TabItem>
<TabItem value="xunit">
Playwright provides base classes to write tests with xUnit via the [`Microsoft.Playwright.Xunit`](https://www.nuget.org/packages/Microsoft.Playwright.Xunit) package.
</TabItem>
</Tabs>
Check out the [installation guide](./intro.md) to get started.
### Running MSTest tests in Parallel
## Running tests in Parallel
<Tabs
groupId="test-runners"
defaultValue="mstest"
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
By default NUnit will run all test files in parallel, while running tests inside each file sequentially (`ParallelScope.Self`). It will create as many processes as there are cores on the host system. You can adjust this behavior using the NUnit.NumberOfTestWorkers parameter.
Only `ParallelScope.Self` is supported.
For CPU-bound tests, we recommend using as many workers as there are cores on your system, divided by 2. For IO-bound tests you can use as many workers as you have cores.
```bash
dotnet test -- NUnit.NumberOfTestWorkers=5
```
</TabItem>
<TabItem value="mstest">
By default MSTest will run all classes in parallel, while running tests inside each class sequentially (`ExecutionScope.ClassLevel`). It will create as many processes as there are cores on the host system. You can adjust this behavior by using the following CLI parameter or using a `.runsettings` file, see below.
Running tests in parallel at the method level (`ExecutionScope.MethodLevel`) is not supported.
@ -26,7 +71,73 @@ Running tests in parallel at the method level (`ExecutionScope.MethodLevel`) is
dotnet test --settings:.runsettings -- MSTest.Parallelize.Workers=4
```
### Customizing [BrowserContext] options
</TabItem>
<TabItem value="xunit">
By default xUnit will run all classes in parallel, while running tests inside each class sequentially.
It will create by default as many processes as there are cores on the system. You can adjust this behavior by using the following CLI parameter or using a `.runsettings` file, see below.
```bash
dotnet test -- xUnit.MaxParallelThreads=5
```
:::note
We recommend xUnit 2.8+ which uses the [`conservative` parallelism algorithm](https://xunit.net/docs/running-tests-in-parallel.html#algorithms) by default.
:::
</TabItem>
</Tabs>
## Customizing [BrowserContext] options
<Tabs
groupId="test-runners"
defaultValue="mstest"
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
To customize context options, you can override the `ContextOptions` method of your test class derived from `Microsoft.Playwright.MSTest.PageTest` or `Microsoft.Playwright.MSTest.ContextTest`. See the following example:
```csharp
using Microsoft.Playwright.NUnit;
namespace PlaywrightTests;
[Parallelizable(ParallelScope.Self)]
[TestFixture]
public class MyTest : PageTest
{
[Test]
public async Task TestWithCustomContextOptions()
{
// The following Page (and BrowserContext) instance has the custom colorScheme, viewport and baseURL set:
await Page.GotoAsync("/login");
}
public override BrowserNewContextOptions ContextOptions()
{
return new BrowserNewContextOptions()
{
ColorScheme = ColorScheme.Light,
ViewportSize = new()
{
Width = 1920,
Height = 1080
},
BaseURL = "https://github.com",
};
}
}
```
</TabItem>
<TabItem value="mstest">
To customize context options, you can override the `ContextOptions` method of your test class derived from `Microsoft.Playwright.MSTest.PageTest` or `Microsoft.Playwright.MSTest.ContextTest`. See the following example:
@ -65,7 +176,46 @@ public class ExampleTest : PageTest
```
### Customizing [Browser]/launch options
</TabItem>
<TabItem value="xunit">
To customize context options, you can override the `ContextOptions` method of your test class derived from `Microsoft.Playwright.Xunit.PageTest` or `Microsoft.Playwright.Xunit.ContextTest`. See the following example:
```csharp
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
namespace PlaywrightTests;
public class UnitTest1 : PageTest
{
[Fact]
public async Task TestWithCustomContextOptions()
{
// The following Page (and BrowserContext) instance has the custom colorScheme, viewport and baseURL set:
await Page.GotoAsync("/login");
}
public override BrowserNewContextOptions ContextOptions()
{
return new BrowserNewContextOptions()
{
ColorScheme = ColorScheme.Light,
ViewportSize = new()
{
Width = 1920,
Height = 1080
},
BaseURL = "https://github.com",
};
}
}
```
</TabItem>
</Tabs>
## Customizing [Browser]/launch options
[Browser]/launch options can be overridden either using a run settings file or by setting the run settings options directly via the
CLI. See the following example:
@ -87,14 +237,56 @@ CLI. See the following example:
dotnet test -- Playwright.BrowserName=chromium Playwright.LaunchOptions.Headless=false Playwright.LaunchOptions.Channel=msedge
```
### Using Verbose API Logs
## Using Verbose API Logs
When you have enabled the [verbose API log](./debug.md#verbose-api-logs), via the `DEBUG` environment variable, you will see the messages in the standard error stream. In MSTest, within Visual Studio, that will be the `Tests` pane of the `Output` window. It will also be displayed in the `Test Log` for each test.
When you have enabled the [verbose API log](./debug.md#verbose-api-logs), via the `DEBUG` environment variable, you will see the messages in the standard error stream. Within Visual Studio, that will be the `Tests` pane of the `Output` window. It will also be displayed in the `Test Log` for each test.
### Using the .runsettings file
## Using the .runsettings file
When running tests from Visual Studio, you can take advantage of the `.runsettings` file. The following shows a reference of the supported values.
<Tabs
groupId="test-runners"
defaultValue="mstest"
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
For example, to specify the number of workers you can use `NUnit.NumberOfTestWorkers` or to enable `DEBUG` logs `RunConfiguration.EnvironmentVariables`.
```xml
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<!-- NUnit adapter -->
<NUnit>
<NumberOfTestWorkers>24</NumberOfTestWorkers>
</NUnit>
<!-- General run configuration -->
<RunConfiguration>
<EnvironmentVariables>
<!-- For debugging selectors, it's recommend to set the following environment variable -->
<DEBUG>pw:api</DEBUG>
</EnvironmentVariables>
</RunConfiguration>
<!-- Playwright -->
<Playwright>
<BrowserName>chromium</BrowserName>
<ExpectTimeout>5000</ExpectTimeout>
<LaunchOptions>
<Headless>false</Headless>
<Channel>msedge</Channel>
</LaunchOptions>
</Playwright>
</RunSettings>
```
</TabItem>
<TabItem value="mstest">
For example, to specify the number of workers, you can use `MSTest.Parallelize.Workers`. You can also enable `DEBUG` logs using `RunConfiguration.EnvironmentVariables`.
```xml
@ -125,109 +317,18 @@ For example, to specify the number of workers, you can use `MSTest.Parallelize.W
</RunSettings>
```
### Base MSTest classes for Playwright
</TabItem>
<TabItem value="xunit">
There are a few base classes available to you in `Microsoft.Playwright.MSTest` namespace:
|Test |Description|
|--------------|-----------|
|PageTest |Each test gets a fresh copy of a web [Page] created in its own unique [BrowserContext]. Extending this class is the simplest way of writing a fully-functional Playwright test.<br></br><br></br>Note: You can override the `ContextOptions` method in each test file to control context options, the ones typically passed into the [`method: Browser.newContext`] method. That way you can specify all kinds of emulation options for your test file individually.|
|ContextTest |Each test will get a fresh copy of a [BrowserContext]. You can create as many pages in this context as you'd like. Using this test is the easiest way to test multi-page scenarios where you need more than one tab.<br></br><br></br>Note: You can override the `ContextOptions` method in each test file to control context options, the ones typically passed into the [`method: Browser.newContext`] method. That way you can specify all kinds of emulation options for your test file individually.|
|BrowserTest |Each test will get a browser and can create as many contexts as it likes. Each test is responsible for cleaning up all the contexts it created.|
|PlaywrightTest|This gives each test a Playwright object so that the test could start and stop as many browsers as it likes.|
## NUnit
Playwright provides base classes to write tests with NUnit via the [`Microsoft.Playwright.NUnit`](https://www.nuget.org/packages/Microsoft.Playwright.NUnit) package.
Check out the [installation guide](./intro.md) to get started.
### Running NUnit tests in Parallel
By default NUnit will run all test files in parallel, while running tests inside each file sequentially (`ParallelScope.Self`). It will create as many processes as there are cores on the host system. You can adjust this behavior using the NUnit.NumberOfTestWorkers parameter.
Only `ParallelScope.Self` is supported.
For CPU-bound tests, we recommend using as many workers as there are cores on your system, divided by 2. For IO-bound tests you can use as many workers as you have cores.
```bash
dotnet test -- NUnit.NumberOfTestWorkers=5
```
### Customizing [BrowserContext] options
To customize context options, you can override the `ContextOptions` method of your test class derived from `Microsoft.Playwright.MSTest.PageTest` or `Microsoft.Playwright.MSTest.ContextTest`. See the following example:
```csharp
using Microsoft.Playwright.NUnit;
namespace PlaywrightTests;
[Parallelizable(ParallelScope.Self)]
[TestFixture]
public class MyTest : PageTest
{
[Test]
public async Task TestWithCustomContextOptions()
{
// The following Page (and BrowserContext) instance has the custom colorScheme, viewport and baseURL set:
await Page.GotoAsync("/login");
}
public override BrowserNewContextOptions ContextOptions()
{
return new BrowserNewContextOptions()
{
ColorScheme = ColorScheme.Light,
ViewportSize = new()
{
Width = 1920,
Height = 1080
},
BaseURL = "https://github.com",
};
}
}
```
### Customizing [Browser]/launch options
[Browser]/launch options can be overridden either using a run settings file or by setting the run settings options directly via the
CLI. See the following example:
For example, to specify the number of workers, you can use `xUnit.MaxParallelThreads`. You can also enable `DEBUG` logs using `RunConfiguration.EnvironmentVariables`.
```xml
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<Playwright>
<BrowserName>chromium</BrowserName>
<LaunchOptions>
<Headless>false</Headless>
<Channel>msedge</Channel>
</LaunchOptions>
</Playwright>
</RunSettings>
```
```bash
dotnet test -- Playwright.BrowserName=chromium Playwright.LaunchOptions.Headless=false Playwright.LaunchOptions.Channel=msedge
```
### Using Verbose API Logs
When you have enabled the [verbose API log](./debug.md#verbose-api-logs), via the `DEBUG` environment variable, you will see the messages in the standard error stream. In NUnit, within Visual Studio, that will be the `Tests` pane of the `Output` window. It will also be displayed in the `Test Log` for each test.
### Using the .runsettings file
When running tests from Visual Studio, you can take advantage of the `.runsettings` file. The following shows a reference of the supported values.
For example, to specify the amount of workers you can use `NUnit.NumberOfTestWorkers` or to enable `DEBUG` logs `RunConfiguration.EnvironmentVariables`.
```xml
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<!-- NUnit adapter -->
<NUnit>
<NumberOfTestWorkers>24</NumberOfTestWorkers>
</NUnit>
<!-- See https://xunit.net/docs/runsettings -->
<xUnit>
<MaxParallelThreads>1</MaxParallelThreads>
</xUnit>
<!-- General run configuration -->
<RunConfiguration>
<EnvironmentVariables>
@ -246,19 +347,40 @@ For example, to specify the amount of workers you can use `NUnit.NumberOfTestWor
</Playwright>
</RunSettings>
```
</TabItem>
</Tabs>
### Base NUnit classes for Playwright
## Base classes for Playwright
<Tabs
groupId="test-runners"
defaultValue="mstest"
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
There are a few base classes available to you in `Microsoft.Playwright.NUnit` namespace:
</TabItem>
<TabItem value="mstest">
There are a few base classes available to you in `Microsoft.Playwright.MSTest` namespace:
</TabItem>
<TabItem value="xunit">
There are a few base classes available to you in `Microsoft.Playwright.Xunit` namespace:
</TabItem>
</Tabs>
|Test |Description|
|--------------|-----------|
|PageTest |Each test gets a fresh copy of a web [Page] created in its own unique [BrowserContext]. Extending this class is the simplest way of writing a fully-functional Playwright test.<br></br><br></br>Note: You can override the `ContextOptions` method in each test file to control context options, the ones typically passed into the [`method: Browser.newContext`] method. That way you can specify all kinds of emulation options for your test file individually.|
|ContextTest |Each test will get a fresh copy of a [BrowserContext]. You can create as many pages in this context as you'd like. Using this test is the easiest way to test multi-page scenarios where you need more than one tab.<br></br><br></br>Note: You can override the `ContextOptions` method in each test file to control context options, the ones typically passed into the [`method: Browser.newContext`] method. That way you can specify all kinds of emulation options for your test file individually.|
|BrowserTest |Each test will get a browser and can create as many contexts as it likes. Each test is responsible for cleaning up all the contexts it created.|
|PlaywrightTest|This gives each test a Playwright object so that the test could start and stop as many browsers as it likes.|
## xUnit support
While using xUnit is also supported, we do not support running parallel tests. This is a well known problem/design limitation
outlined by the maintainers across [several](https://github.com/xunit/xunit/issues/2003) [issues](https://github.com/xunit/xunit/issues/2111#issuecomment-650004247).

View file

@ -259,3 +259,18 @@ def test_bing_is_working(page):
## Deploy to CI
See the [guides for CI providers](./ci.md) to deploy your tests to CI/CD.
## Async Fixtures
If you want to use async fixtures, you can use the [`pytest-playwright-asyncio`](https://pypi.org/project/pytest-playwright-asyncio/) plugin.
Make sure to use `pytest-asyncio>=0.24.0` and make your tests use of [`loop_scope=session`](https://pytest-asyncio.readthedocs.io/en/latest/how-to-guides/run_session_tests_in_same_loop.html).
```python
import pytest
from playwright.async_api import Page
@pytest.mark.asyncio(loop_scope="session")
async def test_foo(page: Page):
await page.goto("https://github.com")
# ...
```

View file

@ -37,7 +37,7 @@ When `fullyParallel: true` is enabled, Playwright Test runs individual tests in
**Sharding without fullyParallel**
Without the fullyParallel setting, Playwright Test defaults to file-level granularity, meaning entire test files are assigned to shards. In this case, the number of tests per file can greatly influence shard distribution. If your test files are not evenly sized (i.e., some files contain many more tests than others), certain shards may end up running significantly more tests, while others may run fewer or even none.
Without the fullyParallel setting, Playwright Test defaults to file-level granularity, meaning entire test files are assigned to shards (note that the same file may be assigned to different shards across different projects). In this case, the number of tests per file can greatly influence shard distribution. If your test files are not evenly sized (i.e., some files contain many more tests than others), certain shards may end up running significantly more tests, while others may run fewer or even none.
**Key Takeaways:**

View file

@ -48,7 +48,7 @@ The snapshot name `example-test-1-chromium-darwin.png` consists of a few parts:
- `chromium-darwin` - the browser name and the platform. Screenshots differ between browsers and platforms due to different rendering, fonts and more, so you will need different snapshots for them. If you use multiple projects in your [configuration file](./test-configuration.md), project name will be used instead of `chromium`.
The snapshot name and path can be configured with [`snapshotPathTemplate`](./api/class-testproject#test-project-snapshot-path-template) in the playwright config.
The snapshot name and path can be configured with [`property: TestConfig.snapshotPathTemplate`] in the playwright config.
## Updating screenshots

View file

@ -7,7 +7,7 @@ import LiteYouTube from '@site/src/components/LiteYouTube';
## Introduction
UI Mode lets you explore, run and debug tests with a time travel experience complete with watch mode. All test files are loaded into the testing sidebar where you can expand each file and describe block to individually run, view, watch and debug each test. Filter tests by **text** or **@tag** or by **passed**, **failed** and **skipped** tests as well as by [**projects**](./test-projects) as set in your `playwright.config` file. See a full trace of your tests and hover back and forward over each action to see what was happening during each step and pop out the DOM snapshot to a separate window for a better debugging experience.
UI Mode lets you explore, run, and debug tests with a time travel experience complete with a watch mode. All test files are displayed in the testing sidebar, allowing you to expand each file and describe block to individually run, view, watch, and debug each test. Filter tests by **name**, [**projects**](./test-projects) (set in your `playwright.config` file), **@tag**, or by the execution status of **passed**, **failed**, and **skipped**. See a full trace of your tests and hover back and forward over each action to see what was happening during each step. You can also pop out the DOM snapshot of a given moment into a separate window for a better debugging experience.
<LiteYouTube
id="d0u6XhXknzU"
@ -18,12 +18,13 @@ UI Mode lets you explore, run and debug tests with a time travel experience comp
To open UI mode, run the following command in your terminal:
```bash
npx playwright test --ui
```
```bash
npx playwright test --ui
```
## Running your tests
Once you launch UI Mode you will see a list of all your test files. You can run all your tests by clicking the triangle icon in the sidebar. You can also run a single test file, a block of tests or a single test by hovering over the name and clicking on the triangle next to it.
Once you launch UI Mode you will see a list of all your test files. You can run all your tests by clicking the triangle icon in the sidebar. You can also run a single test file, a block of tests or a single test by hovering over the name and clicking on the triangle next to it.
![running tests in ui mode](https://github.com/microsoft/playwright/assets/13063165/6b87712f-64a5-4d73-a91d-6562b864712c)
@ -33,17 +34,15 @@ Filter tests by text or `@tag` or by passed, failed or skipped tests. You can al
![filtering tests in ui mode](https://github.com/microsoft/playwright/assets/13063165/6f05e589-036d-45d5-9078-38134e1261e4)
## Timeline view
At the top of the trace you can see a timeline view of your test with different colors to highlight navigation and actions. Hover back and forth to see an image snapshot for each action. Double click on an action to see the time range for that action. You can use the slider in the timeline to increase the actions selected and these will be shown in the Actions tab and all console logs and network logs will be filtered to only show the logs for the actions selected.
![timeline view in ui mode](https://github.com/microsoft/playwright/assets/13063165/811a9985-32aa-4a3e-9869-de32053cf468)
## Actions
In the Actions tab you can see what locator was used for every action and how long each one took to run. Hover over each action of your test and visually see the change in the DOM snapshot. Go back and forward in time and click an action to inspect and debug. Use the Before and After tabs to visually see what happened before and after the action.
In the Actions tab you can see what locator was used for every action and how long each one took to run. Hover over each action of your test and visually see the change in the DOM snapshot. Go back and forward in time and click an action to inspect and debug. Use the Before and After tabs to visually see what happened before and after the action.
![use before and after actions in ui mode](https://github.com/microsoft/playwright/assets/13063165/7b22fab5-7346-4b98-8fdd-a78ed280647f)
## Pop out and inspect the DOM
@ -60,7 +59,7 @@ Click on the pick locator button and hover over the DOM snapshot to see the loca
## Source
As you hover over each action of your test the line of code for that action is highlighted in the source panel.
As you hover over each action of your test the line of code for that action is highlighted in the source panel. The button "Open in VSCode" is at the top-right of this section. Upon clicking the button, it will open your test in VS Code right at the line of code that you clicked on.
![showing source code of tests in ui mode](https://github.com/microsoft/playwright/assets/13063165/49b9fa2a-8a57-4044-acaa-0a2ea4784c5c)
@ -108,7 +107,7 @@ Next to the Actions tab you will find the Metadata tab which will show you more
## Watch mode
Next to the name of each test in the sidebar you will find an eye icon. Clicking on the icon will activate watch mode which will re-run the test when you make changes to it. You can watch a number of tests at the same time be clicking the eye icon next to each one or all tests by clicking the eye icon at the top of the sidebar. If you are using VS Code then you can easily open your test by clicking on the file icon next to the eye icon. This will open your test in VS Code right at the line of code that you clicked on.
Next to the name of each test in the sidebar you will find an eye icon. Clicking on the icon will activate watch mode which will re-run the test when you make changes to it. You can watch a number of tests at the same time be clicking the eye icon next to each one or all tests by clicking the eye icon at the top of the sidebar.
![watch mode in ui mode](https://github.com/microsoft/playwright/assets/13063165/20d7d44c-b52d-43ff-8871-8b828671f3da)

View file

@ -17,7 +17,7 @@ import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Base URL to use in actions like `await page.goto('/')`.
baseURL: 'http://127.0.0.1:3000',
baseURL: 'http://localhost:3000',
// Populates context with given storage state.
storageState: 'state.json',

View file

@ -18,7 +18,7 @@ export default defineConfig({
// Run your local dev server before starting the tests
webServer: {
command: 'npm run start',
url: 'http://127.0.0.1:3000',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
stdout: 'ignore',
stderr: 'pipe',
@ -36,7 +36,8 @@ export default defineConfig({
| `cwd` | Current working directory of the spawned process, defaults to the directory of the configuration file. |
| `stdout` | If `"pipe"`, it will pipe the stdout of the command to the process stdout. If `"ignore"`, it will ignore the stdout of the command. Default to `"ignore"`. |
| `stderr` | Whether to pipe the stderr of the command to the process stderr or ignore it. Defaults to `"pipe"`. |
| `timeout` | `How long to wait for the process to start up and be available in milliseconds. Defaults to 60000. |
| `timeout` | How long to wait for the process to start up and be available in milliseconds. Defaults to 60000. |
| `gracefulShutdown` | How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: 'SIGTERM', timeout: 500 }`, the process group is sent a `SIGTERM` signal, followed by `SIGKILL` if it doesn't exit within 500ms. You can also use `SIGINT` as the signal instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't support `SIGTERM` and `SIGINT` signals, so this option is ignored on Windows. Note that shutting down a Docker container requires `SIGTERM`. |
## Adding a server timeout
@ -51,7 +52,7 @@ export default defineConfig({
// Run your local dev server before starting the tests
webServer: {
command: 'npm run start',
url: 'http://127.0.0.1:3000',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120 * 1000,
},
@ -62,7 +63,7 @@ export default defineConfig({
It is also recommended to specify the `baseURL` in the `use: {}` section of your config, so that tests can use relative urls and you don't have to specify the full URL over and over again.
When using [`method: Page.goto`], [`method: Page.route`], [`method: Page.waitForURL`], [`method: Page.waitForRequest`], or [`method: Page.waitForResponse`] it takes the base URL in consideration by using the [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. For Example, by setting the baseURL to `http://127.0.0.1:3000` and navigating to `/login` in your tests, Playwright will run the test using `http://127.0.0.1:3000/login`.
When using [`method: Page.goto`], [`method: Page.route`], [`method: Page.waitForURL`], [`method: Page.waitForRequest`], or [`method: Page.waitForResponse`] it takes the base URL in consideration by using the [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. For Example, by setting the baseURL to `http://localhost:3000` and navigating to `/login` in your tests, Playwright will run the test using `http://localhost:3000/login`.
```js title="playwright.config.ts"
import { defineConfig } from '@playwright/test';
@ -73,11 +74,11 @@ export default defineConfig({
// Run your local dev server before starting the tests
webServer: {
command: 'npm run start',
url: 'http://127.0.0.1:3000',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
use: {
baseURL: 'http://127.0.0.1:3000',
baseURL: 'http://localhost:3000',
},
});
```
@ -88,7 +89,7 @@ Now you can use a relative path when navigating the page:
import { test } from '@playwright/test';
test('test', async ({ page }) => {
// This will navigate to http://127.0.0.1:3000/login
// This will navigate to http://localhost:3000/login
await page.goto('./login');
});
```
@ -105,19 +106,19 @@ export default defineConfig({
webServer: [
{
command: 'npm run start',
url: 'http://127.0.0.1:3000',
url: 'http://localhost:3000',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
},
{
command: 'npm run backend',
url: 'http://127.0.0.1:3333',
url: 'http://localhost:3333',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
}
],
use: {
baseURL: 'http://127.0.0.1:3000',
baseURL: 'http://localhost:3000',
},
});
```

138
docs/src/touch-events.md Normal file
View file

@ -0,0 +1,138 @@
---
id: touch-events
title: "Emulating legacy touch events"
---
## Introduction
Web applications that handle [touch events](https://developer.mozilla.org/en-US/docs/Web/API/Touch_events) to respond to gestures like swipe, pinch, and tap can be tested by manually dispatching [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent)s to the page. The examples below demonstrate how to use [`method: Locator.dispatchEvent`] and pass [Touch](https://developer.mozilla.org/en-US/docs/Web/API/Touch) points as arguments.
### Emulating pan gesture
In the example below, we emulate pan gesture that is expected to move the map. The app under test only uses `clientX/clientY` coordinates of the touch point, so we initialize just that. In a more complex scenario you may need to also set `pageX/pageY/screenX/screenY`, if your app needs them.
```js
import { test, expect, devices, type Locator } from '@playwright/test';
test.use({ ...devices['Pixel 7'] });
async function pan(locator: Locator, deltaX?: number, deltaY?: number, steps?: number) {
const { centerX, centerY } = await locator.evaluate((target: HTMLElement) => {
const bounds = target.getBoundingClientRect();
const centerX = bounds.left + bounds.width / 2;
const centerY = bounds.top + bounds.height / 2;
return { centerX, centerY };
});
// Providing only clientX and clientY as the app only cares about those.
const touches = [{
identifier: 0,
clientX: centerX,
clientY: centerY,
}];
await locator.dispatchEvent('touchstart',
{ touches, changedTouches: touches, targetTouches: touches });
steps = steps ?? 5;
deltaX = deltaX ?? 0;
deltaY = deltaY ?? 0;
for (let i = 1; i <= steps; i++) {
const touches = [{
identifier: 0,
clientX: centerX + deltaX * i / steps,
clientY: centerY + deltaY * i / steps,
}];
await locator.dispatchEvent('touchmove',
{ touches, changedTouches: touches, targetTouches: touches });
}
await locator.dispatchEvent('touchend');
}
test(`pan gesture to move the map`, async ({ page }) => {
await page.goto('https://www.google.com/maps/place/@37.4117722,-122.0713234,15z',
{ waitUntil: 'commit' });
await page.getByRole('button', { name: 'Keep using web' }).click();
await expect(page.getByRole('button', { name: 'Keep using web' })).not.toBeVisible();
// Get the map element.
const met = page.locator('[data-test-id="met"]');
for (let i = 0; i < 5; i++)
await pan(met, 200, 100);
// Ensure the map has been moved.
await expect(met).toHaveScreenshot();
});
```
### Emulating pinch gesture
In the example below, we emulate pinch gesture, i.e. two touch points moving closer to each other. It is expected to zoom out the map. The app under test only uses `clientX/clientY` coordinates of touch points, so we initialize just that. In a more complex scenario you may need to also set `pageX/pageY/screenX/screenY`, if your app needs them.
```js
import { test, expect, devices, type Locator } from '@playwright/test';
test.use({ ...devices['Pixel 7'] });
async function pinch(locator: Locator,
arg: { deltaX?: number, deltaY?: number, steps?: number, direction?: 'in' | 'out' }) {
const { centerX, centerY } = await locator.evaluate((target: HTMLElement) => {
const bounds = target.getBoundingClientRect();
const centerX = bounds.left + bounds.width / 2;
const centerY = bounds.top + bounds.height / 2;
return { centerX, centerY };
});
const deltaX = arg.deltaX ?? 50;
const steps = arg.steps ?? 5;
const stepDeltaX = deltaX / (steps + 1);
// Two touch points equally distant from the center of the element.
const touches = [
{
identifier: 0,
clientX: centerX - (arg.direction === 'in' ? deltaX : stepDeltaX),
clientY: centerY,
},
{
identifier: 1,
clientX: centerX + (arg.direction === 'in' ? deltaX : stepDeltaX),
clientY: centerY,
},
];
await locator.dispatchEvent('touchstart',
{ touches, changedTouches: touches, targetTouches: touches });
// Move the touch points towards or away from each other.
for (let i = 1; i <= steps; i++) {
const offset = (arg.direction === 'in' ? (deltaX - i * stepDeltaX) : (stepDeltaX * (i + 1)));
const touches = [
{
identifier: 0,
clientX: centerX - offset,
clientY: centerY,
},
{
identifier: 0,
clientX: centerX + offset,
clientY: centerY,
},
];
await locator.dispatchEvent('touchmove',
{ touches, changedTouches: touches, targetTouches: touches });
}
await locator.dispatchEvent('touchend', { touches: [], changedTouches: [], targetTouches: [] });
}
test(`pinch in gesture to zoom out the map`, async ({ page }) => {
await page.goto('https://www.google.com/maps/place/@37.4117722,-122.0713234,15z',
{ waitUntil: 'commit' });
await page.getByRole('button', { name: 'Keep using web' }).click();
await expect(page.getByRole('button', { name: 'Keep using web' })).not.toBeVisible();
// Get the map element.
const met = page.locator('[data-test-id="met"]');
for (let i = 0; i < 5; i++)
await pinch(met, { deltaX: 40, direction: 'in' });
// Ensure the map has been zoomed out.
await expect(met).toHaveScreenshot();
});
```

View file

@ -22,6 +22,7 @@ Traces can be recorded using the [`property: BrowserContext.tracing`] API as fol
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -112,6 +113,69 @@ public class ExampleTest : PageTest
}
```
</TabItem>
<TabItem value="xunit">
```csharp
using System.Reflection;
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
using Xunit.Sdk;
namespace PlaywrightTests;
[WithTestName]
public class UnitTest1 : PageTest
{
public override async Task InitializeAsync()
{
await base.InitializeAsync().ConfigureAwait(false);
await Context.Tracing.StartAsync(new()
{
Title = $"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}",
Screenshots = true,
Snapshots = true,
Sources = true
});
}
public override async Task DisposeAsync()
{
await Context.Tracing.StopAsync(new()
{
Path = Path.Combine(
Environment.CurrentDirectory,
"playwright-traces",
$"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}.zip"
)
});
await base.DisposeAsync().ConfigureAwait(false);
}
[Fact]
public async Task GetStartedLink()
{
// ...
await Page.GotoAsync("https://playwright.dev/dotnet/docs/intro");
}
}
public class WithTestNameAttribute : BeforeAfterTestAttribute
{
public static string CurrentTestName = string.Empty;
public static string CurrentClassName = string.Empty;
public override void Before(MethodInfo methodInfo)
{
CurrentTestName = methodInfo.Name;
CurrentClassName = methodInfo.DeclaringType!.Name;
}
public override void After(MethodInfo methodInfo)
{
}
}
```
</TabItem>
</Tabs>
@ -134,4 +198,4 @@ Check out our detailed guide on [Trace Viewer](/trace-viewer.md) to learn more a
## What's next
- [Run tests on CI with GitHub Actions](/ci-intro.md)
- [Learn more about the MSTest and NUnit base classes](./test-runners.md)
- [Learn more about the MSTest, NUnit, and xUnit base classes](./test-runners.md)

View file

@ -22,7 +22,7 @@ Playwright Trace Viewer is a GUI tool that lets you explore recorded Playwright
## Recording a Trace
By default the [playwright.config](./trace-viewer.md#recording-a-trace-on-ci) file will contain the configuration needed to create a `trace.zip` file for each test. Traces are setup to run `on-first-retry` meaning they will be run on the first retry of a failed test. Also `retries` are set to 2 when running on CI and 0 locally. This means the traces will be recorded on the first retry of a failed test but not on the first run and not on the second retry.
By default the [playwright.config](./trace-viewer.md#tracing-on-ci) file will contain the configuration needed to create a `trace.zip` file for each test. Traces are setup to run `on-first-retry` meaning they will be run on the first retry of a failed test. Also `retries` are set to 2 when running on CI and 0 locally. This means the traces will be recorded on the first retry of a failed test but not on the first run and not on the second retry.
```js title="playwright.config.ts"
import { defineConfig } from '@playwright/test';
@ -45,7 +45,7 @@ npx playwright test --trace on
## Opening the HTML report
The HTML report shows you a report of all your tests that have been ran and on which browsers as well as how long they took. Tests can be filtered by passed tests, failed, flakey or skipped tests. You can also search for a particular test. Clicking on a test will open the detailed view where you can see more information on your tests such as the errors, the test steps and the trace.
The HTML report shows you a report of all your tests that have been run and on which browsers as well as how long they took. Tests can be filtered by passed tests, failed, flaky or skipped tests. You can also search for a particular test. Clicking on a test will open the detailed view where you can see more information on your tests such as the errors, the test steps and the trace.
```bash
npx playwright show-report

View file

@ -17,106 +17,67 @@ Playwright Trace Viewer is a GUI tool that helps you explore recorded Playwright
title="Viewing Playwright Traces"
/>
## Trace Viewer features
### Actions
## Opening Trace Viewer
In the Actions tab you can see what locator was used for every action and how long each one took to run. Hover over each action of your test and visually see the change in the DOM snapshot. Go back and forward in time and click an action to inspect and debug. Use the Before and After tabs to visually see what happened before and after the action.
You can open a saved trace using either the Playwright CLI or in the browser at [trace.playwright.dev](https://trace.playwright.dev). Make sure to add the full path to where your `trace.zip` file is located.
![actions tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/948b65cd-f0fd-4c7f-8e53-2c632b5a07f1)
```bash js
npx playwright show-trace path/to/trace.zip
```
**Selecting each action reveals:**
- action snapshots
- action log
- source code location
```bash java
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="show-trace trace.zip"
```
### Screenshots
```bash python
playwright show-trace trace.zip
```
When tracing with the [`option: Tracing.start.screenshots`] option turned on (default), each trace records a screencast and renders it as a film strip. You can hover over the film strip to see a magnified image of for each action and state which helps you easily find the action you want to inspect.
```bash csharp
pwsh bin/Debug/netX/playwright.ps1 show-trace trace.zip
```
Double click on an action to see the time range for that action. You can use the slider in the timeline to increase the actions selected and these will be shown in the Actions tab and all console logs and network logs will be filtered to only show the logs for the actions selected.
### Using [trace.playwright.dev](https://trace.playwright.dev)
![timeline view in trace viewer](https://github.com/microsoft/playwright/assets/13063165/b04a7d75-54bb-4ab2-9e30-e76f6f74a2c8)
[trace.playwright.dev](https://trace.playwright.dev) is a statically hosted variant of the Trace Viewer. You can upload trace files using drag and drop or via the `Select file(s)` button.
Trace Viewer loads the trace entirely in your browser and does not transmit any data externally.
### Snapshots
<img width="1119" alt="Drop Playwright Trace to load" src="https://user-images.githubusercontent.com/13063165/194577918-b4d45726-2692-4093-8a28-9e73552617ef.png" />
When tracing with the [`option: Tracing.start.snapshots`] option turned on (default), Playwright captures a set of complete DOM snapshots for each action. Depending on the type of the action, it will capture:
### Viewing remote traces
| Type | Description |
|------|-------------|
|Before|A snapshot at the time action is called.|
|Action|A snapshot at the moment of the performed input. This type of snapshot is especially useful when exploring where exactly Playwright clicked.|
|After|A snapshot after the action.|
You can open remote traces directly using its URL. This makes it easy to view the remote trace without having to manually download the file from CI runs, for example.
Here is what the typical Action snapshot looks like:
```bash js
npx playwright show-trace https://example.com/trace.zip
```
![action tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/7168d549-eb0a-4964-9c93-483f03711fa9)
```bash java
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="show-trace https://example.com/trace.zip"
```
Notice how it highlights both, the DOM Node as well as the exact click position.
```bash python
playwright show-trace https://example.com/trace.zip
```
### Source
```bash csharp
pwsh bin/Debug/netX/playwright.ps1 show-trace https://example.com/trace.zip
```
When you click on an action in the sidebar, the line of code for that action is highlighted in the source panel.
When using [trace.playwright.dev](https://trace.playwright.dev), you can also pass the URL of your uploaded trace at some accessible storage (e.g. inside your CI) as a query parameter. CORS (Cross-Origin Resource Sharing) rules might apply.
![showing source code tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/daa8845d-c250-4923-aa7a-5d040da9adc5)
```txt
https://trace.playwright.dev/?trace=https://demo.playwright.dev/reports/todomvc/data/cb0fa77ebd9487a5c899f3ae65a7ffdbac681182.zip
```
### Call
The call tab shows you information about the action such as the time it took, what locator was used, if in strict mode and what key was used.
![showing call tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/95498580-f9dd-4932-a123-c37fe7cfc3c2)
### Log
See a full log of your test to better understand what Playwright is doing behind the scenes such as scrolling into view, waiting for element to be visible, enabled and stable and performing actions such as click, fill, press etc.
![showing log of tests in trace viewer](https://github.com/microsoft/playwright/assets/13063165/de621461-3bab-4140-b39d-9f02d6672dbf)
### Errors
If your test fails you will see the error messages for each test in the Errors tab. The timeline will also show a red line highlighting where the error occurred. You can also click on the source tab to see on which line of the source code the error is.
![showing errors in trace viewer](https://github.com/microsoft/playwright/assets/13063165/e9ef77b3-05d1-4df2-852c-981023723d34)
### Console
See console logs from the browser as well as from your test. Different icons are displayed to show you if the console log came from the browser or from the test file.
![showing log of tests in trace viewer](https://github.com/microsoft/playwright/assets/13063165/4107c08d-1eaf-421c-bdd4-9dd2aa641d4a)
Double click on an action from your test in the actions sidebar. This will filter the console to only show the logs that were made during that action. Click the *Show all* button to see all console logs again.
Use the timeline to filter actions, by clicking a start point and dragging to an ending point. The console tab will also be filtered to only show the logs that were made during the actions selected.
### Network
The Network tab shows you all the network requests that were made during your test. You can sort by different types of requests, status code, method, request, content type, duration and size. Click on a request to see more information about it such as the request headers, response headers, request body and response body.
![network requests tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/0a3d1671-8ccd-4f7a-a844-35f5eb37f236)
Double click on an action from your test in the actions sidebar. This will filter the network requests to only show the requests that were made during that action. Click the *Show all* button to see all network requests again.
Use the timeline to filter actions, by clicking a start point and dragging to an ending point. The network tab will also be filtered to only show the network requests that were made during the actions selected.
### Metadata
Next to the Actions tab you will find the Metadata tab which will show you more information on your test such as the Browser, viewport size, test duration and more.
![meta data in trace viewer](https://github.com/microsoft/playwright/assets/13063165/82ab3d33-1ec9-4b8a-9cf2-30a6e2d59091)
### Attachments
## Recording a trace
* langs: js
The "Attachments" tab allows you to explore attachments. If you're doing [visual regression testing](./test-snapshots.md), you'll be able to compare screenshots by examining the image diff, the actual image and the expected image. When you click on the expected image you can use the slider to slide one image over the other so you can easily see the differences in your screenshots.
![attachments tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/4386178a-5808-4fa8-9436-315350a23b04)
## Recording a trace locally
### Tracing locally
* langs: js
To record a trace during development mode set the `--trace` flag to `on` when running your tests. You can also use [UI Mode](./test-ui-mode.md) for a better developer experience.
To record a trace during development mode set the `--trace` flag to `on` when running your tests. You can also use [UI Mode](./test-ui-mode.md) for a better developer experience, as it traces each test automatically.
```bash
npx playwright test --trace on
@ -126,7 +87,7 @@ You can then open the HTML report and click on the trace icon to open the trace.
```bash
npx playwright show-report
```
## Recording a trace on CI
### Tracing on CI
* langs: js
Traces should be run on continuous integration on the first retry of a failed test
@ -254,6 +215,7 @@ Traces can be recorded using the [`property: BrowserContext.tracing`] API as fol
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -348,6 +310,70 @@ public class UnitTest1 : PageTest
}
```
</TabItem>
<TabItem value="xunit">
```csharp
using System.Reflection;
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
using Xunit.Sdk;
namespace PlaywrightTests;
[WithTestName]
public class UnitTest1 : PageTest
{
public override async Task InitializeAsync()
{
await base.InitializeAsync().ConfigureAwait(false);
await Context.Tracing.StartAsync(new()
{
Title = $"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}",
Screenshots = true,
Snapshots = true,
Sources = true
});
}
public override async Task DisposeAsync()
{
await Context.Tracing.StopAsync(new()
{
Path = Path.Combine(
Environment.CurrentDirectory,
"playwright-traces",
$"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}.zip"
)
});
await base.DisposeAsync().ConfigureAwait(false);
}
[Fact]
public async Task GetStartedLink()
{
// ...
await Page.GotoAsync("https://playwright.dev/dotnet/docs/intro");
}
}
public class WithTestNameAttribute : BeforeAfterTestAttribute
{
public static string CurrentTestName = string.Empty;
public static string CurrentClassName = string.Empty;
public override void Before(MethodInfo methodInfo)
{
CurrentTestName = methodInfo.Name;
CurrentClassName = methodInfo.DeclaringType!.Name;
}
public override void After(MethodInfo methodInfo)
{
}
}
```
</TabItem>
</Tabs>
@ -365,6 +391,7 @@ Setup your tests to record a trace only when the test fails:
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -459,60 +486,165 @@ public class ExampleTest : PageTest
}
```
</TabItem>
<TabItem value="xunit">
```csharp
using System.Reflection;
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
using Xunit.Sdk;
namespace PlaywrightTests;
[WithTestName]
public class UnitTest1 : PageTest
{
public override async Task InitializeAsync()
{
await base.InitializeAsync().ConfigureAwait(false);
await Context.Tracing.StartAsync(new()
{
Title = $"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}",
Screenshots = true,
Snapshots = true,
Sources = true
});
}
public override async Task DisposeAsync()
{
await Context.Tracing.StopAsync(new()
{
Path = !TestOk ? Path.Combine(
Environment.CurrentDirectory,
"playwright-traces",
$"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}.zip"
) : null
});
await base.DisposeAsync().ConfigureAwait(false);
}
[Fact]
public async Task GetStartedLink()
{
// ...
await Page.GotoAsync("https://playwright.dev/dotnet/docs/intro");
}
}
public class WithTestNameAttribute : BeforeAfterTestAttribute
{
public static string CurrentTestName = string.Empty;
public static string CurrentClassName = string.Empty;
public override void Before(MethodInfo methodInfo)
{
CurrentTestName = methodInfo.Name;
CurrentClassName = methodInfo.DeclaringType!.Name;
}
public override void After(MethodInfo methodInfo)
{
}
}
```
</TabItem>
</Tabs>
## Opening the trace
## Trace Viewer features
### Actions
You can open the saved trace using the Playwright CLI or in your browser on [`trace.playwright.dev`](https://trace.playwright.dev). Make sure to add the full path to where your `trace.zip` file is located.
In the Actions tab you can see what locator was used for every action and how long each one took to run. Hover over each action of your test and visually see the change in the DOM snapshot. Go back and forward in time and click an action to inspect and debug. Use the Before and After tabs to visually see what happened before and after the action.
```bash js
npx playwright show-trace path/to/trace.zip
```
![actions tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/948b65cd-f0fd-4c7f-8e53-2c632b5a07f1)
```bash java
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="show-trace trace.zip"
```
**Selecting each action reveals:**
- Action snapshots
- Action log
- Source code location
```bash python
playwright show-trace trace.zip
```
### Screenshots
```bash csharp
pwsh bin/Debug/netX/playwright.ps1 show-trace trace.zip
```
When tracing with the [`option: Tracing.start.screenshots`] option turned on (default), each trace records a screencast and renders it as a film strip. You can hover over the film strip to see a magnified image of for each action and state which helps you easily find the action you want to inspect.
## Using [trace.playwright.dev](https://trace.playwright.dev)
Double click on an action to see the time range for that action. You can use the slider in the timeline to increase the actions selected and these will be shown in the Actions tab and all console logs and network logs will be filtered to only show the logs for the actions selected.
[trace.playwright.dev](https://trace.playwright.dev) is a statically hosted variant of the Trace Viewer. You can upload trace files using drag and drop.
![timeline view in trace viewer](https://github.com/microsoft/playwright/assets/13063165/b04a7d75-54bb-4ab2-9e30-e76f6f74a2c8)
<img width="1119" alt="Drop Playwright Trace to load" src="https://user-images.githubusercontent.com/13063165/194577918-b4d45726-2692-4093-8a28-9e73552617ef.png" />
### Snapshots
## Viewing remote traces
When tracing with the [`option: Tracing.start.snapshots`] option turned on (default), Playwright captures a set of complete DOM snapshots for each action. Depending on the type of the action, it will capture:
You can open remote traces using its URL. They could be generated on a CI run which makes it easy to view the remote trace without having to manually download the file.
| Type | Description |
|------|-------------|
|Before|A snapshot at the time action is called.|
|Action|A snapshot at the moment of the performed input. This type of snapshot is especially useful when exploring where exactly Playwright clicked.|
|After|A snapshot after the action.|
```bash js
npx playwright show-trace https://example.com/trace.zip
```
Here is what the typical Action snapshot looks like:
```bash java
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="show-trace https://example.com/trace.zip"
```
![action tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/7168d549-eb0a-4964-9c93-483f03711fa9)
```bash python
playwright show-trace https://example.com/trace.zip
```
Notice how it highlights both, the DOM Node as well as the exact click position.
```bash csharp
pwsh bin/Debug/netX/playwright.ps1 show-trace https://example.com/trace.zip
```
### Source
When you click on an action in the sidebar, the line of code for that action is highlighted in the source panel.
![showing source code tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/daa8845d-c250-4923-aa7a-5d040da9adc5)
### Call
The call tab shows you information about the action such as the time it took, what locator was used, if in strict mode and what key was used.
![showing call tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/95498580-f9dd-4932-a123-c37fe7cfc3c2)
### Log
See a full log of your test to better understand what Playwright is doing behind the scenes such as scrolling into view, waiting for element to be visible, enabled and stable and performing actions such as click, fill, press etc.
![showing log of tests in trace viewer](https://github.com/microsoft/playwright/assets/13063165/de621461-3bab-4140-b39d-9f02d6672dbf)
### Errors
If your test fails you will see the error messages for each test in the Errors tab. The timeline will also show a red line highlighting where the error occurred. You can also click on the source tab to see on which line of the source code the error is.
![showing errors in trace viewer](https://github.com/microsoft/playwright/assets/13063165/e9ef77b3-05d1-4df2-852c-981023723d34)
### Console
See console logs from the browser as well as from your test. Different icons are displayed to show you if the console log came from the browser or from the test file.
![showing log of tests in trace viewer](https://github.com/microsoft/playwright/assets/13063165/4107c08d-1eaf-421c-bdd4-9dd2aa641d4a)
Double click on an action from your test in the actions sidebar. This will filter the console to only show the logs that were made during that action. Click the *Show all* button to see all console logs again.
Use the timeline to filter actions, by clicking a start point and dragging to an ending point. The console tab will also be filtered to only show the logs that were made during the actions selected.
You can also pass the URL of your uploaded trace (e.g. inside your CI) from some accessible storage as a parameter. CORS (Cross-Origin Resource Sharing) rules might apply.
### Network
```txt
https://trace.playwright.dev/?trace=https://demo.playwright.dev/reports/todomvc/data/cb0fa77ebd9487a5c899f3ae65a7ffdbac681182.zip
```
The Network tab shows you all the network requests that were made during your test. You can sort by different types of requests, status code, method, request, content type, duration and size. Click on a request to see more information about it such as the request headers, response headers, request body and response body.
![network requests tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/0a3d1671-8ccd-4f7a-a844-35f5eb37f236)
Double click on an action from your test in the actions sidebar. This will filter the network requests to only show the requests that were made during that action. Click the *Show all* button to see all network requests again.
Use the timeline to filter actions, by clicking a start point and dragging to an ending point. The network tab will also be filtered to only show the network requests that were made during the actions selected.
### Metadata
Next to the Actions tab you will find the Metadata tab which will show you more information on your test such as the Browser, viewport size, test duration and more.
![meta data in trace viewer](https://github.com/microsoft/playwright/assets/13063165/82ab3d33-1ec9-4b8a-9cf2-30a6e2d59091)
### Attachments
* langs: js
The "Attachments" tab allows you to explore attachments. If you're doing [visual regression testing](./test-snapshots.md), you'll be able to compare screenshots by examining the image diff, the actual image and the expected image. When you click on the expected image you can use the slider to slide one image over the other so you can easily see the differences in your screenshots.
![attachments tab in trace viewer](https://github.com/microsoft/playwright/assets/13063165/4386178a-5808-4fa8-9436-315350a23b04)

View file

@ -39,6 +39,7 @@ Take a look at the following example to see how to write a test.
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -117,6 +118,40 @@ public class ExampleTest : PageTest
}
```
</TabItem>
<TabItem value="xunit">
```csharp title="UnitTest1.cs"
using System.Text.RegularExpressions;
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
namespace PlaywrightTests;
public class UnitTest1: PageTest
{
[Fact]
public async Task HasTitle()
{
await Page.GotoAsync("https://playwright.dev");
// Expect a title "to contain" a substring.
await Expect(Page).ToHaveTitleAsync(new Regex("Playwright"));
}
[Fact]
public async Task GetStartedLink()
{
await Page.GotoAsync("https://playwright.dev");
// Click the get started link.
await Page.GetByRole(AriaRole.Link, new() { Name = "Get started" }).ClickAsync();
// Expects page to have a heading with the name of Installation.
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Installation" })).ToBeVisibleAsync();
}
}
```
</TabItem>
</Tabs>
@ -204,6 +239,7 @@ The Playwright NUnit and MSTest test framework base classes will isolate each te
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
@ -248,23 +284,43 @@ public class ExampleTest : PageTest
}
```
</TabItem>
<TabItem value="xunit">
```csharp title="UnitTest1.cs"
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
namespace PlaywrightTests;
public class UnitTest1: PageTest
{
[Fact]
public async Task BasicTest()
{
await Page.GotoAsync("https://playwright.dev");
}
}
```
</TabItem>
</Tabs>
## Using Test Hooks
You can use `SetUp`/`TearDown` in NUnit or `TestInitialize`/`TestCleanup` in MSTest to prepare and clean up your test environment:
<Tabs
groupId="test-runners"
defaultValue="mstest"
values={[
{label: 'MSTest', value: 'mstest'},
{label: 'NUnit', value: 'nunit'},
{label: 'xUnit', value: 'xunit'},
]
}>
<TabItem value="nunit">
You can use `SetUp`/`TearDown` to prepare and clean up your test environment:
```csharp title="UnitTest1.cs"
using System.Threading.Tasks;
using Microsoft.Playwright.NUnit;
@ -294,6 +350,8 @@ public class ExampleTest : PageTest
</TabItem>
<TabItem value="mstest">
You can use `TestInitialize`/`TestCleanup` to prepare and clean up your test environment:
```csharp title="UnitTest1.cs"
using System.Threading.Tasks;
using Microsoft.Playwright.MSTest;
@ -319,6 +377,39 @@ public class ExampleTest : PageTest
}
```
</TabItem>
<TabItem value="xunit">
You can use `InitializeAsync`/`DisposeAsync` to prepare and clean up your test environment:
```csharp title="UnitTest1.cs"
using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;
namespace PlaywrightTests;
public class UnitTest1: PageTest
{
[Fact]
public async Task MainNavigation()
{
// Assertions use the expect API.
await Expect(Page).ToHaveURLAsync("https://playwright.dev/");
}
override public async Task InitializeAsync()
{
await base.InitializeAsync();
await Page.GotoAsync("https://playwright.dev");
}
public override async Task DisposeAsync()
{
Console.WriteLine("After each test cleanup");
await base.DisposeAsync();
}
}
```
</TabItem>
</Tabs>
@ -328,4 +419,4 @@ public class ExampleTest : PageTest
- [Generate tests with Codegen](./codegen-intro.md)
- [See a trace of your tests](./trace-viewer-intro.md)
- [Run tests on CI](./ci-intro.md)
- [Learn more about the MSTest and NUnit base classes](./test-runners.md)
- [Learn more about the MSTest, NUnit, or xUnit base classes](./test-runners.md)

95
eslint-react.config.mjs Normal file
View file

@ -0,0 +1,95 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { fixupConfigRules } from '@eslint/compat';
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import notice from 'eslint-plugin-notice';
import path from 'path';
import { fileURLToPath } from 'url';
import stylistic from '@stylistic/eslint-plugin';
import { baseRules } from './eslint.config.mjs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});
const baseConfig = fixupConfigRules(compat.extends('plugin:react/recommended', 'plugin:react-hooks/recommended'));
const plugins = {
'@stylistic': stylistic,
'@typescript-eslint': typescriptEslint,
notice,
};
const ignores = [
'.github/',
'*.js',
'**/.cache/',
'**/*.d.ts',
'**/dist/**',
'index.d.ts',
'node_modules/',
'output/',
'packages/*/lib/',
'test-results/',
'tests/',
'utils/',
];
export default [
{ ignores },
{
plugins,
settings: {
react: { version: 'detect' },
}
},
...baseConfig,
packageSection('html-reporter'),
packageSection('recorder'),
packageSection('trace-viewer'),
];
function packageSection(packageName) {
return {
files: [
`packages/${packageName}/src/**/*.ts`,
`packages/${packageName}/src/**/*.tsx`,
`packages/web/src/**/*.ts`,
`packages/web/src/**/*.tsx`,
],
languageOptions: {
parser: tsParser,
ecmaVersion: 9,
sourceType: 'module',
parserOptions: {
project: path.join(__dirname, 'packages', packageName, 'tsconfig.json'),
},
},
rules: {
...baseRules,
'no-console': 2,
}
};
}

292
eslint.config.mjs Normal file
View file

@ -0,0 +1,292 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import notice from 'eslint-plugin-notice';
import path from 'path';
import { fileURLToPath } from 'url';
import stylistic from '@stylistic/eslint-plugin';
import importRules from 'eslint-plugin-import';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const plugins = {
'@stylistic': stylistic,
'@typescript-eslint': typescriptEslint,
notice,
import: importRules,
};
const ignores = [
'.github/',
'*.js',
'**/.cache/',
'**/*.d.ts',
'index.d.ts',
'node_modules/',
'output/',
'packages/*/lib/',
'packages/html-reporter/**',
'packages/playwright-core/src/generated/*',
'packages/playwright-core/src/third_party/',
'packages/playwright-core/types/*',
'packages/playwright-ct-core/src/generated/*',
'packages/recorder/**',
'packages/trace-viewer/**',
'packages/web/**',
'test-results/',
'tests/assets/',
'tests/components/',
'tests/installation/fixture-scripts/',
'tests/third_party/',
'utils/',
];
export const baseRules = {
'@typescript-eslint/no-unused-vars': [2, { args: 'none', caughtErrors: 'none' }],
/**
* Enforced rules
*/
// syntax preferences
'object-curly-spacing': ['error', 'always'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'jsx-quotes': [2, 'prefer-single'],
'no-extra-semi': 2,
'@stylistic/semi': [2],
'comma-style': [2, 'last'],
'wrap-iife': [2, 'inside'],
'spaced-comment': [2, 'always', {
'markers': ['*']
}],
'eqeqeq': [2],
'accessor-pairs': [2, {
'getWithoutSet': false,
'setWithoutGet': false
}],
'brace-style': [2, '1tbs', { 'allowSingleLine': true }],
'curly': [2, 'multi-or-nest', 'consistent'],
'new-parens': 2,
'arrow-parens': [2, 'as-needed'],
'prefer-const': 2,
'quote-props': [2, 'consistent'],
'nonblock-statement-body-position': [2, 'below'],
// anti-patterns
'no-var': 2,
'no-with': 2,
'no-multi-str': 2,
'no-caller': 2,
'no-implied-eval': 2,
'no-labels': 2,
'no-new-object': 2,
'no-octal-escape': 2,
'no-self-compare': 2,
'no-shadow-restricted-names': 2,
'no-cond-assign': 2,
'no-debugger': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-unreachable': 2,
'no-unsafe-negation': 2,
'radix': 2,
'valid-typeof': 2,
'no-implicit-globals': [2],
'no-unused-expressions': [2, { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }],
'no-proto': 2,
// es2015 features
'require-yield': 2,
'template-curly-spacing': [2, 'never'],
// spacing details
'space-infix-ops': 2,
'space-in-parens': [2, 'never'],
'array-bracket-spacing': [2, 'never'],
'comma-spacing': [2, { 'before': false, 'after': true }],
'keyword-spacing': [2, 'always'],
'space-before-function-paren': [2, {
'anonymous': 'never',
'named': 'never',
'asyncArrow': 'always'
}],
'no-whitespace-before-property': 2,
'keyword-spacing': [2, {
'overrides': {
'if': { 'after': true },
'else': { 'after': true },
'for': { 'after': true },
'while': { 'after': true },
'do': { 'after': true },
'switch': { 'after': true },
'return': { 'after': true }
}
}],
'arrow-spacing': [2, {
'after': true,
'before': true
}],
'@stylistic/func-call-spacing': 2,
'@stylistic/type-annotation-spacing': 2,
// file whitespace
'no-multiple-empty-lines': [2, { 'max': 2, 'maxEOF': 0 }],
'no-mixed-spaces-and-tabs': 2,
'no-trailing-spaces': 2,
'linebreak-style': [process.platform === 'win32' ? 0 : 2, 'unix'],
'indent': [2, 2, { 'SwitchCase': 1, 'CallExpression': { 'arguments': 2 }, 'MemberExpression': 2 }],
'key-spacing': [2, {
'beforeColon': false
}],
'eol-last': 2,
// copyright
'notice/notice': [2, {
'mustMatch': 'Copyright',
'templateFile': path.join(__dirname, 'utils', 'copyright.js'),
}],
// react
'react/react-in-jsx-scope': 0
};
const noFloatingPromisesRules = {
'@typescript-eslint/no-floating-promises': 'error',
};
const noBooleanCompareRules = {
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 2,
};
const noWebGlobalsRules = {
'no-restricted-globals': [
'error',
{ 'name': 'window' },
{ 'name': 'document' },
{ 'name': 'globalThis' },
],
};
const noNodeGlobalsRules = {
'no-restricted-globals': [
'error',
{ 'name': 'process' },
],
};
const importOrderRules = {
'import/order': [2, {
'groups': ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index', 'type'],
'newlines-between': 'always',
}],
'import/consistent-type-specifier-style': [2, 'prefer-top-level']
};
const languageOptions = {
parser: tsParser,
ecmaVersion: 9,
sourceType: 'module',
};
const languageOptionsWithTsConfig = {
parser: tsParser,
ecmaVersion: 9,
sourceType: 'module',
parserOptions: {
project: path.join(__dirname, 'tsconfig.json'),
},
};
export default [{
ignores,
}, {
files: ['**/*.ts'],
plugins,
languageOptions,
rules: baseRules,
}, {
files: ['packages/**/*.ts'],
languageOptions: languageOptionsWithTsConfig,
rules: {
'no-console': 2,
'no-restricted-properties': [2, {
'object': 'process',
'property': 'exit',
'message': 'Please use gracefullyProcessExitDoNotHang function to exit the process.',
}],
}
}, {
files: [
'packages/**/*.ts',
],
rules: {
...importOrderRules
},
}, {
files: ['packages/playwright/**/*.ts'],
rules: {
...noFloatingPromisesRules,
}
}, {
files: ['packages/playwright/src/reporters/**/*.ts'],
languageOptions: languageOptionsWithTsConfig,
rules: {
'no-console': 'off'
}
}, {
files: [
'packages/playwright-core/src/server/injected/**/*.ts',
'packages/playwright-core/src/server/isomorphic/**/*.ts',
'packages/playwright-core/src/utils/isomorphic/**/*.ts',
],
languageOptions: languageOptionsWithTsConfig,
rules: {
...noWebGlobalsRules,
...noFloatingPromisesRules,
...noBooleanCompareRules,
}
}, {
files: [
'packages/playwright-core/src/client/**/*.ts',
'packages/playwright-core/src/protocol/**/*.ts',
'packages/playwright-core/src/utils/**/*.ts',
],
languageOptions: languageOptionsWithTsConfig,
rules: {
...noNodeGlobalsRules,
...noFloatingPromisesRules,
...noBooleanCompareRules,
}
}, {
files: ['tests/**/*.spec.js', 'tests/**/*.ts'],
languageOptions: {
parser: tsParser,
ecmaVersion: 9,
sourceType: 'module',
parserOptions: {
project: path.join(__dirname, 'tests', 'tsconfig.json'),
},
},
rules: {
...noFloatingPromisesRules,
}
}];

7328
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"name": "playwright-internal",
"private": true,
"version": "1.49.0-next",
"version": "1.51.0-next",
"description": "A high-level API to automate web browsers",
"repository": {
"type": "git",
@ -30,14 +30,14 @@
"ttest": "node ./tests/playwright-test/stable-test-runner/node_modules/@playwright/test/cli test --config=tests/playwright-test/playwright.config.ts",
"ct": "playwright test tests/components/test-all.spec.js --reporter=list",
"test": "playwright test --config=tests/library/playwright.config.ts",
"eslint": "eslint --cache --report-unused-disable-directives --ext ts,tsx,js,jsx,mjs .",
"eslint": "eslint --cache && eslint -c eslint-react.config.mjs",
"tsc": "tsc -p . && tsc -p packages/html-reporter/",
"build-installer": "babel -s --extensions \".ts\" --out-dir packages/playwright-core/lib/utils/ packages/playwright-core/src/utils",
"doc": "node utils/doclint/cli.js",
"lint": "npm run eslint && npm run tsc && npm run doc && npm run check-deps && node utils/generate_channels.js && node utils/generate_types/ && npm run lint-tests && npm run test-types && npm run lint-packages",
"lint-packages": "node utils/workspace.js --ensure-consistent",
"lint-tests": "node utils/lint_tests.js",
"flint": "concurrently \"npm run eslint\" \"npm run tsc\" \"npm run doc\" \"npm run check-deps\" \"node utils/generate_channels.js\" \"node utils/generate_types/\" \"npm run lint-tests\" \"npm run test-types\" \"npm run lint-packages\"",
"flint": "concurrently \"npm run eslint\" \"npm run tsc\" \"npm run doc\" \"npm run check-deps\" \"node utils/generate_channels.js\" \"node utils/generate_types/\" \"npm run lint-tests\" \"npm run test-types\" \"npm run lint-packages\" \"node utils/doclint/linting-code-snippets/cli.js --js-only\"",
"clean": "node utils/build/clean.js",
"build": "node utils/build/build.js",
"watch": "node utils/build/build.js --watch --lint",
@ -62,18 +62,22 @@
"@babel/plugin-transform-optional-chaining": "^7.23.4",
"@babel/plugin-transform-typescript": "^7.23.6",
"@babel/preset-react": "^7.23.3",
"@eslint/compat": "^1.2.6",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0",
"@stylistic/eslint-plugin": "^3.0.1",
"@types/babel__core": "^7.20.2",
"@types/codemirror": "^5.60.7",
"@types/formidable": "^2.0.4",
"@types/immutable": "^3.8.7",
"@types/node": "^18.19.39",
"@types/node": "^18.19.68",
"@types/react": "^18.0.12",
"@types/react-dom": "^18.0.5",
"@types/ws": "^8.5.3",
"@types/xml2js": "^0.4.9",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"@typescript-eslint/utils": "^7.15.0",
"@typescript-eslint/eslint-plugin": "^8.23.0",
"@typescript-eslint/parser": "^8.23.0",
"@typescript-eslint/utils": "^8.23.0",
"@vitejs/plugin-basic-ssl": "^1.1.0",
"@vitejs/plugin-react": "^4.2.1",
"@zip.js/zip.js": "^2.7.29",
@ -85,24 +89,25 @@
"cross-env": "^7.0.3",
"dotenv": "^16.4.5",
"electron": "^30.1.2",
"esbuild": "^0.18.11",
"eslint": "^8.55.0",
"eslint-plugin-internal-playwright": "file:utils/eslint-plugin-internal-playwright",
"eslint-plugin-notice": "^0.9.10",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"esbuild": "^0.25.0",
"eslint": "^9.19.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-notice": "^1.0.0",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
"formidable": "^2.1.1",
"immutable": "^4.3.7",
"license-checker": "^25.0.1",
"markdown-to-jsx": "^7.7.3",
"mime": "^3.0.0",
"node-stream-zip": "^1.15.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"ssim.js": "^3.5.0",
"typescript": "^5.5.3",
"vite": "^5.4.6",
"typescript": "^5.7.3",
"vite": "^6.1.0",
"ws": "^8.17.1",
"xml2js": "^0.5.0",
"yaml": "^2.6.0"
"yaml": "2.6.0"
}
}

View file

@ -1,21 +0,0 @@
module.exports = {
"extends": "../.eslintrc.js",
/**
* ESLint rules
*
* All available rules: http://eslint.org/docs/rules/
*
* Rules take the following form:
* "rule-name", [severity, { opts }]
* Severity: 2 == error, 1 == warning, 0 == off.
*/
"rules": {
"no-console": 2,
"no-debugger": 2,
"no-restricted-properties": [2, {
"object": "process",
"property": "exit",
"message": "Please use gracefullyProcessExitDoNotHang function to exit the process.",
}],
}
};

View file

@ -51,4 +51,4 @@ export function bundle(): Plugin {
}
},
};
}
}

View file

@ -15,7 +15,7 @@
-->
<!DOCTYPE html>
<html>
<html style='scrollbar-gutter: stable both-edges;'>
<head>
<meta charset='UTF-8'>
<meta name='color-scheme' content='dark light'>

View file

@ -2,10 +2,5 @@
"name": "html-reporter",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build && tsc",
"preview": "vite preview"
}
"type": "module"
}

View file

@ -23,7 +23,11 @@ export default defineConfig({
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
snapshotPathTemplate: '{testDir}/__screenshots__/{projectName}/{testFilePath}/{arg}{ext}',
reporter: process.env.CI ? 'blob' : 'html',
reporter: process.env.CI ? [
['blob', { fileName: `${process.env.PWTEST_BOT_NAME}.zip` }],
] : [
['html']
],
use: {
ctPort: 3101,
ctViteConfig: {

View file

@ -20,6 +20,7 @@ import './colors.css';
import './common.css';
import * as icons from './icons';
import { clsx } from '@web/uiUtils';
import { type AnchorID, useAnchor } from './links';
export const Chip: React.FC<{
header: JSX.Element | string,
@ -28,10 +29,9 @@ export const Chip: React.FC<{
setExpanded?: (expanded: boolean) => void,
children?: any,
dataTestId?: string,
targetRef?: React.RefObject<HTMLDivElement>,
}> = ({ header, expanded, setExpanded, children, noInsets, dataTestId, targetRef }) => {
}> = ({ header, expanded, setExpanded, children, noInsets, dataTestId }) => {
const id = React.useId();
return <div className='chip' data-testid={dataTestId} ref={targetRef}>
return <div className='chip' data-testid={dataTestId}>
<div
role='button'
aria-expanded={!!expanded}
@ -53,16 +53,17 @@ export const AutoChip: React.FC<{
noInsets?: boolean,
children?: any,
dataTestId?: string,
targetRef?: React.RefObject<HTMLDivElement>,
}> = ({ header, initialExpanded, noInsets, children, dataTestId, targetRef }) => {
const [expanded, setExpanded] = React.useState(initialExpanded || initialExpanded === undefined);
revealOnAnchorId?: AnchorID,
}> = ({ header, initialExpanded, noInsets, children, dataTestId, revealOnAnchorId }) => {
const [expanded, setExpanded] = React.useState(initialExpanded ?? true);
const onReveal = React.useCallback(() => setExpanded(true), []);
useAnchor(revealOnAnchorId, onReveal);
return <Chip
header={header}
expanded={expanded}
setExpanded={setExpanded}
noInsets={noInsets}
dataTestId={dataTestId}
targetRef={targetRef}
>
{children}
</Chip>;

View file

@ -267,6 +267,26 @@ article, aside, details, figcaption, figure, footer, header, main, menu, nav, se
flex: none;
}
.button {
flex: none;
height: 24px;
border: 1px solid var(--color-btn-border);
outline: none;
color: var(--color-btn-text);
background: var(--color-btn-bg);
padding: 4px;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.button:not(:disabled):hover {
border-color: var(--color-btn-hover-border);
background-color: var(--color-btn-hover-bg);
}
@media only screen and (max-width: 600px) {
.subnav-item, .form-control {
border-radius: 0 !important;

View file

@ -39,7 +39,7 @@ export const CopyToClipboard: React.FunctionComponent<CopyToClipboardProps> = ({
});
}, [value]);
const iconElement = icon === 'check' ? icons.check() : icon === 'cross' ? icons.cross() : icons.copy();
return <button className='copy-icon' aria-label='Copy to clipboard' onClick={handleCopy}>{iconElement}</button>;
return <button className='copy-icon' title='Copy to clipboard' aria-label='Copy to clipboard' onClick={handleCopy}>{iconElement}</button>;
};
type CopyToClipboardContainerProps = CopyToClipboardProps & {

View file

@ -64,6 +64,6 @@ test('should toggle filters', async ({ page, mount }) => {
await expect(page).toHaveURL(/#\?q=s:flaky/);
await component.locator('a', { hasText: 'Skipped' }).click();
await expect(page).toHaveURL(/#\?q=s:skipped/);
await component.getByRole('searchbox').fill('annot:annotation type=annotation description');
await component.getByRole('textbox').fill('annot:annotation type=annotation description');
expect(filters).toEqual(['', 's:passed', 's:failed', 's:flaky', 's:skipped', 'annot:annotation type=annotation description']);
});

View file

@ -49,12 +49,14 @@ export const HeaderView: React.FC<React.PropsWithChildren<{
<form className='subnav-search' onSubmit={
event => {
event.preventDefault();
navigate(`#?q=${filterText ? encodeURIComponent(filterText) : ''}`);
const url = new URL(window.location.href);
url.hash = filterText ? '?' + new URLSearchParams({ q: filterText }) : '';
navigate(url);
}
}>
{icons.search()}
{/* Use navigationId to reset defaultValue */}
<input type='search' spellCheck={false} className='form-control subnav-search-input input-contrast width-full' value={filterText} onChange={e => {
<input spellCheck={false} className='form-control subnav-search-input input-contrast width-full' value={filterText} onChange={e => {
setFilterText(e.target.value);
}}></input>
</form>

Some files were not shown because too many files have changed in this diff Show more