Image Upload Testing Checklist (2026)

Image Upload Testing Checklist (2026) provides a concrete, step‑by‑step matrix for validating every aspect of an image upload feature—from the simplest happy‑path flow to the most obscure edge case, a

June 18, 2026 · 17 min read · Testing Checklists

Image Upload Testing Checklist (2026) provides a concrete, step‑by‑step matrix for validating every aspect of an image upload feature—from the simplest happy‑path flow to the most obscure edge case, accessibility concern, and security risk. Use this guide as a reference you can bookmark, adapt to your stack, and run manually or through automation. The sections below break the checklist into logical groups, give clear pass criteria, show real‑world examples, and include code snippets that you can drop into a test suite.

---

Image Upload Testing Checklist (2026): Happy Path Scenarios

Core flow validation

Test IDDescriptionInput / ActionExpected ResultPass Criteria
HP‑01Single image upload via file pickerSelect a JPEG ≤ 5 MB, click UploadImage appears in gallery, upload success toast, HTTP 200 response with URLUpload completes within 3 s on 3G, no errors in console
HP‑02Drag‑and‑drop uploadDrag a PNG ≤ 10 MB onto drop zone, releaseSame as HP‑01, visual feedback shows drop zone highlightNo JavaScript errors, drop zone returns to idle state
HP‑03Multiple image selectionChoose 3 images (JPEG, PNG, WebP) each ≤ 2 MBAll three upload concurrently, each shows individual progress bar, final gallery shows all threeAll requests return 200, total time ≤ 1.5× single upload time
HP‑04Upload from camera (mobile)Launch camera, capture photo, confirmPhoto uploaded, EXIF orientation preserved, thumbnail generatedImage displays correctly oriented, no corruption
HP‑05Upload with optional metadataFill caption field “Sunset beach”, select album “Vacation”, uploadBackend stores image URL, caption, album ID; gallery shows caption under thumbnailMetadata matches payload sent in multipart request
HP‑06Resume after network interruptionStart upload, disable Wi‑Fi at 50 % progress, re‑enable after 5 sUpload resumes from checkpoint, completes successfullyNo duplicate files, final size matches original

Implementation notes

Automated happy‑path snippets

cURL (manual verification)


curl -X POST https://api.example.com/v1/images \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@/tmp/sample.jpg;type=image/jpeg" \
  -F "caption=Sunset beach" \
  -F "album_id=42"

Appium (Android) – Java


@Test
public void testHappyPathUpload() {
    driver.findElement(By.id("upload_btn")).click();
    driver.findElement(By.id("file_picker")).sendKeys("/sdcard/Pictures/test.jpg");
    driver.findElement(By.id("caption")).sendKeys("Happy path test");
    driver.findElement(By.id("submit")).click();

    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("toast_success")));
    Assert.assertTrue(driver.findElement(By.id("toast_success")).getText()
            .contains("Upload successful"));
}

Playwright (Web) – TypeScript


test('happy path upload', async ({ page }) => {
  await page.goto('/upload');
  await page.setInputFiles('input[type="file"]', 'tests/fixtures/sample.png');
  await page.fill('textarea[placeholder="Caption"]', 'Playwright test');
  await page.click('button:has-text("Upload")');

  await expect(page.locator('.toast-success')).toContainText('Uploaded');
  const imgSrc = await page.getAttribute('img.gallery-item', 'src');
  expect(imgSrc).toMatch(/^https:\/\/cdn\.example\.com\/images\/.+\.(png|jpe?g)$/);
});

---

Image Upload Testing Checklist (2026): Error Handling and Validation

Client‑side validation

Test IDDescriptionInput / ActionExpected ResultPass Criteria
EH‑01Empty file pickerClick Upload without selecting a fileInline error “Please select an image”, form not submittedNo network request, focus stays on picker
EH‑02Wrong MIME typeSelect a .pdf fileError “Only image files are allowed”Request blocked, file not uploaded
EH‑03Exceed size limitChoose a 12 MB JPEG (limit 10 MB)Error “File too large – max 10 MB”No upload attempt
EH‑04Zero‑byte fileCreate empty file touch empty.jpg, select itError “File appears to be corrupted”Upload rejected
EH‑05Invalid characters in filenameSelect file named image<>.jpgEither sanitized name or error “Invalid filename”No 500 server error; filename stored safely
EH‑06Simultaneous exceed of concurrent uploadsTry to start 6 uploads when limit is 4First 4 start, remaining 2 queued or show “Too many concurrent uploads”System stays responsive, no crash

Server‑side validation

Test IDDescriptionInput / ActionExpected ResultPass Criteria
EH‑07Malformed multipart boundarySend request with missing boundaryHTTP 400 Bad Request, error “Invalid multipart format”No image stored
EH‑08Path traversal in filenameFilename ../../etc/passwdHTTP 400, error “Invalid filename”No file written outside upload directory
EH‑09Embedded scripts (XSS)Upload SVG with File stored but served with Content‑Disposition: attachment or sanitized; script not executedResponse headers prevent execution
EH‑10Virus‑like contentUpload file containing EICAR test stringAV service (if integrated) blocks, returns HTTP 422 with “Malicious content detected”No file persisted
EH‑11Metadata injectionCaption field with SQL '; DROP TABLE images;--Stored as plain text, no SQL errorParameterized queries or ORM used
EH‑12Unsupported image formatUpload HEIC on backend that only accepts JPEG/PNG/WebPHTTP 415 Unsupported Media TypeClear error message, no 500

Implementation notes

Automated error‑handling snippet (Playwright)


