Files
next.js/test/unit/image-optimizer/get-previously-cached-image-or-null.test.ts
Hendrik LiebauandGitHub 6a1b6336a3 Remove revalidate property from incremental cache ctx for FETCH kind (#76500)
The `revalidate` property of the `ctx` object that is passed into the
incremental cache by the patched `fetch` as well as `unstable_cache` is
unused since it was introduced in #43659. It was just added because of
how the method signature for `set()` was changed back then.

However, for those kinds of cache entries, the `revalidate` context
property is never used, and instead the `revalidate` property of the
passed-in `data` is used.

To avoid further confusion (e.g. in [this
question](https://github.com/vercel/next.js/pull/76207#discussion_r1968478141)),
this PR improves the method signatures and types of the incremental
cache so that the different call-site use cases can be clearly
discriminated, and superfluous context properties can be omitted.
2025-02-28 14:44:57 +01:00

123 lines
3.4 KiB
TypeScript

/* eslint-env jest */
import {
getPreviouslyCachedImageOrNull,
getImageEtag,
} from 'next/dist/server/image-optimizer'
import {
CachedRouteKind,
IncrementalCacheEntry,
} from 'next/dist/server/response-cache/types'
import { readFile } from 'fs-extra'
import { join } from 'path'
const getImageUpstream = async (filepath, contentType = 'image/jpeg') => {
const buffer = await readFile(join(__dirname, filepath))
const result: Parameters<typeof getPreviouslyCachedImageOrNull>[0] = {
buffer,
contentType,
cacheControl: 'max-age=31536000',
etag: getImageEtag(buffer),
}
return result
}
const baseCacheEntry = {
revalidateAfter: Date.now() + 1000,
curRevalidate: Date.now() + 500,
revalidate: Date.now() + 1000,
isStale: false,
isMiss: false,
isFallback: false,
} as const
const getPreviousCacheEntry = async (
filepath,
extension = 'jpeg',
optimizedEtag = true
) => {
const buffer = await readFile(join(__dirname, filepath))
const upstreamEtag = getImageEtag(buffer)
const result: IncrementalCacheEntry = {
...baseCacheEntry,
value: {
kind: CachedRouteKind.IMAGE,
upstreamEtag,
etag: optimizedEtag ? 'optimized-etag' : upstreamEtag,
buffer,
extension,
},
}
return result
}
describe('shouldUsePreviouslyCachedEntry', () => {
it('should return the cached image if the upstream image matches previous cache entry upstream etag and not the optimized etag', async () => {
const previousEntry = await getPreviousCacheEntry('./images/test.jpg')
expect(
getPreviouslyCachedImageOrNull(
await getImageUpstream('./images/test.jpg'),
previousEntry
)
).toEqual(previousEntry.value)
})
it('should return null if previous cache entry value is not of kind IMAGE', async () => {
const nonImageCacheEntry: IncrementalCacheEntry = {
...baseCacheEntry,
value: { kind: CachedRouteKind.REDIRECT, props: {} },
}
expect(
getPreviouslyCachedImageOrNull(
await getImageUpstream('./images/test.jpg'),
nonImageCacheEntry
)
).toBe(null)
})
it('should return null if upstream image does not match previous cache entry upstream etag', async () => {
expect(
getPreviouslyCachedImageOrNull(
await getImageUpstream('./images/test.png', 'image/png'),
await getPreviousCacheEntry('./images/test.jpg')
)
).toBe(null)
})
it('should return null if upstream image matches optimized etag', async () => {
expect(
getPreviouslyCachedImageOrNull(
await getImageUpstream('./images/test.jpg'),
await getPreviousCacheEntry('./images/test.jpg', 'jpeg', false)
)
).toBe(null)
})
it('should return null if previous cache entry is undefined', async () => {
expect(
getPreviouslyCachedImageOrNull(
await getImageUpstream('./images/test.jpg'),
undefined
)
).toBe(null)
})
it('should return null if previous cache entry is null', async () => {
expect(
getPreviouslyCachedImageOrNull(
await getImageUpstream('./images/test.jpg'),
null
)
).toBe(null)
})
it('should return null if previous cache entry value is null', async () => {
const nullValueCacheEntry = { ...baseCacheEntry, value: null }
expect(
getPreviouslyCachedImageOrNull(
await getImageUpstream('./images/test.jpg'),
nullValueCacheEntry
)
).toBe(null)
})
})