@v4fire/client
Version:
V4Fire client core library
335 lines (274 loc) • 8.61 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
/**
* @file This file contains test cases that verify the correctness of the internal component state module.
*/
import test from 'tests/config/unit/test';
import type bVirtualScrollNew from 'base/b-virtual-scroll-new/b-virtual-scroll-new';
import { defaultShouldProps } from 'base/b-virtual-scroll-new/const';
import type { ComponentItem, ShouldPerform } from 'base/b-virtual-scroll-new/interface';
import { createTestHelpers } from 'base/b-virtual-scroll-new/test/api/helpers';
import type { VirtualScrollTestHelpers } from 'base/b-virtual-scroll-new/test/api/helpers/interface';
test.describe('<b-virtual-scroll-new>', () => {
let
component: VirtualScrollTestHelpers['component'],
provider: VirtualScrollTestHelpers['provider'],
state: VirtualScrollTestHelpers['state'];
test.beforeEach(async ({demoPage, page}) => {
await demoPage.goto();
({component, provider, state} = await createTestHelpers(page));
await provider.start();
});
test('Initial state', async () => {
const
chunkSize = 12,
mockFn = await component.mockFn((ctx: bVirtualScrollNew) => ctx.getVirtualScrollState());
provider.response(200, {data: []}, {delay: (10).seconds()});
const expectedState = state.compile({
lastLoadedRawData: undefined,
remainingItems: undefined,
remainingChildren: undefined,
maxViewedItem: undefined,
maxViewedChild: undefined,
areRequestsStopped: false,
isLoadingInProgress: true,
lastLoadedData: [],
loadPage: 0
});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
'@componentHook:created': mockFn
})
.build();
await test.expect(mockFn.results).resolves.toEqual([{type: 'return', value: expectedState}]);
});
test('State after loading first and second data chunks', async () => {
const
chunkSize = 12,
providerChunkSize = chunkSize / 2;
const
shouldStopRequestingData = <ShouldPerform>(defaultShouldProps.shouldStopRequestingData),
shouldPerformDataRender = <ShouldPerform>(({isInitialRender, remainingItems: remainingItems}) =>
isInitialRender || remainingItems === 0);
await test.step('After rendering first data chunk', async () => {
provider
.responseOnce(200, {data: state.data.addData(providerChunkSize)})
.responseOnce(200, {data: state.data.addData(providerChunkSize)});
state.data.addItems(chunkSize);
await component
.withDefaultPaginationProviderProps({chunkSize: providerChunkSize})
.withProps({
chunkSize,
shouldStopRequestingData,
shouldPerformDataRender
})
.build();
await component.waitForChildCountEqualsTo(chunkSize);
const
currentState = await component.getVirtualScrollState();
test.expect(currentState).toEqual(state.compile({
isInitialLoading: false,
isInitialRender: false,
areRequestsStopped: false,
isLoadingInProgress: false,
loadPage: 2,
renderPage: 1
}));
});
await test.step('After rendering second data chunk', async () => {
provider
.responseOnce(200, {data: state.data.addData(providerChunkSize)})
.responseOnce(200, {data: state.data.addData(providerChunkSize)})
.response(200, {data: state.data.addData(0)});
state.data.addItems(chunkSize);
await component.scrollToBottom();
await component.waitForChildCountEqualsTo(chunkSize * 2);
await component.scrollToBottom();
await component.waitForLifecycleDone();
const
currentState = await component.getVirtualScrollState();
test.expect(currentState).toEqual(state.compile({
isInitialLoading: false,
isInitialRender: false,
areRequestsStopped: true,
isLoadingInProgress: false,
isLastEmpty: true,
isLifecycleDone: true,
isLastRender: true,
loadPage: 5,
renderPage: 2
}));
});
});
test.describe('state after rendering via `itemsFactory`', () => {
test('`itemsFactory` returns mixed items with `item` and `separator` type', async () => {
const chunkSize = 12;
const separator: ComponentItem = {
item: 'b-button',
key: Object.cast(undefined),
children: ['ima button'],
props: {
id: 'button'
},
type: 'separator'
};
const item = (data): ComponentItem => ({
item: 'section',
key: Object.cast(undefined),
type: 'item',
props: {
'data-index': data.i
},
meta: {
data
}
});
const compileItemsFn = (state, ctx, separator, item) => {
const
data = state.lastLoadedData,
result: ComponentItem[] = [];
data.forEach((data) => {
result.push(separator, item(data));
});
return result;
};
const itemsFactory = await component.mockFn(compileItemsFn, separator, item);
provider
.responseOnce(200, {data: state.data.addData(chunkSize)})
.response(200, {data: state.data.addData(0)});
state.data.addChild(compileItemsFn({lastLoadedData: state.data.data}, null, separator, item));
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
itemsFactory,
shouldPerformDataRender: () => true,
chunkSize
})
.build();
await component.waitForChildCountEqualsTo(chunkSize * 2);
await component.waitForLifecycleDone();
const
currentState = await component.getVirtualScrollState();
test.expect(currentState).toEqual(state.compile({
isInitialLoading: false,
isInitialRender: false,
areRequestsStopped: true,
isLoadingInProgress: false,
isLastEmpty: true,
isLifecycleDone: true,
isLastRender: true,
loadPage: 2,
renderPage: 1
}));
});
test('`itemsFactory` returns items with `item` and last item with `separator` type', async () => {
const chunkSize = 12;
const separator: ComponentItem = {
item: 'b-button',
key: Object.cast(undefined),
children: ['ima button'],
props: {
id: 'button'
},
type: 'separator'
};
const itemsFactory = await component.mockFn((state, ctx, separator) => {
const
data = state.lastLoadedData;
const items = data.map((item) => ({
item: 'section',
key: Object.cast(undefined),
type: 'item',
props: {
'data-index': item.i
},
meta: {
data: item
}
}));
if (data.length > 0) {
items.push(separator);
}
return items;
}, separator);
provider
.responseOnce(200, {data: state.data.addData(chunkSize)})
.response(200, {data: state.data.addData(0)});
state.data.addItems(chunkSize);
state.data.addChild([separator]);
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
itemsFactory,
shouldPerformDataRender: () => true,
chunkSize
})
.build();
await component.waitForChildCountEqualsTo(chunkSize + 1);
await component.waitForLifecycleDone();
const
currentState = await component.getVirtualScrollState();
test.expect(currentState).toEqual(state.compile({
isInitialLoading: false,
isInitialRender: false,
areRequestsStopped: true,
isLoadingInProgress: false,
isLastEmpty: true,
isLifecycleDone: true,
isLastRender: true,
loadPage: 2,
renderPage: 1
}));
});
test('`itemsFactory` does not returns items with `item` type', async () => {
const chunkSize = 12;
const itemsFactory = await component.mockFn((state) => {
const
data = state.lastLoadedData;
const items = data.map((item) => ({
item: 'section',
key: Object.cast(undefined),
type: 'separator',
props: {
'data-index': item.i
}
}));
return items;
});
provider
.responseOnce(200, {data: state.data.addData(chunkSize)})
.response(200, {data: state.data.addData(0)});
state.data.addSeparators(chunkSize);
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
itemsFactory,
shouldPerformDataRender: () => true,
chunkSize
})
.build();
await component.waitForChildCountEqualsTo(chunkSize);
await component.waitForLifecycleDone();
const
currentState = await component.getVirtualScrollState();
test.expect(currentState).toEqual(state.compile({
isInitialLoading: false,
isInitialRender: false,
areRequestsStopped: true,
isLoadingInProgress: false,
isLastEmpty: true,
isLifecycleDone: true,
isLastRender: true,
maxViewedItem: undefined,
loadPage: 2,
renderPage: 1
}));
});
});
});