Files
insforge--insforge/backend/tests/unit/storage-url-versioning.test.ts
wehub-resource-sync 3a28426bf4
Lint and Format Check / lint-and-format (push) Failing after 0s
Check Migrations / Check for duplicate migration numbers (push) Failing after 1s
CI Pre-merge Check / CI Pre-merge Check (push) Failing after 2m17s
chore: import upstream snapshot with attribution
2026-07-13 12:23:40 +08:00

66 lines
2.4 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
// Mock environment before importing the service so getApiBaseUrl returns a
// stable host. The service caches the value at call time, not import time.
vi.mock('@/utils/environment.js', () => ({
getApiBaseUrl: () => 'https://example.test',
// logger.ts (pulled in transitively) gates its file transport on this;
// report cloud so the transport is skipped and no logs/ dir is created
isCloudEnvironment: () => true,
}));
// Stub DatabaseManager so StorageService construction doesn't touch a pool.
vi.mock('@/infra/database/database.manager.js', () => ({
DatabaseManager: { getInstance: () => ({ getPool: () => ({}) }) },
}));
import { StorageService } from '../../src/services/storage/storage.service.ts';
type UrlBuilder = (bucket: string, key: string, version?: string | Date | null) => string;
describe('StorageService URL versioning', () => {
let svc: StorageService;
let buildObjectUrl: UrlBuilder;
beforeEach(() => {
svc = StorageService.getInstance();
// The helpers are private; reach them via the prototype so we can test the
// exact contract a CDN sees without instantiating an Express request.
const proto = Object.getPrototypeOf(svc) as Record<string, unknown>;
buildObjectUrl = (proto.buildObjectUrl as UrlBuilder).bind(svc);
});
afterEach(() => {
vi.restoreAllMocks();
});
it('omits ?v= when no version is supplied', () => {
expect(buildObjectUrl('b', 'k')).toBe('https://example.test/api/storage/buckets/b/objects/k');
});
it('appends ?v=<etag> when an etag string is supplied', () => {
expect(buildObjectUrl('b', 'k', 'abc123')).toBe(
'https://example.test/api/storage/buckets/b/objects/k?v=abc123'
);
});
it('uses epoch-ms when version is a Date', () => {
const d = new Date('2024-01-02T03:04:05.000Z');
expect(buildObjectUrl('b', 'k', d)).toBe(
`https://example.test/api/storage/buckets/b/objects/k?v=${d.getTime()}`
);
});
it('url-encodes the version stamp', () => {
expect(buildObjectUrl('b', 'k', 'has spaces & symbols')).toBe(
'https://example.test/api/storage/buckets/b/objects/k?v=has%20spaces%20%26%20symbols'
);
});
it('url-encodes the object key', () => {
expect(buildObjectUrl('b', 'folder/sub key.png', 'v1')).toBe(
'https://example.test/api/storage/buckets/b/objects/folder%2Fsub%20key.png?v=v1'
);
});
});