text: // @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');
  
  /** @param {Page} page */
  module.exports = (page) => {
  	let
  		component,
  		node,
  		container;
  
  	const
  		getArray = (offset = 0, length = 12) => ({data: Array.from(Array(length), (v, i) => ({i: i + offset}))}),
  		firstChunkExpected = getArray();
  
  	const setProps = (requestProps = {}) => component.evaluate((ctx, requestProps) => {
  		ctx.dataProvider = 'demo.Pagination';
  		ctx.chunkSize = 10;
  		ctx.request = {get: {chunkSize: 12, id: Math.random(), ...requestProps}};
  	}, requestProps);
  
  	const subscribe = () => component.evaluate((ctx) => new Promise((res) => ctx.watch(':onDBChange', res)));
  
  	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);
  		});
  
  		await h.bom.waitForIdleCallback(page);
  		await h.component.waitForComponentStatus(page, '.b-virtual-scroll', 'ready');
  
  		component = await h.component.waitForComponent(page, '#target');
  		node = await h.dom.waitForEl(page, '#target');
  		container = await h.dom.waitForRef(node, 'container');
  	});
  
  	describe('b-virtual-scroll `dbChange` event', () => {
  		describe('emitted', () => {
  			it('after loading the first chunk', async () => {
  				const subscribePromise = subscribe();
  				await setProps();
  
  				await expectAsync(subscribePromise).toBeResolved();
  			});
  
  			it('after loading the second chunk', async () => {
  				await setProps();
  				await h.dom.waitForEl(container, 'section');
  
  				const subscribePromise = subscribe();
  
  				await h.scroll.scrollToBottom(page);
  				await expectAsync(subscribePromise).toBeResolved();
  			});
  
  			it('after loading the first chunk after re-initialization', async () => {
  				await setProps();
  				await h.dom.waitForEl(container, 'section');
  
  				const subscribePromise = subscribe();
  
  				await component.evaluate((ctx) => ctx.request = {get: {chunkSize: 20}});
  				await expectAsync(subscribePromise).toBeResolved();
  			});
  
  			it('three times to get the full data batch', async () => {
  				await component.evaluate((ctx) => {
  					ctx.watch(':onDBChange', () => {
  						ctx.tmp.called = (ctx.tmp.called ?? 0) + 1;
  					});
  				});
  
  				await setProps({chunkSize: 4});
  				await h.dom.waitForEl(container, 'section');
  
  				expect(await component.evaluate((ctx) => ctx.tmp.called)).toBe(3);
  			});
  
  			it('after successful loading of the first chunk without payload', async () => {
  				const subscribePromise = subscribe();
  
  				await setProps({chunkSize: 0, total: 0});
  
  				await expectAsync(subscribePromise).toBeResolved();
  			});
  		});
  
  		describe('not emitted', () => {
  			it('if there was a request error', async () => {
  				await component.evaluate((ctx) => {
  					ctx.watch(':onDBChange', () => {
  						ctx.tmp.called = (ctx.tmp.called ?? 0) + 1;
  					});
  				});
  
  				await setProps({failOn: 0});
  				await h.bom.waitForIdleCallback(page, {sleepAfterIdles: 500});
  
  				expect(await component.evaluate((ctx) => ctx.tmp.called)).toBeUndefined();
  			});
  
  			it('after successful loading of the second chunk without payload', async () => {
  				await setProps({chunkSize: 12, total: 12});
  				await h.dom.waitForEl(container, 'section');
  
  				await component.evaluate((ctx) => {
  					ctx.watch(':onDBChange', () => {
  						ctx.tmp.called = (ctx.tmp.called ?? 0) + 1;
  					});
  				});
  
  				await h.scroll.scrollToBottom(page);
  				expect(await component.evaluate((ctx) => ctx.tmp.called)).toBeUndefined();
  			});
  		});
  
  		describe('has correct payload', () => {
  			it('after loading the first chunk', async () => {
  				const subscribePromise = subscribe();
  
  				await setProps({chunkSize: 4});
  				await h.dom.waitForEl(container, 'section');
  
  				await expectAsync(subscribePromise).toBeResolvedTo(getArray(0, 4));
  			});
  
  			it('after loading two chunks', async () => {
  				await component.evaluate((ctx) => {
  					ctx.watch(':onDBChange', (val) => {
  						ctx.tmp.called = (ctx.tmp.called ?? 0) + 1;
  						ctx.tmp[ctx.tmp.called] = Object.fastClone(val);
  					});
  				});
  
  				await setProps({chunkSize: 6});
  				await h.dom.waitForEl(container, 'section');
  
  				expect(await component.evaluate((ctx) => ctx.tmp[1])).toEqual(getArray(0, 6));
  				expect(await component.evaluate((ctx) => ctx.tmp[2])).toEqual(getArray(0, 12));
  
  			});
  
  			it('after re-initialization and loading the first chunk', async () => {
  				await setProps({chunkSize: 6});
  				await h.dom.waitForEl(container, 'section');
  
  				const subscribePromise = subscribe();
  
  				await setProps({chunkSize: 12, id: Math.random()});
  				await expectAsync(subscribePromise).toBeResolvedTo(firstChunkExpected);
  			});
  		});
  	});
  };
  