-
Notifications
You must be signed in to change notification settings - Fork 285
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(utils): add comments, ts type declarations, and vitest test cases to utils functions #3154
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' | ||
import { afterLeave } from '..' | ||
|
||
describe('afterLeave 函数', () => { | ||
// 模拟定时器 | ||
beforeEach(() => { | ||
vi.useFakeTimers() | ||
}) | ||
|
||
afterEach(() => { | ||
vi.restoreAllMocks() | ||
}) | ||
|
||
it('当参数不完整时应抛出错误', () => { | ||
// 缺少 instance 参数 | ||
expect(() => { | ||
// @ts-expect-error 测试错误情况 | ||
afterLeave(null, () => {}) | ||
}).toThrow('instance & callback is required') | ||
|
||
// 缺少 callback 参数 | ||
expect(() => { | ||
// @ts-expect-error 测试错误情况 | ||
afterLeave({ $on: vi.fn(), $once: vi.fn() }, null) | ||
}).toThrow('instance & callback is required') | ||
}) | ||
|
||
it('应使用 $on 注册事件监听(默认情况)', () => { | ||
const instance = { | ||
$on: vi.fn(), | ||
$once: vi.fn() | ||
} | ||
const callback = vi.fn() | ||
|
||
afterLeave(instance, callback) | ||
|
||
expect(instance.$on).toHaveBeenCalledTimes(1) | ||
expect(instance.$on).toHaveBeenCalledWith('after-leave', expect.any(Function)) | ||
expect(instance.$once).not.toHaveBeenCalled() | ||
}) | ||
|
||
it('当 once 为 true 时应使用 $once 注册事件监听', () => { | ||
const instance = { | ||
$on: vi.fn(), | ||
$once: vi.fn() | ||
} | ||
const callback = vi.fn() | ||
|
||
afterLeave(instance, callback, 300, true) | ||
|
||
expect(instance.$once).toHaveBeenCalledTimes(1) | ||
expect(instance.$once).toHaveBeenCalledWith('after-leave', expect.any(Function)) | ||
expect(instance.$on).not.toHaveBeenCalled() | ||
}) | ||
|
||
it('应在指定的延时后自动触发回调', () => { | ||
const instance = { | ||
$on: vi.fn(), | ||
$once: vi.fn() | ||
} | ||
const callback = vi.fn() | ||
const speed = 200 | ||
|
||
afterLeave(instance, callback, speed) | ||
expect(callback).not.toHaveBeenCalled() | ||
|
||
// 快进时间 | ||
vi.advanceTimersByTime(speed + 100) | ||
expect(callback).toHaveBeenCalledTimes(1) | ||
}) | ||
|
||
it('事件回调应该只被执行一次', () => { | ||
const instance = { | ||
$on: vi.fn(), | ||
$once: vi.fn() | ||
} | ||
const callback = vi.fn() | ||
|
||
afterLeave(instance, callback) | ||
|
||
// 获取注册的事件回调 | ||
const eventCallback = instance.$on.mock.calls[0][1] | ||
|
||
// 手动触发事件回调两次 | ||
eventCallback() | ||
eventCallback() | ||
|
||
// 确认回调只被执行一次 | ||
expect(callback).toHaveBeenCalledTimes(1) | ||
}) | ||
|
||
it('应正确传递参数给回调函数', () => { | ||
const instance = { | ||
$on: vi.fn(), | ||
$once: vi.fn() | ||
} | ||
const callback = vi.fn() | ||
const testArg1 = 'test1' | ||
const testArg2 = 'test2' | ||
|
||
afterLeave(instance, callback) | ||
|
||
// 获取注册的事件回调 | ||
const eventCallback = instance.$on.mock.calls[0][1] | ||
|
||
// 手动触发事件回调并传递参数 | ||
eventCallback(testArg1, testArg2) | ||
|
||
// 确认回调被执行并接收到正确的参数 | ||
expect(callback).toHaveBeenCalledWith(testArg1, testArg2) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
/** | ||
* 数组工具函数单元测试 | ||
*/ | ||
import { describe, expect, it } from 'vitest' | ||
import { indexOf, find, remove, sort, push, unique, toObject, transformPidToChildren, transformTreeData } from '..' | ||
|
||
describe('数组工具函数', () => { | ||
describe('indexOf 函数', () => { | ||
it('应能找到普通数组中元素的索引', () => { | ||
const arr = [1, 2, 3, 4] | ||
expect(indexOf(arr, 2)).toBe(1) | ||
}) | ||
|
||
it('应能找到包含 NaN 的数组中 NaN 的索引', () => { | ||
const arr = [1, 2, NaN, 4] | ||
expect(indexOf(arr, NaN)).toBe(2) | ||
}) | ||
|
||
it('当元素不存在时应返回 -1', () => { | ||
const arr = [1, 2, 3, 4] | ||
expect(indexOf(arr, 5)).toBe(-1) | ||
}) | ||
|
||
it('应支持自定义断言函数', () => { | ||
const arr = [{ id: 1 }, { id: 2 }, { id: 3 }] | ||
const index = indexOf(arr, { id: 2 }, (item, target) => item.id === target.id) | ||
expect(index).toBe(1) | ||
}) | ||
}) | ||
|
||
describe('find 函数', () => { | ||
it('应能通过断言函数找到元素', () => { | ||
const arr = [1, 2, 3, 4] | ||
const result = find(arr, (value) => value > 2) | ||
expect(result).toBe(3) | ||
}) | ||
|
||
it('当找不到元素时应返回 undefined', () => { | ||
const arr = [1, 2, 3, 4] | ||
const result = find(arr, (value) => value > 10) | ||
expect(result).toBeUndefined() | ||
}) | ||
}) | ||
|
||
describe('remove 函数', () => { | ||
it('应能从数组中删除指定元素', () => { | ||
const arr = [1, 2, 3, 4] | ||
remove(arr, 2) | ||
expect(arr).toEqual([1, 3, 4]) | ||
}) | ||
|
||
it('应能从数组中删除指定数量的元素', () => { | ||
const arr = [1, 2, 3, 4] | ||
remove(arr, 2, 2) | ||
expect(arr).toEqual([1, 4]) | ||
}) | ||
|
||
it('应能从数组中删除 NaN', () => { | ||
const arr = [1, 2, NaN, 4] | ||
remove(arr, NaN) | ||
expect(arr).toEqual([1, 2, 4]) | ||
}) | ||
|
||
it('当元素不存在时不应有变化', () => { | ||
const arr = [1, 2, 3, 4] | ||
remove(arr, 5) | ||
expect(arr).toEqual([1, 2, 3, 4]) | ||
}) | ||
}) | ||
|
||
describe('sort 函数', () => { | ||
it('应按字段名称对对象数组进行升序排序', () => { | ||
const arr = [{ a: 100 }, { a: 1 }, { a: 10 }] | ||
const result = sort(arr, 'a') | ||
expect(result).toEqual([{ a: 1 }, { a: 10 }, { a: 100 }]) | ||
}) | ||
|
||
it('应按字段名称对对象数组进行降序排序', () => { | ||
const arr = [{ a: 100 }, { a: 1 }, { a: 10 }] | ||
const result = sort(arr, 'a', 'desc') | ||
expect(result).toEqual([{ a: 100 }, { a: 10 }, { a: 1 }]) | ||
}) | ||
|
||
it('应正确处理包含 NaN 值的情况', () => { | ||
const arr = [{ a: 100 }, { a: 1 }, { a: NaN }, { a: 10 }] | ||
const result = sort(arr, 'a') | ||
expect(result).toEqual([{ a: 1 }, { a: 10 }, { a: 100 }, { a: NaN }]) | ||
}) | ||
}) | ||
|
||
describe('push 函数', () => { | ||
it('应向数组中添加新元素', () => { | ||
const arr = [1, 2, 3, 4] | ||
push(arr, 5) | ||
expect(arr).toEqual([1, 2, 3, 4, 5]) | ||
}) | ||
|
||
it('不应向数组中添加已存在的元素', () => { | ||
const arr = [1, 2, 3, 4] | ||
push(arr, 2) | ||
expect(arr).toEqual([1, 2, 3, 4]) | ||
}) | ||
|
||
it('不应向数组中添加已存在的 NaN', () => { | ||
const arr = [1, 2, NaN, 4] | ||
push(arr, NaN) | ||
expect(arr).toEqual([1, 2, NaN, 4]) | ||
}) | ||
}) | ||
|
||
describe('unique 函数', () => { | ||
it('应去除数组中的重复元素', () => { | ||
const arr = [1, 2, 2, 3, 4, 4] | ||
const result = unique(arr) | ||
expect(result).toEqual([1, 2, 3, 4]) | ||
}) | ||
|
||
it('应正确处理包含 NaN 的数组', () => { | ||
const arr = [1, NaN, 2, NaN, 2, 3, 4] | ||
const result = unique(arr) | ||
expect(result).toEqual([1, NaN, 2, 3, 4]) | ||
}) | ||
}) | ||
|
||
describe('toObject 函数', () => { | ||
it('应将对象数组转换为单一对象', () => { | ||
const arr = [{ key1: 'value1' }, { key2: 'value2' }] | ||
const result = toObject(arr) | ||
expect(result).toEqual({ key1: 'value1', key2: 'value2' }) | ||
}) | ||
|
||
it('后面的对象字段应覆盖前面的同名字段', () => { | ||
const arr = [{ key1: 'value1' }, { key1: 'value2' }] | ||
const result = toObject(arr) | ||
expect(result).toEqual({ key1: 'value2' }) | ||
}) | ||
}) | ||
|
||
describe('transformPidToChildren 函数', () => { | ||
it('应将扁平数据转换为树状结构', () => { | ||
const data = [ | ||
{ id: 100, pId: 0, label: '首页' }, | ||
{ id: 101, pId: 100, label: '指南' } | ||
] | ||
const result = transformPidToChildren(data) | ||
expect(result).toEqual([ | ||
{ | ||
id: 100, | ||
label: '首页', | ||
children: [{ id: 101, label: '指南' }] | ||
} | ||
]) | ||
}) | ||
|
||
it('应支持自定义字段名', () => { | ||
const data = [ | ||
{ uid: 100, parentId: 0, label: '首页' }, | ||
{ uid: 101, parentId: 100, label: '指南' } | ||
] | ||
const result = transformPidToChildren(data, 'parentId', 'items', 'uid') | ||
expect(result).toEqual([ | ||
{ | ||
uid: 100, | ||
label: '首页', | ||
items: [{ uid: 101, label: '指南' }] | ||
} | ||
]) | ||
}) | ||
}) | ||
|
||
describe('transformTreeData 函数', () => { | ||
it('应将扁平数据转换为树状结构', () => { | ||
const data = [ | ||
{ id: 100, pId: 0, label: '首页' }, | ||
{ id: 101, pId: 100, label: '指南' } | ||
] | ||
const result = transformTreeData(data) | ||
expect(result).toEqual([ | ||
{ | ||
id: 100, | ||
label: '首页', | ||
children: [{ id: 101, label: '指南' }] | ||
} | ||
]) | ||
}) | ||
|
||
it('应支持非数组输入', () => { | ||
const data = { id: 100, pId: 0, label: '首页' } | ||
const result = transformTreeData(data) | ||
expect(result).toEqual([ | ||
{ | ||
id: 100, | ||
label: '首页' | ||
} | ||
]) | ||
}) | ||
|
||
it('应支持自定义字段名', () => { | ||
const data = [ | ||
{ uid: 100, parentId: 0, label: '首页' }, | ||
{ uid: 101, parentId: 100, label: '指南' } | ||
] | ||
const result = transformTreeData(data, 'uid', 'parentId') | ||
expect(result).toEqual([ | ||
{ | ||
uid: 100, | ||
label: '首页', | ||
children: [{ uid: 101, label: '指南' }] | ||
} | ||
]) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Type definitions improve function signature clarity, but consider refining the Function type.
The TypeScript type annotations significantly improve the function signature by clearly defining parameter types and return type. However, using the
Function
type is discouraged as it's too generic.Consider using more specific function types:
🏁 Script executed:
Length of output: 936
Refine callback type signature for improved type-safety
The current use of the generic
Function
type in theafterLeave
function (and similar patterns across the codebase) can be made more explicit. Instead of using:this change will enhance clarity and ensure better type checking. Please update the type accordingly in
packages/utils/src/after-leave/index.ts
(lines 35-40) and consider aligning similar patterns in other parts of the codebase if appropriate.📝 Committable suggestion