mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-05 05:00:58 +00:00
API date filter updates (#8544)
* Add 'stocktake_before' and 'stocktake_after' filters for StockItem API * Enable new filters for StockItemTable * Update CUI table filters * Add more date filter options for orders * Add date filters to BuildList * Update BuildOrderTable filters * Add more order date filters * Cleanup PurchaseOrderFilter code * Implement more PUI table filters * Add "Completion Date" column to PurchaseOrderTable * Update ReturnOrderTable * Add 'text' option for TableFilter * filter state management * Bump API version * Sorting for table filters * Add playwright tests for stock table filtering * Playwright updates - Add some helper functions for common operations * Refactoring for Playwright tests
This commit is contained in:
46
src/frontend/tests/helpers.ts
Normal file
46
src/frontend/tests/helpers.ts
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Open the filter drawer for the currently visible table
|
||||
* @param page - The page object
|
||||
*/
|
||||
export const openFilterDrawer = async (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) => {
|
||||
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, name, 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) => {
|
||||
await openFilterDrawer(page);
|
||||
await clickButtonIfVisible(page, 'Clear Filters');
|
||||
await page.getByLabel('filter-drawer-close').click();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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();
|
||||
};
|
@ -1,8 +1,13 @@
|
||||
import { test } from '../baseFixtures.ts';
|
||||
import { baseUrl } from '../defaults.ts';
|
||||
import {
|
||||
clickButtonIfVisible,
|
||||
getRowFromCell,
|
||||
openFilterDrawer
|
||||
} from '../helpers.ts';
|
||||
import { doQuickLogin } from '../login.ts';
|
||||
|
||||
test('Pages - Build Order', async ({ page }) => {
|
||||
test('Build Order - Basic Tests', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/part/`);
|
||||
@ -82,7 +87,7 @@ test('Pages - Build Order', async ({ page }) => {
|
||||
.waitFor();
|
||||
});
|
||||
|
||||
test('Pages - Build Order - Build Outputs', async ({ page }) => {
|
||||
test('Build Order - Build Outputs', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/part/`);
|
||||
@ -140,7 +145,7 @@ test('Pages - Build Order - Build Outputs', async ({ page }) => {
|
||||
|
||||
// Cancel one of the newly created outputs
|
||||
const cell = await page.getByRole('cell', { name: `# ${sn}` });
|
||||
const row = await cell.locator('xpath=ancestor::tr').first();
|
||||
const row = await getRowFromCell(cell);
|
||||
await row.getByLabel(/row-action-menu-/i).click();
|
||||
await page.getByRole('menuitem', { name: 'Cancel' }).click();
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
@ -148,7 +153,7 @@ test('Pages - Build Order - Build Outputs', async ({ page }) => {
|
||||
|
||||
// Complete the other output
|
||||
const cell2 = await page.getByRole('cell', { name: `# ${sn + 1}` });
|
||||
const row2 = await cell2.locator('xpath=ancestor::tr').first();
|
||||
const row2 = await getRowFromCell(cell2);
|
||||
await row2.getByLabel(/row-action-menu-/i).click();
|
||||
await page.getByRole('menuitem', { name: 'Complete' }).click();
|
||||
await page.getByLabel('related-field-location').click();
|
||||
@ -158,7 +163,7 @@ test('Pages - Build Order - Build Outputs', async ({ page }) => {
|
||||
await page.getByText('Build outputs have been completed').waitFor();
|
||||
});
|
||||
|
||||
test('Pages - Build Order - Allocation', async ({ page }) => {
|
||||
test('Build Order - Allocation', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/manufacturing/build-order/1/line-items`);
|
||||
@ -170,7 +175,7 @@ test('Pages - Build Order - Allocation', async ({ page }) => {
|
||||
|
||||
// The capacitor stock should be fully allocated
|
||||
const cell = await page.getByRole('cell', { name: /C_1uF_0805/ });
|
||||
const row = await cell.locator('xpath=ancestor::tr').first();
|
||||
const row = await getRowFromCell(cell);
|
||||
|
||||
await row.getByText(/150 \/ 150/).waitFor();
|
||||
|
||||
@ -237,7 +242,7 @@ test('Pages - Build Order - Allocation', async ({ page }) => {
|
||||
const item = data[idx];
|
||||
|
||||
const cell = await page.getByRole('cell', { name: item.name });
|
||||
const row = await cell.locator('xpath=ancestor::tr').first();
|
||||
const row = await getRowFromCell(cell);
|
||||
const progress = `${item.allocated} / ${item.required}`;
|
||||
|
||||
await row.getByRole('cell', { name: item.ipn }).first().waitFor();
|
||||
@ -257,3 +262,14 @@ test('Pages - Build Order - Allocation', async ({ page }) => {
|
||||
.getByRole('menuitem', { name: 'Deallocate Stock', exact: true })
|
||||
.waitFor();
|
||||
});
|
||||
|
||||
test('Build Order - Filters', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/manufacturing/index/buildorders`);
|
||||
|
||||
await openFilterDrawer(page);
|
||||
await clickButtonIfVisible(page, 'Clear Filters');
|
||||
|
||||
await page.waitForTimeout(2500);
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ import { test } from '../baseFixtures.js';
|
||||
import { doQuickLogin } from '../login.js';
|
||||
import { setPluginState } from '../settings.js';
|
||||
|
||||
test('Pages - Dashboard - Basic', async ({ page }) => {
|
||||
test('Dashboard - Basic', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.getByText('Use the menu to add widgets').waitFor();
|
||||
@ -35,7 +35,7 @@ test('Pages - Dashboard - Basic', async ({ page }) => {
|
||||
await page.getByLabel('dashboard-accept-layout').click();
|
||||
});
|
||||
|
||||
test('Pages - Dashboard - Plugins', async ({ page, request }) => {
|
||||
test('Dashboard - Plugins', async ({ page, request }) => {
|
||||
// Ensure that the "SampleUI" plugin is enabled
|
||||
await setPluginState({
|
||||
request,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { test } from '../baseFixtures';
|
||||
import { baseUrl } from '../defaults';
|
||||
import { getRowFromCell } from '../helpers';
|
||||
import { doQuickLogin } from '../login';
|
||||
|
||||
/**
|
||||
@ -129,9 +130,7 @@ test('Parts - Allocations', async ({ page }) => {
|
||||
|
||||
// Check "progress" bar of BO0001
|
||||
const build_order_cell = await page.getByRole('cell', { name: 'BO0001' });
|
||||
const build_order_row = await build_order_cell
|
||||
.locator('xpath=ancestor::tr')
|
||||
.first();
|
||||
const build_order_row = await getRowFromCell(build_order_cell);
|
||||
await build_order_row.getByText('11 / 75').waitFor();
|
||||
|
||||
// Expand allocations against BO0001
|
||||
@ -147,9 +146,7 @@ test('Parts - Allocations', async ({ page }) => {
|
||||
|
||||
// Check "progress" bar of SO0025
|
||||
const sales_order_cell = await page.getByRole('cell', { name: 'SO0025' });
|
||||
const sales_order_row = await sales_order_cell
|
||||
.locator('xpath=ancestor::tr')
|
||||
.first();
|
||||
const sales_order_row = await getRowFromCell(sales_order_cell);
|
||||
await sales_order_row.getByText('3 / 10').waitFor();
|
||||
|
||||
// Expand allocations against SO0025
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { test } from '../baseFixtures.ts';
|
||||
import { clickButtonIfVisible, openFilterDrawer } from '../helpers.ts';
|
||||
import { doQuickLogin } from '../login.ts';
|
||||
|
||||
test('Purchase Orders - General', async ({ page }) => {
|
||||
@ -51,6 +52,30 @@ test('Purchase Orders - General', async ({ page }) => {
|
||||
await page.getByRole('tab', { name: 'Details' }).waitFor();
|
||||
});
|
||||
|
||||
test('Purchase Orders - Filters', async ({ page }) => {
|
||||
await doQuickLogin(page, 'reader', 'readonly');
|
||||
|
||||
await page.getByRole('tab', { name: 'Purchasing' }).click();
|
||||
await page.getByRole('tab', { name: 'Purchase Orders' }).click();
|
||||
|
||||
// Open filters drawer
|
||||
await openFilterDrawer(page);
|
||||
await clickButtonIfVisible(page, 'Clear Filters');
|
||||
|
||||
await page.getByRole('button', { name: 'Add Filter' }).click();
|
||||
|
||||
// Check for expected filter options
|
||||
await page.getByPlaceholder('Select filter').fill('before');
|
||||
await page.getByRole('option', { name: 'Created Before' }).waitFor();
|
||||
await page.getByRole('option', { name: 'Completed Before' }).waitFor();
|
||||
await page.getByRole('option', { name: 'Target Date Before' }).waitFor();
|
||||
|
||||
await page.getByPlaceholder('Select filter').fill('after');
|
||||
await page.getByRole('option', { name: 'Created After' }).waitFor();
|
||||
await page.getByRole('option', { name: 'Completed After' }).waitFor();
|
||||
await page.getByRole('option', { name: 'Target Date After' }).waitFor();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests for receiving items against a purchase order
|
||||
*/
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { test } from '../baseFixtures.js';
|
||||
import { baseUrl } from '../defaults.js';
|
||||
import { clickButtonIfVisible, openFilterDrawer } from '../helpers.js';
|
||||
import { doQuickLogin } from '../login.js';
|
||||
|
||||
test('Stock', async ({ page }) => {
|
||||
test('Stock - Basic Tests', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/stock/location/index/`);
|
||||
@ -49,6 +50,45 @@ test('Stock - Location Tree', async ({ page }) => {
|
||||
await page.getByRole('cell', { name: 'Factory' }).first().waitFor();
|
||||
});
|
||||
|
||||
test('Stock - Filters', async ({ page }) => {
|
||||
await doQuickLogin(page, 'steven', 'wizardstaff');
|
||||
|
||||
await page.goto(`${baseUrl}/stock/location/index/`);
|
||||
await page.getByRole('tab', { name: 'Stock Items' }).click();
|
||||
|
||||
await openFilterDrawer(page);
|
||||
await clickButtonIfVisible(page, 'Clear Filters');
|
||||
|
||||
// Filter by updated date
|
||||
await page.getByRole('button', { name: 'Add Filter' }).click();
|
||||
await page.getByPlaceholder('Select filter').fill('updated');
|
||||
await page.getByText('Updated After').click();
|
||||
await page.getByPlaceholder('Select date value').fill('2010-01-01');
|
||||
await page.getByText('Show items updated after this date').waitFor();
|
||||
|
||||
// Filter by batch code
|
||||
await page.getByRole('button', { name: 'Add Filter' }).click();
|
||||
await page.getByPlaceholder('Select filter').fill('batch');
|
||||
await page
|
||||
.getByRole('option', { name: 'Batch Code', exact: true })
|
||||
.locator('span')
|
||||
.click();
|
||||
await page.getByPlaceholder('Enter filter value').fill('TABLE-B02');
|
||||
await page.getByLabel('apply-text-filter').click();
|
||||
|
||||
// Close dialog
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
// Ensure correct result is displayed
|
||||
await page
|
||||
.getByRole('cell', { name: 'A round table - with blue paint' })
|
||||
.waitFor();
|
||||
|
||||
// Clear filters (ready for next set of tests)
|
||||
await openFilterDrawer(page);
|
||||
await clickButtonIfVisible(page, 'Clear Filters');
|
||||
});
|
||||
|
||||
test('Stock - Serial Numbers', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
import { test } from './baseFixtures.js';
|
||||
import { baseUrl } from './defaults.js';
|
||||
import {
|
||||
clearTableFilters,
|
||||
closeFilterDrawer,
|
||||
openFilterDrawer
|
||||
} from './helpers.js';
|
||||
import { doQuickLogin } from './login.js';
|
||||
|
||||
// Helper function to set the value of a specific table filter
|
||||
const setFilter = async (page, name: string, value: string) => {
|
||||
await page.getByLabel('table-select-filters').click();
|
||||
await openFilterDrawer(page);
|
||||
|
||||
await page.getByRole('button', { name: 'Add Filter' }).click();
|
||||
await page.getByPlaceholder('Select filter').click();
|
||||
await page.getByRole('option', { name: name, exact: true }).click();
|
||||
await page.getByPlaceholder('Select filter value').click();
|
||||
await page.getByRole('option', { name: value, exact: true }).click();
|
||||
await page.getByLabel('filter-drawer-close').click();
|
||||
};
|
||||
|
||||
// Helper function to clear table filters
|
||||
const clearFilters = async (page) => {
|
||||
await page.getByLabel('table-select-filters').click();
|
||||
await page.getByRole('button', { name: 'Clear Filters' }).click();
|
||||
await page.getByLabel('filter-drawer-close').click();
|
||||
await closeFilterDrawer(page);
|
||||
};
|
||||
|
||||
test('Tables - Filters', async ({ page }) => {
|
||||
@ -30,14 +30,14 @@ test('Tables - Filters', async ({ page }) => {
|
||||
await setFilter(page, 'Responsible', 'allaccess');
|
||||
await setFilter(page, 'Project Code', 'PRJ-NIM');
|
||||
|
||||
await clearFilters(page);
|
||||
await clearTableFilters(page);
|
||||
|
||||
// Head to the "part list" page
|
||||
await page.goto(`${baseUrl}/part/category/index/parts/`);
|
||||
|
||||
await setFilter(page, 'Assembly', 'Yes');
|
||||
|
||||
await clearFilters(page);
|
||||
await clearTableFilters(page);
|
||||
|
||||
// Head to the "purchase order list" page
|
||||
await page.goto(`${baseUrl}/purchasing/index/purchaseorders/`);
|
||||
@ -47,7 +47,7 @@ test('Tables - Filters', async ({ page }) => {
|
||||
await setFilter(page, 'Assigned to me', 'No');
|
||||
await setFilter(page, 'Project Code', 'PRO-ZEN');
|
||||
|
||||
await clearFilters(page);
|
||||
await clearTableFilters(page);
|
||||
});
|
||||
|
||||
test('Tables - Columns', async ({ page }) => {
|
||||
|
Reference in New Issue
Block a user