Files
memory-infrastructure-palace/code/websites/pokedex.online/tests/unit/views/GamemasterExplorer.test.js

277 lines
8.2 KiB
JavaScript

/**
* GamemasterExplorer View Tests
* Integration tests verifying the refactored component works correctly
*/
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { mount } from '@vue/test-utils';
import { ref } from 'vue';
import GamemasterExplorer from '../../../src/views/GamemasterExplorer.vue';
// Mock composables
vi.mock('../../../src/composables/useGamemasterFiles.js', () => ({
useGamemasterFiles: vi.fn(() => ({
selectedFile: ref('pokemon.json'),
fileContent: ref('{"test": "data"}'),
fileLines: ref(['{', ' "test": "data"', '}']),
displayLines: ref(['{', ' "test": "data"', '}']),
isLoading: ref(false),
fileError: ref(null),
preferences: ref({
lineWrap: false,
darkMode: false,
showLineNumbers: true,
performanceMode: 'auto'
}),
hasFiles: ref(true),
fileTooLarge: ref(false),
loadStatus: vi.fn(),
formatSize: vi.fn(size => `${size} B`),
formatFileName: vi.fn(name => name),
getFileType: vi.fn(name => name.replace('.json', ''))
}))
}));
vi.mock('../../../src/composables/useGamemasterSearch.js', () => ({
useGamemasterSearch: vi.fn(() => ({
searchQuery: ref(''),
searchResults: ref([]),
currentResultIndex: ref(-1),
isSearching: ref(false),
searchError: ref(null),
executeSearch: vi.fn(),
clearSearch: vi.fn(),
goToNextResult: vi.fn(),
goToPrevResult: vi.fn()
}))
}));
vi.mock('../../../src/composables/useLineSelection.js', () => ({
useLineSelection: vi.fn(() => ({
selectedLines: ref(new Set()),
hasSelection: ref(false),
selectionCount: ref(0),
toggleLineSelection: vi.fn(),
clearSelection: vi.fn(),
selectAll: vi.fn(),
copySelected: vi.fn(),
exportSelected: vi.fn()
}))
}));
vi.mock('../../../src/composables/useJsonFilter.js', () => ({
default: vi.fn(() => ({
filterProperty: ref(''),
filterValue: ref(''),
filterMode: ref('equals'),
filteredData: ref([]),
setFilter: vi.fn(),
clearFilters: vi.fn(),
getUniqueValues: vi.fn(() => [])
}))
}));
vi.mock('../../../src/composables/useKeyboardShortcuts.js', () => ({
useKeyboardShortcuts: vi.fn()
}));
vi.mock('../../../src/composables/useUrlState.js', () => ({
useUrlState: vi.fn()
}));
vi.mock('../../../src/composables/useClipboard.js', () => ({
useClipboard: vi.fn(() => ({
copied: ref(false),
error: ref(null),
copy: vi.fn()
}))
}));
vi.mock('../../../src/utilities/gamemaster-client.js', () => ({
GamemasterClient: vi.fn(() => ({
getStatus: vi.fn(),
getFile: vi.fn()
}))
}));
describe('GamemasterExplorer', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('renders successfully', () => {
const wrapper = mount(GamemasterExplorer);
expect(wrapper.exists()).toBe(true);
});
it('shows loading state when isLoading is true', async () => {
const { useGamemasterFiles } =
await import('../../../src/composables/useGamemasterFiles.js');
useGamemasterFiles.mockReturnValueOnce({
selectedFile: ref(''),
fileContent: ref(''),
fileLines: ref([]),
displayLines: ref([]),
isLoading: ref(true),
fileError: ref(null),
preferences: ref({}),
hasFiles: ref(false),
fileTooLarge: ref(false),
loadStatus: vi.fn()
});
const wrapper = mount(GamemasterExplorer);
expect(wrapper.find('.loading-state').exists()).toBe(true);
expect(wrapper.text()).toContain('Loading Gamemaster Explorer');
});
it('shows error state when fileError exists', async () => {
const { useGamemasterFiles } =
await import('../../../src/composables/useGamemasterFiles.js');
useGamemasterFiles.mockReturnValueOnce({
selectedFile: ref(''),
fileContent: ref(''),
fileLines: ref([]),
displayLines: ref([]),
isLoading: ref(false),
fileError: ref('Failed to load files'),
preferences: ref({}),
hasFiles: ref(false),
fileTooLarge: ref(false),
loadStatus: vi.fn()
});
const wrapper = mount(GamemasterExplorer);
expect(wrapper.find('.error-state').exists()).toBe(true);
expect(wrapper.text()).toContain('Failed to load files');
});
it('shows no files state when hasFiles is false', async () => {
const { useGamemasterFiles } =
await import('../../../src/composables/useGamemasterFiles.js');
useGamemasterFiles.mockReturnValueOnce({
selectedFile: ref(''),
fileContent: ref(''),
fileLines: ref([]),
displayLines: ref([]),
isLoading: ref(false),
fileError: ref(null),
preferences: ref({}),
hasFiles: ref(false),
fileTooLarge: ref(false),
loadStatus: vi.fn()
});
const wrapper = mount(GamemasterExplorer);
expect(wrapper.find('.no-files-state').exists()).toBe(true);
expect(wrapper.text()).toContain('No Gamemaster Files Available');
});
it('renders main explorer interface when files are loaded', () => {
const wrapper = mount(GamemasterExplorer);
expect(wrapper.find('.explorer-container').exists()).toBe(true);
expect(wrapper.find('.explorer-header').exists()).toBe(true);
expect(wrapper.text()).toContain('Gamemaster Explorer');
});
it('includes all child components', () => {
const wrapper = mount(GamemasterExplorer);
// Check for FileSelector component
expect(wrapper.findComponent({ name: 'FileSelector' }).exists()).toBe(true);
// Check for SearchBar component
expect(wrapper.findComponent({ name: 'SearchBar' }).exists()).toBe(true);
// Check for FilterPanel component
expect(wrapper.findComponent({ name: 'FilterPanel' }).exists()).toBe(true);
// Check for JsonViewer component
expect(wrapper.findComponent({ name: 'JsonViewer' }).exists()).toBe(true);
// Check for ActionToolbar component
expect(wrapper.findComponent({ name: 'ActionToolbar' }).exists()).toBe(
true
);
});
it('toggles help panel', async () => {
const wrapper = mount(GamemasterExplorer);
expect(wrapper.find('.help-panel').exists()).toBe(false);
// Click help button
const helpButton = wrapper.findAll('.btn-icon')[0];
await helpButton.trigger('click');
expect(wrapper.find('.help-panel').exists()).toBe(true);
expect(wrapper.text()).toContain('Keyboard Shortcuts');
});
it('toggles settings panel', async () => {
const wrapper = mount(GamemasterExplorer);
expect(wrapper.find('.settings-panel').exists()).toBe(false);
// Click settings button
const settingsButton = wrapper.findAll('.btn-icon')[1];
await settingsButton.trigger('click');
expect(wrapper.find('.settings-panel').exists()).toBe(true);
expect(wrapper.text()).toContain('Settings');
});
it('has back to home link', () => {
const wrapper = mount(GamemasterExplorer);
const backLink = wrapper.find('.back-button');
expect(backLink.exists()).toBe(true);
expect(backLink.attributes('to')).toBe('/');
});
it('calls loadStatus on mount', async () => {
const { useGamemasterFiles } =
await import('../../../src/composables/useGamemasterFiles.js');
const mockLoadStatus = vi.fn();
useGamemasterFiles.mockReturnValueOnce({
selectedFile: ref(''),
fileContent: ref(''),
fileLines: ref([]),
displayLines: ref([]),
isLoading: ref(false),
fileError: ref(null),
preferences: ref({}),
hasFiles: ref(true),
fileTooLarge: ref(false),
loadStatus: mockLoadStatus
});
mount(GamemasterExplorer);
// loadStatus should be called on mount
expect(mockLoadStatus).toHaveBeenCalled();
});
it('computes filterData from fileContent', () => {
const wrapper = mount(GamemasterExplorer);
// Component should parse JSON content for filtering
const filterData = wrapper.vm.filterData;
expect(filterData).toBeDefined();
});
it('displays toast messages for clipboard operations', async () => {
const { useClipboard } =
await import('../../../src/composables/useClipboard.js');
useClipboard.mockReturnValueOnce({
copied: ref(true),
error: ref(null),
copy: vi.fn()
});
const wrapper = mount(GamemasterExplorer);
expect(wrapper.find('.toast.success').exists()).toBe(true);
expect(wrapper.text()).toContain('Copied to clipboard');
});
});