mirror of
https://github.com/inventree/InvenTree.git
synced 2026-02-13 09:47:09 +00:00
* Additional filtering options for stock list * Fix ordering for stock table * Ordering fix for build order table * Ordering for supplier parts and manufacturer parts * SalesOrderLineItem: Order by IPN * ReturnOrderLineItem table: - Order by part name - Order by part IPN * Update API version to 451 Increment API version to 451 and update changelog. * Add playwright tests for column sorting * Add backend tests for API ordering --------- Co-authored-by: Matthias Mair <code@mjmair.com>
183 lines
5.1 KiB
TypeScript
183 lines
5.1 KiB
TypeScript
import { type Page, expect } from '@playwright/test';
|
|
import { createApi } from './api';
|
|
|
|
export const clickOnParamFilter = async (page: Page, name: string) => {
|
|
const button = await page
|
|
.getByRole('button', { name: `${name} Not sorted` })
|
|
.getByRole('button')
|
|
.first();
|
|
await button.scrollIntoViewIfNeeded();
|
|
await button.click();
|
|
};
|
|
|
|
/**
|
|
* Open the filter drawer for the currently visible table
|
|
* @param page - The page object
|
|
*/
|
|
export const openFilterDrawer = async (page: Page) => {
|
|
await page.getByLabel('table-select-filters').click();
|
|
};
|
|
|
|
/**
|
|
* Close the filter drawer for the currently visible table
|
|
* @param page - The page object
|
|
*/
|
|
export const closeFilterDrawer = async (page: Page) => {
|
|
await page.getByLabel('filter-drawer-close').click();
|
|
};
|
|
|
|
/**
|
|
* Click the specified button (if it is visible)
|
|
* @param page - The page object
|
|
* @param name - The name of the button to click
|
|
*/
|
|
export const clickButtonIfVisible = async (
|
|
page: Page,
|
|
name: string,
|
|
timeout = 500
|
|
) => {
|
|
await page.waitForTimeout(timeout);
|
|
|
|
if (await page.getByRole('button', { name }).isVisible()) {
|
|
await page.getByRole('button', { name }).click();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Clear all filters from the currently visible table
|
|
* @param page - The page object
|
|
*/
|
|
export const clearTableFilters = async (page: Page) => {
|
|
await openFilterDrawer(page);
|
|
await clickButtonIfVisible(page, 'Clear Filters', 250);
|
|
await closeFilterDrawer(page);
|
|
await page.waitForLoadState('networkidle');
|
|
};
|
|
|
|
export const setTableChoiceFilter = async (
|
|
page: Page,
|
|
filter: string,
|
|
value: string
|
|
) => {
|
|
await openFilterDrawer(page);
|
|
|
|
await page.getByRole('button', { name: 'Add Filter' }).click();
|
|
await page.getByPlaceholder('Select filter').fill(filter);
|
|
await page.getByPlaceholder('Select filter').click();
|
|
|
|
// Construct a regex to match the filter name exactly
|
|
const filterRegex = new RegExp(`^${filter}$`, 'i');
|
|
|
|
await page.getByRole('option', { name: filterRegex }).click();
|
|
|
|
await page.getByPlaceholder('Select filter value').click();
|
|
await page.getByRole('option', { name: value }).click();
|
|
|
|
await page.waitForLoadState('networkidle');
|
|
await closeFilterDrawer(page);
|
|
};
|
|
|
|
/**
|
|
* Return the parent 'row' element for a given 'cell' element
|
|
* @param cell - The cell element
|
|
*/
|
|
export const getRowFromCell = async (cell) => {
|
|
return cell.locator('xpath=ancestor::tr').first();
|
|
};
|
|
|
|
export const clickOnRowMenu = async (cell) => {
|
|
const row = await getRowFromCell(cell);
|
|
|
|
await row.getByLabel(/row-action-menu-/i).click();
|
|
};
|
|
|
|
interface NavigateOptions {
|
|
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';
|
|
baseUrl?: string;
|
|
}
|
|
|
|
/**
|
|
* Navigate to the provided page, and wait for loading to complete
|
|
* @param page
|
|
* @param url
|
|
*/
|
|
export const navigate = async (
|
|
page,
|
|
url: string,
|
|
options?: NavigateOptions
|
|
) => {
|
|
if (!url.startsWith('http') && !url.includes('web')) {
|
|
url = `/web/${url}`.replaceAll('//', '/');
|
|
}
|
|
|
|
const path: string = options?.baseUrl
|
|
? new URL(url, options.baseUrl).toString()
|
|
: url;
|
|
|
|
await page.goto(path, { waitUntil: options?.waitUntil ?? 'load' });
|
|
};
|
|
|
|
/**
|
|
* CLick on the 'tab' element with the provided name
|
|
*/
|
|
export const loadTab = async (page: Page, tabName: string, exact?: boolean) => {
|
|
await page
|
|
.getByLabel(/panel-tabs-/)
|
|
.getByRole('tab', { name: tabName, exact: exact ?? false })
|
|
.click();
|
|
|
|
await page.waitForLoadState('networkidle');
|
|
};
|
|
|
|
// Activate "table" view in certain contexts
|
|
export const activateTableView = async (page: Page) => {
|
|
await page.getByLabel('segmented-icon-control-table').click();
|
|
await page.waitForLoadState('networkidle');
|
|
};
|
|
|
|
// Activate "calendar" view in certain contexts
|
|
export const activateCalendarView = async (page: Page) => {
|
|
await page.getByLabel('segmented-icon-control-calendar').click();
|
|
await page.waitForLoadState('networkidle');
|
|
};
|
|
|
|
/**
|
|
* Perform a 'global search' on the provided page, for the provided query text
|
|
*/
|
|
export const globalSearch = async (page: Page, query: string) => {
|
|
await page.getByLabel('open-search').click();
|
|
await page.getByLabel('global-search-input').clear();
|
|
await page.getByPlaceholder('Enter search text').fill(query);
|
|
await page.waitForTimeout(300);
|
|
};
|
|
|
|
export const deletePart = async (name: string) => {
|
|
const api = await createApi({});
|
|
const parts = await api
|
|
.get('part/', {
|
|
params: { search: name }
|
|
})
|
|
.then((res) => res.json());
|
|
const existingPart = parts.find((p: any) => p.name === name);
|
|
if (existingPart) {
|
|
await api.patch(`part/${existingPart.pk}/`, {
|
|
data: { active: false }
|
|
});
|
|
const res = await api.delete(`part/${existingPart.pk}/`);
|
|
expect(res.status()).toBe(204);
|
|
}
|
|
};
|
|
|
|
// Click on the column sorting toggle
|
|
export const toggleColumnSorting = async (page: Page, columnName: string) => {
|
|
// Click on the column header to toggle sorting
|
|
const regex = new RegExp(
|
|
`^${columnName}\\s*(Not sorted|Sorted ascending|Sorted descending)$`,
|
|
'i'
|
|
);
|
|
|
|
await page.getByRole('button', { name: regex }).click();
|
|
await page.waitForTimeout(50);
|
|
await page.waitForLoadState('networkidle');
|
|
};
|