🧪 Add unit tests for JsonViewer component in gamemaster

This commit is contained in:
2026-01-29 03:55:21 +00:00
parent 199c46b3e6
commit b07c74d3c1

View File

@@ -0,0 +1,117 @@
/**
* JsonViewer Component Tests
* Verifies JSON display and line selection UI
*/
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { mount } from '@vue/test-utils';
import { ref } from 'vue';
import JsonViewer from '../../../../src/components/gamemaster/JsonViewer.vue';
import { useLineSelection } from '../../../../src/composables/useLineSelection.js';
vi.mock('../../../../src/composables/useLineSelection.js', () => ({
useLineSelection: vi.fn()
}));
const createSelectionMock = overrides => ({
selectedLines: ref(new Set()),
toggleLineSelection: vi.fn(),
...overrides
});
describe('JsonViewer Component', () => {
let selectionMock;
beforeEach(() => {
selectionMock = createSelectionMock();
useLineSelection.mockReturnValue(selectionMock);
});
const baseProps = {
displayLines: [
{ lineNumber: 1, content: '{', hasMatch: false },
{ lineNumber: 2, content: ' "name": "Pikachu"', hasMatch: true }
],
fileContent: '{\n "name": "Pikachu"\n}',
selectedFile: 'pokemon',
preferences: { showLineNumbers: true, darkMode: false, lineWrap: false },
searchResults: [1],
currentResultIndex: 0,
highlightConfig: { theme: 'github', language: 'json' },
lineHeight: 20
};
it('does not render when fileContent is empty', () => {
const wrapper = mount(JsonViewer, {
props: { ...baseProps, fileContent: '' }
});
expect(wrapper.find('.content-viewer').exists()).toBe(false);
});
it('renders lines with line numbers', () => {
selectionMock.selectedLines.value.add(2);
const wrapper = mount(JsonViewer, {
props: baseProps
});
const lines = wrapper.findAll('.line');
expect(lines.length).toBe(2);
expect(lines[1].classes()).toContain('selected');
expect(wrapper.findAll('.line-number').length).toBe(2);
});
it('calls toggleLineSelection on line click', async () => {
const wrapper = mount(JsonViewer, {
props: baseProps
});
const lines = wrapper.findAll('.line');
await lines[0].trigger('click');
expect(selectionMock.toggleLineSelection).toHaveBeenCalled();
});
it('marks the current search result line', () => {
const wrapper = mount(JsonViewer, {
props: baseProps
});
const current = wrapper.findAll('.line')[1];
expect(current.classes()).toContain('current-result');
});
it('shows warning banner when file is too large', () => {
const wrapper = mount(JsonViewer, {
props: { ...baseProps, fileTooLarge: true }
});
expect(wrapper.find('.warning-banner').exists()).toBe(true);
});
it('uses RecycleScroller for large line counts', () => {
const largeLines = Array.from({ length: 1001 }, (_, index) => ({
lineNumber: index + 1,
content: `line ${index + 1}`,
hasMatch: false
}));
const wrapper = mount(JsonViewer, {
props: {
...baseProps,
displayLines: largeLines
},
global: {
stubs: {
RecycleScroller: {
template: '<div class="scroller"><slot :item="items[0]" /></div>',
props: ['items']
}
}
}
});
expect(wrapper.find('.scroller').exists()).toBe(true);
});
});