Repository: vercel/next.js
File: test/e2e/app-dir/next-image/next-image.test.ts (TypeScript)

Code before:
import { nextTestSetup } from 'e2e-utils'
import fs from 'fs-extra'
import { join } from 'path'

describe('app dir - next-image', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  describe('ssr content', () => {
    it('should handle HEAD requests for uncached images', async () => {
      const imagesDir = join(next.testDir, '.next/cache/images')
      await fs.remove(imagesDir).catch(() => {})

      const $ = await next.render$('/')
      const imageUrl = $('#app-layout').attr('src')

      const headRes = await next.fetch(imageUrl, { method: 'HEAD' })
      expect(headRes.status).toBe(200)
      expect(headRes.headers.get('content-type')).toMatch(/^image\//)
      expect(headRes.headers.get('X-Nextjs-Cache')).toBe('MISS')

      const contentLength = headRes.headers.get('content-length')
      expect(Number(contentLength || '0')).toBeGreaterThan(0)

      const getRes = await next.fetch(imageUrl)
      expect(getRes.status).toBe(200)
      expect(getRes.headers.get('content-type')).toMatch(/^image\//)
      expect(getRes.headers.get('X-Nextjs-Cache')).toBe('HIT')

      const getContentLength = getRes.headers.get('content-length')
      expect(Number(getContentLength || '0')).toBeGreaterThan(0)

      const getBody = await getRes.arrayBuffer()
      expect(getBody.byteLength).toBeGreaterThan(0)
      expect(getBody.byteLength).toBe(Number(getContentLength))
    })

    it('should render images on / route', async () => {
      const $ = await next.render$('/')

Review comment (performance):
I don't think you can do `render()` here since I think it causes the browser to render the html and make a GET request to the img right?

We need to make the HEAD request before the GET request, so it needs to call the `/_next/image` endpoint directly without rendering.

It might be easier to move this test into the existing test suite here: https://github.com/vercel/next.js/blob/8d415853f73c72263d24be3ea92b497d41f242f0/test/integration/image-optimizer/test/util.ts#L1313

Code after:
import { nextTestSetup } from 'e2e-utils'
import fs from 'fs-extra'
import { join } from 'path'

describe('app dir - next-image', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  describe('ssr content', () => {
    it('should handle HEAD requests for uncached images', async () => {
      const imagesDir = join(next.testDir, '.next/cache/images')
      await fs.remove(imagesDir).catch(() => {})

      const $ = await next.render$('/')
      const imageUrl = $('#app-layout').attr('src')

      const headRes = await next.fetch(imageUrl, { method: 'HEAD' })
      expect(headRes.status).toBe(200)
      expect(headRes.headers.get('content-type')).toMatch(/^image\//)
      expect(headRes.headers.get('X-Nextjs-Cache')).toBe('MISS')

      const contentLength = headRes.headers.get('content-length')
      expect(Number(contentLength || '0')).toBeGreaterThan(0)
      const headBody = await headRes.arrayBuffer()
      expect(headBody.byteLength).toBe(0)

      const getRes = await next.fetch(imageUrl)
      expect(getRes.status).toBe(200)
      expect(getRes.headers.get('content-type')).toMatch(/^image\//)
      expect(getRes.headers.get('X-Nextjs-Cache')).toBe('HIT')

      const getContentLength = getRes.headers.get('content-length')
      expect(Number(getContentLength || '0')).toBeGreaterThan(0)

      const getBody = await getRes.arrayBuffer()
      expect(getBody.byteLength).toBeGreaterThan(0)
      expect(getBody.byteLength).toBe(Number(getContentLength))
    })