diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 82f9e0c2..4e6f30b7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -33,7 +33,7 @@ jobs:
node-version: 20
- name: Install dependencies
- run: npm install
+ run: npm ci
- name: Build vscroll
run: npm run build
diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml
index e1c3db5e..e232d976 100644
--- a/.github/workflows/demo.yml
+++ b/.github/workflows/demo.yml
@@ -14,15 +14,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Node
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
- name: Install dependencies
- run: npm install
+ run: npm ci
- name: Build vscroll
run: npm run build
diff --git a/app/static/demo.html b/app/static/demo.html
index 098cb14a..ebd798c9 100644
--- a/app/static/demo.html
+++ b/app/static/demo.html
@@ -24,6 +24,18 @@
.viewport .item span {
font-size: small;
}
+
+ .viewport.horizontal {
+ width: 200px;
+ height: 100px;
+ overflow-x: scroll;
+ overflow-y: hidden;
+ white-space: nowrap;
+ }
+
+ .viewport.horizontal div {
+ display: inline-block;
+ }
diff --git a/package.json b/package.json
index 88a54c89..e2ad5fe3 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"lint": "eslint . --ext .ts",
"jest": "jest ./tests/unit/",
"watch": "jest ./tests/unit/settings.spec.ts --watch",
+ "tsc": "tsc --project ./tsconfig.json",
"build": "node build",
"test": "npm run lint && npm run jest",
"app": "node app/server.js",
diff --git a/tests/e2e/index.d.ts b/tests/e2e/index.d.ts
index ad1412ee..93775e9c 100644
--- a/tests/e2e/index.d.ts
+++ b/tests/e2e/index.d.ts
@@ -1,7 +1,8 @@
-import { VSCROLL } from './misc/types';
+import { VSCROLL, TESTS } from './misc/types';
declare global {
interface Window {
__vscroll__: VSCROLL;
+ __tests__: TESTS;
}
}
\ No newline at end of file
diff --git a/tests/e2e/index.ts b/tests/e2e/index.ts
index b86fe813..7e962c81 100644
--- a/tests/e2e/index.ts
+++ b/tests/e2e/index.ts
@@ -1 +1,2 @@
-import './initialization.spec';
\ No newline at end of file
+import './initialization.spec';
+import './scroll-basic.spec';
\ No newline at end of file
diff --git a/tests/e2e/misc/itemsCounter.ts b/tests/e2e/misc/itemsCounter.ts
index 92a90ccb..b3d9aa8f 100644
--- a/tests/e2e/misc/itemsCounter.ts
+++ b/tests/e2e/misc/itemsCounter.ts
@@ -1,88 +1,197 @@
-import { Direction } from '../../../src/index';
-
-export class ItemsDirCounter {
- count: number;
- index: number;
- padding: number;
- paddingShift?: number;
- size: number;
-
- constructor(count = 0, padding = 0) {
- this.count = count;
- this.padding = padding;
- this.paddingShift = 0;
- this.index = NaN;
- this.size = NaN;
- }
+
+import { Page } from '@playwright/test';
+import { Direction } from '../../../src/inputs/common';
+import { TESTS } from './types';
+
+export type ScrollResult = {
+ edgeItemIndex: (number | undefined)[],
+ oppositeItemIndex: (number | undefined)[],
+ paddingSize: (number | undefined)[],
+ oppositePaddingSize: (number | undefined)[],
}
-export class ItemsCounter {
- direction: Direction | null; // direction per calculations
- backward: ItemsDirCounter;
- forward: ItemsDirCounter;
- average: number;
+export type ItemsCounter = {
+ invertDirection: (direction: Direction) => void,
+ doScrollMax: (direction: Direction) => void,
+ getInitialItemsCounter: () => void,
+ getCurrentItemsCounter: (direction: Direction) => void,
+ getExpectations: (direction: Direction) => ScrollResult,
+}
- get total(): number {
- return this.forward.index - this.backward.index + 1;
- // return this.backward.count + this.forward.count;
- }
+export const initializeItemsCounter = (page: Page) => page.evaluate(() => {
+ const { workflow: { scroller } } = window['__vscroll__'];
+ const forward = 'forward' as Direction;
+ const backward = 'backward' as Direction;
+ let itemsCounter: ItemsCounter;
- get paddings(): number {
- return this.forward.padding + this.backward.padding;
- }
+ class ItemsDirCounter {
+ count: number;
+ index: number;
+ padding: number;
+ paddingShift?: number;
+ size: number;
- constructor(direction?: Direction) {
- this.direction = direction || null;
- this.forward = new ItemsDirCounter();
- this.backward = new ItemsDirCounter();
- this.average = NaN;
+ constructor(count = 0, padding = 0) {
+ this.count = count;
+ this.padding = padding;
+ this.paddingShift = 0;
+ this.index = NaN;
+ this.size = NaN;
+ }
}
- get(token: Direction): ItemsDirCounter {
- return token === Direction.backward ? this.backward : this.forward;
+ class ItemsCounter {
+ direction: Direction | null; // direction per calculations
+ backward: ItemsDirCounter;
+ forward: ItemsDirCounter;
+ average: number;
+
+ get total(): number {
+ return this.forward.index - this.backward.index + 1;
+ // return this.backward.count + this.forward.count;
+ }
+
+ get paddings(): number {
+ return this.forward.padding + this.backward.padding;
+ }
+
+ constructor(direction?: Direction) {
+ this.direction = direction || null;
+ this.forward = new ItemsDirCounter();
+ this.backward = new ItemsDirCounter();
+ this.average = NaN;
+ }
+
+ get(token: Direction): ItemsDirCounter {
+ return token === backward ? this.backward : this.forward;
+ }
+
+ set(token: Direction, value: ItemsDirCounter): void {
+ if (token === backward) {
+ Object.assign(this.backward, value);
+ } else {
+ Object.assign(this.forward, value);
+ }
+ }
}
- set(token: Direction, value: ItemsDirCounter): void {
- if (token === Direction.backward) {
- Object.assign(this.backward, value);
+ const invertDirection = (direction: Direction) => {
+ const _forward = direction === forward;
+ direction = _forward ? backward : forward;
+ };
+
+ const doScrollMax = (direction: Direction) => {
+ if (direction === forward) {
+ scroller.adapter.fix({ scrollPosition: Infinity });
} else {
- Object.assign(this.forward, value);
+ scroller.adapter.fix({ scrollPosition: 0 });
}
- }
-}
+ };
-export const testItemsCounter = (startIndex: number, misc, itemsCounter: ItemsCounter): void => {
- const bwdSize = itemsCounter.backward.size;
- const fwdSize = itemsCounter.forward.size;
- const bwdPadding = itemsCounter.backward.padding;
- const fwdPadding = itemsCounter.forward.padding + (itemsCounter.forward.paddingShift || 0);
- const average = itemsCounter.average;
- const elements = misc.getElements();
- const { viewport, buffer, adapter } = misc.scroller;
- const { bufferInfo, firstVisible } = adapter;
-
- let sizePaddings = 0;
- if (!isNaN(Number(bwdPadding))) {
- expect(bwdPadding).toEqual(viewport.paddings.backward.size);
- sizePaddings += bwdPadding;
- }
- if (!isNaN(Number(fwdPadding))) {
- expect(fwdPadding).toEqual(viewport.paddings.forward.size);
- sizePaddings += fwdPadding;
- }
- if (!isNaN(Number(bwdSize)) && !isNaN(Number(fwdSize))) {
- const size = misc.getScrollableSize();
- expect(bwdSize + fwdSize + sizePaddings).toEqual(size);
- }
- if (!isNaN(Number(average))) {
- expect(average).toEqual(buffer.defaultSize);
- }
- expect(elements.length).toEqual(itemsCounter.total);
- expect(buffer.items.length).toEqual(itemsCounter.total);
- expect(misc.getElementIndex(elements[0])).toEqual(itemsCounter.backward.index);
- expect(misc.getElementIndex(elements[elements.length - 1])).toEqual(itemsCounter.forward.index);
- expect(misc.checkElementContentByIndex(startIndex)).toEqual(true);
- expect(bufferInfo.firstIndex).toEqual(itemsCounter.backward.index);
- expect(bufferInfo.lastIndex).toEqual(itemsCounter.forward.index);
- expect(firstVisible.$index).toEqual(startIndex);
-};
+ const getInitialItemsCounter = () => {
+ const { startIndex } = scroller.settings;
+ const edgeItem = scroller.buffer.getEdgeVisibleItem(forward);
+ const oppositeItem = scroller.buffer.getEdgeVisibleItem(backward);
+ const result = new ItemsCounter();
+ if (!edgeItem || !oppositeItem) {
+ return result;
+ }
+ result.set(forward, {
+ count: edgeItem.$index - startIndex + 1,
+ index: edgeItem.$index,
+ padding: 0,
+ size: 0
+ });
+ result.set(backward, {
+ count: startIndex - oppositeItem.$index,
+ index: oppositeItem.$index,
+ padding: 0,
+ size: NaN
+ });
+ itemsCounter = result;
+ };
+
+ const getFullHouseDiff = (
+ viewportSize: number, paddingDelta: number, itemSize: number, bufferSize: number
+ ): number => {
+ const sizeToFill = viewportSize + 2 * paddingDelta; // size to fill the viewport + padding deltas
+ const itemsToFillNotRounded = sizeToFill / itemSize;
+ const itemsToFillRounded = Math.ceil(sizeToFill / itemSize);
+ const itemsToFill = itemsToFillRounded + (itemsToFillNotRounded === itemsToFillRounded ? 0 : 1);
+ const bufferSizeDiff = bufferSize - itemsToFill;
+ return Math.max(0, bufferSizeDiff);
+ };
+
+
+ const getCurrentItemsCounter = (direction: Direction) => {
+ const previous = itemsCounter;
+ const { bufferSize, padding } = scroller.settings;
+ const viewportSize = scroller.viewport.getSize();
+ const itemSize = scroller.buffer.defaultSize;
+ const fwd = direction === forward;
+ const opposite = fwd ? backward : forward;
+ const delta = viewportSize * padding;
+
+ // handle direction (fetch)
+ const fullHouseDiff = getFullHouseDiff(viewportSize, delta, itemSize, bufferSize);
+ const _singleFetchCount = Math.ceil(delta / itemSize);
+ const singleFetchCount = Math.max(bufferSize, _singleFetchCount);
+ const itemsToFetch = previous.direction && previous.direction !== direction ?
+ (_singleFetchCount + fullHouseDiff) : singleFetchCount;
+ const previousEdgeIndex = previous.get(direction).index;
+ const paddingItems = (fwd ? 1 : -1) * (previous.get(direction).padding / itemSize);
+ const newItemsPack = (fwd ? 1 : -1) * itemsToFetch;
+ const newDirIndex = previousEdgeIndex + paddingItems + newItemsPack;
+
+ // handle opposite (clip)
+ const oppPadding = previous.get(opposite).padding;
+ const previousTotalSize = previous.total * itemSize + previous.paddings;
+ const sizeToClip = previousTotalSize - oppPadding - viewportSize - delta;
+ const itemsToClip = Math.floor(sizeToClip / itemSize);
+ const newOppIndex = previous.get(opposite).index + (fwd ? 1 : -1) * itemsToClip;
+ const newOppPadding = itemsToClip * itemSize + oppPadding;
+
+ const result = new ItemsCounter(direction);
+ result.set(direction, {
+ index: newDirIndex,
+ padding: 0,
+ count: NaN,
+ size: NaN
+ });
+ result.set(opposite, {
+ index: newOppIndex,
+ padding: newOppPadding,
+ count: NaN,
+ size: NaN
+ });
+ itemsCounter = result;
+ };
+
+ const getExpectations = (direction: Direction): ScrollResult => {
+ const opposite = direction === forward ? backward : forward;
+ const edgeItem = scroller.buffer.getEdgeVisibleItem(direction);
+ const oppositeItem = scroller.buffer.getEdgeVisibleItem(opposite);
+ const edgeItemIndex = itemsCounter.get(direction).index;
+ const oppositeItemIndex = itemsCounter.get(opposite).index;
+ const paddingSize = scroller.viewport.paddings.byDirection(direction).size;
+ const oppositePaddingSize = scroller.viewport.paddings.byDirection(direction, true).size;
+
+ return {
+ edgeItemIndex: [edgeItemIndex, edgeItem?.$index],
+ oppositeItemIndex: [oppositeItemIndex, oppositeItem?.$index],
+ paddingSize: [itemsCounter.get(direction).padding, paddingSize],
+ oppositePaddingSize: [itemsCounter.get(opposite).padding, oppositePaddingSize]
+ };
+ };
+
+ const ItemsCounterUtils: TESTS['ItemsCounter'] = {
+ invertDirection,
+ doScrollMax,
+ getInitialItemsCounter,
+ getCurrentItemsCounter,
+ getExpectations
+ };
+
+ window['__tests__'] ??= {} as TESTS;
+ window['__tests__'].ItemsCounter = ItemsCounterUtils;
+});
\ No newline at end of file
diff --git a/tests/e2e/misc/types.ts b/tests/e2e/misc/types.ts
index 8e001aae..78a13986 100644
--- a/tests/e2e/misc/types.ts
+++ b/tests/e2e/misc/types.ts
@@ -1,4 +1,7 @@
+import { Page } from '@playwright/test';
+import { Settings, DevSettings } from '../../../src/interfaces';
import { Workflow, IDatasourceConstructed } from '../../../src/index';
+import { ItemsCounter } from './itemsCounter';
interface Scroller {
workflow: InstanceType;
@@ -16,3 +19,34 @@ export type VSCROLL = {
scroller1: Scroller;
scroller2: Scroller;
};
+
+export type TESTS = {
+ ItemsCounter: ItemsCounter
+};
+
+type TemplateSettings = {
+ noViewportClass?: boolean;
+ viewportHeight?: number;
+ viewportWidth?: number | null;
+ itemHeight?: number;
+ itemWidth?: number | null;
+ horizontal?: boolean;
+ dynamicSize?: string | null;
+ viewportPadding?: number;
+ headerHeight?: number;
+}
+
+export type Config = {
+ datasourceClass?: { new(): unknown };
+ datasourceName?: string;
+ datasourceSettings: Settings;
+ datasourceDevSettings: DevSettings;
+ templateSettings?: TemplateSettings;
+ toThrow?: boolean;
+ custom?: Custom;
+ timeout?: number;
+}
+
+export type It = (args: { config: Config, page: Page }) => Promise;
+
+export type MakeTest = (args: { title: string; config: Config; it: It }) => void;
\ No newline at end of file
diff --git a/tests/e2e/scroll-basic.spec.ts b/tests/e2e/scroll-basic.spec.ts
index e78a3a9f..3a62d1d6 100644
--- a/tests/e2e/scroll-basic.spec.ts
+++ b/tests/e2e/scroll-basic.spec.ts
@@ -1,251 +1,152 @@
-import { test, expect } from '@playwright/test';
+import { test, expect, Page } from '@playwright/test';
+import { ScrollResult, initializeItemsCounter } from './misc/itemsCounter';
+import { Config, It, MakeTest } from './misc/types';
+import { Direction } from '../../src/inputs/common';
-import { Direction } from '../../src/index';
-import { ItemsCounter } from './misc/itemsCounter';
+// test.use({ headless: false });
-const configList = [{
+const URL = '127.0.0.1:3000';
+
+interface ICustom {
+ direction: Direction;
+ count: number;
+ bouncing?: boolean;
+ mass?: boolean;
+}
+
+const configList: Config[] = [{
datasourceSettings: { startIndex: 100, bufferSize: 4, padding: 0.22, itemSize: 20 },
templateSettings: { viewportHeight: 71, itemHeight: 20 },
+ datasourceDevSettings: { debug: true },
custom: { direction: Direction.forward, count: 1 }
-}/*, {
+}, {
datasourceSettings: { startIndex: 1, bufferSize: 5, padding: 0.2, itemSize: 20 },
templateSettings: { viewportHeight: 100 },
+ datasourceDevSettings: { debug: true },
custom: { direction: Direction.forward, count: 1 }
}, {
datasourceSettings: { startIndex: -15, bufferSize: 12, padding: 0.98, itemSize: 20 },
templateSettings: { viewportHeight: 66, itemHeight: 20 },
+ datasourceDevSettings: { debug: true },
custom: { direction: Direction.forward, count: 1 }
}, {
datasourceSettings: { startIndex: 1, bufferSize: 5, padding: 1, horizontal: true, itemSize: 100 },
templateSettings: { viewportWidth: 450, itemWidth: 100, horizontal: true },
+ datasourceDevSettings: { debug: true },
custom: { direction: Direction.forward, count: 1 }
}, {
datasourceSettings: { startIndex: -74, bufferSize: 4, padding: 0.72, horizontal: true, itemSize: 75 },
templateSettings: { viewportWidth: 300, itemWidth: 75, horizontal: true },
+ datasourceDevSettings: { debug: true },
custom: { direction: Direction.forward, count: 1 }
-}*/];
-
-// const treatIndex = (index: number) => index <= 3 ? index : (3 * 2 - index);
-
-// const singleBackwardMaxScrollConfigList =
-// configList.map(config => ({
-// ...config,
-// custom: {
-// ...config.custom,
-// direction: Direction.backward
-// }
-// }));
-
-// const massForwardScrollsConfigList =
-// configList.map((config, index) => ({
-// ...config,
-// custom: {
-// direction: Direction.backward,
-// count: 3 + treatIndex(index) // 3-6 bwd scroll events per config
-// }
-// }));
-
-// const massBackwardScrollsConfigList =
-// massForwardScrollsConfigList.map((config, index) => ({
-// ...config,
-// custom: {
-// direction: Direction.backward,
-// count: 3 + treatIndex(index) // 3-6 fwd scroll events per config
-// }
-// }));
-
-// const massBouncingScrollsConfigList_fwd =
-// massForwardScrollsConfigList.map((config, index) => ({
-// ...config,
-// custom: {
-// direction: Direction.forward,
-// count: (3 + treatIndex(index)) * 2, // 3-6 (fwd + bwd) scroll events per config
-// bouncing: true
-// }
-// }));
-
-// const massBouncingScrollsConfigList_bwd =
-// massForwardScrollsConfigList.map((config, index) => ({
-// ...config,
-// custom: {
-// direction: Direction.backward,
-// count: (3 + treatIndex(index)) * 2, // 3-6 (fwd + bwd) scroll events per config
-// bouncing: true
-// }
-// }));
-
-// const massTwoDirectionalScrollsConfigList_fwd =
-// massForwardScrollsConfigList.map((config, index) => ({
-// ...config,
-// custom: {
-// direction: Direction.forward,
-// count: (3 + treatIndex(index)) * 2, // 3-6 fwd + 3-6 bwd scroll events per config
-// mass: true
-// }
-// }));
-
-// const massTwoDirectionalScrollsConfigList_bwd =
-// massForwardScrollsConfigList.map((config, index) => ({
-// ...config,
-// custom: {
-// direction: Direction.backward,
-// count: (3 + treatIndex(index)) * 2, // 3-6 fwd + 3-6 bwd scroll events per config
-// mass: true
-// }
-// }));
-
-// const doScrollMax = (config, misc) => {
-// if (config.custom.direction === Direction.forward) {
-// misc.scrollMax();
-// } else {
-// misc.scrollMin();
-// }
-// };
-
-// const invertDirection = (config) => {
-// const _forward = config.custom.direction === Direction.forward;
-// config.custom.direction = _forward ? Direction.backward : Direction.forward;
-// };
-
-// const getFullHouseDiff = (
-// viewportSize: number, paddingDelta: number, itemSize: number, bufferSize: number
-// ): number => {
-// const sizeToFill = viewportSize + 2 * paddingDelta; // size to fill the viewport + padding deltas
-// const itemsToFillNotRounded = sizeToFill / itemSize;
-// const itemsToFillRounded = Math.ceil(sizeToFill / itemSize);
-// const itemsToFill = itemsToFillRounded + (itemsToFillNotRounded === itemsToFillRounded ? 0 : 1);
-// const bufferSizeDiff = bufferSize - itemsToFill;
-// return Math.max(0, bufferSizeDiff);
-// };
-
-const shouldScroll = config => async (page) => {
- const custom = config.custom;
- const wfCount = custom.count + 1;
- const wfCountMiddle = Math.ceil(wfCount / 2);
- let itemsCounter: ItemsCounter;
-
- const result = await page.evaluate(({ custom }) => {
- const { workflow } = window['__vscroll__'].workflow;
-
- const finalize = workflow.finalize;
- workflow.finalize = (...args) => {
- finalize.apply(workflow, args);
-
- const cycles = workflow.cyclesDone;
- if (cycles === 1) {
- itemsCounter = ((scroller) => {
- const { startIndex } = scroller.settings;
- const edgeItem = scroller.buffer.getEdgeVisibleItem(Direction.forward);
- const oppositeItem = scroller.buffer.getEdgeVisibleItem(Direction.backward);
- const result = new ItemsCounter();
- if (!edgeItem || !oppositeItem) {
- return result;
- }
- result.set(Direction.forward, {
- count: edgeItem.$index - startIndex + 1,
- index: edgeItem.$index,
- padding: 0,
- size: 0
- });
- result.set(Direction.backward, {
- count: startIndex - oppositeItem.$index,
- index: oppositeItem.$index,
- padding: 0,
- size: NaN
- });
- return result;
- })(workflow.scroller);
-
- } else {
- const getFullHouseDiff = (
- viewportSize: number, paddingDelta: number, itemSize: number, bufferSize: number
- ): number => {
- const sizeToFill = viewportSize + 2 * paddingDelta; // size to fill the viewport + padding deltas
- const itemsToFillNotRounded = sizeToFill / itemSize;
- const itemsToFillRounded = Math.ceil(sizeToFill / itemSize);
- const itemsToFill = itemsToFillRounded + (itemsToFillNotRounded === itemsToFillRounded ? 0 : 1);
- const bufferSizeDiff = bufferSize - itemsToFill;
- return Math.max(0, bufferSizeDiff);
- };
-
- itemsCounter = ((scroller, direction: Direction, previous: ItemsCounter): ItemsCounter => {
- const { bufferSize, padding } = scroller.settings;
- const viewportSize = scroller.viewport.getSize();
- const itemSize = scroller.buffer.defaultSize;
- const fwd = direction === Direction.forward;
- const opposite = fwd ? Direction.backward : Direction.forward;
- const delta = viewportSize * padding;
-
- // handle direction (fetch)
- const fullHouseDiff = getFullHouseDiff(viewportSize, delta, itemSize, bufferSize);
- const _singleFetchCount = Math.ceil(delta / itemSize);
- const singleFetchCount = Math.max(bufferSize, _singleFetchCount);
- const itemsToFetch = previous.direction && previous.direction !== direction ?
- (_singleFetchCount + fullHouseDiff) : singleFetchCount;
- const previousEdgeIndex = previous.get(direction).index;
- const paddingItems = (fwd ? 1 : -1) * (previous.get(direction).padding / itemSize);
- const newItemsPack = (fwd ? 1 : -1) * itemsToFetch;
- const newDirIndex = previousEdgeIndex + paddingItems + newItemsPack;
-
- // handle opposite (clip)
- const oppPadding = previous.get(opposite).padding;
- const previousTotalSize = previous.total * itemSize + previous.paddings;
- const sizeToClip = previousTotalSize - oppPadding - viewportSize - delta;
- const itemsToClip = Math.floor(sizeToClip / itemSize);
- const newOppIndex = previous.get(opposite).index + (fwd ? 1 : -1) * itemsToClip;
- const newOppPadding = itemsToClip * itemSize + oppPadding;
-
- const result = new ItemsCounter(direction);
- result.set(direction, {
- index: newDirIndex,
- padding: 0,
- count: NaN,
- size: NaN
- });
- result.set(opposite, {
- index: newOppIndex,
- padding: newOppPadding,
- count: NaN,
- size: NaN
- });
- return result;
- })(workflow.scroller, custom.direction, itemsCounter);
- }
-
- if (cycles < wfCount) {
- const invertDirection = () => {
- const _forward = custom.direction === Direction.forward;
- custom.direction = _forward ? Direction.backward : Direction.forward;
- };
- if (custom.bouncing) {
- invertDirection();
- } else if (custom.mass) {
- if (cycles === wfCountMiddle) {
- invertDirection();
- }
+}];
+
+const treatIndex = (index: number) => index <= 3 ? index : (3 * 2 - index);
+
+const singleBackwardMaxScrollConfigList =
+ configList.map(config => ({
+ ...config,
+ custom: {
+ ...config.custom,
+ direction: Direction.backward
+ }
+ } as Config));
+
+const massForwardScrollsConfigList =
+ configList.map((config, index) => ({
+ ...config,
+ custom: {
+ direction: Direction.backward,
+ count: 3 + treatIndex(index) // 3-6 bwd scroll events per config
+ }
+ } as Config));
+
+const massBackwardScrollsConfigList =
+ massForwardScrollsConfigList.map((config, index) => ({
+ ...config,
+ custom: {
+ direction: Direction.backward,
+ count: 3 + treatIndex(index) // 3-6 fwd scroll events per config
+ }
+ } as Config));
+
+const massBouncingScrollsConfigList_fwd =
+ massForwardScrollsConfigList.map((config, index) => ({
+ ...config,
+ custom: {
+ direction: Direction.forward,
+ count: (3 + treatIndex(index)) * 2, // 3-6 (fwd + bwd) scroll events per config
+ bouncing: true
+ }
+ } as Config));
+
+const massBouncingScrollsConfigList_bwd =
+ massForwardScrollsConfigList.map((config, index) => ({
+ ...config,
+ custom: {
+ direction: Direction.backward,
+ count: (3 + treatIndex(index)) * 2, // 3-6 (fwd + bwd) scroll events per config
+ bouncing: true
+ }
+ } as Config));
+
+const massTwoDirectionalScrollsConfigList_fwd =
+ massForwardScrollsConfigList.map((config, index) => ({
+ ...config,
+ custom: {
+ direction: Direction.forward,
+ count: (3 + treatIndex(index)) * 2, // 3-6 fwd + 3-6 bwd scroll events per config
+ mass: true
+ }
+ } as Config));
+
+const massTwoDirectionalScrollsConfigList_bwd =
+ massForwardScrollsConfigList.map((config, index) => ({
+ ...config,
+ custom: {
+ direction: Direction.backward,
+ count: (3 + treatIndex(index)) * 2, // 3-6 fwd + 3-6 bwd scroll events per config
+ mass: true
+ }
+ } as Config));
+
+
+const shouldScroll = async (config: Config, page: Page) => {
+
+ await initializeItemsCounter(page);
+
+ const result = await page.evaluate(custom =>
+ new Promise(resolve => {
+ const { workflow } = window['__vscroll__'];
+ const { ItemsCounter: helper } = window['__tests__'];
+
+ workflow.scroller.state.cycle.busy.on(busy => {
+ if (busy) {
+ return;
+ }
+
+ if (workflow.cyclesDone === 1) {
+ helper.getInitialItemsCounter();
+ } else {
+ helper.getCurrentItemsCounter(custom.direction);
}
- if (custom.direction === Direction.forward) {
- workflow.scroller.adapter.fix({ scrollPosition: Infinity });
+
+ const wfCount = custom.count + 1;
+ if (workflow.cyclesDone < wfCount) {
+ if (custom.bouncing) {
+ helper.invertDirection(custom.direction);
+ } else if (custom.mass) {
+ const wfCountMiddle = Math.ceil(wfCount / 2);
+ if (workflow.cyclesDone === wfCountMiddle) {
+ helper.invertDirection(custom.direction);
+ }
+ }
+ helper.doScrollMax(custom.direction);
} else {
- workflow.scroller.adapter.fix({ scrollPosition: 0 });
+ resolve(helper.getExpectations(custom.direction));
}
- } else {
- // expectations
- const direction: Direction = custom.direction;
- const opposite = direction === Direction.forward ? Direction.backward : Direction.forward;
- const edgeItem = workflow.scroller.buffer.getEdgeVisibleItem(direction);
- const oppositeItem = workflow.scroller.buffer.getEdgeVisibleItem(opposite);
- const edgeItemIndex = itemsCounter.get(direction).index;
- const oppositeItemIndex = itemsCounter.get(opposite).index;
- return {
- edgeItemsIndex: [edgeItemIndex, edgeItem?.$index],
- oppositeItemIndex: [oppositeItemIndex, oppositeItem?.$index],
- paddingSize: itemsCounter.get(direction).padding,
- oppositePaddingSize: itemsCounter.get(opposite).padding
- };
- }
- };
- }, { custom });
+ });
+ }), config.custom as ICustom);
const {
edgeItemIndex,
@@ -256,121 +157,148 @@ const shouldScroll = config => async (page) => {
expect(edgeItemIndex?.[0]).toEqual(edgeItemIndex?.[1]);
expect(oppositeItemIndex?.[0]).toEqual(oppositeItemIndex?.[1]);
+ expect(paddingSize?.[0]).toEqual(paddingSize?.[1]);
+ expect(oppositePaddingSize?.[0]).toEqual(oppositePaddingSize?.[1]);
- const _paddingSize = await page.evaluate((direction) =>
- document.querySelector(`[data-padding-${direction}]`)?.clientHeight
- , custom.direction);
-
- const _oppositePaddingSize = await page.evaluate((direction) =>
- document.querySelector(`[data-padding-${direction}]`)?.clientHeight
- , custom.direction === Direction.forward
- ? Direction.backward
- : Direction.forward
- );
-
- expect(_paddingSize).toEqual(paddingSize);
- expect(_oppositePaddingSize).toEqual(oppositePaddingSize);
-
- await expect(page.locator(`[sid="${edgeItemIndex[0]}"]`))
- .toHaveText('item: ' + edgeItemIndex[0]);
- await expect(page.locator(`[sid="${oppositeItemIndex[0]}"]`))
- .toHaveText('item: ' + oppositeItemIndex[0]);
+ await expect(page.locator(`[data-sid="${edgeItemIndex[0]}"]`))
+ .toHaveText(`${edgeItemIndex[0]}) item #${edgeItemIndex[0]}`);
+ await expect(page.locator(`[data-sid="${oppositeItemIndex[0]}"]`))
+ .toHaveText(`${oppositeItemIndex[0]}) item #${oppositeItemIndex[0]}`);
};
-const runScroller = async (page, { settings = {}, devSettings = {} } = {}) =>
- await page.evaluate(({ settings, devSettings }) => {
+const runScroller = async (page: Page, config: Config) =>
+ await page.evaluate(config => {
+ const { datasourceSettings, datasourceDevSettings, templateSettings } = config as Config;
const { Scroller, datasource } = window['__vscroll__'];
- datasource.settings = { ...datasource.settings, ...settings };
- datasource.devSettings = { ...datasource.devSettings, ...devSettings };
+ datasource.settings = { ...datasource.settings, ...datasourceSettings };
+ datasource.devSettings = { ...datasource.devSettings, ...datasourceDevSettings };
+
+ const viewport = window.document.querySelector('.viewport') as HTMLElement;
+ if (templateSettings?.viewportWidth) {
+ viewport.style.width = templateSettings.viewportWidth + 'px';
+ }
+ if (templateSettings?.viewportHeight) {
+ viewport.style.height = templateSettings.viewportHeight + 'px';
+ }
+ if (templateSettings?.horizontal) {
+ viewport.className += ' horizontal';
+ }
+ let styles = '';
+ if (templateSettings?.itemWidth) {
+ styles += `
+ .viewport .item {
+ width: ${templateSettings.itemWidth}px;
+ }`;
+ }
+ if (templateSettings?.itemHeight) {
+ styles += `
+ .viewport .item {
+ height: ${templateSettings.itemHeight}px;
+ }`;
+ }
+ if (styles) {
+ const styleSheet = document.createElement('style');
+ styleSheet.innerText = styles;
+ document.head.appendChild(styleSheet);
+ }
+
const { workflow } = new Scroller(datasource);
window['__vscroll__'].workflow = workflow;
- }, { settings, devSettings });
+ }, config as unknown);
+
-const makeTest = async ({ page, title, config, it }) => {
- console.log(title);
+const makeTest: MakeTest = ({ title, config, it }) =>
+ test(title, ({ page }) => it({ config, page }));
+
+const shouldWork: It = async ({ config, page }) => {
await page.goto(URL + '/need-run');
- await runScroller(page, { settings: config.datasourceSettings });
- await it(page);
+ await runScroller(page, config);
+ await shouldScroll(config, page);
+ // await new Promise(r => setTimeout(r, 2000));
};
+test.describe('Scroll Basic Spec', () => {
+ test.describe.configure({ mode: 'serial' });
+
+ test.describe('Single max fwd scroll event', () =>
+ configList.forEach((config, index) =>
+ makeTest({
+ config,
+ title: `should process 1 forward max scroll (${index + 1})`,
+ it: shouldWork
+ })
+ )
+ );
+
+ test.describe('Single max bwd scroll event', () =>
+ singleBackwardMaxScrollConfigList.forEach((config, index) =>
+ makeTest({
+ config,
+ title: `should process 1 backward max scroll (${index + 1})`,
+ it: shouldWork
+ })
+ )
+ );
+
+ test.describe('Mass max fwd scroll events', () =>
+ massForwardScrollsConfigList.forEach((config, index) =>
+ makeTest({
+ config,
+ title: `should process some forward scrolls (${index + 1})`,
+ it: shouldWork
+ })
+ )
+ );
+
+ test.describe('Mass max bwd scroll events', () =>
+ massBackwardScrollsConfigList.forEach((config, index) =>
+ makeTest({
+ config,
+ title: `should process some backward scrolls (${index + 1})`,
+ it: shouldWork
+ })
+ )
+ );
+
+ test.describe('Bouncing max two-directional scroll events (fwd started)', () =>
+ massBouncingScrollsConfigList_fwd.forEach((config, index) =>
+ makeTest({
+ config,
+ title: `should process some bouncing scrolls (${index + 1})`,
+ it: shouldWork
+ })
+ )
+ );
+
+ test.describe('Bouncing max two-directional scroll events (bwd started)', () =>
+ massBouncingScrollsConfigList_bwd.forEach((config, index) =>
+ makeTest({
+ config,
+ title: `should process some bouncing scrolls (${index + 1})`,
+ it: shouldWork
+ })
+ )
+ );
+
+ test.describe('Mass max two-directional scroll events (fwd started)', () =>
+ massTwoDirectionalScrollsConfigList_fwd.forEach((config, index) =>
+ makeTest({
+ config,
+ title: `should process some two-directional scrolls (${index + 1})`,
+ it: shouldWork
+ })
+ )
+ );
+
+ test.describe('Mass max two-directional scroll events (bwd started)', () =>
+ massTwoDirectionalScrollsConfigList_bwd.forEach((config, index) =>
+ makeTest({
+ config,
+ title: `should process some two-directional scrolls (${index + 1})`,
+ it: shouldWork
+ })
+ )
+ );
+});
-test('Single max fwd scroll event', ({ page }) =>
- configList.forEach(config =>
- makeTest({
- page,
- config,
- title: 'should process 1 forward max scroll',
- it: shouldScroll(config)
- })
- )
-);
-
- // describe('Single max bwd scroll event', () =>
- // singleBackwardMaxScrollConfigList.forEach(config =>
- // _makeTest({
- // config,
- // title: 'should process 1 backward max scroll',
- // it: shouldScroll(config)
- // })
- // )
- // );
-
- // describe('Mass max fwd scroll events', () =>
- // massForwardScrollsConfigList.forEach(config =>
- // _makeTest({
- // config,
- // title: 'should process some forward scrolls',
- // it: shouldScroll(config)
- // })
- // )
- // );
-
- // describe('Mass max bwd scroll events', () =>
- // massBackwardScrollsConfigList.forEach(config =>
- // _makeTest({
- // config,
- // title: 'should process some backward scrolls',
- // it: shouldScroll(config)
- // })
- // )
- // );
-
- // describe('Bouncing max two-directional scroll events (fwd started)', () =>
- // massBouncingScrollsConfigList_fwd.forEach(config =>
- // _makeTest({
- // config,
- // title: 'should process some bouncing scrolls',
- // it: shouldScroll(config)
- // })
- // )
- // );
-
- // describe('Bouncing max two-directional scroll events (bwd started)', () =>
- // massBouncingScrollsConfigList_bwd.forEach(config =>
- // _makeTest({
- // config,
- // title: 'should process some bouncing scrolls',
- // it: shouldScroll(config)
- // })
- // )
- // );
-
- // describe('Mass max two-directional scroll events (fwd started)', () =>
- // massTwoDirectionalScrollsConfigList_fwd.forEach(config =>
- // _makeTest({
- // config,
- // title: 'should process some two-directional scrolls',
- // it: shouldScroll(config)
- // })
- // )
- // );
-
- // describe('Mass max two-directional scroll events (bwd started)', () =>
- // massTwoDirectionalScrollsConfigList_bwd.forEach(config =>
- // _makeTest({
- // config,
- // title: 'should process some two-directional scrolls',
- // it: shouldScroll(config)
- // })
- // )
- // );
+export default {};