68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import MockAdapter from 'axios-mock-adapter';
|
|
import { apiClient } from '@/api/client';
|
|
import { downloadEngagementExport } from '@/api/exports';
|
|
|
|
describe('downloadEngagementExport — Content-Disposition fallback', () => {
|
|
let mock: MockAdapter;
|
|
let capturedAnchor: HTMLAnchorElement | null = null;
|
|
|
|
beforeEach(() => {
|
|
mock = new MockAdapter(apiClient);
|
|
capturedAnchor = null;
|
|
|
|
globalThis.URL.createObjectURL = vi.fn().mockReturnValue('blob:fake-url');
|
|
globalThis.URL.revokeObjectURL = vi.fn();
|
|
|
|
const origCreateElement = document.createElement.bind(document);
|
|
vi.spyOn(document, 'createElement').mockImplementation((tag: string) => {
|
|
const el = origCreateElement(tag);
|
|
if (tag === 'a') {
|
|
capturedAnchor = el as HTMLAnchorElement;
|
|
vi.spyOn(el as HTMLAnchorElement, 'click').mockImplementation(() => {});
|
|
}
|
|
return el;
|
|
});
|
|
|
|
vi.spyOn(document.body, 'appendChild').mockImplementation((node) => node);
|
|
vi.spyOn(document.body, 'removeChild').mockImplementation((node) => node);
|
|
});
|
|
|
|
afterEach(() => {
|
|
mock.restore();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it('uses fallback filename engagement-{id}.md when Content-Disposition is absent', async () => {
|
|
mock.onGet('/engagements/42/export').reply(200, new Blob(['# test']), {
|
|
'content-type': 'text/markdown',
|
|
});
|
|
|
|
await downloadEngagementExport(42, 'md');
|
|
|
|
expect(capturedAnchor?.download).toBe('engagement-42.md');
|
|
});
|
|
|
|
it('uses fallback filename engagement-{id}.csv when Content-Disposition is malformed (no filename=)', async () => {
|
|
mock.onGet('/engagements/7/export').reply(200, new Blob(['col1,col2']), {
|
|
'content-type': 'text/csv',
|
|
'content-disposition': 'attachment',
|
|
});
|
|
|
|
await downloadEngagementExport(7, 'csv');
|
|
|
|
expect(capturedAnchor?.download).toBe('engagement-7.csv');
|
|
});
|
|
|
|
it('uses filename from Content-Disposition when header is well-formed', async () => {
|
|
mock.onGet('/engagements/5/export').reply(200, new Blob(['data']), {
|
|
'content-type': 'application/pdf',
|
|
'content-disposition': 'attachment; filename="engagement-5-slug-20260101.pdf"',
|
|
});
|
|
|
|
await downloadEngagementExport(5, 'pdf');
|
|
|
|
expect(capturedAnchor?.download).toBe('engagement-5-slug-20260101.pdf');
|
|
});
|
|
});
|