@vpmedia/simplify 1.71.0 → 1.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/package.json +10 -16
- package/src/logging/util.js +0 -2
- package/src/pagelifecycle/util.js +0 -3
- package/src/util/event_emitter.js +0 -2
- package/src/util/fetch.js +0 -2
- package/src/util/query.js +1 -1
- package/src/util/uuid.js +0 -2
- package/src/util/validate.js +0 -2
- package/types/logging/util.d.ts.map +1 -1
- package/types/pagelifecycle/util.d.ts.map +1 -1
- package/types/util/event_emitter.d.ts.map +1 -1
- package/types/util/fetch.d.ts.map +1 -1
- package/types/util/uuid.d.ts.map +1 -1
- package/types/util/validate.d.ts.map +1 -1
- package/src/const/http_status.test.js +0 -7
- package/src/logging/Logger.test.js +0 -73
- package/src/logging/util.test.js +0 -33
- package/src/pagelifecycle/util.test.js +0 -102
- package/src/typecheck/TypeChecker.test.js +0 -70
- package/src/typecheck/util.test.js +0 -35
- package/src/util/async.test.js +0 -31
- package/src/util/error.test.js +0 -34
- package/src/util/event_emitter.test.js +0 -231
- package/src/util/fetch.test.js +0 -62
- package/src/util/number.test.js +0 -126
- package/src/util/object.test.js +0 -205
- package/src/util/query.test.js +0 -73
- package/src/util/state.test.js +0 -47
- package/src/util/string.test.js +0 -66
- package/src/util/uuid.test.js +0 -53
- package/src/util/validate.test.js +0 -311
- package/tests/mocks/handlers/fetch.js +0 -34
- package/tests/mocks/handlers.js +0 -3
- package/tsconfig.build.json +0 -24
- package/vitest.setup.js +0 -17
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
/* eslint-disable unicorn/prefer-event-target, no-empty-function, no-invalid-this, func-names, func-style, unicorn/consistent-function-scoping */
|
|
2
|
-
|
|
3
|
-
import { describe, it, expect } from 'vitest';
|
|
4
|
-
import { EventEmitter } from './event_emitter.js';
|
|
5
|
-
|
|
6
|
-
describe('EventEmitter3 basics', () => {
|
|
7
|
-
it('can be instantiated', () => {
|
|
8
|
-
const e = new EventEmitter();
|
|
9
|
-
expect(e).toBeInstanceOf(EventEmitter);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('supports subclassing', () => {
|
|
13
|
-
class Beast extends EventEmitter {}
|
|
14
|
-
const beast = new Beast();
|
|
15
|
-
|
|
16
|
-
expect(beast).toBeInstanceOf(Beast);
|
|
17
|
-
expect(beast).toBeInstanceOf(EventEmitter);
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
describe('emit()', () => {
|
|
22
|
-
it('returns false when no listeners exist', () => {
|
|
23
|
-
const e = new EventEmitter();
|
|
24
|
-
expect(e.emit('foo')).toBe(false);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('returns true when listeners exist', () => {
|
|
28
|
-
const e = new EventEmitter();
|
|
29
|
-
e.on('foo', () => {});
|
|
30
|
-
expect(e.emit('foo')).toBe(true);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('invokes listeners with provided arguments', async () => {
|
|
34
|
-
const e = new EventEmitter();
|
|
35
|
-
|
|
36
|
-
await new Promise((resolve) => {
|
|
37
|
-
e.on('foo', (a, b) => {
|
|
38
|
-
expect(a).toBe(1);
|
|
39
|
-
expect(b).toBe(2);
|
|
40
|
-
resolve();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
e.emit('foo', 1, 2);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('binds the correct context', async () => {
|
|
48
|
-
const e = new EventEmitter();
|
|
49
|
-
const ctx = { value: 42 };
|
|
50
|
-
|
|
51
|
-
await new Promise((resolve) => {
|
|
52
|
-
e.on(
|
|
53
|
-
'foo',
|
|
54
|
-
function () {
|
|
55
|
-
// @ts-expect-error
|
|
56
|
-
expect(this).toBe(ctx);
|
|
57
|
-
resolve();
|
|
58
|
-
},
|
|
59
|
-
ctx
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
e.emit('foo');
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('supports many listeners for the same event', () => {
|
|
67
|
-
const e = new EventEmitter();
|
|
68
|
-
const calls = [];
|
|
69
|
-
|
|
70
|
-
e.on('foo', () => calls.push(1));
|
|
71
|
-
e.on('foo', () => calls.push(2));
|
|
72
|
-
|
|
73
|
-
e.emit('foo');
|
|
74
|
-
|
|
75
|
-
expect(calls).toEqual([1, 2]);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe('once()', () => {
|
|
80
|
-
it('fires the listener only once', () => {
|
|
81
|
-
const e = new EventEmitter();
|
|
82
|
-
let calls = 0;
|
|
83
|
-
|
|
84
|
-
e.once('foo', () => {
|
|
85
|
-
calls += 1;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
e.emit('foo');
|
|
89
|
-
e.emit('foo');
|
|
90
|
-
|
|
91
|
-
expect(calls).toBe(1);
|
|
92
|
-
expect(e.listenerCount('foo')).toBe(0);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('passes arguments correctly', async () => {
|
|
96
|
-
const e = new EventEmitter();
|
|
97
|
-
|
|
98
|
-
await new Promise((resolve) => {
|
|
99
|
-
e.once('foo', (...args) => {
|
|
100
|
-
expect(args).toEqual([1, 2, 3]);
|
|
101
|
-
resolve();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
e.emit('foo', 1, 2, 3);
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('listeners() and listenerCount()', () => {
|
|
110
|
-
it('returns an empty array when no listeners exist', () => {
|
|
111
|
-
const e = new EventEmitter();
|
|
112
|
-
expect(e.listeners('foo')).toEqual([]);
|
|
113
|
-
expect(e.listenerCount('foo')).toBe(0);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('returns only listener functions (not internals)', () => {
|
|
117
|
-
const e = new EventEmitter();
|
|
118
|
-
function fn() {}
|
|
119
|
-
|
|
120
|
-
e.on('foo', fn);
|
|
121
|
-
|
|
122
|
-
expect(e.listeners('foo')).toEqual([fn]);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('does not expose internal listener storage', () => {
|
|
126
|
-
const e = new EventEmitter();
|
|
127
|
-
function fn() {}
|
|
128
|
-
|
|
129
|
-
e.on('foo', fn);
|
|
130
|
-
const listeners = e.listeners('foo');
|
|
131
|
-
listeners.push(() => {});
|
|
132
|
-
|
|
133
|
-
expect(e.listeners('foo')).toEqual([fn]);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe('off()', () => {
|
|
138
|
-
it('removes all listeners for an event when fn is omitted', () => {
|
|
139
|
-
const e = new EventEmitter();
|
|
140
|
-
|
|
141
|
-
e.on('foo', () => {});
|
|
142
|
-
e.on('foo', () => {});
|
|
143
|
-
|
|
144
|
-
e.off('foo');
|
|
145
|
-
|
|
146
|
-
expect(e.listenerCount('foo')).toBe(0);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('removes a specific listener', () => {
|
|
150
|
-
const e = new EventEmitter();
|
|
151
|
-
function fn() {}
|
|
152
|
-
|
|
153
|
-
e.on('foo', fn);
|
|
154
|
-
e.off('foo', fn);
|
|
155
|
-
|
|
156
|
-
expect(e.listeners('foo')).toEqual([]);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('removes listeners matching both function and context', () => {
|
|
160
|
-
const e = new EventEmitter();
|
|
161
|
-
const ctx1 = {};
|
|
162
|
-
const ctx2 = {};
|
|
163
|
-
function fn() {}
|
|
164
|
-
|
|
165
|
-
e.on('foo', fn, ctx1);
|
|
166
|
-
e.on('foo', fn, ctx2);
|
|
167
|
-
|
|
168
|
-
e.off('foo', fn, ctx1);
|
|
169
|
-
|
|
170
|
-
expect(e.listenerCount('foo')).toBe(1);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
describe('removeAllListeners()', () => {
|
|
175
|
-
it('removes listeners for a single event', () => {
|
|
176
|
-
const e = new EventEmitter();
|
|
177
|
-
|
|
178
|
-
e.on('foo', () => {});
|
|
179
|
-
e.on('bar', () => {});
|
|
180
|
-
|
|
181
|
-
e.removeAllListeners('foo');
|
|
182
|
-
|
|
183
|
-
expect(e.listenerCount('foo')).toBe(0);
|
|
184
|
-
expect(e.listenerCount('bar')).toBe(1);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('removes all listeners when no event is specified', () => {
|
|
188
|
-
const e = new EventEmitter();
|
|
189
|
-
|
|
190
|
-
e.on('foo', () => {});
|
|
191
|
-
e.on('bar', () => {});
|
|
192
|
-
|
|
193
|
-
e.removeAllListeners();
|
|
194
|
-
|
|
195
|
-
expect(e.eventNames()).toEqual([]);
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
describe('eventNames()', () => {
|
|
200
|
-
it('returns an empty array when no events exist', () => {
|
|
201
|
-
const e = new EventEmitter();
|
|
202
|
-
expect(e.eventNames()).toEqual([]);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('returns all registered event names', () => {
|
|
206
|
-
const e = new EventEmitter();
|
|
207
|
-
|
|
208
|
-
e.on('foo', () => {});
|
|
209
|
-
e.on('bar', () => {});
|
|
210
|
-
|
|
211
|
-
expect(e.eventNames()).toContain('foo');
|
|
212
|
-
expect(e.eventNames()).toContain('bar');
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it('supports symbol event names', () => {
|
|
216
|
-
const e = new EventEmitter();
|
|
217
|
-
const sym = Symbol('test');
|
|
218
|
-
|
|
219
|
-
e.on(sym, () => {});
|
|
220
|
-
expect(e.eventNames()).toContain(sym);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it('events map is instance field', () => {
|
|
224
|
-
const e1 = new EventEmitter();
|
|
225
|
-
const e2 = new EventEmitter();
|
|
226
|
-
e1.on('event', () => {});
|
|
227
|
-
expect(e1.listenerCount('event')).toBe(1);
|
|
228
|
-
expect(e1.listenerCount('no-event')).toBe(0);
|
|
229
|
-
expect(e2.listenerCount('event')).toBe(0);
|
|
230
|
-
});
|
|
231
|
-
});
|
package/src/util/fetch.test.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { HTTP_404_NOT_FOUND } from '../const/http_status.js';
|
|
2
|
-
import { fetchRetry, FetchError } from './fetch.js';
|
|
3
|
-
|
|
4
|
-
describe('FetchError', () => {
|
|
5
|
-
test('constructor', () => {
|
|
6
|
-
const error = new FetchError('message', 'url', { method: 'GET' }, null);
|
|
7
|
-
expect(error.message).toEqual('message');
|
|
8
|
-
expect(error.resource).toEqual('url');
|
|
9
|
-
expect(error.fetchOptions).toMatchObject({ method: 'GET' });
|
|
10
|
-
expect(error.response).toBe(null);
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
describe('fetchRetry', () => {
|
|
15
|
-
test('fetch OK', async () => {
|
|
16
|
-
const response = await fetchRetry('/test.json', {
|
|
17
|
-
cache: 'no-cache',
|
|
18
|
-
keepalive: false,
|
|
19
|
-
method: 'GET',
|
|
20
|
-
redirect: 'error',
|
|
21
|
-
});
|
|
22
|
-
const json = await response.json();
|
|
23
|
-
const expectedJSON = {
|
|
24
|
-
success: true,
|
|
25
|
-
method: 'GET',
|
|
26
|
-
};
|
|
27
|
-
expect(json).toEqual(expectedJSON);
|
|
28
|
-
});
|
|
29
|
-
test('fetch unknown scheme', async () => {
|
|
30
|
-
try {
|
|
31
|
-
await fetchRetry('htps://', {});
|
|
32
|
-
} catch (error) {
|
|
33
|
-
const typedError = error instanceof Error ? error : new Error(String(error));
|
|
34
|
-
expect(typedError.message).toEqual('fetch failed');
|
|
35
|
-
const typedErrorCause =
|
|
36
|
-
typedError.cause instanceof Error ? typedError.cause : new Error(String(typedError.cause));
|
|
37
|
-
expect(typedErrorCause.message).toEqual('unknown scheme');
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
test('fetch 404 error with retry', async () => {
|
|
41
|
-
try {
|
|
42
|
-
await fetchRetry(
|
|
43
|
-
'/test_error.json',
|
|
44
|
-
{
|
|
45
|
-
cache: 'no-cache',
|
|
46
|
-
keepalive: false,
|
|
47
|
-
method: 'POST',
|
|
48
|
-
redirect: 'error',
|
|
49
|
-
},
|
|
50
|
-
{ numTries: 2, statusExcludes: [], delay: 1 }
|
|
51
|
-
);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
const typedError = error instanceof Error ? error : new Error(String(error));
|
|
54
|
-
expect(typedError).toBeInstanceOf(FetchError);
|
|
55
|
-
if (typedError instanceof FetchError) {
|
|
56
|
-
expect(typedError.message).toBe('Fetch error 404');
|
|
57
|
-
expect(typedError.response.status).toBe(HTTP_404_NOT_FOUND);
|
|
58
|
-
expect(typedError.cause).toBe(HTTP_404_NOT_FOUND);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
});
|
package/src/util/number.test.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
/* eslint-disable unicorn/no-useless-undefined */
|
|
2
|
-
|
|
3
|
-
import { TypeCheckError } from '../typecheck/TypeCheckError.js';
|
|
4
|
-
import {
|
|
5
|
-
fixFloatPrecision,
|
|
6
|
-
getRandomInt,
|
|
7
|
-
isEqual,
|
|
8
|
-
isGreater,
|
|
9
|
-
isGreaterOrEqual,
|
|
10
|
-
isInRange,
|
|
11
|
-
isLess,
|
|
12
|
-
isLessOrEqual,
|
|
13
|
-
deg2rad,
|
|
14
|
-
rad2deg,
|
|
15
|
-
} from './number.js';
|
|
16
|
-
|
|
17
|
-
test('Converts angle in degrees to radians', () => {
|
|
18
|
-
expect(deg2rad(90)).toBe(1.5707963267948966);
|
|
19
|
-
// @ts-expect-error
|
|
20
|
-
expect(() => deg2rad('')).toThrowError(TypeCheckError);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test('Converts angle in radians to degrees', () => {
|
|
24
|
-
expect(rad2deg(1.5707963267948966)).toBe(90);
|
|
25
|
-
// @ts-expect-error
|
|
26
|
-
expect(() => rad2deg('')).toThrowError(TypeCheckError);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe('fixFloatPrecision', () => {
|
|
30
|
-
test('Fixes float precision issues', () => {
|
|
31
|
-
expect(fixFloatPrecision(0.20000000000000004)).toBe(0.2);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('Handles zero', () => {
|
|
35
|
-
expect(fixFloatPrecision(0)).toBe(0);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('Handles negative numbers', () => {
|
|
39
|
-
expect(fixFloatPrecision(-0.20000000000000004)).toBe(-0.2);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('Handles very small numbers', () => {
|
|
43
|
-
expect(fixFloatPrecision(0.0000000000001)).toBe(0);
|
|
44
|
-
expect(fixFloatPrecision(-0.0000000000001)).toBe(0);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test('Handles integer numbers', () => {
|
|
48
|
-
expect(fixFloatPrecision(5)).toBe(5);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test('Handles string number input', () => {
|
|
52
|
-
expect(fixFloatPrecision('5.123456789')).toBe(5.123456789);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('Throws error for invalid input', () => {
|
|
56
|
-
expect(fixFloatPrecision('abc')).toBe(Number.NaN);
|
|
57
|
-
expect(fixFloatPrecision(null)).toBe(Number.NaN);
|
|
58
|
-
expect(fixFloatPrecision(undefined)).toBe(Number.NaN);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('getRandomInt', () => {
|
|
63
|
-
test('Throws error if min or max is not finite number', () => {
|
|
64
|
-
// @ts-expect-error
|
|
65
|
-
expect(() => getRandomInt('', 1)).toThrowError(TypeCheckError);
|
|
66
|
-
// @ts-expect-error
|
|
67
|
-
expect(() => getRandomInt(1, '')).toThrowError(TypeCheckError);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('Returns random integer within range when min equals max', () => {
|
|
71
|
-
expect(getRandomInt(1, 1)).toBe(1);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('Returns random integer within range when min is less than max', () => {
|
|
75
|
-
const result = getRandomInt(1, 10);
|
|
76
|
-
expect(result).toBeGreaterThanOrEqual(1);
|
|
77
|
-
expect(result).toBeLessThanOrEqual(10);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test('Works with negative numbers', () => {
|
|
81
|
-
const result = getRandomInt(-5, -1);
|
|
82
|
-
expect(result).toBeGreaterThanOrEqual(-5);
|
|
83
|
-
expect(result).toBeLessThanOrEqual(-1);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('Works with zero range', () => {
|
|
87
|
-
const result = getRandomInt(0, 0);
|
|
88
|
-
expect(result).toBe(0);
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
describe('number', () => {
|
|
93
|
-
test('isEq', () => {
|
|
94
|
-
expect(isEqual(1, 0)).toBe(false);
|
|
95
|
-
expect(isEqual(1, 1)).toBe(true);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
test('isGt', () => {
|
|
99
|
-
expect(isGreater(1, 0)).toBe(true);
|
|
100
|
-
expect(isGreater(1, 1)).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test('isGtOrEq', () => {
|
|
104
|
-
expect(isGreaterOrEqual(1, 0)).toBe(true);
|
|
105
|
-
expect(isGreaterOrEqual(1, 1)).toBe(true);
|
|
106
|
-
expect(isGreaterOrEqual(1, 2)).toBe(false);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test('isGtOrEq', () => {
|
|
110
|
-
expect(isInRange(1, 0, 2)).toBe(true);
|
|
111
|
-
expect(isInRange(1, 0, 1)).toBe(true);
|
|
112
|
-
expect(isInRange(2, 0, 1)).toBe(false);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('isLe', () => {
|
|
116
|
-
expect(isLess(1, 0)).toBe(false);
|
|
117
|
-
expect(isLess(0, 0)).toBe(false);
|
|
118
|
-
expect(isLess(0, 1)).toBe(true);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
test('isLeOrEq', () => {
|
|
122
|
-
expect(isLessOrEqual(1, 0)).toBe(false);
|
|
123
|
-
expect(isLessOrEqual(0, 0)).toBe(true);
|
|
124
|
-
expect(isLessOrEqual(0, 1)).toBe(true);
|
|
125
|
-
});
|
|
126
|
-
});
|
package/src/util/object.test.js
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import { getObjValueByPath, setObjValueByPath, purgeObject, deepMerge } from './object.js';
|
|
2
|
-
|
|
3
|
-
describe('deepMerge', () => {
|
|
4
|
-
test('should override deep properties correctly', () => {
|
|
5
|
-
const defaultObj = { a: { b: 1, c: 2 }, d: 3 };
|
|
6
|
-
const overrideObj = { a: { b: 42 } };
|
|
7
|
-
const expectedResult = { a: { b: 42, c: 2 }, d: 3 };
|
|
8
|
-
|
|
9
|
-
expect(deepMerge({ ...defaultObj }, overrideObj)).toEqual(expectedResult);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test('should not modify the original target object', () => {
|
|
13
|
-
const target = { x: { y: 10 } };
|
|
14
|
-
const source = { x: { y: 20 } };
|
|
15
|
-
const copy = { ...target };
|
|
16
|
-
|
|
17
|
-
deepMerge(target, source);
|
|
18
|
-
expect(target).toEqual(copy);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test('should handle non-object values correctly', () => {
|
|
22
|
-
expect(deepMerge(null, { a: 1 })).toEqual({ a: 1 });
|
|
23
|
-
expect(deepMerge({ a: 1 }, null)).toEqual({ a: 1 });
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('should handle arrays correctly', () => {
|
|
27
|
-
const target = { arr: [1, 2] };
|
|
28
|
-
const source = { arr: [3, 4] };
|
|
29
|
-
|
|
30
|
-
expect(deepMerge(target, source)).toEqual({ arr: [3, 4] });
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('should handle nested arrays correctly', () => {
|
|
34
|
-
const target = { obj: { arr: [1, 2] } };
|
|
35
|
-
const source = { obj: { arr: [3, 4] } };
|
|
36
|
-
|
|
37
|
-
expect(deepMerge(target, source)).toEqual({ obj: { arr: [3, 4] } });
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('should handle string values', () => {
|
|
41
|
-
const target = { str: 'hello' };
|
|
42
|
-
const source = { str: 'world' };
|
|
43
|
-
|
|
44
|
-
expect(deepMerge(target, source)).toEqual({ str: 'world' });
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test('should handle number values', () => {
|
|
48
|
-
const target = { num: 42 };
|
|
49
|
-
const source = { num: 100 };
|
|
50
|
-
|
|
51
|
-
expect(deepMerge(target, source)).toEqual({ num: 100 });
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('should handle boolean values', () => {
|
|
55
|
-
const target = { bool: true };
|
|
56
|
-
const source = { bool: false };
|
|
57
|
-
|
|
58
|
-
expect(deepMerge(target, source)).toEqual({ bool: false });
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('should handle undefined values', () => {
|
|
62
|
-
const target = { undef: undefined };
|
|
63
|
-
const source = { undef: 'value' };
|
|
64
|
-
|
|
65
|
-
expect(deepMerge(target, source)).toEqual({ undef: 'value' });
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test('should handle null values', () => {
|
|
69
|
-
const target = { nullVal: null };
|
|
70
|
-
const source = { nullVal: 'value' };
|
|
71
|
-
|
|
72
|
-
expect(deepMerge(target, source)).toEqual({ nullVal: 'value' });
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('should handle mixed property types', () => {
|
|
76
|
-
const target = {
|
|
77
|
-
str: 'hello',
|
|
78
|
-
num: 42,
|
|
79
|
-
arr: [1, 2],
|
|
80
|
-
obj: { nested: 'value' },
|
|
81
|
-
};
|
|
82
|
-
const source = {
|
|
83
|
-
str: 'world',
|
|
84
|
-
num: 100,
|
|
85
|
-
arr: [3, 4],
|
|
86
|
-
obj: { nested: 'newValue' },
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
expect(deepMerge(target, source)).toEqual({
|
|
90
|
-
str: 'world',
|
|
91
|
-
num: 100,
|
|
92
|
-
arr: [3, 4],
|
|
93
|
-
obj: { nested: 'newValue' },
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('should handle constructor and __proto__ protection', () => {
|
|
98
|
-
const target = { a: 1 };
|
|
99
|
-
const source = { b: 2 };
|
|
100
|
-
|
|
101
|
-
expect(deepMerge(target, source)).toEqual({ a: 1, b: 2 });
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test('Purges object of null and undefined values', () => {
|
|
106
|
-
const a = { k: 'v' };
|
|
107
|
-
expect(a.k).toBe('v');
|
|
108
|
-
purgeObject(a);
|
|
109
|
-
expect(a.k).toBe(null);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
describe('getObjValueByPath', () => {
|
|
113
|
-
test('Gets object value by path', () => {
|
|
114
|
-
const source = { a: { b: { c: 'd' } } };
|
|
115
|
-
expect(getObjValueByPath(source, 'a.b.c')).toBe('d');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('Returns null when object is null or undefined', () => {
|
|
119
|
-
expect(getObjValueByPath(null, 'a.b.c')).toBeNull();
|
|
120
|
-
expect(getObjValueByPath(undefined, 'a.b.c')).toBeNull();
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('Returns null when path is empty or null', () => {
|
|
124
|
-
expect(getObjValueByPath({ a: 'b' }, '')).toBeNull();
|
|
125
|
-
expect(getObjValueByPath({ a: 'b' }, null)).toBeNull();
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test('Returns null when property does not exist', () => {
|
|
129
|
-
const source = { a: { b: 'c' } };
|
|
130
|
-
expect(getObjValueByPath(source, 'a.b.c')).toBeNull();
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test('Returns null when property is undefined', () => {
|
|
134
|
-
const source = { a: { b: undefined } };
|
|
135
|
-
expect(getObjValueByPath(source, 'a.b')).toBeNull();
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test('Handles single-level paths correctly', () => {
|
|
139
|
-
const source = { a: 'value' };
|
|
140
|
-
expect(getObjValueByPath(source, 'a')).toBe('value');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test('Handles nested paths correctly', () => {
|
|
144
|
-
const source = {
|
|
145
|
-
level1: {
|
|
146
|
-
level2: {
|
|
147
|
-
level3: 'deepValue',
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
expect(getObjValueByPath(source, 'level1.level2.level3')).toBe('deepValue');
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test('Handles arrays in paths', () => {
|
|
155
|
-
const source = {
|
|
156
|
-
items: [{ name: 'item1' }, { name: 'item2' }],
|
|
157
|
-
};
|
|
158
|
-
expect(getObjValueByPath(source, 'items.0.name')).toBe('item1');
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
describe('setObjValueByPath', () => {
|
|
163
|
-
test('Sets object value by path', () => {
|
|
164
|
-
const source = { a: { b: { c: 'd' } } };
|
|
165
|
-
expect(getObjValueByPath(source, 'a.b.c')).toBe('d');
|
|
166
|
-
setObjValueByPath(source, 'a.b.c', 'newValue');
|
|
167
|
-
expect(getObjValueByPath(source, 'a.b.c')).toBe('newValue');
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
test('Handles null or undefined object', () => {
|
|
171
|
-
// Should not throw error
|
|
172
|
-
setObjValueByPath(null, 'a.b.c', 'value');
|
|
173
|
-
setObjValueByPath(undefined, 'a.b.c', 'value');
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test('Handles null or undefined path', () => {
|
|
177
|
-
const source = { a: 'b' };
|
|
178
|
-
// Should not throw error
|
|
179
|
-
setObjValueByPath(source, null, 'value');
|
|
180
|
-
setObjValueByPath(source, undefined, 'value');
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
test('Sets value at root level', () => {
|
|
184
|
-
const source = { a: 'oldValue' };
|
|
185
|
-
setObjValueByPath(source, 'a', 'newValue');
|
|
186
|
-
expect(source.a).toBe('newValue');
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
test('Creates new nested properties', () => {
|
|
190
|
-
const source = { a: { b: 'existing' } };
|
|
191
|
-
setObjValueByPath(source, 'a.c.d', 'newNestedValue');
|
|
192
|
-
expect(getObjValueByPath(source, 'a.c.d')).toBe('newNestedValue');
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
test('Handles array paths', () => {
|
|
196
|
-
const source = { items: [{ name: 'item1' }] };
|
|
197
|
-
setObjValueByPath(source, 'items.0.name', 'updatedItem');
|
|
198
|
-
expect(getObjValueByPath(source, 'items.0.name')).toBe('updatedItem');
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
test('Throws error for __proto__ path', () => {
|
|
202
|
-
const source = { a: 'b' };
|
|
203
|
-
expect(() => setObjValueByPath(source, '__proto__.test', 'value')).toThrow(SyntaxError);
|
|
204
|
-
});
|
|
205
|
-
});
|
package/src/util/query.test.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/* eslint-disable jsdoc/check-tag-names, jsdoc/valid-types */
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @vitest-environment-options { "url": "https://localhost/app/?language=en&token=123-456-öüó%24D" }
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { getURLParam, sanitizeURLParam } from './query.js';
|
|
8
|
-
|
|
9
|
-
describe('getURLParam', () => {
|
|
10
|
-
test('Returns fallback value when parameter is not found', () => {
|
|
11
|
-
const result = getURLParam('nonexistent', 'fallback');
|
|
12
|
-
expect(result).toBe('fallback');
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test('Handles null/undefined input gracefully', () => {
|
|
16
|
-
const result = getURLParam(null, 'fallback');
|
|
17
|
-
expect(result).toBe('fallback');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('Returns default value when param is null', () => {
|
|
21
|
-
const result = getURLParam('key', 'default');
|
|
22
|
-
expect(result).toBe('default');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('Handles valid url parameter sanitized', () => {
|
|
26
|
-
expect(getURLParam('language')).toBe('en');
|
|
27
|
-
expect(getURLParam('token')).toBe('123-456-D');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('Handles valid url parameter unsanitized', () => {
|
|
31
|
-
expect(getURLParam('token', null, false)).toBe('123-456-öüó$D');
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('sanitizeURLParam', () => {
|
|
36
|
-
test('Sanitizes URL parameter correctly', () => {
|
|
37
|
-
expect(sanitizeURLParam('abc<>-123[]{}-()A_BC')).toBe('abc-123-A_BC');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('Handles null input', () => {
|
|
41
|
-
expect(sanitizeURLParam(null)).toBe(null);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('Handles empty string', () => {
|
|
45
|
-
expect(sanitizeURLParam('')).toBe('');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('Handles valid characters', () => {
|
|
49
|
-
expect(sanitizeURLParam('abc123')).toBe('abc123');
|
|
50
|
-
expect(sanitizeURLParam('test-parameter')).toBe('test-parameter');
|
|
51
|
-
expect(sanitizeURLParam('test_parameter')).toBe('test_parameter');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('Handles special characters', () => {
|
|
55
|
-
expect(sanitizeURLParam('test@#$%')).toBe('test');
|
|
56
|
-
expect(sanitizeURLParam('test!@#$%^&*()')).toBe('test');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test('Handles unicode characters', () => {
|
|
60
|
-
expect(sanitizeURLParam('test_äöü')).toBe('test_');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test('Handles edge cases with various special characters', () => {
|
|
64
|
-
expect(sanitizeURLParam('test!!!@@@')).toBe('test');
|
|
65
|
-
expect(sanitizeURLParam('test_param-123')).toBe('test_param-123');
|
|
66
|
-
expect(sanitizeURLParam('test param')).toBe('testparam');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test('Handles very long parameter names', () => {
|
|
70
|
-
const longParam = 'a'.repeat(1000);
|
|
71
|
-
expect(typeof sanitizeURLParam(longParam)).toBe('string');
|
|
72
|
-
});
|
|
73
|
-
});
|