1
0
Fork 1
Spiegel von https://github.com/dani-garcia/vaultwarden.git synchronisiert 2025-03-12 16:47:03 +01:00
Dieser Commit ist enthalten in:
Timshel 2025-02-11 19:47:05 +01:00
Ursprung 7649ce8a3c
Commit edef0ca80d
14 geänderte Dateien mit 393 neuen und 247 gelöschten Zeilen

Datei anzeigen

@ -89,7 +89,7 @@ services:
Maildev: Maildev:
profiles: ["vaultwarden", "maildev"] profiles: ["vaultwarden", "maildev"]
container_name: maildev container_name: maildev
image: timshel/maildev image: timshel/maildev:3.0.4
ports: ports:
- ${SMTP_PORT}:1025 - ${SMTP_PORT}:1025
- 1080:1080 - 1080:1080

Datei anzeigen

@ -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 { EventEmitter } from "events";
import { type Mail, MailServer } from 'maildev'; import { type Mail, MailServer } from 'maildev';
import { execSync } from 'node:child_process'; import { execSync } from 'node:child_process';
@ -32,19 +32,6 @@ export function loadEnv(){
} }
} }
export function closeMails(mailServer: MailServer, mailIterators: AsyncIterator<Mail>[]) {
if( mailServer ) {
mailServer.close();
}
if( mailIterators ) {
for (const mails of mailIterators) {
if(mails){
mails.return();
}
}
}
}
export async function waitFor(url: String, browser: Browser) { export async function waitFor(url: String, browser: Browser) {
var ready = false; var ready = false;
var context; var context;
@ -217,3 +204,9 @@ export async function restartVaultwarden(page: Page, testInfo: TestInfo, env, re
stopVaultwarden(); stopVaultwarden();
return startVaultwarden(page.context().browser(), testInfo, env, resetDB); 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);
}

Datei anzeigen

@ -17,7 +17,130 @@
"@playwright/test": "^1.49.1", "@playwright/test": "^1.49.1",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"dotenv-expand": "^11.0.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": { "node_modules/@noble/hashes": {
@ -32,12 +155,12 @@
} }
}, },
"node_modules/@playwright/test": { "node_modules/@playwright/test": {
"version": "1.49.1", "version": "1.50.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz",
"integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"playwright": "1.49.1" "playwright": "1.50.1"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -65,12 +188,6 @@
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"dev": true "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": { "node_modules/@types/cors": {
"version": "2.8.17", "version": "2.8.17",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
@ -91,9 +208,9 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.10.5", "version": "22.13.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz",
"integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"undici-types": "~6.20.0" "undici-types": "~6.20.0"
@ -295,9 +412,9 @@
} }
}, },
"node_modules/compression": { "node_modules/compression": {
"version": "1.7.5", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz",
"integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
@ -362,17 +479,24 @@
} }
}, },
"node_modules/cssstyle": { "node_modules/cssstyle": {
"version": "4.1.0", "version": "4.2.1",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz",
"integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"rrweb-cssom": "^0.7.1" "@asamuzakjp/css-color": "^2.8.2",
"rrweb-cssom": "^0.8.0"
}, },
"engines": { "engines": {
"node": ">=18" "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": { "node_modules/data-urls": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
@ -396,9 +520,9 @@
} }
}, },
"node_modules/decimal.js": { "node_modules/decimal.js": {
"version": "10.4.3", "version": "10.5.0",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz",
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==",
"dev": true "dev": true
}, },
"node_modules/deepmerge": { "node_modules/deepmerge": {
@ -488,9 +612,9 @@
} }
}, },
"node_modules/dompurify": { "node_modules/dompurify": {
"version": "3.2.3", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz",
"integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==", "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==",
"dev": true, "dev": true,
"optionalDependencies": { "optionalDependencies": {
"@types/trusted-types": "^2.0.7" "@types/trusted-types": "^2.0.7"
@ -576,12 +700,11 @@
} }
}, },
"node_modules/engine.io": { "node_modules/engine.io": {
"version": "6.6.2", "version": "6.6.4",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
"integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==", "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/node": ">=10.0.0", "@types/node": ">=10.0.0",
"accepts": "~1.3.4", "accepts": "~1.3.4",
@ -689,9 +812,9 @@
} }
}, },
"node_modules/es-object-atoms": { "node_modules/es-object-atoms": {
"version": "1.0.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"es-errors": "^1.3.0" "es-errors": "^1.3.0"
@ -1185,17 +1308,15 @@
} }
}, },
"node_modules/long": { "node_modules/long": {
"version": "5.2.3", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", "resolved": "https://registry.npmjs.org/long/-/long-5.3.0.tgz",
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" "integrity": "sha512-5vvY5yF1zF/kXk+L94FRiTDa1Znom46UjPCH6/XbSvS8zBKMFBHTJk8KDMqJ+2J6QezQFi7k1k8v21ClJYHPaw=="
}, },
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "7.18.3", "version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"engines": { "dev": true
"node": ">=12"
}
}, },
"node_modules/lru.min": { "node_modules/lru.min": {
"version": "1.1.1", "version": "1.1.1",
@ -1212,8 +1333,8 @@
} }
}, },
"node_modules/maildev": { "node_modules/maildev": {
"version": "3.0.2", "version": "3.0.4",
"resolved": "git+ssh://git@github.com/timshel/maildev.git#b76b02f184a2b56115ccdf477e81d6532c763994", "resolved": "git+ssh://git@github.com/timshel/maildev.git#ac9aa31d50b1849a73248eaa679a5702e9d10f21",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1258,6 +1379,15 @@
"tlds": "1.255.0" "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": { "node_modules/mailsplit": {
"version": "5.4.2", "version": "5.4.2",
"resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz", "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz",
@ -1383,6 +1513,14 @@
"node": ">=12.0.0" "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": { "node_modules/negotiator": {
"version": "0.6.4", "version": "0.6.4",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
@ -1393,9 +1531,9 @@
} }
}, },
"node_modules/nodemailer": { "node_modules/nodemailer": {
"version": "6.9.16", "version": "6.10.0",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz",
"integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
@ -1417,9 +1555,9 @@
} }
}, },
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.3", "version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@ -1510,13 +1648,13 @@
} }
}, },
"node_modules/pg": { "node_modules/pg": {
"version": "8.13.1", "version": "8.13.2",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.2.tgz",
"integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", "integrity": "sha512-L5QkPvTjVWWHbLaFjCkOSplpb2uCiRYbg0IJ2okCy5ClYfWlSgDDnvdR6dyw3EWAH2AfS4j8E61QFI7gLfTtlw==",
"dependencies": { "dependencies": {
"pg-connection-string": "^2.7.0", "pg-connection-string": "^2.7.0",
"pg-pool": "^3.7.0", "pg-pool": "^3.7.1",
"pg-protocol": "^1.7.0", "pg-protocol": "^1.7.1",
"pg-types": "^2.1.0", "pg-types": "^2.1.0",
"pgpass": "1.x" "pgpass": "1.x"
}, },
@ -1555,17 +1693,17 @@
} }
}, },
"node_modules/pg-pool": { "node_modules/pg-pool": {
"version": "3.7.0", "version": "3.7.1",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.1.tgz",
"integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", "integrity": "sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==",
"peerDependencies": { "peerDependencies": {
"pg": ">=8.0" "pg": ">=8.0"
} }
}, },
"node_modules/pg-protocol": { "node_modules/pg-protocol": {
"version": "1.7.0", "version": "1.7.1",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz",
"integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==" "integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ=="
}, },
"node_modules/pg-types": { "node_modules/pg-types": {
"version": "2.2.0", "version": "2.2.0",
@ -1591,12 +1729,12 @@
} }
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.49.1", "version": "1.50.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz",
"integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"playwright-core": "1.49.1" "playwright-core": "1.50.1"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -1609,9 +1747,9 @@
} }
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.49.1", "version": "1.50.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz",
"integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==",
"dev": true, "dev": true,
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"
@ -2298,9 +2436,9 @@
} }
}, },
"node_modules/whatwg-url": { "node_modules/whatwg-url": {
"version": "14.1.0", "version": "14.1.1",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz",
"integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"tr46": "^5.0.0", "tr46": "^5.0.0",

Datei anzeigen

@ -11,7 +11,7 @@
"@playwright/test": "^1.49.1", "@playwright/test": "^1.49.1",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"dotenv-expand": "^11.0.7", "dotenv-expand": "^11.0.7",
"maildev": "github:timshel/maildev#3.0.2" "maildev": "github:timshel/maildev#3.0.4"
}, },
"dependencies": { "dependencies": {
"mysql2": "^3.12.0", "mysql2": "^3.12.0",

Datei anzeigen

@ -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();
});
});

