mirror of
https://github.com/unraid/api.git
synced 2025-12-30 21:19:49 -06:00
test: create tests for components batch 4 (#1384)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Tests** - Added comprehensive unit tests for the activation code data store, covering loading states, activation code retrieval, fresh install detection, and partner info resolution under various scenarios. - Introduced new tests for the activation code modal store, validating state management, visibility logic, and Konami code sequence handling. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: mdatelle <mike@datelle.net>
This commit is contained in:
193
web/__test__/store/activationCodeData.test.ts
Normal file
193
web/__test__/store/activationCodeData.test.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
import { ref } from 'vue';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
ACTIVATION_CODE_QUERY,
|
||||
PARTNER_INFO_QUERY,
|
||||
} from '~/components/Activation/graphql/activationCode.query';
|
||||
import { useActivationCodeDataStore } from '~/components/Activation/store/activationCodeData';
|
||||
import { RegistrationState } from '~/composables/gql/graphql';
|
||||
|
||||
// Create a complete mock of UseQueryReturn with all required properties
|
||||
const createCompleteQueryMock = <T>(result: T | null = null, loading = false) => ({
|
||||
result: ref(result),
|
||||
loading: ref(loading),
|
||||
error: ref(null),
|
||||
networkStatus: ref(7),
|
||||
called: ref(true),
|
||||
variables: ref({}),
|
||||
document: ref(null),
|
||||
query: ref(null),
|
||||
forceDisabled: ref(false),
|
||||
options: { errorPolicy: 'all' as const },
|
||||
stop: vi.fn(),
|
||||
start: vi.fn(),
|
||||
restart: vi.fn(),
|
||||
refetch: vi.fn(),
|
||||
fetchMore: vi.fn(),
|
||||
onResult: vi.fn(),
|
||||
onError: vi.fn(),
|
||||
subscribeToMore: vi.fn(),
|
||||
updateQuery: vi.fn(),
|
||||
});
|
||||
|
||||
vi.mock('@vue/apollo-composable', () => ({
|
||||
useQuery: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('ActivationCodeData Store', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia());
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('Computed Properties', () => {
|
||||
it('should compute loading state when activationCodeLoading is true', () => {
|
||||
vi.mocked(useQuery).mockImplementation((query) => {
|
||||
if (query === ACTIVATION_CODE_QUERY) {
|
||||
return createCompleteQueryMock(null, true);
|
||||
}
|
||||
|
||||
return createCompleteQueryMock(null, false);
|
||||
});
|
||||
|
||||
const store = useActivationCodeDataStore();
|
||||
|
||||
expect(store.loading).toBe(true);
|
||||
});
|
||||
|
||||
it('should compute loading state when partnerInfoLoading is true', () => {
|
||||
vi.mocked(useQuery).mockImplementation((query) => {
|
||||
if (query === PARTNER_INFO_QUERY) {
|
||||
return createCompleteQueryMock(null, true);
|
||||
}
|
||||
|
||||
return createCompleteQueryMock(null, false);
|
||||
});
|
||||
|
||||
const store = useActivationCodeDataStore();
|
||||
|
||||
expect(store.loading).toBe(true);
|
||||
});
|
||||
|
||||
it('should compute loading state when both loadings are false', () => {
|
||||
vi.mocked(useQuery).mockImplementation(() => createCompleteQueryMock(null, false));
|
||||
|
||||
const store = useActivationCodeDataStore();
|
||||
|
||||
expect(store.loading).toBe(false);
|
||||
});
|
||||
|
||||
it('should compute activationCode correctly', () => {
|
||||
const mockActivationCode = 'TEST-CODE-123';
|
||||
|
||||
vi.mocked(useQuery).mockImplementation((query) => {
|
||||
if (query === ACTIVATION_CODE_QUERY) {
|
||||
return createCompleteQueryMock(
|
||||
{
|
||||
customization: { activationCode: mockActivationCode },
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
return createCompleteQueryMock(null, false);
|
||||
});
|
||||
|
||||
const store = useActivationCodeDataStore();
|
||||
|
||||
expect(store.activationCode).toBe(mockActivationCode);
|
||||
});
|
||||
|
||||
it('should compute isFreshInstall as true when regState is ENOKEYFILE', () => {
|
||||
vi.mocked(useQuery).mockImplementation((query) => {
|
||||
if (query === ACTIVATION_CODE_QUERY) {
|
||||
return createCompleteQueryMock(
|
||||
{
|
||||
vars: { regState: RegistrationState.ENOKEYFILE },
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return createCompleteQueryMock(null, false);
|
||||
});
|
||||
|
||||
const store = useActivationCodeDataStore();
|
||||
|
||||
expect(store.isFreshInstall).toBe(true);
|
||||
});
|
||||
|
||||
it('should compute isFreshInstall as false when regState is not ENOKEYFILE', () => {
|
||||
vi.mocked(useQuery).mockImplementation((query) => {
|
||||
if (query === ACTIVATION_CODE_QUERY) {
|
||||
return createCompleteQueryMock(
|
||||
{
|
||||
vars: { regState: 'REGISTERED' as RegistrationState },
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return createCompleteQueryMock(null, false);
|
||||
});
|
||||
|
||||
const store = useActivationCodeDataStore();
|
||||
|
||||
expect(store.isFreshInstall).toBe(false);
|
||||
});
|
||||
|
||||
it('should use publicPartnerInfo when available', () => {
|
||||
const mockPublicPartnerInfo = { name: 'Public Partner' };
|
||||
vi.mocked(useQuery).mockImplementation((query) => {
|
||||
if (query === PARTNER_INFO_QUERY) {
|
||||
return createCompleteQueryMock(
|
||||
{
|
||||
publicPartnerInfo: mockPublicPartnerInfo,
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return createCompleteQueryMock(null, false);
|
||||
});
|
||||
|
||||
const store = useActivationCodeDataStore();
|
||||
|
||||
expect(store.partnerInfo).toEqual(mockPublicPartnerInfo);
|
||||
});
|
||||
|
||||
it('should fallback to activationCode partnerInfo when publicPartnerInfo is null', () => {
|
||||
const mockPartnerInfo = { name: 'Activation Partner' };
|
||||
vi.mocked(useQuery).mockImplementation((query) => {
|
||||
if (query === ACTIVATION_CODE_QUERY) {
|
||||
return createCompleteQueryMock(
|
||||
{
|
||||
customization: { partnerInfo: mockPartnerInfo },
|
||||
},
|
||||
false
|
||||
);
|
||||
} else if (query === PARTNER_INFO_QUERY) {
|
||||
return createCompleteQueryMock(
|
||||
{
|
||||
publicPartnerInfo: null,
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return createCompleteQueryMock(null, false);
|
||||
});
|
||||
|
||||
const store = useActivationCodeDataStore();
|
||||
|
||||
expect(store.partnerInfo).toEqual(mockPartnerInfo);
|
||||
});
|
||||
});
|
||||
});
|
||||
139
web/__test__/store/activationCodeModal.test.ts
Normal file
139
web/__test__/store/activationCodeModal.test.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { ref } from 'vue';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { useSessionStorage } from '@vueuse/core';
|
||||
|
||||
import { ACTIVATION_CODE_MODAL_HIDDEN_STORAGE_KEY } from '~/consts';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useActivationCodeDataStore } from '~/components/Activation/store/activationCodeData';
|
||||
import { useActivationCodeModalStore } from '~/components/Activation/store/activationCodeModal';
|
||||
import { useCallbackActionsStore } from '~/store/callbackActions';
|
||||
|
||||
vi.mock('@vueuse/core', () => ({
|
||||
useSessionStorage: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('~/components/Activation/store/activationCodeData', () => ({
|
||||
useActivationCodeDataStore: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('~/store/callbackActions', () => ({
|
||||
useCallbackActionsStore: vi.fn(),
|
||||
}));
|
||||
|
||||
describe('ActivationCodeModal Store', () => {
|
||||
let store: ReturnType<typeof useActivationCodeModalStore>;
|
||||
let mockIsHidden: ReturnType<typeof ref>;
|
||||
let mockIsFreshInstall: ReturnType<typeof ref>;
|
||||
let mockCallbackData: ReturnType<typeof ref>;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Mock window.location to prevent navigation errors
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: { href: '' },
|
||||
writable: true,
|
||||
});
|
||||
|
||||
mockIsHidden = ref(null);
|
||||
mockIsFreshInstall = ref(false);
|
||||
mockCallbackData = ref(null);
|
||||
|
||||
vi.mocked(useSessionStorage).mockReturnValue(mockIsHidden);
|
||||
vi.mocked(useActivationCodeDataStore).mockReturnValue({
|
||||
isFreshInstall: mockIsFreshInstall,
|
||||
} as unknown as ReturnType<typeof useActivationCodeDataStore>);
|
||||
vi.mocked(useCallbackActionsStore).mockReturnValue({
|
||||
callbackData: mockCallbackData,
|
||||
} as unknown as ReturnType<typeof useCallbackActionsStore>);
|
||||
|
||||
setActivePinia(createPinia());
|
||||
store = useActivationCodeModalStore();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.resetAllMocks();
|
||||
mockIsHidden.value = null;
|
||||
mockIsFreshInstall.value = false;
|
||||
mockCallbackData.value = null;
|
||||
});
|
||||
|
||||
describe('State Management', () => {
|
||||
it('should initialize with correct storage key', () => {
|
||||
expect(useSessionStorage).toHaveBeenCalledWith(ACTIVATION_CODE_MODAL_HIDDEN_STORAGE_KEY, null);
|
||||
});
|
||||
|
||||
it('should set isHidden value correctly', () => {
|
||||
store.setIsHidden(true);
|
||||
expect(mockIsHidden.value).toBe(true);
|
||||
|
||||
store.setIsHidden(false);
|
||||
expect(mockIsHidden.value).toBe(false);
|
||||
|
||||
store.setIsHidden(null);
|
||||
expect(mockIsHidden.value).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Computed Properties', () => {
|
||||
it('should be visible when explicitly set to show', () => {
|
||||
mockIsHidden.value = false;
|
||||
|
||||
expect(store.isVisible).toBe(true);
|
||||
});
|
||||
|
||||
it('should be visible when fresh install and not explicitly hidden', () => {
|
||||
mockIsHidden.value = null;
|
||||
mockIsFreshInstall.value = true;
|
||||
mockCallbackData.value = null;
|
||||
|
||||
expect(store.isVisible).toBe(true);
|
||||
});
|
||||
|
||||
it('should not be visible when explicitly hidden', () => {
|
||||
mockIsHidden.value = true;
|
||||
|
||||
expect(store.isVisible).toBe(false);
|
||||
});
|
||||
|
||||
it('should not be visible when not fresh install', () => {
|
||||
mockIsHidden.value = null;
|
||||
mockIsFreshInstall.value = false;
|
||||
|
||||
expect(store.isVisible).toBe(false);
|
||||
});
|
||||
|
||||
it('should not be visible when callback data exists', () => {
|
||||
mockIsHidden.value = null;
|
||||
mockIsFreshInstall.value = true;
|
||||
mockCallbackData.value = { someData: 'test' };
|
||||
|
||||
expect(store.isVisible).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Konami Code Handling', () => {
|
||||
const keySequence = [
|
||||
'ArrowUp',
|
||||
'ArrowUp',
|
||||
'ArrowDown',
|
||||
'ArrowDown',
|
||||
'ArrowLeft',
|
||||
'ArrowRight',
|
||||
'ArrowLeft',
|
||||
'ArrowRight',
|
||||
'b',
|
||||
'a',
|
||||
];
|
||||
|
||||
it('should not trigger on partial sequence', () => {
|
||||
keySequence.slice(0, 3).forEach((key) => {
|
||||
window.dispatchEvent(new KeyboardEvent('keydown', { key }));
|
||||
});
|
||||
|
||||
expect(mockIsHidden.value).toBe(null);
|
||||
expect(window.location.href).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user