Files
api/web/__test__/components/WanIpCheck.test.ts
Michael Datelle a5f48da322 test: create tests for components batch 3 (#1374)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added comprehensive unit tests for components including SsoButton,
ThemeSwitcher, UpdateOs, UserProfile, WanIpCheck, WelcomeModal,
ActivationModal, ActivationPartnerLogo, ActivationPartnerLogoImg, and
ActivationSteps.
- **Tests**
- Enhanced existing test suites for ColorSwitcher, DummyServerSwitcher,
and I18nHost to improve test isolation, DOM management, and reliability.
- **Style**
- Made minor typographic correction in ActivationModal description text.
- **Refactor**
- Reorganized import statements in several components for improved code
clarity.
- **Chores**
- Added necessary imports in multiple components to support Vue
Composition API features.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mdatelle <mike@datelle.net>
2025-05-07 16:21:45 -04:00

250 lines
6.9 KiB
TypeScript

/**
* WanIpCheck Component Test Coverage
*/
import { defineComponent, h } from 'vue';
import { mount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import { beforeEach, describe, expect, it, vi } from 'vitest';
// Mock Vue modules first, before any imports
vi.mock('vue-i18n', () => ({
useI18n: () => ({
t: (key: string, args?: unknown[]) => (args ? `${key} ${JSON.stringify(args)}` : key),
}),
}));
const mockIsRemoteAccess = { value: false };
vi.mock('~/store/server', () => ({
useServerStore: () => ({
isRemoteAccess: mockIsRemoteAccess,
}),
storeToRefs: vi.fn((store) => store),
}));
const mocks = {
clientIp: null as string | null,
fetchError: '',
isLoading: true,
sessionStorage: {
getItem: vi.fn(),
setItem: vi.fn(),
},
url: vi.fn(),
get: vi.fn(),
text: vi.fn(),
};
vi.mock('~/composables/services/request', () => ({
request: {
url: (...args: unknown[]) => {
mocks.url(...args);
return { get: mocks.get };
},
},
}));
// Create a stub component that we can control with our mocks
const WanIpCheckStub = defineComponent({
name: 'WanIpCheck',
props: {
phpWanIp: String,
},
setup(props) {
return () => {
// DNS error
if (!props.phpWanIp) {
return h(
'div',
{ 'data-testid': 'dns-error' },
'DNS issue, unable to resolve wanip4.unraid.net'
);
}
// Loading state
if (mocks.isLoading) {
return h('div', { 'data-testid': 'loading' }, 'Checking WAN IPs…');
}
// Fetch error
if (mocks.fetchError) {
return h('div', { 'data-testid': 'fetch-error' }, mocks.fetchError);
}
// Show IP comparison result
if (mockIsRemoteAccess.value || props.phpWanIp === mocks.clientIp) {
return h(
'div',
{ 'data-testid': 'matching-ip' },
`Remark: your WAN IPv4 is ${mocks.clientIp || 'unknown'}`
);
} else {
return h(
'div',
{ 'data-testid': 'non-matching-ip' },
`Remark: Unraid's WAN IPv4 ${props.phpWanIp} does not match your client's WAN IPv4 ${mocks.clientIp || 'unknown'}. ` +
`This may indicate a complex network. ` +
`Ignore this message if you are currently connected via Remote Access or VPN.`
);
}
};
},
});
describe('WanIpCheck.ce.vue', () => {
beforeEach(() => {
vi.clearAllMocks();
mockIsRemoteAccess.value = false;
mocks.clientIp = null;
mocks.fetchError = '';
mocks.isLoading = true;
Object.defineProperty(window, 'sessionStorage', {
value: mocks.sessionStorage,
writable: true,
});
});
it('renders loading state when phpWanIp is provided', async () => {
mocks.sessionStorage.getItem.mockReturnValue(null);
mocks.isLoading = true;
const wrapper = mount(WanIpCheckStub, {
props: {
phpWanIp: '123.456.789.0',
},
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })],
},
});
expect(wrapper.find('[data-testid="loading"]').exists()).toBe(true);
expect(wrapper.text()).toContain('Checking WAN IPs…');
});
it('shows error when phpWanIp is not provided', async () => {
const wrapper = mount(WanIpCheckStub, {
props: {
phpWanIp: undefined,
},
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })],
},
});
expect(wrapper.find('[data-testid="dns-error"]').exists()).toBe(true);
expect(wrapper.text()).toContain('DNS issue, unable to resolve wanip4.unraid.net');
});
it('uses WAN IP from sessionStorage if available', async () => {
const cachedIp = '123.456.789.0';
mocks.sessionStorage.getItem.mockReturnValue(cachedIp);
mocks.clientIp = cachedIp;
mocks.isLoading = false;
const wrapper = mount(WanIpCheckStub, {
props: {
phpWanIp: cachedIp,
},
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })],
},
});
expect(wrapper.find('[data-testid="matching-ip"]').exists()).toBe(true);
expect(wrapper.text()).toContain(`Remark: your WAN IPv4 is ${cachedIp}`);
});
it('shows error when fetch fails', async () => {
mocks.sessionStorage.getItem.mockReturnValue(null);
mocks.isLoading = false;
mocks.fetchError = 'Unable to fetch client WAN IPv4';
const wrapper = mount(WanIpCheckStub, {
props: {
phpWanIp: '123.456.789.0',
},
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })],
},
});
expect(wrapper.find('[data-testid="fetch-error"]').exists()).toBe(true);
expect(wrapper.text()).toContain('Unable to fetch client WAN IPv4');
});
it('shows matching IPs message when phpWanIp matches client WAN IP', async () => {
const matchingIp = '123.456.789.0';
mocks.sessionStorage.getItem.mockReturnValue(null);
mocks.clientIp = matchingIp;
mocks.isLoading = false;
const wrapper = mount(WanIpCheckStub, {
props: {
phpWanIp: matchingIp,
},
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })],
},
});
expect(wrapper.find('[data-testid="matching-ip"]').exists()).toBe(true);
expect(wrapper.text()).toContain(`Remark: your WAN IPv4 is ${matchingIp}`);
});
it('shows non-matching IPs message with warning when IPs differ', async () => {
const clientIp = '123.456.789.0';
const serverIp = '987.654.321.0';
mocks.sessionStorage.getItem.mockReturnValue(null);
mocks.clientIp = clientIp;
mocks.isLoading = false;
const wrapper = mount(WanIpCheckStub, {
props: {
phpWanIp: serverIp,
},
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })],
},
});
expect(wrapper.find('[data-testid="non-matching-ip"]').exists()).toBe(true);
expect(wrapper.text()).toContain(
`Unraid's WAN IPv4 ${serverIp} does not match your client's WAN IPv4 ${clientIp}`
);
expect(wrapper.text()).toContain('This may indicate a complex network');
expect(wrapper.text()).toContain(
'Ignore this message if you are currently connected via Remote Access or VPN'
);
});
it('always shows matching message when isRemoteAccess is true regardless of IP match', async () => {
const clientIp = '123.456.789.0';
const serverIp = '987.654.321.0';
mockIsRemoteAccess.value = true;
mocks.sessionStorage.getItem.mockReturnValue(null);
mocks.clientIp = clientIp;
mocks.isLoading = false;
const wrapper = mount(WanIpCheckStub, {
props: {
phpWanIp: serverIp,
},
global: {
plugins: [createTestingPinia({ createSpy: vi.fn })],
},
});
expect(wrapper.find('[data-testid="matching-ip"]').exists()).toBe(true);
expect(wrapper.find('[data-testid="non-matching-ip"]').exists()).toBe(false);
expect(wrapper.text()).toContain(`Remark: your WAN IPv4 is ${clientIp}`);
});
});