From 0182567a622dba0203ca2c73ee37ba810540c37d Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 11 Nov 2025 19:23:35 +0100 Subject: [PATCH] Playwright against abitrary web-vault (#6380) * Playwright improvements * Playwright fix for the extension setup --------- Co-authored-by: Timshel --- playwright/README.md | 6 +- playwright/compose/warden/build.sh | 15 +- playwright/docker-compose.yml | 5 +- playwright/global-utils.ts | 22 +- playwright/package-lock.json | 328 +++++++----------- playwright/package.json | 8 +- playwright/test.env | 5 +- playwright/tests/login.smtp.spec.ts | 3 + playwright/tests/organization.smtp.spec.ts | 14 +- playwright/tests/setups/2fa.ts | 2 +- playwright/tests/setups/sso.ts | 14 +- playwright/tests/setups/user.ts | 9 +- .../tests/sso_organization.smtp.spec.ts | 15 +- 13 files changed, 204 insertions(+), 242 deletions(-) diff --git a/playwright/README.md b/playwright/README.md index 528bdf07..a27e6105 100644 --- a/playwright/README.md +++ b/playwright/README.md @@ -97,9 +97,9 @@ npx playwright codegen "http://127.0.0.1:8003" ## Override web-vault -It is possible to change the `web-vault` used by referencing a different `bw_web_builds` commit. +It is possible to change the `web-vault` used by referencing a different `vw_web_builds` commit. -Simplest is to set and uncomment `PW_WV_REPO_URL` and `PW_WV_COMMIT_HASH` in the `test.env`. +Simplest is to set and uncomment `PW_VW_REPO_URL` and `PW_VW_COMMIT_HASH` in the `test.env`. Ensure that the image is built with: ```bash @@ -112,6 +112,8 @@ You can check the result running: DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env up Vaultwarden ``` +Then check `http://127.0.0.1:8003/admin/diagnostics` with `admin`. + # OpenID Connect test setup Additionally this `docker-compose` template allows to run locally Vaultwarden, diff --git a/playwright/compose/warden/build.sh b/playwright/compose/warden/build.sh index a29067c8..37e9a25e 100755 --- a/playwright/compose/warden/build.sh +++ b/playwright/compose/warden/build.sh @@ -6,18 +6,19 @@ echo $COMMIT_HASH if [[ ! -z "$REPO_URL" ]] && [[ ! -z "$COMMIT_HASH" ]] ; then rm -rf /web-vault - mkdir bw_web_builds; - cd bw_web_builds; + mkdir -p vw_web_builds; + cd vw_web_builds; git -c init.defaultBranch=main init git remote add origin "$REPO_URL" git fetch --depth 1 origin "$COMMIT_HASH" git -c advice.detachedHead=false checkout FETCH_HEAD - export VAULT_VERSION=$(cat Dockerfile | grep "ARG VAULT_VERSION" | cut -d "=" -f2) - ./scripts/checkout_web_vault.sh - ./scripts/build_web_vault.sh - printf '{"version":"%s"}' "$COMMIT_HASH" > ./web-vault/apps/web/build/vw-version.json + npm ci --ignore-scripts - mv ./web-vault/apps/web/build /web-vault + cd apps/web + npm run dist:oss:selfhost + printf '{"version":"%s"}' "$COMMIT_HASH" > build/vw-version.json + + mv build /web-vault fi diff --git a/playwright/docker-compose.yml b/playwright/docker-compose.yml index c6e33e79..f4402326 100644 --- a/playwright/docker-compose.yml +++ b/playwright/docker-compose.yml @@ -18,10 +18,11 @@ services: context: compose/warden dockerfile: Dockerfile args: - REPO_URL: ${PW_WV_REPO_URL:-} - COMMIT_HASH: ${PW_WV_COMMIT_HASH:-} + REPO_URL: ${PW_VW_REPO_URL:-} + COMMIT_HASH: ${PW_VW_COMMIT_HASH:-} env_file: ${DC_ENV_FILE:-.env} environment: + - ADMIN_TOKEN - DATABASE_URL - I_REALLY_WANT_VOLATILE_STORAGE - LOG_LEVEL diff --git a/playwright/global-utils.ts b/playwright/global-utils.ts index e622451d..224bb4b8 100644 --- a/playwright/global-utils.ts +++ b/playwright/global-utils.ts @@ -221,9 +221,13 @@ export async function restartVault(page: Page, testInfo: TestInfo, env, resetDB: } export async function checkNotification(page: Page, hasText: string) { - await expect(page.locator('bit-toast').filter({ hasText })).toBeVisible(); - await page.locator('bit-toast').filter({ hasText }).getByRole('button').click(); - await expect(page.locator('bit-toast').filter({ hasText })).toHaveCount(0); + await expect(page.locator('bit-toast', { hasText })).toBeVisible(); + try { + await page.locator('bit-toast', { hasText }).getByRole('button', { name: 'Close' }).click({force: true, timeout: 10_000}); + } catch (error) { + console.log(`Closing notification failed but it should now be invisible (${error})`); + } + await expect(page.locator('bit-toast', { hasText })).toHaveCount(0); } export async function cleanLanding(page: Page) { @@ -244,3 +248,15 @@ export async function logout(test: Test, page: Page, user: { name: string }) { await expect(page.getByRole('heading', { name: 'Log in' })).toBeVisible(); }); } + +export async function ignoreExtension(page: Page) { + await page.waitForLoadState('domcontentloaded'); + + try { + await page.getByRole('button', { name: 'Add it later' }).click({timeout: 5_000}); + await page.getByRole('link', { name: 'Skip to web app' }).click(); + } catch (error) { + console.log('Extension setup not visible. Continuing'); + } + +} diff --git a/playwright/package-lock.json b/playwright/package-lock.json index 37d0b512..2f4cd0c1 100644 --- a/playwright/package-lock.json +++ b/playwright/package-lock.json @@ -9,15 +9,15 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "mysql2": "3.15.0", + "mysql2": "3.15.3", "otpauth": "9.4.1", "pg": "8.16.3" }, "devDependencies": { - "@playwright/test": "1.55.1", - "dotenv": "17.2.2", + "@playwright/test": "1.56.1", + "dotenv": "17.2.3", "dotenv-expand": "12.0.3", - "maildev": "npm:@timshel_npm/maildev@^3.2.3" + "maildev": "npm:@timshel_npm/maildev@3.2.5" } }, "node_modules/@asamuzakjp/css-color": { @@ -34,16 +34,16 @@ } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.5.6", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.5.6.tgz", - "integrity": "sha512-Mj3Hu9ymlsERd7WOsUKNUZnJYL4IZ/I9wVVYgtvOsWYiEFbkQ4G7VRIh2USxTVW4BBDIsLG+gBUgqOqf2Kvqow==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.3.tgz", + "integrity": "sha512-kiGFeY+Hxf5KbPpjRLf+ffWbkos1aGo8MBfd91oxS3O57RgU3XhZrt/6UzoVF9VMpWbC3v87SRc9jxGrc9qHtQ==", "dev": true, "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.1" + "lru-cache": "^11.2.2" } }, "node_modules/@asamuzakjp/nwsapi": { @@ -144,9 +144,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz", - "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.15.tgz", + "integrity": "sha512-q0p6zkVq2lJnmzZVPR33doA51G7YOja+FBvRdp5ISIthL0MtFCgYHHhR563z9WFGxcOn0WfjSkPDJ5Qig3H3Sw==", "dev": true, "funding": [ { @@ -160,9 +160,6 @@ ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" } }, "node_modules/@csstools/css-tokenizer": { @@ -196,12 +193,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz", - "integrity": "sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", "dev": true, "dependencies": { - "playwright": "1.55.1" + "playwright": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -249,12 +246,12 @@ } }, "node_modules/@types/node": { - "version": "24.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz", - "integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==", + "version": "24.2.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz", + "integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==", "dev": true, "dependencies": { - "undici-types": "~7.12.0" + "undici-types": "~7.10.0" } }, "node_modules/@types/trusted-types": { @@ -363,9 +360,9 @@ } }, "node_modules/body-parser/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "dependencies": { "ms": "^2.1.3" @@ -637,9 +634,9 @@ } }, "node_modules/dompurify": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", - "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz", + "integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==", "dev": true, "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -660,9 +657,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz", - "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "dev": true, "engines": { "node": ">=12" @@ -952,9 +949,9 @@ } }, "node_modules/express/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "dependencies": { "ms": "^2.1.3" @@ -992,9 +989,9 @@ } }, "node_modules/finalhandler/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "dependencies": { "ms": "^2.1.3" @@ -1340,20 +1337,20 @@ "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" }, "node_modules/jsdom": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.0.0.tgz", - "integrity": "sha512-lIHeR1qlIRrIN5VMccd8tI2Sgw6ieYXSVktcSHaNe3Z5nE/tcPQYQWOq00wxMvYOsz+73eAkNenVvmPC6bba9A==", + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.0.1.tgz", + "integrity": "sha512-SNSQteBL1IlV2zqhwwolaG9CwhIhTvVHWg3kTss/cLE7H/X4644mtPQqYvCfsSrGQWt9hSZcgOXX8bOZaMN+kA==", "dev": true, "dependencies": { - "@asamuzakjp/dom-selector": "^6.5.4", - "cssstyle": "^5.3.0", + "@asamuzakjp/dom-selector": "^6.7.2", + "cssstyle": "^5.3.1", "data-urls": "^6.0.0", - "decimal.js": "^10.5.0", + "decimal.js": "^10.6.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", - "parse5": "^7.3.0", + "parse5": "^8.0.0", "rrweb-cssom": "^0.8.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", @@ -1362,8 +1359,8 @@ "webidl-conversions": "^8.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0", - "ws": "^8.18.2", + "whatwg-url": "^15.1.0", + "ws": "^8.18.3", "xml-name-validator": "^5.0.0" }, "engines": { @@ -1426,9 +1423,9 @@ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" }, "node_modules/lru-cache": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.1.tgz", - "integrity": "sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==", + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", "dev": true, "engines": { "node": "20 || >=22" @@ -1450,9 +1447,9 @@ }, "node_modules/maildev": { "name": "@timshel_npm/maildev", - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@timshel_npm/maildev/-/maildev-3.2.3.tgz", - "integrity": "sha512-CNxMz4Obw7nL8MZbx4y1YUFeqqAQk+Qwm51tcBV5lRBotMlXKeYhuEcayb1v66nUwq832bUfKF4hyQpJixFZrw==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@timshel_npm/maildev/-/maildev-3.2.5.tgz", + "integrity": "sha512-suWQu2s2kmO+MXtNJYW9peklznhd+aorIUb4tSNrfaKoEJjDa3vLXTvWf+3cb67o4Yv4Z6nPeKdMTCDZVn/Nyw==", "dev": true, "dependencies": { "@types/mailparser": "3.4.6", @@ -1461,13 +1458,13 @@ "commander": "14.0.1", "compression": "1.8.1", "cors": "2.8.5", - "dompurify": "3.2.7", + "dompurify": "3.3.0", "express": "5.1.0", - "jsdom": "27.0.0", - "mailparser": "3.7.4", + "jsdom": "27.0.1", + "mailparser": "3.7.5", "mime": "4.1.0", - "nodemailer": "7.0.6", - "smtp-server": "3.14.0", + "nodemailer": "7.0.9", + "smtp-server": "3.15.0", "socket.io": "4.8.1", "wildstring": "1.0.9" }, @@ -1479,36 +1476,44 @@ } }, "node_modules/mailparser": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.4.tgz", - "integrity": "sha512-Beh4yyR4jLq3CZZ32asajByrXnW8dLyKCAQD3WvtTiBnMtFWhxO+wa93F6sJNjDmfjxXs4NRNjw3XAGLqZR3Vg==", + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.5.tgz", + "integrity": "sha512-o59RgZC+4SyCOn4xRH1mtRiZ1PbEmi6si6Ufnd3tbX/V9zmZN1qcqu8xbXY62H6CwIclOT3ppm5u/wV2nujn4g==", "dev": true, "dependencies": { "encoding-japanese": "2.2.0", "he": "1.2.0", "html-to-text": "9.0.5", - "iconv-lite": "0.6.3", + "iconv-lite": "0.7.0", "libmime": "5.3.7", "linkify-it": "5.0.0", - "mailsplit": "5.4.5", - "nodemailer": "7.0.4", + "mailsplit": "5.4.6", + "nodemailer": "7.0.9", "punycode.js": "2.3.1", - "tlds": "1.259.0" + "tlds": "1.260.0" } }, - "node_modules/mailparser/node_modules/nodemailer": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.4.tgz", - "integrity": "sha512-9O00Vh89/Ld2EcVCqJ/etd7u20UhME0f/NToPfArwPEe1Don1zy4mAIz6ariRr7mJ2RDxtaDzN0WJVdVXPtZaw==", + "node_modules/mailparser/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mailsplit": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.5.tgz", - "integrity": "sha512-oMfhmvclR689IIaQmIcR5nODnZRRVwAKtqFT407TIvmhX2OLUBnshUTcxzQBt3+96sZVDud9NfSe1NxAkUNXEQ==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.6.tgz", + "integrity": "sha512-M+cqmzaPG/mEiCDmqQUz8L177JZLZmXAUpq38owtpq2xlXlTSw+kntnxRt2xsxVFFV6+T8Mj/U0l5s7s6e0rNw==", + "deprecated": "This package has been renamed to @zone-eu/mailsplit. Please update your dependencies.", "dev": true, "dependencies": { "libbase64": "1.3.0", @@ -1595,9 +1600,9 @@ "dev": true }, "node_modules/mysql2": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.0.tgz", - "integrity": "sha512-tT6pomf5Z/I7Jzxu8sScgrYBMK9bUFWd7Kbo6Fs1L0M13OOIJ/ZobGKS3Z7tQ8Re4lj+LnLXIQVZZxa3fhYKzA==", + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", + "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", @@ -1647,25 +1652,6 @@ "node": ">=12" } }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/negotiator": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", @@ -1676,9 +1662,9 @@ } }, "node_modules/nodemailer": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.6.tgz", - "integrity": "sha512-F44uVzgwo49xboqbFgBGkRaiMgtoBrBEWCVincJPK9+S9Adkzt/wXCLKbf7dxucmxfTI5gHGB+bEmdyzN6QKjw==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.9.tgz", + "integrity": "sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ==", "dev": true, "engines": { "node": ">=6.0.0" @@ -1747,9 +1733,9 @@ } }, "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "dev": true, "dependencies": { "entities": "^6.0.0" @@ -1793,13 +1779,12 @@ } }, "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "engines": { + "node": ">=16" } }, "node_modules/peberminta": { @@ -1892,20 +1877,13 @@ "split2": "^4.1.0" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "peer": true - }, "node_modules/playwright": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", - "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", "dev": true, "dependencies": { - "playwright-core": "1.55.1" + "playwright-core": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -1918,9 +1896,9 @@ } }, "node_modules/playwright-core": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", - "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -1929,35 +1907,6 @@ "node": ">=18" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -2049,34 +1998,18 @@ } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", "dev": true, "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", - "iconv-lite": "0.7.0", + "iconv-lite": "0.6.3", "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.10" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.8" } }, "node_modules/require-from-string": { @@ -2105,9 +2038,9 @@ } }, "node_modules/router/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "dependencies": { "ms": "^2.1.3" @@ -2205,9 +2138,9 @@ } }, "node_modules/send/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "dependencies": { "ms": "^2.1.3" @@ -2326,29 +2259,20 @@ } }, "node_modules/smtp-server": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/smtp-server/-/smtp-server-3.14.0.tgz", - "integrity": "sha512-cEw/hdIY+xw1pkbQbQ23hvnm9kNABAsgYB+jJYGkzAynZxJ2VB9aqC6JhB1vpdDnqan7C7AL3qHYRGwz5eD6BQ==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/smtp-server/-/smtp-server-3.15.0.tgz", + "integrity": "sha512-yv945vk0/xcukSKAoIhGz6GOlcXoCyGQH2w9IlLrTKk3SJiOBH9bcO6tD0ILTZYJsMqRa6OTRZAyqeuLXkv59Q==", "dev": true, "dependencies": { "base32.js": "0.1.0", "ipv6-normalize": "1.0.1", - "nodemailer": "7.0.3", + "nodemailer": "7.0.9", "punycode.js": "2.3.1" }, "engines": { "node": ">=12.0.0" } }, - "node_modules/smtp-server/node_modules/nodemailer": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.3.tgz", - "integrity": "sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", @@ -2564,30 +2488,30 @@ "dev": true }, "node_modules/tlds": { - "version": "1.259.0", - "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.259.0.tgz", - "integrity": "sha512-AldGGlDP0PNgwppe2quAvuBl18UcjuNtOnDuUkqhd6ipPqrYYBt3aTxK1QTsBVknk97lS2JcafWMghjGWFtunw==", + "version": "1.260.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.260.0.tgz", + "integrity": "sha512-78+28EWBhCEE7qlyaHA9OR3IPvbCLiDh3Ckla593TksfFc9vfTsgvH7eS+dr3o9qr31gwGbogcI16yN91PoRjQ==", "dev": true, "bin": { "tlds": "bin.js" } }, "node_modules/tldts": { - "version": "7.0.16", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.16.tgz", - "integrity": "sha512-5bdPHSwbKTeHmXrgecID4Ljff8rQjv7g8zKQPkCozRo2HWWni+p310FSn5ImI+9kWw9kK4lzOB5q/a6iv0IJsw==", + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.17.tgz", + "integrity": "sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ==", "dev": true, "dependencies": { - "tldts-core": "^7.0.16" + "tldts-core": "^7.0.17" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.16", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.16.tgz", - "integrity": "sha512-XHhPmHxphLi+LGbH0G/O7dmUH9V65OY20R7vH8gETHsp5AZCjBk9l8sqmRKLaGOxnETU7XNSDUPtewAy/K6jbA==", + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.17.tgz", + "integrity": "sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==", "dev": true }, "node_modules/toidentifier": { @@ -2644,9 +2568,9 @@ "dev": true }, "node_modules/undici-types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", - "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", "dev": true }, "node_modules/unpipe": { diff --git a/playwright/package.json b/playwright/package.json index 5b33b1ed..f47ec5dc 100644 --- a/playwright/package.json +++ b/playwright/package.json @@ -8,13 +8,13 @@ "author": "", "license": "ISC", "devDependencies": { - "@playwright/test": "1.55.1", - "dotenv": "17.2.2", + "@playwright/test": "1.56.1", + "dotenv": "17.2.3", "dotenv-expand": "12.0.3", - "maildev": "npm:@timshel_npm/maildev@^3.2.3" + "maildev": "npm:@timshel_npm/maildev@3.2.5" }, "dependencies": { - "mysql2": "3.15.0", + "mysql2": "3.15.3", "otpauth": "9.4.1", "pg": "8.16.3" } diff --git a/playwright/test.env b/playwright/test.env index d97c08d1..df182ebe 100644 --- a/playwright/test.env +++ b/playwright/test.env @@ -55,6 +55,7 @@ ROCKET_PORT=8003 DOMAIN=http://localhost:${ROCKET_PORT} LOG_LEVEL=info,oidcwarden::sso=debug LOGIN_RATELIMIT_MAX_BURST=100 +ADMIN_TOKEN=admin SMTP_SECURITY=off SMTP_PORT=${MAILDEV_SMTP_PORT} @@ -67,8 +68,8 @@ SSO_AUTHORITY=http://${KC_HTTP_HOST}:${KC_HTTP_PORT}/realms/${TEST_REALM} SSO_DEBUG_TOKENS=true # Custom web-vault build -# PW_WV_REPO_URL=https://github.com/dani-garcia/bw_web_builds.git -# PW_WV_COMMIT_HASH=a5f5390895516bce2f48b7baadb6dc399e5fe75a +# PW_VW_REPO_URL=https://github.com/vaultwarden/vw_web_builds.git +# PW_VW_COMMIT_HASH=b5f5b2157b9b64b5813bc334a75a277d0377b5d3 ########################### # Docker MariaDb container# diff --git a/playwright/tests/login.smtp.spec.ts b/playwright/tests/login.smtp.spec.ts index 2f782c14..87474b79 100644 --- a/playwright/tests/login.smtp.spec.ts +++ b/playwright/tests/login.smtp.spec.ts @@ -91,6 +91,9 @@ test('2fa', async ({ page }) => { await page.getByLabel(/Verification code/).fill(code); await page.getByRole('button', { name: 'Continue' }).click(); + await page.getByRole('button', { name: 'Add it later' }).click(); + await page.getByRole('link', { name: 'Skip to web app' }).click(); + await expect(page).toHaveTitle(/Vaults/); }) diff --git a/playwright/tests/organization.smtp.spec.ts b/playwright/tests/organization.smtp.spec.ts index 764f9017..35dfcdb1 100644 --- a/playwright/tests/organization.smtp.spec.ts +++ b/playwright/tests/organization.smtp.spec.ts @@ -57,15 +57,17 @@ test('invited with new account', async ({ page }) => { await expect(page).toHaveTitle(/Create account | Vaultwarden Web/); //await page.getByLabel('Name').fill(users.user2.name); - await page.getByLabel('New master password (required)', { exact: true }).fill(users.user2.password); - await page.getByLabel('Confirm new master password (').fill(users.user2.password); + await page.getByLabel('Master password (required)', { exact: true }).fill(users.user2.password); + await page.getByLabel('Confirm master password (').fill(users.user2.password); await page.getByRole('button', { name: 'Create account' }).click(); await utils.checkNotification(page, 'Your new account has been created'); + await utils.checkNotification(page, 'Invitation accepted'); + await utils.ignoreExtension(page); + // Redirected to the vault await expect(page).toHaveTitle('Vaults | Vaultwarden Web'); - await utils.checkNotification(page, 'You have been logged in!'); - await utils.checkNotification(page, 'Invitation accepted'); + // await utils.checkNotification(page, 'You have been logged in!'); }); await test.step('Check mails', async () => { @@ -91,9 +93,11 @@ test('invited with existing account', async ({ page }) => { await page.getByLabel('Master password').fill(users.user3.password); await page.getByRole('button', { name: 'Log in with master password' }).click(); + await utils.checkNotification(page, 'Invitation accepted'); + await utils.ignoreExtension(page); + // We are now in the default vault page await expect(page).toHaveTitle(/Vaultwarden Web/); - await utils.checkNotification(page, 'Invitation accepted'); await mail3Buffer.expect((m) => m.subject === 'New Device Logged In From Firefox'); await mail1Buffer.expect((m) => m.subject.includes('Invitation to Test accepted')); diff --git a/playwright/tests/setups/2fa.ts b/playwright/tests/setups/2fa.ts index 1406083e..d7936420 100644 --- a/playwright/tests/setups/2fa.ts +++ b/playwright/tests/setups/2fa.ts @@ -48,7 +48,7 @@ export async function activateEmail(test: Test, page: Page, user: { name: string await page.getByRole('menuitem', { name: 'Account settings' }).click(); await page.getByRole('link', { name: 'Security' }).click(); await page.getByRole('link', { name: 'Two-step login' }).click(); - await page.locator('bit-item').filter({ hasText: 'Email Email Enter a code sent' }).getByRole('button').click(); + await page.locator('bit-item').filter({ hasText: 'Enter a code sent to your email' }).getByRole('button').click(); await page.getByLabel('Master password (required)').fill(user.password); await page.getByRole('button', { name: 'Continue' }).click(); await page.getByRole('button', { name: 'Send email' }).click(); diff --git a/playwright/tests/setups/sso.ts b/playwright/tests/setups/sso.ts index 8998b6c7..6317f8b0 100644 --- a/playwright/tests/setups/sso.ts +++ b/playwright/tests/setups/sso.ts @@ -33,19 +33,21 @@ export async function logNewUser( await test.step('Create Vault account', async () => { await expect(page.getByRole('heading', { name: 'Join organisation' })).toBeVisible(); - await page.getByLabel('New master password (required)', { exact: true }).fill(user.password); - await page.getByLabel('Confirm new master password (').fill(user.password); + await page.getByLabel('Master password (required)', { exact: true }).fill(user.password); + await page.getByLabel('Confirm master password (').fill(user.password); await page.getByRole('button', { name: 'Create account' }).click(); }); + await utils.checkNotification(page, 'Account successfully created!'); + await utils.checkNotification(page, 'Invitation accepted'); + + await utils.ignoreExtension(page); + await test.step('Default vault page', async () => { await expect(page).toHaveTitle(/Vaultwarden Web/); await expect(page.getByTitle('All vaults', { exact: true })).toBeVisible(); }); - await utils.checkNotification(page, 'Account successfully created!'); - await utils.checkNotification(page, 'Invitation accepted'); - if( options.mailBuffer ){ let mailBuffer = options.mailBuffer; await test.step('Check emails', async () => { @@ -115,6 +117,8 @@ export async function logUser( await page.getByRole('button', { name: 'Unlock' }).click(); }); + await utils.ignoreExtension(page); + await test.step('Default vault page', async () => { await expect(page).toHaveTitle(/Vaultwarden Web/); await expect(page.getByTitle('All vaults', { exact: true })).toBeVisible(); diff --git a/playwright/tests/setups/user.ts b/playwright/tests/setups/user.ts index 45fd86a0..395196ae 100644 --- a/playwright/tests/setups/user.ts +++ b/playwright/tests/setups/user.ts @@ -17,15 +17,16 @@ export async function createAccount(test, page: Page, user: { email: string, nam await page.getByRole('button', { name: 'Continue' }).click(); // Vault finish Creation - await page.getByLabel('New master password (required)', { exact: true }).fill(user.password); - await page.getByLabel('Confirm new master password (').fill(user.password); + await page.getByLabel('Master password (required)', { exact: true }).fill(user.password); + await page.getByLabel('Confirm master password (').fill(user.password); await page.getByRole('button', { name: 'Create account' }).click(); await utils.checkNotification(page, 'Your new account has been created') + await utils.ignoreExtension(page); // We are now in the default vault page await expect(page).toHaveTitle('Vaults | Vaultwarden Web'); - await utils.checkNotification(page, 'You have been logged in!'); + // await utils.checkNotification(page, 'You have been logged in!'); if( mailBuffer ){ await mailBuffer.expect((m) => m.subject === "Welcome"); @@ -45,6 +46,8 @@ export async function logUser(test, page: Page, user: { email: string, password: await page.getByLabel('Master password').fill(user.password); await page.getByRole('button', { name: 'Log in with master password' }).click(); + await utils.ignoreExtension(page); + // We are now in the default vault page await expect(page).toHaveTitle(/Vaultwarden Web/); diff --git a/playwright/tests/sso_organization.smtp.spec.ts b/playwright/tests/sso_organization.smtp.spec.ts index 45ef5ada..92813f72 100644 --- a/playwright/tests/sso_organization.smtp.spec.ts +++ b/playwright/tests/sso_organization.smtp.spec.ts @@ -67,16 +67,17 @@ test('invited with new account', async ({ page }) => { await test.step('Create Vault account', async () => { await expect(page.getByRole('heading', { name: 'Join organisation' })).toBeVisible(); - await page.getByLabel('New master password (required)', { exact: true }).fill(users.user2.password); - await page.getByLabel('Confirm new master password (').fill(users.user2.password); + await page.getByLabel('Master password (required)', { exact: true }).fill(users.user2.password); + await page.getByLabel('Confirm master password (').fill(users.user2.password); await page.getByRole('button', { name: 'Create account' }).click(); + + await utils.checkNotification(page, 'Account successfully created!'); + await utils.checkNotification(page, 'Invitation accepted'); + await utils.ignoreExtension(page); }); await test.step('Default vault page', async () => { await expect(page).toHaveTitle(/Vaultwarden Web/); - - await utils.checkNotification(page, 'Account successfully created!'); - await utils.checkNotification(page, 'Invitation accepted'); }); await test.step('Check mails', async () => { @@ -107,11 +108,13 @@ test('invited with existing account', async ({ page }) => { await expect(page).toHaveTitle('Vaultwarden Web'); await page.getByLabel('Master password').fill(users.user3.password); await page.getByRole('button', { name: 'Unlock' }).click(); + + await utils.checkNotification(page, 'Invitation accepted'); + await utils.ignoreExtension(page); }); await test.step('Default vault page', async () => { await expect(page).toHaveTitle(/Vaultwarden Web/); - await utils.checkNotification(page, 'Invitation accepted'); }); await test.step('Check mails', async () => {