import { describe, it, expect, vi, beforeEach, afterEach, test } from 'vitest';
import {
getMessageId,
htmlEncode,
cutStr,
getBytes,
isIE11,
isSafari,
getBrowserType,
isLowBrowserVer,
updateLocalLoginCount,
transformRole,
getRuleText,
dataFilter,
dataSort,
compareStrings,
getKey,
baseSort,
dataCustomSort,
deepClone,
compareObjectEqual,
showElMessage,
formattingTime,
loadComponent,
iPv6Translation,
convertToBinary,
restituteIpv6,
initOriginalData,
getSsoErrorMsg,
openOnlineHelp,
getRealColor,
getLocationSearch,
urlStandardization,
escapeHeader,
urlReplace,
frontDownload,
getRandomNumber,
deepEqual,
safeStringify,
} from '@/utils/utils.ts';
import { UTILS } from '@/model/test-enum.ts';
vi.mock('@/model/base-interface', () => {});
vi.mock('@/utils/language', () => ({
traduction: vi.fn(key => key),
}));
vi.mock('element-plus', () => ({
ElMessage: vi.fn(),
}));
vi.mock('@/utils/regular', () => ({
IPREGEXV4: UTILS.IPREGEXV4,
URL_REPLACE: UTILS.URL_REPLACE,
}));
vi.mock('@/utils/composition', () => ({
getStoreData: vi.fn(),
setStoreData: vi.fn(),
}));
vi.mock('@/services/help-relations.service', () => ({
default: {
helpRelation: vi.fn(() => 'test-help-file.html'),
},
}));
vi.mock('@/model/router-utils', () => ({
ROUTER_BASE: 'test/',
}));
describe('test', () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe('getMessageId', () => {
it('空输入', () => {
expect(getMessageId(null)).toBeNull();
expect(getMessageId(undefined)).toBeUndefined();
});
it('应该处理错误对象数组', () => {
const error = {
error: [
{ code: 'ERR001', message: 'Error message 1' },
{ code: 'ERR002', message: 'Error message 2' },
],
};
const result = getMessageId(error);
expect(result).toHaveLength(2);
expect(result[0]).toEqual({ code: 'ERR001', message: 'Error message 1', relation: '' });
expect(result[1]).toEqual({ code: 'ERR002', message: 'Error message 2', relation: '' });
});
it('应该处理非数组错误', () => {
const error = { code: 'ERR001', message: 'Error message 1' };
const result = getMessageId(error);
expect(result).toHaveLength(0);
});
});
describe('htmlEncode', () => {
it('应该处理非字符串输入', () => {
expect(htmlEncode(null)).toBeNull();
expect(htmlEncode(123)).toBe(123);
expect(htmlEncode({})).toEqual({});
});
it('应该编码HTML特殊字符', () => {
const input = '<script>"alert(\'test\')"</script>';
const expected = '<script>"alert('test')"</script>';
expect(htmlEncode(input)).toBe(expected);
});
it('应该处理非数组错误', () => {
expect(htmlEncode('')).toBe('');
});
});
describe('cutStr', () => {
it('应该按字节长度截取字符串', () => {
expect(cutStr('abcdef', 3)).toBe('abc');
expect(cutStr('中文测试', 6)).toBe('中文');
expect(cutStr('abc中文', 3)).toBe('abc');
expect(cutStr('Aь', 3)).toBe('Aь');
});
it('应该处理不需要截取的情况', () => {
expect(cutStr('abc', 5)).toBe('abc');
expect(cutStr('', 5)).toBe('');
});
});
describe('cutStr', () => {
it('应该按字节长度截取字符串', () => {
expect(cutStr('abcdef', 3)).toBe('abc');
expect(cutStr('中文测试', 6)).toBe('中文');
expect(cutStr('abc中文', 3)).toBe('abc');
expect(cutStr('Aь', 3)).toBe('Aь');
});
it('应该处理不需要截取的情况', () => {
expect(cutStr('abc', 5)).toBe('abc');
expect(cutStr('', 5)).toBe('');
});
});
describe('getBytes', () => {
it('应该计算字符串的字节长度', () => {
expect(getBytes('abc')).toBe(3);
expect(getBytes('中文')).toBe(6);
expect(getBytes('a中文b')).toBe(8);
});
it('应该处理非字符串输入', () => {
expect(getBytes(null)).toBe(0);
expect(getBytes(123)).toBe(0);
expect(getBytes(undefined)).toBe(0);
});
});
describe('浏览器检测函数', () => {
beforeEach(() => {
global.originalNavigator = { ...global.navigator };
});
afterEach(() => {
Object.defineProperty(global, 'navigator', {
value: global.originalNavigator,
writable: true,
});
});
it('isIE11应该检测IE11浏览器', () => {
Object.defineProperty(global, 'navigator', {
value: {
userAgent: 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko',
},
writable: true,
});
expect(isIE11()).toBe(true);
});
it('isSafari应该检测Safari浏览器', () => {
Object.defineProperty(global, 'navigator', {
value: {
userAgent:
'Mozilla/5.0 (Macintosh; Inter Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15',
},
writable: true,
});
expect(isSafari()).toBe(true);
});
});
describe('getBrowserType', () => {
beforeEach(() => {
Object.defineProperty(navigator, 'userAgent', {
value: '',
writable: true,
});
});
test('should return Edge browser type and version', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.54',
writable: true,
});
const result = getBrowserType();
expect(result.browser).toBe('chrome');
expect(result.version).toBe(91);
});
test('should return Firefox browser type and version', () => {
Object.defineProperty(navigator, 'userAgent', {
value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0',
writable: true,
});
const result = getBrowserType();
expect(result.browser).toBe('firefox');
expect(result.version).toBe(91);
});
test('should return Chrome browser type and version', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
writable: true,
});
const result = getBrowserType();
expect(result.browser).toBe('chrome');
expect(result.version).toBe(91);
});
test('should return Chrome browser type and version', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/ Safari/537.36',
writable: true,
});
const result = getBrowserType();
expect(result.browser).toBe('chrome');
expect(result.version).toBe(NaN);
});
test('should return Safari browser type and version', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15',
writable: true,
});
const result = getBrowserType();
expect(result.browser).toBe('safari');
expect(result.version).toBe(NaN);
});
test('should return default values for unknown browser', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) UnknownBrowser/1.0',
writable: true,
});
const result = getBrowserType();
expect(result.browser).toBe('');
expect(result.version).toBe(0);
});
test('should return Edge browser type when multiple browser identifiers are present', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.54',
writable: true,
});
const result = getBrowserType();
expect(result.browser).toBe('chrome');
expect(result.version).toBe(91);
});
test('should return default values for empty or invalid userAgent', () => {
Object.defineProperty(navigator, 'userAgent', {
value: '',
writable: true,
});
const result = getBrowserType();
expect(result.browser).toBe('');
expect(result.version).toBe(0);
Object.defineProperty(navigator, 'userAgent', {
value: 'Invalid userAgent string',
writable: true,
});
const result2 = getBrowserType();
expect(result2.browser).toBe('');
expect(result2.version).toBe(0);
});
});
describe('isLowBrowserVer', () => {
beforeEach(() => {
Object.defineProperty(navigator, 'userAgent', {
value: '',
writable: true,
});
});
test('should return true for Firefox version below 63', () => {
Object.defineProperty(navigator, 'userAgent', {
value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0',
writable: true,
});
expect(isLowBrowserVer()).toBe(true);
});
test('should return false for Firefox version 63 or higher', () => {
Object.defineProperty(navigator, 'userAgent', {
value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
writable: true,
});
expect(isLowBrowserVer()).toBe(false);
});
test('should return true for Chrome version below 70', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
writable: true,
});
expect(isLowBrowserVer()).toBe(true);
});
test('should return false for Chrome version 70 or higher', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36',
writable: true,
});
expect(isLowBrowserVer()).toBe(false);
});
test('should return true for Safari version below 11', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/10.1 Safari/605.1.15',
writable: true,
});
expect(isLowBrowserVer()).toBe(false);
});
test('should return false for Safari version 11 or higher', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15',
writable: true,
});
expect(isLowBrowserVer()).toBe(false);
});
test('should return true for IE version below 11', () => {
Object.defineProperty(navigator, 'userAgent', {
value: 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
writable: true,
});
expect(isLowBrowserVer()).toBe(true);
});
test('should return false for IE version 11 or higher', () => {
Object.defineProperty(navigator, 'userAgent', {
value: 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko',
writable: true,
});
expect(isLowBrowserVer()).toBe(true);
});
test('should return false for unknown browser', () => {
Object.defineProperty(navigator, 'userAgent', {
value:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) UnknownBrowser/1.0',
writable: true,
});
expect(isLowBrowserVer()).toBe(true);
});
test('should return false for empty or invalid userAgent', () => {
Object.defineProperty(navigator, 'userAgent', {
value: '',
writable: true,
});
expect(isLowBrowserVer()).toBe(true);
Object.defineProperty(navigator, 'userAgent', {
value: 'Invalid userAgent string',
writable: true,
});
expect(isLowBrowserVer()).toBe(true);
});
});
describe('updateLocalLoginCount', () => {
let originalLocalStorage;
let originalSessionStorage;
beforeEach(() => {
originalLocalStorage = localStorage;
originalSessionStorage = sessionStorage;
const mockLocalStorage = {
getItem: vi.fn(),
setItem: vi.fn(),
removeItem: vi.fn(),
};
const mockSessionStorage = {
getItem: vi.fn(),
setItem: vi.fn(),
removeItem: vi.fn(),
};
Object.defineProperty(global, 'localStorage', {
value: mockLocalStorage,
writable: true,
});
Object.defineProperty(global, 'sessionStorage', {
value: mockSessionStorage,
writable: true,
});
mockLocalStorage.getItem.mockImplementation(key => {
if (key === 'tabs') {
return '0';
}
return null;
});
mockSessionStorage.getItem.mockImplementation(key => null);
});
afterEach(() => {
global.localStorage = originalLocalStorage;
global.sessionStorage = originalSessionStorage;
});
it('should delete tabs and remove tabIsValid when type is delete', () => {
localStorage.setItem('tabs', '5');
sessionStorage.setItem('tabIsValid', 'true');
updateLocalLoginCount('delete');
expect(localStorage.setItem).toHaveBeenCalledWith('tabs', '0');
expect(sessionStorage.removeItem).toHaveBeenCalledWith('tabIsValid');
});
it('should add to tabs and set tabIsValid when type is add and tabIsValid is not present', () => {
sessionStorage.getItem.mockImplementation(key => null);
updateLocalLoginCount('add');
expect(localStorage.setItem).toHaveBeenCalledWith('tabs', '1');
expect(sessionStorage.setItem).toHaveBeenCalledWith('tabIsValid', 'true');
});
it('should not add to tabs when type is add and tabIsValid is present', () => {
sessionStorage.getItem.mockImplementation(key => 'true');
updateLocalLoginCount('add');
expect(localStorage.setItem).not.toHaveBeenCalled();
expect(sessionStorage.setItem).not.toHaveBeenCalled();
});
});
describe('dataFilter', () => {
const testData = [
{ name: 'John', age: 30, city: 'New York' },
{ name: 'Jane', age: 25, city: 'Los Angeles' },
{ name: 'Bob', age: 35, city: 'Chicago' },
];
it('应该根据指定字段过滤数据', () => {
const result = dataFilter(testData, ['name', 'city'], 'jan');
expect(result).toHaveLength(1);
expect(result[0].name).toBe('Jane');
});
it('应该处理空搜索条件', () => {
const result = dataFilter(testData, ['name'], '');
expect(result).toEqual(testData);
});
it('应该处理空数据或空字段列表', () => {
expect(dataFilter([], ['name'], 'test')).toEqual([]);
expect(dataFilter(testData, [], 'test')).toEqual(testData);
});
it('应该处理空数据或空字段列表', () => {
expect(dataFilter([], ['name'], 'test')).toEqual([]);
expect(dataFilter(testData, [], 'test')).toEqual(testData);
});
});
describe('dataSort', () => {
const testData = [
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 },
{ name: 'Bob', age: 35 },
];
it('应该按指定字段升序排序', () => {
const result = dataSort(testData, 'name', 1);
expect(result[0].name).toBe('Bob');
expect(result[1].name).toBe('Jane');
expect(result[2].name).toBe('John');
});
it('应该按指定字段降序排序', () => {
const result = dataSort(testData, 'name', 2);
expect(result[0].name).toBe('John');
expect(result[1].name).toBe('Jane');
expect(result[2].name).toBe('Bob');
});
});
describe('deepClone', () => {
it('应该深度克隆对象', () => {
const original = {
a: 1,
b: {
c: 2,
d: [3, 4, { e: 5 }],
},
};
const cloned = deepClone(original);
expect(cloned).toEqual(original);
expect(cloned).not.toBe(original);
expect(cloned.b).not.toBe(original.b);
expect(cloned.b.d).not.toBe(original.b.d);
expect(cloned.b.d[2]).not.toBe(original.b.d[2]);
cloned.b.c = 99;
expect(original.b.c).toBe(2);
});
it('应该处理非对象值', () => {
expect(deepClone(null)).toBeNull();
expect(deepClone(undefined)).toBeUndefined();
expect(deepClone(123)).toBe(123);
expect(deepClone('test')).toBe('test');
});
it('应该处理日期和正则表达式', () => {
const date = new Date();
const regex = /test/gi;
expect(deepClone(date)).toEqual(date);
expect(deepClone(regex)).toEqual(regex);
});
});
describe('compareObjectEqual', () => {
it('应该比较两个对象是否相等', () => {
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { a: 1, b: { c: 2 } };
const obj3 = { a: 1, b: { c: 3 } };
expect(compareObjectEqual(obj1, obj2)).toBe(true);
expect(compareObjectEqual(obj1, obj3)).toBe(false);
});
it('应该处理排除字段', () => {
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { a: 1, b: 99, c: 3 };
expect(compareObjectEqual(obj1, obj2, 'b')).toBe(true);
expect(compareObjectEqual(obj1, obj2, ['b'])).toBe(true);
});
it('应该处理非对象值', () => {
expect(compareObjectEqual(1, 1)).toBe(true);
expect(compareObjectEqual(1, '1')).toBe(false);
expect(compareObjectEqual(null, null)).toBe(true);
expect(compareObjectEqual(null, undefined)).toBe(false);
});
});
describe('formattingTime', () => {
it('应该格式化日期对象', () => {
const date = new Date(2023, 5, 15, 12, 30, 45);
const formatted = formattingTime(date);
expect(formatted).toMatch(/2023\/06\/15 12:30:45/);
});
it('应该处理非日期输入', () => {
expect(formattingTime('not a date')).toBe('not a date');
expect(formattingTime(null)).toBeNull();
});
});
describe('iPv6Translation', () => {
it('应该转换IPv6地址', () => {
expect(iPv6Translation(['2001', 'db8', '', '1'])).toBe(
'2001:0db8:0000:0000:0000:0000:0000:0001',
);
expect(iPv6Translation(['2001', 'db8', '0', '0', '0', '0', '0', '1'])).toBe(
'2001:0db8:0000:0000:0000:0000:0000:0001',
);
});
});
describe('restituteIpv6', () => {
it('应该还原IPv6完整格式', () => {
expect(restituteIpv6('2001:db8::1')).toBe('2001:0db8:0000:0000:0000:0000:0000:0001');
expect(restituteIpv6('::1')).toBe('0000:0000:0000:0000:0000:0000:0000:0001');
});
it('应该处理非字符串输入', () => {
expect(restituteIpv6(null)).toBe('');
expect(restituteIpv6(123)).toBe('');
});
});
describe('initOriginalData', () => {
it('应该返回原始值或默认值', () => {
expect(initOriginalData('test')).toBe('test');
expect(initOriginalData(0)).toBe(0);
expect(initOriginalData(null, 'default')).toBe('default');
expect(initOriginalData(undefined, '')).toBe('');
expect(initOriginalData(null, null)).toBeNull();
expect(initOriginalData(undefined, undefined)).toBe('--');
});
});
describe('getSsoErrorMsg', () => {
it('应该返回对应的SSO错误消息键', () => {
expect(getSsoErrorMsg(4096)).toBe('LOGING_SSO_ERROR_4096');
expect(getSsoErrorMsg(130)).toBe('LOGING_SSO_ERROR_130');
expect(getSsoErrorMsg(131)).toBe('LOGING_SSO_ERROR_131');
expect(getSsoErrorMsg(1)).toBe('LOGING_SSO_ERROR_1');
});
it('应该处理非数字输入', () => {
expect(getSsoErrorMsg('not a number')).toBe('not a number');
});
});
describe('getLocationSearch', () => {
it('应该解析URL查询参数', () => {
const search = '?name=John&age=30&city=New+York';
const result = getLocationSearch(search);
expect(result).toEqual({
name: 'John',
age: '30',
city: 'New+York',
});
});
it('应该处理空查询字符串', () => {
expect(getLocationSearch('')).toEqual({});
expect(getLocationSearch('?')).toEqual({});
});
});
describe('urlReplace', () => {
it('应该替换URL中的参数', () => {
const url = '/api/users/{userId}/posts/{postId}';
const params = { userId: 123, postId: 456 };
const result = urlReplace(url, params);
expect(result).toBe('/api/users/123/posts/456');
});
it('应该处理编码参数', () => {
const url = '/api/search/{query}';
const params = { query: 'test value' };
const result = urlReplace(url, params);
expect(result).toBe('/api/search/test%20value');
});
it('应该处理缺少参数的情况', () => {
const url = '/api/users/{userId}';
const result = urlReplace(url, {});
expect(result).toBe('/api/users/');
});
});
describe('deepEqual', () => {
it('应该深度比较两个对象', () => {
const obj1 = { a: 1, b: { c: 2, d: [3, 4] } };
const obj2 = { a: 1, b: { c: 2, d: [3, 4] } };
const obj3 = { a: 1, b: { c: 2, d: [3, 5] } };
expect(deepEqual(obj1, obj2)).toBe(true);
expect(deepEqual(obj1, obj3)).toBe(false);
});
it('应该处理非对象值', () => {
expect(deepEqual('test', 'test')).toBe(true);
expect(deepEqual('test', 'different')).toBe(false);
expect(deepEqual(123, 123)).toBe(true);
expect(deepEqual(123, 456)).toBe(false);
expect(deepEqual(null, null)).toBe(true);
expect(deepEqual(null, undefined)).toBe(false);
});
it('应该处理不同结构的对象', () => {
const obj1 = { a: 1, b: 2 };
const obj2 = { a: 1 };
expect(deepEqual(obj1, obj2)).toBe(false);
});
});
describe('safeStringify', () => {
test('Basic values', () => {
const input = {
string: 'hello',
number: 123,
boolean: true,
null: null,
};
const json = safeStringify(input);
const output = JSON.parse(json);
expect(output).toEqual(input);
});
test('Circular references', () => {
const obj: any = { name: 'test' };
obj.self = obj;
const json = safeStringify(obj);
const output = JSON.parse(json);
expect(output.name).toBe('test');
expect(output.self).toBe('[Circular]');
});
test('Nested objects', () => {
const input = {
level1: {
string: 'nested',
level2: {
number: 456,
},
},
};
const json = safeStringify(input);
const output = JSON.parse(json);
expect(output.level1.string).toBe('nested');
expect(output.level1.level2.number).toBe(456);
});
test('Arrays', () => {
const input = {
array: [1, 'two', true, { nested: 'object' }],
};
const json = safeStringify(input);
const output = JSON.parse(json);
expect(output.array[0]).toBe(1);
expect(output.array[1]).toBe('two');
expect(output.array[2]).toBe(true);
expect(output.array[3].nested).toBe('object');
});
test('Nested circular references', () => {
const parent: any = { name: 'parent' };
const child: any = { name: 'child' };
parent.child = child;
child.parent = parent;
const json = safeStringify(parent);
const output = JSON.parse(json);
expect(output.name).toBe('parent');
expect(output.child.name).toBe('child');
expect(output.child.parent).toBe('[Circular]');
});
test('Error handling', () => {
const badObj = { bad: '1' };
Object.defineProperty(badObj, 'bad', {
get: () => {
throw new Error('Simulated error');
},
});
const output = safeStringify(badObj);
expect(output).toBe('[]');
});
test('Deeply nested objects', () => {
let obj: any = {};
let current = obj;
for (let i = 0; i < 100; i++) {
current.next = { level: i + 1 };
current = current.next;
}
const json = safeStringify(obj);
expect(json).toContain('"level":100');
});
});
});