Datei anzeigen

@ -30,57 +30,24 @@ test.afterAll('Teardown', async ({}) => {
}); });
test('Account creation', async ({ page }) => { test('Account creation', async ({ page }) => {
const emails = mailserver.iterator(users.user1.email); const mailBuffer = mailserver.buffer(users.user1.email);
await createAccount(test, page, users.user1, mailBuffer);
await createAccount(test, page, users.user1); mailBuffer.close();
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();
}); });
test('Login', async ({ context, page }) => { 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 logUser(test, page, users.user1, mailBuffer);
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 test.step('verify email', async () => { await test.step('verify email', async () => {
await page.getByText('Verify your account\'s email').click(); await page.getByText('Verify your account\'s email').click();
await expect(page.getByText('Verify your account\'s email')).toBeVisible(); await expect(page.getByText('Verify your account\'s email')).toBeVisible();
await page.getByRole('button', { name: 'Send email' }).click(); await page.getByRole('button', { name: 'Send email' }).click();
// Close the toast message await utils.checkNotification(page, 'Check your email inbox for a verification link');
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);
const { value: verify } = await emails.next(); const verify = await mailBuffer.next((m) => m.subject === "Verify Your Email");
expect(verify.subject).toBe("Verify Your Email");
expect(verify.from[0]?.address).toBe(process.env.VAULTWARDEN_SMTP_FROM); expect(verify.from[0]?.address).toBe(process.env.VAULTWARDEN_SMTP_FROM);
const page2 = await context.newPage(); const page2 = await context.newPage();
@ -89,10 +56,10 @@ test('Login', async ({ context, page }) => {
await page2.close(); await page2.close();
await page.goto(link); 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 }) => { 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: 'Continue' }).click();
await page.getByRole('button', { name: 'Turn off' }).click(); await page.getByRole('button', { name: 'Turn off' }).click();
await page.getByRole('button', { name: 'Yes' }).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(); emails.close();

Datei anzeigen

@ -89,6 +89,6 @@ test('Authenticator 2fa', async ({ context, page }) => {
await page.getByRole('button', { name: 'Continue' }).click(); await page.getByRole('button', { name: 'Continue' }).click();
await page.getByRole('button', { name: 'Turn off' }).click(); await page.getByRole('button', { name: 'Turn off' }).click();
await page.getByRole('button', { name: 'Yes' }).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');
}); });
}); });

