Add test module
This commit is contained in:
parent
84b927a71b
commit
18b167266d
@ -1,4 +1,5 @@
|
|||||||
import { Logger, LevelLogLabel } from "./logger/index";
|
import { Logger } from "./logger/Logger";
|
||||||
|
import { LevelLogLabel } from "./logger/LevelLogLabel";
|
||||||
|
|
||||||
|
|
||||||
App<IAppOption>({
|
App<IAppOption>({
|
||||||
|
@ -11,7 +11,7 @@ class InternalLogLabel {
|
|||||||
* 堆栈路径样式
|
* 堆栈路径样式
|
||||||
*/
|
*/
|
||||||
public static readonly normalStyle:LogStyle = new LogStyle()
|
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();
|
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);
|
InternalLogLabel.normalStyle, false, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ class InternalLogLabel {
|
|||||||
// 获得调用堆栈
|
// 获得调用堆栈
|
||||||
let stack = StackInfo.getFirstStack();
|
let stack = StackInfo.getFirstStack();
|
||||||
|
|
||||||
return new LogLabel(stack?.url ?? "Unknown url",
|
return new LogLabel(stack?.calcPathName() ?? "Unknown url",
|
||||||
InternalLogLabel.normalStyle, false, true, true);
|
InternalLogLabel.normalStyle, false, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class InternalLogLabel {
|
|||||||
// 获得调用堆栈
|
// 获得调用堆栈
|
||||||
let stack = StackInfo.getFirstStack();
|
let stack = StackInfo.getFirstStack();
|
||||||
|
|
||||||
return new LogLabel(stack?.url ?? "Unknown url",
|
return new LogLabel(stack?.calcPathName() ?? "Unknown url",
|
||||||
InternalLogLabel.normalStyle, true, false, true);
|
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 { InternalLogLabel } from "./InternalLogLabel";
|
||||||
import { LogLabel } from "./LogLabel";
|
import { LogLabel } from "./LogLabel";
|
||||||
import { MultipleLogContent } from "./MultipleLogContent";
|
import { MultipleLogContent } from "./MultipleLogContent";
|
||||||
@ -147,12 +147,12 @@ class Logger {
|
|||||||
public static logLine<T>(content:T, ...labels:LogLabel[]):T {
|
public static logLine<T>(content:T, ...labels:LogLabel[]):T {
|
||||||
return Logger.logBase<Array<T>>(
|
return Logger.logBase<Array<T>>(
|
||||||
new MultipleLogContent<Array<T>>(content), labels,
|
new MultipleLogContent<Array<T>>(content), labels,
|
||||||
[InternalLogLabel.urlLabel, InternalLogLabel.blankLabel]
|
[InternalLogLabel.fileNameLabel, InternalLogLabel.blankLabel]
|
||||||
)[0];
|
)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 函数 Logger.logMultiple 的别名
|
* 函数 Logger.logLine 的别名
|
||||||
*/
|
*/
|
||||||
public static ll:typeof Logger.logLine = 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 {
|
public static logLineMultiple<T extends Array<any>>(labels:LogLabel[], ...content:T):T {
|
||||||
return Logger.logBase<T>(
|
return Logger.logBase<T>(
|
||||||
new MultipleLogContent<T>(...content), labels,
|
new MultipleLogContent<T>(...content), labels,
|
||||||
[InternalLogLabel.urlLabel, InternalLogLabel.blankLabel]
|
[InternalLogLabel.fileNameLabel, InternalLogLabel.blankLabel]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,13 +19,46 @@ class StackInfo {
|
|||||||
*/
|
*/
|
||||||
public url:string | undefined;
|
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.functionName = functionName;
|
||||||
this.fileName = fileName;
|
this.fileNameLine = fileNameLine;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
return this;
|
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++) {
|
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];
|
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";
|
|
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