Aligns seeded and test login addresses with production branding while keeping admin@bilhalsning.se for local docker admin seed only. - Change test@bilhalsning.se to test@bilhej.se in dev migration and all tests
220 lines
6.4 KiB
TypeScript
220 lines
6.4 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { setActivePinia, createPinia } from 'pinia'
|
|
import { useAuthStore } from '@/stores/authStore'
|
|
|
|
function mockFetchResponse(status: number, body: unknown) {
|
|
return Promise.resolve({
|
|
ok: status >= 200 && status < 300,
|
|
status,
|
|
json: () => Promise.resolve(body),
|
|
})
|
|
}
|
|
|
|
describe('authStore', () => {
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia())
|
|
localStorage.clear()
|
|
globalThis.fetch = vi.fn()
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(201, { token: 'test-token' }),
|
|
)
|
|
})
|
|
|
|
it('starts unauthenticated', () => {
|
|
const store = useAuthStore()
|
|
expect(store.isAuthenticated).toBe(false)
|
|
expect(store.token).toBeNull()
|
|
})
|
|
|
|
it('restores token from localStorage', () => {
|
|
localStorage.setItem('auth_token', 'saved-token')
|
|
const store = useAuthStore()
|
|
expect(store.token).toBe('saved-token')
|
|
expect(store.isAuthenticated).toBe(true)
|
|
})
|
|
|
|
it('sets token on registerUser success', async () => {
|
|
const store = useAuthStore()
|
|
|
|
await store.registerUser('test@example.com', 'password123')
|
|
|
|
expect(store.token).toBe('test-token')
|
|
expect(store.isAuthenticated).toBe(true)
|
|
expect(localStorage.getItem('auth_token')).toBe('test-token')
|
|
})
|
|
|
|
it('rejects when register API fails', async () => {
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(409, {
|
|
message: 'E-postadressen är redan registrerad',
|
|
}),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await expect(
|
|
store.registerUser('taken@example.com', 'password123'),
|
|
).rejects.toThrow('E-postadressen är redan registrerad')
|
|
|
|
expect(store.isAuthenticated).toBe(false)
|
|
expect(store.token).toBeNull()
|
|
})
|
|
|
|
it('clears token on logout', () => {
|
|
localStorage.setItem('auth_token', 'some-token')
|
|
const store = useAuthStore()
|
|
|
|
store.logout()
|
|
|
|
expect(store.token).toBeNull()
|
|
expect(store.isAuthenticated).toBe(false)
|
|
expect(localStorage.getItem('auth_token')).toBeNull()
|
|
})
|
|
|
|
it('sets token on loginUser success', async () => {
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(200, { token: 'login-token' }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await store.loginUser('user@example.com', 'password123')
|
|
|
|
expect(store.token).toBe('login-token')
|
|
expect(store.isAuthenticated).toBe(true)
|
|
expect(localStorage.getItem('auth_token')).toBe('login-token')
|
|
})
|
|
|
|
it('rejects when login API fails', async () => {
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(401, { message: 'Felaktig e-post eller lösenord' }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await expect(
|
|
store.loginUser('user@example.com', 'wrongpassword'),
|
|
).rejects.toThrow('Felaktig e-post eller lösenord')
|
|
|
|
expect(store.isAuthenticated).toBe(false)
|
|
expect(store.token).toBeNull()
|
|
})
|
|
|
|
it('calls login endpoint with correct credentials', async () => {
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(200, { token: 'login-token' }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await store.loginUser('user@example.com', 'password123')
|
|
|
|
expect(globalThis.fetch).toHaveBeenCalledWith(
|
|
'/api/auth/login',
|
|
expect.objectContaining({
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
email: 'user@example.com',
|
|
password: 'password123',
|
|
}),
|
|
}),
|
|
)
|
|
})
|
|
|
|
it('does not call register endpoint on login', async () => {
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(200, { token: 'login-token' }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await store.loginUser('user@example.com', 'password123')
|
|
|
|
const calls = vi.mocked(globalThis.fetch).mock.calls
|
|
const registerCall = calls.find((call) => call[0] === '/api/auth/register')
|
|
expect(registerCall).toBeUndefined()
|
|
})
|
|
|
|
it('extracts role from JWT token', async () => {
|
|
const jwt = makeJwt({ role: 'admin' })
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(200, { token: jwt }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await store.loginUser('admin@example.com', 'password123')
|
|
|
|
expect(store.role).toBe('admin')
|
|
expect(store.isAdmin).toBe(true)
|
|
})
|
|
|
|
it('defaults to null role for user role', async () => {
|
|
const jwt = makeJwt({ role: 'user' })
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(200, { token: jwt }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await store.loginUser('user@example.com', 'password123')
|
|
|
|
expect(store.role).toBe('user')
|
|
expect(store.isAdmin).toBe(false)
|
|
})
|
|
|
|
it('clears role on logout', async () => {
|
|
const jwt = makeJwt({ role: 'admin' })
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(200, { token: jwt }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await store.loginUser('admin@example.com', 'password123')
|
|
expect(store.isAdmin).toBe(true)
|
|
|
|
store.logout()
|
|
expect(store.role).toBeNull()
|
|
expect(store.isAdmin).toBe(false)
|
|
})
|
|
|
|
it('restores role from localStorage on init', () => {
|
|
const jwt = makeJwt({ role: 'admin' })
|
|
localStorage.setItem('auth_token', jwt)
|
|
const store = useAuthStore()
|
|
|
|
expect(store.role).toBe('admin')
|
|
expect(store.isAdmin).toBe(true)
|
|
})
|
|
|
|
it('extracts email from JWT sub claim', async () => {
|
|
const jwt = makeJwt({ sub: 'test@bilhej.se', role: 'user' })
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(200, { token: jwt }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await store.loginUser('test@bilhej.se', 'test1234')
|
|
|
|
expect(store.email).toBe('test@bilhej.se')
|
|
})
|
|
|
|
it('returns null email when not authenticated', () => {
|
|
const store = useAuthStore()
|
|
expect(store.email).toBeNull()
|
|
})
|
|
|
|
it('clears email on logout', async () => {
|
|
const jwt = makeJwt({ sub: 'test@bilhej.se', role: 'user' })
|
|
vi.mocked(globalThis.fetch).mockResolvedValue(
|
|
mockFetchResponse(200, { token: jwt }),
|
|
)
|
|
const store = useAuthStore()
|
|
|
|
await store.loginUser('test@bilhej.se', 'test1234')
|
|
expect(store.email).toBe('test@bilhej.se')
|
|
|
|
store.logout()
|
|
expect(store.email).toBeNull()
|
|
})
|
|
})
|
|
|
|
function makeJwt(payload: Record<string, unknown>): string {
|
|
const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))
|
|
const body = btoa(JSON.stringify(payload))
|
|
const signature = 'test-sig'
|
|
return `${header}.${body}.${signature}`
|
|
}
|