Datei anzeigen

@ -1,83 +1,59 @@
import { test, expect, type TestInfo } from '@playwright/test'; import { test, expect, type TestInfo } from '@playwright/test';
import { MailDev } from 'maildev'; 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'; import { createAccount, logUser } from './setups/user';
let users = utils.loadEnv(); let users = utils.loadEnv();
let mailserver, user1Mails, user2Mails, user3Mails; let mailServer, mail1Buffer, mail2Buffer, mail3Buffer;
test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
mailserver = new MailDev({ mailServer = new MailDev({
port: process.env.MAILDEV_SMTP_PORT, port: process.env.MAILDEV_SMTP_PORT,
web: { port: process.env.MAILDEV_HTTP_PORT }, web: { port: process.env.MAILDEV_HTTP_PORT },
}) })
await mailserver.listen(); await mailServer.listen();
await utils.startVaultwarden(browser, testInfo, { await utils.startVaultwarden(browser, testInfo, {
SMTP_HOST: process.env.MAILDEV_HOST, SMTP_HOST: process.env.MAILDEV_HOST,
SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM, SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM,
}); });
user1Mails = mailserver.iterator(users.user1.email); mail1Buffer = mailServer.buffer(users.user1.email);
user2Mails = mailserver.iterator(users.user2.email); mail2Buffer = mailServer.buffer(users.user2.email);
user3Mails = mailserver.iterator(users.user3.email); mail3Buffer = mailServer.buffer(users.user3.email);
}); });
test.afterAll('Teardown', async ({}, testInfo: TestInfo) => { test.afterAll('Teardown', async ({}, testInfo: TestInfo) => {
utils.stopVaultwarden(testInfo); utils.stopVaultwarden(testInfo);
utils.closeMails(mailserver, [user1Mails, user2Mails, user3Mails]); [mail1Buffer, mail2Buffer, mail3Buffer, mailServer].map((m) => m?.close());
}); });
test('Create user3', async ({ page }) => { test('Create user3', async ({ page }) => {
await createAccount(test, page, users.user3, user3Mails); await createAccount(test, page, users.user3, mail3Buffer);
}); });
test('Invite users', async ({ page }) => { test('Invite users', async ({ page }) => {
await createAccount(test, page, users.user1, user1Mails); await createAccount(test, page, users.user1, mail1Buffer);
await logUser(test, page, users.user1, user1Mails); await logUser(test, page, users.user1, mail1Buffer);
await test.step('Create Org', async () => { await orgs.create(test, page, 'Test');
await page.getByRole('link', { name: 'New organisation' }).click(); await orgs.members(test, page, 'Test');
await page.getByLabel('Organisation name (required)').fill('Test'); await orgs.invite(test, page, 'Test', users.user2.email);
await page.getByRole('button', { name: 'Submit' }).click(); await orgs.invite(test, page, 'Test', users.user3.email, {
await page.locator('div').filter({ hasText: 'Members' }).nth(2).click(); navigate: false,
});
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();
}); });
}); });
test('invited with new account', async ({ page }) => { test('invited with new account', async ({ page }) => {
const { value: invited } = await user2Mails.next(); const invited = await mail2Buffer.next((mail) => mail.subject === 'Join Test');
expect(invited.subject).toContain("Join Test")
await test.step('Create account', async () => { await test.step('Create account', async () => {
await page.setContent(invited.html); 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 page.goto(link);
await expect(page).toHaveTitle(/Create account | Vaultwarden Web/); 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(); await page.getByRole('button', { name: 'Create account' }).click();
// Back to the login page // Back to the login page
await expect(page).toHaveTitle('Vaultwarden Web'); await utils.checkNotification(page, 'Your new account has been created');
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 test.step('Login', async () => { await test.step('Login', async () => {
@ -105,23 +76,21 @@ test('invited with new account', async ({ page }) => {
// We are now in the default vault page // We are now in the default vault page
await expect(page).toHaveTitle(/Vaultwarden Web/); await expect(page).toHaveTitle(/Vaultwarden Web/);
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); await utils.checkNotification(page, 'Invitation accepted');
await page.locator('#toast-container').getByRole('button').click();
const { value: logged } = await user2Mails.next();
expect(logged.subject).toContain("New Device Logged");
}); });
const { value: accepted } = await user1Mails.next(); await test.step('Check mails', async () => {
expect(accepted.subject).toContain("Invitation to Test accepted") 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 }) => { test('invited with existing account', async ({ page }) => {
const { value: invited } = await user3Mails.next(); const invited = await mail3Buffer.next((mail) => mail.subject === 'Join Test');
expect(invited.subject).toContain("Join Test")
await page.setContent(invited.html); 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 page.goto(link);
@ -135,36 +104,23 @@ test('invited with existing account', async ({ page }) => {
// We are now in the default vault page // We are now in the default vault page
await expect(page).toHaveTitle(/Vaultwarden Web/); await expect(page).toHaveTitle(/Vaultwarden Web/);
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); await utils.checkNotification(page, 'Invitation accepted');
await page.locator('#toast-container').getByRole('button').click();
const { value: logged } = await user3Mails.next(); await expect(mail3Buffer.next((m) => m.subject === 'New Device Logged In From Firefox')).resolves.toBeDefined();
expect(logged.subject).toContain("New Device Logged") await expect(mail1Buffer.next((m) => m.subject.includes('Invitation to Test accepted'))).resolves.toBeDefined();
const { value: accepted } = await user1Mails.next();
expect(accepted.subject).toContain("Invitation to Test accepted")
}); });
test('Confirm invited user', async ({ page }) => { test('Confirm invited user', async ({ page }) => {
await logUser(test, page, users.user1, user1Mails); await logUser(test, page, users.user1, mail1Buffer);
await page.getByLabel('Switch products').click();
await page.getByRole('link', { name: ' Admin Console' }).click();
await page.getByRole('link', { name: 'Members' }).click();
await test.step('Accept user2', async () => { await orgs.members(test, page, 'Test');
await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); await orgs.confirm(test, page, 'Test', users.user2.name);
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();
const { value: logged } = await user2Mails.next(); await expect(mail2Buffer.next((m) => m.subject.includes('Invitation to Test confirmed'))).resolves.toBeDefined();
expect(logged.subject).toContain("Invitation to Test confirmed");
});
}); });
test('Organization is visible', async ({ page }) => { 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 page.getByLabel('vault: Test').click();
await expect(page.getByLabel('Filter: Default collection')).toBeVisible(); await expect(page.getByLabel('Filter: Default collection')).toBeVisible();
}); });

Datei anzeigen

@ -37,8 +37,7 @@ test('Invite users', async ({ page }) => {
await page.getByLabel('Select collections').click(); await page.getByLabel('Select collections').click();
await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByLabel('Options list').getByText('Default collection').click();
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); await utils.checkNotification(page, 'User(s) invited');
await page.locator('#toast-container').getByRole('button').click();
await expect(page.getByRole('row', { name: users.user2.email })).toHaveText(/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('Select collections').click();
await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByLabel('Options list').getByText('Default collection').click();
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); await utils.checkNotification(page, 'User(s) invited');
await page.locator('#toast-container').getByRole('button').click();
await expect(page.getByRole('row', { name: users.user3.name })).toHaveText(/Needs confirmation/); 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('row', { name: users.user3.name }).getByLabel('Options').click();
await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('menuitem', { name: 'Confirm' }).click();
await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); await utils.checkNotification(page, 'confirmed');
await page.locator('#toast-container').getByRole('button').click();
}); });
}); });
@ -78,7 +75,7 @@ test('Confirm invited user', async ({ page }) => {
await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click();
await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('menuitem', { name: 'Confirm' }).click();
await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); await utils.checkNotification(page, 'confirmed');
}); });
}); });

