/** * Registration Component Test Coverage */ import { setActivePinia } from 'pinia'; import { mount } from '@vue/test-utils'; import { createTestingPinia } from '@pinia/testing'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import type { VueWrapper } from '@vue/test-utils'; import type { ServerconnectPluginInstalled } from '~/types/server'; import type { Pinia } from 'pinia'; import Registration from '~/components/Registration.ce.vue'; import { usePurchaseStore } from '~/store/purchase'; import { useReplaceRenewStore } from '~/store/replaceRenew'; import { useServerStore } from '~/store/server'; vi.mock('crypto-js/aes.js', () => ({ default: {} })); vi.mock('@unraid/shared-callbacks', () => ({ useCallback: vi.fn(() => ({ send: vi.fn(), watcher: vi.fn(), })), })); vi.mock('@vue/apollo-composable', () => ({ useQuery: () => ({ result: { value: {} }, loading: { value: false }, }), useLazyQuery: () => ({ result: { value: {} }, loading: { value: false }, load: vi.fn(), refetch: vi.fn(), onResult: vi.fn(), onError: vi.fn(), }), useMutation: () => ({ mutate: vi.fn(), onDone: vi.fn(), onError: vi.fn(), }), provideApolloClient: vi.fn(), })); vi.mock('@unraid/ui', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, BrandButton: { template: '', props: ['text', 'title', 'icon', 'disabled'] }, CardWrapper: { template: '
' }, PageContainer: { template: '
' }, SettingsGrid: { template: '
' }, }; }); vi.mock('~/components/KeyActions.vue', () => ({ default: { template: '
', props: ['t', 'filterOut'] }, })); vi.mock('~/components/Registration/KeyLinkedStatus.vue', () => ({ default: { template: '
', props: ['t'] }, })); vi.mock('~/components/Registration/ReplaceCheck.vue', () => ({ default: { template: '
', props: ['t'] }, })); vi.mock('~/components/Registration/UpdateExpirationAction.vue', () => ({ default: { template: '
', props: ['t'] }, })); vi.mock('~/components/UserProfile/UptimeExpire.vue', () => ({ default: { template: '
', props: ['t', 'forExpire', 'shortText'], }, })); // Define initial state for the server store for testing const initialServerState = { dateTimeFormat: { date: 'MMM D, YYYY', time: 'h:mm A' }, deviceCount: 0, guid: '', flashVendor: '', flashProduct: '', keyfile: '', regGuid: '', regTm: '', regTo: '', regTy: '', regExp: null, regUpdatesExpired: false, serverErrors: [], state: 'ENOKEYFILE', stateData: { heading: 'Default Heading', message: 'Default Message' }, stateDataError: false, tooManyDevices: false, }; const mockFormattedDateTime = vi.fn(() => 'Formatted Date'); vi.mock('~/composables/dateTime', () => ({ default: vi.fn(() => ({ outputDateTimeFormatted: { value: mockFormattedDateTime() }, })), })); const t = (key: string) => key; vi.mock('vue-i18n', () => ({ useI18n: () => ({ t }), })); describe('Registration.ce.vue', () => { let wrapper: VueWrapper; let pinia: Pinia; let serverStore: ReturnType; let replaceRenewStore: ReturnType; let purchaseStore: ReturnType; const findItemByLabel = (labelKey: string) => { const allLabels = wrapper.findAll('.font-semibold'); const label = allLabels.find((el) => el.html().includes(t(labelKey))); if (!label) return undefined; const nextSibling = label.element.nextElementSibling; return { exists: () => true, props: (prop: string) => { if (prop === 'text' && nextSibling) { return nextSibling.textContent?.trim(); } return undefined; }, }; }; beforeEach(() => { pinia = createTestingPinia({ createSpy: vi.fn, initialState: { server: { ...initialServerState }, }, stubActions: true, }); setActivePinia(pinia); serverStore = useServerStore(); replaceRenewStore = useReplaceRenewStore(); purchaseStore = usePurchaseStore(); serverStore.deprecatedUnraidSSL = undefined; replaceRenewStore.check = vi.fn(); vi.clearAllMocks(); // Mount after store setup wrapper = mount(Registration, { global: { plugins: [pinia], stubs: { ShieldCheckIcon: { template: '
' }, ShieldExclamationIcon: { template: '
' }, }, }, }); }); afterEach(() => { wrapper?.unmount(); vi.restoreAllMocks(); }); it('renders default heading and message when state is ENOKEYFILE', () => { const heading = wrapper.find('h3'); const subheading = wrapper.find('.prose'); expect(heading.text()).toContain("Let's Unleash Your Hardware"); expect(subheading.text()).toContain('Choose an option below'); expect(findItemByLabel(t('License key type'))).toBeUndefined(); expect(findItemByLabel(t('Flash GUID'))).toBeUndefined(); expect(wrapper.find('[data-testid="key-actions"]').exists()).toBe(true); expect(wrapper.find('[data-testid="replace-check"]').exists()).toBe(false); expect(wrapper.find('[data-testid="key-linked-status"]').exists()).toBe(false); }); it('triggers expected action when key action is clicked', async () => { serverStore.state = 'TRIAL'; await wrapper.vm.$nextTick(); const keyActionsElement = wrapper.find('[data-testid="key-actions"]'); expect(keyActionsElement.exists(), 'KeyActions element not found').toBe(true); const expectedActions = serverStore.keyActions?.filter((action) => !['renew'].includes(action.name)); expect(expectedActions, 'No expected actions found in store for TRIAL state').toBeDefined(); expect(expectedActions!.length).toBeGreaterThan(0); const purchaseAction = expectedActions!.find((a) => a.name === 'purchase'); expect(purchaseAction, 'Purchase action not found in expected actions').toBeDefined(); purchaseAction!.click?.(); expect(purchaseStore.purchase).toHaveBeenCalled(); }); it('renders registered state information when state is PRO', async () => { serverStore.state = 'PRO'; serverStore.regTy = 'Pro'; serverStore.regTo = 'Test User'; serverStore.regGuid = '12345-ABCDE'; serverStore.registered = true; serverStore.connectPluginInstalled = 'INSTALLED' as ServerconnectPluginInstalled; serverStore.guid = 'FLASH-GUID-123'; serverStore.deviceCount = 5; await wrapper.vm.$nextTick(); const keyTypeItem = findItemByLabel(t('License key type')); expect(keyTypeItem).toBeDefined(); expect(keyTypeItem?.props('text')).toBe('Pro'); const registeredToItem = findItemByLabel(t('Registered to')); expect(registeredToItem).toBeDefined(); expect(registeredToItem?.props('text')).toBe('Test User'); expect(findItemByLabel(t('Flash GUID'))).toBeDefined(); expect(findItemByLabel(t('Attached Storage Devices'))).toBeDefined(); expect(wrapper.find('[data-testid="key-actions"]').exists()).toBe(false); }); });