mirror of
https://github.com/inventree/InvenTree.git
synced 2025-10-21 08:27:38 +00:00
Generator updates (#10605)
* Form Field updates: - Allow spec of leftSection prop - Allow spec of rightSection prop * Add ability to auto-fill text input with placeholder value * Simplify stock form * Better serial number placeholders * Update other generator fields * Add default placeholder to DateInput * Enhance TextField * Remove serial_numbers field for non-creation forms * Update playwright tests * Adjust playwright tests * Further playwright adjustments * Fix project code field for build serializer
This commit is contained in:
@@ -33,7 +33,6 @@ from generic.states.fields import InvenTreeCustomStatusSerializerMixin
|
|||||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||||
from InvenTree.serializers import (
|
from InvenTree.serializers import (
|
||||||
FilterableCharField,
|
FilterableCharField,
|
||||||
FilterableIntegerField,
|
|
||||||
FilterableSerializerMixin,
|
FilterableSerializerMixin,
|
||||||
InvenTreeDecimalField,
|
InvenTreeDecimalField,
|
||||||
InvenTreeModelSerializer,
|
InvenTreeModelSerializer,
|
||||||
@@ -164,17 +163,6 @@ class BuildSerializer(
|
|||||||
filter_name='project_code_detail',
|
filter_name='project_code_detail',
|
||||||
)
|
)
|
||||||
|
|
||||||
project_code = enable_filter(
|
|
||||||
FilterableIntegerField(
|
|
||||||
allow_null=True,
|
|
||||||
required=False,
|
|
||||||
label=_('Project Code'),
|
|
||||||
help_text=_('Project code for this build order'),
|
|
||||||
),
|
|
||||||
True,
|
|
||||||
filter_name='project_code_detail',
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Add custom annotations to the BuildSerializer queryset, performing database queries as efficiently as possible.
|
"""Add custom annotations to the BuildSerializer queryset, performing database queries as efficiently as possible.
|
||||||
|
@@ -53,9 +53,12 @@ export type ApiFormFieldHeader = {
|
|||||||
* @param error : Optional error message to display
|
* @param error : Optional error message to display
|
||||||
* @param exclude : Whether to exclude the field from the submitted data
|
* @param exclude : Whether to exclude the field from the submitted data
|
||||||
* @param placeholder : The placeholder text to display
|
* @param placeholder : The placeholder text to display
|
||||||
|
* @param placeholderAutofill: Whether to allow auto-filling of the placeholder value
|
||||||
* @param description : The description to display for the field
|
* @param description : The description to display for the field
|
||||||
* @param preFieldContent : Content to render before the field
|
* @param preFieldContent : Content to render before the field
|
||||||
* @param postFieldContent : Content to render after the field
|
* @param postFieldContent : Content to render after the field
|
||||||
|
* @param leftSection : Content to render in the left section of the field
|
||||||
|
* @param rightSection : Content to render in the right section of the field
|
||||||
* @param autoFill: Whether to automatically fill the field with data from the API
|
* @param autoFill: Whether to automatically fill the field with data from the API
|
||||||
* @param autoFillFilters: Optional filters to apply when auto-filling the field
|
* @param autoFillFilters: Optional filters to apply when auto-filling the field
|
||||||
* @param onValueChange : Callback function to call when the field value changes
|
* @param onValueChange : Callback function to call when the field value changes
|
||||||
@@ -103,9 +106,12 @@ export type ApiFormFieldType = {
|
|||||||
exclude?: boolean;
|
exclude?: boolean;
|
||||||
read_only?: boolean;
|
read_only?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
placeholderAutofill?: boolean;
|
||||||
description?: string;
|
description?: string;
|
||||||
preFieldContent?: JSX.Element;
|
preFieldContent?: JSX.Element;
|
||||||
postFieldContent?: JSX.Element;
|
postFieldContent?: JSX.Element;
|
||||||
|
leftSection?: JSX.Element;
|
||||||
|
rightSection?: JSX.Element;
|
||||||
autoFill?: boolean;
|
autoFill?: boolean;
|
||||||
autoFillFilters?: any;
|
autoFillFilters?: any;
|
||||||
adjustValue?: (value: any) => any;
|
adjustValue?: (value: any) => any;
|
||||||
|
@@ -74,6 +74,7 @@ export function ApiFormField({
|
|||||||
return {
|
return {
|
||||||
...fieldDefinition,
|
...fieldDefinition,
|
||||||
autoFill: undefined,
|
autoFill: undefined,
|
||||||
|
placeholderAutofill: undefined,
|
||||||
autoFillFilters: undefined,
|
autoFillFilters: undefined,
|
||||||
onValueChange: undefined,
|
onValueChange: undefined,
|
||||||
adjustFilters: undefined,
|
adjustFilters: undefined,
|
||||||
@@ -146,6 +147,7 @@ export function ApiFormField({
|
|||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
definition={reducedDefinition}
|
definition={reducedDefinition}
|
||||||
|
placeholderAutofill={fieldDefinition.placeholderAutofill ?? false}
|
||||||
controller={controller}
|
controller={controller}
|
||||||
fieldName={fieldName}
|
fieldName={fieldName}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import type { ApiFormFieldType } from '@lib/types/Forms';
|
import type { ApiFormFieldType } from '@lib/types/Forms';
|
||||||
|
import { t } from '@lingui/core/macro';
|
||||||
import { DateInput } from '@mantine/dates';
|
import { DateInput } from '@mantine/dates';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||||
@@ -72,7 +73,7 @@ export default function DateField({
|
|||||||
valueFormat={valueFormat}
|
valueFormat={valueFormat}
|
||||||
label={definition.label}
|
label={definition.label}
|
||||||
description={definition.description}
|
description={definition.description}
|
||||||
placeholder={definition.placeholder}
|
placeholder={definition.placeholder ?? t`Select date`}
|
||||||
leftSection={definition.icon}
|
leftSection={definition.icon}
|
||||||
highlightToday
|
highlightToday
|
||||||
/>
|
/>
|
||||||
|
@@ -1,7 +1,15 @@
|
|||||||
import { TextInput } from '@mantine/core';
|
import { t } from '@lingui/core/macro';
|
||||||
|
import { TextInput, Tooltip } from '@mantine/core';
|
||||||
import { useDebouncedValue } from '@mantine/hooks';
|
import { useDebouncedValue } from '@mantine/hooks';
|
||||||
import { IconX } from '@tabler/icons-react';
|
import { IconCopyCheck, IconX } from '@tabler/icons-react';
|
||||||
import { useCallback, useEffect, useId, useState } from 'react';
|
import {
|
||||||
|
type ReactNode,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useId,
|
||||||
|
useMemo,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
import type { FieldValues, UseControllerReturn } from 'react-hook-form';
|
import type { FieldValues, UseControllerReturn } from 'react-hook-form';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -13,12 +21,14 @@ export default function TextField({
|
|||||||
controller,
|
controller,
|
||||||
fieldName,
|
fieldName,
|
||||||
definition,
|
definition,
|
||||||
|
placeholderAutofill,
|
||||||
onChange,
|
onChange,
|
||||||
onKeyDown
|
onKeyDown
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
controller: UseControllerReturn<FieldValues, any>;
|
controller: UseControllerReturn<FieldValues, any>;
|
||||||
definition: any;
|
definition: any;
|
||||||
fieldName: string;
|
fieldName: string;
|
||||||
|
placeholderAutofill?: boolean;
|
||||||
onChange: (value: any) => void;
|
onChange: (value: any) => void;
|
||||||
onKeyDown: (value: any) => void;
|
onKeyDown: (value: any) => void;
|
||||||
}>) {
|
}>) {
|
||||||
@@ -28,7 +38,7 @@ export default function TextField({
|
|||||||
fieldState: { error }
|
fieldState: { error }
|
||||||
} = controller;
|
} = controller;
|
||||||
|
|
||||||
const { value } = field;
|
const { value } = useMemo(() => field, [field]);
|
||||||
|
|
||||||
const [rawText, setRawText] = useState<string>(value || '');
|
const [rawText, setRawText] = useState<string>(value || '');
|
||||||
|
|
||||||
@@ -48,6 +58,44 @@ export default function TextField({
|
|||||||
}
|
}
|
||||||
}, [debouncedText]);
|
}, [debouncedText]);
|
||||||
|
|
||||||
|
// Construct a "right section" for the text field
|
||||||
|
const textFieldRightSection: ReactNode = useMemo(() => {
|
||||||
|
if (definition.rightSection) {
|
||||||
|
// Use the specified override value
|
||||||
|
return definition.rightSection;
|
||||||
|
} else if (value) {
|
||||||
|
if (!definition.required && !definition.disabled) {
|
||||||
|
// Render a button to clear the text field
|
||||||
|
return (
|
||||||
|
<Tooltip label={t`Clear`} position='top-end'>
|
||||||
|
<IconX
|
||||||
|
aria-label={`text-field-${fieldName}-clear`}
|
||||||
|
size='1rem'
|
||||||
|
color='red'
|
||||||
|
onClick={() => onTextChange('')}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
!value &&
|
||||||
|
definition.placeholder &&
|
||||||
|
placeholderAutofill &&
|
||||||
|
!definition.disabled
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<Tooltip label={t`Accept suggested value`} position='top-end'>
|
||||||
|
<IconCopyCheck
|
||||||
|
aria-label={`text-field-${fieldName}-accept-placeholder`}
|
||||||
|
size='1rem'
|
||||||
|
color='green'
|
||||||
|
onClick={() => onTextChange(definition.placeholder)}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [placeholderAutofill, definition, value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextInput
|
<TextInput
|
||||||
{...definition}
|
{...definition}
|
||||||
@@ -71,11 +119,7 @@ export default function TextField({
|
|||||||
}
|
}
|
||||||
onKeyDown(event.code);
|
onKeyDown(event.code);
|
||||||
}}
|
}}
|
||||||
rightSection={
|
rightSection={textFieldRightSection}
|
||||||
value && !definition.required ? (
|
|
||||||
<IconX size='1rem' color='red' onClick={() => onTextChange('')} />
|
|
||||||
) : null
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -107,9 +107,8 @@ export function useBuildOrderFields({
|
|||||||
icon: <IconTruckDelivery />
|
icon: <IconTruckDelivery />
|
||||||
},
|
},
|
||||||
batch: {
|
batch: {
|
||||||
placeholder:
|
placeholder: batchGenerator.result,
|
||||||
batchGenerator.result &&
|
placeholderAutofill: true,
|
||||||
`${t`Next batch code`}: ${batchGenerator.result}`,
|
|
||||||
value: batchCode,
|
value: batchCode,
|
||||||
onValueChange: (value: any) => setBatchCode(value)
|
onValueChange: (value: any) => setBatchCode(value)
|
||||||
},
|
},
|
||||||
@@ -207,14 +206,12 @@ export function useBuildOrderOutputFields({
|
|||||||
},
|
},
|
||||||
serial_numbers: {
|
serial_numbers: {
|
||||||
hidden: !trackable,
|
hidden: !trackable,
|
||||||
placeholder:
|
placeholder: serialGenerator.result && `${serialGenerator.result}+`,
|
||||||
serialGenerator.result &&
|
placeholderAutofill: true
|
||||||
`${t`Next serial number`}: ${serialGenerator.result}`
|
|
||||||
},
|
},
|
||||||
batch_code: {
|
batch_code: {
|
||||||
placeholder:
|
placeholder: batchGenerator.result,
|
||||||
batchGenerator.result &&
|
placeholderAutofill: true
|
||||||
`${t`Next batch code`}: ${batchGenerator.result}`
|
|
||||||
},
|
},
|
||||||
location: {
|
location: {
|
||||||
value: location,
|
value: location,
|
||||||
|
@@ -212,23 +212,21 @@ export function useStockFields({
|
|||||||
description: t`Enter serial numbers for new stock (or leave blank)`,
|
description: t`Enter serial numbers for new stock (or leave blank)`,
|
||||||
required: false,
|
required: false,
|
||||||
hidden: !create,
|
hidden: !create,
|
||||||
placeholder:
|
placeholderAutofill: true,
|
||||||
serialGenerator.result &&
|
placeholder: serialGenerator.result && `${serialGenerator.result}+`
|
||||||
`${t`Next serial number`}: ${serialGenerator.result}`
|
|
||||||
},
|
},
|
||||||
serial: {
|
serial: {
|
||||||
placeholder:
|
placeholderAutofill: true,
|
||||||
serialGenerator.result &&
|
placeholder: serialGenerator.result,
|
||||||
`${t`Next serial number`}: ${serialGenerator.result}`,
|
|
||||||
hidden:
|
hidden:
|
||||||
create ||
|
create ||
|
||||||
partInstance.trackable == false ||
|
partInstance.trackable == false ||
|
||||||
(stockItem?.quantity != undefined && stockItem?.quantity != 1)
|
(stockItem?.quantity != undefined && stockItem?.quantity != 1)
|
||||||
},
|
},
|
||||||
batch: {
|
batch: {
|
||||||
placeholder:
|
default: '',
|
||||||
batchGenerator.result &&
|
placeholderAutofill: true,
|
||||||
`${t`Next batch code`}: ${batchGenerator.result}`
|
placeholder: batchGenerator.result
|
||||||
},
|
},
|
||||||
status_custom_key: {
|
status_custom_key: {
|
||||||
label: t`Stock Status`
|
label: t`Stock Status`
|
||||||
@@ -272,6 +270,10 @@ export function useStockFields({
|
|||||||
delete fields.expiry_date;
|
delete fields.expiry_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!create) {
|
||||||
|
delete fields.serial_numbers;
|
||||||
|
}
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}, [
|
}, [
|
||||||
stockItem,
|
stockItem,
|
||||||
@@ -400,9 +402,8 @@ export function useStockItemSerializeFields({
|
|||||||
return {
|
return {
|
||||||
quantity: {},
|
quantity: {},
|
||||||
serial_numbers: {
|
serial_numbers: {
|
||||||
placeholder:
|
placeholder: serialGenerator.result && `${serialGenerator.result}+`,
|
||||||
serialGenerator.result &&
|
placeholderAutofill: true
|
||||||
`${t`Next serial number`}: ${serialGenerator.result}`
|
|
||||||
},
|
},
|
||||||
destination: {}
|
destination: {}
|
||||||
};
|
};
|
||||||
|
@@ -34,7 +34,7 @@ test('Build Order - Basic Tests', async ({ browser }) => {
|
|||||||
|
|
||||||
// Edit the build order (via keyboard shortcut)
|
// Edit the build order (via keyboard shortcut)
|
||||||
await page.keyboard.press('Control+E');
|
await page.keyboard.press('Control+E');
|
||||||
await page.getByLabel('text-field-title').waitFor();
|
await page.getByLabel('text-field-title', { exact: true }).waitFor();
|
||||||
await page.getByLabel('related-field-project_code').waitFor();
|
await page.getByLabel('related-field-project_code').waitFor();
|
||||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
|
|
||||||
@@ -85,7 +85,9 @@ test('Build Order - Basic Tests', async ({ browser }) => {
|
|||||||
.getByLabel('add-test-result');
|
.getByLabel('add-test-result');
|
||||||
|
|
||||||
await button.click();
|
await button.click();
|
||||||
await page.getByRole('textbox', { name: 'text-field-value' }).waitFor();
|
await page
|
||||||
|
.getByRole('textbox', { name: 'text-field-value', exact: true })
|
||||||
|
.waitFor();
|
||||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
|
|
||||||
// Click through to the "parent" build
|
// Click through to the "parent" build
|
||||||
@@ -189,22 +191,27 @@ test('Build Order - Build Outputs', async ({ browser }) => {
|
|||||||
await page.getByLabel('action-button-add-build-output').click();
|
await page.getByLabel('action-button-add-build-output').click();
|
||||||
await page.getByLabel('number-field-quantity').fill('5');
|
await page.getByLabel('number-field-quantity').fill('5');
|
||||||
|
|
||||||
const placeholder = await page
|
const placeholder: string =
|
||||||
.getByLabel('text-field-serial_numbers')
|
(await page
|
||||||
.getAttribute('placeholder');
|
.getByLabel('text-field-serial_numbers', { exact: true })
|
||||||
|
.getAttribute('placeholder')) || '';
|
||||||
|
|
||||||
expect(placeholder).toContain('Next serial number');
|
expect(placeholder).toContain('+');
|
||||||
|
|
||||||
let sn = 1;
|
let sn = 1;
|
||||||
|
|
||||||
if (!!placeholder && placeholder.includes('Next serial number')) {
|
sn = Number.parseInt(placeholder.split('+')[0].trim());
|
||||||
sn = Number.parseInt(placeholder.split(':')[1].trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate some new serial numbers
|
// Generate some new serial numbers
|
||||||
await page.getByLabel('text-field-serial_numbers').fill(`${sn}, ${sn + 1}`);
|
await page
|
||||||
|
.getByLabel('text-field-serial_numbers', { exact: true })
|
||||||
|
.fill(`${sn}, ${sn + 1}`);
|
||||||
|
|
||||||
|
// Accept the suggested batch code
|
||||||
|
await page
|
||||||
|
.getByRole('img', { name: 'text-field-batch_code-accept-placeholder' })
|
||||||
|
.click();
|
||||||
|
|
||||||
await page.getByLabel('text-field-batch_code').fill('BATCH12345');
|
|
||||||
await page.getByLabel('related-field-location').click();
|
await page.getByLabel('related-field-location').click();
|
||||||
await page.getByLabel('related-field-location').fill('Reel');
|
await page.getByLabel('related-field-location').fill('Reel');
|
||||||
await page.getByText('- Electronics Lab/Reel Storage').click();
|
await page.getByText('- Electronics Lab/Reel Storage').click();
|
||||||
@@ -397,7 +404,7 @@ test('Build Order - Consume Stock', async ({ browser }) => {
|
|||||||
await page.getByLabel('Consume Stock').getByText('5 / 35').waitFor();
|
await page.getByLabel('Consume Stock').getByText('5 / 35').waitFor();
|
||||||
await page.getByLabel('Consume Stock').getByText('5 / 40').waitFor();
|
await page.getByLabel('Consume Stock').getByText('5 / 40').waitFor();
|
||||||
await page
|
await page
|
||||||
.getByRole('textbox', { name: 'text-field-notes' })
|
.getByRole('textbox', { name: 'text-field-notes', exact: true })
|
||||||
.fill('some notes here...');
|
.fill('some notes here...');
|
||||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
|
|
||||||
@@ -426,7 +433,7 @@ test('Build Order - Tracked Outputs', async ({ browser }) => {
|
|||||||
const cancelBuildOutput = async (cell) => {
|
const cancelBuildOutput = async (cell) => {
|
||||||
await clickOnRowMenu(cell);
|
await clickOnRowMenu(cell);
|
||||||
await page.getByRole('menuitem', { name: 'Cancel' }).click();
|
await page.getByRole('menuitem', { name: 'Cancel' }).click();
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit', exact: true }).click();
|
||||||
await page.getByText('Build outputs have been cancelled').waitFor();
|
await page.getByText('Build outputs have been cancelled').waitFor();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -444,7 +451,9 @@ test('Build Order - Tracked Outputs', async ({ browser }) => {
|
|||||||
.getByRole('button', { name: 'action-button-add-build-output' })
|
.getByRole('button', { name: 'action-button-add-build-output' })
|
||||||
.click();
|
.click();
|
||||||
await page.getByLabel('number-field-quantity').fill('1');
|
await page.getByLabel('number-field-quantity').fill('1');
|
||||||
await page.getByLabel('text-field-serial_numbers').fill('15');
|
await page
|
||||||
|
.getByLabel('text-field-serial_numbers', { exact: true })
|
||||||
|
.fill('15');
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
await page.getByText('Build output created').waitFor();
|
await page.getByText('Build output created').waitFor();
|
||||||
|
|
||||||
@@ -499,7 +508,9 @@ test('Build Order - Tracked Outputs', async ({ browser }) => {
|
|||||||
.getByRole('button', { name: 'action-button-add-build-output' })
|
.getByRole('button', { name: 'action-button-add-build-output' })
|
||||||
.click();
|
.click();
|
||||||
await page.getByLabel('number-field-quantity').fill('1');
|
await page.getByLabel('number-field-quantity').fill('1');
|
||||||
await page.getByLabel('text-field-serial_numbers').fill('16');
|
await page
|
||||||
|
.getByLabel('text-field-serial_numbers', { exact: true })
|
||||||
|
.fill('16');
|
||||||
await page
|
await page
|
||||||
.locator('label')
|
.locator('label')
|
||||||
.filter({ hasText: 'Auto Allocate Serial' })
|
.filter({ hasText: 'Auto Allocate Serial' })
|
||||||
@@ -560,7 +571,9 @@ test('Build Order - Duplicate', async ({ browser }) => {
|
|||||||
await page.getByLabel('action-menu-build-order-actions-duplicate').click();
|
await page.getByLabel('action-menu-build-order-actions-duplicate').click();
|
||||||
|
|
||||||
// Ensure a new reference is suggested
|
// Ensure a new reference is suggested
|
||||||
await expect(page.getByLabel('text-field-reference')).not.toBeEmpty();
|
await expect(
|
||||||
|
page.getByLabel('text-field-reference', { exact: true })
|
||||||
|
).not.toBeEmpty();
|
||||||
|
|
||||||
// Submit the duplicate request and ensure it completes
|
// Submit the duplicate request and ensure it completes
|
||||||
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
||||||
|
@@ -30,8 +30,10 @@ test('Company', async ({ browser }) => {
|
|||||||
await page.getByLabel('action-menu-company-actions').click();
|
await page.getByLabel('action-menu-company-actions').click();
|
||||||
await page.getByLabel('action-menu-company-actions-edit').click();
|
await page.getByLabel('action-menu-company-actions-edit').click();
|
||||||
|
|
||||||
await page.getByLabel('text-field-name').fill('');
|
await page.getByLabel('text-field-name', { exact: true }).fill('');
|
||||||
await page.getByLabel('text-field-website').fill('invalid-website');
|
await page
|
||||||
|
.getByLabel('text-field-website', { exact: true })
|
||||||
|
.fill('invalid-website');
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
await page.getByText('This field may not be blank.').waitFor();
|
await page.getByText('This field may not be blank.').waitFor();
|
||||||
|
@@ -142,14 +142,16 @@ test('Part - Editing', async ({ browser }) => {
|
|||||||
// Open part edit dialog
|
// Open part edit dialog
|
||||||
await page.keyboard.press('Control+E');
|
await page.keyboard.press('Control+E');
|
||||||
|
|
||||||
const keywords = await page.getByLabel('text-field-keywords').inputValue();
|
const keywords = await page
|
||||||
|
.getByLabel('text-field-keywords', { exact: true })
|
||||||
|
.inputValue();
|
||||||
await page
|
await page
|
||||||
.getByLabel('text-field-keywords')
|
.getByLabel('text-field-keywords', { exact: true })
|
||||||
.fill(keywords ? '' : 'table furniture');
|
.fill(keywords ? '' : 'table furniture');
|
||||||
|
|
||||||
// Test URL validation
|
// Test URL validation
|
||||||
await page
|
await page
|
||||||
.getByRole('textbox', { name: 'text-field-link' })
|
.getByRole('textbox', { name: 'text-field-link', exact: true })
|
||||||
.fill('htxp-??QQQ++');
|
.fill('htxp-??QQQ++');
|
||||||
await page.waitForTimeout(200);
|
await page.waitForTimeout(200);
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
@@ -157,11 +159,15 @@ test('Part - Editing', async ({ browser }) => {
|
|||||||
|
|
||||||
// Fill with an empty URL
|
// Fill with an empty URL
|
||||||
const description = await page
|
const description = await page
|
||||||
.getByLabel('text-field-description')
|
.getByLabel('text-field-description', { exact: true })
|
||||||
.inputValue();
|
.inputValue();
|
||||||
|
|
||||||
await page.getByRole('textbox', { name: 'text-field-link' }).fill('');
|
await page
|
||||||
await page.getByLabel('text-field-description').fill(`${description}+`);
|
.getByRole('textbox', { name: 'text-field-link', exact: true })
|
||||||
|
.fill('');
|
||||||
|
await page
|
||||||
|
.getByLabel('text-field-description', { exact: true })
|
||||||
|
.fill(`${description}+`);
|
||||||
await page.waitForTimeout(200);
|
await page.waitForTimeout(200);
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
await page.getByText('Item Updated').waitFor();
|
await page.getByText('Item Updated').waitFor();
|
||||||
@@ -462,8 +468,12 @@ test('Parts - Attachments', async ({ browser }) => {
|
|||||||
|
|
||||||
// Submit a new external link
|
// Submit a new external link
|
||||||
await page.getByLabel('action-button-add-external-').click();
|
await page.getByLabel('action-button-add-external-').click();
|
||||||
await page.getByLabel('text-field-link').fill('https://www.google.com');
|
await page
|
||||||
await page.getByLabel('text-field-comment').fill('a sample comment');
|
.getByLabel('text-field-link', { exact: true })
|
||||||
|
.fill('https://www.google.com');
|
||||||
|
await page
|
||||||
|
.getByLabel('text-field-comment', { exact: true })
|
||||||
|
.fill('a sample comment');
|
||||||
|
|
||||||
// Note: Text field values are debounced for 250ms
|
// Note: Text field values are debounced for 250ms
|
||||||
await page.waitForTimeout(300);
|
await page.waitForTimeout(300);
|
||||||
@@ -473,7 +483,9 @@ test('Parts - Attachments', async ({ browser }) => {
|
|||||||
|
|
||||||
// Launch dialog to upload a file
|
// Launch dialog to upload a file
|
||||||
await page.getByLabel('action-button-add-attachment').click();
|
await page.getByLabel('action-button-add-attachment').click();
|
||||||
await page.getByLabel('text-field-comment').fill('some comment');
|
await page
|
||||||
|
.getByLabel('text-field-comment', { exact: true })
|
||||||
|
.fill('some comment');
|
||||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -489,7 +501,9 @@ test('Parts - Parameters', async ({ browser }) => {
|
|||||||
await page.getByLabel('choice-field-data').click();
|
await page.getByLabel('choice-field-data').click();
|
||||||
await page.getByRole('option', { name: 'Green' }).click();
|
await page.getByRole('option', { name: 'Green' }).click();
|
||||||
|
|
||||||
await page.getByLabel('text-field-note').fill('A custom note field');
|
await page
|
||||||
|
.getByLabel('text-field-note', { exact: true })
|
||||||
|
.fill('A custom note field');
|
||||||
|
|
||||||
// Select the "polarized" parameter template (should create a "checkbox" field)
|
// Select the "polarized" parameter template (should create a "checkbox" field)
|
||||||
await page.getByLabel('related-field-template').fill('Polarized');
|
await page.getByLabel('related-field-template').fill('Polarized');
|
||||||
@@ -577,8 +591,8 @@ test('Parts - Notes', async ({ browser }) => {
|
|||||||
|
|
||||||
// Use keyboard shortcut to "edit" the part
|
// Use keyboard shortcut to "edit" the part
|
||||||
await page.keyboard.press('Control+E');
|
await page.keyboard.press('Control+E');
|
||||||
await page.getByLabel('text-field-name').waitFor();
|
await page.getByLabel('text-field-name', { exact: true }).waitFor();
|
||||||
await page.getByLabel('text-field-description').waitFor();
|
await page.getByLabel('text-field-description', { exact: true }).waitFor();
|
||||||
await page.getByLabel('related-field-category').waitFor();
|
await page.getByLabel('related-field-category').waitFor();
|
||||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
|
|
||||||
|
@@ -169,13 +169,15 @@ test('Purchase Orders - General', async ({ browser }) => {
|
|||||||
.click();
|
.click();
|
||||||
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
||||||
|
|
||||||
await page.getByLabel('text-field-title').waitFor();
|
await page.getByLabel('text-field-title', { exact: true }).waitFor();
|
||||||
await page.getByLabel('text-field-line2').waitFor();
|
await page.getByLabel('text-field-line2', { exact: true }).waitFor();
|
||||||
|
|
||||||
// Read the current value of the cell, to ensure we always *change* it!
|
// Read the current value of the cell, to ensure we always *change* it!
|
||||||
const value = await page.getByLabel('text-field-line2').inputValue();
|
const value = await page
|
||||||
|
.getByLabel('text-field-line2', { exact: true })
|
||||||
|
.inputValue();
|
||||||
await page
|
await page
|
||||||
.getByLabel('text-field-line2')
|
.getByLabel('text-field-line2', { exact: true })
|
||||||
.fill(value == 'old' ? 'new' : 'old');
|
.fill(value == 'old' ? 'new' : 'old');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
||||||
@@ -344,9 +346,13 @@ test('Purchase Orders - Receive Items', async ({ browser }) => {
|
|||||||
await page.getByLabel('action-button-change-status').click();
|
await page.getByLabel('action-button-change-status').click();
|
||||||
await page.getByLabel('action-button-add-note').click();
|
await page.getByLabel('action-button-add-note').click();
|
||||||
|
|
||||||
await page.getByLabel('text-field-batch_code').fill('my-batch-code');
|
await page
|
||||||
await page.getByLabel('text-field-packaging').fill('bucket');
|
.getByLabel('text-field-batch_code', { exact: true })
|
||||||
await page.getByLabel('text-field-note').fill('The quick brown fox');
|
.fill('my-batch-code');
|
||||||
|
await page.getByLabel('text-field-packaging', { exact: true }).fill('bucket');
|
||||||
|
await page
|
||||||
|
.getByLabel('text-field-note', { exact: true })
|
||||||
|
.fill('The quick brown fox');
|
||||||
await page.getByLabel('choice-field-status').click();
|
await page.getByLabel('choice-field-status').click();
|
||||||
await page.getByRole('option', { name: 'Destroyed' }).click();
|
await page.getByRole('option', { name: 'Destroyed' }).click();
|
||||||
|
|
||||||
@@ -371,7 +377,9 @@ test('Purchase Orders - Duplicate', async ({ browser }) => {
|
|||||||
await page.getByLabel('action-menu-order-actions-duplicate').click();
|
await page.getByLabel('action-menu-order-actions-duplicate').click();
|
||||||
|
|
||||||
// Ensure a new reference is suggested
|
// Ensure a new reference is suggested
|
||||||
await expect(page.getByLabel('text-field-reference')).not.toBeEmpty();
|
await expect(
|
||||||
|
page.getByLabel('text-field-reference', { exact: true })
|
||||||
|
).not.toBeEmpty();
|
||||||
|
|
||||||
// Submit the duplicate request and ensure it completes
|
// Submit the duplicate request and ensure it completes
|
||||||
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
||||||
|
@@ -120,8 +120,12 @@ test('Sales Orders - Shipments', async ({ browser }) => {
|
|||||||
|
|
||||||
// Create a new shipment
|
// Create a new shipment
|
||||||
await page.getByLabel('action-button-add-shipment').click();
|
await page.getByLabel('action-button-add-shipment').click();
|
||||||
await page.getByLabel('text-field-tracking_number').fill('1234567890');
|
await page
|
||||||
await page.getByLabel('text-field-invoice_number').fill('9876543210');
|
.getByLabel('text-field-tracking_number', { exact: true })
|
||||||
|
.fill('1234567890');
|
||||||
|
await page
|
||||||
|
.getByLabel('text-field-invoice_number', { exact: true })
|
||||||
|
.fill('9876543210');
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
// Expected field error
|
// Expected field error
|
||||||
@@ -140,7 +144,7 @@ test('Sales Orders - Shipments', async ({ browser }) => {
|
|||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
let tracking_number = await page
|
let tracking_number = await page
|
||||||
.getByLabel('text-field-tracking_number')
|
.getByLabel('text-field-tracking_number', { exact: true })
|
||||||
.inputValue();
|
.inputValue();
|
||||||
|
|
||||||
if (!tracking_number) {
|
if (!tracking_number) {
|
||||||
@@ -154,7 +158,9 @@ test('Sales Orders - Shipments', async ({ browser }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Change the tracking number
|
// Change the tracking number
|
||||||
await page.getByLabel('text-field-tracking_number').fill(tracking_number);
|
await page
|
||||||
|
.getByLabel('text-field-tracking_number', { exact: true })
|
||||||
|
.fill(tracking_number);
|
||||||
await page.waitForTimeout(250);
|
await page.waitForTimeout(250);
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
@@ -217,7 +223,9 @@ test('Sales Orders - Duplicate', async ({ browser }) => {
|
|||||||
await page.getByLabel('action-menu-order-actions-duplicate').click();
|
await page.getByLabel('action-menu-order-actions-duplicate').click();
|
||||||
|
|
||||||
// Ensure a new reference is suggested
|
// Ensure a new reference is suggested
|
||||||
await expect(page.getByLabel('text-field-reference')).not.toBeEmpty();
|
await expect(
|
||||||
|
page.getByLabel('text-field-reference', { exact: true })
|
||||||
|
).not.toBeEmpty();
|
||||||
|
|
||||||
// Submit the duplicate request and ensure it completes
|
// Submit the duplicate request and ensure it completes
|
||||||
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
await page.getByRole('button', { name: 'Submit' }).isEnabled();
|
||||||
|
@@ -130,7 +130,9 @@ test('Stock - Serial Numbers', async ({ browser }) => {
|
|||||||
await page.getByLabel('action-button-add-stock-item').click();
|
await page.getByLabel('action-button-add-stock-item').click();
|
||||||
|
|
||||||
// Initially fill with invalid serial/quantity combinations
|
// Initially fill with invalid serial/quantity combinations
|
||||||
await page.getByLabel('text-field-serial_numbers').fill('200-250');
|
await page
|
||||||
|
.getByLabel('text-field-serial_numbers', { exact: true })
|
||||||
|
.fill('200-250');
|
||||||
await page.getByLabel('number-field-quantity').fill('10');
|
await page.getByLabel('number-field-quantity').fill('10');
|
||||||
|
|
||||||
// Add delay to account to field debounce
|
// Add delay to account to field debounce
|
||||||
@@ -171,7 +173,7 @@ test('Stock - Serial Navigation', async ({ browser }) => {
|
|||||||
|
|
||||||
await page.getByLabel('action-menu-stock-actions').click();
|
await page.getByLabel('action-menu-stock-actions').click();
|
||||||
await page.getByLabel('action-menu-stock-actions-search').click();
|
await page.getByLabel('action-menu-stock-actions-search').click();
|
||||||
await page.getByLabel('text-field-serial').fill('359');
|
await page.getByLabel('text-field-serial', { exact: true }).fill('359');
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
// Start at serial 359
|
// Start at serial 359
|
||||||
@@ -183,7 +185,7 @@ test('Stock - Serial Navigation', async ({ browser }) => {
|
|||||||
await page.getByText('358', { exact: true }).first().waitFor();
|
await page.getByText('358', { exact: true }).first().waitFor();
|
||||||
|
|
||||||
await page.getByLabel('action-button-find-serial').click();
|
await page.getByLabel('action-button-find-serial').click();
|
||||||
await page.getByLabel('text-field-serial').fill('200');
|
await page.getByLabel('text-field-serial', { exact: true }).fill('200');
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
await page.getByText('Serial Number: 200').waitFor();
|
await page.getByText('Serial Number: 200').waitFor();
|
||||||
@@ -201,10 +203,15 @@ test('Stock - Serialize', async ({ browser }) => {
|
|||||||
|
|
||||||
// Check for expected placeholder value
|
// Check for expected placeholder value
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('textbox', { name: 'text-field-serial_numbers' })
|
page.getByRole('textbox', {
|
||||||
).toHaveAttribute('placeholder', 'Next serial number: 365');
|
name: 'text-field-serial_numbers',
|
||||||
|
exact: true
|
||||||
|
})
|
||||||
|
).toHaveAttribute('placeholder', '365+');
|
||||||
|
|
||||||
await page.getByLabel('text-field-serial_numbers').fill('200-250');
|
await page
|
||||||
|
.getByLabel('text-field-serial_numbers', { exact: true })
|
||||||
|
.fill('200-250');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
@@ -212,7 +219,9 @@ test('Stock - Serialize', async ({ browser }) => {
|
|||||||
.getByText('Number of unique serial numbers (51) must match quantity (100)')
|
.getByText('Number of unique serial numbers (51) must match quantity (100)')
|
||||||
.waitFor();
|
.waitFor();
|
||||||
|
|
||||||
await page.getByLabel('text-field-serial_numbers').fill('1, 2, 3');
|
await page
|
||||||
|
.getByLabel('text-field-serial_numbers', { exact: true })
|
||||||
|
.fill('1, 2, 3');
|
||||||
await page.waitForTimeout(250);
|
await page.waitForTimeout(250);
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ test('Forms - Stock Item Validation', async ({ browser }) => {
|
|||||||
await page.getByText('Valid part must be supplied').waitFor();
|
await page.getByText('Valid part must be supplied').waitFor();
|
||||||
|
|
||||||
// Adjust other field - the errors should persist
|
// Adjust other field - the errors should persist
|
||||||
await page.getByLabel('text-field-batch').fill('BATCH-123');
|
await page.getByLabel('text-field-batch', { exact: true }).fill('BATCH-123');
|
||||||
await page.waitForTimeout(250);
|
await page.waitForTimeout(250);
|
||||||
|
|
||||||
await page.getByText('Valid part must be supplied').waitFor();
|
await page.getByText('Valid part must be supplied').waitFor();
|
||||||
@@ -53,14 +53,16 @@ test('Forms - Stock Item Validation', async ({ browser }) => {
|
|||||||
await page.getByLabel('action-menu-stock-item-actions-edit').click();
|
await page.getByLabel('action-menu-stock-item-actions-edit').click();
|
||||||
|
|
||||||
await page.getByLabel('number-field-purchase_price').fill('-1');
|
await page.getByLabel('number-field-purchase_price').fill('-1');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
await page.getByText('Errors exist for one or more form fields').waitFor();
|
await page.getByText('Errors exist for one or more form fields').waitFor();
|
||||||
await page
|
await page
|
||||||
.getByText('Ensure this value is greater than or equal to 0')
|
.getByText('Ensure this value is greater than or equal to 0')
|
||||||
.waitFor();
|
.waitFor();
|
||||||
|
|
||||||
// Check the error message still persists after editing a different field
|
// Check the error message still persists after editing a different field
|
||||||
await page.getByLabel('text-field-packaging').fill('a box');
|
await page.getByLabel('text-field-packaging', { exact: true }).fill('a box');
|
||||||
await page.waitForTimeout(250);
|
await page.waitForTimeout(250);
|
||||||
await page
|
await page
|
||||||
.getByText('Ensure this value is greater than or equal to 0')
|
.getByText('Ensure this value is greater than or equal to 0')
|
||||||
@@ -87,7 +89,9 @@ test('Forms - Supplier Validation', async ({ browser }) => {
|
|||||||
await page.waitForURL('**/purchasing/index/**');
|
await page.waitForURL('**/purchasing/index/**');
|
||||||
|
|
||||||
await page.getByLabel('action-button-add-company').click();
|
await page.getByLabel('action-button-add-company').click();
|
||||||
await page.getByLabel('text-field-website').fill('not-a-website');
|
await page
|
||||||
|
.getByLabel('text-field-website', { exact: true })
|
||||||
|
.fill('not-a-website');
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
@@ -98,7 +102,9 @@ test('Forms - Supplier Validation', async ({ browser }) => {
|
|||||||
await page.getByText('Enter a valid URL.').waitFor();
|
await page.getByText('Enter a valid URL.').waitFor();
|
||||||
|
|
||||||
// Fill out another field, expect that the errors persist
|
// Fill out another field, expect that the errors persist
|
||||||
await page.getByLabel('text-field-description').fill('A description');
|
await page
|
||||||
|
.getByLabel('text-field-description', { exact: true })
|
||||||
|
.fill('A description');
|
||||||
await page.waitForTimeout(250);
|
await page.waitForTimeout(250);
|
||||||
await page.getByText('This field may not be blank.').waitFor();
|
await page.getByText('This field may not be blank.').waitFor();
|
||||||
await page.getByText('Enter a valid URL.').waitFor();
|
await page.getByText('Enter a valid URL.').waitFor();
|
||||||
@@ -108,9 +114,9 @@ test('Forms - Supplier Validation', async ({ browser }) => {
|
|||||||
|
|
||||||
// Fill with good data
|
// Fill with good data
|
||||||
await page
|
await page
|
||||||
.getByLabel('text-field-website')
|
.getByLabel('text-field-website', { exact: true })
|
||||||
.fill('https://www.test-website.co.uk');
|
.fill('https://www.test-website.co.uk');
|
||||||
await page.getByLabel('text-field-name').fill(supplierName);
|
await page.getByLabel('text-field-name', { exact: true }).fill(supplierName);
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
await page.getByText('A description').first().waitFor();
|
await page.getByText('A description').first().waitFor();
|
||||||
@@ -122,7 +128,7 @@ test('Forms - Supplier Validation', async ({ browser }) => {
|
|||||||
await navigate(page, 'purchasing/index/suppliers');
|
await navigate(page, 'purchasing/index/suppliers');
|
||||||
await page.waitForURL('**/purchasing/index/**');
|
await page.waitForURL('**/purchasing/index/**');
|
||||||
await page.getByLabel('action-button-add-company').click();
|
await page.getByLabel('action-button-add-company').click();
|
||||||
await page.getByLabel('text-field-name').fill(supplierName);
|
await page.getByLabel('text-field-name', { exact: true }).fill(supplierName);
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
// Is prevented, due to uniqueness requirements
|
// Is prevented, due to uniqueness requirements
|
||||||
|
@@ -270,16 +270,20 @@ test('Settings - Admin', async ({ browser }) => {
|
|||||||
await roomRow.getByLabel(/row-action-menu-/i).click();
|
await roomRow.getByLabel(/row-action-menu-/i).click();
|
||||||
|
|
||||||
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
||||||
await expect(page.getByLabel('text-field-name')).toHaveValue('Room');
|
await expect(page.getByLabel('text-field-name', { exact: true })).toHaveValue(
|
||||||
|
'Room'
|
||||||
|
);
|
||||||
|
|
||||||
// Toggle the "description" field
|
// Toggle the "description" field
|
||||||
const oldDescription = await page
|
const oldDescription = await page
|
||||||
.getByLabel('text-field-description')
|
.getByLabel('text-field-description', { exact: true })
|
||||||
.inputValue();
|
.inputValue();
|
||||||
|
|
||||||
const newDescription = `${oldDescription} (edited)`;
|
const newDescription = `${oldDescription} (edited)`;
|
||||||
|
|
||||||
await page.getByLabel('text-field-description').fill(newDescription);
|
await page
|
||||||
|
.getByLabel('text-field-description', { exact: true })
|
||||||
|
.fill(newDescription);
|
||||||
await page.waitForTimeout(500);
|
await page.waitForTimeout(500);
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
|
||||||
@@ -293,19 +297,21 @@ test('Settings - Admin', async ({ browser }) => {
|
|||||||
await boxRow.getByLabel(/row-action-menu-/i).click();
|
await boxRow.getByLabel(/row-action-menu-/i).click();
|
||||||
|
|
||||||
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
||||||
await expect(page.getByLabel('text-field-name')).toHaveValue('Box (Large)');
|
await expect(page.getByLabel('text-field-name', { exact: true })).toHaveValue(
|
||||||
await expect(page.getByLabel('text-field-description')).toHaveValue(
|
'Box (Large)'
|
||||||
'Large cardboard box'
|
|
||||||
);
|
);
|
||||||
|
await expect(
|
||||||
|
page.getByLabel('text-field-description', { exact: true })
|
||||||
|
).toHaveValue('Large cardboard box');
|
||||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
|
|
||||||
// Edit first item again (revert values)
|
// Edit first item again (revert values)
|
||||||
await roomRow.getByLabel(/row-action-menu-/i).click();
|
await roomRow.getByLabel(/row-action-menu-/i).click();
|
||||||
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
await page.getByRole('menuitem', { name: 'Edit' }).click();
|
||||||
await page.getByLabel('text-field-name').fill('Room');
|
await page.getByLabel('text-field-name', { exact: true }).fill('Room');
|
||||||
await page.waitForTimeout(500);
|
await page.waitForTimeout(500);
|
||||||
await page
|
await page
|
||||||
.getByLabel('text-field-description')
|
.getByLabel('text-field-description', { exact: true })
|
||||||
.fill(newDescription.replaceAll(' (edited)', ''));
|
.fill(newDescription.replaceAll(' (edited)', ''));
|
||||||
await page.waitForTimeout(500);
|
await page.waitForTimeout(500);
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
@@ -50,25 +50,25 @@ test('Tables - Pagination', async ({ browser }) => {
|
|||||||
|
|
||||||
// Expected pagination size is 25
|
// Expected pagination size is 25
|
||||||
// Note: Due to other tests, there may be more than 25 items in the list
|
// Note: Due to other tests, there may be more than 25 items in the list
|
||||||
await page.getByText(/1 - 25 \/ 2[2|8]/).waitFor();
|
await page.getByText(/1 - 25 \/ \d+/).waitFor();
|
||||||
await page.getByRole('button', { name: 'Next page' }).click();
|
await page.getByRole('button', { name: 'Next page' }).click();
|
||||||
await page.getByText(/26 - 2[7|8] \/ 2[7|8]/).waitFor();
|
await page.getByText(/26 - \d+ \/ \d+/).waitFor();
|
||||||
|
|
||||||
// Set page size to 10
|
// Set page size to 10
|
||||||
await page.getByRole('button', { name: '25' }).click();
|
await page.getByRole('button', { name: '25' }).click();
|
||||||
await page.getByRole('menuitem', { name: '10', exact: true }).click();
|
await page.getByRole('menuitem', { name: '10', exact: true }).click();
|
||||||
|
|
||||||
await page.getByText(/1 - 10 \/ 2[7|8]/).waitFor();
|
await page.getByText(/1 - 10 \/ \d+/).waitFor();
|
||||||
await page.getByRole('button', { name: '3' }).click();
|
await page.getByRole('button', { name: '3' }).click();
|
||||||
await page.getByText(/21 - 2[7|8] \/ 2[7|8]/).waitFor();
|
await page.getByText(/21 - \d+ \/ \d+/).waitFor();
|
||||||
await page.getByRole('button', { name: 'Previous page' }).click();
|
await page.getByRole('button', { name: 'Previous page' }).click();
|
||||||
await page.getByText(/11 - 20 \/ 2[7|8]/).waitFor();
|
await page.getByText(/11 - 20 \/ \d+/).waitFor();
|
||||||
|
|
||||||
// Set page size back to 25
|
// Set page size back to 25
|
||||||
await page.getByRole('button', { name: '10' }).click();
|
await page.getByRole('button', { name: '10' }).click();
|
||||||
await page.getByRole('menuitem', { name: '25', exact: true }).click();
|
await page.getByRole('menuitem', { name: '25', exact: true }).click();
|
||||||
|
|
||||||
await page.getByText(/1 - 25 \/ 2[7|8]/).waitFor();
|
await page.getByText(/1 - 25 \/ \d+/).waitFor();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Tables - Columns', async ({ browser }) => {
|
test('Tables - Columns', async ({ browser }) => {
|
||||||
|
Reference in New Issue
Block a user