From e109c93ce7c95f1d05a8d210f184b30dffa955b3 Mon Sep 17 00:00:00 2001 From: Rene Haas Date: Thu, 18 Aug 2022 16:40:07 +0200 Subject: [PATCH] improve types for events, configure codecov add fast test for setup update --- .github/workflows/test.yml | 8 +- README.md | 3 +- local/browser-testing/src/select.ts | 4 +- local/playwright-tooling/index.d.ts | 2 +- packages/overlayscrollbars/README.md | 4 +- packages/overlayscrollbars/package.json | 4 +- .../src/support/eventListeners.ts | 23 ++- .../jest-jsdom/support/eventListeners.test.ts | 6 +- .../update/handleEnvironment.ts | 3 +- .../structureSetup/update/index.browser.ts | 148 ++++++++++-------- .../setups/structureSetup/update/index.html | 1 + .../structureSetup/update/index.test.ts | 39 +++-- 12 files changed, 132 insertions(+), 113 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c04f35b..6e121ef 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,12 +23,12 @@ jobs: run: npm ci --install-links - name: Run Jest run: npm run jest - - uses: codecov/codecov-action@v3 - with: - flags: unit - files: "**/jest/coverage*.json" - name: Run Playwright run: xvfb-run npm run playwright + - uses: codecov/codecov-action@v3 + with: + flags: unit + files: "**/jest/coverage*.json" - uses: codecov/codecov-action@v3 with: flags: ui diff --git a/README.md b/README.md index 6a0ec37..906fc49 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,10 @@ Downloads Version License + Code Coverage Max. Bundle Size - - > OverlayScrollbars is a javascript scrollbar plugin that hides native scrollbars, provides custom styleable overlay scrollbars and keeps the native functionality and feeling. > This is the documentation for version `2.x`. which is currently in beta. You can read the version `1.x` docs [here](https://github.com/KingSora/OverlayScrollbars/tree/v1.x) or on the [website](https://kingsora.github.io/OverlayScrollbars/#!overview). diff --git a/local/browser-testing/src/select.ts b/local/browser-testing/src/select.ts index 9360823..3fd6766 100644 --- a/local/browser-testing/src/select.ts +++ b/local/browser-testing/src/select.ts @@ -91,7 +91,9 @@ export const iterateSelect = async ( if (select) { const { beforeEach = noop, check = noop, afterEach = noop, filter } = options || {}; const selectOptions = getSelectOptions(select); - const selectOptionsReversed = getSelectOptions(select).reverse(); + const selectOptionsReversed = getSelectOptions(select) + .reverse() + .filter((_, i) => i > 0); const iterateOptions = [...selectOptions, ...selectOptionsReversed].filter( filter || (() => true) ); diff --git a/local/playwright-tooling/index.d.ts b/local/playwright-tooling/index.d.ts index 4916371..9d4dfb0 100644 --- a/local/playwright-tooling/index.d.ts +++ b/local/playwright-tooling/index.d.ts @@ -1,4 +1,4 @@ declare module '@~local/playwright-tooling' { export function playwrightRollup(): void; - export function expectSuccess(page: any): void; + export function expectSuccess(page: any): Promise; } diff --git a/packages/overlayscrollbars/README.md b/packages/overlayscrollbars/README.md index ce6afe5..906fc49 100644 --- a/packages/overlayscrollbars/README.md +++ b/packages/overlayscrollbars/README.md @@ -7,14 +7,14 @@ Downloads Version License + Code Coverage Max. Bundle Size - - > OverlayScrollbars is a javascript scrollbar plugin that hides native scrollbars, provides custom styleable overlay scrollbars and keeps the native functionality and feeling. > This is the documentation for version `2.x`. which is currently in beta. You can read the version `1.x` docs [here](https://github.com/KingSora/OverlayScrollbars/tree/v1.x) or on the [website](https://kingsora.github.io/OverlayScrollbars/#!overview). + ## Why I've created this plugin because I hate ugly and space consuming scrollbars. Similar plugins haven't met my requirements in terms of features, quality, simplicity, license or browser support. diff --git a/packages/overlayscrollbars/package.json b/packages/overlayscrollbars/package.json index bc60ec6..7896d9d 100644 --- a/packages/overlayscrollbars/package.json +++ b/packages/overlayscrollbars/package.json @@ -42,11 +42,11 @@ "sideEffects": ["*.css", "*.scss", "*.sass"], "scripts": { "build": "rollup -c", - "test": "jest --coverage && playwright test", + "test": "jest --coverage && playwright test --grep-invert @special", "jest": "jest --coverage --testPathPattern", "jest:node": "jest --selectProjects node --testPathPattern", "jest:jsdom": "jest --selectProjects jsdom --testPathPattern", - "playwright": "playwright test", + "playwright": "playwright test --grep-invert @special", "playwright:dev": "playwright test --workers 1 --timeout 0 --global-timeout 0", "posttest": "playwright-merge-coverage && full-coverage", "postjest": "full-coverage", diff --git a/packages/overlayscrollbars/src/support/eventListeners.ts b/packages/overlayscrollbars/src/support/eventListeners.ts index fb7ad8b..e410fdf 100644 --- a/packages/overlayscrollbars/src/support/eventListeners.ts +++ b/packages/overlayscrollbars/src/support/eventListeners.ts @@ -2,18 +2,17 @@ import { isArray } from 'support/utils/types'; import { keys } from 'support/utils/object'; import { each, from, isEmptyArray } from 'support/utils/array'; -export type EventListener< - EventMap extends Record, - N extends keyof EventMap = keyof EventMap -> = (...args: EventMap[N]) => void; +export type EventListener, N extends keyof EventMap> = ( + ...args: EventMap[N] +) => void; export type InitialEventListeners> = { - [K in keyof EventMap]?: EventListener | EventListener[]; + [K in keyof EventMap]?: EventListener | EventListener[]; }; -const manageListener = >( - callback: (listener?: EventListener) => void, - listener?: EventListener | EventListener[] +const manageListener = , N extends keyof EventMap>( + callback: (listener?: EventListener) => void, + listener?: EventListener | EventListener[] ) => { each(isArray(listener) ? listener : [listener], callback); }; @@ -22,7 +21,7 @@ export const createEventListenerHub = >( initialEventListeners?: InitialEventListeners ) => { // eslint-disable-next-line @typescript-eslint/no-shadow - type EventListener = (...args: EventMap[N]) => void; + type EventListener = (...args: EventMap[N]) => void; type RemoveEvent = { (name?: N, listener?: EventListener): void; (name?: N, listener?: EventListener[]): void; @@ -40,7 +39,7 @@ export const createEventListenerHub = >( (name: N, args?: EventMap[N]): void; }; - const events = new Map>(); + const events = new Map>>(); const removeEvent: RemoveEvent = ( name?: N, @@ -50,9 +49,9 @@ export const createEventListenerHub = >( const eventSet = events.get(name); manageListener((currListener) => { if (eventSet) { - eventSet[currListener ? 'delete' : 'clear'](currListener!); + eventSet[currListener ? 'delete' : 'clear'](currListener! as any); } - }, listener as any); + }, listener); } else { events.forEach((eventSet) => { eventSet.clear(); diff --git a/packages/overlayscrollbars/tests/jest-jsdom/support/eventListeners.test.ts b/packages/overlayscrollbars/tests/jest-jsdom/support/eventListeners.test.ts index b6ec75e..2b45502 100644 --- a/packages/overlayscrollbars/tests/jest-jsdom/support/eventListeners.test.ts +++ b/packages/overlayscrollbars/tests/jest-jsdom/support/eventListeners.test.ts @@ -1,14 +1,14 @@ import { createEventListenerHub } from 'support/eventListeners'; type EventMap = { - onBoolean: [boolean, string]; + onBoolean: [a: boolean, b: string]; onUndefined: []; }; describe('eventListeners', () => { describe('createEventListenerHub', () => { test('initialization', () => { - const onBooleanA = jest.fn(); + const onBooleanA = jest.fn((a: boolean, b: string) => a + b); const onBooleanB = jest.fn(); const onUndefined = jest.fn(); const [, , triggerEvent] = createEventListenerHub({ @@ -28,7 +28,7 @@ describe('eventListeners', () => { }); test('addEvent', () => { - const onBooleanA = jest.fn(); + const onBooleanA = jest.fn((a: boolean, b: string) => a + b); const onBooleanB = jest.fn(); const onUndefinedA = jest.fn(); const onUndefinedB = jest.fn(); diff --git a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/handleEnvironment.ts b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/handleEnvironment.ts index 607f6fe..c656a31 100644 --- a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/handleEnvironment.ts +++ b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/handleEnvironment.ts @@ -6,6 +6,7 @@ import { addClass } from 'support'; const params = url.searchParams; /** + * fast: faster but not so accurate run * nsh: native scrollbar hiding * fbg: flexbox glue * ccp: css custom props @@ -14,7 +15,7 @@ import { addClass } from 'support'; * vpt: viewport is target * pa: padding absolute */ - ['nsh', 'fbg', 'ccp', 'po', 'fo', 'vpt', 'pa'].forEach((param) => { + ['fast', 'nsh', 'fbg', 'ccp', 'po', 'fo', 'vpt', 'pa'].forEach((param) => { const paramValue = Boolean(params.get(param)); if (paramValue) { diff --git a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.browser.ts b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.browser.ts index c246a02..a2b6896 100644 --- a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.browser.ts +++ b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.browser.ts @@ -27,6 +27,8 @@ import { createDOM, hasClass, createDiv, + removeElements, + removeClass, } from 'support'; import { Options } from 'options'; import { DeepPartial } from 'typings'; @@ -77,7 +79,6 @@ interface Metrics { height: number; }; } - interface CheckComparisonObj { updCount: number; metrics: Metrics; @@ -102,7 +103,8 @@ const msedge = window.navigator.userAgent.toLowerCase().indexOf('edge') > -1; msie11 && addClass(document.body, 'msie11'); -const paddingAbsolute = hasClass(document.body, 'pa'); +const initialPaddingAbsolute = hasClass(document.body, 'pa'); +const isFastTestRun = hasClass(document.body, 'fast'); const useContentElement = false; const fixedDigits = msie11 ? 1 : 3; const fixedDigitsOffset = 3; @@ -122,6 +124,8 @@ const targetOptionsSlot: HTMLElement | null = document.querySelector('#options') const targetUpdatesSlot: HTMLElement | null = document.querySelector('#updates'); const comparisonContentElm: HTMLElement = document.createElement('div'); const envElms = document.querySelectorAll('.env'); +const getComparisonViewport = () => + (comparison?.querySelector(`.${classNameViewport}`) || comparison) as HTMLElement; const initObj = hasClass(document.body, 'vpt') ? { @@ -146,19 +150,37 @@ const osInstance = (window.os = OverlayScrollbars( initObj, { - paddingAbsolute, + paddingAbsolute: initialPaddingAbsolute, }, { - updated() { + updated(instance) { updateCount++; + const { paddingAbsolute, overflow } = instance.options(); + const comparisonViewport = getComparisonViewport(); + + if (paddingAbsolute) { + if (comparisonViewport === comparison) { + addClass(document.body, 'pa'); + const absoluteWrapper = createDiv(classNameViewport); + appendChildren(absoluteWrapper, contents(comparison)); + + appendChildren(comparison, absoluteWrapper); + } + } else if (comparisonViewport !== comparison) { + removeClass(document.body, 'pa'); + appendChildren(comparison, contents(comparisonViewport)); + removeElements(comparisonViewport); + } + requestAnimationFrame(() => { if (targetUpdatesSlot) { targetUpdatesSlot.textContent = `${updateCount}`; } if (targetOptionsSlot) { targetOptionsSlot.textContent = JSON.stringify( - assignDeep({}, osInstance.options().overflow, { - paddingAbsolute: osInstance.options().paddingAbsolute, + assignDeep({}, overflow, { + paddingAbsolute, + viewportIsTarget: instance.elements().viewport === target, }), null, 2 @@ -169,8 +191,6 @@ const osInstance = } )); -const getComparisonViewport = () => - paddingAbsolute ? (comparison!.firstElementChild as HTMLElement) : comparison; const getMetrics = (elm: HTMLElement): Metrics => { // const rounding = isFractionalPixelRatio() ? Math.round : (num: number) => num; const elmIsTarget = elm === target; @@ -185,7 +205,6 @@ const getMetrics = (elm: HTMLElement): Metrics => { width: Math.max(0, comparisonViewport!.scrollWidth - comparisonViewport!.clientWidth), height: Math.max(0, comparisonViewport!.scrollHeight - comparisonViewport!.clientHeight), }; - console.log(elm, amount, comparisonViewport); return { width: condition(amount.width) ? amount.width : 0, height: condition(amount.height) ? amount.height : 0, @@ -348,8 +367,6 @@ const checkMetrics = async (checkComparison: CheckComparisonObj) => { const scrollWidth = targetMetrics.scroll.width - comparisonMetrics.scroll.width; const scrollHeight = targetMetrics.scroll.height - comparisonMetrics.scroll.height; if (scrollWidth !== 0 || scrollHeight !== 0) { - console.log(scrollWidth); - console.log(scrollHeight); roundingElm!.textContent = `${(parseInt(roundingElm!.textContent || '0', 10) || 0) + 1}`; } } else { @@ -550,10 +567,10 @@ const checkMetrics = async (checkComparison: CheckComparisonObj) => { const iterate = async ( select: HTMLSelectElement | null, afterEach?: () => any, - skippedItems?: string[] + skippedItems?: string[] | false | null ) => { await iterateSelect(select, { - filter: (item: string) => !skippedItems?.includes(item), + filter: skippedItems ? (item: string) => !skippedItems?.includes(item) : undefined, beforeEach() { const metrics = getMetrics(comparison!); return { @@ -575,10 +592,10 @@ const iterateEnvHeight = async (afterEach?: () => any) => { await iterate(envHeightSelect, afterEach); }; */ -const iterateHeight = async (afterEach?: () => any, skippedItems?: string[]) => { +const iterateHeight = async (afterEach?: () => any, skippedItems?: string[] | false | null) => { await iterate(containerHeightSelect, afterEach, skippedItems); }; -const iterateWidth = async (afterEach?: () => any, skippedItems?: string[]) => { +const iterateWidth = async (afterEach?: () => any, skippedItems?: string[] | false | null) => { await iterate(containerWidthSelect, afterEach, skippedItems); }; /* @@ -586,10 +603,10 @@ const iterateFloat = async (afterEach?: () => any) => { await iterate(containerFloatSelect, afterEach); }; */ -const iteratePadding = async (afterEach?: () => any, skippedItems?: string[]) => { +const iteratePadding = async (afterEach?: () => any, skippedItems?: string[] | false | null) => { await iterate(containerPaddingSelect, afterEach, skippedItems); }; -const iterateBorder = async (afterEach?: () => any, skippedItems?: string[]) => { +const iterateBorder = async (afterEach?: () => any, skippedItems?: string[] | false | null) => { await iterate(containerBorderSelect, afterEach, skippedItems); }; /* @@ -765,45 +782,34 @@ const overflowTest = async (osOptions?: DeepPartial) => { removeAttr(comparisonEnd, 'style'); }; + const withSkippedItems = osOptions || isFastTestRun; + if (osOptions) { osInstance.options(osOptions); - - await iterateMinMax(async () => { - await iterateBoxSizing(async () => { - await iterateHeight(async () => { - await iterateWidth(async () => { - await iterateBorder(async () => { - await iteratePadding(async () => { - await iterateOverflow(); - }, ['paddingLarge']); - }, ['borderSmall']); - }, ['widthHundred']); - }, ['heightHundred']); - }); - }); - } else { - await iterateMinMax(async () => { - await iterateBoxSizing(async () => { - await iterateHeight(async () => { - await iterateWidth(async () => { - await iterateBorder(async () => { - // assume this part isn't critical - /* - await iterateFloat(async () => { - await iterateMargin(); - }); - */ - - await iteratePadding(async () => { - await iterateOverflow(); - }); - await iterateDirection(); - }); - }); - }); - }); - }); } + + await iterateMinMax(async () => { + await iterateBoxSizing(async () => { + await iterateHeight(async () => { + await iterateWidth(async () => { + await iterateBorder(async () => { + // assume this part isn't critical + // await iterateFloat(async () => { + // await iterateMargin(); + // }); + await iteratePadding(async () => { + await iterateOverflow(); + }, withSkippedItems && ['paddingLarge']); + + // assume this part isn't critical for special options + if (!osOptions) { + await iterateDirection(); + } + }, withSkippedItems && ['borderSmall']); + }, withSkippedItems && ['widthHundred']); + }, withSkippedItems && ['heightHundred']); + }); + }); }; const start = async () => { @@ -812,17 +818,28 @@ const start = async () => { target?.removeAttribute('style'); try { await overflowTest(); + + osInstance.options({ paddingAbsolute: !initialPaddingAbsolute }); + + await overflowTest(); + + osInstance.options({ paddingAbsolute: initialPaddingAbsolute }); + await overflowTest({ overflow: { x: 'visible', y: 'visible' } }); - await overflowTest({ overflow: { x: 'visible-scroll', y: 'visible-hidden' } }); - await overflowTest({ overflow: { x: 'visible-hidden', y: 'hidden' } }); - await overflowTest({ overflow: { x: 'visible', y: 'visible-scroll' } }); - await overflowTest({ overflow: { x: 'scroll', y: 'visible-scroll' } }); await overflowTest({ overflow: { x: 'hidden', y: 'scroll' } }); - await overflowTest({ overflow: { x: 'scroll', y: 'hidden' } }); - await overflowTest({ overflow: { x: 'visible', y: 'scroll' } }); - await overflowTest({ overflow: { x: 'scroll', y: 'visible' } }); - await overflowTest({ overflow: { x: 'visible', y: 'hidden' } }); - await overflowTest({ overflow: { x: 'hidden', y: 'visible' } }); + await overflowTest({ overflow: { x: 'visible-hidden', y: 'scroll' } }); + await overflowTest({ overflow: { x: 'visible-scroll', y: 'visible-hidden' } }); + + if (!isFastTestRun) { + await overflowTest({ overflow: { x: 'hidden', y: 'visible' } }); + await overflowTest({ overflow: { x: 'visible', y: 'scroll' } }); + await overflowTest({ overflow: { x: 'visible-hidden', y: 'hidden' } }); + await overflowTest({ overflow: { x: 'visible', y: 'visible-scroll' } }); + await overflowTest({ overflow: { x: 'scroll', y: 'visible-scroll' } }); + await overflowTest({ overflow: { x: 'scroll', y: 'hidden' } }); + await overflowTest({ overflow: { x: 'scroll', y: 'visible' } }); + await overflowTest({ overflow: { x: 'visible', y: 'hidden' } }); + } } catch (e) { console.log(e); } @@ -842,10 +859,3 @@ if (!useContentElement) { appendChildren(comparison, comparisonContentElm); appendChildren(comparisonContentElm, elms); } - -if (paddingAbsolute) { - const absoluteWrapper = createDiv(classNameViewport); - appendChildren(absoluteWrapper, contents(comparison)); - - appendChildren(comparison, absoluteWrapper); -} diff --git a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.html b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.html index 0e87d7f..00fe807 100644 --- a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.html +++ b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.html @@ -1,4 +1,5 @@
+ diff --git a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.test.ts b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.test.ts index da0f89c..70da511 100644 --- a/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.test.ts +++ b/packages/overlayscrollbars/tests/playwright/setups/structureSetup/update/index.test.ts @@ -3,12 +3,17 @@ import { test, Page } from '@playwright/test'; playwrightRollup(); -test.describe('StructureSetup.update', () => { - [false].forEach((targetIsViewport) => { +const createTests = (fast?: boolean) => { + [false, true].forEach((targetIsViewport) => { const isOrIsNot = targetIsViewport ? 'is' : 'is not'; const setTargetIsVp = async (page: Page) => { if (targetIsViewport) { - await page.click('#tvp'); + await page.click('#vpt'); + } + }; + const setFast = async (page: Page) => { + if (fast || targetIsViewport) { + await page.click('#fast'); } }; @@ -21,20 +26,20 @@ test.describe('StructureSetup.update', () => { } }; + test.beforeEach(async ({ page }) => { + await setFast(page); + await setTargetIsVp(page); + await nsh(page); + }); + test.describe(`${withText} native scrollbar styling`, () => { - test.describe.configure({ mode: 'parallel' }); + // test.describe.configure({ mode: 'parallel' }); test('default', async ({ page }) => { - await setTargetIsVp(page); - await nsh(page); - await expectSuccess(page); }); test('with fully overlaid scrollbars', async ({ page }) => { - await setTargetIsVp(page); - await nsh(page); - await page.click('#fo'); await expectSuccess(page); @@ -46,18 +51,12 @@ test.describe('StructureSetup.update', () => { "firefox can't simulate partially overlaid scrollbars, boost speed by omitting webkit" ); - await setTargetIsVp(page); - await nsh(page); - await page.click('#po'); await expectSuccess(page); }); test('without flexbox glue & css custom props', async ({ page }) => { - await setTargetIsVp(page); - await nsh(page); - await page.click('#fbg'); await page.click('#ccp'); @@ -67,4 +66,12 @@ test.describe('StructureSetup.update', () => { }); }); }); +}; + +test.describe('StructureSetup.update @special', () => { + createTests(); +}); + +test.describe('StructureSetup.update', () => { + createTests(true); });