Add store tests with mocked axios and apiError

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 19:30:33 +08:00
parent 83c2db7582
commit 529e9a4aa1
12 changed files with 1260 additions and 0 deletions

View File

@@ -0,0 +1,246 @@
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { setActivePinia, createPinia } from 'pinia';
vi.mock('@/module/apiError.js', () => ({
default: vi.fn(),
}));
// Mock login store to avoid its side effects
vi.mock('@/stores/login.ts', () => {
const { defineStore } = require('pinia');
return {
default: defineStore('loginStore', {
state: () => ({
userData: { username: 'currentUser', name: 'Current' },
}),
actions: {
getUserData: vi.fn(),
},
}),
};
});
import useAcctMgmtStore from '@/stores/acctMgmt.ts';
describe('acctMgmtStore', () => {
let store;
const mockAxios = {
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn(),
};
beforeEach(() => {
setActivePinia(createPinia());
store = useAcctMgmtStore();
store.$axios = mockAxios;
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 () => {
mockAxios.post.mockResolvedValue({ status: 200 });
const user = { username: 'newuser', password: 'pass' };
await store.createNewAccount(user);
expect(mockAxios.post).toHaveBeenCalledWith(
'/api/users', user,
);
expect(store.isOneAccountJustCreate).toBe(true);
expect(store.justCreateUsername).toBe('newuser');
});
});
describe('deleteAccount', () => {
it('returns true on success', async () => {
mockAxios.delete.mockResolvedValue({ status: 200 });
const result = await store.deleteAccount('alice');
expect(mockAxios.delete).toHaveBeenCalledWith(
'/api/users/alice',
);
expect(result).toBe(true);
});
it('returns false on error', async () => {
mockAxios.delete.mockRejectedValue(new Error('fail'));
const result = await store.deleteAccount('alice');
expect(result).toBe(false);
});
});
describe('editAccount', () => {
it('puts edited data', async () => {
mockAxios.put.mockResolvedValue({ status: 200 });
const detail = {
username: 'alice',
password: 'newpw',
name: 'Alice',
is_active: true,
};
const result = await store.editAccount('alice', detail);
expect(mockAxios.put).toHaveBeenCalledWith(
'/api/users/alice',
expect.objectContaining({ password: 'newpw' }),
);
expect(result).toBe(true);
});
});
describe('addRoleToUser', () => {
it('puts role assignment', async () => {
mockAxios.put.mockResolvedValue({ status: 200 });
const result = await store.addRoleToUser('alice', 'admin');
expect(mockAxios.put).toHaveBeenCalledWith(
'/api/users/alice/roles/admin',
);
expect(result).toBe(true);
});
});
describe('deleteRoleToUser', () => {
it('deletes role', async () => {
mockAxios.delete.mockResolvedValue({ status: 200 });
const result = await store.deleteRoleToUser('alice', 'admin');
expect(mockAxios.delete).toHaveBeenCalledWith(
'/api/users/alice/roles/admin',
);
expect(result).toBe(true);
});
});
describe('getUserDetail', () => {
it('fetches user and sets admin flag', async () => {
mockAxios.get.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 () => {
mockAxios.get.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');
});
});