How to Test File Upload in Mobile and Web Apps
File upload sits at the intersection of UI, network, and backend validation. Small bugs manifest as big problems: users cannot submit forms, documents are silently corrupted, or malicious files slip t
File upload sits at the intersection of UI, network, and backend validation. Small bugs manifest as big problems: users cannot submit forms, documents are silently corrupted, or malicious files slip through. This guide covers the test plan that catches all three.
What to test
Upload UI
- Tap / click triggers file picker
- Camera option (mobile) for photos
- Gallery option (mobile) for existing media
- Document picker (files) on supported platforms
- Drag-and-drop (web) works and is visually signaled
- Multiple files selectable (if supported)
File restrictions
- Accepted types enforced (images only, PDFs only, etc.)
- Invalid types rejected with clear message
- File size limit enforced client-side
- File size limit enforced server-side (do not trust client)
- Total upload size limit (if multiple files)
Upload process
- Progress indicator visible
- Progress accurate (not jumping to 99%)
- Cancel mid-upload works
- Upload resumes after transient network drops (if supported)
- Force-close mid-upload: queued or lost cleanly (not corrupted)
- Multiple simultaneous uploads handled
- Upload succeeds on Wi-Fi, cellular, roaming
- Low-bandwidth upload times out gracefully
Post-upload
- Success state clear (filename, thumbnail, URL)
- Error state actionable ("Upload failed, try again")
- File replaceable (re-upload overwrites or adds)
- File removable (delete clears server record)
Security
- File type validated by content, not just extension (
.exerenamed to.jpgdetected) - File size capped server-side
- Uploaded files scanned for malware (antivirus integration)
- Executable files blocked for typical-user uploads
- Filename sanitized (no path traversal like
../../../etc/passwd) - EXIF / metadata stripped from images (location leak)
- Uploaded file URL not predictable (random UUID, not
user_id/filename) - ACL enforced — user A cannot access user B's upload
Mobile-specific
- Camera permission requested correctly
- Gallery permission requested correctly
- Background upload continues if user backgrounds app
- Permission denied → clear recovery path
- HEIC images (iOS) converted if server expects JPG
Accessibility
- Upload button labeled
- Progress announced to screen reader
- Success / error state announced
- Touch target ≥ 48dp
Edge cases
- 0-byte file → rejected
- Exactly-max-size file → accepted
- Just-over-max file → rejected with message
- Very long filename → truncated display, full name stored
- Filename with special characters, emoji → preserved or sanitized consistently
- Duplicate file upload → handled per policy (dedup or version)
- Concurrent uploads from two devices → last-write or conflict UI
How to test manually
Prepare a test file bank:
- Minimum: 1 tiny valid file, 1 just-under-max, 1 just-over-max, 1 wrong-type, 1 zero-byte
- Ideal: also a large valid file, a file with special chars in name, an image with EXIF/GPS data, a file that looks like one type but is another (
file.jpgthat is actually.exe)
Test on:
- Strong Wi-Fi
- Weak Wi-Fi
- 4G
- Edge (slow cellular)
- Packet loss conditions (mitmproxy / network conditioner)
- Flight mode (rejection)
Automated testing
Playwright
def test_file_upload(page):
page.goto("/upload")
page.set_input_files('input[type="file"]', 'test_assets/small.jpg')
page.click('button[type="submit"]')
expect(page.locator('.success-message')).to_be_visible()
Appium (Android)
# Push file to device first
driver.push_file("/sdcard/Download/test.jpg", source_path="test.jpg")
driver.find_element(AppiumBy.ID, "upload_btn").click()
# Navigate the file picker
driver.find_element(AppiumBy.XPATH, "//android.widget.Button[@text='Downloads']").click()
driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[@text='test.jpg']").click()
Backend validation
Unit-test the server validator with a matrix of filenames, types, sizes. Ensure:
- Extension and content-type match
- Size within bounds
- Filename sanitized
- Path traversal blocked
How SUSA handles file upload
SUSA pushes a test assets bundle to the device and drives upload flows. Test files include valid, invalid, boundary-size, and special-character filename cases.
susatest-agent test myapp.apk --persona adversarial --test-assets ./assets
The adversarial persona tries invalid file types and oversized files, stressing the client-side validation. Findings include: upload that silently ignored a server error, client accepting files server rejects, progress bar stuck after cancel.
Common production bugs
- Client validates extension, server validates size — can upload oversized binary if named
.jpg - Progress jumps from 0% to 100% — not actually monitoring upload
- EXIF GPS data leaked in user-uploaded photos on public profile
- Cancel does not stop the upload — request continues, bandwidth wasted
- Filename collisions overwrite — user loses old upload silently
Upload is worth a dedicated test pass every release. The security implications alone justify the attention.
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free