mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-22 23:00:54 +00:00
[Refactor] Serial generation (#8246)
* Refactor "update_serial_number" method * Refactor serial number validation - Query is much more efficient now - Does not have to check each serial number individually - Makes use of existing Part class method * Refactor creation of multiple stock items * Fix for singular item creation * Refactor serializeStock method: - Push "rebuild tree" to background worker - Use bulk_create actions * Refactor createion of serialized build outputs * Prevent 1+N DB hits * Cleanup * Cleanup * Reinstate serial number checks * Add limit for serial number extraction * Fix cache config * Revert cache settings * Fix for unit tests * Playwright tests * Bug fix * Force False cookie mode in testing * Revert aria-label for PanelGroup items - No longer works as expected with playwright locators * Fix playwright vtest * Further updates * Playwright test adjustments * Remove duplicate locator
This commit is contained in:
src
backend
InvenTree
frontend
src
components
forms
tables
stock
tests
@ -13,6 +13,7 @@ export function SpotlightButton() {
|
||||
onClick={() => firstSpotlight.open()}
|
||||
title={t`Open spotlight`}
|
||||
variant="transparent"
|
||||
aria-label="open-spotlight"
|
||||
>
|
||||
<IconCommand />
|
||||
</ActionIcon>
|
||||
|
@ -103,7 +103,11 @@ export function Header() {
|
||||
<NavTabs />
|
||||
</Group>
|
||||
<Group>
|
||||
<ActionIcon onClick={openSearchDrawer} variant="transparent">
|
||||
<ActionIcon
|
||||
onClick={openSearchDrawer}
|
||||
variant="transparent"
|
||||
aria-label="open-search"
|
||||
>
|
||||
<IconSearch />
|
||||
</ActionIcon>
|
||||
<SpotlightButton />
|
||||
@ -119,6 +123,7 @@ export function Header() {
|
||||
<ActionIcon
|
||||
onClick={openNotificationDrawer}
|
||||
variant="transparent"
|
||||
aria-label="open-notifications"
|
||||
>
|
||||
<IconBell />
|
||||
</ActionIcon>
|
||||
|
@ -68,7 +68,13 @@ function QueryResultGroup({
|
||||
const model = getModelInfo(query.model);
|
||||
|
||||
return (
|
||||
<Paper shadow="sm" radius="xs" p="md" key={`paper-${query.model}`}>
|
||||
<Paper
|
||||
shadow="sm"
|
||||
radius="xs"
|
||||
p="md"
|
||||
key={`paper-${query.model}`}
|
||||
aria-label={`search-group-${query.model}`}
|
||||
>
|
||||
<Stack key={`stack-${query.model}`}>
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<Group justify="left" gap={5} wrap="nowrap">
|
||||
@ -84,13 +90,14 @@ function QueryResultGroup({
|
||||
color="red"
|
||||
variant="transparent"
|
||||
radius="xs"
|
||||
aria-label={`remove-search-group-${query.model}`}
|
||||
onClick={() => onRemove(query.model)}
|
||||
>
|
||||
<IconX />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
<Divider />
|
||||
<Stack>
|
||||
<Stack aria-label={`search-group-results-${query.model}`}>
|
||||
{query.results.results.map((result: any) => (
|
||||
<Anchor
|
||||
onClick={(event: any) =>
|
||||
@ -367,6 +374,7 @@ export function SearchDrawer({
|
||||
title={
|
||||
<Group justify="space-between" gap={1} wrap="nowrap">
|
||||
<TextInput
|
||||
aria-label="global-search-input"
|
||||
placeholder={t`Enter search text`}
|
||||
radius="xs"
|
||||
value={value}
|
||||
|
@ -127,9 +127,14 @@ function BasePanelGroup({
|
||||
|
||||
return (
|
||||
<Boundary label={`PanelGroup-${pageKey}`}>
|
||||
<Paper p="sm" radius="xs" shadow="xs">
|
||||
<Tabs value={currentPanel} orientation="vertical" keepMounted={false}>
|
||||
<Tabs.List justify="left">
|
||||
<Paper p="sm" radius="xs" shadow="xs" aria-label={`${pageKey}`}>
|
||||
<Tabs
|
||||
value={currentPanel}
|
||||
orientation="vertical"
|
||||
keepMounted={false}
|
||||
aria-label={`panel-group-${pageKey}`}
|
||||
>
|
||||
<Tabs.List justify="left" aria-label={`panel-tabs-${pageKey}`}>
|
||||
{allPanels.map(
|
||||
(panel) =>
|
||||
!panel.hidden && (
|
||||
|
@ -50,8 +50,10 @@ import { useGlobalSettingsState } from '../states/SettingsState';
|
||||
export function useStockFields({
|
||||
item_detail,
|
||||
part_detail,
|
||||
partId,
|
||||
create = false
|
||||
}: {
|
||||
partId?: number;
|
||||
item_detail?: any;
|
||||
part_detail?: any;
|
||||
create: boolean;
|
||||
@ -81,7 +83,7 @@ export function useStockFields({
|
||||
return useMemo(() => {
|
||||
const fields: ApiFormFieldSet = {
|
||||
part: {
|
||||
value: part,
|
||||
value: partId,
|
||||
disabled: !create,
|
||||
filters: {
|
||||
active: create ? true : undefined
|
||||
@ -201,7 +203,8 @@ export function useStockFields({
|
||||
batchCode,
|
||||
serialNumbers,
|
||||
trackable,
|
||||
create
|
||||
create,
|
||||
partId
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -401,7 +401,7 @@ export function StockItemTable({
|
||||
};
|
||||
}, [table]);
|
||||
|
||||
const stockItemFields = useStockFields({ create: true });
|
||||
const stockItemFields = useStockFields({ create: true, partId: params.part });
|
||||
|
||||
const newStockItem = useCreateApiFormModal({
|
||||
url: ApiEndpoints.stock_item_list,
|
||||
|
@ -5,7 +5,7 @@ test('Modals as admin', async ({ page }) => {
|
||||
await doQuickLogin(page, 'admin', 'inventree');
|
||||
|
||||
// use server info
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Server Information About this Inventree instance'
|
||||
@ -17,7 +17,7 @@ test('Modals as admin', async ({ page }) => {
|
||||
await page.waitForURL('**/platform/home');
|
||||
|
||||
// use license info
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'License Information Licenses for dependencies of the service'
|
||||
@ -44,7 +44,7 @@ test('Modals as admin', async ({ page }) => {
|
||||
.click();
|
||||
|
||||
// use about
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page
|
||||
.getByRole('button', { name: 'About InvenTree About the InvenTree org' })
|
||||
.click();
|
||||
|
@ -178,3 +178,53 @@ test('Purchase Orders - Barcodes', async ({ page }) => {
|
||||
await page.waitForTimeout(500);
|
||||
await page.getByRole('button', { name: 'Issue Order' }).waitFor();
|
||||
});
|
||||
|
||||
test('Purchase Orders - General', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.getByRole('tab', { name: 'Purchasing' }).click();
|
||||
await page.getByRole('cell', { name: 'PO0012' }).click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
await page.getByRole('tab', { name: 'Line Items' }).click();
|
||||
await page.getByRole('tab', { name: 'Received Stock' }).click();
|
||||
await page.getByRole('tab', { name: 'Attachments' }).click();
|
||||
await page.getByRole('tab', { name: 'Purchasing' }).click();
|
||||
await page.getByRole('tab', { name: 'Suppliers' }).click();
|
||||
await page.getByText('Arrow', { exact: true }).click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
await page.getByRole('tab', { name: 'Supplied Parts' }).click();
|
||||
await page.getByRole('tab', { name: 'Purchase Orders' }).click();
|
||||
await page.getByRole('tab', { name: 'Stock Items' }).click();
|
||||
await page.getByRole('tab', { name: 'Contacts' }).click();
|
||||
await page.getByRole('tab', { name: 'Addresses' }).click();
|
||||
await page.getByRole('tab', { name: 'Attachments' }).click();
|
||||
await page.getByRole('tab', { name: 'Purchasing' }).click();
|
||||
await page.getByRole('tab', { name: 'Manufacturers' }).click();
|
||||
await page.getByText('AVX Corporation').click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
await page.getByRole('tab', { name: 'Addresses' }).click();
|
||||
await page.getByRole('cell', { name: 'West Branch' }).click();
|
||||
await page.locator('.mantine-ScrollArea-root').click();
|
||||
await page
|
||||
.getByRole('row', { name: 'West Branch Yes Surf Avenue 9' })
|
||||
.getByRole('button')
|
||||
.click();
|
||||
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
||||
|
||||
await page.getByLabel('text-field-title').waitFor();
|
||||
await page.getByLabel('text-field-line2').waitFor();
|
||||
|
||||
// Read the current value of the cell, to ensure we always *change* it!
|
||||
const value = await page.getByLabel('text-field-line2').inputValue();
|
||||
await page
|
||||
.getByLabel('text-field-line2')
|
||||
.fill(value == 'old' ? 'new' : 'old');
|
||||
|
||||
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
||||
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
await page.getByRole('tab', { name: 'Details' }).waitFor();
|
||||
});
|
||||
|
104
src/frontend/tests/pages/pui_stock.spec.ts
Normal file
104
src/frontend/tests/pages/pui_stock.spec.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { test } from '../baseFixtures.js';
|
||||
import { baseUrl } from '../defaults.js';
|
||||
import { doQuickLogin } from '../login.js';
|
||||
|
||||
test('Stock', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/stock/location/index/`);
|
||||
await page.waitForURL('**/platform/stock/location/**');
|
||||
|
||||
await page.getByRole('tab', { name: 'Location Details' }).click();
|
||||
await page.waitForURL('**/platform/stock/location/index/details');
|
||||
|
||||
await page.getByRole('tab', { name: 'Stock Items' }).click();
|
||||
await page.getByText('1551ABK').first().click();
|
||||
|
||||
await page.getByRole('tab', { name: 'Stock', exact: true }).click();
|
||||
await page.waitForURL('**/platform/stock/**');
|
||||
await page.getByRole('tab', { name: 'Stock Locations' }).click();
|
||||
await page.getByRole('cell', { name: 'Electronics Lab' }).first().click();
|
||||
await page.getByRole('tab', { name: 'Default Parts' }).click();
|
||||
await page.getByRole('tab', { name: 'Stock Locations' }).click();
|
||||
await page.getByRole('tab', { name: 'Stock Items' }).click();
|
||||
await page.getByRole('tab', { name: 'Location Details' }).click();
|
||||
|
||||
await page.goto(`${baseUrl}/stock/item/1194/details`);
|
||||
await page.getByText('D.123 | Doohickey').waitFor();
|
||||
await page.getByText('Batch Code: BX-123-2024-2-7').waitFor();
|
||||
await page.getByRole('tab', { name: 'Stock Tracking' }).click();
|
||||
await page.getByRole('tab', { name: 'Test Data' }).click();
|
||||
await page.getByText('395c6d5586e5fb656901d047be27e1f7').waitFor();
|
||||
await page.getByRole('tab', { name: 'Installed Items' }).click();
|
||||
});
|
||||
|
||||
test('Stock - Location Tree', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/stock/location/index/`);
|
||||
await page.waitForURL('**/platform/stock/location/**');
|
||||
await page.getByRole('tab', { name: 'Location Details' }).click();
|
||||
|
||||
await page.getByLabel('nav-breadcrumb-action').click();
|
||||
await page.getByLabel('nav-tree-toggle-1}').click();
|
||||
await page.getByLabel('nav-tree-item-2').click();
|
||||
|
||||
await page.getByLabel('breadcrumb-2-storage-room-a').waitFor();
|
||||
await page.getByLabel('breadcrumb-1-factory').click();
|
||||
|
||||
await page.getByRole('cell', { name: 'Factory' }).first().waitFor();
|
||||
});
|
||||
|
||||
test('Stock - Serial Numbers', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
// Use the "global search" functionality to find a part we are interested in
|
||||
// This is to exercise the search functionality and ensure it is working as expected
|
||||
await page.getByLabel('open-search').click();
|
||||
|
||||
await page.getByLabel('global-search-input').clear();
|
||||
await page.getByLabel('global-search-input').fill('widget green');
|
||||
|
||||
// Remove the "stock item" results group
|
||||
await page.getByLabel('remove-search-group-stockitem').click();
|
||||
|
||||
await page
|
||||
.getByText(/widget\.green/)
|
||||
.first()
|
||||
.click();
|
||||
|
||||
await page
|
||||
.getByLabel('panel-tabs-part')
|
||||
.getByRole('tab', { name: 'Stock', exact: true })
|
||||
.click();
|
||||
await page.getByLabel('action-button-add-stock-item').click();
|
||||
|
||||
// Initially fill with invalid serial/quantity combinations
|
||||
await page.getByLabel('text-field-serial_numbers').fill('200-250');
|
||||
await page.getByLabel('number-field-quantity').fill('10');
|
||||
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
|
||||
// Expected error messages
|
||||
await page.getByText('Errors exist for one or more form fields').waitFor();
|
||||
await page
|
||||
.getByText(/exceeds allowed quantity/)
|
||||
.first()
|
||||
.waitFor();
|
||||
|
||||
// Now, with correct quantity
|
||||
await page.getByLabel('number-field-quantity').fill('51');
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
await page
|
||||
.getByText(
|
||||
/The following serial numbers already exist or are invalid : 200,201,202,203,204/
|
||||
)
|
||||
.first()
|
||||
.waitFor();
|
||||
|
||||
// Expected error messages
|
||||
await page.getByText('Errors exist for one or more form fields').waitFor();
|
||||
|
||||
// Close the form
|
||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||
});
|
@ -15,7 +15,7 @@ test('Quick Command', async ({ page }) => {
|
||||
await page.waitForURL('**/platform/dashboard');
|
||||
|
||||
// Open Spotlight with Button
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page.getByRole('button', { name: 'Home Go to the home page' }).click();
|
||||
await page
|
||||
.getByRole('heading', { name: 'Welcome to your Dashboard,' })
|
||||
@ -35,7 +35,7 @@ test('Quick Command - No Keys', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
// Open Spotlight with Button
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page.getByRole('button', { name: 'Home Go to the home page' }).click();
|
||||
await page
|
||||
.getByRole('heading', { name: 'Welcome to your Dashboard,' })
|
||||
@ -43,7 +43,7 @@ test('Quick Command - No Keys', async ({ page }) => {
|
||||
await page.waitForURL('**/platform');
|
||||
|
||||
// Use navigation menu
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page
|
||||
.getByRole('button', { name: 'Open Navigation Open the main' })
|
||||
.click();
|
||||
@ -56,7 +56,7 @@ test('Quick Command - No Keys', async ({ page }) => {
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
// use server info
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Server Information About this Inventree instance'
|
||||
@ -68,7 +68,7 @@ test('Quick Command - No Keys', async ({ page }) => {
|
||||
await page.waitForURL('**/platform');
|
||||
|
||||
// use license info
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'License Information Licenses for dependencies of the service'
|
||||
@ -80,7 +80,7 @@ test('Quick Command - No Keys', async ({ page }) => {
|
||||
await page.getByLabel('License Information').getByRole('button').click();
|
||||
|
||||
// use about
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page
|
||||
.getByRole('button', { name: 'About InvenTree About the InvenTree org' })
|
||||
.click();
|
||||
@ -89,7 +89,7 @@ test('Quick Command - No Keys', async ({ page }) => {
|
||||
await page.getByLabel('About InvenTree').getByRole('button').click();
|
||||
|
||||
// use documentation
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Documentation Visit the documentation to learn more about InvenTree'
|
||||
@ -105,7 +105,7 @@ test('Quick Command - No Keys', async ({ page }) => {
|
||||
/*
|
||||
await page.getByPlaceholder('Search...').fill('secret');
|
||||
await page.getByRole('button', { name: 'Secret action It was' }).click();
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
await page.getByPlaceholder('Search...').fill('Another secret action');
|
||||
await page
|
||||
.getByRole('button', {
|
||||
@ -113,7 +113,7 @@ test('Quick Command - No Keys', async ({ page }) => {
|
||||
})
|
||||
.click();
|
||||
await page.getByRole('tab', { name: 'Home' }).click();
|
||||
await page.getByRole('button', { name: 'Open spotlight' }).click();
|
||||
await page.getByLabel('open-spotlight').click();
|
||||
*/
|
||||
await page.getByPlaceholder('Search...').fill('secret');
|
||||
await page.getByText('Nothing found...').click();
|
||||
|
@ -1,100 +0,0 @@
|
||||
import { test } from './baseFixtures.js';
|
||||
import { baseUrl } from './defaults.js';
|
||||
import { doQuickLogin } from './login.js';
|
||||
|
||||
test('Stock', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/stock/location/index/`);
|
||||
await page.waitForURL('**/platform/stock/location/**');
|
||||
|
||||
await page.getByRole('tab', { name: 'Location Details' }).click();
|
||||
await page.waitForURL('**/platform/stock/location/index/details');
|
||||
|
||||
await page.getByRole('tab', { name: 'Stock Items' }).click();
|
||||
await page.getByText('1551ABK').first().click();
|
||||
|
||||
await page.getByRole('tab', { name: 'Stock', exact: true }).click();
|
||||
await page.waitForURL('**/platform/stock/**');
|
||||
await page.getByRole('tab', { name: 'Stock Locations' }).click();
|
||||
await page.getByRole('cell', { name: 'Electronics Lab' }).first().click();
|
||||
await page.getByRole('tab', { name: 'Default Parts' }).click();
|
||||
await page.getByRole('tab', { name: 'Stock Locations' }).click();
|
||||
await page.getByRole('tab', { name: 'Stock Items' }).click();
|
||||
await page.getByRole('tab', { name: 'Location Details' }).click();
|
||||
|
||||
await page.goto(`${baseUrl}/stock/item/1194/details`);
|
||||
await page.getByText('D.123 | Doohickey').waitFor();
|
||||
await page.getByText('Batch Code: BX-123-2024-2-7').waitFor();
|
||||
await page.getByRole('tab', { name: 'Stock Tracking' }).click();
|
||||
await page.getByRole('tab', { name: 'Test Data' }).click();
|
||||
await page.getByText('395c6d5586e5fb656901d047be27e1f7').waitFor();
|
||||
await page.getByRole('tab', { name: 'Installed Items' }).click();
|
||||
});
|
||||
|
||||
test('Purchasing', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.getByRole('tab', { name: 'Purchasing' }).click();
|
||||
await page.getByRole('cell', { name: 'PO0012' }).click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
await page.getByRole('tab', { name: 'Line Items' }).click();
|
||||
await page.getByRole('tab', { name: 'Received Stock' }).click();
|
||||
await page.getByRole('tab', { name: 'Attachments' }).click();
|
||||
await page.getByRole('tab', { name: 'Purchasing' }).click();
|
||||
await page.getByRole('tab', { name: 'Suppliers' }).click();
|
||||
await page.getByText('Arrow', { exact: true }).click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
await page.getByRole('tab', { name: 'Supplied Parts' }).click();
|
||||
await page.getByRole('tab', { name: 'Purchase Orders' }).click();
|
||||
await page.getByRole('tab', { name: 'Stock Items' }).click();
|
||||
await page.getByRole('tab', { name: 'Contacts' }).click();
|
||||
await page.getByRole('tab', { name: 'Addresses' }).click();
|
||||
await page.getByRole('tab', { name: 'Attachments' }).click();
|
||||
await page.getByRole('tab', { name: 'Purchasing' }).click();
|
||||
await page.getByRole('tab', { name: 'Manufacturers' }).click();
|
||||
await page.getByText('AVX Corporation').click();
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
await page.getByRole('tab', { name: 'Addresses' }).click();
|
||||
await page.getByRole('cell', { name: 'West Branch' }).click();
|
||||
await page.locator('.mantine-ScrollArea-root').click();
|
||||
await page
|
||||
.getByRole('row', { name: 'West Branch Yes Surf Avenue 9' })
|
||||
.getByRole('button')
|
||||
.click();
|
||||
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
||||
|
||||
await page.getByLabel('text-field-title').waitFor();
|
||||
await page.getByLabel('text-field-line2').waitFor();
|
||||
|
||||
// Read the current value of the cell, to ensure we always *change* it!
|
||||
const value = await page.getByLabel('text-field-line2').inputValue();
|
||||
await page
|
||||
.getByLabel('text-field-line2')
|
||||
.fill(value == 'old' ? 'new' : 'old');
|
||||
|
||||
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
||||
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
await page.getByRole('tab', { name: 'Details' }).waitFor();
|
||||
});
|
||||
|
||||
test('Stock Location Tree', async ({ page }) => {
|
||||
await doQuickLogin(page);
|
||||
|
||||
await page.goto(`${baseUrl}/stock/location/index/`);
|
||||
await page.waitForURL('**/platform/stock/location/**');
|
||||
await page.getByRole('tab', { name: 'Location Details' }).click();
|
||||
|
||||
await page.getByLabel('nav-breadcrumb-action').click();
|
||||
await page.getByLabel('nav-tree-toggle-1}').click();
|
||||
await page.getByLabel('nav-tree-item-2').click();
|
||||
|
||||
await page.getByLabel('breadcrumb-2-storage-room-a').waitFor();
|
||||
await page.getByLabel('breadcrumb-1-factory').click();
|
||||
|
||||
await page.getByRole('cell', { name: 'Factory' }).first().waitFor();
|
||||
});
|
Reference in New Issue
Block a user