DodoTransfer/tests/unit/settings.test.js
2026-11-05 10:28:10 +09:00

104 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
const fs = require('fs');
const os = require('os');
const path = require('path');
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'psitransfer-settings-'));
process.env.PSITRANSFER_UPLOAD_DIR = tmpDir;
const { test, beforeEach, after } = require('node:test');
const assert = require('node:assert');
const config = require('../../config');
const settings = require('../../lib/settings');
const PNG = Buffer.concat([Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]), Buffer.alloc(32)]);
const SVG = Buffer.from('<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1"><rect width="1" height="1"/></svg>');
beforeEach(() => {
fs.rmSync(config.settingsDir, { recursive: true, force: true });
settings.reset();
});
after(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
test('settings live inside the data directory', () => {
assert.strictEqual(config.settingsDir, path.join(tmpDir, '.settings'));
});
test('brand falls back to the configured defaults', () => {
const brand = settings.brand();
assert.strictEqual(brand.name, 'Dodo Transfer');
assert.strictEqual(brand.from, 2026);
assert.strictEqual(brand.customLogo, false);
assert.match(brand.logoUrl, /assets\/brand-logo\?v=[0-9a-f]{10}$/);
});
test('footer shows a range once the start year is in the past', () => {
assert.strictEqual(settings.footerText('ACME', 2026, 2026), '© 2026 ACME');
assert.strictEqual(settings.footerText('ACME', 2026, 2028), '© 2026–2028 ACME');
assert.strictEqual(settings.footerText('', 2026, 2026), '© 2026');
});
test('update validates and persists', () => {
settings.update({ name: ' My Transfer ', owner: 'Team', from: '2024' });
assert.deepStrictEqual(
JSON.parse(fs.readFileSync(path.join(config.settingsDir, 'settings.json'), 'utf8')),
{ name: 'My Transfer', owner: 'Team', from: 2024 }
);
settings.reset();
assert.strictEqual(settings.brand().name, 'My Transfer');
assert.throws(() => settings.update({ name: ' ' }), /name/);
assert.throws(() => settings.update({ name: 'x'.repeat(41) }), /name/);
assert.throws(() => settings.update({ from: 1999 }), /year/);
assert.throws(() => settings.update({ from: 'abc' }), /year/);
assert.throws(() => settings.update({ owner: 'x'.repeat(61) }), /owner/);
// failed updates change nothing
assert.strictEqual(settings.brand().name, 'My Transfer');
});
test('logo is detected by its content', () => {
assert.strictEqual(settings.detectLogo(PNG).mime, 'image/png');
assert.strictEqual(settings.detectLogo(SVG).mime, 'image/svg+xml');
assert.strictEqual(settings.detectLogo(Buffer.from('RIFF\0\0\0\0WEBPVP8 ')).mime, 'image/webp');
assert.strictEqual(settings.detectLogo(Buffer.from('<html><svg></svg></html>')), null);
assert.strictEqual(settings.detectLogo(Buffer.from('GIF89a......')), null);
});
test('svg logos with scripts are rejected', () => {
const evil = Buffer.from('<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>');
assert.throws(() => settings.detectLogo(evil), /script/i);
const handler = Buffer.from('<svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"></svg>');
assert.throws(() => settings.detectLogo(handler), /script/i);
});
test('custom logo replaces the default and can be restored', () => {
const before = settings.brand();
const after1 = settings.setLogo(PNG);
assert.strictEqual(after1.customLogo, true);
assert.notStrictEqual(after1.logoUrl, before.logoUrl, 'url changes with the image (cache busting)');
assert.ok(fs.existsSync(path.join(config.settingsDir, 'logo.png')));
// another type removes the old file
settings.setLogo(SVG);
assert.ok(fs.existsSync(path.join(config.settingsDir, 'logo.svg')));
assert.ok(!fs.existsSync(path.join(config.settingsDir, 'logo.png')));
assert.strictEqual(settings.logoInfo().mime, 'image/svg+xml');
const restored = settings.clearLogo();
assert.strictEqual(restored.customLogo, false);
assert.strictEqual(restored.logoUrl, before.logoUrl);
assert.ok(!fs.existsSync(path.join(config.settingsDir, 'logo.svg')));
});
test('invalid logos are refused', () => {
assert.throws(() => settings.setLogo(Buffer.alloc(0)), /no image/);
assert.throws(() => settings.setLogo(Buffer.from('not an image at all')), /PNG/);
assert.throws(() => settings.setLogo(Buffer.concat([PNG, Buffer.alloc(settings.MAX_LOGO_SIZE)])), /1MB/);
assert.strictEqual(settings.brand().customLogo, false);
});