Skip to content

Commit f516dd9

Browse files
committed
fix(js-client): replace real-API e2e tests with MSW integration tests
- Add MSW-based integration tests (tests/api/index.test.ts) using the preconditions pattern, covering query param serialization, relation resolution pipeline, pagination via HTTP headers, links map extraction, and client-side caching behaviour - Trim e2e suite to 6 high-value smoke tests wrapped in describe.skipIf so they skip cleanly in CI when VITE_ACCESS_TOKEN is absent, fixing the external contributor CI failure - Add msw as a devDependency to storyblok-js-client Fixes WDX-307
1 parent 718b67d commit f516dd9

File tree

4 files changed

+260
-125
lines changed

4 files changed

+260
-125
lines changed

packages/js-client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"@vitest/coverage-v8": "^3.1.3",
6262
"@vitest/ui": "^3.1.3",
6363
"eslint": "^9.26.0",
64+
"msw": "^2.10.2",
6465
"tsdown": "^0.20.3",
6566
"typescript": "5.8.3",
6667
"vite": "^7.0.6",
Lines changed: 38 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,60 @@
11
import StoryblokClient from 'storyblok-js-client';
22
import { beforeEach, describe, expect, it } from 'vitest';
33

4-
describe('StoryblokClient', () => {
4+
/**
5+
* Smoke tests against the real Storyblok CDN API.
6+
*
7+
* These tests are intentionally minimal — they exist to catch real API
8+
* regressions (e.g. auth, response shape changes, content structure) that
9+
* MSW-based tests cannot detect.
10+
*
11+
* They are skipped automatically when VITE_ACCESS_TOKEN is not set, so
12+
* they never block CI for external contributors. They run when a valid
13+
* token is available (e.g. internal PRs or scheduled workflows).
14+
*
15+
* Required env vars (in .env.test):
16+
* VITE_ACCESS_TOKEN — CDN access token
17+
* VITE_SPACE_ID — numeric space ID
18+
*/
19+
describe.skipIf(!process.env.VITE_ACCESS_TOKEN)('StoryblokClient (smoke tests)', () => {
520
let client: StoryblokClient;
621

722
beforeEach(() => {
8-
// Setup default mocks
923
client = new StoryblokClient({
1024
accessToken: process.env.VITE_ACCESS_TOKEN,
1125
cache: { type: 'memory', clear: 'auto' },
1226
});
1327
});
14-
// TODO: Uncomment when we have a valid token
15-
/* if (process.env.VITE_OAUTH_TOKEN) {
16-
describe('management API', () => {
17-
const spaceId = process.env.VITE_SPACE_ID
18-
describe('should return all spaces', async () => {
19-
const StoryblokManagement = new StoryblokClient({
20-
oauthToken: process.env.VITE_OAUTH_TOKEN,
21-
})
22-
const result = await StoryblokManagement.getAll(
23-
`spaces/${spaceId}/stories`
24-
)
25-
expect(result.length).toBeGreaterThan(0)
26-
})
27-
})
28-
} */
2928

30-
describe('get function', () => {
31-
it('get(\'cdn/spaces/me\') should return the space information', async () => {
32-
const { data } = await client.get('cdn/spaces/me');
33-
expect(data.space.id).toBe(Number(process.env.VITE_SPACE_ID));
34-
});
35-
36-
it('get(\'cdn/stories\') should return all stories', async () => {
37-
const { data } = await client.get('cdn/stories');
38-
expect(data.stories.length).toBeGreaterThan(0);
39-
});
40-
41-
it('get(\'cdn/stories/testcontent-0\' should return the specific story', async () => {
42-
const { data } = await client.get('cdn/stories/testcontent-0');
43-
expect(data.story.slug).toBe('testcontent-0');
44-
});
45-
46-
it('get(\'cdn/stories\' { starts_with: testcontent-0 } should return the specific story', async () => {
47-
const { data } = await client.get('cdn/stories', {
48-
starts_with: 'testcontent-0',
49-
});
50-
expect(data.stories.length).toBe(1);
51-
});
52-
53-
it('get(\'cdn/stories/testcontent-draft\', { version: \'draft\' }) should return the specific story draft', async () => {
54-
const { data } = await client.get('cdn/stories/testcontent-draft', {
55-
version: 'draft',
56-
});
57-
expect(data.story.slug).toBe('testcontent-draft');
58-
});
59-
60-
it('get(\'cdn/stories/testcontent-0\', { version: \'published\' }) should return the specific story published', async () => {
61-
const { data } = await client.get('cdn/stories/testcontent-0', {
62-
version: 'published',
63-
});
64-
expect(data.story.slug).toBe('testcontent-0');
65-
});
66-
67-
it('cdn/stories/testcontent-0 should resolve author relations', async () => {
68-
const { data } = await client.get('cdn/stories/testcontent-0', {
69-
resolve_relations: 'root.author',
70-
});
71-
72-
expect(data.story.content.author[0].slug).toBe('edgar-allan-poe');
73-
});
74-
75-
it('get(\'cdn/stories\', { by_slugs: \'folder/*\' }) should return the specific story', async () => {
76-
const { data } = await client.get('cdn/stories', {
77-
by_slugs: 'folder/*',
78-
});
79-
expect(data.stories.length).toBeGreaterThan(0);
80-
});
29+
it('authenticates and returns space information', async () => {
30+
const { data } = await client.get('cdn/spaces/me');
31+
expect(data.space.id).toBe(Number(process.env.VITE_SPACE_ID));
8132
});
8233

83-
describe('getAll function', () => {
84-
it('getAll(\'cdn/stories\') should return all stories', async () => {
85-
const result = await client.getAll('cdn/stories', {});
86-
expect(result.length).toBeGreaterThan(0);
87-
});
88-
89-
it('getAll(\'cdn/stories\') should return all stories with filtered results', async () => {
90-
const result = await client.getAll('cdn/stories', {
91-
starts_with: 'testcontent-0',
92-
});
93-
expect(result.length).toBe(1);
94-
});
95-
96-
it('getAll(\'cdn/stories\', filter_query: { __or: [{ category: { any_in_array: \'Category 1\' } }, { category: { any_in_array: \'Category 2\' } }]}) should return all stories with the specific filter applied', async () => {
97-
const result = await client.getAll('cdn/stories', {
98-
filter_query: {
99-
__or: [
100-
{ category: { any_in_array: 'Category 1' } },
101-
{ category: { any_in_array: 'Category 2' } },
102-
],
103-
},
104-
});
105-
expect(result.length).toBeGreaterThan(0);
106-
});
107-
108-
it('getAll(\'cdn/stories\', {by_slugs: \'folder/*\'}) should return all stories with the specific filter applied', async () => {
109-
const result = await client.getAll('cdn/stories', {
110-
by_slugs: 'folder/*',
111-
});
112-
expect(result.length).toBeGreaterThan(0);
113-
});
34+
it('returns at least one published story', async () => {
35+
const { data } = await client.get('cdn/stories');
36+
expect(data.stories.length).toBeGreaterThan(0);
37+
});
11438

115-
it('getAll(\'cdn/links\') should return all links', async () => {
116-
const result = await client.getAll('cdn/links', {});
117-
expect(result.length).toBeGreaterThan(0);
118-
});
39+
it('returns a specific story by slug', async () => {
40+
const { data } = await client.get('cdn/stories/testcontent-0');
41+
expect(data.story.slug).toBe('testcontent-0');
11942
});
12043

121-
describe('caching', () => {
122-
it('get(\'cdn/spaces/me\') should not be cached', async () => {
123-
const provider = client.cacheProvider();
124-
await provider.flush();
125-
await client.get('cdn/spaces/me');
126-
expect(Object.values(provider.getAll()).length).toBe(0);
44+
it('resolves relations against real content', async () => {
45+
const { data } = await client.get('cdn/stories/testcontent-0', {
46+
resolve_relations: 'root.author',
12747
});
48+
expect(data.story.content.author[0].slug).toBe('edgar-allan-poe');
49+
});
12850

129-
it('get(\'cdn/stories\') should be cached when is a published version', async () => {
130-
const cacheVersion = client.cacheVersion();
131-
132-
await client.get('cdn/stories');
133-
134-
expect(cacheVersion).not.toBe(undefined);
135-
136-
const newCacheVersion = client.cacheVersion();
137-
138-
await client.get('cdn/stories');
139-
140-
expect(newCacheVersion).toBe(client.cacheVersion());
141-
142-
await client.get('cdn/stories');
51+
it('returns stories matching a by_slugs wildcard', async () => {
52+
const { data } = await client.get('cdn/stories', { by_slugs: 'folder/*' });
53+
expect(data.stories.length).toBeGreaterThan(0);
54+
});
14355

144-
expect(newCacheVersion).toBe(client.cacheVersion());
145-
});
56+
it('paginates through all stories with getAll', async () => {
57+
const result = await client.getAll('cdn/stories', {});
58+
expect(result.length).toBeGreaterThan(0);
14659
});
14760
});

0 commit comments

Comments
 (0)