From 7f547068214d5c84c59615f7959e0219043adecb Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Wed, 7 Jan 2026 10:50:26 +0400 Subject: [PATCH] E2E: add user smoke tests - Disable captcha + open registrations in E2E Pleroma config - Await login after signup to avoid redirect race - Add basic register/login/post smoke specs - Fix failure artifact copying order --- docker/pleroma/entrypoint.e2e.sh | 14 ++++ src/modules/users.js | 2 +- test/e2e-playwright/specs/user_smoke.spec.js | 80 ++++++++++++++++++++ tools/e2e/run.sh | 4 +- 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 test/e2e-playwright/specs/user_smoke.spec.js diff --git a/docker/pleroma/entrypoint.e2e.sh b/docker/pleroma/entrypoint.e2e.sh index 6945cf5b6..96920eeae 100644 --- a/docker/pleroma/entrypoint.e2e.sh +++ b/docker/pleroma/entrypoint.e2e.sh @@ -3,12 +3,26 @@ set -eu SEED_SENTINEL_PATH="/var/lib/pleroma/.e2e_seeded" +CONFIG_OVERRIDE_PATH="/var/lib/pleroma/config.exs" echo "-- Waiting for database..." while ! pg_isready -U "${DB_USER:-pleroma}" -d "postgres://${DB_HOST:-db}:${DB_PORT:-5432}/${DB_NAME:-pleroma}" -t 1; do sleep 1s done +echo "-- Writing E2E config overrides..." +cat > "$CONFIG_OVERRIDE_PATH" <<'EOF' +import Config + +config :pleroma, Pleroma.Captcha, + enabled: false + +config :pleroma, :instance, + registrations_open: true, + account_activation_required: false, + approval_required: false +EOF + echo "-- Running migrations..." /opt/pleroma/bin/pleroma_ctl migrate diff --git a/src/modules/users.js b/src/modules/users.js index 5563a280e..e9b56362d 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -551,7 +551,7 @@ const users = { if (data.access_token) { store.commit('signUpSuccess') oauthStore.setToken(data.access_token) - store.dispatch('loginUser', data.access_token) + await store.dispatch('loginUser', data.access_token) return 'ok' } else { // Request succeeded, but user cannot login yet. store.commit('signUpNotice', data) diff --git a/test/e2e-playwright/specs/user_smoke.spec.js b/test/e2e-playwright/specs/user_smoke.spec.js new file mode 100644 index 000000000..080a20d1a --- /dev/null +++ b/test/e2e-playwright/specs/user_smoke.spec.js @@ -0,0 +1,80 @@ +import { randomUUID } from 'node:crypto' +import { test, expect } from 'playwright/test' + +const createTestUser = () => { + const id = randomUUID().slice(0, 8) + return { + username: `e2e_${id}`, + fullname: `E2E ${id}`, + email: `e2e_${id}@example.com`, + password: 'e2e-password' + } +} + +const register = async (page, user) => { + await page.goto('/registration') + + const registrationForm = page.locator('#main-scroller form.registration-form') + await registrationForm.locator('#sign-up-username').fill(user.username) + await registrationForm.locator('#sign-up-fullname').fill(user.fullname) + await registrationForm.locator('#email').fill(user.email) + await registrationForm.locator('#sign-up-password').fill(user.password) + await registrationForm.locator('#sign-up-password-confirmation').fill(user.password) + await Promise.all([ + page.waitForURL(/\/main\/friends/), + registrationForm.getByRole('button', { name: 'Register' }).click() + ]) +} + +const logout = async (page) => { + await page.getByTitle('Log out').click() + const confirmLogout = page.getByRole('button', { name: 'Logout', exact: true }) + if (await confirmLogout.isVisible()) { + await Promise.all([ + page.waitForURL(/\/main\/(public|all)/), + confirmLogout.click() + ]) + } else { + await page.waitForURL(/\/main\/(public|all)/) + } + + await expect(page.locator('#sidebar form.login-form')).toBeVisible() +} + +const login = async (page, user) => { + await page.goto('/login') + + const loginForm = page.locator('#main-scroller form.login-form') + await loginForm.locator('#username').fill(user.username) + await loginForm.locator('#password').fill(user.password) + await loginForm.getByRole('button', { name: 'Log in' }).click() + + await page.waitForURL(/\/main\/friends/) +} + +test('user can register, log out, and log back in', async ({ page }) => { + const user = createTestUser() + await register(page, user) + await expect(page.getByTitle('Log out')).toBeVisible() + + await logout(page) + + await login(page, user) + await expect(page.getByTitle('Log out')).toBeVisible() +}) + +test('user can post a status', async ({ page }) => { + const user = createTestUser() + await register(page, user) + + const statusText = `Hello from ${user.username} (${randomUUID().slice(0, 8)})` + const composer = page.locator('#sidebar .user-panel .post-status-form') + await composer.locator('textarea.form-post-body').fill(statusText) + await Promise.all([ + page.waitForResponse((resp) => resp.request().method() === 'POST' && resp.url().includes('/api/v1/statuses') && resp.ok()), + composer.getByRole('button', { name: 'Post', exact: true }).click() + ]) + + await page.goto(`/users/${user.username}`) + await expect(page.getByText(statusText)).toBeVisible() +}) diff --git a/tools/e2e/run.sh b/tools/e2e/run.sh index 5ff2637ce..3c0ba8a36 100644 --- a/tools/e2e/run.sh +++ b/tools/e2e/run.sh @@ -24,10 +24,10 @@ result="$?" set -e if [ "$result" -ne 0 ]; then + docker compose -f "$COMPOSE_FILE" cp e2e:/app/test/e2e-playwright/test-results test/e2e-playwright >/dev/null 2>&1 || true + docker compose -f "$COMPOSE_FILE" cp e2e:/app/test/e2e-playwright/playwright-report test/e2e-playwright >/dev/null 2>&1 || true mkdir -p test/e2e-playwright/test-results docker compose -f "$COMPOSE_FILE" logs --no-color pleroma db > test/e2e-playwright/test-results/docker-compose.log 2>/dev/null || true - docker compose -f "$COMPOSE_FILE" cp e2e:/app/test/e2e-playwright/test-results test/e2e-playwright/test-results >/dev/null 2>&1 || true - docker compose -f "$COMPOSE_FILE" cp e2e:/app/test/e2e-playwright/playwright-report test/e2e-playwright/playwright-report >/dev/null 2>&1 || true fi cleanup