✨ Add unit tests for useLineSelection composable
This commit is contained in:
209
code/websites/pokedex.online/src/composables/useLineSelection.js
Normal file
209
code/websites/pokedex.online/src/composables/useLineSelection.js
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { useClipboard } from '@/composables/useClipboard.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* useLineSelection - Composable for managing line selection operations
|
||||||
|
*
|
||||||
|
* Handles:
|
||||||
|
* - Single, range, and multi-line selection with Shift/Ctrl modifiers
|
||||||
|
* - Copy selected/all lines to clipboard
|
||||||
|
* - Export selected/all lines to JSON file
|
||||||
|
* - URL sharing
|
||||||
|
* - Selection state management
|
||||||
|
*
|
||||||
|
* @param {Ref<Set>} displayLines - Current displayed lines with metadata
|
||||||
|
* @param {Ref<string>} fileContent - Full file content for export
|
||||||
|
* @param {Ref<string>} selectedFile - Current file name for export naming
|
||||||
|
* @returns {Object} Line selection composable API
|
||||||
|
*/
|
||||||
|
export function useLineSelection(displayLines, fileContent, selectedFile) {
|
||||||
|
// Clipboard composable
|
||||||
|
const clipboard = useClipboard();
|
||||||
|
|
||||||
|
// Selection state - use Set for O(1) lookups
|
||||||
|
const selectedLines = ref(new Set());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if any lines are selected
|
||||||
|
*/
|
||||||
|
const hasSelection = computed(() => selectedLines.value.size > 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get count of selected lines
|
||||||
|
*/
|
||||||
|
const selectionCount = computed(() => selectedLines.value.size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get selected line numbers as sorted array
|
||||||
|
*/
|
||||||
|
const selectedLineNumbers = computed(() => {
|
||||||
|
return [...selectedLines.value].sort((a, b) => a - b);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle line selection with modifiers
|
||||||
|
*
|
||||||
|
* Supports:
|
||||||
|
* - Single click: Select only that line
|
||||||
|
* - Shift+click: Select range from last selected to current
|
||||||
|
* - Ctrl/Cmd+click: Toggle individual line
|
||||||
|
*/
|
||||||
|
function toggleLineSelection(lineNumber, event) {
|
||||||
|
if (event.shiftKey && selectedLines.value.size > 0) {
|
||||||
|
// Range selection
|
||||||
|
const lastSelected = Math.max(...selectedLines.value);
|
||||||
|
const start = Math.min(lastSelected, lineNumber);
|
||||||
|
const end = Math.max(lastSelected, lineNumber);
|
||||||
|
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
selectedLines.value.add(i);
|
||||||
|
}
|
||||||
|
} else if (event.ctrlKey || event.metaKey) {
|
||||||
|
// Toggle individual line
|
||||||
|
if (selectedLines.value.has(lineNumber)) {
|
||||||
|
selectedLines.value.delete(lineNumber);
|
||||||
|
} else {
|
||||||
|
selectedLines.value.add(lineNumber);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Single selection
|
||||||
|
selectedLines.value.clear();
|
||||||
|
selectedLines.value.add(lineNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all selections
|
||||||
|
*/
|
||||||
|
function clearSelection() {
|
||||||
|
selectedLines.value.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get content of selected lines
|
||||||
|
*/
|
||||||
|
function getSelectedContent() {
|
||||||
|
if (selectedLines.value.size === 0) return '';
|
||||||
|
|
||||||
|
const lines = selectedLineNumbers.value;
|
||||||
|
const content = lines
|
||||||
|
.map(lineNum => {
|
||||||
|
return (
|
||||||
|
displayLines.value.find(l => l.lineNumber === lineNum)?.content || ''
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy selected lines to clipboard
|
||||||
|
*/
|
||||||
|
async function copySelected() {
|
||||||
|
if (selectedLines.value.size === 0) return;
|
||||||
|
|
||||||
|
const content = getSelectedContent();
|
||||||
|
await clipboard.copyToClipboard(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy all content to clipboard
|
||||||
|
*/
|
||||||
|
async function copyAll() {
|
||||||
|
await clipboard.copyToClipboard(fileContent.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export selected lines to JSON file
|
||||||
|
*/
|
||||||
|
function exportSelected() {
|
||||||
|
if (selectedLines.value.size === 0) return;
|
||||||
|
|
||||||
|
const content = getSelectedContent();
|
||||||
|
downloadFile(
|
||||||
|
content,
|
||||||
|
`${selectedFile.value}-selected-${Date.now()}.json`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export all content to JSON file
|
||||||
|
*/
|
||||||
|
function exportAll() {
|
||||||
|
downloadFile(fileContent.value, `${selectedFile.value}-${Date.now()}.json`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper: Download content as file
|
||||||
|
*/
|
||||||
|
function downloadFile(content, filename) {
|
||||||
|
const blob = new Blob([content], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = filename;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share current URL (copy to clipboard)
|
||||||
|
*/
|
||||||
|
async function shareUrl() {
|
||||||
|
const url = globalThis.location.href;
|
||||||
|
await clipboard.copyToClipboard(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select all available lines
|
||||||
|
*/
|
||||||
|
function selectAll() {
|
||||||
|
displayLines.value.forEach(line => {
|
||||||
|
selectedLines.value.add(line.lineNumber);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invert selection (select all not selected, deselect all selected)
|
||||||
|
*/
|
||||||
|
function invertSelection() {
|
||||||
|
const allLineNumbers = new Set(
|
||||||
|
displayLines.value.map(line => line.lineNumber)
|
||||||
|
);
|
||||||
|
const newSelection = new Set();
|
||||||
|
|
||||||
|
allLineNumbers.forEach(lineNum => {
|
||||||
|
if (!selectedLines.value.has(lineNum)) {
|
||||||
|
newSelection.add(lineNum);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
selectedLines.value.clear();
|
||||||
|
newSelection.forEach(lineNum => selectedLines.value.add(lineNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
// State
|
||||||
|
selectedLines,
|
||||||
|
|
||||||
|
// Computed
|
||||||
|
hasSelection,
|
||||||
|
selectionCount,
|
||||||
|
selectedLineNumbers,
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
toggleLineSelection,
|
||||||
|
clearSelection,
|
||||||
|
getSelectedContent,
|
||||||
|
copySelected,
|
||||||
|
copyAll,
|
||||||
|
exportSelected,
|
||||||
|
exportAll,
|
||||||
|
shareUrl,
|
||||||
|
selectAll,
|
||||||
|
invertSelection
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,310 @@
|
|||||||
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useLineSelection } from '@/composables/useLineSelection.js';
|
||||||
|
|
||||||
|
describe('useLineSelection', () => {
|
||||||
|
let displayLines;
|
||||||
|
let fileContent;
|
||||||
|
let selectedFile;
|
||||||
|
let composable;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
displayLines = ref([
|
||||||
|
{ lineNumber: 1, content: 'line 1' },
|
||||||
|
{ lineNumber: 2, content: 'line 2' },
|
||||||
|
{ lineNumber: 3, content: 'line 3' },
|
||||||
|
{ lineNumber: 4, content: 'line 4' },
|
||||||
|
{ lineNumber: 5, content: 'line 5' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
fileContent = ref('line 1\nline 2\nline 3\nline 4\nline 5');
|
||||||
|
selectedFile = ref('test-file');
|
||||||
|
|
||||||
|
composable = useLineSelection(displayLines, fileContent, selectedFile);
|
||||||
|
|
||||||
|
// Mock clipboard
|
||||||
|
global.navigator = {
|
||||||
|
clipboard: {
|
||||||
|
writeText: vi.fn()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock URL methods
|
||||||
|
global.URL.createObjectURL = vi.fn(() => 'blob:test');
|
||||||
|
global.URL.revokeObjectURL = vi.fn();
|
||||||
|
|
||||||
|
// Mock document methods
|
||||||
|
document.body.appendChild = vi.fn();
|
||||||
|
document.body.removeChild = vi.fn();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initialization', () => {
|
||||||
|
it('should initialize with empty selection', () => {
|
||||||
|
expect(composable.selectedLines.value.size).toBe(0);
|
||||||
|
expect(composable.hasSelection.value).toBe(false);
|
||||||
|
expect(composable.selectionCount.value).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toggleLineSelection', () => {
|
||||||
|
it('should select single line with no modifiers', () => {
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
composable.toggleLineSelection(1, event);
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.has(1)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.size).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear previous selection on single click', () => {
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
composable.toggleLineSelection(1, event);
|
||||||
|
composable.toggleLineSelection(3, event);
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.has(1)).toBe(false);
|
||||||
|
expect(composable.selectedLines.value.has(3)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.size).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle line with Ctrl modifier', () => {
|
||||||
|
const ctrlEvent = { shiftKey: false, ctrlKey: true, metaKey: false };
|
||||||
|
composable.toggleLineSelection(1, ctrlEvent);
|
||||||
|
expect(composable.selectedLines.value.has(1)).toBe(true);
|
||||||
|
|
||||||
|
composable.toggleLineSelection(1, ctrlEvent);
|
||||||
|
expect(composable.selectedLines.value.has(1)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle line with Cmd modifier (Mac)', () => {
|
||||||
|
const cmdEvent = { shiftKey: false, ctrlKey: false, metaKey: true };
|
||||||
|
composable.toggleLineSelection(1, cmdEvent);
|
||||||
|
expect(composable.selectedLines.value.has(1)).toBe(true);
|
||||||
|
|
||||||
|
composable.toggleLineSelection(1, cmdEvent);
|
||||||
|
expect(composable.selectedLines.value.has(1)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add multiple lines with Ctrl', () => {
|
||||||
|
const ctrlEvent = { shiftKey: false, ctrlKey: true, metaKey: false };
|
||||||
|
composable.toggleLineSelection(1, ctrlEvent);
|
||||||
|
composable.toggleLineSelection(3, ctrlEvent);
|
||||||
|
composable.toggleLineSelection(5, ctrlEvent);
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.size).toBe(3);
|
||||||
|
expect(composable.selectedLines.value.has(1)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.has(3)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.has(5)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should select range with Shift modifier', () => {
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
const shiftEvent = { shiftKey: true, ctrlKey: false, metaKey: false };
|
||||||
|
|
||||||
|
composable.toggleLineSelection(2, event); // Set starting point
|
||||||
|
composable.toggleLineSelection(4, shiftEvent); // Select range
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.has(2)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.has(3)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.has(4)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.size).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should select range in reverse order with Shift', () => {
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
const shiftEvent = { shiftKey: true, ctrlKey: false, metaKey: false };
|
||||||
|
|
||||||
|
composable.toggleLineSelection(4, event); // Set starting point
|
||||||
|
composable.toggleLineSelection(2, shiftEvent); // Select range backwards
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.has(2)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.has(3)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.has(4)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.size).toBe(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('clearSelection', () => {
|
||||||
|
it('should clear all selections', () => {
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
composable.toggleLineSelection(1, event);
|
||||||
|
composable.toggleLineSelection(3, event);
|
||||||
|
|
||||||
|
composable.clearSelection();
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.size).toBe(0);
|
||||||
|
expect(composable.hasSelection.value).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSelectedContent', () => {
|
||||||
|
it('should return empty string when no selection', () => {
|
||||||
|
expect(composable.getSelectedContent()).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return selected lines content', () => {
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
const ctrlEvent = { shiftKey: false, ctrlKey: true, metaKey: false };
|
||||||
|
|
||||||
|
composable.toggleLineSelection(1, event);
|
||||||
|
composable.toggleLineSelection(3, ctrlEvent);
|
||||||
|
|
||||||
|
const content = composable.getSelectedContent();
|
||||||
|
expect(content).toContain('line 1');
|
||||||
|
expect(content).toContain('line 3');
|
||||||
|
expect(content).not.toContain('line 2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should maintain line order in output', () => {
|
||||||
|
const ctrlEvent = { shiftKey: false, ctrlKey: true, metaKey: false };
|
||||||
|
composable.toggleLineSelection(5, ctrlEvent);
|
||||||
|
composable.toggleLineSelection(2, ctrlEvent);
|
||||||
|
composable.toggleLineSelection(4, ctrlEvent);
|
||||||
|
|
||||||
|
const content = composable.getSelectedContent();
|
||||||
|
const lines = content.split('\n');
|
||||||
|
|
||||||
|
expect(lines[0]).toBe('line 2');
|
||||||
|
expect(lines[1]).toBe('line 4');
|
||||||
|
expect(lines[2]).toBe('line 5');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('computed properties', () => {
|
||||||
|
it('should update hasSelection', () => {
|
||||||
|
expect(composable.hasSelection.value).toBe(false);
|
||||||
|
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
composable.toggleLineSelection(1, event);
|
||||||
|
|
||||||
|
expect(composable.hasSelection.value).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update selectionCount', () => {
|
||||||
|
const ctrlEvent = { shiftKey: false, ctrlKey: true, metaKey: false };
|
||||||
|
expect(composable.selectionCount.value).toBe(0);
|
||||||
|
|
||||||
|
composable.toggleLineSelection(1, ctrlEvent);
|
||||||
|
expect(composable.selectionCount.value).toBe(1);
|
||||||
|
|
||||||
|
composable.toggleLineSelection(3, ctrlEvent);
|
||||||
|
expect(composable.selectionCount.value).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return sorted selected line numbers', () => {
|
||||||
|
const ctrlEvent = { shiftKey: false, ctrlKey: true, metaKey: false };
|
||||||
|
composable.toggleLineSelection(5, ctrlEvent);
|
||||||
|
composable.toggleLineSelection(2, ctrlEvent);
|
||||||
|
composable.toggleLineSelection(4, ctrlEvent);
|
||||||
|
|
||||||
|
expect(composable.selectedLineNumbers.value).toEqual([2, 4, 5]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('selectAll', () => {
|
||||||
|
it('should select all available lines', () => {
|
||||||
|
composable.selectAll();
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.size).toBe(5);
|
||||||
|
expect(composable.hasSelection.value).toBe(true);
|
||||||
|
for (let i = 1; i <= 5; i++) {
|
||||||
|
expect(composable.selectedLines.value.has(i)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('invertSelection', () => {
|
||||||
|
it('should invert selection', () => {
|
||||||
|
const ctrlEvent = { shiftKey: false, ctrlKey: true, metaKey: false };
|
||||||
|
composable.toggleLineSelection(2, ctrlEvent);
|
||||||
|
composable.toggleLineSelection(4, ctrlEvent);
|
||||||
|
|
||||||
|
composable.invertSelection();
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.has(1)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.has(2)).toBe(false);
|
||||||
|
expect(composable.selectedLines.value.has(3)).toBe(true);
|
||||||
|
expect(composable.selectedLines.value.has(4)).toBe(false);
|
||||||
|
expect(composable.selectedLines.value.has(5)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should invert empty selection to select all', () => {
|
||||||
|
composable.invertSelection();
|
||||||
|
|
||||||
|
expect(composable.selectedLines.value.size).toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('copySelected', () => {
|
||||||
|
it('should not copy if no selection', async () => {
|
||||||
|
await composable.copySelected();
|
||||||
|
expect(global.navigator.clipboard.writeText).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should copy selected lines', async () => {
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
composable.toggleLineSelection(1, event);
|
||||||
|
|
||||||
|
await composable.copySelected();
|
||||||
|
|
||||||
|
expect(global.navigator.clipboard.writeText).toHaveBeenCalledWith(
|
||||||
|
'line 1'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('copyAll', () => {
|
||||||
|
it('should copy all content', async () => {
|
||||||
|
await composable.copyAll();
|
||||||
|
|
||||||
|
expect(global.navigator.clipboard.writeText).toHaveBeenCalledWith(
|
||||||
|
fileContent.value
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('exportSelected', () => {
|
||||||
|
it('should not export if no selection', () => {
|
||||||
|
const createElementSpy = vi.spyOn(document, 'createElement');
|
||||||
|
composable.exportSelected();
|
||||||
|
expect(createElementSpy).not.toHaveBeenCalledWith('a');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should export selected lines as file', () => {
|
||||||
|
const event = { shiftKey: false, ctrlKey: false, metaKey: false };
|
||||||
|
const ctrlEvent = { shiftKey: false, ctrlKey: true, metaKey: false };
|
||||||
|
|
||||||
|
composable.toggleLineSelection(1, event);
|
||||||
|
composable.toggleLineSelection(3, ctrlEvent);
|
||||||
|
|
||||||
|
const createElementSpy = vi.spyOn(document, 'createElement');
|
||||||
|
composable.exportSelected();
|
||||||
|
|
||||||
|
const linkElement = createElementSpy.mock.results.find(
|
||||||
|
r => r.value?.click
|
||||||
|
)?.value;
|
||||||
|
expect(linkElement?.download).toContain('test-file-selected');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('exportAll', () => {
|
||||||
|
it('should export all content as file', () => {
|
||||||
|
const createElementSpy = vi.spyOn(document, 'createElement');
|
||||||
|
composable.exportAll();
|
||||||
|
|
||||||
|
const linkElement = createElementSpy.mock.results.find(
|
||||||
|
r => r.value?.click
|
||||||
|
)?.value;
|
||||||
|
expect(linkElement?.download).toContain('test-file');
|
||||||
|
expect(linkElement?.download).not.toContain('selected');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('shareUrl', () => {
|
||||||
|
it('should copy current URL to clipboard', async () => {
|
||||||
|
await composable.shareUrl();
|
||||||
|
|
||||||
|
expect(global.navigator.clipboard.writeText).toHaveBeenCalled();
|
||||||
|
const call = global.navigator.clipboard.writeText.mock.calls[0][0];
|
||||||
|
expect(call).toContain(globalThis.location.href || '');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// vitest.config.js
|
||||||
|
import { defineConfig } from "file:///Users/fragginwagon/Developer/MemoryPalace/code/websites/pokedex.online/node_modules/vitest/dist/config.js";
|
||||||
|
import vue from "file:///Users/fragginwagon/Developer/MemoryPalace/code/websites/pokedex.online/node_modules/@vitejs/plugin-vue/dist/index.mjs";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
var __vite_injected_original_import_meta_url = "file:///Users/fragginwagon/Developer/MemoryPalace/code/websites/pokedex.online/vitest.config.js";
|
||||||
|
var vitest_config_default = defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@": fileURLToPath(new URL("./src", __vite_injected_original_import_meta_url))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: "happy-dom",
|
||||||
|
setupFiles: ["./tests/setup.js"],
|
||||||
|
coverage: {
|
||||||
|
provider: "v8",
|
||||||
|
reporter: ["text", "json", "html", "lcov"],
|
||||||
|
exclude: [
|
||||||
|
"node_modules/",
|
||||||
|
"tests/",
|
||||||
|
"dist/",
|
||||||
|
"server/",
|
||||||
|
"*.config.js",
|
||||||
|
".eslintrc.cjs"
|
||||||
|
],
|
||||||
|
thresholds: {
|
||||||
|
lines: 80,
|
||||||
|
functions: 80,
|
||||||
|
branches: 75,
|
||||||
|
statements: 80
|
||||||
|
}
|
||||||
|
},
|
||||||
|
include: ["tests/**/*.test.js", "tests/**/*.spec.js"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
export {
|
||||||
|
vitest_config_default as default
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZXN0LmNvbmZpZy5qcyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9Vc2Vycy9mcmFnZ2lud2Fnb24vRGV2ZWxvcGVyL01lbW9yeVBhbGFjZS9jb2RlL3dlYnNpdGVzL3Bva2VkZXgub25saW5lXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvVXNlcnMvZnJhZ2dpbndhZ29uL0RldmVsb3Blci9NZW1vcnlQYWxhY2UvY29kZS93ZWJzaXRlcy9wb2tlZGV4Lm9ubGluZS92aXRlc3QuY29uZmlnLmpzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9mcmFnZ2lud2Fnb24vRGV2ZWxvcGVyL01lbW9yeVBhbGFjZS9jb2RlL3dlYnNpdGVzL3Bva2VkZXgub25saW5lL3ZpdGVzdC5jb25maWcuanNcIjtpbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlc3QvY29uZmlnJztcbmltcG9ydCB2dWUgZnJvbSAnQHZpdGVqcy9wbHVnaW4tdnVlJztcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICdub2RlOnVybCc7XG5cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG4gIHBsdWdpbnM6IFt2dWUoKV0sXG4gIHJlc29sdmU6IHtcbiAgICBhbGlhczoge1xuICAgICAgJ0AnOiBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4vc3JjJywgaW1wb3J0Lm1ldGEudXJsKSlcbiAgICB9XG4gIH0sXG4gIHRlc3Q6IHtcbiAgICBnbG9iYWxzOiB0cnVlLFxuICAgIGVudmlyb25tZW50OiAnaGFwcHktZG9tJyxcbiAgICBzZXR1cEZpbGVzOiBbJy4vdGVzdHMvc2V0dXAuanMnXSxcbiAgICBjb3ZlcmFnZToge1xuICAgICAgcHJvdmlkZXI6ICd2OCcsXG4gICAgICByZXBvcnRlcjogWyd0ZXh0JywgJ2pzb24nLCAnaHRtbCcsICdsY292J10sXG4gICAgICBleGNsdWRlOiBbXG4gICAgICAgICdub2RlX21vZHVsZXMvJyxcbiAgICAgICAgJ3Rlc3RzLycsXG4gICAgICAgICdkaXN0LycsXG4gICAgICAgICdzZXJ2ZXIvJyxcbiAgICAgICAgJyouY29uZmlnLmpzJyxcbiAgICAgICAgJy5lc2xpbnRyYy5janMnXG4gICAgICBdLFxuICAgICAgdGhyZXNob2xkczoge1xuICAgICAgICBsaW5lczogODAsXG4gICAgICAgIGZ1bmN0aW9uczogODAsXG4gICAgICAgIGJyYW5jaGVzOiA3NSxcbiAgICAgICAgc3RhdGVtZW50czogODBcbiAgICAgIH1cbiAgICB9LFxuICAgIGluY2x1ZGU6IFsndGVzdHMvKiovKi50ZXN0LmpzJywgJ3Rlc3RzLyoqLyouc3BlYy5qcyddXG4gIH1cbn0pO1xuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUEyWSxTQUFTLG9CQUFvQjtBQUN4YSxPQUFPLFNBQVM7QUFDaEIsU0FBUyxxQkFBcUI7QUFGME4sSUFBTSwyQ0FBMkM7QUFJelMsSUFBTyx3QkFBUSxhQUFhO0FBQUEsRUFDMUIsU0FBUyxDQUFDLElBQUksQ0FBQztBQUFBLEVBQ2YsU0FBUztBQUFBLElBQ1AsT0FBTztBQUFBLE1BQ0wsS0FBSyxjQUFjLElBQUksSUFBSSxTQUFTLHdDQUFlLENBQUM7QUFBQSxJQUN0RDtBQUFBLEVBQ0Y7QUFBQSxFQUNBLE1BQU07QUFBQSxJQUNKLFNBQVM7QUFBQSxJQUNULGFBQWE7QUFBQSxJQUNiLFlBQVksQ0FBQyxrQkFBa0I7QUFBQSxJQUMvQixVQUFVO0FBQUEsTUFDUixVQUFVO0FBQUEsTUFDVixVQUFVLENBQUMsUUFBUSxRQUFRLFFBQVEsTUFBTTtBQUFBLE1BQ3pDLFNBQVM7QUFBQSxRQUNQO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxRQUNBO0FBQUEsUUFDQTtBQUFBLFFBQ0E7QUFBQSxNQUNGO0FBQUEsTUFDQSxZQUFZO0FBQUEsUUFDVixPQUFPO0FBQUEsUUFDUCxXQUFXO0FBQUEsUUFDWCxVQUFVO0FBQUEsUUFDVixZQUFZO0FBQUEsTUFDZDtBQUFBLElBQ0Y7QUFBQSxJQUNBLFNBQVMsQ0FBQyxzQkFBc0Isb0JBQW9CO0FBQUEsRUFDdEQ7QUFDRixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo=
|
||||||
Reference in New Issue
Block a user