Skip to content

Commit 060dd69

Browse files
authored
fix: retrieve links with the right typings (#911)
1 parent 49d1fab commit 060dd69

File tree

3 files changed

+162
-2
lines changed

3 files changed

+162
-2
lines changed

src/index.test.ts

+127
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
33
import type { ResponseFn } from './sbFetch';
44
import SbFetch from './sbFetch';
55
import { SbHelpers } from './sbHelpers';
6+
import type { ISbLink } from './interfaces';
67

78
// Mocking external dependencies
89
vi.mock('../src/sbFetch', () => {
@@ -376,6 +377,132 @@ describe('storyblokClient', () => {
376377
// Verify the API was called only once (no relation resolution)
377378
expect(mockGet).toHaveBeenCalledTimes(1);
378379
});
380+
381+
describe('cdn/links endpoint', () => {
382+
it('should fetch links with dates when include_dates is set to 1', async () => {
383+
const mockLinksResponse = {
384+
data: {
385+
links: {
386+
'story-1': {
387+
id: 1,
388+
uuid: 'story-1-uuid',
389+
slug: 'story-1',
390+
name: 'Story 1',
391+
is_folder: false,
392+
parent_id: 0,
393+
published: true,
394+
position: 0,
395+
// Date fields included because of include_dates: 1
396+
created_at: '2024-01-01T10:00:00.000Z',
397+
published_at: '2024-01-01T11:00:00.000Z',
398+
updated_at: '2024-01-02T10:00:00.000Z',
399+
},
400+
'story-2': {
401+
id: 2,
402+
uuid: 'story-2-uuid',
403+
slug: 'story-2',
404+
name: 'Story 2',
405+
is_folder: false,
406+
parent_id: 0,
407+
published: true,
408+
position: 1,
409+
created_at: '2024-01-03T10:00:00.000Z',
410+
published_at: '2024-01-03T11:00:00.000Z',
411+
updated_at: '2024-01-04T10:00:00.000Z',
412+
},
413+
},
414+
},
415+
headers: {},
416+
status: 200,
417+
};
418+
419+
const mockGet = vi.fn().mockResolvedValue(mockLinksResponse);
420+
421+
client.client = {
422+
get: mockGet,
423+
post: vi.fn(),
424+
setFetchOptions: vi.fn(),
425+
baseURL: 'https://api.storyblok.com/v2',
426+
};
427+
428+
const response = await client.get('cdn/links', {
429+
version: 'draft',
430+
include_dates: 1,
431+
});
432+
433+
// Verify the structure of the response
434+
expect(response).toHaveProperty('data.links');
435+
436+
// Check if links are present and have the correct structure
437+
expect(response.data.links['story-1']).toBeDefined();
438+
expect(response.data.links['story-2']).toBeDefined();
439+
440+
// Verify date fields are present in the response
441+
const link: ISbLink = response.data.links['story-1'];
442+
expect(link).toHaveProperty('created_at');
443+
expect(link).toHaveProperty('published_at');
444+
expect(link).toHaveProperty('updated_at');
445+
446+
// Verify the date formats
447+
const DATETIME_FORMAT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
448+
expect(link.created_at).toMatch(DATETIME_FORMAT);
449+
expect(link.published_at).toMatch(DATETIME_FORMAT);
450+
expect(link.updated_at).toMatch(DATETIME_FORMAT);
451+
452+
// Verify the API was called with correct parameters
453+
expect(mockGet).toHaveBeenCalledWith('/cdn/links', {
454+
cv: 0,
455+
token: 'test-token',
456+
version: 'draft',
457+
include_dates: 1,
458+
});
459+
expect(mockGet).toHaveBeenCalledTimes(1);
460+
});
461+
462+
it('should handle links response without dates when include_dates is not set', async () => {
463+
const mockResponse = {
464+
data: {
465+
links: {
466+
'story-1': {
467+
id: 1,
468+
uuid: 'story-1-uuid',
469+
slug: 'story-1',
470+
name: 'Story 1',
471+
is_folder: false,
472+
parent_id: 0,
473+
published: true,
474+
position: 0,
475+
// No date fields
476+
},
477+
},
478+
},
479+
headers: {},
480+
status: 200,
481+
};
482+
483+
const mockGet = vi.fn().mockResolvedValue(mockResponse);
484+
client.client.get = mockGet;
485+
486+
const response = await client.get('cdn/links', { version: 'draft' });
487+
488+
expect(response.data.links['story-1']).not.toHaveProperty('created_at');
489+
expect(response.data.links['story-1']).not.toHaveProperty('published_at');
490+
expect(response.data.links['story-1']).not.toHaveProperty('updated_at');
491+
});
492+
493+
it('should handle errors gracefully', async () => {
494+
const mockGet = vi.fn().mockRejectedValue({
495+
status: 404,
496+
});
497+
client.client.get = mockGet;
498+
499+
await expect(client.get('cdn/links', {
500+
version: 'draft',
501+
})).rejects.toMatchObject({
502+
status: 404,
503+
});
504+
});
505+
});
379506
});
380507

381508
describe('getAll', () => {

src/index.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import type {
1212
ISbConfig,
1313
ISbContentMangmntAPI,
1414
ISbCustomFetch,
15+
ISbLinksParams,
16+
ISbLinksResult,
1517
ISbLinkURLObject,
1618
ISbNode,
1719
ISbResponse,
@@ -226,11 +228,23 @@ class Storyblok {
226228
return this.cacheResponse(url, query, undefined, fetchOptions);
227229
}
228230

231+
public get(
232+
slug: 'cdn/links',
233+
params?: ISbLinksParams,
234+
fetchOptions?: ISbCustomFetch
235+
): Promise<ISbLinksResult>;
236+
229237
public get(
230238
slug: string,
231239
params?: ISbStoriesParams,
240+
fetchOptions?: ISbCustomFetch
241+
): Promise<ISbResult>;
242+
243+
public get(
244+
slug: string,
245+
params?: ISbStoriesParams | ISbLinksParams,
232246
fetchOptions?: ISbCustomFetch,
233-
): Promise<ISbResult> {
247+
): Promise<ISbResult | ISbLinksResult> {
234248
if (!params) {
235249
params = {} as ISbStoriesParams;
236250
}
@@ -451,7 +465,6 @@ class Storyblok {
451465
const fieldPath = jtree.component ? `${jtree.component}.${treeItem}` : treeItem;
452466
// Check if this exact pattern exists in the fields to resolve
453467
if (Array.isArray(fields) ? fields.includes(fieldPath) : fields === fieldPath) {
454-
//
455468
this._resolveField(jtree, treeItem, resolveId);
456469
}
457470
}

src/interfaces.ts

+20
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,10 @@ export interface ISbResult {
238238
headers: Headers;
239239
}
240240

241+
export interface ISbLinksResult extends ISbResult {
242+
data: ISbLinks;
243+
}
244+
241245
export interface ISbResponse {
242246
data: any;
243247
status: number;
@@ -333,6 +337,22 @@ export interface ISbLink {
333337
position?: number;
334338
uuid?: string;
335339
is_startpage?: boolean;
340+
path?: string;
341+
real_path?: string;
342+
published_at?: string;
343+
created_at?: string;
344+
updated_at?: string;
345+
}
346+
347+
export interface ISbLinksParams {
348+
starts_with?: string;
349+
version?: 'published' | 'draft';
350+
paginated?: number;
351+
per_page?: number;
352+
page?: number;
353+
sort_by?: string;
354+
include_dates?: 0 | 1;
355+
with_parent?: number;
336356
}
337357

338358
export interface ISbLinks {

0 commit comments

Comments
 (0)