test(phase-02): add Nyquist validation tests for plan 06 gaps
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
da526cb727
commit
0505beb0a4
@@ -0,0 +1,81 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
|
||||
// Must mock before importing router (which imports useAuthStore)
|
||||
vi.mock('../../stores/auth.js', () => ({
|
||||
useAuthStore: vi.fn(),
|
||||
}))
|
||||
|
||||
// Mock all lazily-imported view components so the router can be instantiated
|
||||
vi.mock('../../views/auth/LoginView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/auth/RegisterView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/auth/PasswordResetView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/auth/NewPasswordView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/AdminView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/SharedView.vue', () => ({ default: { template: '<div />' } }))
|
||||
|
||||
// Heavy view components imported statically — stub them too
|
||||
vi.mock('../../views/FileManagerView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/TopicsView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/DocumentView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/SettingsView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/CloudFolderView.vue', () => ({ default: { template: '<div />' } }))
|
||||
vi.mock('../../views/CloudStorageView.vue', () => ({ default: { template: '<div />' } }))
|
||||
|
||||
import { useAuthStore } from '../../stores/auth.js'
|
||||
import router from '../index.js'
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('router — auth route meta (SEC-07, AUTH-01)', () => {
|
||||
const authPaths = ['/login', '/register', '/password-reset', '/password-reset/confirm']
|
||||
|
||||
it.each(authPaths)(
|
||||
'route %s has meta.public = true so guard skips auth check',
|
||||
(path) => {
|
||||
const route = router.getRoutes().find(r => r.path === path)
|
||||
expect(route, `route "${path}" should exist`).toBeDefined()
|
||||
expect(route.meta.public).toBe(true)
|
||||
}
|
||||
)
|
||||
|
||||
it.each(authPaths)(
|
||||
'route %s has meta.layout = "auth" so sidebar is never rendered',
|
||||
(path) => {
|
||||
const route = router.getRoutes().find(r => r.path === path)
|
||||
expect(route, `route "${path}" should exist`).toBeDefined()
|
||||
expect(route.meta.layout).toBe('auth')
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe('router — admin guard (SEC-07)', () => {
|
||||
it('redirects a non-admin user away from /admin to /', async () => {
|
||||
// Arrange: authenticated but role = 'viewer'
|
||||
useAuthStore.mockReturnValue({
|
||||
accessToken: 'fake-token',
|
||||
user: { id: '1', role: 'viewer' },
|
||||
refresh: vi.fn().mockResolvedValue(undefined),
|
||||
})
|
||||
|
||||
// Act: attempt to navigate to /admin
|
||||
const result = await router.push('/admin')
|
||||
// The guard returns { path: '/' }, so the router resolves to '/'
|
||||
expect(router.currentRoute.value.path).toBe('/')
|
||||
})
|
||||
|
||||
it('allows an admin user to reach /admin', async () => {
|
||||
// Arrange: authenticated as admin
|
||||
useAuthStore.mockReturnValue({
|
||||
accessToken: 'fake-token',
|
||||
user: { id: '1', role: 'admin' },
|
||||
refresh: vi.fn().mockResolvedValue(undefined),
|
||||
})
|
||||
|
||||
await router.push('/admin')
|
||||
expect(router.currentRoute.value.path).toBe('/admin')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user