test(11-01): add failing tests for PAX8 client pagination helpers
- listAllCompanies/listAllSubscriptions/listAllProducts multi-page concat - size=200 param assertion, single-page no-infinite-loop case - Assert every request is GET with Authorization: Bearer header
This commit is contained in:
parent
0d819badc2
commit
19fe788778
1 changed files with 133 additions and 0 deletions
|
|
@ -41,6 +41,62 @@ function makeFetchMock(opts: {
|
|||
return { fetchMock, calls };
|
||||
}
|
||||
|
||||
/**
|
||||
* Multi-page fetch mock for the listAll* pagination helpers. Keys page
|
||||
* bodies by URL substring (e.g. '/subscriptions') and by the `page=N` query
|
||||
* param, returning one page envelope per (resource, page) pair.
|
||||
*/
|
||||
function makeMultiPageFetchMock(opts: {
|
||||
resource: string; // e.g. 'subscriptions', 'products', 'companies'
|
||||
pages: Array<{ content: unknown[]; totalPages: number }>;
|
||||
tokenBody?: unknown;
|
||||
}) {
|
||||
const {
|
||||
resource,
|
||||
pages,
|
||||
tokenBody = { access_token: 'tok', token_type: 'Bearer', expires_in: 86400 },
|
||||
} = opts;
|
||||
|
||||
const calls: Array<{ url: string; init?: RequestInit }> = [];
|
||||
|
||||
const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {
|
||||
calls.push({ url, init });
|
||||
|
||||
if (url.includes('/token')) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => tokenBody,
|
||||
text: async () => '',
|
||||
} as unknown as Response;
|
||||
}
|
||||
|
||||
if (url.includes(`/${resource}`)) {
|
||||
const match = url.match(/page=(\d+)/);
|
||||
const pageNum = match ? parseInt(match[1], 10) : 0;
|
||||
const p = pages[pageNum];
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({
|
||||
content: p.content,
|
||||
page: { size: 200, totalElements: pages.reduce((n, pg) => n + pg.content.length, 0), totalPages: p.totalPages, number: pageNum },
|
||||
}),
|
||||
text: async () => '',
|
||||
} as unknown as Response;
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({ content: [], page: { size: 200, totalElements: 0, totalPages: 1, number: 0 } }),
|
||||
text: async () => '',
|
||||
} as unknown as Response;
|
||||
});
|
||||
|
||||
return { fetchMock, calls };
|
||||
}
|
||||
|
||||
describe('Pax8Client', () => {
|
||||
beforeEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
|
|
@ -105,4 +161,81 @@ describe('Pax8Client', () => {
|
|||
|
||||
expect(result).toEqual(companiesBody);
|
||||
});
|
||||
|
||||
it('listAllSubscriptions() concatenates content across all pages in order', async () => {
|
||||
const pages = [
|
||||
{ content: [{ id: 's1' }, { id: 's2' }], totalPages: 2 },
|
||||
{ content: [{ id: 's3' }], totalPages: 2 },
|
||||
];
|
||||
const { fetchMock, calls } = makeMultiPageFetchMock({ resource: 'subscriptions', pages });
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const client = new Pax8Client({ clientId: 'id1', clientSecret: SECRET });
|
||||
const result = await client.listAllSubscriptions();
|
||||
|
||||
expect(result).toEqual([{ id: 's1' }, { id: 's2' }, { id: 's3' }]);
|
||||
|
||||
const subCalls = calls.filter(c => c.url.includes('/subscriptions'));
|
||||
expect(subCalls).toHaveLength(2);
|
||||
for (const c of subCalls) {
|
||||
expect(c.url).toContain('size=200');
|
||||
}
|
||||
});
|
||||
|
||||
it('listAllSubscriptions() stops after a single page when totalPages is 1 (no infinite loop)', async () => {
|
||||
const pages = [{ content: [{ id: 's1' }], totalPages: 1 }];
|
||||
const { fetchMock, calls } = makeMultiPageFetchMock({ resource: 'subscriptions', pages });
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const client = new Pax8Client({ clientId: 'id1', clientSecret: SECRET });
|
||||
const result = await client.listAllSubscriptions();
|
||||
|
||||
expect(result).toEqual([{ id: 's1' }]);
|
||||
expect(calls.filter(c => c.url.includes('/subscriptions'))).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('listAllProducts() concatenates content across all pages in order', async () => {
|
||||
const pages = [
|
||||
{ content: [{ id: 'p1' }], totalPages: 2 },
|
||||
{ content: [{ id: 'p2' }], totalPages: 2 },
|
||||
];
|
||||
const { fetchMock } = makeMultiPageFetchMock({ resource: 'products', pages });
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const client = new Pax8Client({ clientId: 'id1', clientSecret: SECRET });
|
||||
const result = await client.listAllProducts();
|
||||
|
||||
expect(result).toEqual([{ id: 'p1' }, { id: 'p2' }]);
|
||||
});
|
||||
|
||||
it('listAllCompanies() concatenates content across all pages in order', async () => {
|
||||
const pages = [
|
||||
{ content: [{ id: 'c1' }], totalPages: 2 },
|
||||
{ content: [{ id: 'c2' }], totalPages: 2 },
|
||||
];
|
||||
const { fetchMock } = makeMultiPageFetchMock({ resource: 'companies', pages });
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const client = new Pax8Client({ clientId: 'id1', clientSecret: SECRET });
|
||||
const result = await client.listAllCompanies();
|
||||
|
||||
expect(result).toEqual([{ id: 'c1' }, { id: 'c2' }]);
|
||||
});
|
||||
|
||||
it('every request the listAll* helpers issue is a GET with an Authorization: Bearer header; none use a mutating method', async () => {
|
||||
const pages = [{ content: [{ id: 's1' }], totalPages: 1 }];
|
||||
const { fetchMock, calls } = makeMultiPageFetchMock({ resource: 'subscriptions', pages });
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
const client = new Pax8Client({ clientId: 'id1', clientSecret: SECRET });
|
||||
await client.listAllSubscriptions();
|
||||
|
||||
const dataCalls = calls.filter(c => !c.url.includes('/token'));
|
||||
expect(dataCalls.length).toBeGreaterThan(0);
|
||||
for (const c of dataCalls) {
|
||||
expect(c.init?.method === undefined || c.init?.method === 'GET').toBe(true);
|
||||
const authHeader = (c.init!.headers as Record<string, string>)['Authorization'];
|
||||
expect(authHeader).toMatch(/^Bearer /);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue