118 lines
3.2 KiB
JavaScript
118 lines
3.2 KiB
JavaScript
/**
|
|
* 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);
|
|
});
|
|
});
|