From 4357eb4fac1f0d5662c1700c026fcb01d2f4a49b Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 May 2026 17:30:44 +0200 Subject: [PATCH] test(register): replace 8 setTimeout sleeps with vi.waitFor on reactive state changes Co-Authored-By: Claude Opus 4.7 --- .../src/routes/register/page.svelte.test.ts | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/frontend/src/routes/register/page.svelte.test.ts b/frontend/src/routes/register/page.svelte.test.ts index cb9f9e79..68aec375 100644 --- a/frontend/src/routes/register/page.svelte.test.ts +++ b/frontend/src/routes/register/page.svelte.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, afterEach } from 'vitest'; +import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import RegisterPage from './+page.svelte'; @@ -127,13 +127,10 @@ describe('register page', () => { const toggle = pw.parentElement?.querySelector('button[type="button"]') as HTMLButtonElement; toggle.click(); - - await new Promise((r) => setTimeout(r, 30)); - expect(pw.type).toBe('text'); + await vi.waitFor(() => expect(pw.type).toBe('text')); toggle.click(); - await new Promise((r) => setTimeout(r, 30)); - expect(pw.type).toBe('password'); + await vi.waitFor(() => expect(pw.type).toBe('password')); }); it('toggles passwordConfirm visibility independently from password', async () => { @@ -147,8 +144,7 @@ describe('register page', () => { ) as HTMLButtonElement; toggle.click(); - await new Promise((r) => setTimeout(r, 30)); - expect(confirm.type).toBe('text'); + await vi.waitFor(() => expect(confirm.type).toBe('text')); }); it('shows the password length hint after typing a short password', async () => { @@ -158,7 +154,6 @@ describe('register page', () => { pw.value = 'abc'; pw.dispatchEvent(new Event('input', { bubbles: true })); - await new Promise((r) => setTimeout(r, 30)); await expect.element(page.getByText(/mindestens 8 zeichen/i)).toBeVisible(); }); @@ -169,10 +164,9 @@ describe('register page', () => { pw.value = 'longenoughpw'; pw.dispatchEvent(new Event('input', { bubbles: true })); - await new Promise((r) => setTimeout(r, 30)); - // password OK hint shows up — find a green-700 text near password - const greens = document.querySelectorAll('.text-green-700'); - expect(greens.length).toBeGreaterThan(0); + await vi.waitFor(() => { + expect(document.querySelectorAll('.text-green-700').length).toBeGreaterThan(0); + }); }); it('shows the password mismatch error when confirm differs from password', async () => { @@ -185,9 +179,9 @@ describe('register page', () => { confirm.value = 'differentpw'; confirm.dispatchEvent(new Event('input', { bubbles: true })); - await new Promise((r) => setTimeout(r, 30)); - const reds = document.querySelectorAll('.text-red-600'); - expect(reds.length).toBeGreaterThan(0); + await vi.waitFor(() => { + expect(document.querySelectorAll('.text-red-600').length).toBeGreaterThan(0); + }); }); it('shows the password match success when confirm equals password', async () => { @@ -200,10 +194,10 @@ describe('register page', () => { confirm.value = 'longenoughpw'; confirm.dispatchEvent(new Event('input', { bubbles: true })); - await new Promise((r) => setTimeout(r, 30)); - // At least 2 green-700 elements (pw OK + match OK) - const greens = document.querySelectorAll('.text-green-700'); - expect(greens.length).toBeGreaterThanOrEqual(2); + await vi.waitFor(() => { + // Both "pw OK" and "match OK" hints render with text-green-700. + expect(document.querySelectorAll('.text-green-700').length).toBeGreaterThanOrEqual(2); + }); }); it('renders the form error from the form prop', async () => { @@ -222,7 +216,6 @@ describe('register page', () => { expect(cb.checked).toBe(true); cb.click(); - await new Promise((r) => setTimeout(r, 30)); - expect(cb.checked).toBe(false); + await vi.waitFor(() => expect(cb.checked).toBe(false)); }); });