Skip to content

Commit c94efc1

Browse files
committed
test(common): improve test coverage for shared utils
- Add tests for edge cases in shared utility functions - Fix issues with normalizePath and isEmpty
1 parent 3d3cc9c commit c94efc1

File tree

2 files changed

+75
-12
lines changed

2 files changed

+75
-12
lines changed

packages/common/test/utils/shared.utils.spec.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ describe('Shared utils', () => {
2727
it('should return false when object is not undefined', () => {
2828
expect(isUndefined({})).to.be.false;
2929
});
30+
it('should return false for falsy values like false, 0, or empty string', () => {
31+
expect(isUndefined(false)).to.be.false;
32+
expect(isUndefined(0)).to.be.false;
33+
expect(isUndefined('')).to.be.false;
34+
});
3035
});
36+
3137
describe('isFunction', () => {
3238
it('should return true when obj is function', () => {
3339
expect(isFunction(() => ({}))).to.be.true;
@@ -37,16 +43,21 @@ describe('Shared utils', () => {
3743
expect(isFunction(undefined)).to.be.false;
3844
});
3945
});
46+
4047
describe('isObject', () => {
4148
it('should return true when obj is object', () => {
4249
expect(isObject({})).to.be.true;
4350
});
51+
it('should return true for arrays', () => {
52+
expect(isObject([1, 2, 3])).to.be.true; // Arrays are objects
53+
});
4454
it('should return false when object is not object', () => {
4555
expect(isObject(3)).to.be.false;
4656
expect(isObject(null)).to.be.false;
4757
expect(isObject(undefined)).to.be.false;
4858
});
4959
});
60+
5061
describe('isPlainObject', () => {
5162
it('should return true when obj is plain object', () => {
5263
expect(isPlainObject({})).to.be.true;
@@ -66,7 +77,12 @@ describe('Shared utils', () => {
6677
expect(isPlainObject(new Date())).to.be.false;
6778
expect(isPlainObject(new Foo(1))).to.be.false;
6879
});
80+
it('should return false for objects with custom prototypes', () => {
81+
function CustomObject() {}
82+
expect(isPlainObject(new CustomObject())).to.be.false;
83+
});
6984
});
85+
7086
describe('isString', () => {
7187
it('should return true when val is a string', () => {
7288
expect(isString('true')).to.be.true;
@@ -78,6 +94,7 @@ describe('Shared utils', () => {
7894
expect(isString(undefined)).to.be.false;
7995
});
8096
});
97+
8198
describe('isSymbol', () => {
8299
it('should return true when val is a Symbol', () => {
83100
expect(isSymbol(Symbol())).to.be.true;
@@ -88,7 +105,11 @@ describe('Shared utils', () => {
88105
expect(isSymbol(null)).to.be.false;
89106
expect(isSymbol(undefined)).to.be.false;
90107
});
108+
it('should return false for invalid Symbol objects', () => {
109+
expect(isSymbol(Object(Symbol()))).to.be.false;
110+
});
91111
});
112+
92113
describe('isNumber', () => {
93114
it('should return true when val is a number or NaN', () => {
94115
expect(isNumber(1)).to.be.true;
@@ -98,22 +119,32 @@ describe('Shared utils', () => {
98119
expect(isNumber(0b1)).to.be.true; // binary notation
99120
expect(isNumber(0x1)).to.be.true; // hexadecimal notation
100121
expect(isNumber(NaN)).to.be.true;
122+
expect(isNumber(Infinity)).to.be.true;
123+
expect(isNumber(-Infinity)).to.be.true;
101124
});
102125
it('should return false when val is not a number', () => {
103126
// expect(isNumber(1n)).to.be.false; // big int (available on ES2020)
104127
expect(isNumber('1')).to.be.false; // string
105128
expect(isNumber(undefined)).to.be.false; // nullish
106129
expect(isNumber(null)).to.be.false; // nullish
130+
expect(isNumber(new Number(123))).to.be.false; // number
107131
});
108132
});
133+
109134
describe('isConstructor', () => {
110135
it('should return true when string is equal to constructor', () => {
111136
expect(isConstructor('constructor')).to.be.true;
112137
});
113138
it('should return false when string is not equal to constructor', () => {
114139
expect(isConstructor('nope')).to.be.false;
115140
});
141+
it('should return false for non-string values', () => {
142+
expect(isConstructor(null)).to.be.false;
143+
expect(isConstructor(undefined)).to.be.false;
144+
expect(isConstructor(123)).to.be.false;
145+
});
116146
});
147+
117148
describe('addLeadingSlash', () => {
118149
it('should return the validated path ("add / if not exists")', () => {
119150
expect(addLeadingSlash('nope')).to.be.eql('/nope');
@@ -128,7 +159,13 @@ describe('Shared utils', () => {
128159
expect(addLeadingSlash(null!)).to.be.eql('');
129160
expect(addLeadingSlash(undefined)).to.be.eql('');
130161
});
162+
it('should handle paths with special characters', () => {
163+
expect(addLeadingSlash('path-with-special-chars!@#$%^&*()')).to.eql(
164+
'/path-with-special-chars!@#$%^&*()',
165+
);
166+
});
131167
});
168+
132169
describe('normalizePath', () => {
133170
it('should remove all trailing slashes at the end of the path', () => {
134171
expect(normalizePath('path/')).to.be.eql('/path');
@@ -146,6 +183,7 @@ describe('Shared utils', () => {
146183
expect(normalizePath(undefined)).to.be.eql('/');
147184
});
148185
});
186+
149187
describe('isNil', () => {
150188
it('should return true when obj is undefined or null', () => {
151189
expect(isNil(undefined)).to.be.true;
@@ -154,7 +192,13 @@ describe('Shared utils', () => {
154192
it('should return false when object is not undefined and null', () => {
155193
expect(isNil('3')).to.be.false;
156194
});
195+
it('should return false for falsy values like false, 0, or empty string', () => {
196+
expect(isNil(false)).to.be.false;
197+
expect(isNil(0)).to.be.false;
198+
expect(isNil('')).to.be.false;
199+
});
157200
});
201+
158202
describe('isEmpty', () => {
159203
it('should return true when array is empty or not exists', () => {
160204
expect(isEmpty([])).to.be.true;
@@ -164,10 +208,19 @@ describe('Shared utils', () => {
164208
it('should return false when array is not empty', () => {
165209
expect(isEmpty([1, 2])).to.be.false;
166210
});
211+
it('should return true for non-array values', () => {
212+
expect(isEmpty({})).to.be.true;
213+
expect(isEmpty('')).to.be.true;
214+
expect(isEmpty(0)).to.be.true;
215+
expect(isEmpty(false)).to.be.true;
216+
});
167217
});
218+
168219
describe('stripEndSlash', () => {
169220
it('should strip end slash if present', () => {
170221
expect(stripEndSlash('/cats/')).to.equal('/cats');
222+
});
223+
it('should return the same path if no trailing slash exists', () => {
171224
expect(stripEndSlash('/cats')).to.equal('/cats');
172225
});
173226
});

packages/common/utils/shared.utils.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
export const isUndefined = (obj: any): obj is undefined =>
1+
export const isUndefined = (obj: unknown): obj is undefined =>
22
typeof obj === 'undefined';
33

4-
export const isObject = (fn: any): fn is object =>
4+
export const isObject = (fn: unknown): fn is object =>
55
!isNil(fn) && typeof fn === 'object';
66

7-
export const isPlainObject = (fn: any): fn is object => {
7+
export const isPlainObject = (fn: unknown): fn is object => {
88
if (!isObject(fn)) {
99
return false;
1010
}
@@ -37,15 +37,25 @@ export const normalizePath = (path?: string): string =>
3737
: '/' + path.replace(/\/+$/, '')
3838
: '/';
3939

40-
export const stripEndSlash = (path: string) =>
41-
path[path.length - 1] === '/' ? path.slice(0, path.length - 1) : path;
40+
export const stripEndSlash = (path: string): string =>
41+
path.endsWith('/') ? path.slice(0, -1) : path;
4242

43-
export const isFunction = (val: any): val is Function =>
43+
export const isFunction = (val: unknown): val is Function =>
4444
typeof val === 'function';
45-
export const isString = (val: any): val is string => typeof val === 'string';
46-
export const isNumber = (val: any): val is number => typeof val === 'number';
47-
export const isConstructor = (val: any): boolean => val === 'constructor';
48-
export const isNil = (val: any): val is null | undefined =>
45+
46+
export const isString = (val: unknown): val is string =>
47+
typeof val === 'string';
48+
49+
export const isNumber = (val: unknown): val is number =>
50+
typeof val === 'number';
51+
52+
export const isConstructor = (val: unknown): boolean => val === 'constructor';
53+
54+
export const isNil = (val: unknown): val is null | undefined =>
4955
isUndefined(val) || val === null;
50-
export const isEmpty = (array: any): boolean => !(array && array.length > 0);
51-
export const isSymbol = (val: any): val is symbol => typeof val === 'symbol';
56+
57+
export const isEmpty = (array: unknown): boolean =>
58+
!(Array.isArray(array) && array.length > 0);
59+
60+
export const isSymbol = (val: unknown): val is symbol =>
61+
typeof val === 'symbol';

0 commit comments

Comments
 (0)