mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-14 01:22:27 +03:00
TrinsicObserver with tests
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { createDOM } from 'support/dom';
|
import { createDOM } from 'support/dom';
|
||||||
import { getEnvironment } from 'environment';
|
import { getEnvironment } from 'environment';
|
||||||
import { createSizeObserver } from 'overlayscrollbars/observers/SizeObserver';
|
import { createSizeObserver } from 'overlayscrollbars/observers/SizeObserver';
|
||||||
|
import { createTrinsicObserver } from 'overlayscrollbars/observers/TrinsicObserver';
|
||||||
|
|
||||||
const abc = {
|
const abc = {
|
||||||
a: 1,
|
a: 1,
|
||||||
@@ -12,6 +13,7 @@ export default () => {
|
|||||||
return [
|
return [
|
||||||
getEnvironment(),
|
getEnvironment(),
|
||||||
createSizeObserver(document.body, () => {}),
|
createSizeObserver(document.body, () => {}),
|
||||||
|
createTrinsicObserver(document.body, () => {}),
|
||||||
createDOM(
|
createDOM(
|
||||||
'\
|
'\
|
||||||
<div class="os-host">\
|
<div class="os-host">\
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@import './sizeobserver.scss';
|
@import './sizeobserver.scss';
|
||||||
|
@import './trinsicobserver.scss';
|
||||||
|
|
||||||
#os-environment {
|
#os-environment {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export const createSizeObserver = (
|
|||||||
onSizeChangedCallback(dir === true);
|
onSizeChangedCallback(dir === true);
|
||||||
};
|
};
|
||||||
const offListeners: (() => void)[] = [];
|
const offListeners: (() => void)[] = [];
|
||||||
let appearCallback: (...args: any) => any = onSizeChangedCallbackProxy;
|
let appearCallback: ((...args: any) => any) | null = appear ? onSizeChangedCallbackProxy : null;
|
||||||
|
|
||||||
if (ResizeObserverConstructor) {
|
if (ResizeObserverConstructor) {
|
||||||
const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
|
const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
|
||||||
@@ -81,7 +81,9 @@ export const createSizeObserver = (
|
|||||||
};
|
};
|
||||||
const onResized = function () {
|
const onResized = function () {
|
||||||
rAFId = 0;
|
rAFId = 0;
|
||||||
if (!isDirty) return;
|
if (!isDirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cacheSize = currSize;
|
cacheSize = currSize;
|
||||||
onSizeChangedCallbackProxy();
|
onSizeChangedCallbackProxy();
|
||||||
@@ -114,7 +116,7 @@ export const createSizeObserver = (
|
|||||||
height: scrollAmount,
|
height: scrollAmount,
|
||||||
});
|
});
|
||||||
reset();
|
reset();
|
||||||
appearCallback = onScroll;
|
appearCallback = appear ? onScroll : reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direction) {
|
if (direction) {
|
||||||
@@ -140,7 +142,8 @@ export const createSizeObserver = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appear) {
|
// appearCallback is always needed on scroll-observer strategy to reset it
|
||||||
|
if (appearCallback) {
|
||||||
addClass(sizeObserver, classNameSizeObserverAppear);
|
addClass(sizeObserver, classNameSizeObserverAppear);
|
||||||
offListeners.push(on(sizeObserver, animationStartEventName, appearCallback));
|
offListeners.push(on(sizeObserver, animationStartEventName, appearCallback));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export const createTrinsicObserver = (
|
|||||||
createSizeObserver(trinsicObserver, () => {
|
createSizeObserver(trinsicObserver, () => {
|
||||||
const newSize = offsetSize(trinsicObserver);
|
const newSize = offsetSize(trinsicObserver);
|
||||||
const newHeightIntrinsic = newSize.h === 0;
|
const newHeightIntrinsic = newSize.h === 0;
|
||||||
|
|
||||||
if (newHeightIntrinsic !== heightIntrinsic) {
|
if (newHeightIntrinsic !== heightIntrinsic) {
|
||||||
onTrinsicChangedCallback(false, newSize.h === 0);
|
onTrinsicChangedCallback(false, newSize.h === 0);
|
||||||
heightIntrinsic = newHeightIntrinsic;
|
heightIntrinsic = newHeightIntrinsic;
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any)
|
|||||||
|
|
||||||
if (dimensions && (offsetSizeChanged || dirChanged)) {
|
if (dimensions && (offsetSizeChanged || dirChanged)) {
|
||||||
await waitFor(
|
await waitFor(
|
||||||
async () => {
|
() => {
|
||||||
if (offsetSizeChanged) {
|
if (offsetSizeChanged) {
|
||||||
should.equal(sizeIterations, currSizeIterations + 1);
|
should.equal(sizeIterations, currSizeIterations + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import 'overlayscrollbars.scss';
|
||||||
|
import './index.scss';
|
||||||
|
import should from 'should';
|
||||||
|
import { waitFor } from '@testing-library/dom';
|
||||||
|
import { generateSelectCallback, iterateSelect, selectOption } from '@/testing-browser/Select';
|
||||||
|
import { timeout } from '@/testing-browser/timeout';
|
||||||
|
import { setTestResult } from '@/testing-browser/TestResult';
|
||||||
|
import { offsetSize } from 'support';
|
||||||
|
|
||||||
|
import { createTrinsicObserver } from 'overlayscrollbars/observers/TrinsicObserver';
|
||||||
|
|
||||||
|
const waitForOptions = {
|
||||||
|
onTimeout(error: Error): Error {
|
||||||
|
setTestResult(false);
|
||||||
|
return error;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let heightIterations = 0;
|
||||||
|
let heightIntrinsicCache: boolean;
|
||||||
|
const envElm = document.querySelector('#env');
|
||||||
|
const targetElm = document.querySelector('#target');
|
||||||
|
const checkElm = document.querySelector('#check');
|
||||||
|
const envHeightSelect: HTMLSelectElement | null = document.querySelector('#envHeight');
|
||||||
|
const targetHeightSelect: HTMLSelectElement | null = document.querySelector('#targetHeight');
|
||||||
|
const displaySelect: HTMLSelectElement | null = document.querySelector('#display');
|
||||||
|
const startBtn: HTMLButtonElement | null = document.querySelector('#start');
|
||||||
|
const changesSlot: HTMLButtonElement | null = document.querySelector('#changes');
|
||||||
|
|
||||||
|
const envElmSelectCallback = generateSelectCallback(envElm as HTMLElement);
|
||||||
|
const targetElmSelectCallback = generateSelectCallback(targetElm as HTMLElement);
|
||||||
|
|
||||||
|
envHeightSelect?.addEventListener('change', envElmSelectCallback);
|
||||||
|
targetHeightSelect?.addEventListener('change', targetElmSelectCallback);
|
||||||
|
displaySelect?.addEventListener('change', targetElmSelectCallback);
|
||||||
|
|
||||||
|
envElmSelectCallback(envHeightSelect);
|
||||||
|
targetElmSelectCallback(targetHeightSelect);
|
||||||
|
targetElmSelectCallback(displaySelect);
|
||||||
|
|
||||||
|
const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any) => {
|
||||||
|
interface IterateSelect {
|
||||||
|
currHeightIterations: number;
|
||||||
|
currHeightIntrinsic: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
await iterateSelect<IterateSelect>(select, {
|
||||||
|
beforeEach() {
|
||||||
|
const currHeightIterations = heightIterations;
|
||||||
|
const currHeightIntrinsic = offsetSize(checkElm as HTMLElement).h === 0;
|
||||||
|
return {
|
||||||
|
currHeightIterations,
|
||||||
|
currHeightIntrinsic,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async check({ currHeightIterations, currHeightIntrinsic }) {
|
||||||
|
const newHeightIntrinsic = offsetSize(checkElm as HTMLElement).h === 0;
|
||||||
|
const trinsicHeightChanged = newHeightIntrinsic !== currHeightIntrinsic;
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
if (trinsicHeightChanged) {
|
||||||
|
should.equal(heightIterations, currHeightIterations + 1);
|
||||||
|
}
|
||||||
|
}, waitForOptions);
|
||||||
|
},
|
||||||
|
afterEach,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const iterateEnvHeight = async (afterEach?: () => any) => {
|
||||||
|
await iterate(envHeightSelect, afterEach);
|
||||||
|
};
|
||||||
|
const iterateTargetHeight = async (afterEach?: () => any) => {
|
||||||
|
await iterate(targetHeightSelect, afterEach);
|
||||||
|
};
|
||||||
|
const changeWhileHidden = async () => {
|
||||||
|
selectOption(targetHeightSelect as HTMLSelectElement, 'targetHeightHundred');
|
||||||
|
|
||||||
|
const autoToHundred = async () => {
|
||||||
|
selectOption(envHeightSelect as HTMLSelectElement, 'envHeightAuto');
|
||||||
|
selectOption(displaySelect as HTMLSelectElement, 'displayNone');
|
||||||
|
|
||||||
|
await timeout(250);
|
||||||
|
|
||||||
|
selectOption(envHeightSelect as HTMLSelectElement, 'envHeightHundred');
|
||||||
|
selectOption(displaySelect as HTMLSelectElement, 'displayBlock');
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
should.equal(heightIntrinsicCache, false);
|
||||||
|
}, waitForOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
const hundredToAuto = async () => {
|
||||||
|
selectOption(envHeightSelect as HTMLSelectElement, 'envHeightHundred');
|
||||||
|
selectOption(displaySelect as HTMLSelectElement, 'displayNone');
|
||||||
|
|
||||||
|
await timeout(250);
|
||||||
|
|
||||||
|
selectOption(envHeightSelect as HTMLSelectElement, 'envHeightAuto');
|
||||||
|
selectOption(displaySelect as HTMLSelectElement, 'displayBlock');
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
should.equal(heightIntrinsicCache, true);
|
||||||
|
}, waitForOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
await autoToHundred();
|
||||||
|
await hundredToAuto();
|
||||||
|
await autoToHundred();
|
||||||
|
await hundredToAuto();
|
||||||
|
};
|
||||||
|
|
||||||
|
const start = async () => {
|
||||||
|
setTestResult(null);
|
||||||
|
|
||||||
|
targetElm?.removeAttribute('style');
|
||||||
|
await iterateEnvHeight();
|
||||||
|
await iterateTargetHeight();
|
||||||
|
await iterateEnvHeight(async () => {
|
||||||
|
await iterateTargetHeight();
|
||||||
|
});
|
||||||
|
await changeWhileHidden();
|
||||||
|
|
||||||
|
setTestResult(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
startBtn?.addEventListener('click', start);
|
||||||
|
|
||||||
|
createTrinsicObserver(targetElm as HTMLElement, (widthIntrinsic: boolean, heightIntrinsic: boolean) => {
|
||||||
|
if (heightIntrinsic !== heightIntrinsicCache) {
|
||||||
|
heightIterations += 1;
|
||||||
|
heightIntrinsicCache = heightIntrinsic;
|
||||||
|
}
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (changesSlot) {
|
||||||
|
changesSlot.textContent = heightIterations.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export { start };
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<div id="controls">
|
||||||
|
<label for="display">display</label>
|
||||||
|
<select name="display" id="display">
|
||||||
|
<option value="displayBlock">block</option>
|
||||||
|
<option value="displayNone">none</option>
|
||||||
|
</select>
|
||||||
|
<label for="envHeight">envHeight</label>
|
||||||
|
<select name="envHeight" id="envHeight">
|
||||||
|
<option value="envHeightAuto">auto</option>
|
||||||
|
<option value="envHeightHundred">100%</option>
|
||||||
|
<option value="envHeight200">200px</option>
|
||||||
|
</select>
|
||||||
|
<label for="targetHeight">targetHeight</label>
|
||||||
|
<select name="targetHeight" id="targetHeight">
|
||||||
|
<option value="targetHeightAuto">auto</option>
|
||||||
|
<option value="targetHeightHundred">100%</option>
|
||||||
|
<option value="targetHeight200">200px</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button id="start">start</button>
|
||||||
|
<span>Detected changes: <span id="changes">0</span></span>
|
||||||
|
</div>
|
||||||
|
<div id="stage">
|
||||||
|
<div>
|
||||||
|
<div id="env">
|
||||||
|
<div id="target">
|
||||||
|
<div id="check"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
#controls {
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
#stage {
|
||||||
|
flex: auto;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background: lightgoldenrodyellow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#canvas > div {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#env {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#target {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
// prevent container from reaching 0x0 dimensions for testing purposes
|
||||||
|
min-width: 50px;
|
||||||
|
min-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#check {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.envHeightAuto,
|
||||||
|
.targetHeightAuto {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.envHeight200,
|
||||||
|
.targetHeight200 {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.envHeightHundred,
|
||||||
|
.targetHeightHundred {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayNone {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.displayBlock {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import expectPuppeteer from 'expect-puppeteer';
|
||||||
|
import url from './.build/build.html';
|
||||||
|
|
||||||
|
describe('Environment', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await page.goto(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('test', async () => {
|
||||||
|
await expectPuppeteer(page).toClick('#start');
|
||||||
|
await expectPuppeteer(page).toMatchElement('#testResult.passed', {
|
||||||
|
timeout: 60000,
|
||||||
|
});
|
||||||
|
}, 60000);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user