feat: add error handling and tests for client.ts
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { PBHttpError } from '../error';
|
||||
import { getCollection } from './client';
|
||||
|
||||
describe('getCollection', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
describe('when PocketBase is unreachable', () => {
|
||||
it('returns an empty list instead of throwing', async () => {
|
||||
vi.stubEnv('PB_URL', 'http://localhost:8090');
|
||||
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new TypeError('fetch failed')));
|
||||
|
||||
const result = await getCollection('projects');
|
||||
|
||||
expect(result.items).toEqual([]);
|
||||
expect(result.totalItems).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when PocketBase returns an HTTP error', () => {
|
||||
it('rethrows PBHttpError', async () => {
|
||||
vi.stubEnv('PB_URL', 'http://localhost:8090');
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn().mockResolvedValue({
|
||||
ok: false,
|
||||
status: 403,
|
||||
statusText: 'Forbidden',
|
||||
json: vi.fn(),
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(getCollection('projects')).rejects.toBeInstanceOf(PBHttpError);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,10 @@
|
||||
import { PBHttpError } from './error';
|
||||
import type { ListResponse } from './types';
|
||||
import { PBHttpError } from '../error';
|
||||
import type { ListResponse } from '../types';
|
||||
|
||||
/*
|
||||
* Native fetch wrapper for PocketBase API requests.
|
||||
*/
|
||||
|
||||
/* Required in production; falls back to localhost in development. */
|
||||
const PB_URL = process.env.PB_URL ?? (process.env.NODE_ENV === 'development' ? 'http://127.0.0.1:8090' : undefined);
|
||||
|
||||
/**
|
||||
* Options for PocketBase collection fetching.
|
||||
*/
|
||||
@@ -40,12 +37,15 @@ export type PBFetchOptions = {
|
||||
* Fetch a list of records from a PocketBase collection.
|
||||
*/
|
||||
export async function getCollection<T>(collection: string, options: PBFetchOptions = {}): Promise<ListResponse<T>> {
|
||||
const { sort, filter, expand, tags, revalidate } = options;
|
||||
/* Required in production; falls back to localhost in development. */
|
||||
const pbUrl = process.env.PB_URL ?? (process.env.NODE_ENV === 'development' ? 'http://127.0.0.1:8090' : undefined);
|
||||
|
||||
if (!PB_URL) {
|
||||
if (!pbUrl) {
|
||||
throw new Error('PB_URL is required in production');
|
||||
}
|
||||
|
||||
const { sort, filter, expand, tags, revalidate } = options;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (sort) {
|
||||
params.set('sort', sort);
|
||||
@@ -57,8 +57,9 @@ export async function getCollection<T>(collection: string, options: PBFetchOptio
|
||||
params.set('expand', expand);
|
||||
}
|
||||
|
||||
const url = `${PB_URL}/api/collections/${collection}/records?${params.toString()}`;
|
||||
const url = `${pbUrl}/api/collections/${collection}/records?${params.toString()}`;
|
||||
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
next: {
|
||||
tags: tags ?? [],
|
||||
@@ -71,6 +72,13 @@ export async function getCollection<T>(collection: string, options: PBFetchOptio
|
||||
}
|
||||
|
||||
return res.json();
|
||||
} catch (err) {
|
||||
if (err instanceof PBHttpError) {
|
||||
throw err;
|
||||
}
|
||||
console.warn(`[getCollection] "${collection}" unreachable — returning empty list`, err);
|
||||
return { items: [], page: 1, perPage: 0, totalItems: 0, totalPages: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from './client';
|
||||
export * from './client/client';
|
||||
export * from './types';
|
||||
|
||||
Reference in New Issue
Block a user