This commit is contained in:
28
website/tests/unit/api-envelope.test.js
Normal file
28
website/tests/unit/api-envelope.test.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { unwrap } from '../../js/api-envelope.js';
|
||||
|
||||
describe('unwrap', () => {
|
||||
it('unwraps ok:true object data', () => {
|
||||
const r = unwrap({ ok: true, data: { token: 'abc', role: 'admin' } });
|
||||
expect(r.success).toBe(true);
|
||||
expect(r.token).toBe('abc');
|
||||
expect(r.role).toBe('admin');
|
||||
});
|
||||
|
||||
it('unwraps ok:true array data as items', () => {
|
||||
const r = unwrap({ ok: true, data: [{ id: 1 }] });
|
||||
expect(r.success).toBe(true);
|
||||
expect(r.items).toEqual([{ id: 1 }]);
|
||||
});
|
||||
|
||||
it('unwraps ok:false errors', () => {
|
||||
const r = unwrap({ ok: false, error: { code: 'X', message: 'Failed' } });
|
||||
expect(r.success).toBe(false);
|
||||
expect(r.error).toBe('Failed');
|
||||
});
|
||||
|
||||
it('passes through legacy body', () => {
|
||||
const legacy = { success: true, questionnaires: [] };
|
||||
expect(unwrap(legacy)).toBe(legacy);
|
||||
});
|
||||
});
|
||||
41
website/tests/unit/auth-state.test.js
Normal file
41
website/tests/unit/auth-state.test.js
Normal file
@ -0,0 +1,41 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { canEdit, isLoggedIn, getRole, authGuard, roleGuard } from '../../js/auth-state.js';
|
||||
|
||||
describe('auth-state', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('canEdit allows admin and supervisor only', () => {
|
||||
localStorage.setItem('qdb_role', 'admin');
|
||||
expect(canEdit()).toBe(true);
|
||||
localStorage.setItem('qdb_role', 'supervisor');
|
||||
expect(canEdit()).toBe(true);
|
||||
localStorage.setItem('qdb_role', 'coach');
|
||||
expect(canEdit()).toBe(false);
|
||||
});
|
||||
|
||||
it('isLoggedIn checks token', () => {
|
||||
expect(isLoggedIn()).toBe(false);
|
||||
localStorage.setItem('qdb_token', 't');
|
||||
expect(isLoggedIn()).toBe(true);
|
||||
});
|
||||
|
||||
it('authGuard redirects when logged out', () => {
|
||||
const navigate = vi.fn();
|
||||
const handler = vi.fn();
|
||||
const guarded = authGuard(navigate, handler);
|
||||
guarded({});
|
||||
expect(navigate).toHaveBeenCalledWith('#/login');
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('roleGuard redirects coach from admin routes', () => {
|
||||
localStorage.setItem('qdb_token', 't');
|
||||
localStorage.setItem('qdb_role', 'coach');
|
||||
const navigate = vi.fn();
|
||||
const handler = vi.fn();
|
||||
roleGuard(navigate, ['admin', 'supervisor'], handler)({});
|
||||
expect(navigate).toHaveBeenCalledWith('#/');
|
||||
});
|
||||
});
|
||||
39
website/tests/unit/editor-utils.test.js
Normal file
39
website/tests/unit/editor-utils.test.js
Normal file
@ -0,0 +1,39 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import {
|
||||
parseConfig,
|
||||
questionLocalIds,
|
||||
layoutLabel,
|
||||
readConfigFromForm,
|
||||
} from '../../js/editor-utils.js';
|
||||
|
||||
describe('editor-utils', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
it('parseConfig parses JSON', () => {
|
||||
expect(parseConfig({ configJson: '{"textKey":"a"}' })).toEqual({ textKey: 'a' });
|
||||
expect(parseConfig({ configJson: 'not-json' })).toEqual({});
|
||||
});
|
||||
|
||||
it('questionLocalIds extracts short ids', () => {
|
||||
const ids = questionLocalIds([
|
||||
{ questionID: 'qn__q1', defaultText: 'Q1' },
|
||||
{ questionID: 'qn__q2', defaultText: 'Q2' },
|
||||
]);
|
||||
expect(ids.map(i => i.localId)).toEqual(['q1', 'q2']);
|
||||
});
|
||||
|
||||
it('layoutLabel resolves known layouts', () => {
|
||||
expect(layoutLabel('radio_question')).toContain('Radio');
|
||||
});
|
||||
|
||||
it('readConfigFromForm round-trips value_spinner', () => {
|
||||
document.body.innerHTML = `
|
||||
<input id="pfx_rangeMin" value="1" />
|
||||
<input id="pfx_rangeMax" value="10" />
|
||||
`;
|
||||
const json = readConfigFromForm('value_spinner', 'pfx');
|
||||
expect(JSON.parse(json)).toEqual({ range: { min: 1, max: 10 } });
|
||||
});
|
||||
});
|
||||
33
website/tests/unit/router.test.js
Normal file
33
website/tests/unit/router.test.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
import { navigate, currentHash, matchRoute } from '../../js/router.js';
|
||||
|
||||
|
||||
|
||||
describe('router', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
window.location.hash = '';
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
it('currentHash defaults to / when empty', () => {
|
||||
|
||||
window.location.hash = '';
|
||||
|
||||
expect(currentHash()).toBe('/');
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
it('currentHash strips leading hash', () => {
|
||||
|
||||
window.location.hash = '#/dashboard';
|
||||
|
||||
expect(currentHash()).toBe('/dashboard');
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user