Skip to content

fix: misc issues #132

Merged
merged 8 commits into from
May 2, 2026
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "frontend-temp",
"name": "nettdetektivene-frontend",
"version": "0.0.0",
"private": true,
"type": "module",
Expand Down
41 changes: 39 additions & 2 deletions src/app/router/__tests__/auth-routing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ describe('authenticated routing', () => {
await router.push('/teacher/classrooms/7/notifications')
await router.isReady()

expect(router.currentRoute.value.name).toBe('classroom-notifications')
expect(router.currentRoute.value.name).toBe(
'teacher-classroom-notifications',
)
expect(router.currentRoute.value.fullPath).toBe(
'/teacher/classrooms/7/notifications',
)
Expand All @@ -159,7 +161,9 @@ describe('authenticated routing', () => {
await router.push('/teacher/classrooms/7/pupils/15/notebook')
await router.isReady()

expect(router.currentRoute.value.name).toBe('classroom-pupil-notebook')
expect(router.currentRoute.value.name).toBe(
'teacher-classroom-pupil-notebook',
)
expect(router.currentRoute.value.fullPath).toBe(
'/teacher/classrooms/7/pupils/15/notebook',
)
Expand All @@ -179,6 +183,39 @@ describe('authenticated routing', () => {
expect(router.currentRoute.value.fullPath).toBe('/pupil/join-classroom')
})

it('does not register duplicate route names', () => {
const pinia = createPinia()
const router = createAppRouter(createMemoryHistory(), pinia)
const routeNames = router
.getRoutes()
.flatMap((route) => (route.name ? [String(route.name)] : []))

expect(new Set(routeNames).size).toBe(routeNames.length)
})

it('does not register teacher classroom management routes under the pupil portal', async () => {
const pinia = createPinia()
const authStore = useAuthStore(pinia)
authStore.status = 'authenticated'
authStore.accessToken = 'access-token'
authStore.user = authenticatedUser('PUPIL', {
pupilProfile: {
displayName: 'Ada',
totalXp: 0,
currentLevel: 1,
currentClassroomId: 101,
hasCompletedOnboarding: true,
membershipStatus: 'ACTIVE',
},
})

const router = createAppRouter(createMemoryHistory(), pinia)
await router.push('/pupil/classrooms/7/tasks/nyhetskvartalet')
await router.isReady()

expect(router.currentRoute.value.name).toBe('not-found')
})

it('waits for session restore before allowing the first protected navigation', async () => {
const pinia = createPinia()
const authStore = useAuthStore(pinia)
Expand Down
94 changes: 94 additions & 0 deletions src/classrooms/__tests__/classrooms.api.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import {
getClassrooms,
getPupilsForClassroom,
} from '@/classrooms/api/classrooms.api'

describe('classrooms.api', () => {
afterEach(() => {
vi.unstubAllGlobals()
})

it('normalizes owned classrooms that use id instead of classroomId', async () => {
const fetchMock = vi.fn().mockResolvedValue({
ok: true,
json: async () => [
{
id: 7,
title: 'Detektivgjengen 6B',
description: '',
pupilCount: 24,
pendingPupilCount: 0,
teacherCount: 2,
taskCount: 5,
},
],
})
vi.stubGlobal('fetch', fetchMock)

await expect(getClassrooms('Bearer token')).resolves.toEqual([
{
classroomId: 7,
title: 'Detektivgjengen 6B',
description: '',
pupilCount: 24,
pendingPupilCount: 0,
teacherCount: 2,
taskCount: 5,
},
])
})

it('returns pupils from the classroom detail endpoint', async () => {
const fetchMock = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
id: 7,
title: 'Detektivgjengen 6B',
description: '',
joinCode: 'ABC123',
status: 'ACTIVE',
ownerTeacherId: 1,
teachers: [],
pupils: [
{
userId: 15,
displayName: 'Ada',
pupilStatus: 'ACTIVE',
currentLevel: 4,
completedStopsCount: 3,
},
],
}),
})
vi.stubGlobal('fetch', fetchMock)

await expect(getPupilsForClassroom('7', 'Bearer token')).resolves.toEqual([
{
userId: 15,
displayName: 'Ada',
pupilStatus: 'ACTIVE',
currentLevel: 4,
completedStopsCount: 3,
},
])
expect(fetchMock).toHaveBeenCalledWith('/api/v1/classrooms/7', {
headers: {
Authorization: 'Bearer token',
},
credentials: 'include',
})
})

it('rejects pupil lookups without an authorization header', async () => {
await expect(getPupilsForClassroom('7', null)).rejects.toThrow(
'Not authenticated',
)
})

it('rejects pupil lookups with invalid classroom ids', async () => {
await expect(
getPupilsForClassroom('classroom-1', 'Bearer token'),
).rejects.toThrow('Invalid classroom id')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -174,5 +174,14 @@ describe('classrooms store', () => {
teacherCount: 1,
},
])

const store = useClassroomsStore()

await store.fetchClassrooms()
await store.fetchClassrooms()

expect(store.classrooms).toHaveLength(1)
expect(store.classrooms[0]!.classroomId).toBe(2)
expect(store.classrooms[0]!.title).toBe('New')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,18 @@ describe('join classroom routing', () => {

expect(router.currentRoute.value.name).toBe('not-found')
})

it('only registers join and pending classroom routes for pupils', () => {
const pinia = createPinia()
const router = createAppRouter(createMemoryHistory(), pinia)
const routeNames = router
.getRoutes()
.flatMap((route) => (route.name ? [String(route.name)] : []))

expect(routeNames).toContain('pupil-join-classroom')
expect(routeNames).toContain('pupil-pending-approval')
expect(routeNames).not.toContain('pupil-classrooms')
expect(routeNames).not.toContain('pupil-classroom-details')
expect(routeNames).not.toContain('classroom-tasks')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,46 @@ describe('teacher classroom navigation', () => {
'/teacher/classrooms/7/moderation',
)
})

it('resolves teacher classroom management routes under the teacher portal', () => {
const pinia = createPinia()
const router = createAppRouter(createMemoryHistory(), pinia)

expect(
router.resolve({
name: 'teacher-classroom-pupils',
params: { classroomId: 7 },
}).fullPath,
).toBe('/teacher/classrooms/7/pupils')
expect(
router.resolve({
name: 'teacher-classroom-tasks',
params: { classroomId: 7, slug: 'nyhetskvartalet' },
}).fullPath,
).toBe('/teacher/classrooms/7/tasks/nyhetskvartalet')
expect(
router.resolve({
name: 'teacher-classroom-notifications',
params: { classroomId: 7 },
}).fullPath,
).toBe('/teacher/classrooms/7/notifications')
expect(
router.resolve({
name: 'teacher-classroom-mystery',
params: { classroomId: 7 },
}).fullPath,
).toBe('/teacher/classrooms/7/mystery')
expect(
router.resolve({
name: 'teacher-classroom-moderation',
params: { classroomId: 7 },
}).fullPath,
).toBe('/teacher/classrooms/7/moderation')
expect(
router.resolve({
name: 'teacher-classroom-pupil-notebook',
params: { classroomId: 7, pupilId: 15 },
}).fullPath,
).toBe('/teacher/classrooms/7/pupils/15/notebook')
})
})
38 changes: 0 additions & 38 deletions src/classrooms/_tests_/classrooms.api.spec.ts

This file was deleted.

Loading