@lytjs/test-utils 5.0.1 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,44 +1,53 @@
1
1
  {
2
2
  "name": "@lytjs/test-utils",
3
- "version": "5.0.1",
4
- "description": "Lyt.js 测试工具库 - 提供组件挂载、状态模拟和断言辅助等测试工具",
3
+ "version": "6.4.0",
4
+ "description": "LytJS testing utilities for unit and integration testing",
5
+ "type": "module",
5
6
  "main": "./dist/index.cjs",
6
7
  "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
7
9
  "exports": {
8
10
  ".": {
9
- "types": "./dist/types/index.d.ts",
11
+ "types": "./dist/index.d.ts",
10
12
  "import": "./dist/index.mjs",
11
- "require": "./dist/index.cjs",
12
- "default": "./dist/index.mjs"
13
- }
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./package.json": "./package.json"
14
16
  },
15
- "sideEffects": false,
16
17
  "files": [
17
18
  "dist"
18
19
  ],
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "build": "echo 'Skipping test-utils build for now'",
23
+ "dev": "tsup --watch",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "test:coverage": "vitest run --coverage",
27
+ "type-check": "tsc --noEmit",
28
+ "lint": "eslint \"src/**/*.ts\"",
29
+ "clean": "rm -rf dist"
30
+ },
31
+ "dependencies": {
32
+ "@lytjs/core": "^6.0.0",
33
+ "@lytjs/reactivity": "^6.0.0",
34
+ "@lytjs/component": "^6.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "tsup": "^8.0.0",
38
+ "typescript": "^5.4.0",
39
+ "vitest": "^3.0.0"
40
+ },
19
41
  "license": "MIT",
20
- "author": "lytjs",
21
42
  "repository": {
22
43
  "type": "git",
23
- "url": "https://gitee.com/lytjs/lytjs"
44
+ "url": "https://gitee.com/lytjs/lytjs.git",
45
+ "directory": "packages/tools/packages/test-utils"
24
46
  },
25
- "homepage": "https://gitee.com/lytjs/lytjs",
26
47
  "keywords": [
27
- "lyt",
28
48
  "lytjs",
29
- "javascript",
30
- "framework",
31
- "frontend",
32
- "vue-like",
33
- "lightweight",
34
- "zero-dependency",
35
49
  "test",
36
50
  "testing",
37
- "utils",
38
- "mount",
39
- "测试"
40
- ],
41
- "publishConfig": {
42
- "access": "public"
43
- }
51
+ "utils"
52
+ ]
44
53
  }
