Fix Playwright docker (#6206)

This commit is contained in:
Timshel
2025-08-25 17:59:55 +02:00
committed by GitHub
parent 1f73630136
commit de808c5ad9
8 changed files with 34 additions and 41 deletions

View File

@@ -91,17 +91,25 @@ When creating new scenario use the recorder to more easily identify elements
This does not start the server, you will need to start it manually. This does not start the server, you will need to start it manually.
```bash ```bash
npx playwright codegen "http://127.0.0.1:8000" DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env up Vaultwarden
npx playwright codegen "http://127.0.0.1:8003"
``` ```
## Override web-vault ## Override web-vault
It is possible to change the `web-vault` used by referencing a different `bw_web_builds` commit. It is possible to change the `web-vault` used by referencing a different `bw_web_builds` commit.
Simplest is to set and uncomment `PW_WV_REPO_URL` and `PW_WV_COMMIT_HASH` in the `test.env`.
Ensure that the image is built with:
```bash ```bash
export PW_WV_REPO_URL=https://github.com/Timshel/oidc_web_builds.git DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env build Vaultwarden
export PW_WV_COMMIT_HASH=8707dc76df3f0cceef2be5bfae37bb29bd17fae6 ```
DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env build Playwright
You can check the result running:
```bash
DOCKER_BUILDKIT=1 docker compose --profile playwright --env-file test.env up Vaultwarden
``` ```
# OpenID Connect test setup # OpenID Connect test setup

View File

@@ -1,6 +1,6 @@
FROM playwright_oidc_vaultwarden_prebuilt AS prebuilt FROM playwright_oidc_vaultwarden_prebuilt AS prebuilt
FROM node:22-bookworm AS build FROM node:22-trixie AS build
ARG REPO_URL ARG REPO_URL
ARG COMMIT_HASH ARG COMMIT_HASH
@@ -14,7 +14,7 @@ COPY build.sh /build.sh
RUN /build.sh RUN /build.sh
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
FROM docker.io/library/debian:bookworm-slim FROM docker.io/library/debian:trixie-slim
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
@@ -24,7 +24,7 @@ RUN mkdir /data && \
--no-install-recommends \ --no-install-recommends \
ca-certificates \ ca-certificates \
curl \ curl \
libmariadb-dev-compat \ libmariadb-dev \
libpq5 \ libpq5 \
openssl && \ openssl && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*

View File

@@ -16,7 +16,6 @@ if [[ ! -z "$REPO_URL" ]] && [[ ! -z "$COMMIT_HASH" ]] ; then
export VAULT_VERSION=$(cat Dockerfile | grep "ARG VAULT_VERSION" | cut -d "=" -f2) export VAULT_VERSION=$(cat Dockerfile | grep "ARG VAULT_VERSION" | cut -d "=" -f2)
./scripts/checkout_web_vault.sh ./scripts/checkout_web_vault.sh
./scripts/patch_web_vault.sh
./scripts/build_web_vault.sh ./scripts/build_web_vault.sh
printf '{"version":"%s"}' "$COMMIT_HASH" > ./web-vault/apps/web/build/vw-version.json printf '{"version":"%s"}' "$COMMIT_HASH" > ./web-vault/apps/web/build/vw-version.json

View File

@@ -26,9 +26,9 @@ export default defineConfig({
* But short action/nav/expect timeouts to fail on specific step (raise locally if not enough). * But short action/nav/expect timeouts to fail on specific step (raise locally if not enough).
*/ */
timeout: 120 * 1000, timeout: 120 * 1000,
actionTimeout: 10 * 1000, actionTimeout: 20 * 1000,
navigationTimeout: 10 * 1000, navigationTimeout: 20 * 1000,
expect: { timeout: 10 * 1000 }, expect: { timeout: 20 * 1000 },
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: { use: {

View File

@@ -66,6 +66,10 @@ SSO_CLIENT_SECRET=warden
SSO_AUTHORITY=http://${KC_HTTP_HOST}:${KC_HTTP_PORT}/realms/${TEST_REALM} SSO_AUTHORITY=http://${KC_HTTP_HOST}:${KC_HTTP_PORT}/realms/${TEST_REALM}
SSO_DEBUG_TOKENS=true SSO_DEBUG_TOKENS=true
# Custom web-vault build
# PW_WV_REPO_URL=https://github.com/dani-garcia/bw_web_builds.git
# PW_WV_COMMIT_HASH=a5f5390895516bce2f48b7baadb6dc399e5fe75a
########################### ###########################
# Docker MariaDb container# # Docker MariaDb container#
########################### ###########################

View File

@@ -12,7 +12,7 @@ export async function logNewUser(
test: Test, test: Test,
page: Page, page: Page,
user: { email: string, name: string, password: string }, user: { email: string, name: string, password: string },
options: { mailBuffer?: MailBuffer, override?: boolean } = {} options: { mailBuffer?: MailBuffer } = {}
) { ) {
await test.step(`Create user ${user.name}`, async () => { await test.step(`Create user ${user.name}`, async () => {
await page.context().clearCookies(); await page.context().clearCookies();
@@ -20,12 +20,8 @@ export async function logNewUser(
await test.step('Landing page', async () => { await test.step('Landing page', async () => {
await utils.cleanLanding(page); await utils.cleanLanding(page);
if( options.override ) { await page.locator("input[type=email].vw-email-sso").fill(user.email);
await page.getByRole('button', { name: 'Continue' }).click();
} else {
await page.getByLabel(/Email address/).fill(user.email);
await page.getByRole('button', { name: /Use single sign-on/ }).click(); await page.getByRole('button', { name: /Use single sign-on/ }).click();
}
}); });
await test.step('Keycloak login', async () => { await test.step('Keycloak login', async () => {
@@ -69,7 +65,6 @@ export async function logUser(
user: { email: string, password: string }, user: { email: string, password: string },
options: { options: {
mailBuffer ?: MailBuffer, mailBuffer ?: MailBuffer,
override?: boolean,
totp?: OTPAuth.TOTP, totp?: OTPAuth.TOTP,
mail2fa?: boolean, mail2fa?: boolean,
} = {} } = {}
@@ -82,12 +77,8 @@ export async function logUser(
await test.step('Landing page', async () => { await test.step('Landing page', async () => {
await utils.cleanLanding(page); await utils.cleanLanding(page);
if( options.override ) { await page.locator("input[type=email].vw-email-sso").fill(user.email);
await page.getByRole('button', { name: 'Continue' }).click();
} else {
await page.getByLabel(/Email address/).fill(user.email);
await page.getByRole('button', { name: /Use single sign-on/ }).click(); await page.getByRole('button', { name: /Use single sign-on/ }).click();
}
}); });
await test.step('Keycloak login', async () => { await test.step('Keycloak login', async () => {

View File

@@ -29,8 +29,8 @@ test('SSO login', async ({ page }) => {
test('Non SSO login', async ({ page }) => { test('Non SSO login', async ({ page }) => {
// Landing page // Landing page
await page.goto('/'); await page.goto('/');
await page.getByLabel(/Email address/).fill(users.user1.email); await page.locator("input[type=email].vw-email-sso").fill(users.user1.email);
await page.getByRole('button', { name: 'Continue' }).click(); await page.getByRole('button', { name: 'Other' }).click();
// Unlock page // Unlock page
await page.getByLabel('Master password').fill(users.user1.password); await page.getByLabel('Master password').fill(users.user1.password);
@@ -58,20 +58,12 @@ test('Non SSO login impossible', async ({ page, browser }, testInfo: TestInfo) =
// Landing page // Landing page
await page.goto('/'); await page.goto('/');
await page.getByLabel(/Email address/).fill(users.user1.email);
// Check that SSO login is available // Check that SSO login is available
await expect(page.getByRole('button', { name: /Use single sign-on/ })).toHaveCount(1); await expect(page.getByRole('button', { name: /Use single sign-on/ })).toHaveCount(1);
await page.getByLabel(/Email address/).fill(users.user1.email); // No Continue/Other
await page.getByRole('button', { name: 'Continue' }).click(); await expect(page.getByRole('button', { name: 'Other' })).toHaveCount(0);
// Unlock page
await page.getByLabel('Master password').fill(users.user1.password);
await page.getByRole('button', { name: 'Log in with master password' }).click();
// An error should appear
await page.getByLabel('SSO sign-in is required')
}); });
@@ -82,13 +74,12 @@ test('No SSO login', async ({ page }, testInfo: TestInfo) => {
// Landing page // Landing page
await page.goto('/'); await page.goto('/');
await page.getByLabel(/Email address/).fill(users.user1.email);
// No SSO button (rely on a correct selector checked in previous test) // No SSO button (rely on a correct selector checked in previous test)
await page.getByLabel('Master password');
await expect(page.getByRole('button', { name: /Use single sign-on/ })).toHaveCount(0); await expect(page.getByRole('button', { name: /Use single sign-on/ })).toHaveCount(0);
// Can continue to Master password // Can continue to Master password
await page.getByLabel(/Email address/).fill(users.user1.email);
await page.getByRole('button', { name: 'Continue' }).click(); await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.getByRole('button', { name: /Log in with master password/ })).toHaveCount(1); await expect(page.getByRole('button', { name: 'Log in with master password' })).toHaveCount(1);
}); });

View File

@@ -65,7 +65,7 @@ test('Enforce password policy', async ({ page }) => {
await utils.logout(test, page, users.user1); await utils.logout(test, page, users.user1);
await test.step(`Unlock trigger policy`, async () => { await test.step(`Unlock trigger policy`, async () => {
await page.getByRole('textbox', { name: 'Email address (required)' }).fill(users.user1.email); await page.locator("input[type=email].vw-email-sso").fill(users.user1.email);
await page.getByRole('button', { name: 'Use single sign-on' }).click(); await page.getByRole('button', { name: 'Use single sign-on' }).click();
await page.getByRole('textbox', { name: 'Master password (required)' }).fill(users.user1.password); await page.getByRole('textbox', { name: 'Master password (required)' }).fill(users.user1.password);