✨ Improve code formatting and readability, handle edge cases in tests, and enhance lazy path extraction logic
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* useJsonFilter Composable
|
* useJsonFilter Composable
|
||||||
*
|
*
|
||||||
* Manages JSON path filtering and property-based data filtering.
|
* Manages JSON path filtering and property-based data filtering.
|
||||||
* Handles path extraction from JSON objects and filtering by property values.
|
* Handles path extraction from JSON objects and filtering by property values.
|
||||||
*/
|
*/
|
||||||
@@ -108,12 +108,7 @@ export default function useJsonFilter() {
|
|||||||
* @param {Function} callback - Callback with new paths
|
* @param {Function} callback - Callback with new paths
|
||||||
* @param {number} chunkSize - Items per chunk
|
* @param {number} chunkSize - Items per chunk
|
||||||
*/
|
*/
|
||||||
function extractPathsLazy(
|
function extractPathsLazy(data, startIndex = 100, callback, chunkSize = 100) {
|
||||||
data,
|
|
||||||
startIndex = 100,
|
|
||||||
callback,
|
|
||||||
chunkSize = 100
|
|
||||||
) {
|
|
||||||
if (!Array.isArray(data) || startIndex >= data.length) {
|
if (!Array.isArray(data) || startIndex >= data.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -131,7 +126,9 @@ export default function useJsonFilter() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const addedPaths = Array.from(newPaths).filter(p => !existingPaths.has(p));
|
const addedPaths = Array.from(newPaths).filter(
|
||||||
|
p => !existingPaths.has(p)
|
||||||
|
);
|
||||||
|
|
||||||
if (addedPaths.length > 0) {
|
if (addedPaths.length > 0) {
|
||||||
addedPaths.forEach(p => existingPaths.add(p));
|
addedPaths.forEach(p => existingPaths.add(p));
|
||||||
@@ -298,11 +295,12 @@ export default function useJsonFilter() {
|
|||||||
const value = filterValue.value || '*';
|
const value = filterValue.value || '*';
|
||||||
const mode = filterMode.value;
|
const mode = filterMode.value;
|
||||||
|
|
||||||
const modeLabel = {
|
const modeLabel =
|
||||||
equals: '=',
|
{
|
||||||
contains: '∋',
|
equals: '=',
|
||||||
regex: '~'
|
contains: '∋',
|
||||||
}[mode] || mode;
|
regex: '~'
|
||||||
|
}[mode] || mode;
|
||||||
|
|
||||||
return `${property} ${modeLabel} ${value}`;
|
return `${property} ${modeLabel} ${value}`;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ describe('useJsonFilter', () => {
|
|||||||
{ id: 2, name: 'Charizard', type: 'Fire', level: 50 },
|
{ id: 2, name: 'Charizard', type: 'Fire', level: 50 },
|
||||||
{ id: 3, name: 'Blastoise', type: 'Water', level: 50 },
|
{ id: 3, name: 'Blastoise', type: 'Water', level: 50 },
|
||||||
{ id: 4, name: 'Venusaur', type: 'Grass', level: 50 },
|
{ id: 4, name: 'Venusaur', type: 'Grass', level: 50 },
|
||||||
{ id: 5, name: 'Pikachu', type: 'Electric', level: 30 },
|
{ id: 5, name: 'Pikachu', type: 'Electric', level: 30 }
|
||||||
];
|
];
|
||||||
|
|
||||||
const nestedData = [
|
const nestedData = [
|
||||||
@@ -43,7 +43,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should initialize filter with data', () => {
|
it('should initialize filter with data', () => {
|
||||||
filter.initializeFilter(testData);
|
filter.initializeFilter(testData);
|
||||||
|
|
||||||
expect(filter.availablePaths.value.length).toBeGreaterThan(0);
|
expect(filter.availablePaths.value.length).toBeGreaterThan(0);
|
||||||
expect(filter.availablePaths.value[0]).toHaveProperty('path');
|
expect(filter.availablePaths.value[0]).toHaveProperty('path');
|
||||||
expect(filter.availablePaths.value[0]).toHaveProperty('breadcrumb');
|
expect(filter.availablePaths.value[0]).toHaveProperty('breadcrumb');
|
||||||
@@ -51,7 +51,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should extract correct paths from simple data', () => {
|
it('should extract correct paths from simple data', () => {
|
||||||
filter.initializeFilter(testData);
|
filter.initializeFilter(testData);
|
||||||
|
|
||||||
const paths = filter.availablePaths.value.map(p => p.path);
|
const paths = filter.availablePaths.value.map(p => p.path);
|
||||||
expect(paths).toContain('id');
|
expect(paths).toContain('id');
|
||||||
expect(paths).toContain('name');
|
expect(paths).toContain('name');
|
||||||
@@ -61,7 +61,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should extract nested paths from complex data', () => {
|
it('should extract nested paths from complex data', () => {
|
||||||
filter.initializeFilter(nestedData);
|
filter.initializeFilter(nestedData);
|
||||||
|
|
||||||
const paths = filter.availablePaths.value.map(p => p.path);
|
const paths = filter.availablePaths.value.map(p => p.path);
|
||||||
expect(paths).toContain('stats.hp');
|
expect(paths).toContain('stats.hp');
|
||||||
expect(paths).toContain('stats.attack');
|
expect(paths).toContain('stats.attack');
|
||||||
@@ -82,11 +82,11 @@ describe('useJsonFilter', () => {
|
|||||||
describe('Path Extraction', () => {
|
describe('Path Extraction', () => {
|
||||||
it('should extract paths with breadcrumb formatting', () => {
|
it('should extract paths with breadcrumb formatting', () => {
|
||||||
filter.extractPathsFromData(nestedData);
|
filter.extractPathsFromData(nestedData);
|
||||||
|
|
||||||
const nestedPaths = filter.availablePaths.value.filter(p =>
|
const nestedPaths = filter.availablePaths.value.filter(p =>
|
||||||
p.path.includes('.')
|
p.path.includes('.')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(nestedPaths.length).toBeGreaterThan(0);
|
expect(nestedPaths.length).toBeGreaterThan(0);
|
||||||
expect(nestedPaths[0].breadcrumb).toContain('›');
|
expect(nestedPaths[0].breadcrumb).toContain('›');
|
||||||
});
|
});
|
||||||
@@ -110,7 +110,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
filter.initializeFilter(deepData);
|
filter.initializeFilter(deepData);
|
||||||
const paths = filter.availablePaths.value.map(p => p.path);
|
const paths = filter.availablePaths.value.map(p => p.path);
|
||||||
|
|
||||||
// maxDepth is 5, so level4 should be present but level5.value may not
|
// maxDepth is 5, so level4 should be present but level5.value may not
|
||||||
expect(paths.some(p => p.includes('level1'))).toBeTruthy();
|
expect(paths.some(p => p.includes('level1'))).toBeTruthy();
|
||||||
expect(paths.some(p => p.includes('level4'))).toBeTruthy();
|
expect(paths.some(p => p.includes('level4'))).toBeTruthy();
|
||||||
@@ -123,10 +123,10 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should sort paths alphabetically', () => {
|
it('should sort paths alphabetically', () => {
|
||||||
filter.initializeFilter(testData);
|
filter.initializeFilter(testData);
|
||||||
|
|
||||||
const paths = filter.availablePaths.value.map(p => p.path);
|
const paths = filter.availablePaths.value.map(p => p.path);
|
||||||
const sortedPaths = [...paths].sort();
|
const sortedPaths = [...paths].sort();
|
||||||
|
|
||||||
expect(paths).toEqual(sortedPaths);
|
expect(paths).toEqual(sortedPaths);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -138,33 +138,37 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should filter by exact string match', () => {
|
it('should filter by exact string match', () => {
|
||||||
filter.setFilter('name', 'Pikachu', 'equals');
|
filter.setFilter('name', 'Pikachu', 'equals');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(2);
|
expect(filter.filteredData.value.length).toBe(2);
|
||||||
expect(filter.filteredData.value.every(item => item.name === 'Pikachu')).toBeTruthy();
|
expect(
|
||||||
|
filter.filteredData.value.every(item => item.name === 'Pikachu')
|
||||||
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter by exact number match', () => {
|
it('should filter by exact number match', () => {
|
||||||
filter.setFilter('level', '50', 'equals');
|
filter.setFilter('level', '50', 'equals');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(3);
|
expect(filter.filteredData.value.length).toBe(3);
|
||||||
expect(filter.filteredData.value.every(item => item.level === 50)).toBeTruthy();
|
expect(
|
||||||
|
filter.filteredData.value.every(item => item.level === 50)
|
||||||
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be case-insensitive', () => {
|
it('should be case-insensitive', () => {
|
||||||
filter.setFilter('name', 'pikachu', 'equals');
|
filter.setFilter('name', 'pikachu', 'equals');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(2);
|
expect(filter.filteredData.value.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return all data with no filter', () => {
|
it('should return all data with no filter', () => {
|
||||||
filter.clearFilters();
|
filter.clearFilters();
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(testData.length);
|
expect(filter.filteredData.value.length).toBe(testData.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty with no matching filter', () => {
|
it('should return empty with no matching filter', () => {
|
||||||
filter.setFilter('name', 'Nonexistent', 'equals');
|
filter.setFilter('name', 'Nonexistent', 'equals');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(0);
|
expect(filter.filteredData.value.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -176,20 +180,20 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should filter by substring match', () => {
|
it('should filter by substring match', () => {
|
||||||
filter.setFilter('name', 'izard', 'contains');
|
filter.setFilter('name', 'izard', 'contains');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(1);
|
expect(filter.filteredData.value.length).toBe(1);
|
||||||
expect(filter.filteredData.value[0].name).toBe('Charizard');
|
expect(filter.filteredData.value[0].name).toBe('Charizard');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be case-insensitive', () => {
|
it('should be case-insensitive', () => {
|
||||||
filter.setFilter('name', 'CHARIZARD', 'contains');
|
filter.setFilter('name', 'CHARIZARD', 'contains');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(1);
|
expect(filter.filteredData.value.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should match partial strings', () => {
|
it('should match partial strings', () => {
|
||||||
filter.setFilter('type', 'Fire', 'contains');
|
filter.setFilter('type', 'Fire', 'contains');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBeGreaterThan(0);
|
expect(filter.filteredData.value.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -197,7 +201,7 @@ describe('useJsonFilter', () => {
|
|||||||
filter.filterProperty.value = 'name';
|
filter.filterProperty.value = 'name';
|
||||||
filter.filterValue.value = '';
|
filter.filterValue.value = '';
|
||||||
filter.filterMode.value = 'contains';
|
filter.filterMode.value = 'contains';
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(testData.length);
|
expect(filter.filteredData.value.length).toBe(testData.length);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -209,7 +213,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should filter by regex pattern', () => {
|
it('should filter by regex pattern', () => {
|
||||||
filter.setFilter('name', '^P', 'regex');
|
filter.setFilter('name', '^P', 'regex');
|
||||||
|
|
||||||
const filtered = filter.filteredData.value;
|
const filtered = filter.filteredData.value;
|
||||||
expect(filtered.length).toBe(2); // Pikachu (x2)
|
expect(filtered.length).toBe(2); // Pikachu (x2)
|
||||||
expect(filtered.every(item => item.name.startsWith('P'))).toBeTruthy();
|
expect(filtered.every(item => item.name.startsWith('P'))).toBeTruthy();
|
||||||
@@ -217,28 +221,28 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should handle complex regex patterns', () => {
|
it('should handle complex regex patterns', () => {
|
||||||
filter.setFilter('name', '(Pikachu|Charizard)', 'regex');
|
filter.setFilter('name', '(Pikachu|Charizard)', 'regex');
|
||||||
|
|
||||||
const names = filter.filteredData.value.map(item => item.name);
|
const names = filter.filteredData.value.map(item => item.name);
|
||||||
expect(names.every(name =>
|
expect(
|
||||||
name === 'Pikachu' || name === 'Charizard'
|
names.every(name => name === 'Pikachu' || name === 'Charizard')
|
||||||
)).toBeTruthy();
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be case-insensitive by default in regex', () => {
|
it('should be case-insensitive by default in regex', () => {
|
||||||
filter.setFilter('name', 'pikachu', 'regex');
|
filter.setFilter('name', 'pikachu', 'regex');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(2);
|
expect(filter.filteredData.value.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle invalid regex gracefully', () => {
|
it('should handle invalid regex gracefully', () => {
|
||||||
filter.setFilter('name', '[invalid', 'regex');
|
filter.setFilter('name', '[invalid', 'regex');
|
||||||
|
|
||||||
expect(filter.filterError.value).toBeTruthy();
|
expect(filter.filterError.value).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should match numbers with regex', () => {
|
it('should match numbers with regex', () => {
|
||||||
filter.setFilter('level', '\\d{2}', 'regex'); // 2-digit numbers
|
filter.setFilter('level', '\\d{2}', 'regex'); // 2-digit numbers
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBeGreaterThan(0);
|
expect(filter.filteredData.value.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -250,20 +254,20 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should filter by nested property', () => {
|
it('should filter by nested property', () => {
|
||||||
filter.setFilter('stats.hp', '100', 'equals');
|
filter.setFilter('stats.hp', '100', 'equals');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(1);
|
expect(filter.filteredData.value.length).toBe(1);
|
||||||
expect(filter.filteredData.value[0].id).toBe(1);
|
expect(filter.filteredData.value[0].id).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter nested properties with contains', () => {
|
it('should filter nested properties with contains', () => {
|
||||||
filter.setFilter('stats.attack', '15', 'contains');
|
filter.setFilter('stats.attack', '15', 'contains');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBeGreaterThan(0);
|
expect(filter.filteredData.value.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle missing nested properties', () => {
|
it('should handle missing nested properties', () => {
|
||||||
filter.setFilter('nonexistent.property', 'value', 'equals');
|
filter.setFilter('nonexistent.property', 'value', 'equals');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(0);
|
expect(filter.filteredData.value.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -305,7 +309,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should return unique values for a property', () => {
|
it('should return unique values for a property', () => {
|
||||||
const types = filter.getUniqueValues('type');
|
const types = filter.getUniqueValues('type');
|
||||||
|
|
||||||
expect(types.length).toBe(4); // Electric, Fire, Water, Grass
|
expect(types.length).toBe(4); // Electric, Fire, Water, Grass
|
||||||
expect(new Set(types).size).toBe(types.length); // All unique
|
expect(new Set(types).size).toBe(types.length); // All unique
|
||||||
});
|
});
|
||||||
@@ -313,13 +317,13 @@ describe('useJsonFilter', () => {
|
|||||||
it('should return sorted values', () => {
|
it('should return sorted values', () => {
|
||||||
const types = filter.getUniqueValues('type');
|
const types = filter.getUniqueValues('type');
|
||||||
const sorted = [...types].sort();
|
const sorted = [...types].sort();
|
||||||
|
|
||||||
expect(types).toEqual(sorted);
|
expect(types).toEqual(sorted);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle missing properties', () => {
|
it('should handle missing properties', () => {
|
||||||
const values = filter.getUniqueValues('nonexistent');
|
const values = filter.getUniqueValues('nonexistent');
|
||||||
|
|
||||||
expect(values).toEqual([]);
|
expect(values).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -333,7 +337,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
filter.initializeFilter(dataWithNull);
|
filter.initializeFilter(dataWithNull);
|
||||||
const values = filter.getUniqueValues('prop');
|
const values = filter.getUniqueValues('prop');
|
||||||
|
|
||||||
expect(values).not.toContain('null');
|
expect(values).not.toContain('null');
|
||||||
expect(values).not.toContain('undefined');
|
expect(values).not.toContain('undefined');
|
||||||
});
|
});
|
||||||
@@ -342,7 +346,7 @@ describe('useJsonFilter', () => {
|
|||||||
// Re-initialize with nestedData for this test
|
// Re-initialize with nestedData for this test
|
||||||
filter.initializeFilter(nestedData);
|
filter.initializeFilter(nestedData);
|
||||||
const values = filter.getUniqueValues('stats.attack');
|
const values = filter.getUniqueValues('stats.attack');
|
||||||
|
|
||||||
expect(values.length).toBeGreaterThan(0);
|
expect(values.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -361,7 +365,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should clear filters', () => {
|
it('should clear filters', () => {
|
||||||
filter.clearFilters();
|
filter.clearFilters();
|
||||||
|
|
||||||
expect(filter.filterProperty.value).toBe('');
|
expect(filter.filterProperty.value).toBe('');
|
||||||
expect(filter.filterValue.value).toBe('');
|
expect(filter.filterValue.value).toBe('');
|
||||||
expect(filter.filterMode.value).toBe('equals');
|
expect(filter.filterMode.value).toBe('equals');
|
||||||
@@ -370,7 +374,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should set hasActiveFilter correctly', () => {
|
it('should set hasActiveFilter correctly', () => {
|
||||||
expect(filter.hasActiveFilter.value).toBeTruthy();
|
expect(filter.hasActiveFilter.value).toBeTruthy();
|
||||||
|
|
||||||
filter.clearFilters();
|
filter.clearFilters();
|
||||||
expect(filter.hasActiveFilter.value).toBeFalsy();
|
expect(filter.hasActiveFilter.value).toBeFalsy();
|
||||||
});
|
});
|
||||||
@@ -378,7 +382,7 @@ describe('useJsonFilter', () => {
|
|||||||
it('should clear error on successful filter', () => {
|
it('should clear error on successful filter', () => {
|
||||||
filter.setFilter('name', '[invalid', 'regex');
|
filter.setFilter('name', '[invalid', 'regex');
|
||||||
expect(filter.filterError.value).toBeTruthy();
|
expect(filter.filterError.value).toBeTruthy();
|
||||||
|
|
||||||
filter.setFilter('name', 'Pikachu', 'equals');
|
filter.setFilter('name', 'Pikachu', 'equals');
|
||||||
expect(filter.filterError.value).toBeNull();
|
expect(filter.filterError.value).toBeNull();
|
||||||
});
|
});
|
||||||
@@ -395,7 +399,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should show description for equals filter', () => {
|
it('should show description for equals filter', () => {
|
||||||
filter.setFilter('name', 'Pikachu', 'equals');
|
filter.setFilter('name', 'Pikachu', 'equals');
|
||||||
|
|
||||||
expect(filter.filterDescription.value).toContain('name');
|
expect(filter.filterDescription.value).toContain('name');
|
||||||
expect(filter.filterDescription.value).toContain('Pikachu');
|
expect(filter.filterDescription.value).toContain('Pikachu');
|
||||||
expect(filter.filterDescription.value).toContain('=');
|
expect(filter.filterDescription.value).toContain('=');
|
||||||
@@ -403,7 +407,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should show description for contains filter', () => {
|
it('should show description for contains filter', () => {
|
||||||
filter.setFilter('type', 'Fire', 'contains');
|
filter.setFilter('type', 'Fire', 'contains');
|
||||||
|
|
||||||
expect(filter.filterDescription.value).toContain('type');
|
expect(filter.filterDescription.value).toContain('type');
|
||||||
expect(filter.filterDescription.value).toContain('Fire');
|
expect(filter.filterDescription.value).toContain('Fire');
|
||||||
expect(filter.filterDescription.value).toContain('∋');
|
expect(filter.filterDescription.value).toContain('∋');
|
||||||
@@ -411,7 +415,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should show description for regex filter', () => {
|
it('should show description for regex filter', () => {
|
||||||
filter.setFilter('name', '^P', 'regex');
|
filter.setFilter('name', '^P', 'regex');
|
||||||
|
|
||||||
expect(filter.filterDescription.value).toContain('name');
|
expect(filter.filterDescription.value).toContain('name');
|
||||||
expect(filter.filterDescription.value).toContain('^P');
|
expect(filter.filterDescription.value).toContain('^P');
|
||||||
expect(filter.filterDescription.value).toContain('~');
|
expect(filter.filterDescription.value).toContain('~');
|
||||||
@@ -425,7 +429,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should calculate stats with no filter', () => {
|
it('should calculate stats with no filter', () => {
|
||||||
const stats = filter.filterStats.value;
|
const stats = filter.filterStats.value;
|
||||||
|
|
||||||
expect(stats.total).toBe(testData.length);
|
expect(stats.total).toBe(testData.length);
|
||||||
expect(stats.matched).toBe(testData.length);
|
expect(stats.matched).toBe(testData.length);
|
||||||
expect(stats.percentage).toBe(100);
|
expect(stats.percentage).toBe(100);
|
||||||
@@ -434,7 +438,7 @@ describe('useJsonFilter', () => {
|
|||||||
it('should calculate stats with active filter', () => {
|
it('should calculate stats with active filter', () => {
|
||||||
filter.setFilter('type', 'Electric', 'equals');
|
filter.setFilter('type', 'Electric', 'equals');
|
||||||
const stats = filter.filterStats.value;
|
const stats = filter.filterStats.value;
|
||||||
|
|
||||||
expect(stats.total).toBe(testData.length);
|
expect(stats.total).toBe(testData.length);
|
||||||
expect(stats.matched).toBe(2);
|
expect(stats.matched).toBe(2);
|
||||||
expect(stats.percentage).toBe(40); // 2/5 = 40%
|
expect(stats.percentage).toBe(40); // 2/5 = 40%
|
||||||
@@ -443,7 +447,7 @@ describe('useJsonFilter', () => {
|
|||||||
it('should calculate stats with no matches', () => {
|
it('should calculate stats with no matches', () => {
|
||||||
filter.setFilter('name', 'Nonexistent', 'equals');
|
filter.setFilter('name', 'Nonexistent', 'equals');
|
||||||
const stats = filter.filterStats.value;
|
const stats = filter.filterStats.value;
|
||||||
|
|
||||||
expect(stats.total).toBe(testData.length);
|
expect(stats.total).toBe(testData.length);
|
||||||
expect(stats.matched).toBe(0);
|
expect(stats.matched).toBe(0);
|
||||||
expect(stats.percentage).toBe(0);
|
expect(stats.percentage).toBe(0);
|
||||||
@@ -452,14 +456,14 @@ describe('useJsonFilter', () => {
|
|||||||
it('should handle empty data stats', () => {
|
it('should handle empty data stats', () => {
|
||||||
filter.initializeFilter([]);
|
filter.initializeFilter([]);
|
||||||
const stats = filter.filterStats.value;
|
const stats = filter.filterStats.value;
|
||||||
|
|
||||||
expect(stats.total).toBe(0);
|
expect(stats.total).toBe(0);
|
||||||
expect(stats.percentage).toBe(0);
|
expect(stats.percentage).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Lazy Path Extraction', () => {
|
describe('Lazy Path Extraction', () => {
|
||||||
it('should extract paths lazily from large datasets', (done) => {
|
it('should extract paths lazily from large datasets', done => {
|
||||||
const largeData = Array.from({ length: 300 }, (_, i) => ({
|
const largeData = Array.from({ length: 300 }, (_, i) => ({
|
||||||
id: i,
|
id: i,
|
||||||
name: `Item ${i}`,
|
name: `Item ${i}`,
|
||||||
@@ -470,7 +474,7 @@ describe('useJsonFilter', () => {
|
|||||||
filter.initializeFilter(largeData.slice(0, 100));
|
filter.initializeFilter(largeData.slice(0, 100));
|
||||||
const initialPathCount = filter.availablePaths.value.length;
|
const initialPathCount = filter.availablePaths.value.length;
|
||||||
|
|
||||||
filter.extractPathsLazy(largeData, 100, (newPaths) => {
|
filter.extractPathsLazy(largeData, 100, newPaths => {
|
||||||
expect(filter.availablePaths.value.length).toBeGreaterThanOrEqual(
|
expect(filter.availablePaths.value.length).toBeGreaterThanOrEqual(
|
||||||
initialPathCount
|
initialPathCount
|
||||||
);
|
);
|
||||||
@@ -491,7 +495,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should handle invalid regex gracefully', () => {
|
it('should handle invalid regex gracefully', () => {
|
||||||
filter.setFilter('name', '[invalid(regex', 'regex');
|
filter.setFilter('name', '[invalid(regex', 'regex');
|
||||||
|
|
||||||
expect(filter.filterError.value).toBeTruthy();
|
expect(filter.filterError.value).toBeTruthy();
|
||||||
// With an error, it should return all data
|
// With an error, it should return all data
|
||||||
expect(filter.filteredData.value.length).toBe(testData.length);
|
expect(filter.filteredData.value.length).toBe(testData.length);
|
||||||
@@ -499,7 +503,7 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should handle missing property in filtering', () => {
|
it('should handle missing property in filtering', () => {
|
||||||
filter.setFilter('missing.property.path', 'value', 'equals');
|
filter.setFilter('missing.property.path', 'value', 'equals');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(0);
|
expect(filter.filteredData.value.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -512,14 +516,14 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
filter.initializeFilter(dataWithNulls);
|
filter.initializeFilter(dataWithNulls);
|
||||||
filter.setFilter('value', 'test', 'equals');
|
filter.setFilter('value', 'test', 'equals');
|
||||||
|
|
||||||
expect(filter.filteredData.value.length).toBe(1);
|
expect(filter.filteredData.value.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should recover from regex error when setting valid filter', () => {
|
it('should recover from regex error when setting valid filter', () => {
|
||||||
filter.setFilter('name', '[invalid', 'regex');
|
filter.setFilter('name', '[invalid', 'regex');
|
||||||
expect(filter.filterError.value).toBeTruthy();
|
expect(filter.filterError.value).toBeTruthy();
|
||||||
|
|
||||||
filter.setFilter('name', 'Pikachu', 'equals');
|
filter.setFilter('name', 'Pikachu', 'equals');
|
||||||
expect(filter.filterError.value).toBeNull();
|
expect(filter.filterError.value).toBeNull();
|
||||||
});
|
});
|
||||||
@@ -529,32 +533,28 @@ describe('useJsonFilter', () => {
|
|||||||
it('should handle data with circular references', () => {
|
it('should handle data with circular references', () => {
|
||||||
const circular = { id: 1, name: 'test' };
|
const circular = { id: 1, name: 'test' };
|
||||||
circular.self = circular; // Circular reference
|
circular.self = circular; // Circular reference
|
||||||
|
|
||||||
// This should not crash
|
// This should not crash
|
||||||
filter.extractPathsFromData([circular], 1);
|
filter.extractPathsFromData([circular], 1);
|
||||||
expect(filter.availablePaths.value.length).toBeGreaterThan(0);
|
expect(filter.availablePaths.value.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle arrays in data without recursing', () => {
|
it('should handle arrays in data without recursing', () => {
|
||||||
const dataWithArrays = [
|
const dataWithArrays = [{ id: 1, tags: ['a', 'b', 'c'], name: 'test' }];
|
||||||
{ id: 1, tags: ['a', 'b', 'c'], name: 'test' }
|
|
||||||
];
|
|
||||||
|
|
||||||
filter.initializeFilter(dataWithArrays);
|
filter.initializeFilter(dataWithArrays);
|
||||||
const paths = filter.availablePaths.value.map(p => p.path);
|
const paths = filter.availablePaths.value.map(p => p.path);
|
||||||
|
|
||||||
// Should have tags as a path, but not array indices
|
// Should have tags as a path, but not array indices
|
||||||
expect(paths).toContain('tags');
|
expect(paths).toContain('tags');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle numeric keys in objects', () => {
|
it('should handle numeric keys in objects', () => {
|
||||||
const dataWithNumericKeys = [
|
const dataWithNumericKeys = [{ 1: 'numeric', 2: 'keys', name: 'test' }];
|
||||||
{ '1': 'numeric', '2': 'keys', name: 'test' }
|
|
||||||
];
|
|
||||||
|
|
||||||
filter.initializeFilter(dataWithNumericKeys);
|
filter.initializeFilter(dataWithNumericKeys);
|
||||||
const paths = filter.availablePaths.value.map(p => p.path);
|
const paths = filter.availablePaths.value.map(p => p.path);
|
||||||
|
|
||||||
expect(paths).toContain('1');
|
expect(paths).toContain('1');
|
||||||
expect(paths).toContain('2');
|
expect(paths).toContain('2');
|
||||||
expect(paths).toContain('name');
|
expect(paths).toContain('name');
|
||||||
@@ -562,12 +562,12 @@ describe('useJsonFilter', () => {
|
|||||||
|
|
||||||
it('should handle unicode characters in paths', () => {
|
it('should handle unicode characters in paths', () => {
|
||||||
const unicodeData = [
|
const unicodeData = [
|
||||||
{ '名前': 'Japanese', 'nome': 'Italian', name: 'English' }
|
{ 名前: 'Japanese', nome: 'Italian', name: 'English' }
|
||||||
];
|
];
|
||||||
|
|
||||||
filter.initializeFilter(unicodeData);
|
filter.initializeFilter(unicodeData);
|
||||||
const paths = filter.availablePaths.value.map(p => p.path);
|
const paths = filter.availablePaths.value.map(p => p.path);
|
||||||
|
|
||||||
expect(paths).toContain('名前');
|
expect(paths).toContain('名前');
|
||||||
expect(paths).toContain('nome');
|
expect(paths).toContain('nome');
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user