UNPKG

@v4fire/client

Version:

V4Fire client core library

514 lines (416 loc) • 11.7 kB
/*! * 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 }); }); }); });