Datei anzeigen

@ -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');
});
}

Datei anzeigen

@ -1,6 +1,8 @@
import { expect, type Page, Test } from '@playwright/test'; import { expect, type Page, Test } from '@playwright/test';
import { type MailBuffer, MailServer } from 'maildev'; 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 * If a MailBuffer is passed it will be used and consume the expected emails
*/ */
@ -44,8 +46,8 @@ export async function logNewUser(
if( mailBuffer ){ if( mailBuffer ){
await test.step('Check emails', async () => { 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.includes("New Device Logged"))).resolves.toBeDefined();
await expect(mailBuffer.next((m) => m.subject === "Master Password Has Been Changed")).resolves.toBeDefined();
}); });
} }
}); });

Datei anzeigen

@ -1,6 +1,9 @@
import { expect, type Browser,Page } from '@playwright/test'; 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 () => { await test.step('Create user', async () => {
// Landing page // Landing page
await page.goto('/'); await page.goto('/');
@ -16,16 +19,15 @@ export async function createAccount(test, page: Page, user: { email: string, nam
// Back to the login page // Back to the login page
await expect(page).toHaveTitle('Vaultwarden Web'); 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 ){ if( mailBuffer ){
const { value: welcome } = await emails.next(); await expect(mailBuffer.next((m) => m.subject === "Welcome")).resolves.toBeDefined();
expect(welcome.subject).toContain("Welcome");
} }
}); });
} }
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 () => { await test.step('Log user', async () => {
// Landing page // Landing page
await page.goto('/'); 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 // We are now in the default vault page
await expect(page).toHaveTitle(/Vaultwarden Web/); await expect(page).toHaveTitle(/Vaultwarden Web/);
if( emails ){ if( mailBuffer ){
const { value: logged } = await emails.next(); await expect(mailBuffer.next((m) => m.subject === 'New Device Logged In From Firefox')).resolves.toBeDefined();
expect(logged.subject).toContain("New Device Logged");
} }
}); });
} }