package/README.md DELETED
@@ -1,299 +0,0 @@
1
- # @lytjs/test-utils
2
-
3
- Lyt.js 统一测试框架 -- 轻量级测试运行器和断言库,纯原生实现,零外部依赖。
4
-
5
- ## 安装
6
-
7
- ```bash
8
- npm install @lytjs/test-utils --save-dev
9
-
10
- # 或使用 pnpm
11
- pnpm add @lytjs/test-utils -D
12
- ```
13
-
14
- ## 特性
15
-
16
- - 轻量级测试运行器(describe/it/test/skip)
17
- - 链式断言库(expect + .not 取反)
18
- - 生命周期钩子(beforeEach/afterEach)
19
- - 异步测试支持
20
- - 彩色终端输出
21
- - 失败日志自动保存
22
- - 零外部依赖
23
-
24
- ## 快速开始
25
-
26
- ```typescript
27
- import { describe, it, expect, runAll } from '@lytjs/test-utils'
28
-
29
- describe('我的模块', () => {
30
- it('应该正常工作', () => {
31
- expect(1 + 1).toBe(2)
32
- })
33
-
34
- it('应该支持深度比较', () => {
35
- expect({ a: 1, b: 2 }).toEqual({ a: 1, b: 2 })
36
- })
37
-
38
- it('应该支持取反断言', () => {
39
- expect(null).not.toBeTruthy()
40
- })
41
- })
42
-
43
- runAll()
44
- ```
45
-
46
- ## API 参考
47
-
48
- ### describe(name, fn)
49
-
50
- 定义测试套件。
51
-
52
- ```typescript
53
- import { describe } from '@lytjs/test-utils'
54
-
55
- describe('数学运算', () => {
56
- // 在此注册测试用例
57
- })
58
- ```
59
-
60
- ### it(name, fn) / test(name, fn)
61
-
62
- 注册测试用例。`test` 是 `it` 的别名。
63
-
64
- ```typescript
65
- import { it, test } from '@lytjs/test-utils'
66
-
67
- it('加法运算', () => {
68
- expect(1 + 1).toBe(2)
69
- })
70
-
71
- // test 是 it 的别名
72
- test('减法运算', () => {
73
- expect(3 - 1).toBe(2)
74
- })
75
- ```
76
-
77
- ### skip(name, fn)
78
-
79
- 跳过测试用例(不会执行)。
80
-
81
- ```typescript
82
- import { skip } from '@lytjs/test-utils'
83
-
84
- skip('待实现的测试', () => {
85
- expect(true).toBe(false)
86
- })
87
- ```
88
-
89
- ### beforeEach(fn) / afterEach(fn)
90
-
91
- 注册前置/后置钩子,在每个测试用例执行前/后调用。
92
-
93
- ```typescript
94
- import { describe, it, beforeEach, afterEach, expect } from '@lytjs/test-utils'
95
-
96
- let counter = 0
97
-
98
- describe('计数器', () => {
99
- beforeEach(() => {
100
- counter = 0
101
- })
102
-
103
- afterEach(() => {
104
- counter = -1
105
- })
106
-
107
- it('初始值为 0', () => {
108
- expect(counter).toBe(0)
109
- })
110
- })
111
- ```
112
-
113
- ### expect(value)
114
-
115
- 创建断言对象,支持链式调用。
116
-
117
- #### 断言方法
118
-
119
- | 方法 | 说明 |
120
- |------|------|
121
- | `toBe(expected)` | 严格相等 (`===`) |
122
- | `toEqual(expected)` | 深度相等 |
123
- | `toBeTruthy()` | 断言为真值 |
124
- | `toBeFalsy()` | 断言为假值 |
125
- | `toBeNull()` | 断言为 null |
126
- | `toBeUndefined()` | 断言为 undefined |
127
- | `toBeDefined()` | 断言已定义(非 undefined) |
128
- | `toThrow(message?)` | 断言函数抛出异常 |
129
- | `toContain(item)` | 断言数组/字符串包含指定项 |
130
- | `toBeGreaterThan(n)` | 断言数值大于 n |
131
- | `toBeLessThan(n)` | 断言数值小于 n |
132
- | `toBeGreaterThanOrEqual(n)` | 断言数值大于等于 n |
133
- | `toBeLessThanOrEqual(n)` | 断言数值小于等于 n |
134
- | `toHaveLength(n)` | 断言数组/字符串长度为 n |
135
-
136
- #### 取反断言
137
-
138
- 所有断言方法均可通过 `.not` 取反:
139
-
140
- ```typescript
141
- expect(1).not.toBe(2)
142
- expect([1, 2]).not.toContain(3)
143
- ```
144
-
145
- ### runAll()
146
-
147
- 运行所有已注册的测试套件,输出格式化报告。
148
-
149
- ```typescript
150
- import { runAll } from '@lytjs/test-utils'
151
-
152
- const result = await runAll()
153
- // result: { total, passed, failed, skipped, results }
154
- ```
155
-
156
- ### waitFor(ms)
157
-
158
- 等待指定毫秒数,用于异步测试。
159
-
160
- ```typescript
161
- import { waitFor } from '@lytjs/test-utils'
162
-
163
- it('异步操作', async () => {
164
- await waitFor(100)
165
- expect(true).toBe(true)
166
- })
167
- ```
168
-
169
- ### deepEqual(a, b)
170
-
171
- 深度比较两个值是否相等。
172
-
173
- ```typescript
174
- import { deepEqual } from '@lytjs/test-utils'
175
-
176
- const result = deepEqual({ a: [1, 2] }, { a: [1, 2] })
177
- // result: true
178
- ```
179
-
180
- ## 示例
181
-
182
- ### 基础测试
183
-
184
- ```typescript
185
- import { describe, it, expect, runAll } from '@lytjs/test-utils'
186
-
187
- describe('字符串操作', () => {
188
- it('应该正确拼接字符串', () => {
189
- const result = 'hello' + ' ' + 'world'
190
- expect(result).toBe('hello world')
191
- })
192
-
193
- it('应该正确获取长度', () => {
194
- expect('hello').toHaveLength(5)
195
- })
196
-
197
- it('应该包含子串', () => {
198
- expect('hello world').toContain('world')
199
- })
200
- })
201
-
202
- runAll()
203
- ```
204
-
205
- ### 异步测试
206
-
207
- ```typescript
208
- import { describe, it, expect, waitFor, runAll } from '@lytjs/test-utils'
209
-
210
- describe('异步操作', () => {
211
- it('应该支持 async/await', async () => {
212
- await waitFor(50)
213
- expect(true).toBe(true)
214
- })
215
-
216
- it('应该处理 Promise', async () => {
217
- const promise = Promise.resolve(42)
218
- const result = await promise
219
- expect(result).toBe(42)
220
- })
221
- })
222
-
223
- runAll()
224
- ```
225
-
226
- ### 错误处理测试
227
-
228
- ```typescript
229
- import { describe, it, expect, runAll } from '@lytjs/test-utils'
230
-
231
- describe('错误处理', () => {
232
- it('应该抛出异常', () => {
233
- expect(() => {
234
- throw new Error('test error')
235
- }).toThrow('test error')
236
- })
237
-
238
- it('应该断言不抛出异常', () => {
239
- expect(() => {
240
- // 不抛出异常
241
- }).not.toThrow()
242
- })
243
- })
244
-
245
- runAll()
246
- ```
247
-
248
- ### 数值比较
249
-
250
- ```typescript
251
- import { describe, it, expect, runAll } from '@lytjs/test-utils'
252
-
253
- describe('数值比较', () => {
254
- it('应该支持大于比较', () => {
255
- expect(10).toBeGreaterThan(5)
256
- })
257
-
258
- it('应该支持小于比较', () => {
259
- expect(3).toBeLessThan(8)
260
- })
261
-
262
- it('应该支持大于等于', () => {
263
- expect(5).toBeGreaterThanOrEqual(5)
264
- })
265
-
266
- it('应该支持小于等于', () => {
267
- expect(5).toBeLessThanOrEqual(5)
268
- })
269
- })
270
-
271
- runAll()
272
- ```
273
-
274
- ## 运行输出
275
-
276
- 运行 `runAll()` 后,终端会输出彩色格式化的测试报告:
277
-
278
- ```
279
- === Lyt.js 测试运行器 ===
280
-
281
- 我的模块
282
- [PASS] 应该正常工作
283
- [PASS] 应该支持深度比较
284
-
285
- === 测试结果 ===
286
- 总计: 2
287
- 通过: 2
288
-
289
- 所有测试通过!
290
- ```
291
-
292
- ## 兼容性
293
-
294
- - Node.js >= 18.0.0
295
- - TypeScript 5.0+
296
-
297
- ## License
298
-
299
- MIT
package/dist/index.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";var d=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var b=(i,t)=>{for(var e in t)d(i,e,{get:t[e],enumerable:!0})},_=(i,t,e,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of $(t))!y.call(i,s)&&s!==e&&d(i,s,{get:()=>t[s],enumerable:!(a=m(t,s))||a.enumerable});return i};var v=i=>_(d({},"__esModule",{value:!0}),i);var B={};b(B,{Assertion:()=>l,afterEach:()=>T,beforeEach:()=>k,deepEqual:()=>u,describe:()=>E,expect:()=>O,it:()=>g,runAll:()=>j,skip:()=>x,test:()=>w,waitFor:()=>F});module.exports=v(B);var p=[],o=null;function E(i,t){let e={name:i,tests:[],beforeEachFn:[],afterEachFn:[]},a=o;o=e,t(),o=a,p.push(e)}function g(i,t){if(!o)throw new Error("it() must be called inside describe()");o.tests.push({name:i,fn:t})}var w=g;function x(i,t){if(!o)throw new Error("skip() must be called inside describe()");o.tests.push({name:i,fn:t,skipped:!0})}function k(i){var t;(t=o==null?void 0:o.beforeEachFn)==null||t.push(i)}function T(i){var t;(t=o==null?void 0:o.afterEachFn)==null||t.push(i)}function O(i){return new l(i)}function u(i,t){if(Object.is(i,t))return!0;if(i===null||t===null||typeof i!=typeof t)return!1;if(typeof i=="object"){let e=Object.keys(i),a=Object.keys(t);if(e.length!==a.length)return!1;for(let s of e)if(!Object.prototype.hasOwnProperty.call(t,s)||!u(i[s],t[s]))return!1;return!0}return!1}function F(i){return new Promise(t=>setTimeout(t,i))}async function j(){let i=[],t=0,e=0,a=0;for(let s of p)for(let n of s.tests){if(n.skipped){a++,i.push({name:n.name,suite:s.name,status:"skipped",duration:0}),console.log(` \x1B[33m\u2298 SKIP\x1B[0m ${s.name} > ${n.name}`);continue}let r=Date.now();try{if(s.beforeEachFn)for(let f of s.beforeEachFn)f();let h=n.fn();if(h instanceof Promise&&await h,s.afterEachFn)for(let f of s.afterEachFn)f();let c=Date.now()-r;t++,i.push({name:n.name,suite:s.name,status:"passed",duration:c}),console.log(` \x1B[32m\u2713 PASS\x1B[0m ${s.name} > ${n.name} (${c}ms)`)}catch(h){let c=Date.now()-r;e++,i.push({name:n.name,suite:s.name,status:"failed",error:h,duration:c}),console.log(` \x1B[31m\u2717 FAIL\x1B[0m ${s.name} > ${n.name}`),console.log(` \x1B[31m${h.message}\x1B[0m`)}}return p.length=0,console.log(""),console.log(`--- \u6D4B\u8BD5\u7ED3\u679C: ${t} \u901A\u8FC7, ${e} \u5931\u8D25, ${a} \u8DF3\u8FC7, \u5171 ${t+e+a} \u4E2A ---`),console.log(""),{total:t+e+a,passed:t,failed:e,skipped:a,results:i}}var l=class{constructor(t){this.negated=!1;this.actual=t}get not(){return this.negated=!this.negated,this}toBe(t){let e=this.negated?!Object.is(this.actual,t):Object.is(this.actual,t);this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u7B49\u4E8E ${this._fmt(t)}`)}toEqual(t){let e=this.negated?!u(this.actual,t):u(this.actual,t);this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u6DF1\u5EA6\u7B49\u4E8E ${this._fmt(t)}`)}toBeTruthy(){let t=this.negated?!this.actual:!!this.actual;this._assert(t,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u4E3A\u771F\u503C`)}toBeFalsy(){let t=this.negated?!!this.actual:!this.actual;this._assert(t,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u4E3A\u5047\u503C`)}toBeNull(){let t=this.negated?this.actual!==null:this.actual===null;this._assert(t,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u4E3A null`)}toBeUndefined(){let t=this.negated?this.actual!==void 0:this.actual===void 0;this._assert(t,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u4E3A undefined`)}toBeDefined(){let t=this.negated?this.actual===void 0:this.actual!==void 0;this._assert(t,`\u671F\u671B\u503C ${this.negated?"\u4E0D":""}\u5DF2\u5B9A\u4E49`)}toThrow(t){let e=!1,a="";try{if(typeof this.actual=="function")this.actual();else throw new Error("toThrow() \u7684\u5B9E\u9645\u503C\u5FC5\u987B\u662F\u51FD\u6570")}catch(n){e=!0,a=n.message||String(n)}let s=this.negated?!e:e;s&&e&&t&&!this.negated&&(s=a.includes(t)),this._assert(s,`\u671F\u671B\u51FD\u6570${this.negated?"\u4E0D":""}\u629B\u51FA\u5F02\u5E38${t?` (\u5305\u542B "${t}")`:""}`)}toContain(t){let e;typeof this.actual=="string"?e=this.actual.includes(t):Array.isArray(this.actual)?e=this.actual.some(a=>u(a,t)):e=!1,this.negated&&(e=!e),this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5305\u542B ${this._fmt(t)}`)}toBeGreaterThan(t){let e=this.negated?!(this.actual>t):this.actual>t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5927\u4E8E ${t}`)}toBeLessThan(t){let e=this.negated?!(this.actual<t):this.actual<t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5C0F\u4E8E ${t}`)}toBeGreaterThanOrEqual(t){let e=this.negated?!(this.actual>=t):this.actual>=t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5927\u4E8E\u7B49\u4E8E ${t}`)}toBeLessThanOrEqual(t){let e=this.negated?!(this.actual<=t):this.actual<=t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5C0F\u4E8E\u7B49\u4E8E ${t}`)}toHaveLength(t){var s;let e=(s=this.actual)==null?void 0:s.length,a=this.negated?e!==t:e===t;this._assert(a,`\u671F\u671B\u957F\u5EA6\u4E3A ${t}\uFF0C\u5B9E\u9645\u4E3A ${e}`)}toBeInstanceOf(t){let e=this.negated?!(this.actual instanceof t):this.actual instanceof t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u662F ${t.name} \u7684\u5B9E\u4F8B`)}toHaveProperty(t,e){let a=t.split("."),s=this.actual,n=!0;for(let r of a){if(s==null||typeof s!="object"){n=!1;break}s=s[r]}if(e!==void 0){let r=this.negated?!(n&&Object.is(s,e)):n&&Object.is(s,e);this._assert(r,`\u671F\u671B\u5BF9\u8C61${this.negated?"\u4E0D":""}\u5305\u542B\u5C5E\u6027 "${t}" \u503C\u4E3A ${this._fmt(e)}`)}else{let r=this.negated?!n:n;this._assert(r,`\u671F\u671B\u5BF9\u8C61${this.negated?"\u4E0D":""}\u5305\u542B\u5C5E\u6027 "${t}"`)}}_assert(t,e){if(!t)throw new Error(e)}_fmt(t){if(t===null)return"null";if(t===void 0)return"undefined";if(typeof t=="string")return`"${t}"`;if(typeof t=="function")return"[Function]";if(Array.isArray(t))try{return JSON.stringify(t)}catch(e){return"[Array]"}if(typeof t=="object")try{return JSON.stringify(t)}catch(e){return"[Object]"}return String(t)}};0&&(module.exports={Assertion,afterEach,beforeEach,deepEqual,describe,expect,it,runAll,skip,test,waitFor});
package/dist/index.mjs DELETED
@@ -1 +0,0 @@
1
- var f=[],o=null;function g(i,t){let e={name:i,tests:[],beforeEachFn:[],afterEachFn:[]},a=o;o=e,t(),o=a,f.push(e)}function p(i,t){if(!o)throw new Error("it() must be called inside describe()");o.tests.push({name:i,fn:t})}var m=p;function $(i,t){if(!o)throw new Error("skip() must be called inside describe()");o.tests.push({name:i,fn:t,skipped:!0})}function y(i){var t;(t=o==null?void 0:o.beforeEachFn)==null||t.push(i)}function b(i){var t;(t=o==null?void 0:o.afterEachFn)==null||t.push(i)}function _(i){return new d(i)}function c(i,t){if(Object.is(i,t))return!0;if(i===null||t===null||typeof i!=typeof t)return!1;if(typeof i=="object"){let e=Object.keys(i),a=Object.keys(t);if(e.length!==a.length)return!1;for(let s of e)if(!Object.prototype.hasOwnProperty.call(t,s)||!c(i[s],t[s]))return!1;return!0}return!1}function v(i){return new Promise(t=>setTimeout(t,i))}async function E(){let i=[],t=0,e=0,a=0;for(let s of f)for(let n of s.tests){if(n.skipped){a++,i.push({name:n.name,suite:s.name,status:"skipped",duration:0}),console.log(` \x1B[33m\u2298 SKIP\x1B[0m ${s.name} > ${n.name}`);continue}let r=Date.now();try{if(s.beforeEachFn)for(let l of s.beforeEachFn)l();let h=n.fn();if(h instanceof Promise&&await h,s.afterEachFn)for(let l of s.afterEachFn)l();let u=Date.now()-r;t++,i.push({name:n.name,suite:s.name,status:"passed",duration:u}),console.log(` \x1B[32m\u2713 PASS\x1B[0m ${s.name} > ${n.name} (${u}ms)`)}catch(h){let u=Date.now()-r;e++,i.push({name:n.name,suite:s.name,status:"failed",error:h,duration:u}),console.log(` \x1B[31m\u2717 FAIL\x1B[0m ${s.name} > ${n.name}`),console.log(` \x1B[31m${h.message}\x1B[0m`)}}return f.length=0,console.log(""),console.log(`--- \u6D4B\u8BD5\u7ED3\u679C: ${t} \u901A\u8FC7, ${e} \u5931\u8D25, ${a} \u8DF3\u8FC7, \u5171 ${t+e+a} \u4E2A ---`),console.log(""),{total:t+e+a,passed:t,failed:e,skipped:a,results:i}}var d=class{constructor(t){this.negated=!1;this.actual=t}get not(){return this.negated=!this.negated,this}toBe(t){let e=this.negated?!Object.is(this.actual,t):Object.is(this.actual,t);this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u7B49\u4E8E ${this._fmt(t)}`)}toEqual(t){let e=this.negated?!c(this.actual,t):c(this.actual,t);this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u6DF1\u5EA6\u7B49\u4E8E ${this._fmt(t)}`)}toBeTruthy(){let t=this.negated?!this.actual:!!this.actual;this._assert(t,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u4E3A\u771F\u503C`)}toBeFalsy(){let t=this.negated?!!this.actual:!this.actual;this._assert(t,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u4E3A\u5047\u503C`)}toBeNull(){let t=this.negated?this.actual!==null:this.actual===null;this._assert(t,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u4E3A null`)}toBeUndefined(){let t=this.negated?this.actual!==void 0:this.actual===void 0;this._assert(t,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u4E3A undefined`)}toBeDefined(){let t=this.negated?this.actual===void 0:this.actual!==void 0;this._assert(t,`\u671F\u671B\u503C ${this.negated?"\u4E0D":""}\u5DF2\u5B9A\u4E49`)}toThrow(t){let e=!1,a="";try{if(typeof this.actual=="function")this.actual();else throw new Error("toThrow() \u7684\u5B9E\u9645\u503C\u5FC5\u987B\u662F\u51FD\u6570")}catch(n){e=!0,a=n.message||String(n)}let s=this.negated?!e:e;s&&e&&t&&!this.negated&&(s=a.includes(t)),this._assert(s,`\u671F\u671B\u51FD\u6570${this.negated?"\u4E0D":""}\u629B\u51FA\u5F02\u5E38${t?` (\u5305\u542B "${t}")`:""}`)}toContain(t){let e;typeof this.actual=="string"?e=this.actual.includes(t):Array.isArray(this.actual)?e=this.actual.some(a=>c(a,t)):e=!1,this.negated&&(e=!e),this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5305\u542B ${this._fmt(t)}`)}toBeGreaterThan(t){let e=this.negated?!(this.actual>t):this.actual>t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5927\u4E8E ${t}`)}toBeLessThan(t){let e=this.negated?!(this.actual<t):this.actual<t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5C0F\u4E8E ${t}`)}toBeGreaterThanOrEqual(t){let e=this.negated?!(this.actual>=t):this.actual>=t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5927\u4E8E\u7B49\u4E8E ${t}`)}toBeLessThanOrEqual(t){let e=this.negated?!(this.actual<=t):this.actual<=t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u5C0F\u4E8E\u7B49\u4E8E ${t}`)}toHaveLength(t){var s;let e=(s=this.actual)==null?void 0:s.length,a=this.negated?e!==t:e===t;this._assert(a,`\u671F\u671B\u957F\u5EA6\u4E3A ${t}\uFF0C\u5B9E\u9645\u4E3A ${e}`)}toBeInstanceOf(t){let e=this.negated?!(this.actual instanceof t):this.actual instanceof t;this._assert(e,`\u671F\u671B ${this._fmt(this.actual)} ${this.negated?"\u4E0D":""}\u662F ${t.name} \u7684\u5B9E\u4F8B`)}toHaveProperty(t,e){let a=t.split("."),s=this.actual,n=!0;for(let r of a){if(s==null||typeof s!="object"){n=!1;break}s=s[r]}if(e!==void 0){let r=this.negated?!(n&&Object.is(s,e)):n&&Object.is(s,e);this._assert(r,`\u671F\u671B\u5BF9\u8C61${this.negated?"\u4E0D":""}\u5305\u542B\u5C5E\u6027 "${t}" \u503C\u4E3A ${this._fmt(e)}`)}else{let r=this.negated?!n:n;this._assert(r,`\u671F\u671B\u5BF9\u8C61${this.negated?"\u4E0D":""}\u5305\u542B\u5C5E\u6027 "${t}"`)}}_assert(t,e){if(!t)throw new Error(e)}_fmt(t){if(t===null)return"null";if(t===void 0)return"undefined";if(typeof t=="string")return`"${t}"`;if(typeof t=="function")return"[Function]";if(Array.isArray(t))try{return JSON.stringify(t)}catch(e){return"[Array]"}if(typeof t=="object")try{return JSON.stringify(t)}catch(e){return"[Object]"}return String(t)}};export{d as Assertion,b as afterEach,y as beforeEach,c as deepEqual,g as describe,_ as expect,p as it,E as runAll,$ as skip,m as test,v as waitFor};
@@ -1,113 +0,0 @@
1
- /**
2
- * Lyt.js 统一测试框架
3
- *
4
- * 自定义轻量级测试框架,用于 Node.js 环境下运行测试。
5
- * 由 test-runner.ts 统一调度,通过 globalThis 挂载到全局。
6
- *
7
- * 使用方式:
8
- * ```ts
9
- * import { describe, it, expect } from '@lytjs/test-utils'
10
- *
11
- * describe('我的模块', () => {
12
- * it('应该正常工作', () => {
13
- * expect(1 + 1).toBe(2)
14
- * })
15
- * })
16
- * ```
17
- */
18
- export interface TestCase {
19
- name: string;
20
- fn: () => void | Promise<void>;
21
- skipped?: boolean;
22
- }
23
- export interface TestResult {
24
- name: string;
25
- suite: string;
26
- status: 'passed' | 'failed' | 'skipped';
27
- error?: Error;
28
- duration: number;
29
- }
30
- export interface TestSuite {
31
- name: string;
32
- tests: TestCase[];
33
- beforeEachFn?: (() => void)[];
34
- afterEachFn?: (() => void)[];
35
- }
36
- /**
37
- * 注册一个测试套件
38
- */
39
- export declare function describe(name: string, fn: () => void): void;
40
- /**
41
- * 注册一个测试用例
42
- */
43
- export declare function it(name: string, fn: () => void | Promise<void>): void;
44
- /**
45
- * test 是 it 的别名
46
- */
47
- export declare const test: typeof it;
48
- /**
49
- * 跳过一个测试用例
50
- */
51
- export declare function skip(name: string, fn: () => void | Promise<void>): void;
52
- /**
53
- * 注册 beforeEach 钩子
54
- */
55
- export declare function beforeEach(fn: () => void): void;
56
- /**
57
- * 注册 afterEach 钩子
58
- */
59
- export declare function afterEach(fn: () => void): void;
60
- /**
61
- * 创建一个断言对象
62
- */
63
- export declare function expect(actual: any): Assertion;
64
- /**
65
- * 深度比较两个值
66
- *
67
- * @param a 第一个值
68
- * @param b 第二个值
69
- * @returns 是否深度相等
70
- */
71
- export declare function deepEqual(a: any, b: any): boolean;
72
- /**
73
- * 等待指定毫秒数
74
- *
75
- * @param ms 等待时间(毫秒)
76
- * @returns Promise
77
- */
78
- export declare function waitFor(ms: number): Promise<void>;
79
- /**
80
- * 运行所有已注册的测试套件
81
- */
82
- export declare function runAll(): Promise<{
83
- total: number;
84
- passed: number;
85
- failed: number;
86
- skipped: number;
87
- results: TestResult[];
88
- }>;
89
- export declare class Assertion {
90
- private actual;
91
- private negated;
92
- constructor(actual: any);
93
- get not(): Assertion;
94
- toBe(expected: any): void;
95
- toEqual(expected: any): void;
96
- toBeTruthy(): void;
97
- toBeFalsy(): void;
98
- toBeNull(): void;
99
- toBeUndefined(): void;
100
- toBeDefined(): void;
101
- toThrow(message?: string): void;
102
- toContain(item: any): void;
103
- toBeGreaterThan(n: number): void;
104
- toBeLessThan(n: number): void;
105
- toBeGreaterThanOrEqual(n: number): void;
106
- toBeLessThanOrEqual(n: number): void;
107
- toHaveLength(n: number): void;
108
- toBeInstanceOf(cls: any): void;
109
- toHaveProperty(path: string, value?: any): void;
110
- private _assert;
111
- private _fmt;
112
- }
113
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}