From ad00a91ca42b462ff77c6e4c9e09e0d9c30bfed1 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Sun, 10 Aug 2025 08:40:05 +0800 Subject: [PATCH 01/10] test: add `__test__` folder --- .../devtools-vite/src/app/utils/{ => __tests__}/cache.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename packages/devtools-vite/src/app/utils/{ => __tests__}/cache.test.ts (98%) diff --git a/packages/devtools-vite/src/app/utils/cache.test.ts b/packages/devtools-vite/src/app/utils/__tests__/cache.test.ts similarity index 98% rename from packages/devtools-vite/src/app/utils/cache.test.ts rename to packages/devtools-vite/src/app/utils/__tests__/cache.test.ts index ab75df1c..6092c376 100644 --- a/packages/devtools-vite/src/app/utils/cache.test.ts +++ b/packages/devtools-vite/src/app/utils/__tests__/cache.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { FixedTupleMap, MaybeWeakMap, TupleMap } from './cache' +import { FixedTupleMap, MaybeWeakMap, TupleMap } from '../cache' describe('maybeWeakMap', () => { it('should work', () => { From fe39c2a85eebc88af39a21ed8052889a5d05b3a3 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Sun, 10 Aug 2025 08:54:49 +0800 Subject: [PATCH 02/10] test: add test for `is.test.ts` --- .../devtools-vite/src/app/utils/__tests__/is.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/devtools-vite/src/app/utils/__tests__/is.test.ts diff --git a/packages/devtools-vite/src/app/utils/__tests__/is.test.ts b/packages/devtools-vite/src/app/utils/__tests__/is.test.ts new file mode 100644 index 00000000..c89203c2 --- /dev/null +++ b/packages/devtools-vite/src/app/utils/__tests__/is.test.ts @@ -0,0 +1,11 @@ +import { describe, expect, it } from 'vitest' +import { isNumeric } from '../is' + +describe('isNumeric', () => { + it('is numeric', () => { + expect(isNumeric(1)).toBeTruthy() + }) + it('not a numeric', () => { + expect(isNumeric('Vite')).toBeFalsy() + }) +}) From 8a09bdc0a236956390294935165ff957968f6d79 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Sun, 10 Aug 2025 13:26:55 +0800 Subject: [PATCH 03/10] test: add test for `color.test.ts` --- .../src/app/utils/__tests__/color.test.ts | 53 +++++++++++++++++++ packages/devtools-vite/src/app/utils/color.ts | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 packages/devtools-vite/src/app/utils/__tests__/color.test.ts diff --git a/packages/devtools-vite/src/app/utils/__tests__/color.test.ts b/packages/devtools-vite/src/app/utils/__tests__/color.test.ts new file mode 100644 index 00000000..e65e9557 --- /dev/null +++ b/packages/devtools-vite/src/app/utils/__tests__/color.test.ts @@ -0,0 +1,53 @@ +import { beforeEach, describe, expect, it } from 'vitest' +import { isDark } from '../../composables/dark' +import { getHashColorFromString, getHsla, getPluginColor, predefinedColorMap } from '../color' + +describe('getHashColorFromString', () => { + it('should get the same color with the same string', () => { + expect(getHashColorFromString('Vite')).toBe(getHashColorFromString('Vite')) + }) + it('should get different colors with different strings', () => { + expect(getHashColorFromString('Vite')).not.toBe(getHashColorFromString('Devtools')) + }) +}) + +describe('getHsla', () => { + beforeEach(() => { + isDark.value = false + }) + + it('light mode with default opacity', () => { + expect(getHsla(180)).toBe('hsla(180, 65%, 40%, 1)') + }) + + it('light mode with custom opacity', () => { + expect(getHsla(180, 0.5)).toBe('hsla(180, 65%, 40%, 0.5)') + }) + + it('dark mode with default opacity', () => { + isDark.value = true + expect(getHsla(180)).toBe('hsla(180, 50%, 60%, 1)') + }) + + it('dark mode with custom opacity', () => { + isDark.value = true + expect(getHsla(180, 0.8)).toBe('hsla(180, 50%, 60%, 0.8)') + }) +}) + +describe('getPluginColor', () => { + it('should use predefinedColorMap with known name', () => { + for (const name in predefinedColorMap) { + if (Object.prototype.hasOwnProperty.call(predefinedColorMap, name) + && name === name.replace(/[^a-z]+/gi, '').toLowerCase() + && predefinedColorMap[name] + && typeof predefinedColorMap[name] === 'number') { + expect(getPluginColor(`8080-=(🤔)${name}`)).toBe(getHsla(predefinedColorMap[name])) + } + } + }) + + it('should use getHashColorFromString with unknown name', () => { + expect(getPluginColor('😄Foo')).toBe(getHashColorFromString('foo')) + }) +}) diff --git a/packages/devtools-vite/src/app/utils/color.ts b/packages/devtools-vite/src/app/utils/color.ts index 5d774434..cf54de75 100644 --- a/packages/devtools-vite/src/app/utils/color.ts +++ b/packages/devtools-vite/src/app/utils/color.ts @@ -35,7 +35,7 @@ export function getHsla( * - 240: blue * - 270: purple */ -const predefinedColorMap = { +export const predefinedColorMap = { error: 0, client: 60, bailout: -1, From 85c29abb047600e6189b09bb21066aebdc873e89 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Sun, 10 Aug 2025 19:07:46 +0800 Subject: [PATCH 04/10] test: add test for `filepath.ts` --- .../src/app/utils/__tests__/filepath.test.ts | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 packages/devtools-vite/src/app/utils/__tests__/filepath.test.ts diff --git a/packages/devtools-vite/src/app/utils/__tests__/filepath.test.ts b/packages/devtools-vite/src/app/utils/__tests__/filepath.test.ts new file mode 100644 index 00000000..3312a502 --- /dev/null +++ b/packages/devtools-vite/src/app/utils/__tests__/filepath.test.ts @@ -0,0 +1,80 @@ +import { describe, expect, it } from 'vitest' +import { getModuleNameFromPath, isBuiltInModule, isNodeModulePath, parseReadablePath } from '../filepath' + +describe('isNodeModulePath', () => { + it('should return true if includes node_modules path', () => { + expect(isNodeModulePath('/foo/node_modules/bar')).toBeTruthy() + expect(isNodeModulePath('C:\\foo\\node_modules\\bar')).toBeTruthy() + }) + + it('should return true if package names', () => { + expect(isNodeModulePath('vite')).toBeTruthy() + expect(isNodeModulePath('@vitejs/devtools')).toBeTruthy() + expect(isNodeModulePath('#import')).toBeTruthy() + }) + + it('should return false if not node_modules', () => { + expect(isNodeModulePath('/foo/bar')).toBeFalsy() + }) +}) + +describe('getModuleNameFromPath', () => { + it('should return package name', () => { + expect(getModuleNameFromPath('vite')).toBe('vite') + expect(getModuleNameFromPath('@vite/devtools')).toBe('@vite/devtools') + }) + + it('should return undefined with a non-module name', () => { + expect(getModuleNameFromPath('/foo/bar')).toBeUndefined() + expect(getModuleNameFromPath('C:\\foo\\bar')).toBeUndefined() + }) + + it('should return scope package name', () => { + expect(getModuleNameFromPath('/foo/bar/node_modules/@vitejs/devtools')).toBe('@vitejs/devtools') + expect(getModuleNameFromPath('C:\\foo\\node_modules\\@vitejs\\devtools')).toBe('@vitejs/devtools') + }) + + it('should return normal package name', () => { + expect(getModuleNameFromPath('/foo/bar/node_modules/vite')).toBe('vite') + expect(getModuleNameFromPath('C:\\foo\\node_modules\\@vitejs\\devtools')).toBe('@vitejs/devtools') + }) +}) + +describe('isBuiltInModule', () => { + it('should return undefined with undefined name', () => { + expect(isBuiltInModule(undefined)).toBeUndefined() + }) + + it('should return true with a built-in module name', () => { + expect(isBuiltInModule('nuxt')).toBeTruthy() + }) + + it('should return false with a not built-in module name', () => { + expect(isBuiltInModule('foo')).toBeFalsy() + }) +}) + +describe('parseReadablePath', () => { + it('should return path with package names', () => { + expect(parseReadablePath('vite', '/')).toEqual({ moduleName: 'vite', path: 'vite' }) + expect(parseReadablePath('@vitejs/devtools', '/')).toEqual({ moduleName: '@vitejs/devtools', path: '@vitejs/devtools' }) + expect(parseReadablePath('@vitejs\\devtools', '/')).toEqual({ moduleName: '@vitejs/devtools', path: '@vitejs/devtools' }) + expect(parseReadablePath('@vitejs%2Fdevtools', '/')).toEqual({ moduleName: '@vitejs/devtools', path: '@vitejs/devtools' }) + }) + + it('should return path with :', () => { + expect(parseReadablePath('nuxt:index.mjs', '/')).toEqual({ moduleName: 'nuxt:index.mjs', path: 'nuxt:index.mjs' }) + }) + + it('should return moduleName and subpath', () => { + expect(parseReadablePath('/foo/node_modules/vite/dist/index.mjs', '/')).toEqual({ moduleName: 'vite', path: 'vite/dist/index.mjs' }) + }) + + it('should add ./ for no ./ items', () => { + expect(parseReadablePath('/foo/index.mjs', '/foo')).toEqual({ path: './index.mjs' }) + }) + + it('should add replace ./.nuxt to #build for .nuxt items', () => { + expect(parseReadablePath('/foo/.nuxt/index.mjs', '/foo')).toEqual({ path: '#build/index.mjs' }) + }) +}) From 0e548e8fb61c6c99dd86f62046a88953a47c7c69 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Sun, 10 Aug 2025 21:15:32 +0800 Subject: [PATCH 05/10] test: add test for `format.ts` --- .../src/app/utils/__tests__/format.test.ts | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 packages/devtools-vite/src/app/utils/__tests__/format.test.ts diff --git a/packages/devtools-vite/src/app/utils/__tests__/format.test.ts b/packages/devtools-vite/src/app/utils/__tests__/format.test.ts new file mode 100644 index 00000000..61e1dc91 --- /dev/null +++ b/packages/devtools-vite/src/app/utils/__tests__/format.test.ts @@ -0,0 +1,98 @@ +import type { ModuleDest, ModuleTreeNode } from '../../../shared/types/data' +import { describe, expect, it } from 'vitest' +import { bytesToHumanSize, getContentByteSize, toTree } from '../format' + +describe('bytesToHumanSize', () => { + it('should return raw bytes (<1024)', () => { + expect(bytesToHumanSize(10)).toEqual([10, 'B']) + }) + + it('should return kb with proper digits', () => { + expect(bytesToHumanSize(1024)).toEqual(['1', 'KB']) + expect(bytesToHumanSize(1024 * 1.5)).toEqual(['1.5', 'KB']) + expect(bytesToHumanSize(1024 * 1.666, 1)).toEqual(['1.7', 'KB']) + }) + + it('should return mb with proper digits', () => { + expect(bytesToHumanSize(1024 * 1024)).toEqual(['1', 'MB']) + expect(bytesToHumanSize(1024 * 1024 * 1.5)).toEqual(['1.5', 'MB']) + expect(bytesToHumanSize(1024 * 1024 * 1.666, 1)).toEqual(['1.7', 'MB']) + }) + + // larger... +}) + +describe('getContentByteSize', () => { + it('should return 0 with empty string', () => { + expect(getContentByteSize('')).toBe(0) + }) + + it('should return bytes', () => { + expect(getContentByteSize('vite')).toBe(4) + }) +}) + +describe('toTree', () => { + it('should work with empty modules', () => { + expect(toTree([], 'Root')).toEqual({ + name: 'Root', + children: {}, + items: [], + }) + }) + + it('should work', () => { + const modules: ModuleDest[] = [ + { + full: '/path/to/project/dist/src/components/Button.js', + path: 'src/components/Button.js', + }, + { + full: '/path/to/project/dist/src/utils/helper.js', + path: 'src/utils/helper.js', + }, + { + full: '/path/to/project/dist/index.js', + path: 'index.js', + }, + ] + + expect(toTree(modules, 'Root')).toEqual({ + name: 'Root', + children: { + src: { + name: 'src', + children: { + components: { + name: 'components', + children: {}, + items: [ + { + full: '/path/to/project/dist/src/components/Button.js', + path: 'src/components/Button.js', + }, + ], + }, + utils: { + name: 'utils', + children: {}, + items: [ + { + full: '/path/to/project/dist/src/utils/helper.js', + path: 'src/utils/helper.js', + }, + ], + }, + }, + items: [], + }, + }, + items: [ + { + full: '/path/to/project/dist/index.js', + path: 'index.js', + }, + ], + } satisfies ModuleTreeNode) + }) +}) From c630fe3819043a10aaf204c9dc88a1d59244d8f1 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Sun, 10 Aug 2025 21:25:19 +0800 Subject: [PATCH 06/10] test: add test for `icon.ts` --- .../src/app/utils/__tests__/icon.test.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 packages/devtools-vite/src/app/utils/__tests__/icon.test.ts diff --git a/packages/devtools-vite/src/app/utils/__tests__/icon.test.ts b/packages/devtools-vite/src/app/utils/__tests__/icon.test.ts new file mode 100644 index 00000000..54a637d1 --- /dev/null +++ b/packages/devtools-vite/src/app/utils/__tests__/icon.test.ts @@ -0,0 +1,61 @@ +import { describe, expect, it } from 'vitest' +import { DefaultFileTypeRule, DefaultPluginType, getFileTypeFromModuleId, getFileTypeFromName, getPluginTypeFromName } from '../icon' + +describe('getFileTypeFromName', () => { + it('should return correct rule by name', () => { + expect(getFileTypeFromName('vue').name).toBe('vue') + expect(getFileTypeFromName('ts').name).toBe('ts') + }) + + it('should return default rule for unknown names', () => { + expect(getFileTypeFromName('unknown')).toBe(DefaultFileTypeRule) + }) +}) + +describe('getFileTypeFromModuleId', () => { + it('should match node_modules', () => { + expect(getFileTypeFromModuleId('/node_modules/vue/dist/vue.js').name).toBe('node_modules') + expect(getFileTypeFromModuleId('C:\\node_modules\\react\\index.js').name).toBe('node_modules') + }) + + it('should match virtual modules', () => { + expect(getFileTypeFromModuleId('virtual:my-module').name).toBe('virtual') + expect(getFileTypeFromModuleId('\0rollup-plugin').name).toBe('virtual') + }) + + it('should match file extensions', () => { + expect(getFileTypeFromModuleId('/src/App.vue').name).toBe('vue') + expect(getFileTypeFromModuleId('/src/index.ts').name).toBe('ts') + expect(getFileTypeFromModuleId('/src/index.tsx').name).toBe('jsx') + expect(getFileTypeFromModuleId('/src/index.js').name).toBe('js') + expect(getFileTypeFromModuleId('/src/style.css').name).toBe('css') + }) + + it('should handle query parameters', () => { + expect(getFileTypeFromModuleId('/src/App.vue?v=123').name).toBe('vue') + expect(getFileTypeFromModuleId('/src/App.vue?').name).toBe('vue') + }) + + it('should match packages', () => { + expect(getFileTypeFromModuleId('lodash').name).toBe('package') + expect(getFileTypeFromModuleId('@vue/core').name).toBe('package') + }) + + it('should return default for unknown files', () => { + expect(getFileTypeFromModuleId('/unknown.xyz')).toBe(DefaultFileTypeRule) + }) +}) + +describe('getPluginTypeFromName', () => { + it('should match plugin types', () => { + expect(getPluginTypeFromName('replace').name).toBe('rollup') + expect(getPluginTypeFromName('vite:css').name).toBe('vite') + expect(getPluginTypeFromName('unocss:core').name).toBe('unocss') + expect(getPluginTypeFromName('nuxt:pages').name).toBe('nuxt') + expect(getPluginTypeFromName('builtin:fs').name).toBe('builtin') + }) + + it('should return default for unknown plugins', () => { + expect(getPluginTypeFromName('custom-plugin')).toBe(DefaultPluginType) + }) +}) From c7b3e43cf649eb18f1c5a0f1cbf826c538d8e213 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Sun, 10 Aug 2025 22:27:22 +0800 Subject: [PATCH 07/10] test: better testing for `is.ts` --- .../src/app/utils/__tests__/is.test.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/devtools-vite/src/app/utils/__tests__/is.test.ts b/packages/devtools-vite/src/app/utils/__tests__/is.test.ts index c89203c2..10089d72 100644 --- a/packages/devtools-vite/src/app/utils/__tests__/is.test.ts +++ b/packages/devtools-vite/src/app/utils/__tests__/is.test.ts @@ -2,10 +2,23 @@ import { describe, expect, it } from 'vitest' import { isNumeric } from '../is' describe('isNumeric', () => { - it('is numeric', () => { + it('should return true for numbers', () => { expect(isNumeric(1)).toBeTruthy() + expect(isNumeric(0)).toBeTruthy() + expect(isNumeric(-1)).toBeTruthy() }) - it('not a numeric', () => { + + it('should return false for non-numeric strings', () => { expect(isNumeric('Vite')).toBeFalsy() + expect(isNumeric('123abc')).toBeFalsy() + }) + + it('should return true for numeric strings', () => { + expect(isNumeric('123')).toBeTruthy() + }) + + it('should return false for NaN/Infinity', () => { + expect(isNumeric(Number.NaN)).toBeTruthy() + expect(isNumeric(Infinity)).toBeTruthy() }) }) From 144339c51c0581ecbefbe3898cbb3b0350ac306f Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Mon, 11 Aug 2025 08:43:21 +0800 Subject: [PATCH 08/10] test: better testing --- packages/devtools-vite/src/app/utils/__tests__/icon.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devtools-vite/src/app/utils/__tests__/icon.test.ts b/packages/devtools-vite/src/app/utils/__tests__/icon.test.ts index 54a637d1..6783ed58 100644 --- a/packages/devtools-vite/src/app/utils/__tests__/icon.test.ts +++ b/packages/devtools-vite/src/app/utils/__tests__/icon.test.ts @@ -37,8 +37,8 @@ describe('getFileTypeFromModuleId', () => { }) it('should match packages', () => { - expect(getFileTypeFromModuleId('lodash').name).toBe('package') - expect(getFileTypeFromModuleId('@vue/core').name).toBe('package') + expect(getFileTypeFromModuleId('vite').name).toBe('package') + expect(getFileTypeFromModuleId('@vitejs/devtools').name).toBe('package') }) it('should return default for unknown files', () => { From 0f97e8af6d30a151688ea00d6c661dfd0b98e485 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Tue, 12 Aug 2025 09:28:17 +0800 Subject: [PATCH 09/10] test: add edge cases testing for #73 --- .../devtools-vite/src/app/utils/__tests__/color.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/devtools-vite/src/app/utils/__tests__/color.test.ts b/packages/devtools-vite/src/app/utils/__tests__/color.test.ts index e65e9557..d1327c02 100644 --- a/packages/devtools-vite/src/app/utils/__tests__/color.test.ts +++ b/packages/devtools-vite/src/app/utils/__tests__/color.test.ts @@ -39,10 +39,10 @@ describe('getPluginColor', () => { it('should use predefinedColorMap with known name', () => { for (const name in predefinedColorMap) { if (Object.prototype.hasOwnProperty.call(predefinedColorMap, name) - && name === name.replace(/[^a-z]+/gi, '').toLowerCase() - && predefinedColorMap[name] - && typeof predefinedColorMap[name] === 'number') { - expect(getPluginColor(`8080-=(🤔)${name}`)).toBe(getHsla(predefinedColorMap[name])) + && name === name.replace(/[^a-z]+/gi, '').toLowerCase()) { + if (typeof predefinedColorMap[name] === 'number') { + expect(getPluginColor(`8080-=(🤔)${name}`)).toBe(getHsla(predefinedColorMap[name])) + } } } }) From 7ceb126d1f8c35f81a837cd63d111c97a30d8c98 Mon Sep 17 00:00:00 2001 From: liangmiQwQ Date: Tue, 12 Aug 2025 09:35:18 +0800 Subject: [PATCH 10/10] test: add edge cases testing for #75 --- .../devtools-vite/src/app/utils/__tests__/filepath.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/devtools-vite/src/app/utils/__tests__/filepath.test.ts b/packages/devtools-vite/src/app/utils/__tests__/filepath.test.ts index 3312a502..12a084d9 100644 --- a/packages/devtools-vite/src/app/utils/__tests__/filepath.test.ts +++ b/packages/devtools-vite/src/app/utils/__tests__/filepath.test.ts @@ -62,19 +62,22 @@ describe('parseReadablePath', () => { expect(parseReadablePath('@vitejs%2Fdevtools', '/')).toEqual({ moduleName: '@vitejs/devtools', path: '@vitejs/devtools' }) }) - it('should return path with :', () => { + it('should return path with : unless Windows path', () => { expect(parseReadablePath('nuxt:index.mjs', '/')).toEqual({ moduleName: 'nuxt:index.mjs', path: 'nuxt:index.mjs' }) }) it('should return moduleName and subpath', () => { expect(parseReadablePath('/foo/node_modules/vite/dist/index.mjs', '/')).toEqual({ moduleName: 'vite', path: 'vite/dist/index.mjs' }) + expect(parseReadablePath('C:\\foo\\node_modules\\vite\\dist\\index.mjs', 'C:\\')).toEqual({ moduleName: 'vite', path: 'vite/dist/index.mjs' }) }) it('should add ./ for no ./ items', () => { expect(parseReadablePath('/foo/index.mjs', '/foo')).toEqual({ path: './index.mjs' }) + expect(parseReadablePath('C:\\foo\\index.mjs', 'C:\\foo')).toEqual({ path: './index.mjs' }) }) it('should add replace ./.nuxt to #build for .nuxt items', () => { expect(parseReadablePath('/foo/.nuxt/index.mjs', '/foo')).toEqual({ path: '#build/index.mjs' }) + expect(parseReadablePath('C:\\foo\\.nuxt\\index.mjs', 'C:\\foo')).toEqual({ path: '#build/index.mjs' }) }) })