Bundles the prior autonomous-session output that was sitting unstaged: - Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances) - country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk after the per-subpath dynamic-import approach silently failed in webpack) - Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index, redirects (ocr to ai, reports to dashboard, invitations to users), docs/admin-ia-proposal.md - Per-template email tester (registry + endpoint + UI on Email admin page) - Cancel-document mode picker (delete-from-Documenso vs keep-for-audit) - Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers - Customize-widgets per-region sortables at xl+ (charts/rails/feed); single flat sortable below xl when the layout stacks; per-viewport saved orders - Audit doc updates capturing each shipped item - Lint fixes: react-compiler immutability in DonutChart (reduce instead of let-reassign), set-state-in-effect disables in CountryFlag and UploadForSigning preview-bytes effect, unused 'confirm' destructures in interest contract + reservation tabs, unescaped apostrophe in test-template card copy
63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
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);
|
|
});
|
|
});
|