Developer testing guide
Exact-size file upload boundary testing
Upload-limit bugs often come from measuring different things. The browser may report File.size, a reverse proxy may enforce the full multipart request, and an application may validate decoded or persisted bytes. Test every boundary explicitly.
Verified . The workflow separates file bytes from transport bytes and uses Playwright buffers with explicit lengths.
Practical checklist
- Write the limit in bytes before creating fixtures.
- Test limit minus one, exact limit, and limit plus one.
- Distinguish file bytes from multipart request bytes.
- Assert status, error code, UI message, and storage side effects.
Define the measured boundary
Document whether KB means 1,000 bytes or KiB means 1,024 bytes. State whether the limit applies to one file, the combined files, the multipart body, decoded content, or the object stored after processing.
Use three adjacent fixtures
For a limit L, test L−1, L, and L+1 bytes. Keep the content type and filename constant so size is the only changed variable. Test zero-byte and very large declared Content-Length cases separately.
Assert the entire failure contract
A rejected upload should return the documented status and machine-readable error, show a useful message, create no persistent object, and remain retryable with a smaller file.
Expected results
- L−1 and L follow the documented acceptance rule.
- L+1 is rejected before expensive parsing.
- Rejected uploads leave no object, preview job, or database row.
Common failure modes
- Mixing decimal KB and binary KiB.
- Testing File.size while the proxy limits the multipart body.
- Returning success before an asynchronous size validation fails.
Check the fixture with curl
Download the representative file and print the response status, MIME type, and transferred byte count.
curl --fail --location --silent --show-error \
--output sample-document.pdf \
--write-out 'status=%{http_code}\ncontent_type=%{content_type}\nbytes=%{size_download}\n' \
'https://assets.testfiles.dev/documents/sample-document.pdf'Verify document integrity with Python Requests
Download the document and assert its MIME type, exact byte size, and SHA-256 digest before passing it to a parser or preview service.
import hashlib
import requests
url = "https://assets.testfiles.dev/documents/sample-document.pdf"
response = requests.get(url, timeout=30)
response.raise_for_status()
assert "application/pdf" in response.headers.get("content-type", "")
assert len(response.content) == 9051
assert hashlib.sha256(response.content).hexdigest() == "c0ca139748753dd192bda50ea731868e8f832b5ed97499d12ffb2c995791ffbc"
print("Verified sample-document.pdf", len(response.content), "bytes")Playwright boundary upload
Download a verified PDF, pad copies to adjacent byte sizes, and submit each buffer through a real file input.
import { test, expect } from '@playwright/test';
test('checks an exact 1 MiB upload boundary', async ({ page, request }) => {
const source = await request.get('https://assets.testfiles.dev/documents/sample-document.pdf');
const bytes = await source.body();
const limit = 1024 * 1024;
for (const size of [limit - 1, limit, limit + 1]) {
const payload = Buffer.alloc(size);
bytes.copy(payload, 0, 0, Math.min(bytes.length, size));
await page.getByLabel('File').setInputFiles({ name: 'boundary.pdf', mimeType: 'application/pdf', buffer: payload });
await page.getByRole('button', { name: 'Upload' }).click();
await expect(page.getByTestId('upload-status')).toHaveText(size <= limit ? 'Accepted' : 'Too large');
}
});Use stable sample files
These fixtures have stable URLs, recorded MIME types, byte sizes, SHA-256 values, and dedicated detail pages.