change product to dump to object before storing in redix. TODO: solve dimensions issue.
This commit is contained in:
@ -4,31 +4,44 @@ import React from "react";
|
||||
import { useState } from "react";
|
||||
import { StyleSheet, Text, TextInput, TouchableHighlight, View } from "react-native";
|
||||
|
||||
export type ProductAttributeChangeFunc = (product_id: string, key: string, newValue: string) => any;
|
||||
export type ProductAttributeDeleteFunc = (product_id: string, key: string) => any;
|
||||
export type ProductAttributeChangeFunc = (key: string, newValue: string) => any;
|
||||
export type ProductAttributeDeleteFunc = (key: string) => any;
|
||||
export type ChangeAttributeFunction = (oldKey : string, newKey : string) => any;
|
||||
|
||||
export type ProductAttributeProps = { product: Product, attributeKey: string, attributeValue: string, onChange?: ProductAttributeChangeFunc, onDelete?: ProductAttributeChangeFunc, };
|
||||
export type ProductAttributeProps = {
|
||||
attributeKey: string,
|
||||
attributeValue: string,
|
||||
onChangeAttributeKey?: ChangeAttributeFunction,
|
||||
onChangeAttribute?: ProductAttributeChangeFunc,
|
||||
onDelete?: ProductAttributeChangeFunc,
|
||||
};
|
||||
|
||||
export const ProductAttributeEditor = ({ product, attributeKey: key, attributeValue: value, onDelete, onChange }: ProductAttributeProps) => {
|
||||
const [doEdit, setDoEdit] = useState(true);
|
||||
const [newValue, setNewValue] = useState(value);
|
||||
export const ProductAttributeEditor = ({ attributeKey, attributeValue, onDelete, onChangeAttributeKey, onChangeAttribute }: ProductAttributeProps) => {
|
||||
|
||||
const doChange = (e: any) => {
|
||||
setNewValue(e);
|
||||
onChange && onChange(product.id, key, e);
|
||||
const doChangeKey = (e: any) => {
|
||||
onChangeAttributeKey && onChangeAttributeKey(attributeKey, e);
|
||||
}
|
||||
|
||||
const doChangeValue = (e: any) => {
|
||||
onChangeAttribute && onChangeAttribute(attributeKey, e);
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.productAttributeRow}>
|
||||
<Text style={styles.key}>{key}</Text>
|
||||
<TextInput
|
||||
value={newValue}
|
||||
onChangeText={doChange}
|
||||
defaultValue={attributeKey}
|
||||
onChangeText={doChangeKey}
|
||||
style={styles.value}
|
||||
aria-label="Edit Key"
|
||||
/>
|
||||
<TextInput
|
||||
defaultValue={attributeValue}
|
||||
onChangeText={doChangeValue}
|
||||
style={styles.value}
|
||||
aria-label="Edit Value" />
|
||||
<TouchableHighlight
|
||||
onPress={() => onDelete && onDelete(product.id, key, value)}
|
||||
onPress={() => onDelete && onDelete(attributeKey, attributeValue)}
|
||||
aria-label="Delete Attribute"
|
||||
style={{ backgroundColor: "darkred", borderRadius: 5, margin: 5, padding: 5, }}>
|
||||
<Ionicons name="trash-bin-outline" size={30} color={"white"} />
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||
import { deleteProduct, selectProducts, updateProduct } from "@/features/product/productSlice"
|
||||
import { Product } from "@/lib/product";
|
||||
import { addAttribute, changeKey, deleteAttribute, deleteProduct, selectProductIds, selectProducts, updateAttribute, updateDimensions, updatePrice, updateProduct } from "@/features/product/productSlice"
|
||||
import { Id, Product, dimensions_t } from "@/lib/product";
|
||||
import { FlatList, SafeAreaView, StyleSheet, Text } from "react-native";
|
||||
import { ProductEditorItem } from "./ProductEditorItem";
|
||||
|
||||
@ -13,23 +13,50 @@ export const ProductEditor = ({}) => {
|
||||
dispatch(deleteProduct(product_id));
|
||||
}
|
||||
|
||||
function onProductUpdated(product_id: string, product: Product) {
|
||||
dispatch(updateProduct(product));
|
||||
function onAttributeDelete(product_id: string, attribute: string) {
|
||||
dispatch(deleteAttribute({product_id: product_id, attribute}));
|
||||
}
|
||||
|
||||
function onAttributeUpdated(product_id: string, attribute: string, value: string) {
|
||||
dispatch(updateAttribute({product_id, attributeKey: attribute, attributeValue: value}));
|
||||
}
|
||||
|
||||
function onAttributeAdded(product_id: Id) {
|
||||
console.log("Adding attribute to %s", product_id);
|
||||
dispatch(addAttribute(product_id));
|
||||
}
|
||||
|
||||
function onPriceUpdated(product_id: string, pricePerUnit: number) {
|
||||
dispatch(updatePrice({product_id, pricePerUnit}));
|
||||
}
|
||||
|
||||
function onAttributeKeyChanged(product_id : string, oldKey : string, newKey : string) {
|
||||
dispatch(changeKey({product_id, oldKey, newKey}))
|
||||
}
|
||||
|
||||
function onDimensionUpdated(product_id: string, dimensions: dimensions_t) {
|
||||
dispatch(updateDimensions({product_id, dimensions}));
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<h1 style={styles.h1}>Edit Products</h1>
|
||||
<FlatList
|
||||
data={products}
|
||||
keyExtractor={(p, i) => `product-${p.id}`}
|
||||
renderItem={
|
||||
({item}) => {
|
||||
|
||||
return (
|
||||
<ProductEditorItem
|
||||
product={item}
|
||||
onProductDeleted={onProductDeleted}
|
||||
onProductUpdated={onProductUpdated}
|
||||
onAttributeDeleted={onAttributeDelete}
|
||||
onAttributeKeyChanged={onAttributeKeyChanged}
|
||||
onAttributeUpdated={onAttributeUpdated}
|
||||
onAttributeAdded={onAttributeAdded}
|
||||
onPriceUpdated={onPriceUpdated}
|
||||
onDimensionsUpdated={onDimensionUpdated}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -1,41 +1,86 @@
|
||||
import { Product } from "@/lib/product"
|
||||
import { Id, Product, dimensions_t } from "@/lib/product"
|
||||
import { useState } from "react"
|
||||
import { FlatList, StyleSheet, Text, TouchableHighlight, View } from "react-native"
|
||||
import { Button, FlatList, StyleSheet, Text, Touchable, TouchableHighlight, View } from "react-native"
|
||||
import { ProductAttributeEditor } from "./ProductAttributeEditor";
|
||||
import { TextInput } from "react-native-gesture-handler";
|
||||
import { useAppSelector } from "@/app/store";
|
||||
import rfdc from "rfdc";
|
||||
import SelectDropdown from "react-native-select-dropdown";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
|
||||
export type ProductUpdatedFunc = (product_id: string, product: Product) => any;
|
||||
export type ProductDeletedFunc = (product_id: string) => any;
|
||||
export type ProductAddedFunc = () => any;
|
||||
export type ProductDeletedFunc = (product_id: Id) => any;
|
||||
export type AttributeAddedFunc = (product_id: Id) => any;
|
||||
export type AttributeKeyUpdatedFunc = (product_id: Id, oldKey: string, newKey: string) => any;
|
||||
export type AttributeUpdatedFunc = (product_id: Id, attribute: string, value: string) => any;
|
||||
export type AttributeDeletedFunc = (product_id: Id, attribute: string) => any;
|
||||
export type PriceUpdatedFunc = (product_id: Id, price: number) => any;
|
||||
export type DimensionUpdatedFunc = (product_id: Id, dimension: dimensions_t) => any;
|
||||
|
||||
export type ProductEditorItemProps = {
|
||||
product: Product,
|
||||
onProductUpdated?: ProductUpdatedFunc,
|
||||
onProductAdded?: ProductAddedFunc,
|
||||
onProductDeleted?: ProductDeletedFunc,
|
||||
onAttributeAdded?: AttributeAddedFunc,
|
||||
onAttributeKeyChanged?: AttributeKeyUpdatedFunc,
|
||||
onAttributeUpdated?: AttributeUpdatedFunc,
|
||||
onAttributeDeleted?: AttributeDeletedFunc,
|
||||
onPriceUpdated?: PriceUpdatedFunc,
|
||||
onDimensionsUpdated?: DimensionUpdatedFunc,
|
||||
}
|
||||
|
||||
export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted }: ProductEditorItemProps) => {
|
||||
export const ProductEditorItem = (props: ProductEditorItemProps) => {
|
||||
|
||||
const [showAttributes, setShowAttributes] = useState(false);
|
||||
const [doEditName, setDoEditName] = useState(false);
|
||||
const [newName, setNewName] = useState(product.attributes.name || `Product ${product.id}`);
|
||||
const product = props.product;
|
||||
|
||||
function updateName(name : string) {
|
||||
setNewName(name);
|
||||
product.attributes["name"] = name;
|
||||
onProductUpdated && onProductUpdated(product.id, product);
|
||||
function onAttributeChanged(key: string, newValue: string) {
|
||||
props.onAttributeUpdated && props.onAttributeUpdated(product.id, key, newValue);
|
||||
}
|
||||
|
||||
function onAttributeChanged(product_id: string, key: string, newValue: string) {
|
||||
product.attributes[key] = newValue;
|
||||
onProductUpdated && onProductUpdated(product_id, product);
|
||||
|
||||
function onAttributeKeyChanged(oldKey: string, newKey: string) {
|
||||
props.onAttributeKeyChanged && props.onAttributeKeyChanged(product.id, oldKey, newKey);
|
||||
}
|
||||
|
||||
function onAttributeDelete(product_id: string, key: string) {
|
||||
product.removeAttribute(key);
|
||||
onProductDeleted && onProductDeleted(product_id);
|
||||
function onAttributeDelete(key: string) {
|
||||
props.onAttributeDeleted && props.onAttributeDeleted(product.id, key);
|
||||
}
|
||||
|
||||
function onPricePerUnitChange(pricePerUnit: string) {
|
||||
props.onPriceUpdated && props.onPriceUpdated(product.id, parseFloat(pricePerUnit) || parseInt(pricePerUnit));
|
||||
}
|
||||
|
||||
function onUnitsChanged(newUnits: "foot" | "inch") {
|
||||
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
|
||||
...((product.area || product.length) as dimensions_t),
|
||||
u: newUnits,
|
||||
})
|
||||
}
|
||||
|
||||
function onChangeLength(len: string) {
|
||||
const l = parseFloat(len) || parseInt(len);
|
||||
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
|
||||
...((product.area || product.length) as dimensions_t),
|
||||
l,
|
||||
})
|
||||
}
|
||||
|
||||
function onChangeWidth(width: string) {
|
||||
const w = parseFloat(width) || parseInt(width);
|
||||
props.onDimensionsUpdated && props.onDimensionsUpdated(product.id, {
|
||||
...((product.area || product.length) as dimensions_t),
|
||||
w,
|
||||
})
|
||||
}
|
||||
|
||||
function onDeleteProduct() {
|
||||
props.onProductDeleted && props.onProductDeleted(product.id);
|
||||
}
|
||||
|
||||
const length = new String(product.area?.l || product.length?.l || "0") as string;
|
||||
const width = new String(product.area?.w || "") as string;
|
||||
const dimension = product.area?.u || product.length?.u || "foot";
|
||||
|
||||
return (
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
@ -43,24 +88,67 @@ export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted
|
||||
aria-label="Product Item"
|
||||
style={styles.productItemName}
|
||||
>
|
||||
<Text style={styles.productNameText}>{newName}</Text>
|
||||
<Text style={styles.productNameText}>{product.attributes.name || `Product ${product.id}`}</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
onPress={() => onDeleteProduct()}
|
||||
aria-label="delete product"
|
||||
style={styles.deleteProductHighlight}
|
||||
>
|
||||
<Ionicons style={styles.deleteProductButton} name="trash-outline" />
|
||||
</TouchableHighlight>
|
||||
{showAttributes &&
|
||||
(
|
||||
<FlatList
|
||||
style={styles.productAttributesList}
|
||||
data={product.attributesAsList}
|
||||
renderItem={({ item }) => (
|
||||
<ProductAttributeEditor
|
||||
product={product}
|
||||
attributeKey={item.key || "some key"}
|
||||
attributeValue={item.value}
|
||||
onChange={onAttributeChanged}
|
||||
onDelete={onAttributeDelete}
|
||||
<View>
|
||||
<View style={styles.priceSpecWrapper}>
|
||||
<Text style={styles.priceLabel}></Text>
|
||||
<TextInput inputMode="decimal"
|
||||
defaultValue={new String(product.pricePerUnit) as string}
|
||||
aria-label="price per unit"
|
||||
onChangeText={onPricePerUnitChange}
|
||||
style={styles.priceInput}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={(item) => `${product.id}-${item.key}`}
|
||||
/>
|
||||
<Text style={styles.per}>per</Text>
|
||||
<Text style={styles.unitsLabel}>Units: </Text>
|
||||
<select
|
||||
onChange={(e) => onUnitsChanged(e.target.value as "foot" | "inch")}
|
||||
style={styles.unitsSelect}
|
||||
aria-label="units">
|
||||
<option value="foot" selected={dimension === "foot"}>feet</option>
|
||||
<option value="inch" selected={dimension === "inch"}>inches</option>
|
||||
</select>
|
||||
<TextInput
|
||||
inputMode="decimal"
|
||||
defaultValue={length}
|
||||
onChangeText={onChangeLength}
|
||||
style={styles.lengthInput}
|
||||
aria-label="length"
|
||||
/>
|
||||
<Text>x</Text>
|
||||
<TextInput
|
||||
inputMode="decimal"
|
||||
defaultValue={width}
|
||||
onChangeText={onChangeWidth}
|
||||
style={styles.widthInput}
|
||||
aria-label="width"
|
||||
/>
|
||||
</View>
|
||||
<Button title="+ Add Attribute" onPress={() => props.onAttributeAdded && props.onAttributeAdded(product.id)} />
|
||||
<FlatList
|
||||
style={styles.productAttributesList}
|
||||
data={Object.entries(product.attributes)}
|
||||
renderItem={({ item }) => (
|
||||
<ProductAttributeEditor
|
||||
attributeKey={item[0] || "some key"}
|
||||
attributeValue={item[1]}
|
||||
onChangeAttributeKey={onAttributeKeyChanged}
|
||||
onChangeAttribute={onAttributeChanged}
|
||||
onDelete={onAttributeDelete}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={(item, i) => `${product.id}-${i}`}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
</View>
|
||||
@ -68,6 +156,36 @@ export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
deleteProductHighlight: {
|
||||
|
||||
},
|
||||
deleteProductButton: {
|
||||
|
||||
},
|
||||
priceSpecWrapper: {
|
||||
|
||||
},
|
||||
priceLabel: {
|
||||
|
||||
},
|
||||
priceInput: {
|
||||
|
||||
},
|
||||
per: {
|
||||
|
||||
},
|
||||
unitsLabel: {
|
||||
|
||||
},
|
||||
unitsSelect: {
|
||||
|
||||
},
|
||||
lengthInput: {
|
||||
|
||||
},
|
||||
widthInput: {
|
||||
|
||||
},
|
||||
productNameText: {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
|
@ -6,10 +6,12 @@ import React from "react";
|
||||
import { emitTypingEvents } from "@testing-library/react-native/build/user-event/type/type";
|
||||
|
||||
describe("Product editor tests", () => {
|
||||
const productName = "Fun Product";
|
||||
it("Product attributes can be deleted", async () => {
|
||||
const product = new Product(
|
||||
100,
|
||||
area("squareFoot", 4 * 7)
|
||||
{l: 100, u: "foot"},
|
||||
{"name" : productName}
|
||||
);
|
||||
const onChange = jest.fn();
|
||||
const onDelete = jest.fn();
|
||||
@ -18,7 +20,7 @@ describe("Product editor tests", () => {
|
||||
attributeKey="name"
|
||||
attributeValue="product"
|
||||
product={product}
|
||||
onChange={onChange}
|
||||
onChangeAttribute={onChange}
|
||||
onDelete={onDelete}
|
||||
/>);
|
||||
expect(screen.getByLabelText("Delete Attribute")).not.toBeNull();
|
||||
@ -26,25 +28,28 @@ describe("Product editor tests", () => {
|
||||
expect(onDelete).toHaveBeenCalled();
|
||||
});
|
||||
it("Product attributes can be modified", async () => {
|
||||
const productName = "Fun Product";
|
||||
const product = new Product(
|
||||
100,
|
||||
area("squareFoot", 4 * 7),
|
||||
{ name: productName },
|
||||
{l: 100, u: "foot"},
|
||||
{"name" : productName}
|
||||
);
|
||||
const onChange = jest.fn();
|
||||
const onDelete = jest.fn();
|
||||
const onKeyChange = jest.fn();
|
||||
render(
|
||||
<ProductAttributeEditor
|
||||
attributeKey="Name"
|
||||
attributeValue="product"
|
||||
product={product}
|
||||
onChange={onChange}
|
||||
attributeKey="old test key"
|
||||
attributeValue="old test value"
|
||||
onChangeAttribute={onChange}
|
||||
onDelete={onDelete}
|
||||
onChangeAttributeKey={onKeyChange}
|
||||
/>);
|
||||
fireEvent.press(screen.getByText("product")); // Use getByText instead of findByText
|
||||
fireEvent.changeText(screen.getByLabelText("Edit Key"), "new test key");
|
||||
expect(onKeyChange).toHaveBeenCalled();
|
||||
fireEvent.changeText(screen.getByLabelText("Edit Value"), "new name");
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
fireEvent.press(screen.getByLabelText("Delete Attribute"));
|
||||
expect(onDelete).toHaveBeenCalled();
|
||||
})
|
||||
|
||||
})
|
@ -1,25 +1,51 @@
|
||||
import { renderWithProviders } from "@/lib/rendering";
|
||||
import { ProductEditor } from "@/components/ProductEditor";
|
||||
import {products as fixtures} from "@/__fixtures__/initialProducts";
|
||||
import { screen } from "@testing-library/react-native";
|
||||
import { act, fireEvent, screen } from "@testing-library/react-native";
|
||||
import { selectProducts } from "@/features/product/productSlice";
|
||||
import { Product } from "@/lib/product";
|
||||
|
||||
describe("ProductEditor", () => {
|
||||
const productName = "Flooring"
|
||||
const mockProduct = new Product(
|
||||
25,
|
||||
{ l: 4, w: 8, u: "foot" },
|
||||
{ name: productName },
|
||||
)
|
||||
it("renders correctly", async () => {
|
||||
const {store} = renderWithProviders(<ProductEditor />, {
|
||||
products: fixtures,
|
||||
const { store } = renderWithProviders(<ProductEditor />, {
|
||||
products: [
|
||||
mockProduct.asObject,
|
||||
],
|
||||
});
|
||||
|
||||
const state1 = store.getState();
|
||||
|
||||
const products = selectProducts(state1);
|
||||
let products = selectProducts(state1);
|
||||
|
||||
expect(products).toHaveLength(6);
|
||||
expect(products).toHaveLength(1);
|
||||
|
||||
// Check if the product names are rendered
|
||||
expect(screen.getByText(products[0].attributes.name as string)).toBeTruthy();
|
||||
expect(screen.getByText(products[1].attributes.name as string)).toBeTruthy();
|
||||
expect(screen.getByText(products[2].attributes.name as string)).toBeTruthy();
|
||||
expect(screen.getByText(products[3].attributes.name as string)).toBeTruthy();
|
||||
|
||||
// Start to edit a product
|
||||
fireEvent.press(screen.getByText(productName));
|
||||
|
||||
// Change properties of the product to make sure it's updated in the store
|
||||
|
||||
act(() => {
|
||||
fireEvent.changeText(screen.getByLabelText("length"), "16");
|
||||
})
|
||||
products = selectProducts(store.getState());
|
||||
expect(products[0].dimensions.l).toBe(16);
|
||||
act(() => {
|
||||
fireEvent.changeText(screen.getByLabelText("width"), "32");
|
||||
})
|
||||
products = selectProducts(store.getState());
|
||||
|
||||
expect(products[0].dimensions.w).toBe(32);
|
||||
|
||||
fireEvent.press(screen.getByLabelText("delete product"));
|
||||
products = selectProducts(store.getState());
|
||||
expect(products.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
@ -3,22 +3,36 @@ import { render, fireEvent, screen } from '@testing-library/react-native';
|
||||
import { ProductEditorItem } from '../ProductEditorItem';
|
||||
import { Product } from '@/lib/product';
|
||||
import { area } from 'enheter';
|
||||
import { renderWithProviders } from '@/lib/rendering';
|
||||
|
||||
describe('ProductEditorItem', () => {
|
||||
const productName = "Product 1";
|
||||
const mockProduct = new Product(
|
||||
25,
|
||||
area("squareFoot", 4 * 8),
|
||||
{"name": "Product 1"},
|
||||
{l: 4, u: 'feet'},
|
||||
{"name": productName},
|
||||
)
|
||||
|
||||
const mockOnProductUpdated = jest.fn();
|
||||
const onAttributeAdded = jest.fn();
|
||||
const mockOnProductDeleted = jest.fn();
|
||||
const onAttributeDeleted = jest.fn();
|
||||
const onAttributeKeyChanged = jest.fn();
|
||||
const onAttributeUpdated = jest.fn();
|
||||
const onProductAdded = jest.fn();
|
||||
const onPriceUpdated = jest.fn();
|
||||
const onDimensionUpdated = jest.fn();
|
||||
|
||||
it('renders correctly', () => {
|
||||
render(
|
||||
<ProductEditorItem
|
||||
product={mockProduct}
|
||||
onProductUpdated={mockOnProductUpdated}
|
||||
onAttributeAdded={onAttributeAdded}
|
||||
onAttributeDeleted={onAttributeDeleted}
|
||||
onAttributeKeyChanged={onAttributeKeyChanged}
|
||||
onAttributeUpdated={onAttributeUpdated}
|
||||
onProductAdded={onProductAdded}
|
||||
onPriceUpdated={onPriceUpdated}
|
||||
onDimensionsUpdated={onDimensionUpdated}
|
||||
onProductDeleted={mockOnProductDeleted}
|
||||
/>
|
||||
);
|
||||
@ -26,15 +40,37 @@ describe('ProductEditorItem', () => {
|
||||
});
|
||||
|
||||
it('calls onProductUpdated when TouchableHighlight is pressed', () => {
|
||||
render(
|
||||
const {store} = renderWithProviders(
|
||||
<ProductEditorItem
|
||||
product={mockProduct}
|
||||
onProductUpdated={mockOnProductUpdated}
|
||||
onAttributeAdded={onAttributeAdded}
|
||||
onAttributeDeleted={onAttributeDeleted}
|
||||
onAttributeKeyChanged={onAttributeKeyChanged}
|
||||
onAttributeUpdated={onAttributeUpdated}
|
||||
onProductAdded={onProductAdded}
|
||||
onPriceUpdated={onPriceUpdated}
|
||||
onDimensionsUpdated={onDimensionUpdated}
|
||||
onProductDeleted={mockOnProductDeleted}
|
||||
/>
|
||||
/>, {
|
||||
products: [mockProduct],
|
||||
}
|
||||
);
|
||||
fireEvent.press(screen.getByText("Product 1"));
|
||||
expect(screen.getByText('name')).toBeTruthy();
|
||||
expect(screen.getAllByText('Product 1').length).toEqual(2);
|
||||
expect(screen.getByLabelText("units")).toBeTruthy();
|
||||
expect(screen.getByLabelText("Edit Key")).toBeTruthy();
|
||||
expect(screen.getAllByLabelText("Edit Value").length).toEqual(1);
|
||||
|
||||
// Now start modifying the properties.
|
||||
fireEvent.changeText(screen.getByLabelText("price per unit"), "40.00");
|
||||
expect(onPriceUpdated).toHaveBeenCalled();
|
||||
|
||||
fireEvent.changeText(screen.getByLabelText("length"), "12");
|
||||
expect(onDimensionUpdated).toHaveBeenCalled();
|
||||
|
||||
fireEvent.changeText(screen.getByLabelText("width"), "12");
|
||||
expect(onDimensionUpdated).toHaveBeenCalled();
|
||||
|
||||
fireEvent.press(screen.getByLabelText("delete product"));
|
||||
expect(mockOnProductDeleted).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user