@spoolcms/nextjs
Version:
The beautiful headless CMS for Next.js developers
124 lines (123 loc) • 4.98 kB
JavaScript
"use strict";
/**
* Test for the "Body is unusable" error fix
*/
Object.defineProperty(exports, "__esModule", { value: true });
const content_1 = require("../utils/content");
const cache_1 = require("../utils/cache");
// Mock fetch to simulate the "Body is unusable" error
const mockFetch = jest.fn();
global.fetch = mockFetch;
// Mock environment to simulate client-side behavior
jest.mock('../utils/environment', () => ({
detectEnvironment: () => ({
isServer: false,
isClient: true,
isDevelopment: true,
isProduction: false,
isReactStrictMode: true,
}),
getEnvironmentCacheKey: () => 'client-dev',
}));
describe('Body is unusable error fix', () => {
beforeEach(() => {
mockFetch.mockClear();
cache_1.globalCache.clear();
});
it('should handle "Body is unusable" error and retry', async () => {
const config = {
apiKey: 'test-key',
siteId: 'test-site',
baseUrl: 'http://localhost:3000'
};
const mockData = {
id: '1',
slug: 'test-post',
data: { title: 'Test Post', body: 'Test content' }
};
// First call fails with "Body is unusable"
const bodyUnusableError = new Error('Body is unusable');
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest.fn().mockRejectedValue(bodyUnusableError),
clone: jest.fn().mockReturnThis(),
});
// Second call (retry) succeeds
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest.fn().mockResolvedValue(mockData),
clone: jest.fn().mockReturnThis(),
});
const result = await (0, content_1.getSpoolContent)({ collection: 'blog', slug: 'test-post', config: config });
// Should return flattened structure
expect(result.id).toBe('1');
expect(result.slug).toBe('test-post');
expect(result.title).toBe('Test Post');
expect(result.body).toBe('Test content');
expect(result.data.title).toBe('Test Post');
expect(result.data.body).toBe('Test content');
// Should have made 2 fetch calls (failed + retry)
expect(mockFetch).toHaveBeenCalledTimes(2);
// Second call should have cache: 'no-store'
expect(mockFetch).toHaveBeenNthCalledWith(2, expect.any(String), expect.objectContaining({
cache: 'no-store'
}));
});
it('should handle "disturbed" error and retry', async () => {
const config = {
apiKey: 'test-key',
siteId: 'test-site',
baseUrl: 'http://localhost:3000'
};
const mockData = {
id: '1',
slug: 'test-post',
data: { title: 'Test Post', body: 'Test content' }
};
// First call fails with "disturbed" error
const disturbedError = new Error('Body stream is disturbed');
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest.fn().mockRejectedValue(disturbedError),
clone: jest.fn().mockReturnThis(),
});
// Second call (retry) succeeds
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest.fn().mockResolvedValue(mockData),
clone: jest.fn().mockReturnThis(),
});
const result = await (0, content_1.getSpoolContent)({ collection: 'blog', slug: 'test-post', config: config });
// Should return flattened structure
expect(result.id).toBe('1');
expect(result.slug).toBe('test-post');
expect(result.title).toBe('Test Post');
expect(result.body).toBe('Test content');
expect(result.data.title).toBe('Test Post');
expect(result.data.body).toBe('Test content');
// Should have made 2 fetch calls (failed + retry)
expect(mockFetch).toHaveBeenCalledTimes(2);
// Second call should have cache: 'no-store'
expect(mockFetch).toHaveBeenNthCalledWith(2, expect.any(String), expect.objectContaining({
cache: 'no-store'
}));
});
it('should return null for non-body-related JSON errors', async () => {
const config = {
apiKey: 'test-key',
siteId: 'test-site',
baseUrl: 'http://localhost:3000'
};
const syntaxError = new SyntaxError('Unexpected token');
mockFetch.mockResolvedValueOnce({
ok: true,
json: jest.fn().mockRejectedValue(syntaxError),
clone: jest.fn().mockReturnThis(),
});
// Should return null instead of throwing (error handling in getSpoolContent)
const result = await (0, content_1.getSpoolContent)({ collection: 'blog', slug: 'test-post', config: config });
expect(result).toBeNull();
// Should only make 1 fetch call (no retry for syntax errors)
expect(mockFetch).toHaveBeenCalledTimes(1);
});
});