import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest' import { mount } from '@vue/test-utils' import { createRouter, createMemoryHistory } from 'vue-router' import ResetPasswordPage from '@/pages/ResetPasswordPage.vue' function mockFetchResponse(status: number, body: unknown) { return Promise.resolve({ ok: status >= 200 && status < 300, status, json: () => Promise.resolve(body), }) } function createTestRouter() { return createRouter({ history: createMemoryHistory(), routes: [ { path: '/aterstall-losenord', name: 'reset-password', component: ResetPasswordPage, }, { path: '/logga-in', name: 'login', component: { template: '
Login
' }, }, { path: '/glomt-losenord', name: 'forgot-password', component: { template: '
Forgot
' }, }, ], }) } async function mountPage(initialPath: string) { const router = createTestRouter() await router.push(initialPath) await router.isReady() return { router, wrapper: mount(ResetPasswordPage, { global: { plugins: [router] }, }), } } describe('ResetPasswordPage', () => { beforeEach(() => { vi.useFakeTimers() globalThis.fetch = vi.fn() vi.mocked(globalThis.fetch).mockResolvedValue( mockFetchResponse(200, { message: 'Lösenordet har uppdaterats. Du kan nu logga in.', }), ) }) afterEach(() => { vi.useRealTimers() }) it('shows error when token query is missing', async () => { const { wrapper } = await mountPage('/aterstall-losenord') await vi.waitFor(() => { expect(wrapper.text()).toContain( 'Återställningslänken saknar en giltig kod.', ) }) }) it('shows password min length hint', async () => { const { wrapper } = await mountPage('/aterstall-losenord?token=abc') await wrapper.find('#password').setValue('short') expect(wrapper.text()).toContain('Lösenordet måste vara minst 8 tecken') }) it('shows mismatch hint when confirm password differs', async () => { const { wrapper } = await mountPage('/aterstall-losenord?token=abc') await wrapper.find('#password').setValue('password1234') await wrapper.find('#confirmPassword').setValue('different1234') expect(wrapper.text()).toContain('Lösenorden matchar inte') }) it('shows success and navigates to login after reset', async () => { const { wrapper, router } = await mountPage('/aterstall-losenord?token=abc') await wrapper.find('#password').setValue('newpassword123') await wrapper.find('#confirmPassword').setValue('newpassword123') await wrapper.find('form').trigger('submit.prevent') await vi.waitFor(() => { expect(wrapper.text()).toContain( 'Lösenordet har uppdaterats. Du kan nu logga in.', ) }) await vi.advanceTimersByTimeAsync(2000) expect(router.currentRoute.value.path).toBe('/logga-in') }) it('shows invalid token message from backend', async () => { vi.mocked(globalThis.fetch).mockResolvedValue( mockFetchResponse(400, { message: 'Återställningslänken är ogiltig eller har gått ut', }), ) const { wrapper } = await mountPage('/aterstall-losenord?token=bad') await wrapper.find('#password').setValue('newpassword123') await wrapper.find('#confirmPassword').setValue('newpassword123') await wrapper.find('form').trigger('submit.prevent') await vi.waitFor(() => { expect(wrapper.text()).toContain( 'Återställningslänken är ogiltig eller har gått ut', ) expect(wrapper.find('a[href="/glomt-losenord"]').text()).toContain( 'Begär ny länk', ) }) }) })