This repository has been archived on 2025-04-22. You can view files and clone it, but cannot push or open issues or pull requests.
hlk_autotest/tests/utils/utils.js
LingandRX 6517e4192c feat: 初始化慧来客自动化测试项目
- 添加项目配置文件和环境变量设置
- 创建测试用例目录结构和命名规范
- 实现基础测试 fixture 和页面对象模型
- 添加示例测试用例和数据生成器
- 配置 playwright 和 gitignore 文件
2024-12-22 19:18:27 +08:00

202 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 解析二维码
const decodeImage = require('jimp').read;
const { readFile, unlinkSync } = require('fs');
const qrcodeReader = require('qrcode-reader');
const sharp = require('sharp');
const Tesseract = require('tesseract.js');
/**
* 解析二维码
* @param {*} pathSrc 图片路径
* @returns Promise<qrResult> 二维码内容
*/
export const decodeQR = function(pathSrc) {
// var filePath = path.resolve(__dirname, pathSrc);
return new Promise((resolve, reject) => {
readFile(pathSrc, function(err, fileBuffer) {
if (err) {
reject(err);
return;
}
decodeImage(fileBuffer, function(err, image) {
if (err) {
reject(err);
return;
}
let decodeQR = new qrcodeReader();
decodeQR.callback = function(errorWhenDecodeQR, result) {
if (errorWhenDecodeQR) {
reject(errorWhenDecodeQR);
unlinkSync(pathSrc);
return;
}
if (!result) {
console.log('gone with wind');
resolve('');
unlinkSync(pathSrc);
} else {
resolve(result.result);
console.log(result.result); //结果
unlinkSync(pathSrc);
}
};
decodeQR.decode(image.bitmap);
});
});
});
};
/**
* - ¥1500 -> { method: '', amount: 1500 }
* - 银联¥1500.0 -> { method: 银联, amount: 1500 }
* @param {string} amountText ¥1500
* @returns {{ method: string, amount: number }}
*/
export const convertAmountText = function(amountText) {
let method = '';
let amount = 0;
const text = amountText.replace('\n', '');
const amountTextArray = text.match(/(\s)¥([0-9.]+)/);
if (amountTextArray) {
method = amountTextArray[1];
amount = Number(amountTextArray[2]);
}
return { method: method, amount: amount };
};
/**
* 返回列表中目标元素的index
* @param {import('@playwright/test').Locator} targetElement
* @param elementList
*/
export const getListIndexForTargetElement = async (targetElement, elementList) => {
return targetElement.evaluate((el, list) => {
return Array.from(list).indexOf(el);
}, await elementList.elementHandles());
};
/**
* 保留数字(清空非数字)
* @param {*} str 仅保留数字
* @returns
*/
export function KeepOnlyNumbers(str) {
return str.replace(/\D/g, '');
}
/**
* 保留中文和数字(清空符号)
* @param {*} str 仅保留中文和数字
* @returns
*/
export function CleanPunctuation(str) {
return str.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, '');
}
/**
* 等待指定接口加载完成
* @param {import('@playwright/test').Page} page
* @param {string[]} apiArray 接口名称数组
* @returns Promise<Response[]>
*/
export const waitSpecifyApiLoad = (page, apiArray) => {
if (apiArray === undefined || apiArray.length === 0) {
return Promise.resolve([]);
}
return Promise.all(
apiArray.map(api => page.waitForResponse(res => res.url().includes(api) && res.status() === 200)),
);
};
/**
* 等待Locator元素内的文本值不再变化
* @param {import('@playwright/test').Locator} locator
* @param {boolean} [waitForAnimations = false] 等待动画结束
* @param {number} [sameTextCount = 20] 重复次数
* @returns
*/
export const waitStable = async function(locator, waitForAnimations = false, sameTextCount = 20) {
await locator.evaluate(
async (element, { waitForAnimations, sameTextCount }) => {
const progressIsStable = async function(element, lastText = null, sameTextCounter = 0, iteration = 0) {
// 递归次数超过500次退出
if (iteration > 500) {
throw new Error('超出了最大的递归次数');
}
// 等待动画结束
if (waitForAnimations) {
await Promise.all(element.getAnimations().map(animation => animation.finished));
}
// 间隔15ms检测一次元素变化
await new Promise(resolve => setTimeout(resolve, 15));
// 获取当前元素文本
const text = element.innerText;
// 和上次元素的文本进行对比
const sameText = text === lastText;
if (sameText) {
// 和上次一致,则+1
++sameTextCounter;
} else {
// 和上次不一致则归0
sameTextCounter = 0;
}
const isStable = sameTextCounter >= sameTextCount;
if (isStable) {
// 重复次数超过20次则推出循环
return true;
} else {
// 否则继续递归
return progressIsStable(element, text, sameTextCounter, ++iteration);
}
};
// 进行递归
return progressIsStable(element);
},
{ waitForAnimations, sameTextCount },
);
// 返回通过校验的locator
return locator;
};
/**
* 处理图像并进行验证码识别
* @param {string} inputImagePath - 输入图像文件名(位于 .images 文件夹内)
* @param {string} outputImagePath - 输出处理后图像的文件名(位于 .images 文件夹内)
* @returns {Promise<string>} - 返回识别的文本结果
*/
export const processAndRecognizeCaptcha = async (inputImagePath, outputImagePath) => {
try {
// 图像处理
await sharp(inputImagePath)
// .sharpen()
.modulate({
brightness: 1.2, // 增加亮度
contrast: 1.5, // 增强对比度
})
.resize(800) // 调整图像宽度为800像素保持纵横比
.grayscale() // 转换为灰度图
.threshold(128) // 二值化阈值设定为128
.toFile(outputImagePath);
console.log('图像处理完成:', outputImagePath);
// 图像识别
const {
data: { text },
} = await Tesseract.recognize(outputImagePath, 'eng', {
langPath: './tessdata',
});
console.log('识别结果:', text.trim());
return text.replace(/\s+/g, '').trim(); // 返回识别的文本结果
} catch (err) {
console.error('处理或识别出错:', err);
throw err; // 将错误抛出以供调用者处理
}
};