Skip to content

Commit

Permalink
test(cookie): 编写单元测试
Browse files Browse the repository at this point in the history
  • Loading branch information
renxia committed Jan 16, 2024
1 parent c882eea commit d8baf5a
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 7 deletions.
86 changes: 86 additions & 0 deletions src/common/cookie.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { cookieParse, cookieStringfiy, setCookie } from './cookie';

describe('cookie.ts', () => {
it('cookieParse', () => {
globalThis.document = {} as never;

const list = [
['', {}],
[null, {}],
[void 0, {}],
[0, {}],
['a=1', { a: '1' }],
['a=1;b=b', { a: '1', b: 'b' }],
['a=;b=b', { a: '', b: 'b' }],
['a=%E6%B5%8B%E8%AF%95001;b=b', { a: '测试001', b: 'b' }],
] as const;
for (const [cookie, obj] of list) {
expect(cookieParse(cookie as never)).toEqual(obj);
}
});

it('cookieStringfiy', () => {
const list = [
['', ''],
[void 0 as never as number, ''],
[null as never as number, ''],
[0, ''],
['abc', ''],
[123, ''],
[{}, ''],
[{ a: 1 }, 'a=1'],
[{ a: 1, b: 'b' }, 'a=1; b=b'],
[{ a: '测试001', b: 'b' }, 'a=%E6%B5%8B%E8%AF%95001; b=b'],
] as const;
for (const [val, cookie] of list) {
expect(cookieStringfiy(val as never)).toBe(cookie);
}
});

it('cookieStringfiy.removeKeys', () => {
const list = [
['', [], ''],
[{}, ['a'], ''],
[{ a: 1, b: 1 }, ['a'], 'b=1'],
[{ a: 1, b: 1 }, ['b'], 'a=1'],
[{ a: 1, b: 1 }, ['c'], 'a=1; b=1'],
[{ a: 1, b: 1, ab: 1, bcd: 1 }, [/b/], 'a=1'],
] as const;
for (const [val, keys, cookie] of list) {
expect(cookieStringfiy(val as never, { removeKeys: keys as never })).toBe(cookie);
}
});

it('cookieStringfiy.onlyKeys', () => {
const list = [
['', [], ''],
[{}, ['a'], ''],
[{ a: 1, b: 1 }, ['a'], 'a=1'],
[{ a: 1, b: 1 }, ['b'], 'b=1'],
[{ a: 1, b: 1 }, ['c'], ''],
[{ a: 1, b: 1, ab: 1, bcd: 1 }, [/b/], 'b=1; ab=1; bcd=1'],
] as const;
for (const [val, keys, cookie] of list) {
expect(cookieStringfiy(val as never, { onlyKeys: keys as never })).toBe(cookie);
}
});

it('cookieStringfiy.removeNil', () => {
const list = [[{ key1: 'value1', key2: null, key3: 'value3' }, 'key1=value1; key3=value3']] as const;
for (const [val, cookie] of list) {
expect(cookieStringfiy(val as never, { removeNil: true })).toBe(cookie);
}
});
});

describe('cookie/setCookie', () => {
test('should set a cookie with the given name, value, and options', () => {
globalThis.document = {} as never;
expect(setCookie('myCookie', 'myValue', { expires: 10, path: '/' })).toBe(true);
});

test('should return false when the cookie cannot be set', () => {
global.document = void 0 as never;
expect(setCookie('myCookie', 'myValue', { expires: -1 })).toBe(false);
});
});
37 changes: 33 additions & 4 deletions src/common/cookie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @Author: renxia
* @Date: 2024-01-15 11:26:52
* @LastEditors: renxia
* @LastEditTime: 2024-01-15 11:53:38
* @LastEditTime: 2024-01-16 16:38:39
* @Description: cookie 相关处理工具方法
*/

Expand Down Expand Up @@ -35,8 +35,37 @@ export function cookieStringfiy(
cookieObj: Record<string, string | number | boolean | undefined>,
options: { removeKeys?: (string | RegExp)[]; onlyKeys?: (string | RegExp)[]; removeNil?: boolean } = {}
) {
cookieObj = objectFilterByKeys(cookieObj, options);
return Object.values(cookieObj)
.map((key, value) => `${key}=${value ? encodeURIComponent(value) : ''}`)
const obj = objectFilterByKeys(cookieObj, options);
return Object.entries(obj)
.map(([key, value]) => `${key}=${value ? encodeURIComponent(value) : ''}`)
.join('; ');
}

