@v4fire/client
Version:
V4Fire client core library
286 lines (216 loc) • 9.11 kB
JavaScript
// @ts-check
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
/**
* @typedef {import('playwright').Page} Page
*/
const
h = include('tests/helpers').default;
/** @param {Page} page */
module.exports = (page) => {
let
component,
node,
container;
const
getContainerChildCount = () => component.evaluate((ctx) => ctx.$refs.container.childElementCount);
const setProps = async (reqParams) => {
await component.evaluate((ctx, reqParams) => {
ctx.dataProvider = 'demo.Pagination';
ctx.chunkSize = 10;
ctx.request = {get: {chunkSize: 10, id: Math.random(), ...reqParams}};
}, reqParams);
await h.dom.waitForEl(container, 'section');
};
const
initialTimeout = globalThis.jasmine.DEFAULT_TIMEOUT_INTERVAL;
beforeAll(() => {
globalThis.jasmine.DEFAULT_TIMEOUT_INTERVAL = (20).seconds();
});
afterAll(() => {
globalThis.jasmine.DEFAULT_TIMEOUT_INTERVAL = initialTimeout;
});
beforeEach(async () => {
await page.evaluate(() => {
globalThis.removeCreatedComponents();
const baseAttrs = {
theme: 'demo',
option: 'section',
optionProps: ({current}) => ({'data-index': current.i})
};
const scheme = [
{
attrs: {
...baseAttrs,
id: 'target'
}
}
];
globalThis.renderComponents('b-virtual-scroll', scheme);
globalThis.componentNode = document.querySelector('.b-virtual-scroll');
});
await h.bom.waitForIdleCallback(page);
await h.component.waitForComponentStatus(page, '.b-virtual-scroll', 'ready');
node = await h.dom.waitForEl(page, '#target');
component = await h.component.waitForComponent(page, '#target');
container = await h.dom.waitForRef(node, 'container');
});
describe('b-virtual-scroll rendering', () => {
describe('after re-initialization', () => {
describe('by changing the `request` prop', () => {
it('removes old elements', async () => {
await setProps();
await component.evaluate((ctx) => ctx.request = {get: {chunkSize: 10, total: 0}});
await h.dom.waitForEl(container, 'section', {to: 'unmount'});
expect(await component.evaluate((ctx) => ctx.$refs.container.childElementCount === 0)).toBeTrue();
});
it('renders new', async () => {
await setProps();
const
chunkSize = await component.evaluate((ctx) => ctx.requestParams.get.chunkSize);
await h.dom.waitForEl(container, `section:nth-child(${chunkSize - 1})`);
expect(await getContainerChildCount()).toBe(chunkSize);
await component.evaluate((ctx) => ctx.request = {get: {chunkSize: 4, total: 4, id: 'uniq-options'}});
await h.dom.waitForEl(container, 'section', {to: 'unmount'});
await h.dom.waitForEl(container, 'section');
const
newChunkSize = await component.evaluate((ctx) => ctx.requestParams.get.chunkSize);
await h.dom.waitForEl(container, `section:nth-child(${newChunkSize - 1})`);
expect(await getContainerChildCount()).toBe(newChunkSize);
});
});
describe('by changing the `request` prop while second data batch loading is in progress', () => {
it('should render first chunk with correct data', async () => {
await component.evaluate((ctx) => {
ctx.dataProvider = 'demo.Pagination';
ctx.chunkSize = 2;
ctx.request = {get: {chunkSize: 2, delay: 1500, id: Math.random()}};
});
await h.dom.waitForEl(container, 'section');
await component.evaluate((ctx) => {
ctx.dataProvider = 'demo.Pagination';
ctx.chunkSize = 2;
ctx.request = {get: {chunkSize: 2, i: 10, total: 2, delay: 1500, id: Math.random()}};
});
expect(await h.dom.waitForEl(container, '[data-index="10"]'));
expect(await getContainerChildCount()).toBe(2);
});
});
describe('by changing the `dataProvider` prop', () => {
it('removes old elements', async () => {
await setProps();
await component.evaluate((ctx) => ctx.dataProvider = undefined);
await h.dom.waitForEl(container, 'section', {to: 'unmount'});
expect(await component.evaluate((ctx) => ctx.$refs.container.childElementCount === 0)).toBeTrue();
});
it('renders new', async () => {
await h.dom.waitForEl(container, 'section', {to: 'unmount'});
expect(await component.evaluate((ctx) => ctx.$refs.container.childElementCount === 0)).toBeTrue();
await component.evaluate((ctx) => ctx.dataProvider = 'demo.Pagination');
await h.dom.waitForEl(container, 'section');
expect(await getContainerChildCount()).toBeGreaterThan(0);
});
});
});
describe('with `options`', () => {
it('renders the first chunk', async () => {
const
chunkSize = await component.evaluate((ctx) => ctx.chunkSize);
await component.evaluate((ctx) => ctx.options = Array.from(Array(40), (v, i) => ({i})));
await h.dom.waitForEl(container, 'section');
expect(await getContainerChildCount()).toBe(chunkSize);
});
it('renders all available `options`', async () => {
await component.evaluate((ctx) => ctx.options = Array.from(Array(40), (v, i) => ({i})));
await h.dom.waitForEl(container, 'section');
const
total = await component.evaluate((ctx) => ctx.options.length),
checkFn = async () => await getContainerChildCount() === total;
await h.scroll.scrollToBottomWhile(page, checkFn, {timeout: 1e5});
expect(await getContainerChildCount()).toBe(total);
});
it('does not render more than received data', async () => {
await component.evaluate((ctx) => ctx.options = Array.from(Array(40), (v, i) => ({i})));
await h.dom.waitForEl(container, 'section');
const
total = await component.evaluate((ctx) => ctx.options.length),
checkFn = async () => await getContainerChildCount() === total;
await h.scroll.scrollToBottomWhile(page, checkFn, {timeout: 1e5});
expect(await getContainerChildCount()).toBe(total);
await h.bom.waitForIdleCallback(page);
await h.scroll.scrollToBottom(page);
expect(await getContainerChildCount()).toBe(total);
});
});
describe('with `dataProvider`', () => {
it('renders the first chunk', async () => {
await setProps();
const
chunkSize = await component.evaluate((ctx) => ctx.chunkSize);
expect(await getContainerChildCount()).toBe(chunkSize);
});
it('renders all available items', async () => {
await setProps({total: 40});
const
total = await component.evaluate((ctx) => ctx.requestParams.get.total),
checkFn = async () => await getContainerChildCount() === total;
await h.scroll.scrollToBottomWhile(page, checkFn, {timeout: 1e5});
expect(await getContainerChildCount()).toBe(total);
});
it('does not render more than received data', async () => {
await setProps({total: 40});
const
total = await component.evaluate((ctx) => ctx.requestParams.get.total),
checkFn = async () => await getContainerChildCount() === total;
await h.scroll.scrollToBottomWhile(page, checkFn, {timeout: 1e5});
expect(await getContainerChildCount()).toBe(total);
await h.bom.waitForIdleCallback(page);
await h.scroll.scrollToBottom(page);
expect(await getContainerChildCount()).toBe(total);
});
it('renders the first chunk with 3 requests to get the full chunk', async () => {
await setProps({chunkSize: 4});
const
chunkSize = await component.evaluate((ctx) => ctx.chunkSize);
await h.dom.waitForEl(container, 'section');
expect(await getContainerChildCount()).toBe(chunkSize);
});
it('renders the first chunk with truncated data in all loaded chunks', async () => {
await component.evaluate((ctx) => {
ctx.dataProvider = 'demo.Pagination';
ctx.chunkSize = 4;
ctx.request = {get: {chunkSize: 8, total: 32, id: 'uniq'}};
ctx.dbConverter = ({data}) => ({data: data.splice(0, 1)});
});
const
chunkSize = await component.evaluate((ctx) => ctx.chunkSize);
await h.dom.waitForEl(container, 'section');
expect(await getContainerChildCount()).toBe(chunkSize);
});
it('renders all data if `shouldStopRequest` returns true', async () => {
await component.evaluate((ctx) => {
ctx.dataProvider = 'demo.Pagination';
ctx.chunkSize = 10;
ctx.request = {get: {chunkSize: 40, total: 80, id: Math.random(), delay: 100}};
ctx.shouldStopRequest = ({data}) => data.length === 80;
});
const
checkFn = async () => await getContainerChildCount() === 80;
await h.scroll.scrollToBottomWhile(page, checkFn, {timeout: 1e5});
expect(await getContainerChildCount()).toBe(80);
});
});
describe('without `options` and` dataProvider` specified', () => {
it('does not render anything', async () => {
expect(await component.evaluate((ctx) => ctx.options.length === 0)).toBeTrue();
expect(await component.evaluate((ctx) => ctx.dataProvider === undefined)).toBeTrue();
expect(await component.evaluate((ctx) => ctx.$refs.container.childElementCount === 0)).toBeTrue();
});
});
});
};