@v4fire/client
Version:
V4Fire client core library
239 lines (205 loc) • 6.69 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
import type { Locator, Page } from 'playwright';
import { ComponentObject, Scroll } from 'tests/helpers';
import type bVirtualScrollNew from 'base/b-virtual-scroll-new/b-virtual-scroll-new';
import type { ComponentRefs, VirtualScrollState } from 'base/b-virtual-scroll-new/interface';
import type { SlotsStateObj } from 'base/b-virtual-scroll-new/modules/slots';
import { testStyles } from 'base/b-virtual-scroll-new/test/api/component-object/styles';
/**
* The component object API for testing the {@link bVirtualScrollNew} component.
*/
export class VirtualScrollComponentObject extends ComponentObject<bVirtualScrollNew['unsafe']> {
/**
* The locator for the container ref.
*/
readonly container: Locator;
/**
* The locator to select all children in the container ref.
*/
readonly childList: Locator;
override get componentStyles(): string {
return testStyles;
}
/**
* @param page - the Playwright page instance.
*/
constructor(page: Page) {
super(page, 'b-virtual-scroll-new');
this.container = this.node.locator(this.elSelector('container'));
this.childList = this.container.locator('> *');
}
/**
* Calls the reload method of the component
* {@link bVirtualScrollNew.reload}
*/
reload(): Promise<void> {
return this.evaluate((ctx) => ctx.reload());
}
/**
* Returns the internal component state
* {@link bVirtualScrollNew.getVirtualScrollState}
*/
getVirtualScrollState(): Promise<VirtualScrollState> {
return this.evaluate((ctx) => ctx.getVirtualScrollState());
}
/**
* Returns the count of children in the container ref
*/
getChildCount(): Promise<number> {
return this.childList.count();
}
/**
* Waits for the container child count to be equal to N.
* Throws an error if there are more items in the child list than expected.
*
* @param count - the expected child count.
*/
async waitForChildCountEqualsTo(count: number): Promise<void> {
await this.childList.nth(count - 1).waitFor({state: 'attached'});
const realCount = await this.childList.count();
if (realCount > count) {
throw new Error(`Expected container to have exactly ${count} items, but got ${realCount}`);
}
}
/**
* Returns a promise that resolves when an element matching the given selector is inserted into the container.
*
* @param selector - the selector to match the element.
* @returns A promise that resolves when the element is attached.
*/
async waitForChild(selector: string): Promise<void> {
await this.container.locator(selector).waitFor({state: 'attached'});
}
/**
* Returns a promise that resolves when an element with the attribute data-index="n" is inserted into the container.
*
* @param index - the index value for the data-index attribute.
* @returns A promise that resolves when the element is attached.
*/
async waitForDataIndexChild(index: number): Promise<void> {
return this.waitForChild(`[data-index="${index}"]`);
}
/**
* Returns a promise that resolves when the specified event occurs.
*
* @param eventName - the name of the event to wait for.
* @returns A promise that resolves to the payload of the event, or `undefined`.
*/
async waitForEvent<PAYLOAD extends unknown>(eventName: string): Promise<CanUndef<PAYLOAD>> {
return this.evaluate((ctx, [eventName]) => ctx.promisifyOnce(eventName), <const>[eventName]);
}
/**
* Waits for the component lifecycle to be done
*/
async waitForLifecycleDone(): Promise<void> {
await this.evaluate((ctx) => {
const state = ctx.getVirtualScrollState();
if (state.isLifecycleDone) {
return;
}
return ctx.unsafe.componentEmitter.promisifyOnce('lifecycleDone');
});
}
/**
* Waits for the provided slot to reach the specified visibility state.
*
* @param slotName - the name of the slot.
* @param isVisible - the expected visibility state.
* @param timeout - the timeout for waiting (optional).
*/
async waitForSlotState(slotName: keyof ComponentRefs, isVisible: boolean, timeout?: number): Promise<void> {
const slot = this.node.locator(this.elSelector(slotName.dasherize()));
await slot.waitFor({state: isVisible ? 'visible' : 'hidden', timeout});
}
/**
* Returns an object representing the state of all slots.
* Each slot is represented as [slotName: slotState], where `slotState=true` means the slot is visible.
*/
async getSlotsState(): Promise<Required<SlotsStateObj>> {
const
container = this.node.locator(this.elSelector('container')),
loader = this.node.locator(this.elSelector('loader')),
tombstones = this.node.locator(this.elSelector('tombstones')),
empty = this.node.locator(this.elSelector('empty')),
retry = this.node.locator(this.elSelector('retry')),
done = this.node.locator(this.elSelector('done')),
renderNext = this.node.locator(this.elSelector('render-next'));
return {
container: await container.isVisible(),
loader: await loader.isVisible(),
tombstones: await tombstones.isVisible(),
empty: await empty.isVisible(),
retry: await retry.isVisible(),
done: await done.isVisible(),
renderNext: await renderNext.isVisible()
};
}
/**
* Scrolls the page to the bottom
*/
async scrollToBottom(): Promise<this> {
await Scroll.scrollToBottom(this.pwPage);
return this;
}
/**
* Scrolls the page to the top
*/
async scrollToTop(): Promise<this> {
await Scroll.scrollToTop(this.pwPage);
return this;
}
/**
* Adds default `itemProps` for pagination
*/
withPaginationItemProps(): this {
this.withProps({
item: 'section',
itemProps: (item) => ({'data-index': item.i})
});
return this;
}
/**
* Adds a `requestProp` for pagination.
*
* @param requestParams - the request parameters.
*/
withRequestPaginationProps(requestParams: Dictionary = {}): this {
this.withProps({
request: {
get: {
chunkSize: 10,
id: Math.random(),
...requestParams
}
}
});
return this;
}
/**
* Adds a `Provider` into the provider prop for pagination
*/
withPaginationProvider(): this {
this.withProps({dataProvider: 'Provider'});
return this;
}
/**
* Calls all default pagination prop setters:
* - `withPaginationProvider`
* - `withPaginationItemProps`
* - `withRequestProp`
*
* @param requestParams - the request parameters.
*/
withDefaultPaginationProviderProps(requestParams: Dictionary = {}): this {
this.withPaginationProvider();
this.withPaginationItemProps();
this.withRequestPaginationProps(requestParams);
return this;
}
}