@v4fire/client
Version:
V4Fire client core library
514 lines (416 loc) • 11.7 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 describes test cases for checking the correctness of displaying component slots in different states.
*/
import delay from 'delay';
import test from 'tests/config/unit/test';
import { BOM } from 'tests/helpers';
import type { ShouldPerform } from 'base/b-virtual-scroll-new/b-virtual-scroll-new';
import type { SlotsStateObj } from 'base/b-virtual-scroll-new/modules/slots';
import { createTestHelpers } from 'base/b-virtual-scroll-new/test/api/helpers';
// eslint-disable-next-line max-lines-per-function
test.describe('<b-virtual-scroll-new>', () => {
let
component: Awaited<ReturnType<typeof createTestHelpers>>['component'],
provider: Awaited<ReturnType<typeof createTestHelpers>>['provider'],
state: Awaited<ReturnType<typeof createTestHelpers>>['state'];
test.beforeEach(async ({demoPage, page}) => {
await demoPage.goto();
({component, provider, state} = await createTestHelpers(page));
await provider.start();
await component.withChildren({
done: {
type: 'div',
attrs: {
id: 'done'
}
},
empty: {
type: 'div',
attrs: {
id: 'empty'
}
},
retry: {
type: 'div',
attrs: {
id: 'retry'
}
},
tombstone: {
type: 'div',
attrs: {
id: 'tombstone'
}
},
loader: {
type: 'div',
attrs: {
id: 'loader'
}
}
});
await component.withProps({
tombstoneCount: 1
});
});
test.describe('`done`', () => {
test('activates when all data has been loaded after the initial load', async () => {
const chunkSize = 12;
provider
.responseOnce(200, {data: state.data.addData(chunkSize)})
.response(200, {data: []});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({chunkSize})
.build();
await component.waitForChildCountEqualsTo(chunkSize);
await component.scrollToBottom();
await component.waitForSlotState('done', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: true,
empty: false,
loader: false,
renderNext: false,
retry: false,
tombstones: false
});
});
test('activates when all data has been loaded after the second load', async () => {
const chunkSize = 12;
provider
.responseOnce(200, {data: state.data.addData(chunkSize)})
.responseOnce(200, {data: state.data.addData(chunkSize)})
.response(200, {data: []});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
shouldPerformDataRender: () => true
})
.build();
await component.waitForDataIndexChild(chunkSize - 1);
await component.scrollToBottom();
await component.waitForSlotState('done', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: true,
empty: false,
loader: false,
renderNext: false,
retry: false,
tombstones: false
});
});
test('activates when data loading is completed but data is less than chunkSize', async () => {
const chunkSize = 12;
provider
.responseOnce(200, {data: state.data.addData(chunkSize / 2)})
.response(200, {data: []});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
shouldPerformDataRender: () => true
})
.build();
await component.waitForSlotState('done', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: true,
empty: false,
loader: false,
renderNext: false,
retry: false,
tombstones: false
});
});
test('does not activates if there is more data to download', async () => {
const chunkSize = 12;
provider
.responseOnce(200, {data: state.data.addData(chunkSize)})
.responseOnce(200, {data: state.data.addData(chunkSize)})
.responseOnce(200, {data: state.data.addData(chunkSize)})
.response(200, {data: []});
const shouldPerformDataRender =
<ShouldPerform>(({isInitialRender, remainingItems}) => isInitialRender || remainingItems === 0);
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
shouldPerformDataRender
})
.build();
await component.waitForChildCountEqualsTo(chunkSize);
await component.waitForSlotState('loader', false);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: false,
renderNext: false,
retry: false,
tombstones: false
});
});
});
test.describe('empty', () => {
test('activates when no data has been loaded after the initial load', async () => {
const chunkSize = 12;
provider.response(200, {data: []});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
shouldPerformDataRender: () => true
})
.build();
await component.waitForSlotState('empty', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: true,
empty: true,
loader: false,
renderNext: false,
retry: false,
tombstones: false
});
});
});
test.describe('tombstone & loader', () => {
test('activates while initial data loading in progress', async () => {
const chunkSize = 12;
provider
.response(200, {data: state.data.addData(chunkSize)}, {delay: (10).seconds()});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({chunkSize})
.build();
await component.waitForSlotState('loader', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: true,
renderNext: false,
retry: false,
tombstones: true
});
});
test('active while initial load loads all data', async () => {
const
chunkSize = 12,
providerChunkSize = chunkSize / 2;
provider
.response(200, {data: state.data.addData(providerChunkSize)}, {delay: (4).seconds()});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({chunkSize})
.build();
let i = 0;
while (i < 4) {
await component.waitForSlotState('loader', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: true,
renderNext: false,
retry: false,
tombstones: true
});
await delay(700);
i++;
}
});
});
test.describe('retry', () => {
test('activates when a data load error occurred during initial loading', async () => {
const chunkSize = 12;
provider.response(500, {});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
shouldPerformDataRender: () => true
})
.build();
await component.waitForSlotState('retry', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: false,
renderNext: false,
retry: true,
tombstones: false
});
});
test('activates when a data load error occurred during initial loading of the second data chunk', async () => {
const
chunkSize = 12,
providerChunkSize = chunkSize / 2;
provider
.responseOnce(200, {data: state.data.addData(providerChunkSize)})
.response(500, {});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
shouldPerformDataRender: () => true
})
.build();
await component.waitForSlotState('retry', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: false,
renderNext: false,
retry: true,
tombstones: false
});
});
test('activates when a data load error ocurred during loading of second data chunk', async () => {
const chunkSize = 12;
provider
.responseOnce(200, {data: state.data.addData(chunkSize)})
.response(500, {});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize
})
.build();
await component.waitForChildCountEqualsTo(chunkSize);
await component.scrollToBottom();
await component.waitForSlotState('retry', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: false,
renderNext: false,
retry: true,
tombstones: false
});
});
});
test.describe('renderNext', () => {
test.beforeEach(async () => {
await component.withChildren({
renderNext: {
type: 'div',
attrs: {
id: 'renderNext'
}
}
});
});
test('activates when data is loaded', async () => {
const chunkSize = 12;
provider
.responseOnce(200, {data: state.data.addData(chunkSize)})
.response(200, {data: []});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
disableObserver: true,
shouldPerformDataRender: () => true
})
.build();
await component.waitForSlotState('renderNext', true);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: false,
renderNext: true,
retry: false,
tombstones: false
});
});
test('doesn\'t activates while data is loading', async ({page}) => {
const chunkSize = 12;
provider
.responseOnce(200, {data: state.data.addData(chunkSize)}, {delay: (10).seconds()})
.response(200, {data: []});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
disableObserver: true,
shouldPerformDataRender: () => true
})
.build();
await BOM.waitForIdleCallback(page);
await component.waitForSlotState('renderNext', false);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: true,
renderNext: false,
retry: false,
tombstones: true
});
});
test('doesn\'t activates if there\'s a data loading error', async () => {
const chunkSize = 12;
provider.response(500, {data: []});
await component
.withDefaultPaginationProviderProps({chunkSize})
.withProps({
chunkSize,
disableObserver: true,
shouldPerformDataRender: () => true
})
.build();
await component.waitForSlotState('renderNext', false);
await component.waitForSlotState('tombstones', false);
const
slots = await component.getSlotsState();
test.expect(slots).toEqual(<Required<SlotsStateObj>>{
container: true,
done: false,
empty: false,
loader: false,
renderNext: false,
retry: true,
tombstones: false
});
});
});
});