252 lines
6.8 KiB
JavaScript
252 lines
6.8 KiB
JavaScript
// The Lucia project.
|
|
// Copyright 2026-2026 DSP, inc. All rights reserved.
|
|
// Authors:
|
|
// imacat.yang@dsp.im (imacat), 2026/03/05
|
|
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { setActivePinia, createPinia } from 'pinia';
|
|
|
|
vi.mock('@/module/apiError.js', () => ({
|
|
default: vi.fn(),
|
|
}));
|
|
|
|
const { mockGet, mockPost, mockPut, mockDelete } = vi.hoisted(() => ({
|
|
mockGet: vi.fn(), mockPost: vi.fn(), mockPut: vi.fn(), mockDelete: vi.fn(),
|
|
}));
|
|
vi.mock('@/api/client.js', () => ({
|
|
default: { get: mockGet, post: mockPost, put: mockPut, delete: mockDelete },
|
|
}));
|
|
|
|
// Mock login store to avoid its side effects
|
|
vi.mock('@/stores/login', () => {
|
|
const { defineStore } = require('pinia');
|
|
return {
|
|
useLoginStore: defineStore('loginStore', {
|
|
state: () => ({
|
|
userData: { username: 'currentUser', name: 'Current' },
|
|
}),
|
|
actions: {
|
|
getUserData: vi.fn(),
|
|
},
|
|
}),
|
|
};
|
|
});
|
|
|
|
import { useAcctMgmtStore } from '@/stores/acctMgmt';
|
|
|
|
describe('acctMgmtStore', () => {
|
|
let store;
|
|
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia());
|
|
store = useAcctMgmtStore();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('has correct default state', () => {
|
|
expect(store.allUserAccoutList).toEqual([]);
|
|
expect(store.isAcctMenuOpen).toBe(false);
|
|
});
|
|
|
|
describe('menu actions', () => {
|
|
it('openAcctMenu sets true', () => {
|
|
store.openAcctMenu();
|
|
expect(store.isAcctMenuOpen).toBe(true);
|
|
});
|
|
|
|
it('closeAcctMenu sets false', () => {
|
|
store.openAcctMenu();
|
|
store.closeAcctMenu();
|
|
expect(store.isAcctMenuOpen).toBe(false);
|
|
});
|
|
|
|
it('toggleIsAcctMenuOpen toggles', () => {
|
|
store.toggleIsAcctMenuOpen();
|
|
expect(store.isAcctMenuOpen).toBe(true);
|
|
store.toggleIsAcctMenuOpen();
|
|
expect(store.isAcctMenuOpen).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('setCurrentViewingUser', () => {
|
|
it('finds user by username', () => {
|
|
store.allUserAccoutList = [
|
|
{ username: 'alice', name: 'Alice', detail: {} },
|
|
{ username: 'bob', name: 'Bob', detail: {} },
|
|
];
|
|
store.setCurrentViewingUser('bob');
|
|
expect(store.currentViewingUser.name).toBe('Bob');
|
|
});
|
|
});
|
|
|
|
describe('clearCurrentViewingUser', () => {
|
|
it('resets to empty user', () => {
|
|
store.currentViewingUser = { username: 'test', detail: {} };
|
|
store.clearCurrentViewingUser();
|
|
expect(store.currentViewingUser.username).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('createNewAccount', () => {
|
|
it('posts to /api/users and sets flag on success', async () => {
|
|
mockPost.mockResolvedValue({ status: 200 });
|
|
const user = { username: 'newuser', password: 'pass' };
|
|
|
|
await store.createNewAccount(user);
|
|
|
|
expect(mockPost).toHaveBeenCalledWith(
|
|
'/api/users', user,
|
|
);
|
|
expect(store.isOneAccountJustCreate).toBe(true);
|
|
expect(store.justCreateUsername).toBe('newuser');
|
|
});
|
|
});
|
|
|
|
describe('deleteAccount', () => {
|
|
it('returns true on success', async () => {
|
|
mockDelete.mockResolvedValue({ status: 200 });
|
|
|
|
const result = await store.deleteAccount('alice');
|
|
|
|
expect(mockDelete).toHaveBeenCalledWith(
|
|
'/api/users/alice',
|
|
);
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('returns false on error', async () => {
|
|
mockDelete.mockRejectedValue(new Error('fail'));
|
|
|
|
const result = await store.deleteAccount('alice');
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('editAccount', () => {
|
|
it('puts edited data', async () => {
|
|
mockPut.mockResolvedValue({ status: 200 });
|
|
const detail = {
|
|
username: 'alice',
|
|
password: 'newpw',
|
|
name: 'Alice',
|
|
is_active: true,
|
|
};
|
|
|
|
const result = await store.editAccount('alice', detail);
|
|
|
|
expect(mockPut).toHaveBeenCalledWith(
|
|
'/api/users/alice',
|
|
expect.objectContaining({ password: 'newpw' }),
|
|
);
|
|
expect(result).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('addRoleToUser', () => {
|
|
it('puts role assignment', async () => {
|
|
mockPut.mockResolvedValue({ status: 200 });
|
|
|
|
const result = await store.addRoleToUser('alice', 'admin');
|
|
|
|
expect(mockPut).toHaveBeenCalledWith(
|
|
'/api/users/alice/roles/admin',
|
|
);
|
|
expect(result).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('deleteRoleToUser', () => {
|
|
it('deletes role', async () => {
|
|
mockDelete.mockResolvedValue({ status: 200 });
|
|
|
|
const result = await store.deleteRoleToUser('alice', 'admin');
|
|
|
|
expect(mockDelete).toHaveBeenCalledWith(
|
|
'/api/users/alice/roles/admin',
|
|
);
|
|
expect(result).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('getUserDetail', () => {
|
|
it('fetches user and sets admin flag', async () => {
|
|
mockGet.mockResolvedValue({
|
|
status: 200,
|
|
data: {
|
|
username: 'alice',
|
|
roles: [{ code: 'admin' }],
|
|
},
|
|
});
|
|
|
|
const result = await store.getUserDetail('alice');
|
|
|
|
expect(result).toBe(true);
|
|
expect(store.currentViewingUser.is_admin).toBe(true);
|
|
});
|
|
|
|
it('returns false on error', async () => {
|
|
mockGet.mockRejectedValue(new Error('not found'));
|
|
|
|
const result = await store.getUserDetail('ghost');
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('hover state actions', () => {
|
|
beforeEach(() => {
|
|
store.allUserAccoutList = [
|
|
{
|
|
username: 'alice',
|
|
isDeleteHovered: false,
|
|
isRowHovered: false,
|
|
isEditHovered: false,
|
|
isDetailHovered: false,
|
|
},
|
|
];
|
|
});
|
|
|
|
it('changeIsDeleteHoveredByUser', () => {
|
|
store.changeIsDeleteHoveredByUser('alice', true);
|
|
expect(store.allUserAccoutList[0].isDeleteHovered).toBe(true);
|
|
});
|
|
|
|
it('changeIsRowHoveredByUser', () => {
|
|
store.changeIsRowHoveredByUser('alice', true);
|
|
expect(store.allUserAccoutList[0].isRowHovered).toBe(true);
|
|
});
|
|
|
|
it('changeIsEditHoveredByUser', () => {
|
|
store.changeIsEditHoveredByUser('alice', true);
|
|
expect(store.allUserAccoutList[0].isEditHovered).toBe(true);
|
|
});
|
|
|
|
it('changeIsDetailHoveredByUser', () => {
|
|
store.changeIsDetailHoveredByUser('alice', true);
|
|
expect(store.allUserAccoutList[0].isDetailHovered).toBe(true);
|
|
});
|
|
});
|
|
|
|
it('resetJustCreateFlag resets flag', () => {
|
|
store.isOneAccountJustCreate = true;
|
|
store.resetJustCreateFlag();
|
|
expect(store.isOneAccountJustCreate).toBe(false);
|
|
});
|
|
|
|
it('setShouldUpdateList sets boolean', () => {
|
|
store.setShouldUpdateList(true);
|
|
expect(store.shouldUpdateList).toBe(true);
|
|
});
|
|
|
|
it('updateSingleAccountPiniaState updates user', () => {
|
|
store.allUserAccoutList = [
|
|
{ username: 'alice', name: 'Old' },
|
|
];
|
|
store.updateSingleAccountPiniaState({
|
|
username: 'alice', name: 'New',
|
|
});
|
|
expect(store.allUserAccoutList[0].name).toBe('New');
|
|
});
|
|
});
|