mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
Based on our metrics, the P99.9 for a source image is 47 MB so we can adjust the default setting to be much lower (by changing from from 300 MB to 50 MB) in favor of reducing memory.
189 lines
5.5 KiB
TypeScript
189 lines
5.5 KiB
TypeScript
/* eslint-env jest */
|
|
import {
|
|
fetchExternalImage,
|
|
ImageError,
|
|
} from 'next/dist/server/image-optimizer'
|
|
|
|
describe('fetchExternalImage', () => {
|
|
describe('response size limit', () => {
|
|
it('should throw error when response has no body', async () => {
|
|
global.fetch = jest.fn().mockResolvedValue({
|
|
ok: true,
|
|
status: 200,
|
|
body: null,
|
|
headers: {
|
|
get: jest.fn(() => null),
|
|
},
|
|
})
|
|
|
|
const error = await fetchExternalImage(
|
|
'http://example.com/no-body.jpg',
|
|
false,
|
|
50_000_000
|
|
).catch((e) => e)
|
|
|
|
expect(error).toBeInstanceOf(ImageError)
|
|
expect((error as ImageError).statusCode).toBe(400)
|
|
expect((error as ImageError).message).toBe(
|
|
'"url" parameter is valid but upstream response is invalid'
|
|
)
|
|
})
|
|
|
|
it('should throw error when exceeding maximumResponseBody config on later chunk', async () => {
|
|
const maximumResponseBody = 2_000 // 2KB custom limit
|
|
const chunkSize = 1_000 // 1KB chunks
|
|
const numChunks = 3 // 3KB total, exceeds custom 2KB limit
|
|
|
|
global.fetch = jest.fn().mockImplementation(() => {
|
|
let chunksRead = 0
|
|
const mockReadableStream = new ReadableStream({
|
|
async pull(controller) {
|
|
if (chunksRead < numChunks) {
|
|
controller.enqueue(new Uint8Array(chunkSize))
|
|
chunksRead++
|
|
} else {
|
|
controller.close()
|
|
}
|
|
},
|
|
})
|
|
|
|
return Promise.resolve({
|
|
ok: true,
|
|
status: 200,
|
|
body: mockReadableStream,
|
|
headers: {
|
|
get: jest.fn((header: string) => {
|
|
if (header === 'Content-Type') return 'image/jpeg'
|
|
return null
|
|
}),
|
|
},
|
|
})
|
|
})
|
|
|
|
const error = await fetchExternalImage(
|
|
'http://example.com/custom-limit.jpg',
|
|
false,
|
|
maximumResponseBody
|
|
).catch((e) => e)
|
|
|
|
expect(error).toBeInstanceOf(ImageError)
|
|
expect((error as ImageError).statusCode).toBe(413)
|
|
expect((error as ImageError).message).toBe(
|
|
'"url" parameter is valid but upstream response is invalid'
|
|
)
|
|
})
|
|
|
|
it('should throw error when exceeding maximumResponseBody config on first chunk', async () => {
|
|
const maximumResponseBody = 2_000 // 2KB custom limit
|
|
|
|
global.fetch = jest.fn().mockImplementation(() => {
|
|
const mockReadableStream = new ReadableStream({
|
|
async pull(controller) {
|
|
controller.enqueue(new Uint8Array(maximumResponseBody + 1))
|
|
controller.close()
|
|
},
|
|
})
|
|
|
|
return Promise.resolve({
|
|
ok: true,
|
|
status: 200,
|
|
body: mockReadableStream,
|
|
headers: {
|
|
get: jest.fn((header: string) => {
|
|
if (header === 'Content-Type') return 'image/jpeg'
|
|
return null
|
|
}),
|
|
},
|
|
})
|
|
})
|
|
|
|
const error = await fetchExternalImage(
|
|
'http://example.com/custom-limit.jpg',
|
|
false,
|
|
maximumResponseBody
|
|
).catch((e) => e)
|
|
|
|
expect(error).toBeInstanceOf(ImageError)
|
|
expect((error as ImageError).statusCode).toBe(413)
|
|
expect((error as ImageError).message).toBe(
|
|
'"url" parameter is valid but upstream response is invalid'
|
|
)
|
|
})
|
|
|
|
it('should succeed when exactly matching maximumResponseBody config on first chunk', async () => {
|
|
const maximumResponseBody = 3_000 // 3KB custom limit
|
|
|
|
global.fetch = jest.fn().mockImplementation(() => {
|
|
const mockReadableStream = new ReadableStream({
|
|
async pull(controller) {
|
|
controller.enqueue(new Uint8Array(maximumResponseBody))
|
|
controller.close()
|
|
},
|
|
})
|
|
|
|
return Promise.resolve({
|
|
ok: true,
|
|
status: 200,
|
|
body: mockReadableStream,
|
|
headers: {
|
|
get: jest.fn((header: string) => {
|
|
if (header === 'Content-Type') return 'image/jpeg'
|
|
return null
|
|
}),
|
|
},
|
|
})
|
|
})
|
|
|
|
const result = await fetchExternalImage(
|
|
'http://example.com/custom-limit.jpg',
|
|
false,
|
|
maximumResponseBody
|
|
)
|
|
|
|
expect(result.buffer).toBeInstanceOf(Buffer)
|
|
expect(result.buffer.length).toBe(maximumResponseBody)
|
|
})
|
|
|
|
it('should succeed when exactly matching maximumResponseBody config on later chunk', async () => {
|
|
const maximumResponseBody = 3_000 // 3KB custom limit
|
|
const chunkSize = 1_000 // 1KB chunks
|
|
const numChunks = 3 // 3KB total
|
|
|
|
global.fetch = jest.fn().mockImplementation(() => {
|
|
let chunksRead = 0
|
|
const mockReadableStream = new ReadableStream({
|
|
async pull(controller) {
|
|
if (chunksRead < numChunks) {
|
|
controller.enqueue(new Uint8Array(chunkSize))
|
|
chunksRead++
|
|
} else {
|
|
controller.close()
|
|
}
|
|
},
|
|
})
|
|
|
|
return Promise.resolve({
|
|
ok: true,
|
|
status: 200,
|
|
body: mockReadableStream,
|
|
headers: {
|
|
get: jest.fn((header: string) => {
|
|
if (header === 'Content-Type') return 'image/jpeg'
|
|
return null
|
|
}),
|
|
},
|
|
})
|
|
})
|
|
|
|
const result = await fetchExternalImage(
|
|
'http://example.com/custom-limit.jpg',
|
|
false,
|
|
maximumResponseBody
|
|
)
|
|
|
|
expect(result.buffer).toBeInstanceOf(Buffer)
|
|
expect(result.buffer.length).toBe(maximumResponseBody)
|
|
})
|
|
})
|
|
})
|