From edef0ca80d14d92d7f5999cbf65c09d86484b5ff Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 11 Feb 2025 19:47:05 +0100 Subject: [PATCH] Improve tests --- playwright/docker-compose.yml | 2 +- playwright/global-utils.ts | 21 +- playwright/package-lock.json | 282 +++++++++++++----- playwright/package.json | 2 +- playwright/tests/collection.spec.ts | 38 +++ playwright/tests/login.smtp.spec.ts | 53 +--- playwright/tests/login.spec.ts | 2 +- playwright/tests/organization.smtp.spec.ts | 116 +++---- playwright/tests/organization.spec.ts | 11 +- playwright/tests/setups/orgs.ts | 62 ++++ playwright/tests/setups/sso.ts | 4 +- playwright/tests/setups/user.ts | 19 +- .../tests/sso_organization.smtp.spec.ts | 16 +- playwright/tests/sso_organization.spec.ts | 12 +- 14 files changed, 393 insertions(+), 247 deletions(-) create mode 100644 playwright/tests/collection.spec.ts create mode 100644 playwright/tests/setups/orgs.ts diff --git a/playwright/docker-compose.yml b/playwright/docker-compose.yml index ea2ab5e9..e5dd4a70 100644 --- a/playwright/docker-compose.yml +++ b/playwright/docker-compose.yml @@ -89,7 +89,7 @@ services: Maildev: profiles: ["vaultwarden", "maildev"] container_name: maildev - image: timshel/maildev + image: timshel/maildev:3.0.4 ports: - ${SMTP_PORT}:1025 - 1080:1080 diff --git a/playwright/global-utils.ts b/playwright/global-utils.ts index 724b0877..79f4f90b 100644 --- a/playwright/global-utils.ts +++ b/playwright/global-utils.ts @@ -1,4 +1,4 @@ -import { type Browser, type TestInfo } from '@playwright/test'; +import { expect, type Browser, type TestInfo } from '@playwright/test'; import { EventEmitter } from "events"; import { type Mail, MailServer } from 'maildev'; import { execSync } from 'node:child_process'; @@ -32,19 +32,6 @@ export function loadEnv(){ } } -export function closeMails(mailServer: MailServer, mailIterators: AsyncIterator[]) { - if( mailServer ) { - mailServer.close(); - } - if( mailIterators ) { - for (const mails of mailIterators) { - if(mails){ - mails.return(); - } - } - } -} - export async function waitFor(url: String, browser: Browser) { var ready = false; var context; @@ -217,3 +204,9 @@ export async function restartVaultwarden(page: Page, testInfo: TestInfo, env, re stopVaultwarden(); return startVaultwarden(page.context().browser(), 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); +} diff --git a/playwright/package-lock.json b/playwright/package-lock.json index 9225899d..3e5d313c 100644 --- a/playwright/package-lock.json +++ b/playwright/package-lock.json @@ -17,7 +17,130 @@ "@playwright/test": "^1.49.1", "dotenv": "^16.4.7", "dotenv-expand": "^11.0.7", - "maildev": "github:timshel/maildev#3.0.2" + "maildev": "github:timshel/maildev#3.0.4" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz", + "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==", + "dev": true, + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", + "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", + "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" } }, "node_modules/@noble/hashes": { @@ -32,12 +155,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", - "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", + "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", "dev": true, "dependencies": { - "playwright": "1.49.1" + "playwright": "1.50.1" }, "bin": { "playwright": "cli.js" @@ -65,12 +188,6 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, "node_modules/@types/cors": { "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", @@ -91,9 +208,9 @@ } }, "node_modules/@types/node": { - "version": "22.10.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", - "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", + "version": "22.13.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", + "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", "dev": true, "dependencies": { "undici-types": "~6.20.0" @@ -295,9 +412,9 @@ } }, "node_modules/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -362,17 +479,24 @@ } }, "node_modules/cssstyle": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", - "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz", + "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==", "dev": true, "dependencies": { - "rrweb-cssom": "^0.7.1" + "@asamuzakjp/css-color": "^2.8.2", + "rrweb-cssom": "^0.8.0" }, "engines": { "node": ">=18" } }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -396,9 +520,9 @@ } }, "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "dev": true }, "node_modules/deepmerge": { @@ -488,9 +612,9 @@ } }, "node_modules/dompurify": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz", - "integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", "dev": true, "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -576,12 +700,11 @@ } }, "node_modules/engine.io": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz", - "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", "dev": true, "dependencies": { - "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", @@ -689,9 +812,9 @@ } }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "dependencies": { "es-errors": "^1.3.0" @@ -1185,17 +1308,15 @@ } }, "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.0.tgz", + "integrity": "sha512-5vvY5yF1zF/kXk+L94FRiTDa1Znom46UjPCH6/XbSvS8zBKMFBHTJk8KDMqJ+2J6QezQFi7k1k8v21ClJYHPaw==" }, "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "engines": { - "node": ">=12" - } + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true }, "node_modules/lru.min": { "version": "1.1.1", @@ -1212,8 +1333,8 @@ } }, "node_modules/maildev": { - "version": "3.0.2", - "resolved": "git+ssh://git@github.com/timshel/maildev.git#b76b02f184a2b56115ccdf477e81d6532c763994", + "version": "3.0.4", + "resolved": "git+ssh://git@github.com/timshel/maildev.git#ac9aa31d50b1849a73248eaa679a5702e9d10f21", "dev": true, "license": "MIT", "dependencies": { @@ -1258,6 +1379,15 @@ "tlds": "1.255.0" } }, + "node_modules/mailparser/node_modules/nodemailer": { + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", + "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/mailsplit": { "version": "5.4.2", "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz", @@ -1383,6 +1513,14 @@ "node": ">=12.0.0" } }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, "node_modules/negotiator": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", @@ -1393,9 +1531,9 @@ } }, "node_modules/nodemailer": { - "version": "6.9.16", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", - "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz", + "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -1417,9 +1555,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "engines": { "node": ">= 0.4" @@ -1510,13 +1648,13 @@ } }, "node_modules/pg": { - "version": "8.13.1", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", - "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", + "version": "8.13.2", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.2.tgz", + "integrity": "sha512-L5QkPvTjVWWHbLaFjCkOSplpb2uCiRYbg0IJ2okCy5ClYfWlSgDDnvdR6dyw3EWAH2AfS4j8E61QFI7gLfTtlw==", "dependencies": { "pg-connection-string": "^2.7.0", - "pg-pool": "^3.7.0", - "pg-protocol": "^1.7.0", + "pg-pool": "^3.7.1", + "pg-protocol": "^1.7.1", "pg-types": "^2.1.0", "pgpass": "1.x" }, @@ -1555,17 +1693,17 @@ } }, "node_modules/pg-pool": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", - "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.1.tgz", + "integrity": "sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==", "peerDependencies": { "pg": ">=8.0" } }, "node_modules/pg-protocol": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", - "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==" + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz", + "integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==" }, "node_modules/pg-types": { "version": "2.2.0", @@ -1591,12 +1729,12 @@ } }, "node_modules/playwright": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", - "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", + "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", "dev": true, "dependencies": { - "playwright-core": "1.49.1" + "playwright-core": "1.50.1" }, "bin": { "playwright": "cli.js" @@ -1609,9 +1747,9 @@ } }, "node_modules/playwright-core": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", - "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", + "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -2298,9 +2436,9 @@ } }, "node_modules/whatwg-url": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", - "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz", + "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==", "dev": true, "dependencies": { "tr46": "^5.0.0", diff --git a/playwright/package.json b/playwright/package.json index 7bf09059..e3e7c7e8 100644 --- a/playwright/package.json +++ b/playwright/package.json @@ -11,7 +11,7 @@ "@playwright/test": "^1.49.1", "dotenv": "^16.4.7", "dotenv-expand": "^11.0.7", - "maildev": "github:timshel/maildev#3.0.2" + "maildev": "github:timshel/maildev#3.0.4" }, "dependencies": { "mysql2": "^3.12.0", diff --git a/playwright/tests/collection.spec.ts b/playwright/tests/collection.spec.ts new file mode 100644 index 00000000..ef67e738 --- /dev/null +++ b/playwright/tests/collection.spec.ts @@ -0,0 +1,38 @@ +import { test, expect, type TestInfo } from '@playwright/test'; + +import * as utils from "../global-utils"; +import { createAccount, logUser } from './setups/user'; + +let users = utils.loadEnv(); + +test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { + await utils.startVaultwarden(browser, testInfo); +}); + +test.afterAll('Teardown', async ({}) => { + utils.stopVaultwarden(); +}); + +test('Create', async ({ page }) => { + await createAccount(test, page, users.user1); + await logUser(test, page, users.user1); + + await test.step('Create Org', async () => { + await page.getByRole('link', { name: 'New organisation' }).click(); + await page.getByLabel('Organisation name (required)').fill('Test'); + await page.getByRole('button', { name: 'Submit' }).click(); + await page.locator('div').filter({ hasText: 'Members' }).nth(2).click(); + + await utils.checkNotification(page, 'Organisation created'); + }); + + await test.step('Create Collection', async () => { + await page.getByRole('link', { name: 'Collections' }).click(); + await page.getByRole('button', { name: 'New' }).click(); + await page.getByRole('menuitem', { name: 'Collection' }).click(); + await page.getByLabel('Name (required)').fill('RandomCollec'); + await page.getByRole('button', { name: 'Save' }).click(); + await utils.checkNotification(page, 'Created collection RandomCollec'); + await expect(page.getByRole('button', { name: 'RandomCollec' })).toBeVisible(); + }); +}); diff --git a/playwright/tests/login.smtp.spec.ts b/playwright/tests/login.smtp.spec.ts index 8401b7c2..6261fd89 100644 --- a/playwright/tests/login.smtp.spec.ts +++ b/playwright/tests/login.smtp.spec.ts @@ -30,57 +30,24 @@ test.afterAll('Teardown', async ({}) => { }); test('Account creation', async ({ page }) => { - const emails = mailserver.iterator(users.user1.email); - - await createAccount(test, page, users.user1); - - const { value: created } = await emails.next(); - expect(created.subject).toBe("Welcome"); - expect(created.from[0]?.address).toBe(process.env.VAULTWARDEN_SMTP_FROM); - - // Back to the login page - await expect(page).toHaveTitle('Vaultwarden Web'); - await expect(page.getByTestId("toast-message")).toHaveText(/Your new account has been created/); - await page.getByRole('button', { name: 'Continue' }).click(); - - // Unlock page - await page.getByLabel('Master password').fill(users.user1.password); - await page.getByRole('button', { name: 'Log in with master password' }).click(); - - // We are now in the default vault page - await expect(page).toHaveTitle(/Vaultwarden Web/); - - const { value: logged } = await emails.next(); - expect(logged.subject).toBe("New Device Logged In From Firefox"); - expect(logged.to[0]?.address).toBe(process.env.TEST_USER_MAIL); - expect(logged.from[0]?.address).toBe(process.env.VAULTWARDEN_SMTP_FROM); - - emails.return(); + const mailBuffer = mailserver.buffer(users.user1.email); + await createAccount(test, page, users.user1, mailBuffer); + mailBuffer.close(); }); test('Login', async ({ context, page }) => { - const emails = mailserver.iterator(users.user1.email); + const mailBuffer = mailserver.buffer(users.user1.email); - await logUser(test, page, users.user1); - - await test.step('new device email', async () => { - const { value: logged } = await emails.next(); - expect(logged.subject).toBe("New Device Logged In From Firefox"); - expect(logged.from[0]?.address).toBe(process.env.VAULTWARDEN_SMTP_FROM); - }); + await logUser(test, page, users.user1, mailBuffer); await test.step('verify email', async () => { await page.getByText('Verify your account\'s email').click(); await expect(page.getByText('Verify your account\'s email')).toBeVisible(); await page.getByRole('button', { name: 'Send email' }).click(); - // Close the toast message - await expect(page.getByTestId("toast-message")).toHaveText(/Check your email inbox/); - await page.locator('#toast-container').getByRole('button').click(); - await expect(page.getByTestId("toast-message")).toHaveCount(0); + await utils.checkNotification(page, 'Check your email inbox for a verification link'); - const { value: verify } = await emails.next(); - expect(verify.subject).toBe("Verify Your Email"); + const verify = await mailBuffer.next((m) => m.subject === "Verify Your Email"); expect(verify.from[0]?.address).toBe(process.env.VAULTWARDEN_SMTP_FROM); const page2 = await context.newPage(); @@ -89,10 +56,10 @@ test('Login', async ({ context, page }) => { await page2.close(); await page.goto(link); - await expect(page.getByTestId("toast-message")).toHaveText("Account email verified"); + await utils.checkNotification(page, 'Account email verified'); }); - emails.return(); + mailBuffer.close(); }); test('Activaite 2fa', async ({ context, page }) => { @@ -156,7 +123,7 @@ test('2fa', async ({ context, page }) => { await page.getByRole('button', { name: 'Continue' }).click(); await page.getByRole('button', { name: 'Turn off' }).click(); await page.getByRole('button', { name: 'Yes' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText(/Two-step login provider turned off/); + await utils.checkNotification(page, 'Two-step login provider turned off'); }); emails.close(); diff --git a/playwright/tests/login.spec.ts b/playwright/tests/login.spec.ts index 69309e2e..b21ab537 100644 --- a/playwright/tests/login.spec.ts +++ b/playwright/tests/login.spec.ts @@ -89,6 +89,6 @@ test('Authenticator 2fa', async ({ context, page }) => { await page.getByRole('button', { name: 'Continue' }).click(); await page.getByRole('button', { name: 'Turn off' }).click(); await page.getByRole('button', { name: 'Yes' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText(/Two-step login provider turned off/); + await utils.checkNotification(page, 'Two-step login provider turned off'); }); }); diff --git a/playwright/tests/organization.smtp.spec.ts b/playwright/tests/organization.smtp.spec.ts index 6d5788c4..f2e8c757 100644 --- a/playwright/tests/organization.smtp.spec.ts +++ b/playwright/tests/organization.smtp.spec.ts @@ -1,83 +1,59 @@ import { test, expect, type TestInfo } from '@playwright/test'; import { MailDev } from 'maildev'; -import * as utils from "../global-utils"; +import * as utils from '../global-utils'; +import * as orgs from './setups/orgs'; import { createAccount, logUser } from './setups/user'; let users = utils.loadEnv(); -let mailserver, user1Mails, user2Mails, user3Mails; +let mailServer, mail1Buffer, mail2Buffer, mail3Buffer; test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { - mailserver = new MailDev({ + mailServer = new MailDev({ port: process.env.MAILDEV_SMTP_PORT, web: { port: process.env.MAILDEV_HTTP_PORT }, }) - await mailserver.listen(); + await mailServer.listen(); await utils.startVaultwarden(browser, testInfo, { SMTP_HOST: process.env.MAILDEV_HOST, SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM, }); - user1Mails = mailserver.iterator(users.user1.email); - user2Mails = mailserver.iterator(users.user2.email); - user3Mails = mailserver.iterator(users.user3.email); + mail1Buffer = mailServer.buffer(users.user1.email); + mail2Buffer = mailServer.buffer(users.user2.email); + mail3Buffer = mailServer.buffer(users.user3.email); }); test.afterAll('Teardown', async ({}, testInfo: TestInfo) => { utils.stopVaultwarden(testInfo); - utils.closeMails(mailserver, [user1Mails, user2Mails, user3Mails]); + [mail1Buffer, mail2Buffer, mail3Buffer, mailServer].map((m) => m?.close()); }); test('Create user3', async ({ page }) => { - await createAccount(test, page, users.user3, user3Mails); + await createAccount(test, page, users.user3, mail3Buffer); }); test('Invite users', async ({ page }) => { - await createAccount(test, page, users.user1, user1Mails); - await logUser(test, page, users.user1, user1Mails); + await createAccount(test, page, users.user1, mail1Buffer); + await logUser(test, page, users.user1, mail1Buffer); - await test.step('Create Org', async () => { - await page.getByRole('link', { name: 'New organisation' }).click(); - await page.getByLabel('Organisation name (required)').fill('Test'); - await page.getByRole('button', { name: 'Submit' }).click(); - await page.locator('div').filter({ hasText: 'Members' }).nth(2).click(); - }); - - await test.step('Invite user2', async () => { - await page.getByRole('button', { name: 'Invite member' }).click(); - await page.getByLabel('Email (required)').fill(users.user2.email); - await page.getByRole('tab', { name: 'Collections' }).click(); - await page.getByLabel('Permission').selectOption('edit'); - await page.getByLabel('Select collections').click(); - await page.getByLabel('Options list').getByText('Default collection').click(); - await page.getByRole('button', { name: 'Save' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); - await page.locator('#toast-container').getByRole('button').click(); - }); - - await test.step('Invite user3', async () => { - await page.getByRole('button', { name: 'Invite member' }).click(); - await page.getByLabel('Email (required)').fill(users.user3.email); - await page.getByRole('tab', { name: 'Collections' }).click(); - await page.getByLabel('Permission').selectOption('edit'); - await page.getByLabel('Select collections').click(); - await page.getByLabel('Options list').getByText('Default collection').click(); - await page.getByRole('button', { name: 'Save' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); - await page.locator('#toast-container').getByRole('button').click(); + await orgs.create(test, page, 'Test'); + await orgs.members(test, page, 'Test'); + await orgs.invite(test, page, 'Test', users.user2.email); + await orgs.invite(test, page, 'Test', users.user3.email, { + navigate: false, }); }); test('invited with new account', async ({ page }) => { - const { value: invited } = await user2Mails.next(); - expect(invited.subject).toContain("Join Test") + const invited = await mail2Buffer.next((mail) => mail.subject === 'Join Test'); await test.step('Create account', async () => { await page.setContent(invited.html); - const link = await page.getByTestId("invite").getAttribute("href"); + const link = await page.getByTestId('invite').getAttribute('href'); await page.goto(link); await expect(page).toHaveTitle(/Create account | Vaultwarden Web/); @@ -87,12 +63,7 @@ test('invited with new account', async ({ page }) => { await page.getByRole('button', { name: 'Create account' }).click(); // Back to the login page - await expect(page).toHaveTitle('Vaultwarden Web'); - await expect(page.getByTestId("toast-message")).toHaveText(/Your new account has been created/); - await page.locator('#toast-container').getByRole('button').click(); - - const { value: welcome } = await user2Mails.next(); - expect(welcome.subject).toContain("Welcome") + await utils.checkNotification(page, 'Your new account has been created'); }); await test.step('Login', async () => { @@ -105,23 +76,21 @@ test('invited with new account', async ({ page }) => { // We are now in the default vault page await expect(page).toHaveTitle(/Vaultwarden Web/); - await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); - await page.locator('#toast-container').getByRole('button').click(); - - const { value: logged } = await user2Mails.next(); - expect(logged.subject).toContain("New Device Logged"); + await utils.checkNotification(page, 'Invitation accepted'); }); - const { value: accepted } = await user1Mails.next(); - expect(accepted.subject).toContain("Invitation to Test accepted") + await test.step('Check mails', async () => { + await expect(mail2Buffer.next((m) => m.subject === 'Welcome')).resolves.toBeDefined(); + await expect(mail2Buffer.next((m) => m.subject === 'New Device Logged In From Firefox')).resolves.toBeDefined(); + await expect(mail1Buffer.next((m) => m.subject.includes('Invitation to Test accepted'))).resolves.toBeDefined(); + }); }); test('invited with existing account', async ({ page }) => { - const { value: invited } = await user3Mails.next(); - expect(invited.subject).toContain("Join Test") + const invited = await mail3Buffer.next((mail) => mail.subject === 'Join Test'); await page.setContent(invited.html); - const link = await page.getByTestId("invite").getAttribute("href"); + const link = await page.getByTestId('invite').getAttribute('href'); await page.goto(link); @@ -135,36 +104,23 @@ test('invited with existing account', async ({ page }) => { // We are now in the default vault page await expect(page).toHaveTitle(/Vaultwarden Web/); - await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'Invitation accepted'); - const { value: logged } = await user3Mails.next(); - expect(logged.subject).toContain("New Device Logged") - - const { value: accepted } = await user1Mails.next(); - expect(accepted.subject).toContain("Invitation to Test accepted") + await expect(mail3Buffer.next((m) => m.subject === 'New Device Logged In From Firefox')).resolves.toBeDefined(); + await expect(mail1Buffer.next((m) => m.subject.includes('Invitation to Test accepted'))).resolves.toBeDefined(); }); test('Confirm invited user', async ({ page }) => { - await logUser(test, page, users.user1, user1Mails); - await page.getByLabel('Switch products').click(); - await page.getByRole('link', { name: ' Admin Console' }).click(); - await page.getByRole('link', { name: 'Members' }).click(); + await logUser(test, page, users.user1, mail1Buffer); - await test.step('Accept user2', async () => { - await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); - await page.getByRole('menuitem', { name: 'Confirm' }).click(); - await page.getByRole('button', { name: 'Confirm' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); - await page.locator('#toast-container').getByRole('button').click(); + await orgs.members(test, page, 'Test'); + await orgs.confirm(test, page, 'Test', users.user2.name); - const { value: logged } = await user2Mails.next(); - expect(logged.subject).toContain("Invitation to Test confirmed"); - }); + await expect(mail2Buffer.next((m) => m.subject.includes('Invitation to Test confirmed'))).resolves.toBeDefined(); }); test('Organization is visible', async ({ page }) => { - await logUser(test, page, users.user2, user2Mails); + await logUser(test, page, users.user2, mail2Buffer); await page.getByLabel('vault: Test').click(); await expect(page.getByLabel('Filter: Default collection')).toBeVisible(); }); diff --git a/playwright/tests/organization.spec.ts b/playwright/tests/organization.spec.ts index 0b051760..0267549b 100644 --- a/playwright/tests/organization.spec.ts +++ b/playwright/tests/organization.spec.ts @@ -37,8 +37,7 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Select collections').click(); await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'User(s) invited'); await expect(page.getByRole('row', { name: users.user2.email })).toHaveText(/Invited/); }); @@ -50,8 +49,7 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Select collections').click(); await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'User(s) invited'); await expect(page.getByRole('row', { name: users.user3.name })).toHaveText(/Needs confirmation/); }); @@ -59,8 +57,7 @@ test('Invite users', async ({ page }) => { await page.getByRole('row', { name: users.user3.name }).getByLabel('Options').click(); await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'confirmed'); }); }); @@ -78,7 +75,7 @@ test('Confirm invited user', async ({ page }) => { await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); + await utils.checkNotification(page, 'confirmed'); }); }); diff --git a/playwright/tests/setups/orgs.ts b/playwright/tests/setups/orgs.ts new file mode 100644 index 00000000..a0f5299b --- /dev/null +++ b/playwright/tests/setups/orgs.ts @@ -0,0 +1,62 @@ +import { expect, type Browser,Page } from '@playwright/test'; + +import * as utils from '../../global-utils'; + +export async function create(test, page: Page, name: string) { + await test.step('Create Org', async () => { + await page.locator('a').filter({ hasText: 'Password Manager' }).first().click(); + await expect(page.getByTitle('All vaults', { exact: true })).toBeVisible(); + await page.getByRole('link', { name: 'New organisation' }).click(); + await page.getByLabel('Organisation name (required)').fill(name); + await page.getByRole('button', { name: 'Submit' }).click(); + + await utils.checkNotification(page, 'Organisation created'); + }); +} + +export async function members(test, page: Page, name: string) { + await test.step(`Navigate to ${name}`, async () => { + await page.locator('a').filter({ hasText: 'Admin Console' }).first().click(); + await page.locator('org-switcher').getByLabel(/Toggle collapse/).click(); + await page.locator('org-switcher').getByRole('link', { name: `${name}` }).first().click(); + await expect(page.getByRole('heading', { name: `${name} collections` })).toBeVisible(); + await page.locator('div').filter({ hasText: 'Members' }).nth(2).click(); + await expect(page.getByRole('heading', { name: 'Members' })).toBeVisible(); + }); +} + +export async function invite(test, page: Page, name: string, email: string) { + await test.step(`Invite ${email}`, async () => { + await expect(page.getByRole('heading', { name: 'Members' })).toBeVisible(); + await page.getByRole('button', { name: 'Invite member' }).click(); + await page.getByLabel('Email (required)').fill(email); + await page.getByRole('tab', { name: 'Collections' }).click(); + await page.getByLabel('Permission').selectOption('edit'); + await page.getByLabel('Select collections').click(); + await page.getByLabel('Options list').getByText('Default collection').click(); + await page.getByRole('button', { name: 'Save' }).click(); + await utils.checkNotification(page, 'User(s) invited'); + }); +} + +export async function confirm(test, page: Page, name: string, user_name: string) { + await test.step(`Confirm ${user_name}`, async () => { + await expect(page.getByRole('heading', { name: 'Members' })).toBeVisible(); + await page.getByRole('row', { name: user_name }).getByLabel('Options').click(); + await page.getByRole('menuitem', { name: 'Confirm' }).click(); + await expect(page.getByRole('heading', { name: 'Confirm user' })).toBeVisible(); + await page.getByRole('button', { name: 'Confirm' }).click(); + await utils.checkNotification(page, 'confirmed'); + }); +} + +export async function revoke(test, page: Page, name: string, user_name: string) { + await test.step(`Revoke ${user_name}`, async () => { + await expect(page.getByRole('heading', { name: 'Members' })).toBeVisible(); + await page.getByRole('row', { name: user_name }).getByLabel('Options').click(); + await page.getByRole('menuitem', { name: 'Revoke access' }).click(); + await expect(page.getByRole('heading', { name: 'Revoke access' })).toBeVisible(); + await page.getByRole('button', { name: 'Revoke access' }).click(); + await utils.checkNotification(page, 'Revoked organisation access'); + }); +} diff --git a/playwright/tests/setups/sso.ts b/playwright/tests/setups/sso.ts index dc176b0e..8b0b43ff 100644 --- a/playwright/tests/setups/sso.ts +++ b/playwright/tests/setups/sso.ts @@ -1,6 +1,8 @@ import { expect, type Page, Test } from '@playwright/test'; import { type MailBuffer, MailServer } from 'maildev'; +import * as utils from '../../global-utils'; + /** * If a MailBuffer is passed it will be used and consume the expected emails */ @@ -44,8 +46,8 @@ export async function logNewUser( if( mailBuffer ){ await test.step('Check emails', async () => { + await expect(mailBuffer.next((m) => m.subject === "Welcome")).resolves.toBeDefined(); await expect(mailBuffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined(); - await expect(mailBuffer.next((m) => m.subject === "Master Password Has Been Changed")).resolves.toBeDefined(); }); } }); diff --git a/playwright/tests/setups/user.ts b/playwright/tests/setups/user.ts index b91dc133..db8db86a 100644 --- a/playwright/tests/setups/user.ts +++ b/playwright/tests/setups/user.ts @@ -1,6 +1,9 @@ import { expect, type Browser,Page } from '@playwright/test'; +import { type MailBuffer } from 'maildev'; -export async function createAccount(test, page: Page, user: { email: string, name: string, password: string }, emails) { +import * as utils from '../../global-utils'; + +export async function createAccount(test, page: Page, user: { email: string, name: string, password: string }, mailBuffer?: MailBuffer) { await test.step('Create user', async () => { // Landing page await page.goto('/'); @@ -16,16 +19,15 @@ export async function createAccount(test, page: Page, user: { email: string, nam // Back to the login page await expect(page).toHaveTitle('Vaultwarden Web'); - await expect(page.getByTestId("toast-message")).toHaveText(/Your new account has been created/); + await utils.checkNotification(page, 'Your new account has been created'); - if( emails ){ - const { value: welcome } = await emails.next(); - expect(welcome.subject).toContain("Welcome"); + if( mailBuffer ){ + await expect(mailBuffer.next((m) => m.subject === "Welcome")).resolves.toBeDefined(); } }); } -export async function logUser(test, page: Page, user: { email: string, password: string }, emails) { +export async function logUser(test, page: Page, user: { email: string, password: string }, mailBuffer?: MailBuffer) { await test.step('Log user', async () => { // Landing page await page.goto('/'); @@ -39,9 +41,8 @@ export async function logUser(test, page: Page, user: { email: string, password: // We are now in the default vault page await expect(page).toHaveTitle(/Vaultwarden Web/); - if( emails ){ - const { value: logged } = await emails.next(); - expect(logged.subject).toContain("New Device Logged"); + if( mailBuffer ){ + await expect(mailBuffer.next((m) => m.subject === 'New Device Logged In From Firefox')).resolves.toBeDefined(); } }); } diff --git a/playwright/tests/sso_organization.smtp.spec.ts b/playwright/tests/sso_organization.smtp.spec.ts index e64d6d67..c3586fc4 100644 --- a/playwright/tests/sso_organization.smtp.spec.ts +++ b/playwright/tests/sso_organization.smtp.spec.ts @@ -30,7 +30,7 @@ test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { test.afterAll('Teardown', async ({}) => { utils.stopVaultwarden(); - [mailServer, mail1Buffer, mail2Buffer, mail3Buffer].map((m) => m?.close()); + [mail1Buffer, mail2Buffer, mail3Buffer, mailServer].map((m) => m?.close()); }); test('Create user3', async ({ page }) => { @@ -55,8 +55,7 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Select collections').click(); await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'User(s) invited'); }); await test.step('Invite user3', async () => { @@ -67,12 +66,11 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Select collections').click(); await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'User(s) invited'); }); }); -test.fail('invited with new account', async ({ page }) => { +test('invited with new account', async ({ page }) => { const link = await test.step('Extract email link', async () => { const invited = await mail2Buffer.next((m) => m.subject === "Join Test"); await page.setContent(invited.html); @@ -99,8 +97,7 @@ test.fail('invited with new account', async ({ page }) => { await test.step('Default vault page', async () => { await expect(page).toHaveTitle(/Vaultwarden Web/); - await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); - await page.locator('#toast-container').getByRole('button').click(); + // await utils.checkNotification(page, 'Invitation accepted'); }); await test.step('Check mails', async () => { @@ -135,8 +132,7 @@ test('invited with existing account', async ({ page }) => { await test.step('Default vault page', async () => { await expect(page).toHaveTitle(/Vaultwarden Web/); - await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'Invitation accepted'); }); await test.step('Check mails', async () => { diff --git a/playwright/tests/sso_organization.spec.ts b/playwright/tests/sso_organization.spec.ts index f9e73c0d..360369af 100644 --- a/playwright/tests/sso_organization.spec.ts +++ b/playwright/tests/sso_organization.spec.ts @@ -39,8 +39,7 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Select collections').click(); await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'User(s) invited'); await expect(page.getByRole('row', { name: users.user2.email })).toHaveText(/Invited/); }); @@ -52,8 +51,7 @@ test('Invite users', async ({ page }) => { await page.getByLabel('Select collections').click(); await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByRole('button', { name: 'Save' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'User(s) invited'); await expect(page.getByRole('row', { name: users.user3.name })).toHaveText(/Needs confirmation/); }); @@ -61,8 +59,7 @@ test('Invite users', async ({ page }) => { await page.getByRole('row', { name: users.user3.name }).getByLabel('Options').click(); await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'confirmed'); }); }); @@ -82,8 +79,7 @@ test('Confirm invited user', async ({ page }) => { await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click(); - await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); - await page.locator('#toast-container').getByRole('button').click(); + await utils.checkNotification(page, 'confirmed'); }); });