test(realapi): Phase A integration spec scaffolds
Adds four realapi specs that gate cleanly on env: smtp-system-send (roundtrip + attachment bytes), email-attachments-roundtrip (cross-port 403), documenso-cancel (in-flight cancel → status flip), minio-file-lifecycle (upload/list/download/delete byte-equal). Specs skip without DOCUMENSO_API_*/SMTP/IMAP/MINIO env so they run as no-ops when those services aren't reachable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
62
tests/e2e/realapi/minio-file-lifecycle.spec.ts
Normal file
62
tests/e2e/realapi/minio-file-lifecycle.spec.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'dotenv/config';
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
import { login, apiHeaders } from '../smoke/helpers';
|
||||
|
||||
/**
|
||||
* Real-API spec for the MinIO file lifecycle (Phase A PR11).
|
||||
*
|
||||
* Uploads a file via POST /api/v1/files, lists it, downloads it, asserts
|
||||
* byte-equality with the upload, then deletes it. Verifies port-isolation
|
||||
* by attempting download with no auth and expecting 401.
|
||||
*
|
||||
* Requires MINIO_* env to be configured (the dev-server startup already
|
||||
* validates these via env.ts). Skips when MINIO_ENDPOINT is unset.
|
||||
*/
|
||||
|
||||
const MINIO_ENDPOINT = process.env.MINIO_ENDPOINT;
|
||||
|
||||
test.describe('MinIO file lifecycle', () => {
|
||||
test.skip(!MINIO_ENDPOINT, 'MINIO_ENDPOINT not configured');
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await login(page, 'super_admin');
|
||||
});
|
||||
|
||||
test('upload → list → download → delete round-trip', async ({ page }) => {
|
||||
const headers = await apiHeaders(page);
|
||||
const sentinel = `phase-a-minio-${Date.now()}`;
|
||||
const buffer = Buffer.from(sentinel.repeat(8));
|
||||
|
||||
// Upload
|
||||
const uploadRes = await page.request.post('/api/v1/files', {
|
||||
headers,
|
||||
multipart: {
|
||||
file: {
|
||||
name: 'phase-a-minio.txt',
|
||||
mimeType: 'text/plain',
|
||||
buffer,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(uploadRes.ok(), `upload: ${uploadRes.status()}`).toBe(true);
|
||||
const uploadBody = (await uploadRes.json()) as { data: { id: string } };
|
||||
const fileId = uploadBody.data.id;
|
||||
|
||||
// List should include the file
|
||||
const list = await page.request.get('/api/v1/files?limit=50', { headers });
|
||||
expect(list.ok()).toBe(true);
|
||||
const listBody = (await list.json()) as { data: Array<{ id: string }> };
|
||||
expect(listBody.data.find((f) => f.id === fileId)).toBeDefined();
|
||||
|
||||
// Download — assert byte-equality
|
||||
const dlRes = await page.request.get(`/api/v1/files/${fileId}/download`, { headers });
|
||||
expect(dlRes.ok()).toBe(true);
|
||||
const dlBody = await dlRes.body();
|
||||
expect(dlBody.equals(buffer)).toBe(true);
|
||||
|
||||
// Delete
|
||||
const delRes = await page.request.delete(`/api/v1/files/${fileId}`, { headers });
|
||||
expect(delRes.ok()).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user