zero-query 0.9.0 → 0.9.1

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.
@@ -160,3 +160,182 @@ describe('validate', () => {
160
160
  }
161
161
  });
162
162
  });
163
+
164
+
165
+ // ===========================================================================
166
+ // onError — clearing and edge cases
167
+ // ===========================================================================
168
+
169
+ describe('onError — edge cases', () => {
170
+ afterEach(() => onError(null));
171
+
172
+ it('passing null clears handler', () => {
173
+ const spy = vi.fn();
174
+ onError(spy);
175
+ onError(null);
176
+ reportError(ErrorCode.INVALID_ARGUMENT, 'test');
177
+ expect(spy).not.toHaveBeenCalled();
178
+ });
179
+
180
+ it('passing non-function is treated as null', () => {
181
+ const spy = vi.fn();
182
+ onError(spy);
183
+ onError('not a function');
184
+ reportError(ErrorCode.INVALID_ARGUMENT, 'test');
185
+ expect(spy).not.toHaveBeenCalled();
186
+ });
187
+
188
+ it('handler exceptions do not crash reportError', () => {
189
+ onError(() => { throw new Error('handler crash'); });
190
+ expect(() => reportError(ErrorCode.INVALID_ARGUMENT, 'test')).not.toThrow();
191
+ });
192
+ });
193
+
194
+
195
+ // ===========================================================================
196
+ // reportError — cause reuse
197
+ // ===========================================================================
198
+
199
+ describe('reportError — cause handling', () => {
200
+ afterEach(() => onError(null));
201
+
202
+ it('reuses ZQueryError cause directly', () => {
203
+ const causes = [];
204
+ onError((err) => causes.push(err));
205
+ const existing = new ZQueryError(ErrorCode.COMP_RENDER, 'original');
206
+ reportError(ErrorCode.COMP_RENDER, 'wrapped', {}, existing);
207
+ expect(causes[0]).toBe(existing);
208
+ });
209
+
210
+ it('wraps non-ZQueryError cause', () => {
211
+ const causes = [];
212
+ onError((err) => causes.push(err));
213
+ const original = new Error('plain error');
214
+ reportError(ErrorCode.COMP_RENDER, 'wrapped', {}, original);
215
+ expect(causes[0]).toBeInstanceOf(ZQueryError);
216
+ expect(causes[0].cause).toBe(original);
217
+ });
218
+ });
219
+
220
+
221
+ // ===========================================================================
222
+ // guardCallback
223
+ // ===========================================================================
224
+
225
+ describe('guardCallback — edge cases', () => {
226
+ afterEach(() => onError(null));
227
+
228
+ it('returns function result on success', () => {
229
+ const guarded = guardCallback(() => 42, ErrorCode.INVALID_ARGUMENT);
230
+ expect(guarded()).toBe(42);
231
+ });
232
+
233
+ it('returns undefined on error', () => {
234
+ const guarded = guardCallback(() => { throw new Error('bang'); }, ErrorCode.INVALID_ARGUMENT);
235
+ expect(guarded()).toBeUndefined();
236
+ });
237
+
238
+ it('passes arguments through', () => {
239
+ const guarded = guardCallback((a, b) => a + b, ErrorCode.INVALID_ARGUMENT);
240
+ expect(guarded(2, 3)).toBe(5);
241
+ });
242
+ });
243
+
244
+
245
+ // ===========================================================================
246
+ // validate — edge cases
247
+ // ===========================================================================
248
+
249
+ describe('validate — edge cases', () => {
250
+ it('validates without expectedType (null/undefined only)', () => {
251
+ expect(() => validate(null, 'x')).toThrow();
252
+ expect(() => validate(undefined, 'x')).toThrow();
253
+ expect(() => validate(0, 'x')).not.toThrow();
254
+ expect(() => validate('', 'x')).not.toThrow();
255
+ expect(() => validate(false, 'x')).not.toThrow();
256
+ });
257
+ });
258
+
259
+
260
+ // ===========================================================================
261
+ // ZQueryError — structure
262
+ // ===========================================================================
263
+
264
+ describe('ZQueryError — structure', () => {
265
+ it('has correct name', () => {
266
+ const err = new ZQueryError(ErrorCode.INVALID_ARGUMENT, 'test');
267
+ expect(err.name).toBe('ZQueryError');
268
+ });
269
+
270
+ it('has empty context by default', () => {
271
+ const err = new ZQueryError(ErrorCode.INVALID_ARGUMENT, 'test');
272
+ expect(err.context).toEqual({});
273
+ });
274
+
275
+ it('stores cause when provided', () => {
276
+ const cause = new Error('root');
277
+ const err = new ZQueryError(ErrorCode.INVALID_ARGUMENT, 'test', {}, cause);
278
+ expect(err.cause).toBe(cause);
279
+ });
280
+
281
+ it('has no cause property when not provided', () => {
282
+ const err = new ZQueryError(ErrorCode.INVALID_ARGUMENT, 'test');
283
+ expect(err.cause).toBeUndefined();
284
+ });
285
+ });
286
+
287
+
288
+ // ===========================================================================
289
+ // ErrorCode — completeness
290
+ // ===========================================================================
291
+
292
+ describe('ErrorCode — all codes defined', () => {
293
+ it('has reactive codes', () => {
294
+ expect(ErrorCode.REACTIVE_CALLBACK).toBe('ZQ_REACTIVE_CALLBACK');
295
+ expect(ErrorCode.SIGNAL_CALLBACK).toBe('ZQ_SIGNAL_CALLBACK');
296
+ expect(ErrorCode.EFFECT_EXEC).toBe('ZQ_EFFECT_EXEC');
297
+ });
298
+
299
+ it('has expression codes', () => {
300
+ expect(ErrorCode.EXPR_PARSE).toBe('ZQ_EXPR_PARSE');
301
+ expect(ErrorCode.EXPR_EVAL).toBe('ZQ_EXPR_EVAL');
302
+ expect(ErrorCode.EXPR_UNSAFE_ACCESS).toBe('ZQ_EXPR_UNSAFE_ACCESS');
303
+ });
304
+
305
+ it('has component codes', () => {
306
+ expect(ErrorCode.COMP_INVALID_NAME).toBe('ZQ_COMP_INVALID_NAME');
307
+ expect(ErrorCode.COMP_NOT_FOUND).toBe('ZQ_COMP_NOT_FOUND');
308
+ expect(ErrorCode.COMP_MOUNT_TARGET).toBe('ZQ_COMP_MOUNT_TARGET');
309
+ expect(ErrorCode.COMP_RENDER).toBe('ZQ_COMP_RENDER');
310
+ expect(ErrorCode.COMP_LIFECYCLE).toBe('ZQ_COMP_LIFECYCLE');
311
+ expect(ErrorCode.COMP_RESOURCE).toBe('ZQ_COMP_RESOURCE');
312
+ expect(ErrorCode.COMP_DIRECTIVE).toBe('ZQ_COMP_DIRECTIVE');
313
+ });
314
+
315
+ it('has router codes', () => {
316
+ expect(ErrorCode.ROUTER_LOAD).toBe('ZQ_ROUTER_LOAD');
317
+ expect(ErrorCode.ROUTER_GUARD).toBe('ZQ_ROUTER_GUARD');
318
+ expect(ErrorCode.ROUTER_RESOLVE).toBe('ZQ_ROUTER_RESOLVE');
319
+ });
320
+
321
+ it('has store codes', () => {
322
+ expect(ErrorCode.STORE_ACTION).toBe('ZQ_STORE_ACTION');
323
+ expect(ErrorCode.STORE_MIDDLEWARE).toBe('ZQ_STORE_MIDDLEWARE');
324
+ expect(ErrorCode.STORE_SUBSCRIBE).toBe('ZQ_STORE_SUBSCRIBE');
325
+ });
326
+
327
+ it('has http codes', () => {
328
+ expect(ErrorCode.HTTP_REQUEST).toBe('ZQ_HTTP_REQUEST');
329
+ expect(ErrorCode.HTTP_TIMEOUT).toBe('ZQ_HTTP_TIMEOUT');
330
+ expect(ErrorCode.HTTP_INTERCEPTOR).toBe('ZQ_HTTP_INTERCEPTOR');
331
+ expect(ErrorCode.HTTP_PARSE).toBe('ZQ_HTTP_PARSE');
332
+ });
333
+
334
+ it('has general codes', () => {
335
+ expect(ErrorCode.INVALID_ARGUMENT).toBe('ZQ_INVALID_ARGUMENT');
336
+ });
337
+
338
+ it('object is frozen', () => {
339
+ expect(Object.isFrozen(ErrorCode)).toBe(true);
340
+ });
341
+ });