1
0

carosel images
All checks were successful
Test / test (push) Successful in 9m32s

This commit is contained in:
Aiden
2026-06-10 15:12:25 +10:00
parent c28386ccdd
commit 857c9ac980
14 changed files with 466 additions and 21 deletions

View File

@@ -2,6 +2,7 @@ import test from 'node:test';
import assert from 'node:assert/strict';
import {
createMediaAdapter,
ImageCarouselMediaAdapter,
ImageMediaAdapter,
VideoMediaAdapter
} from '../vr180player/media/media-adapter.js';
@@ -59,11 +60,20 @@ function createImage({
classList: createClassList(),
complete,
currentSrc: source,
listeners: {},
naturalWidth,
src: source,
style: { display: '' },
tagName: 'IMG',
addEventListener() {},
addEventListener(type, listener) {
this.listeners[type] ??= [];
this.listeners[type].push(listener);
},
dispatch(type) {
for (const listener of this.listeners[type] ?? []) {
listener({ currentTarget: this });
}
},
getAttribute(name) {
if (name === 'title') return title;
if (name === 'alt') return alt;
@@ -78,7 +88,9 @@ test('VideoMediaAdapter exposes video capabilities and lifecycle helpers', () =>
assert.deepEqual(adapter.capabilities, {
audio: true,
carousel: false,
dynamicTexture: true,
navigation: true,
playback: true,
timeline: true
});
@@ -127,7 +139,9 @@ test('ImageMediaAdapter exposes static image capabilities and lifecycle helpers'
assert.deepEqual(adapter.capabilities, {
audio: false,
carousel: false,
dynamicTexture: false,
navigation: false,
playback: false,
timeline: false
});
@@ -151,6 +165,82 @@ test('ImageMediaAdapter falls back to source filename', () => {
assert.equal(adapter.getTitle(), 'static sbs demo');
});
test('ImageCarouselMediaAdapter exposes carousel image navigation', () => {
const firstImage = createImage({ title: 'First image', source: 'https://cdn.example.com/media/first.png' });
const secondImage = createImage({ title: 'Second image', source: 'https://cdn.example.com/media/second.png' });
const adapter = new ImageCarouselMediaAdapter([firstImage, secondImage]);
assert.deepEqual(adapter.capabilities, {
audio: false,
carousel: true,
dynamicTexture: false,
navigation: true,
playback: false,
timeline: false
});
assert.equal(adapter.element, firstImage);
assert.equal(adapter.textureSource, firstImage);
assert.equal(adapter.getTitle(), 'First image');
assert.equal(firstImage.style.display, '');
assert.equal(secondImage.style.display, 'none');
assert.deepEqual(firstImage.classList.values, ['vrwp-media', 'vrwp-image', 'vrwp-carousel-image']);
assert.deepEqual(secondImage.classList.values, ['vrwp-media', 'vrwp-image', 'vrwp-carousel-image']);
assert.equal(adapter.next(), true);
assert.equal(adapter.element, secondImage);
assert.equal(adapter.textureSource, secondImage);
assert.equal(adapter.getTitle(), 'Second image');
assert.equal(firstImage.style.display, 'none');
assert.equal(secondImage.style.display, '');
assert.equal(adapter.next(), true);
assert.equal(adapter.element, firstImage);
adapter.hideElement();
assert.equal(firstImage.style.display, 'none');
assert.equal(secondImage.style.display, 'none');
adapter.previous();
adapter.showElement();
assert.equal(adapter.element, secondImage);
assert.equal(firstImage.style.display, 'none');
assert.equal(secondImage.style.display, '');
adapter.load();
assert.equal(firstImage.loading, 'eager');
assert.equal(secondImage.loading, 'eager');
});
test('ImageCarouselMediaAdapter waits for all images before reporting ready', async () => {
const firstImage = createImage({ complete: false, naturalWidth: 0 });
const secondImage = createImage({ complete: false, naturalWidth: 0 });
const adapter = new ImageCarouselMediaAdapter([firstImage, secondImage]);
let readyCount = 0;
adapter.bindLoadState({
onError: () => {},
onReady: () => {
readyCount += 1;
}
});
await new Promise((resolve) => setImmediate(resolve));
assert.equal(readyCount, 0);
firstImage.complete = true;
firstImage.naturalWidth = 1920;
firstImage.dispatch('load');
assert.equal(readyCount, 0);
secondImage.complete = true;
secondImage.naturalWidth = 1920;
secondImage.dispatch('load');
assert.equal(readyCount, 1);
firstImage.dispatch('load');
assert.equal(readyCount, 1);
});
test('createMediaAdapter finds and marks the supported video element', () => {
const video = createVideo();
const playerContainer = {
@@ -181,10 +271,32 @@ test('createMediaAdapter finds and marks the supported image element', () => {
assert.deepEqual(image.classList.values, ['vrwp-media', 'vrwp-image']);
});
test('createMediaAdapter creates an image carousel when requested', () => {
const firstImage = createImage({ title: 'First image' });
const secondImage = createImage({ title: 'Second image' });
const playerContainer = {
dataset: { carousel: '' },
querySelectorAll(selector) {
return selector === 'video,img' ? [firstImage, secondImage] : [];
}
};
const adapter = createMediaAdapter(playerContainer);
assert.ok(adapter instanceof ImageCarouselMediaAdapter);
assert.equal(adapter.element, firstImage);
assert.equal(adapter.next(), true);
assert.equal(adapter.element, secondImage);
});
test('createMediaAdapter refuses missing or ambiguous media elements', () => {
const video = createVideo();
const image = createImage();
const secondImage = createImage();
assert.equal(createMediaAdapter({ querySelectorAll: () => [] }), null);
assert.equal(createMediaAdapter({ querySelectorAll: () => [video, image] }), null);
assert.equal(createMediaAdapter({ querySelectorAll: () => [image, secondImage] }), null);
assert.equal(createMediaAdapter({ dataset: { carousel: '' }, querySelectorAll: () => [image] }), null);
assert.equal(createMediaAdapter({ dataset: { carousel: '' }, querySelectorAll: () => [video, image] }), null);
});

View File

@@ -53,6 +53,24 @@ test('MediaTextureManager assigns and clears material maps', () => {
assert.equal(manager.current, null);
});
test('MediaTextureManager can switch sources before creating the next texture', () => {
const firstSource = { name: 'first' };
const secondSource = { name: 'second' };
const createdFrom = [];
const manager = new MediaTextureManager(firstSource, (source) => {
createdFrom.push(source);
return createTexture(source.name);
}, () => true);
const firstTexture = manager.create();
manager.setSource(secondSource);
const secondTexture = manager.create();
assert.equal(firstTexture.disposed, true);
assert.equal(secondTexture.name, 'second');
assert.deepEqual(createdFrom, [firstSource, secondSource]);
});
test('MediaTextureManager only marks textures dirty when the update predicate allows it', () => {
const video = createVideo();
const manager = new MediaTextureManager(