/**
* 将 cookie 设置到浏览器
* @param name - cookie 名称
* @param value - cookie 值
* @param options - cookie 选项
*/
export function setCookie(
name: string,
value: string,
options: {
expires?: number | Date;
path?: string;
domain?: string;
secure?: boolean;
sameSite?: 'lax' | 'strict' | 'none';
} = {}
): boolean {
if (!globalThis.document) return false;
const { expires = 365, path = '/', domain = '', secure = false, sameSite = 'strict' } = options;
const expiresValue = expires instanceof Date ? expires.toUTCString() : `${expires}`;
const cookieStr = `${name}=${value}; path=${path}; domain=${domain}; expires=${expiresValue}; ${
secure ? 'secure; ' : ''
}httponly; samesite=${sameSite}`;

// eslint-disable-next-line unicorn/no-document-cookie
document.cookie = cookieStr;
return document.cookie.includes(name);
}
94 changes: 94 additions & 0 deletions src/common/objects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
ensureArray,
safeJsonParse,
tryLoadJSON5,
toLowcaseKeyObject,
objectFilterByKeys,
} from './objects';

describe('objects/assign', () => {
Expand Down Expand Up @@ -166,3 +168,95 @@ describe('objects/assign', () => {
expect(ensureArray([1])[0]).toBe(1);
});
});

describe('objects/toLowcaseKeyObject', () => {
test('should return an empty object when no object is provided', () => {
expect(toLowcaseKeyObject()).toBeDefined();
});

test('should return a new object with lowercase keys', () => {
const cookieObj = {
Key1: 'value1',
KeY2: 'value2',
Key3: 'value3',
};
const expectedObj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
};

expect(toLowcaseKeyObject(cookieObj)).toEqual(expectedObj);
});

test('should return a new object with lowercase keys and ignore non-string keys', () => {
const cookieObj = {
Key1: 'value1',
Key2: 'value2',
Key3: 'value3',
nUm: 42,
};
const expectedObj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
num: 42,
};

expect(toLowcaseKeyObject(cookieObj)).toEqual(expectedObj);
});
});

describe('objects/objectFilterByKeys', () => {
test('should return an empty object when no object is provided', () => {
expect(objectFilterByKeys(void 0 as never)).toBeDefined();
});

test('should return an empty object when object is empty', () => {
expect(objectFilterByKeys({})).toBeDefined();
});

test('should return a new object with filtered keys', () => {
const cookieObj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
};
const removeKeys = ['key2'];
const expectedObj = {
key1: 'value1',
key3: 'value3',
};

expect(objectFilterByKeys(cookieObj, { removeKeys })).toEqual(expectedObj);
});

test('should return a new object with filtered keys and onlyKeys', () => {
const cookieObj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
};
const onlyKeys = ['key1'];
const expectedObj = {
key1: 'value1',
};

expect(objectFilterByKeys(cookieObj, { onlyKeys })).toEqual(expectedObj);
});

test('should return a new object with filtered keys and removeNil', () => {
const cookieObj = {
key1: 'value1',
key2: null,
key3: 'value3',
};
const removeNil = true;
const expectedObj = {
key1: 'value1',
key3: 'value3',
};

expect(objectFilterByKeys(cookieObj, { removeNil })).toEqual(expectedObj);
});
});
9 changes: 6 additions & 3 deletions src/common/objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,16 @@ export function objectFilterByKeys<T extends Record<string, unknown>>(
obj: T,
options: { removeKeys?: (string | RegExp)[]; onlyKeys?: (string | RegExp)[]; removeNil?: boolean } = {}
) {
const newObj: Record<string, any> = {};
if (!obj || typeof obj !== 'object') return newObj;

const keys = Object.keys(obj).filter(key => {
if (options.removeKeys?.some(d => (d instanceof RegExp ? d.test(key) : d === key))) return false;
if (!options.onlyKeys?.some(d => (d instanceof RegExp ? d.test(key) : d === key))) return false;
if (options.removeKeys?.length && options.removeKeys.some(d => (d instanceof RegExp ? d.test(key) : d === key))) return false;
if (options.onlyKeys?.length && !options.onlyKeys.some(d => (d instanceof RegExp ? d.test(key) : d === key))) return false;
if (options.removeNil && (obj[key] == null || obj[key] === '')) return false;
return true;
});
const newObj: Record<string, any> = {};

for (const k of keys) newObj[k] = obj[k];
return newObj as Partial<typeof obj>;
}

0 comments on commit d8baf5a

Please sign in to comment.