Files
wehub-resource-sync 0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

134 lines
4.6 KiB
TypeScript

import { beforeEach, describe, expect, it, Mock, vi } from 'vitest';
import { setDownloadHeaders } from '../../../src/server/utils/downloadHelpers';
import type { Response } from 'express';
describe('downloadHelpers', () => {
describe('setDownloadHeaders', () => {
let mockRes: Partial<Response>;
let setHeaderMock: Mock;
beforeEach(() => {
setHeaderMock = vi.fn().mockReturnThis();
mockRes = {
setHeader: setHeaderMock,
} as Partial<Response>;
});
it('should set correct headers for CSV download', () => {
setDownloadHeaders(mockRes as Response, 'test-file.csv', 'text/csv');
expect(setHeaderMock).toHaveBeenCalledWith('Content-Type', 'text/csv');
expect(setHeaderMock).toHaveBeenCalledWith(
'Content-Disposition',
'attachment; filename="test-file.csv"',
);
expect(setHeaderMock).toHaveBeenCalledWith(
'Cache-Control',
'no-cache, no-store, must-revalidate',
);
expect(setHeaderMock).toHaveBeenCalledWith('Pragma', 'no-cache');
expect(setHeaderMock).toHaveBeenCalledWith('Expires', '0');
});
it('should set correct headers for JSON download', () => {
setDownloadHeaders(mockRes as Response, 'data.json', 'application/json');
expect(setHeaderMock).toHaveBeenCalledWith('Content-Type', 'application/json');
expect(setHeaderMock).toHaveBeenCalledWith(
'Content-Disposition',
'attachment; filename="data.json"',
);
});
it('should handle special characters in filename', () => {
setDownloadHeaders(mockRes as Response, 'file with spaces & special.csv', 'text/csv');
expect(setHeaderMock).toHaveBeenCalledWith(
'Content-Disposition',
'attachment; filename="file with spaces & special.csv"',
);
});
it('should handle very long filenames', () => {
const longFileName = 'a'.repeat(255) + '.csv';
setDownloadHeaders(mockRes as Response, longFileName, 'text/csv');
expect(setHeaderMock).toHaveBeenCalledWith(
'Content-Disposition',
`attachment; filename="${longFileName}"`,
);
});
it('should handle Unicode characters in filename', () => {
setDownloadHeaders(mockRes as Response, '测试文件.csv', 'text/csv');
expect(setHeaderMock).toHaveBeenCalledWith(
'Content-Disposition',
'attachment; filename="测试文件.csv"',
);
});
it('should handle different content types', () => {
const testCases = [
{ fileName: 'file.pdf', contentType: 'application/pdf' },
{ fileName: 'file.xml', contentType: 'application/xml' },
{ fileName: 'file.txt', contentType: 'text/plain' },
{ fileName: 'file.yaml', contentType: 'application/x-yaml' },
];
testCases.forEach(({ fileName, contentType }) => {
setHeaderMock.mockClear();
setDownloadHeaders(mockRes as Response, fileName, contentType);
expect(setHeaderMock).toHaveBeenCalledWith('Content-Type', contentType);
expect(setHeaderMock).toHaveBeenCalledWith(
'Content-Disposition',
`attachment; filename="${fileName}"`,
);
});
});
it('should set all cache control headers', () => {
setDownloadHeaders(mockRes as Response, 'test.csv', 'text/csv');
// Verify all cache-preventing headers are set
const calls = setHeaderMock.mock.calls;
const headerMap = new Map(calls.map((call) => [call[0] as string, call[1]]));
expect(headerMap.get('Cache-Control')).toBe('no-cache, no-store, must-revalidate');
expect(headerMap.get('Pragma')).toBe('no-cache');
expect(headerMap.get('Expires')).toBe('0');
});
it('should be called exactly 5 times for all headers', () => {
setDownloadHeaders(mockRes as Response, 'test.csv', 'text/csv');
expect(setHeaderMock).toHaveBeenCalledTimes(5);
});
it('should handle empty filename', () => {
setDownloadHeaders(mockRes as Response, '', 'text/csv');
expect(setHeaderMock).toHaveBeenCalledWith('Content-Disposition', 'attachment; filename=""');
});
it('should handle filename with quotes', () => {
setDownloadHeaders(mockRes as Response, 'file"with"quotes.csv', 'text/csv');
expect(setHeaderMock).toHaveBeenCalledWith(
'Content-Disposition',
'attachment; filename="file"with"quotes.csv"',
);
});
it('should handle filename with path separators', () => {
setDownloadHeaders(mockRes as Response, 'path/to/file.csv', 'text/csv');
expect(setHeaderMock).toHaveBeenCalledWith(
'Content-Disposition',
'attachment; filename="path/to/file.csv"',
);
});
});
});