Datei anzeigen

@ -30,7 +30,7 @@ test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
test.afterAll('Teardown', async ({}) => { test.afterAll('Teardown', async ({}) => {
utils.stopVaultwarden(); utils.stopVaultwarden();
[mailServer, mail1Buffer, mail2Buffer, mail3Buffer].map((m) => m?.close()); [mail1Buffer, mail2Buffer, mail3Buffer, mailServer].map((m) => m?.close());
}); });
test('Create user3', async ({ page }) => { test('Create user3', async ({ page }) => {
@ -55,8 +55,7 @@ test('Invite users', async ({ page }) => {
await page.getByLabel('Select collections').click(); await page.getByLabel('Select collections').click();
await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByLabel('Options list').getByText('Default collection').click();
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); await utils.checkNotification(page, 'User(s) invited');
await page.locator('#toast-container').getByRole('button').click();
}); });
await test.step('Invite user3', async () => { await test.step('Invite user3', async () => {
@ -67,12 +66,11 @@ test('Invite users', async ({ page }) => {
await page.getByLabel('Select collections').click(); await page.getByLabel('Select collections').click();
await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByLabel('Options list').getByText('Default collection').click();
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); await utils.checkNotification(page, 'User(s) invited');
await page.locator('#toast-container').getByRole('button').click();
}); });
}); });
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 link = await test.step('Extract email link', async () => {
const invited = await mail2Buffer.next((m) => m.subject === "Join Test"); const invited = await mail2Buffer.next((m) => m.subject === "Join Test");
await page.setContent(invited.html); 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 test.step('Default vault page', async () => {
await expect(page).toHaveTitle(/Vaultwarden Web/); await expect(page).toHaveTitle(/Vaultwarden Web/);
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); // await utils.checkNotification(page, 'Invitation accepted');
await page.locator('#toast-container').getByRole('button').click();
}); });
await test.step('Check mails', async () => { 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 test.step('Default vault page', async () => {
await expect(page).toHaveTitle(/Vaultwarden Web/); await expect(page).toHaveTitle(/Vaultwarden Web/);
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted"); await utils.checkNotification(page, 'Invitation accepted');
await page.locator('#toast-container').getByRole('button').click();
}); });
await test.step('Check mails', async () => { await test.step('Check mails', async () => {

Datei anzeigen

@ -39,8 +39,7 @@ test('Invite users', async ({ page }) => {
await page.getByLabel('Select collections').click(); await page.getByLabel('Select collections').click();
await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByLabel('Options list').getByText('Default collection').click();
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); await utils.checkNotification(page, 'User(s) invited');
await page.locator('#toast-container').getByRole('button').click();
await expect(page.getByRole('row', { name: users.user2.email })).toHaveText(/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('Select collections').click();
await page.getByLabel('Options list').getByText('Default collection').click(); await page.getByLabel('Options list').getByText('Default collection').click();
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited'); await utils.checkNotification(page, 'User(s) invited');
await page.locator('#toast-container').getByRole('button').click();
await expect(page.getByRole('row', { name: users.user3.name })).toHaveText(/Needs confirmation/); 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('row', { name: users.user3.name }).getByLabel('Options').click();
await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('menuitem', { name: 'Confirm' }).click();
await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); await utils.checkNotification(page, 'confirmed');
await page.locator('#toast-container').getByRole('button').click();
}); });
}); });
@ -82,8 +79,7 @@ test('Confirm invited user', async ({ page }) => {
await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click(); await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click();
await page.getByRole('menuitem', { name: 'Confirm' }).click(); await page.getByRole('menuitem', { name: 'Confirm' }).click();
await page.getByRole('button', { name: 'Confirm' }).click(); await page.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/); await utils.checkNotification(page, 'confirmed');
await page.locator('#toast-container').getByRole('button').click();
}); });
}); });