Compare commits
	
		
			4 Commits
		
	
	
		
			d02cc5db3b
			...
			18b167266d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 18b167266d | |||
| 84b927a71b | |||
| 004ea1895b | |||
| 0f70998a5f | 
| @ -1,4 +1,5 @@ | ||||
| import { Logger, LevelLogLabel } from "./logger/index"; | ||||
| import { Logger } from "./logger/Logger"; | ||||
| import { LevelLogLabel } from "./logger/LevelLogLabel"; | ||||
| 
 | ||||
| 
 | ||||
| App<IAppOption>({ | ||||
|  | ||||
| @ -11,7 +11,7 @@ class InternalLogLabel { | ||||
|      * 堆栈路径样式 | ||||
|      */ | ||||
|     public static readonly normalStyle:LogStyle = new LogStyle() | ||||
|     .setColor("#CCCCCC").setBorder("4px", "1px solid #979797").setBlank("0 5px"); | ||||
|     .setColor("#979797").setBorder("4px", "1px solid #979797").setBlank("0 5px"); | ||||
| 
 | ||||
|     /** | ||||
|      * 一个回车 | ||||
| @ -27,7 +27,7 @@ class InternalLogLabel { | ||||
|         // 获得调用堆栈
 | ||||
|         let stack = StackInfo.getFirstStack(); | ||||
| 
 | ||||
|         return new LogLabel(stack?.fileName ?? "Unknown file name",  | ||||
|         return new LogLabel(stack?.calcFileName() ?? "Unknown file name",  | ||||
|         InternalLogLabel.normalStyle, false, true, true); | ||||
|     } | ||||
| 
 | ||||
| @ -39,7 +39,7 @@ class InternalLogLabel { | ||||
|         // 获得调用堆栈
 | ||||
|         let stack = StackInfo.getFirstStack(); | ||||
| 
 | ||||
|         return new LogLabel(stack?.url ?? "Unknown url",  | ||||
|         return new LogLabel(stack?.calcPathName() ?? "Unknown url",  | ||||
|         InternalLogLabel.normalStyle, false, true, true); | ||||
|     } | ||||
| 
 | ||||
| @ -51,7 +51,7 @@ class InternalLogLabel { | ||||
|         // 获得调用堆栈
 | ||||
|         let stack = StackInfo.getFirstStack(); | ||||
| 
 | ||||
|         return new LogLabel(stack?.url ?? "Unknown url",  | ||||
|         return new LogLabel(stack?.calcPathName() ?? "Unknown url",  | ||||
|         InternalLogLabel.normalStyle, true, false, true); | ||||
|     } | ||||
|      | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import {LOGGER_CONSOLE, LOGGER_FILTER} from "../Config"; | ||||
| import { LOGGER_FILTER, LOGGER_CONSOLE } from "../utils/Config"; | ||||
| import { InternalLogLabel } from "./InternalLogLabel"; | ||||
| import { LogLabel } from "./LogLabel"; | ||||
| import { MultipleLogContent } from "./MultipleLogContent"; | ||||
| @ -147,12 +147,12 @@ class Logger { | ||||
|     public static logLine<T>(content:T, ...labels:LogLabel[]):T { | ||||
|         return Logger.logBase<Array<T>>( | ||||
|             new MultipleLogContent<Array<T>>(content), labels,  | ||||
|             [InternalLogLabel.urlLabel, InternalLogLabel.blankLabel] | ||||
|             [InternalLogLabel.fileNameLabel, InternalLogLabel.blankLabel] | ||||
|         )[0]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 函数 Logger.logMultiple 的别名 | ||||
|      * 函数 Logger.logLine 的别名 | ||||
|      */ | ||||
|     public static ll:typeof Logger.logLine = Logger.logLine; | ||||
| 
 | ||||
| @ -164,7 +164,7 @@ class Logger { | ||||
|     public static logLineMultiple<T extends Array<any>>(labels:LogLabel[], ...content:T):T { | ||||
|         return Logger.logBase<T>( | ||||
|             new MultipleLogContent<T>(...content), labels,  | ||||
|             [InternalLogLabel.urlLabel, InternalLogLabel.blankLabel] | ||||
|             [InternalLogLabel.fileNameLabel, InternalLogLabel.blankLabel] | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -19,13 +19,46 @@ class StackInfo { | ||||
|      */ | ||||
|     public url:string | undefined; | ||||
| 
 | ||||
|     public setInfo(functionName:string, fileName:string, url:string):StackInfo { | ||||
|     /** | ||||
|      * 文件名和行号 | ||||
|      */ | ||||
|     public fileNameLine: string | undefined;     | ||||
| 
 | ||||
|     /** | ||||
|      * 设置信息 | ||||
|      * @param functionName 函数名 | ||||
|      * @param fileName 文件名 | ||||
|      * @param url 文件路径 | ||||
|      */ | ||||
|     public setInfo(functionName:string, fileNameLine:string, url:string):StackInfo { | ||||
|         this.functionName = functionName; | ||||
|         this.fileName = fileName; | ||||
|         this.fileNameLine = fileNameLine; | ||||
|         this.url = url; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 计算文件名 | ||||
|      */ | ||||
|     public calcFileName():string | undefined { | ||||
| 
 | ||||
|         let replaceToTs = this.fileNameLine?.replace(".js", ".ts"); | ||||
|         let matched = replaceToTs?.match(/^(.+\.(js|ts)):\d+:\d+$/); | ||||
| 
 | ||||
|         return matched ? matched[1] : undefined; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 计算路径名 | ||||
|      */ | ||||
|     public calcPathName():string | undefined { | ||||
| 
 | ||||
|         let replaceToTs = this.url?.replace(".js", ".ts"); | ||||
|         let matched = replaceToTs?.match(/^https?:\/\/(\d+\.){3}\d+:\d+\/(.+):\d+:\d+$/); | ||||
| 
 | ||||
|         return matched ? matched[2] : undefined; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取函数调用栈列表 | ||||
|      */ | ||||
| @ -65,7 +98,7 @@ class StackInfo { | ||||
|     /** | ||||
|      * 排除的 | ||||
|      */ | ||||
|     public static readonly excludeFile:RegExp = /^Logger\.js:\d+:\d+/; | ||||
|     public static readonly excludeFile:RegExp = /^.*(\\|\/)logger(\\|\/).+\.js:\d+:\d+/; | ||||
| 
 | ||||
|     /** | ||||
|      * 获取第一个调用栈 | ||||
| @ -76,9 +109,9 @@ class StackInfo { | ||||
| 
 | ||||
|         for(let i = 0; i < callStack.length; i++) { | ||||
| 
 | ||||
|             if(!callStack[i].fileName) continue; | ||||
|             if(!callStack[i].url) continue; | ||||
| 
 | ||||
|             if(!StackInfo.excludeFile.test(callStack[i].fileName ?? "")) { | ||||
|             if(!StackInfo.excludeFile.test(callStack[i].url ?? "")) { | ||||
|                 return callStack[i]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -1,11 +0,0 @@ | ||||
| import Logger from "./Logger"; | ||||
| 
 | ||||
| export default Logger; | ||||
| export { Logger }; | ||||
| 
 | ||||
| export { InternalLogLabel } from "./InternalLogLabel"; | ||||
| export { MultipleLogContent } from "./MultipleLogContent"; | ||||
| export { LevelLogLabel } from "./LevelLogLabel"; | ||||
| export { LogLabel } from "./LogLabel"; | ||||
| export { LogStyle } from "./LogStyle"; | ||||
| export { StackInfo } from "./StackInfo"; | ||||
| @ -1 +1 @@ | ||||
| <text>pages/Account/Account.wxml</text> | ||||
| <!-- <text>pages/Account/Account.wxml</text> --> | ||||
|  | ||||
							
								
								
									
										206
									
								
								miniprogram/utils/TestCase.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								miniprogram/utils/TestCase.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,206 @@ | ||||
| // import { Logger } from "../logger/Logger";
 | ||||
| import { LogStyle } from "../logger/LogStyle"; | ||||
| import { LogLabel } from "../logger/LogLabel"; | ||||
| 
 | ||||
| /** | ||||
|  * 测试结果 | ||||
|  */ | ||||
| class TestResult { | ||||
|      | ||||
|     /** | ||||
|      * 用例名称 | ||||
|      */ | ||||
|     public caseName:string; | ||||
| 
 | ||||
|     /** | ||||
|      * 测试结果 | ||||
|      */ | ||||
|     public result:boolean; | ||||
| 
 | ||||
|     /** | ||||
|      * 消息 | ||||
|      */ | ||||
|     public message:string; | ||||
| 
 | ||||
|     /** | ||||
|      * 附加消息 | ||||
|      */ | ||||
|     public attach:string; | ||||
| 
 | ||||
|     /** | ||||
|      * 初始化 | ||||
|      * @param caseName 用例名称 | ||||
|      */ | ||||
|     constructor(caseName:string) { | ||||
|         this.caseName = caseName; | ||||
|         this.result = false; | ||||
|         this.message = ""; | ||||
|         this.attach = ""; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置结果 | ||||
|      */ | ||||
|     public setResult(result:boolean, message?:string, attach?:string) { | ||||
|         this.result = result; | ||||
|         this.message = message ?? (result ? "success!" : "failed!"); | ||||
|         this.attach = attach ?? this.attach; | ||||
| 
 | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 测试函数结构 | ||||
|  */ | ||||
| type TestFunction = () => TestResult | Promise<TestResult>; | ||||
| 
 | ||||
| /** | ||||
|  * 收集测试函数结构 | ||||
|  */ | ||||
| class CaseCollect { | ||||
| 
 | ||||
|     /** | ||||
|      * 用例键名 | ||||
|      */ | ||||
|     public key:string; | ||||
| 
 | ||||
|     /** | ||||
|      * 用例测试函数 | ||||
|      */ | ||||
|     public caseFunction:TestFunction; | ||||
| 
 | ||||
|     /** | ||||
|      * 测试结果 | ||||
|      */ | ||||
|     result: Promise<TestResult> | undefined; | ||||
| 
 | ||||
|     /** | ||||
|      * @param key 测试用例键名 | ||||
|      * @param caseFunction 测试函数 | ||||
|      */ | ||||
|     public constructor(key:string, caseFunction:TestFunction) { | ||||
|         this.key = key; | ||||
|         this.caseFunction = caseFunction; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 运行测试用例 | ||||
|      */ | ||||
|     public async runTestCase():Promise<CaseCollect> { | ||||
|          | ||||
|         let result = this.caseFunction(); | ||||
| 
 | ||||
|         if(result instanceof Promise) { | ||||
|             this.result = result; | ||||
|         } else { | ||||
|             this.result = Promise.resolve(result); | ||||
|         } | ||||
| 
 | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public static readonly baseStyle = new LogStyle().setBlank(); | ||||
| 
 | ||||
|     public static readonly successLabel:LogLabel = new LogLabel("√", | ||||
|         new LogStyle().setBlank("0 4px").setBorder("1000px", "1px solid green") | ||||
|     ); | ||||
| 
 | ||||
|     /** | ||||
|      * 打印结果 | ||||
|      * @param current 当前进度 | ||||
|      * @param total 总进度 | ||||
|      */ | ||||
|     public printResult(current?:number, total?:number) { | ||||
| 
 | ||||
|         // 如果测试没有运行,先运行它
 | ||||
|         if(this.result === void 0) this.runTestCase(); | ||||
| 
 | ||||
|         this.result?.then((res) => { | ||||
| 
 | ||||
|             if(res.result) { | ||||
|                 console.log( | ||||
|                     `%c√%c %c1/1%c %c${ this.key }%c ` + res.message,  | ||||
|                     "padding:0 4px; border-radius:1000px; border:1px solid green; color:green", | ||||
|                     "", "padding:0 4px; border-radius:4px; border:1px solid green; color:green", | ||||
|                     "", "padding:0 4px; border-radius:4px; border:1px solid #979797; color:#979797", | ||||
|                     "" | ||||
|                 ) | ||||
|             } else { | ||||
|                 console.log( | ||||
|                     `%c√%c %c1/1%c %c${ this.key }%c ` + res.message,  | ||||
|                     "padding:0 4px; border-radius:1000px; border:1px solid red; color:red", | ||||
|                     "", "padding:0 4px; border-radius:4px; border:1px solid red; color:red", | ||||
|                     "", "padding:0 4px; border-radius:4px; border:1px solid #979797; color:#979797", | ||||
|                     "" | ||||
|                 ) | ||||
|             } | ||||
|             console.log(res) | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 收集测试用例 | ||||
|      * @param testCaseClass 测试用例表 | ||||
|      */ | ||||
|     public static collectCase(testCaseClass:ITestCase):CaseCollect[] { | ||||
| 
 | ||||
|         // 获取静态方法 key
 | ||||
|         let key = Object.getOwnPropertyNames(testCaseClass); | ||||
| 
 | ||||
|         // 过滤掉通用的方法和属性
 | ||||
|         key = key.filter((key) => !/(length|name|prototype)/.test(key) ); | ||||
| 
 | ||||
|         // 生成 CaseCollect
 | ||||
|         let caseCollect = []; | ||||
|          | ||||
|         for (let i = 0; i < key.length; i++) { | ||||
|             caseCollect.push(new CaseCollect(key[i], testCaseClass[key[i]])) | ||||
|         } | ||||
| 
 | ||||
|         return caseCollect; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 运行测试样例 | ||||
|      */ | ||||
|     public static async runCollectCase(cases:CaseCollect[]):Promise<CaseCollect[]> { | ||||
| 
 | ||||
|         let running:Promise<CaseCollect>[] = []; | ||||
| 
 | ||||
|         for(let i = 0; i < cases.length; i++) { | ||||
|             running.push(cases[i].runTestCase()); | ||||
|         } | ||||
| 
 | ||||
|         return Promise.all(running); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 启动单元测试 | ||||
|      */ | ||||
|     public static runUnitTest(testCaseClass:ITestCase) { | ||||
|          | ||||
|         let caseCollect = this.collectCase(testCaseClass); | ||||
| 
 | ||||
|         CaseCollect.runCollectCase(caseCollect).then((caseCollect:CaseCollect[]) => { | ||||
|              | ||||
|             for(let i = 0; i < caseCollect.length; i++) { | ||||
|                 caseCollect[i].printResult() | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 测试用例接口 | ||||
|  */ | ||||
| interface ITestCase { | ||||
| 
 | ||||
|     /** | ||||
|      * 测试用例函数 | ||||
|      */ | ||||
|     [key:string]:TestFunction; | ||||
| } | ||||
| 
 | ||||
| export default ITestCase; | ||||
| export { ITestCase, TestResult, TestFunction, CaseCollect }; | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user