Files
immich-folio/lib/__tests__/alt-text.test.ts

136 lines
3.9 KiB
TypeScript
Raw Normal View History

import { describe, it, expect } from 'vitest';
import {
albumPaths,
buildAltTextReport,
immichWebUrl,
pickImmichWebUrl,
type AltTextAssetInput,
} from '../admin/alt-text';
const photo = (id: string, description: string | null = null): AltTextAssetInput => ({
id,
type: 'IMAGE',
originalFileName: `${id}.jpg`,
exifInfo: { description },
});
describe('buildAltTextReport', () => {
it('lists photos without a description, per album', () => {
const report = buildAltTextReport(
[
{
id: 'a1',
name: 'Island',
path: '/travel',
assets: [photo('p1', 'A fjord'), photo('p2')],
},
],
true,
);
expect(report.total).toBe(2);
expect(report.described).toBe(1);
expect(report.albums).toEqual([
{
albumId: 'a1',
albumName: 'Island',
path: '/travel',
total: 2,
missing: [{ assetId: 'p2', fileName: 'p2.jpg' }],
},
]);
});
/** A description of spaces renders as an empty alt all the same. */
it('treats a blank description as missing', () => {
const report = buildAltTextReport(
[{ id: 'a1', name: 'A', path: '/', assets: [photo('p1', ' ')] }],
true,
);
expect(report.described).toBe(0);
expect(report.albums[0].missing).toHaveLength(1);
});
/** Videos have no alt attribute to fill. */
it('does not count videos', () => {
const report = buildAltTextReport(
[
{
id: 'a1',
name: 'A',
path: '/',
assets: [{ id: 'v1', type: 'VIDEO', originalFileName: 'v1.mp4' }, photo('p1', 'x')],
},
],
true,
);
expect(report.total).toBe(1);
expect(report.albums).toEqual([]);
});
it('counts a photo that sits in two albums once', () => {
const shared = photo('p1');
const report = buildAltTextReport(
[
{ id: 'a1', name: 'A', path: '/', assets: [shared] },
{ id: 'a2', name: 'B', path: '/', assets: [shared] },
],
true,
);
expect(report.total).toBe(1);
expect(report.albums).toHaveLength(2);
});
it('puts the album with the most gaps first and leaves out complete ones', () => {
const report = buildAltTextReport(
[
{ id: 'few', name: 'Few', path: '/', assets: [photo('p1')] },
{ id: 'done', name: 'Done', path: '/', assets: [photo('p2', 'x')] },
{ id: 'many', name: 'Many', path: '/', assets: [photo('p3'), photo('p4')] },
],
true,
);
expect(report.albums.map((a) => a.albumId)).toEqual(['many', 'few']);
});
it('passes the caption setting through', () => {
expect(buildAltTextReport([], false).captionsEnabled).toBe(false);
});
});
describe('albumPaths', () => {
it('uses the first subpage that lists an album', () => {
const paths = albumPaths([
{ slug: 'travel', albumIds: ['a1'] },
{ slug: 'best-of', albumIds: ['a1', 'a2'] },
]);
expect(paths.get('a1')).toBe('/travel');
expect(paths.get('a2')).toBe('/best-of');
expect(paths.get('a3')).toBeUndefined();
});
});
describe('immichWebUrl', () => {
it('drops the /api suffix Folio appends', () => {
expect(immichWebUrl('http://immich:2283/api')).toBe('http://immich:2283');
expect(immichWebUrl('https://photos.example.com/api/')).toBe('https://photos.example.com');
});
});
describe('pickImmichWebUrl', () => {
it("prefers Immich's external domain", () => {
expect(pickImmichWebUrl('https://photos.example.com/', 'http://immich:2283/api')).toEqual({
url: 'https://photos.example.com',
source: 'external-domain',
});
});
it('falls back to the API address when the domain is unset or not a URL', () => {
for (const domain of ['', ' ', null, undefined, 'photos.example.com']) {
expect(pickImmichWebUrl(domain, 'http://immich:2283/api')).toEqual({
url: 'http://immich:2283',
source: 'api-url',
});
}
});
});