Files
vercel__next.js/test/unit/image-optimizer/find-closest-quality.test.ts
Daniel Tao 208c4f44b1 fix(image): findClosestQuality returns 0 for low quality values (#89621)
Fixes #89620

Fix `findClosestQuality` returning `0` when the `quality` prop on
`<Image>` is set to a low value (e.g. `quality={1}`), which causes the
image optimization server to reject the request with a 400 error.

### Cause

The `reduce` call in `findClosestQuality` used `0` as its initial
accumulator. Since `0` is not a valid quality value (must be 1-100), it
would win the "closest" comparison for any `quality <= 37` with the
default `qualities: [75]` config. This produced `q=0` in the image URL,
which the server rejects.

### Fix Description

Changed the `reduce` initializer from `0` to `config.qualities[0]`. This
is safe because the early return above already handles the empty array
case, so `config.qualities[0]` is always defined when reached.

Added a unit test for `quality=1` with `qualities=[75]` to verify it
returns `75` instead of `0`.

---------

Co-authored-by: Steven <steven@ceriously.com>
2026-02-09 10:11:38 -05:00

90 lines
2.3 KiB
TypeScript

/* eslint-env jest */
import { findClosestQuality } from 'next/dist/shared/lib/find-closest-quality'
describe('findClosestQuality', () => {
it.each<{ input: Parameters<typeof findClosestQuality>; output: number }>([
{
input: [undefined, undefined],
output: 75,
},
{
input: [50, undefined],
output: 50,
},
{
input: [50, { qualities: undefined }],
output: 50,
},
{
input: [35, { qualities: [10, 30, 50] }],
output: 30,
},
{
input: [30, { qualities: [10, 30, 50] }],
output: 30,
},
{
input: [31, { qualities: [10, 30, 50] }],
output: 30,
},
{
input: [29, { qualities: [10, 30, 50] }],
output: 30,
},
{
input: [39, { qualities: [10, 30, 50] }],
output: 30,
},
{
input: [40, { qualities: [10, 30, 50] }],
output: 30, // favor the lower number when halfway
},
{
input: [41, { qualities: [10, 30, 50] }],
output: 50,
},
{
input: [75, { qualities: [50, 75, 100] }],
output: 75,
},
{
input: [undefined, { qualities: [50, 75, 100] }],
output: 75,
},
{
input: [undefined, { qualities: [25, 60, 100] }],
output: 60, // use closest to 75 when 75 is not in the config
},
{
input: [undefined, { qualities: [25, 50, 75] }],
output: 75, // use 75 when 75 is in the config
},
{
input: [undefined, { qualities: [100, 10, 75, 15] }],
output: 75, // use 75 when 75 is in the config, even out of order
},
{
input: [10, { qualities: [100, 10, 75, 15] }],
output: 10, // use input even when config is out of order
},
{
input: [14, { qualities: [100, 10, 75, 15] }],
output: 15, // use closet input even when config is out of order
},
{
input: [1, { qualities: [75] }],
output: 75, // low quality should not return 0
},
{
input: [4, { qualities: [5, 25] }],
output: 5, // ensure low quality still rounds up
},
{
input: [6, { qualities: [5, 25] }],
output: 5, // ensure low quality still rounds down
},
])('for quality $input expected $output', ({ input, output }) => {
expect(findClosestQuality(...input)).toEqual(output)
})
})