(html`
${scrollerHtml('dis66', 6)}
`);
const minimap = wrapper.querySelector('nile-minimap') as NileMinimap;
await settle(minimap);
expect(part(minimap, 'viewport')!.getAttribute('aria-disabled')).to.equal('true');
});
it('67. disabled makes the viewport non-focusable (tabindex -1)', async () => {
const wrapper = await fixture(html`
${scrollerHtml('dis67', 6)}
`);
const minimap = wrapper.querySelector('nile-minimap') as NileMinimap;
await settle(minimap);
expect(part(minimap, 'viewport')!.getAttribute('tabindex')).to.equal('-1');
});
it('68. disabled still mirrors container scrolling', async () => {
const wrapper = await fixture(html`
${scrollerHtml('dis68', 6)}
`);
const minimap = wrapper.querySelector('nile-minimap') as NileMinimap;
const scroller = wrapper.querySelector('#dis68') as HTMLElement;
await settle(minimap);
scroller.scrollLeft = scroller.scrollWidth - scroller.clientWidth;
scroller.dispatchEvent(new Event('scroll'));
await settle(minimap);
expect(Number(part(minimap, 'viewport')!.getAttribute('aria-valuenow'))).to.be.greaterThan(0);
});
it('69. disabled viewport does not scroll the container on click', async () => {
const wrapper = await fixture(html`
${scrollerHtml('dis69', 6)}
`);
const minimap = wrapper.querySelector('nile-minimap') as NileMinimap;
const scroller = wrapper.querySelector('#dis69') as HTMLElement;
await settle(minimap);
scroller.scrollLeft = 0;
await settle(minimap);
const track = part(minimap, 'track')!;
const rect = track.getBoundingClientRect();
track.dispatchEvent(
new MouseEvent('click', {
bubbles: true,
composed: true,
clientX: rect.left + rect.width * 0.9,
clientY: rect.top + rect.height / 2,
})
);
await settle(minimap);
expect(scroller.scrollLeft).to.equal(0);
});
// === DISCONNECT ===
it('70. releases listeners on disconnect (scroll after removal does not update)', async () => {
const { minimap, scroller, wrapper } = await docFixture('dc70');
await settle(minimap);
const vpBefore = part(minimap, 'viewport')!.getAttribute('aria-valuenow');
minimap.remove();
expect(() => {
scroller.scrollLeft = scroller.scrollWidth - scroller.clientWidth;
scroller.dispatchEvent(new Event('scroll'));
}).to.not.throw();
await aTimeout(16);
// detached minimap's reported value should not have moved
expect(part(minimap, 'viewport')!.getAttribute('aria-valuenow')).to.equal(vpBefore);
wrapper.remove();
});
it('71. disconnecting and reconnecting does not throw', async () => {
const { minimap, wrapper } = await docFixture('dc71');
const parent = minimap.parentElement!;
minimap.remove();
parent.appendChild(minimap);
await settle(minimap);
expect(minimap.shadowRoot).to.exist;
wrapper.remove();
});
// === DYNAMIC PROPERTY UPDATES ===
it('72. switching mode to track updates rendering', async () => {
const { minimap } = await docFixture('dp72', { count: 6 });
expect(minimap.shadowRoot!.querySelectorAll('[part~="segment"]').length).to.equal(6);
minimap.mode = 'track';
await settle(minimap);
expect(minimap.mode).to.equal('track');
});
it('73. is an instance of NileMinimap with the right constructor', async () => {
const { minimap } = await docFixture('dp73');
expect(minimap.constructor.name).to.contain('Minimap');
});
it('74. has static styles defined', async () => {
const ctor = customElements.get('nile-minimap') as unknown as { styles?: unknown };
expect(ctor.styles).to.exist;
});
// === AUTO-HIDE ===
const isIdle = (el: NileMinimap) => el.hasAttribute('data-idle');
const baseOpacity = (el: NileMinimap) => getComputedStyle(part(el, 'base')!).opacity;
const wait = (ms: number) => new Promise((r) => setTimeout(r, ms));
async function autoHideFixture(id: string, hideDelay = 60) {
const f = await docFixture(id);
f.minimap.hideDelay = hideDelay;
f.minimap.autoHide = true;
await settle(f.minimap);
return f;
}
it('75. autoHide defaults to false and hideDelay to 1200', async () => {
const { minimap } = await docFixture('ah75');
expect(minimap.autoHide).to.be.false;
expect(minimap.hideDelay).to.equal(1200);
expect(isIdle(minimap)).to.be.false;
});
it('76. autoHide reflects and starts hidden (opacity 0, no pointer events) but keeps its size', async () => {
const { minimap } = await autoHideFixture('ah76');
expect(minimap.hasAttribute('autohide')).to.be.true;
expect(isIdle(minimap)).to.be.true;
await wait(200); // let the fade transition finish
expect(baseOpacity(minimap)).to.equal('0');
expect(getComputedStyle(part(minimap, 'base')!).pointerEvents).to.equal('none');
expect(minimap.getBoundingClientRect().width).to.be.greaterThan(0);
});
it('77. scrolling the container reveals it, then it hides after hideDelay', async () => {
const { minimap, scroller } = await autoHideFixture('ah77');
scroller.scrollLeft = 120;
scroller.dispatchEvent(new Event('scroll'));
expect(isIdle(minimap)).to.be.false;
await wait(20);
expect(isIdle(minimap)).to.be.false;
await wait(120);
expect(isIdle(minimap)).to.be.true;
});
it('78. each scroll restarts the countdown', async () => {
const { minimap, scroller } = await autoHideFixture('ah78', 100);
scroller.dispatchEvent(new Event('scroll'));
await wait(70);
scroller.dispatchEvent(new Event('scroll'));
await wait(70);
expect(isIdle(minimap)).to.be.false;
await wait(80);
expect(isIdle(minimap)).to.be.true;
});
it('79. stays visible while hovered and hides after the pointer leaves', async () => {
const { minimap, scroller } = await autoHideFixture('ah79');
scroller.dispatchEvent(new Event('scroll'));
minimap.dispatchEvent(new PointerEvent('pointerenter'));
await wait(150);
expect(isIdle(minimap)).to.be.false;
minimap.dispatchEvent(new PointerEvent('pointerleave'));
await wait(150);
expect(isIdle(minimap)).to.be.true;
});
it('80. keyboard focus reveals it and keeps it visible until blur', async () => {
const { minimap } = await autoHideFixture('ah80');
expect(isIdle(minimap)).to.be.true;
part(minimap, 'viewport')!.focus();
expect(isIdle(minimap)).to.be.false;
await wait(150);
expect(isIdle(minimap)).to.be.false;
part(minimap, 'viewport')!.blur();
await wait(150);
expect(isIdle(minimap)).to.be.true;
});
it('81. turning autoHide off shows it immediately and stops hiding', async () => {
const { minimap, scroller } = await autoHideFixture('ah81');
expect(isIdle(minimap)).to.be.true;
minimap.autoHide = false;
await settle(minimap);
expect(isIdle(minimap)).to.be.false;
scroller.dispatchEvent(new Event('scroll'));
await wait(150);
expect(isIdle(minimap)).to.be.false;
});
});