test('rejects PDF upload', async ({ page }) => {
  await page.goto('/upload');
  await page.setInputFiles('input[type="file"]', 'tests/fixtures/dummy.pdf');
  await expect(page.locator('.error-message')).toHaveText(/Only image files are allowed/);
  await expect(page.request.once('request', r => r.url().includes('/v1/images'))).not.toBeCalled();
});

---

Image Upload Testing Checklist (2026): Edge and Boundary Cases

File‑size boundaries

Test IDSize (bytes)LimitExpected Result
EB‑010 (empty)>0Rejected (see EH‑04)
EB‑021 byte>0Accepted if valid image header (rare) – otherwise rejected
EB‑039 999 99910 MBAccepted
EB‑0410 000 00010 MBAccepted (exact boundary)
EB‑0510 000 00110 MBRejected
EB‑0650 MB100 MB (high‑limit endpoint)Accepted
EB‑07150 MB100 MBRejected

Dimension boundaries

Test IDWidth × Height (px)Max dimensionExpected Result
EB‑081 × 15000 pxAccepted (tiny but valid)
EB‑095000 × 50005000 pxAccepted (exact)
EB‑105001 × 50005000 pxRejected (width exceeds)
EB‑1110000 × 1005000 pxRejected (height exceeds)
EB‑120 × 0N/ARejected (invalid image)

Format‑specific quirks

Test IDFormatParticularityExpected Result
EB‑13JPEG with CMYK profileSome browsers cannot display CMYKImage uploaded, but preview may show colors shifted – ensure server converts to sRGB or warns
EB‑14PNG with alpha channelTransparencyPreserved after upload; verify via GET that alpha channel intact
EB‑15WebP losslessNewer formatAccepted if backend supports; otherwise returns 415
EB‑16Animated GIFMultiple framesAccepted; ensure only first frame used for thumbnail unless spec says otherwise
EB‑17HEIC (Apple)Requires licensingIf backend lacks HEIC support, return 415 with helpful message
EB‑18SVG with external resourcesSanitize or block external references; otherwise may lead to SSRF

Implementation notes

Shell script to create boundary JPEGs


#!/usr/bin/env bash
# creates a JPEG of exact size $1 bytes (approximate)
SIZE=$1
OUT="test_${SIZE}b.jpg"
# start with a 100x100 color image
convert -size 100x100 xc:#$(printf "%06x" $((RANDOM%0xffffff))) tmp.png
# adjust quality until file size approximates target
QUAL=95
while true; do
  convert tmp.png -quality $QUAL $OUT
  ACTUAL=$(stat -c%s "$OUT")
  if (( ACTUAL <= SIZE && ACTUAL > SIZE-500 )); then break; fi
  if (( ACTUAL > SIZE )); then ((QUAL--)); else ((QUAL++)); fi
done
echo "Generated $OUT ($ACTUAL bytes)"

---

Image Upload Testing Checklist (2026): Accessibility

Keyboard navigation

Test IDActionExpected Result
A‑01Tab to file‑picker button, press EnterFile‑picker dialog opens
A‑02Tab through drop zone, press SpaceSame as click – file‑picker opens
A‑03After selecting file, tab to caption field, type, then tab to Upload button, press EnterUpload initiates
A‑04Escape key while dialog open closes dialog without selectionNo stray file attached

Screen‑reader announcements

Test IDScenarioExpected Announcement
A‑05File‑picker opens“Choose file, button”
A‑06File selected“File selected, image.jpg”
A‑07Upload in progress“Uploading, 30 percent completed” (if live region)
A‑08Upload success“Upload successful, image.jpg added to gallery”
A‑09Upload error“Error, file too large – maximum 10 MB”

Color contrast & focus visibility

ARIA & labeling

Automated accessibility check (axe‑core with Playwright)


import { injectAxe, checkA11y } from '@playwright/experimental-axe-helper';

test.describe('upload accessibility', () => {
  test.beforeEach(async ({ page }) => {
    await injectAxe(page);
    await page.goto('/upload');
  });

  test('passes axe core checks', async ({ page }) => {
    const accessibilitySnapshot = await checkA11y(page, {
      // exclude known false positives if any
      exclude: ['.tooltip'],
    });
    expect(accessibilitySnapshot.violations).toEqual([]);
  });
});

---

Image Upload Testing Checklist (2026): Security and Privacy

Threat model checklist

Test IDThreatTest caseExpected mitigation
S‑01Unauthorized uploadOmit auth token, attempt POSTHTTP 401 Unauthorized
S‑02File type spoofingRename .exe to .jpg, uploadServer rejects based on magic bytes, not extension
S‑03Path traversalFilename ../../../tmp/evil.jpgServer normalizes, returns 400
S‑04SSRF via image URL fetchProvide URL http://169.254.169.254/latest/meta-data/ in metadata fieldServer disallows fetching external URLs or restricts to allow‑list domains
S‑05Denial of service via huge fileUpload 5 GB fileConnection timed out or rejected early by size check before disk consumption
S‑06Metadata leakageUpload image with GPS coordinates, check if EXIF strippedEither EXIF removed or stored separately with user consent
S‑07CSRFSubmit upload form from another site without tokenRequest rejected due to missing/invalid CSRF token
S‑08ClickjackingEmbed upload page in iframeX-Frame-Options: DENY or CSP frame-ancestors 'none'
S‑09Rate limiting abuseSend 100 upload requests in 5 s from same IPHTTP 429 Too Many Requests after threshold
S‑10Stored XSS via SVGUpload SVG with