Files
dingtalk-bot/tests/helpers/assertions.js

244 lines
6.3 KiB
JavaScript

/**
* 自定义断言工具
* 提供项目特定的断言方法
*/
import { expect } from 'vitest';
/**
* 验证钉钉消息格式
*
* @param {object} message - 消息对象
* @param {string} expectedType - 期望的消息类型
*/
export function assertDingTalkMessage(message, expectedType) {
expect(message).toBeDefined();
expect(message).toBeTypeOf('object');
expect(message.msgtype).toBe(expectedType);
switch (expectedType) {
case 'text':
expect(message.text).toBeDefined();
expect(message.text.content).toBeTypeOf('string');
break;
case 'markdown':
expect(message.markdown).toBeDefined();
expect(message.markdown.title).toBeTypeOf('string');
expect(message.markdown.text).toBeTypeOf('string');
break;
case 'link':
expect(message.link).toBeDefined();
expect(message.link.title).toBeTypeOf('string');
expect(message.link.text).toBeTypeOf('string');
expect(message.link.messageUrl).toBeTypeOf('string');
break;
case 'actionCard':
expect(message.actionCard).toBeDefined();
expect(message.actionCard.title).toBeTypeOf('string');
expect(message.actionCard.text).toBeTypeOf('string');
break;
case 'feedCard':
expect(message.feedCard).toBeDefined();
expect(message.feedCard.links).toBeInstanceOf(Array);
break;
}
}
/**
* 验证 @ 功能配置
*
* @param {object} message - 消息对象
* @param {object} expectedAt - 期望的 @ 配置
*/
export function assertAtConfiguration(message, expectedAt) {
expect(message.at).toBeDefined();
if (expectedAt.atMobiles) {
expect(message.at.atMobiles).toEqual(expectedAt.atMobiles);
}
if (expectedAt.atUserIds) {
expect(message.at.atUserIds).toEqual(expectedAt.atUserIds);
}
if (expectedAt.isAtAll !== undefined) {
expect(message.at.isAtAll).toBe(expectedAt.isAtAll);
}
}
/**
* 验证 ActionCard 按钮配置
*
* @param {object} actionCard - ActionCard 对象
* @param {object} expectedButtons - 期望的按钮配置
*/
export function assertActionCardButtons(actionCard, expectedButtons) {
if (expectedButtons.single) {
expect(actionCard.singleTitle).toBe(expectedButtons.single.title);
expect(actionCard.singleURL).toBe(expectedButtons.single.url);
expect(actionCard.btns).toBeUndefined();
} else if (expectedButtons.multiple) {
expect(actionCard.btns).toBeInstanceOf(Array);
expect(actionCard.btns).toHaveLength(expectedButtons.multiple.length);
expectedButtons.multiple.forEach((expectedBtn, index) => {
expect(actionCard.btns[index].title).toBe(expectedBtn.title);
expect(actionCard.btns[index].actionURL).toBe(expectedBtn.actionURL);
});
expect(actionCard.singleTitle).toBeUndefined();
expect(actionCard.singleURL).toBeUndefined();
}
if (expectedButtons.orientation !== undefined) {
expect(actionCard.btnOrientation).toBe(expectedButtons.orientation);
}
}
/**
* 验证 FeedCard 链接配置
*
* @param {object} feedCard - FeedCard 对象
* @param {Array} expectedLinks - 期望的链接配置
*/
export function assertFeedCardLinks(feedCard, expectedLinks) {
expect(feedCard.links).toBeInstanceOf(Array);
expect(feedCard.links).toHaveLength(expectedLinks.length);
expectedLinks.forEach((expectedLink, index) => {
const link = feedCard.links[index];
expect(link.title).toBe(expectedLink.title);
expect(link.messageURL).toBe(expectedLink.messageURL);
if (expectedLink.picURL) {
expect(link.picURL).toBe(expectedLink.picURL);
}
});
}
/**
* 验证配置对象结构
*
* @param {object} config - 配置对象
* @param {Array} requiredFields - 必需字段列表
*/
export function assertConfigStructure(config, requiredFields = []) {
expect(config).toBeDefined();
expect(config).toBeTypeOf('object');
requiredFields.forEach(field => {
expect(config).toHaveProperty(field);
});
}
/**
* 验证错误对象
*
* @param {Error} error - 错误对象
* @param {string} expectedMessage - 期望的错误消息(可选)
* @param {string} expectedCode - 期望的错误代码(可选)
*/
export function assertError(error, expectedMessage, expectedCode) {
expect(error).toBeInstanceOf(Error);
if (expectedMessage) {
expect(error.message).toContain(expectedMessage);
}
if (expectedCode) {
expect(error.code).toBe(expectedCode);
}
}
/**
* 验证 HTTP 请求选项
*
* @param {object} options - 请求选项
* @param {object} expected - 期望的选项
*/
export function assertHttpOptions(options, expected) {
expect(options).toBeDefined();
expect(options).toBeTypeOf('object');
if (expected.hostname) {
expect(options.hostname).toBe(expected.hostname);
}
if (expected.path) {
expect(options.path).toBe(expected.path);
}
if (expected.method) {
expect(options.method).toBe(expected.method);
}
if (expected.headers) {
expect(options.headers).toEqual(expect.objectContaining(expected.headers));
}
}
/**
* 验证 URL 格式
*
* @param {string} url - URL 字符串
*/
export function assertValidUrl(url) {
expect(url).toBeTypeOf('string');
expect(url.length).toBeGreaterThan(0);
expect(() => new URL(url)).not.toThrow();
}
/**
* 验证 JSON 字符串
*
* @param {string} jsonString - JSON 字符串
* @returns {object} 解析后的对象
*/
export function assertValidJson(jsonString) {
expect(jsonString).toBeTypeOf('string');
let parsed;
expect(() => {
parsed = JSON.parse(jsonString);
}).not.toThrow();
return parsed;
}
/**
* 验证数组包含特定元素
*
* @param {Array} array - 数组
* @param {*} element - 要查找的元素
*/
export function assertArrayContains(array, element) {
expect(array).toBeInstanceOf(Array);
expect(array).toContain(element);
}
/**
* 验证对象深度相等
*
* @param {object} actual - 实际对象
* @param {object} expected - 期望对象
*/
export function assertDeepEqual(actual, expected) {
expect(actual).toEqual(expected);
}
/**
* 验证函数抛出特定错误
*
* @param {Function} fn - 要测试的函数
* @param {string|RegExp} expectedError - 期望的错误消息或正则表达式
*/
export function assertThrows(fn, expectedError) {
if (typeof expectedError === 'string') {
expect(fn).toThrow(expectedError);
} else if (expectedError instanceof RegExp) {
expect(fn).toThrow(expectedError);
} else {
expect(fn).toThrow();
}
}