Files
HDR/test/hdr-enhance.test.mjs

376 lines
11 KiB
JavaScript

import assert from 'node:assert/strict';
import { createRequire } from 'node:module';
import test from 'node:test';
const require = createRequire(import.meta.url);
const HDREnhancer = require('../src/hdr-enhance.js');
function createMatchMedia(matches) {
return (query) => ({
media: query,
matches: Boolean(matches[query]),
addEventListener() {},
removeEventListener() {}
});
}
function createFakeDocument() {
const nodesById = new Map();
const attach = (node, parentList) => {
parentList.push(node);
if (node.id) nodesById.set(node.id, node);
return node;
};
const documentElement = {
dataset: {},
style: {
values: {},
setProperty(name, value) {
this.values[name] = value;
},
removeProperty(name) {
delete this.values[name];
}
}
};
const body = {
dataset: {},
children: [],
appendChild(node) {
return attach(node, this.children);
},
removeAttribute(name) {
if (name === 'data-hdr-enhanced') delete this.dataset.hdrEnhanced;
if (name === 'data-hdr-mode') delete this.dataset.hdrMode;
if (name === 'data-hdr-media') delete this.dataset.hdrMedia;
if (name === 'data-hdr-text') delete this.dataset.hdrText;
}
};
const head = {
children: [],
appendChild(node) {
return attach(node, this.children);
}
};
return {
body,
documentElement,
head,
createElement(tagName) {
return {
tagName: tagName.toUpperCase(),
id: '',
className: '',
textContent: '',
innerHTML: '',
dataset: {},
style: {},
children: [],
attributes: {},
setAttribute(name, value) {
this.attributes[name] = String(value);
},
appendChild(child) {
return attach(child, this.children);
},
remove() {
nodesById.delete(this.id);
head.children = head.children.filter((node) => node !== this);
body.children = body.children.filter((node) => node !== this);
}
};
},
getElementById(id) {
return nodesById.get(id) || null;
},
querySelectorAll() {
return [];
}
};
}
test('detectCapabilities prefers the widest available gamut and HDR dynamic range', () => {
const capabilities = HDREnhancer.detectCapabilities({
matchMedia: createMatchMedia({
'(dynamic-range: high)': true,
'(color-gamut: rec2020)': true,
'(color-gamut: p3)': true,
'(prefers-reduced-motion: reduce)': false
}),
CSS: {
supports(property, value) {
return (
property === 'color' && value === 'color(display-p3 1 0 0)'
) || (
property === 'dynamic-range-limit' && value === 'no-limit'
);
}
}
});
assert.equal(capabilities.dynamicRange, 'high');
assert.equal(capabilities.colorGamut, 'rec2020');
assert.equal(capabilities.supportsDisplayP3, true);
assert.equal(capabilities.supportsDynamicRangeLimit, true);
assert.equal(capabilities.prefersReducedMotion, false);
});
test('createStyleText includes HDR, P3, pure-black, no-limit, and reduced-motion rules', () => {
const css = HDREnhancer.createStyleText({
intensity: 1.2,
animated: true,
text: true,
textBoost: 2.4
}, {
dynamicRange: 'high',
colorGamut: 'p3',
supportsDisplayP3: true,
supportsHdrColor: true,
prefersReducedMotion: false
});
assert.match(css, /@media \(dynamic-range: high\)/);
assert.match(css, /@media \(color-gamut: p3\)/);
assert.match(css, /dynamic-range-limit: no-limit/);
assert.match(css, /background: #000000 !important/);
assert.match(css, /body\[data-hdr-enhanced="true"\]::before/);
assert.match(css, /color\(display-p3/);
assert.match(css, /--hdr-fallback-cyan/);
assert.match(css, /--hdr-text-boost: 2\.40/);
assert.match(css, /data-hdr-text/);
assert.match(css, /--hdr-texture-url/);
assert.match(css, /background-clip: text/);
assert.match(css, /-webkit-text-fill-color: transparent/);
assert.match(css, /hdr-color/);
assert.match(css, /:where\(body\[data-hdr-enhanced="true"\] > :not/);
assert.match(css, /prefers-reduced-motion: reduce/);
});
test('createMediaConfig defaults to HDR video on HDR-capable outputs only', () => {
const hdr = HDREnhancer.createMediaConfig({
assetBase: 'https://example.com/',
media: true
}, {
dynamicRange: 'high'
});
const sdr = HDREnhancer.createMediaConfig({
assetBase: 'https://example.com/',
media: true
}, {
dynamicRange: 'standard'
});
const disabled = HDREnhancer.createMediaConfig({
assetBase: 'https://example.com/',
media: false
}, {
dynamicRange: 'high'
});
assert.equal(hdr.enabled, true);
assert.equal(hdr.type, 'video');
assert.equal(hdr.src, 'https://example.com/media/hdr-galaxy-fireworks.mp4');
assert.deepEqual(hdr.sources, [
{
src: 'https://example.com/media/hdr-galaxy-fireworks.mp4',
type: 'video/mp4; codecs="hvc1"'
},
{
src: 'https://example.com/media/hdr-galaxy-fireworks.webm',
type: 'video/webm; codecs="vp09.02.10.10.01.09.16.09.01"'
}
]);
assert.equal(sdr.enabled, false);
assert.equal(disabled.enabled, false);
});
test('createMediaConfig can inject a swappable HDR image stage', () => {
const hdr = HDREnhancer.createMediaConfig({
assetBase: 'https://example.com/',
media: true,
mediaType: 'image',
imageSrc: '/assets/custom-hdr.png'
}, {
dynamicRange: 'high'
});
assert.equal(hdr.enabled, true);
assert.equal(hdr.type, 'image');
assert.equal(hdr.src, 'https://example.com/assets/custom-hdr.png');
assert.equal(hdr.sources.length, 1);
assert.equal(hdr.sources[0].type, 'image/png');
});
test('enhance injects pure-black HDR media once, then disable removes it', () => {
const document = createFakeDocument();
const window = {
document,
matchMedia: createMatchMedia({
'(dynamic-range: high)': true,
'(color-gamut: p3)': true
}),
CSS: {
supports() {
return true;
}
}
};
const first = HDREnhancer.enhance({ window, intensity: 1.1 });
const second = HDREnhancer.enhance({ window, intensity: 1.1 });
assert.equal(first.active, true);
assert.equal(second.active, true);
assert.equal(second.reused, true);
assert.equal(document.head.children.filter((node) => node.id === 'hdr-enhancer-style').length, 1);
assert.equal(document.body.children.filter((node) => node.id === 'hdr-enhancer-overlay').length, 0);
assert.equal(document.body.children.filter((node) => node.id === 'hdr-enhancer-video').length, 1);
assert.equal(document.body.dataset.hdrEnhanced, 'true');
assert.equal(document.body.dataset.hdrMode, 'p3');
assert.equal(document.body.dataset.hdrMedia, 'true');
const disabled = HDREnhancer.disable({ window });
assert.equal(disabled.active, false);
assert.equal(document.getElementById('hdr-enhancer-style'), null);
assert.equal(document.getElementById('hdr-enhancer-overlay'), null);
assert.equal(document.getElementById('hdr-enhancer-video'), null);
assert.equal(document.body.dataset.hdrEnhanced, undefined);
assert.equal(document.body.dataset.hdrMedia, undefined);
});
test('readScriptOptions maps script data attributes into plugin options', () => {
const options = HDREnhancer.readScriptOptions({
dataset: {
hdrIntensity: '1.35',
hdrAnimated: 'false',
hdrOverlay: 'true',
hdrScanlines: 'false',
hdrBadge: 'false',
hdrEffects: 'true',
hdrEffect: 'cosmic-fireworks',
hdrQuality: 'high',
hdrFps: '48',
hdrMaxDpr: '1.5',
hdrMotion: 'ambient',
hdrMedia: 'true',
hdrBlackout: 'true',
hdrVideoSrc: '/media/custom-hdr.mp4',
hdrWebmSrc: '/media/custom-hdr.webm',
hdrImageSrc: '/media/custom-hdr.png',
hdrMediaType: 'image',
hdrText: 'true',
hdrTextBoost: '2.65',
hdrTextSrc: '/media/custom-text-hdr.png'
},
src: 'https://cdn.example.com/dist/hdr-web-plugin.js'
});
assert.deepEqual(options, {
intensity: 1.35,
animated: false,
overlay: true,
scanlines: false,
badge: false,
effects: true,
effect: 'cosmic-fireworks',
quality: 'high',
fps: 48,
maxDpr: 1.5,
motion: 'ambient',
media: true,
blackout: true,
videoSrc: '/media/custom-hdr.mp4',
webmSrc: '/media/custom-hdr.webm',
imageSrc: '/media/custom-hdr.png',
mediaType: 'image',
text: true,
textBoost: 2.65,
textSrc: '/media/custom-text-hdr.png',
assetBase: 'https://cdn.example.com/'
});
});
test('plugin exposes stable metadata for script tag consumers', () => {
assert.equal(HDREnhancer.pluginName, 'HDR Web Plugin');
assert.match(HDREnhancer.version, /^\d+\.\d+\.\d+$/);
assert.equal(typeof HDREnhancer.install, 'function');
});
test('dist plugin entry exports the same public API', () => {
const DistHDREnhancer = require('../dist/hdr-web-plugin.js');
assert.equal(DistHDREnhancer.pluginName, HDREnhancer.pluginName);
assert.equal(DistHDREnhancer.version, HDREnhancer.version);
assert.equal(typeof DistHDREnhancer.enhance, 'function');
assert.equal(typeof DistHDREnhancer.disable, 'function');
});
test('createEffectConfig enables cosmic fireworks with reduced-motion fallback', () => {
const active = HDREnhancer.createEffectConfig({
intensity: 1.5,
effect: 'cosmic-fireworks',
effects: true,
motion: 'ambient'
}, {
prefersReducedMotion: false,
colorGamut: 'p3'
});
const reduced = HDREnhancer.createEffectConfig({
intensity: 1.5,
effect: 'cosmic-fireworks',
effects: true
}, {
prefersReducedMotion: true,
colorGamut: 'p3'
});
assert.equal(active.enabled, true);
assert.equal(active.effect, 'cosmic-fireworks');
assert.equal(active.fireworkBursts, true);
assert.equal(active.galaxy, true);
assert.equal(active.motionScale, 1);
assert.equal(reduced.motionScale, 0.18);
});
test('createEffectConfig defaults to a static low-power budget', () => {
const config = HDREnhancer.createEffectConfig({
intensity: 1.55,
effect: 'cosmic-fireworks',
effects: true
}, {
prefersReducedMotion: false,
colorGamut: 'p3'
});
assert.equal(config.quality, 'low');
assert.equal(config.motion, 'static');
assert.equal(config.shouldAnimate, false);
assert.equal(config.targetFps <= 1, true);
assert.equal(config.dprCap, 1);
assert.equal(config.starCount <= 50, true);
assert.equal(config.galaxyCount <= 58, true);
assert.equal(config.burstParticleCount, 0);
assert.equal(config.maxSparks, 0);
});
test('createEffectConfig requires explicit ambient motion for continuous animation', () => {
const config = HDREnhancer.createEffectConfig({
intensity: 1.55,
effect: 'cosmic-fireworks',
effects: true,
quality: 'balanced',
motion: 'ambient'
}, {
prefersReducedMotion: false,
colorGamut: 'p3'
});
assert.equal(config.quality, 'balanced');
assert.equal(config.motion, 'ambient');
assert.equal(config.shouldAnimate, true);
assert.equal(config.targetFps <= 24, true);
assert.equal(config.dprCap <= 1.15, true);
assert.equal(config.maxSparks <= 90, true);
});