modified: .gitignore
modified: src/components/PickItemRow.test.tsx modified: src/components/ProductAutocomplete.tsx modified: src/screens/ActivePickListScreen.test.tsx modified: src/screens/ActivePickListScreen.tsx modified: src/screens/ManageCategoriesScreen.test.tsx modified: src/screens/ManageProductsScreen.test.tsx modified: src/screens/ManageProductsScreen.tsx modified: src/screens/StartPickListScreen.test.tsx
This commit is contained in:
1 parent
d6b784ad11
commit
59be57a5e4
9 files changed
+479
-445
No files matched your search
@@ -59,19 +59,18 @@ describe('PickItemRow', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
const productName = screen.getByText(baseProduct.name);
|
||||
const quantityLabel = screen.getByText('Qty: 1 unit');
|
||||
// The component now renders the quantity together with the product name
|
||||
// (e.g. "1 x Test Product"). Match the combined text.
|
||||
const productName = screen.getByText(new RegExp(`${baseItem.quantity} x ${baseProduct.name}`));
|
||||
const titleRow = screen.getByTestId('pick-item-title-row');
|
||||
|
||||
const rowStyle = getComputedStyle(titleRow);
|
||||
expect(rowStyle.display).toBe('flex');
|
||||
expect(rowStyle.flexDirection).toBe('row');
|
||||
|
||||
// Ensure the title typography exists and has the expected fontWeight set by the component
|
||||
const productStyle = getComputedStyle(productName);
|
||||
const quantityStyle = getComputedStyle(quantityLabel);
|
||||
|
||||
expect(productStyle.fontSize).toBe(quantityStyle.fontSize);
|
||||
expect(productStyle.fontWeight).toBe(quantityStyle.fontWeight);
|
||||
expect(productStyle.fontWeight).toBe('600');
|
||||
});
|
||||
|
||||
it('asks for confirmation before deleting a product from the pick list', async () => {
|
||||
@@ -143,7 +142,8 @@ describe('PickItemRow', () => {
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /open item controls/i }));
|
||||
|
||||
expect(screen.getByRole('dialog', { name: baseProduct.name })).toBeVisible();
|
||||
// Dialog title is now prefixed with quantity ("1 x Test Product"), so match by product name substring.
|
||||
expect(screen.getByRole('dialog', { name: new RegExp(baseProduct.name) })).toBeVisible();
|
||||
});
|
||||
|
||||
it('uses inline controls on wide screens', async () => {
|
||||
@@ -193,6 +193,7 @@ describe('PickItemRow', () => {
|
||||
row.focus();
|
||||
await user.keyboard('{Enter}');
|
||||
|
||||
expect(screen.getByRole('dialog', { name: baseProduct.name })).toBeVisible();
|
||||
// Match dialog by product name substring (dialog title contains "1 x Test Product")
|
||||
expect(screen.getByRole('dialog', { name: new RegExp(baseProduct.name) })).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
// src/components/ProductAutocomplete.tsx
|
||||
import {
|
||||
Autocomplete,
|
||||
IconButton,
|
||||
@@ -16,12 +17,14 @@ interface ProductAutocompleteProps {
|
||||
availableProducts: Product[];
|
||||
onSelect: (product: Product) => void;
|
||||
placeholder?: string;
|
||||
onQueryChange?: (q: string) => void;
|
||||
}
|
||||
|
||||
export const ProductAutocomplete = ({
|
||||
availableProducts,
|
||||
onSelect,
|
||||
placeholder = 'Search products',
|
||||
onQueryChange,
|
||||
}: ProductAutocompleteProps) => {
|
||||
const categories = useCategories();
|
||||
const categoriesById = useMemo(() => new Map(categories.map((c) => [c.id, c.name])), [categories]);
|
||||
@@ -35,6 +38,7 @@ export const ProductAutocomplete = ({
|
||||
onSelect(selectedProduct);
|
||||
setSelectedProduct(null);
|
||||
setQuery('');
|
||||
if (onQueryChange) onQueryChange('');
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedProduct]);
|
||||
|
||||
@@ -57,8 +61,14 @@ export const ProductAutocomplete = ({
|
||||
onChange={(_, value) => setSelectedProduct(value ?? null)}
|
||||
inputValue={query}
|
||||
onInputChange={(_, value, reason) => {
|
||||
if (reason === 'input') setQuery(value);
|
||||
if (reason === 'clear') setQuery('');
|
||||
if (reason === 'input') {
|
||||
setQuery(value);
|
||||
if (onQueryChange) onQueryChange(value);
|
||||
}
|
||||
if (reason === 'clear') {
|
||||
setQuery('');
|
||||
if (onQueryChange) onQueryChange('');
|
||||
}
|
||||
}}
|
||||
filterOptions={(options) => options}
|
||||
noOptionsText="No available products"
|
||||
@@ -67,6 +77,12 @@ export const ProductAutocomplete = ({
|
||||
<TextField
|
||||
{...params}
|
||||
placeholder={placeholder}
|
||||
/* Add accessible name and stable test id */
|
||||
inputProps={{
|
||||
...params.inputProps,
|
||||
'aria-label': placeholder,
|
||||
'data-testid': 'product-search-input',
|
||||
}}
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
startAdornment: (
|
||||
@@ -74,12 +90,12 @@ export const ProductAutocomplete = ({
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
{params.InputProps.startAdornment}
|
||||
{params.InputProps?.startAdornment}
|
||||
</>
|
||||
),
|
||||
endAdornment: (
|
||||
<>
|
||||
{params.InputProps.endAdornment}
|
||||
{params.InputProps?.endAdornment}
|
||||
<InputAdornment position="end">
|
||||
<Tooltip title="Add a new product">
|
||||
<IconButton aria-label="Add product" component={RouterLink} to="/products" size="small">
|
||||
|
||||
Reference in new issue
Block a user