covered product editor test cases.
This commit is contained in:
parent
562cae7f5a
commit
dc9cfad401
@ -5,7 +5,7 @@ import { MeasurementInput } from '@/components/LengthInput';
|
|||||||
import { setupStore, useAppDispatch } from '../store';
|
import { setupStore, useAppDispatch } from '../store';
|
||||||
import { selectProducts } from '@/features/product/productSlice';
|
import { selectProducts } from '@/features/product/productSlice';
|
||||||
import { Product } from '@/lib/product';
|
import { Product } from '@/lib/product';
|
||||||
import { ProductTile } from '@/components/ProductTyle';
|
import { ProductTile } from '@/components/ProductTile';
|
||||||
import { Measure, area, length } from 'enheter';
|
import { Measure, area, length } from 'enheter';
|
||||||
|
|
||||||
export default function HomeScreen() {
|
export default function HomeScreen() {
|
||||||
|
@ -1,40 +1,44 @@
|
|||||||
import { Product } from "@/lib/product";
|
import { Product } from "@/lib/product";
|
||||||
import Ionicons from "@expo/vector-icons/Ionicons";
|
import Ionicons from "@expo/vector-icons/Ionicons";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ChangeEvent, SetStateAction, useState } from "react";
|
import { useState } from "react";
|
||||||
import { NativeSyntheticEvent, StyleSheet, Text, TextInput, TextInputChangeEventData, TextInputProps, TouchableHighlight, View } from "react-native";
|
import { StyleSheet, Text, TextInput, TouchableHighlight, View } from "react-native";
|
||||||
|
|
||||||
export type ProductAttributeChangeFunc = (product_id: string, key: string, newValue: string) => any;
|
export type ProductAttributeChangeFunc = (product_id: string, key: string, newValue: string) => any;
|
||||||
export type ProductAttributeDeleteFunc = (product_id: string, key: string) => any;
|
export type ProductAttributeDeleteFunc = (product_id: string, key: string) => any;
|
||||||
|
|
||||||
export type ProductAttributeProps = { product: Product, key: string, value: string, onChange?: ProductAttributeChangeFunc, onDelete?: ProductAttributeChangeFunc, };
|
export type ProductAttributeProps = { product: Product, attributeKey: string, attributeValue: string, onChange?: ProductAttributeChangeFunc, onDelete?: ProductAttributeChangeFunc, };
|
||||||
|
|
||||||
export default function ProductAttributeEditor({ product, key, value, onDelete, onChange }: ProductAttributeProps) {
|
export const ProductAttributeEditor = ({ product, attributeKey: key, attributeValue: value, onDelete, onChange } : ProductAttributeProps) => {
|
||||||
const [doEdit, setDoEdit] = useState(true);
|
const [doEdit, setDoEdit] = useState(true);
|
||||||
const [newValue, setNewValue] = useState(value);
|
const [newValue, setNewValue] = useState(value);
|
||||||
|
|
||||||
const doChange = (e : any) => {
|
const doChange = (e: any) => {
|
||||||
setNewValue(e.target.value);
|
setNewValue(e);
|
||||||
|
onChange && onChange(product.id, key, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<Text>
|
<Text>{key}</Text>
|
||||||
{key}
|
|
||||||
</Text>
|
|
||||||
<View>
|
<View>
|
||||||
|
<TouchableHighlight
|
||||||
|
onPress={() => setDoEdit(!doEdit)}
|
||||||
|
aria-label="Property Value"
|
||||||
|
>
|
||||||
|
{doEdit ?
|
||||||
|
(<Text>{newValue}</Text>) :
|
||||||
|
(<TextInput
|
||||||
|
value={newValue}
|
||||||
|
onChangeText={doChange}
|
||||||
|
aria-label="Edit Value" />)
|
||||||
|
}
|
||||||
|
</TouchableHighlight>
|
||||||
<TouchableHighlight
|
<TouchableHighlight
|
||||||
onPress={() => onDelete && onDelete(product.id, key, value)}
|
onPress={() => onDelete && onDelete(product.id, key, value)}
|
||||||
aria-label="Delete Attribute">
|
aria-label="Delete Attribute">
|
||||||
<Ionicons name="trash-bin-outline" />
|
<Ionicons name="trash-bin-outline" />
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
{doEdit ?
|
|
||||||
(<Text>
|
|
||||||
{newValue}
|
|
||||||
</Text>) : (
|
|
||||||
<TextInput value={newValue} onChange={doChange} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ import { FlatListComponent, StyleSheet, Text } from "react-native";
|
|||||||
import { FlatList } from "react-native-reanimated/lib/typescript/Animated";
|
import { FlatList } from "react-native-reanimated/lib/typescript/Animated";
|
||||||
import { SafeAreaView } from "react-native-safe-area-context";
|
import { SafeAreaView } from "react-native-safe-area-context";
|
||||||
import { ProductEditorItem } from "./ProductEditorItem";
|
import { ProductEditorItem } from "./ProductEditorItem";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
export const ProductEditor = () => {
|
export const ProductEditor = () => {
|
||||||
const products = useAppSelector(selectProducts) as Product [];
|
const products = useAppSelector(selectProducts) as Product [];
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import { Product } from "@/lib/product"
|
import { Product } from "@/lib/product"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { StyleSheet, Text, TouchableHighlight } from "react-native"
|
import { FlatList, StyleSheet, Text, TouchableHighlight, View } from "react-native"
|
||||||
import { FlatList } from "react-native-reanimated/lib/typescript/Animated";
|
import {ProductAttributeEditor} from "./ProductAttributeEditor";
|
||||||
import ProductAttributeEditor from "./ProductAttributeEditor";
|
import React from "react";
|
||||||
|
|
||||||
export type ProductUpdatedFunc = (product_id : string, product : Product) => any;
|
export type ProductUpdatedFunc = (product_id: string, product: Product) => any;
|
||||||
export type ProductDeletedFunc = (product_id : string) => any;
|
export type ProductDeletedFunc = (product_id: string) => any;
|
||||||
|
|
||||||
export type ProductEditorItemProps = {
|
export type ProductEditorItemProps = {
|
||||||
product : Product,
|
product: Product,
|
||||||
onProductUpdated?: ProductUpdatedFunc,
|
onProductUpdated?: ProductUpdatedFunc,
|
||||||
onProductDeleted?: ProductDeletedFunc,
|
onProductDeleted?: ProductDeletedFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted }: ProductEditorItemProps) => {
|
export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted }: ProductEditorItemProps) => {
|
||||||
|
|
||||||
const [showAttributes, setShowAttributes] = useState(true);
|
const [showAttributes, setShowAttributes] = useState(false);
|
||||||
|
|
||||||
function onAttributeChanged(product_id: string, key: string, newValue: string) {
|
function onAttributeChanged(product_id: string, key: string, newValue: string) {
|
||||||
product.attributes[key] = newValue;
|
product.attributes[key] = newValue;
|
||||||
@ -25,14 +25,17 @@ export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted
|
|||||||
|
|
||||||
function onAttributeDelete(product_id: string, key: string) {
|
function onAttributeDelete(product_id: string, key: string) {
|
||||||
product.removeAttribute(key);
|
product.removeAttribute(key);
|
||||||
onProductUpdated && onProductUpdated(product_id, product);
|
onProductDeleted && onProductDeleted(product_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<View>
|
||||||
<TouchableHighlight
|
<TouchableHighlight
|
||||||
onPress={() => setShowAttributes(true)}
|
onPress={() => setShowAttributes(!showAttributes)}
|
||||||
|
aria-label="Product Item"
|
||||||
>
|
>
|
||||||
<Text style={styles.product}>{product.attributes.name || `Product ${product.id}`} </Text>
|
<Text style={styles.product}>{product.attributes.name || `Product ${product.id}`} </Text>
|
||||||
|
</TouchableHighlight>
|
||||||
{showAttributes &&
|
{showAttributes &&
|
||||||
(
|
(
|
||||||
<FlatList
|
<FlatList
|
||||||
@ -40,16 +43,17 @@ export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted
|
|||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<ProductAttributeEditor
|
<ProductAttributeEditor
|
||||||
product={product}
|
product={product}
|
||||||
key={item.key}
|
attributeKey={item.key || "some key"}
|
||||||
value={item.value}
|
attributeValue={item.value}
|
||||||
onChange={onAttributeChanged}
|
onChange={onAttributeChanged}
|
||||||
onDelete={onAttributeDelete}
|
onDelete={onAttributeDelete}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
keyExtractor={(item) => `${product.id}-${item.key}`}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</TouchableHighlight>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,27 +1,50 @@
|
|||||||
import { Product } from "@/lib/product"
|
import { Product } from "@/lib/product"
|
||||||
import ProductAttributeEditor from "../ProductAttributeEditor"
|
import {ProductAttributeEditor} from "../ProductAttributeEditor"
|
||||||
import { renderWithProviders } from "./util"
|
|
||||||
import { area } from "enheter"
|
import { area } from "enheter"
|
||||||
import {screen} from '@testing-library/react-native';
|
import { fireEvent, render, screen } from '@testing-library/react-native';
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { emitTypingEvents } from "@testing-library/react-native/build/user-event/type/type";
|
||||||
|
|
||||||
describe("Product editor tests", () => {
|
describe("Product editor tests", () => {
|
||||||
it("Product attributes render", () => {
|
it("Product attributes can be deleted", async () => {
|
||||||
const product = new Product(
|
const product = new Product(
|
||||||
100,
|
100,
|
||||||
area("squareFoot", 4 * 7)
|
area("squareFoot", 4 * 7)
|
||||||
);
|
);
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const onDelete = jest.fn();
|
const onDelete = jest.fn();
|
||||||
renderWithProviders(
|
render(
|
||||||
<ProductAttributeEditor
|
<ProductAttributeEditor
|
||||||
key="Name"
|
attributeKey="name"
|
||||||
value="product"
|
attributeValue="product"
|
||||||
product={product}
|
product={product}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
/>);
|
/>);
|
||||||
expect(screen.findByLabelText("Delete Attribute")).not.toBeNull();
|
expect(screen.getByLabelText("Delete Attribute")).not.toBeNull();
|
||||||
|
fireEvent.press(await screen.getByLabelText("Delete Attribute"));
|
||||||
|
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 },
|
||||||
|
);
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const onDelete = jest.fn();
|
||||||
|
render(
|
||||||
|
<ProductAttributeEditor
|
||||||
|
attributeKey="Name"
|
||||||
|
attributeValue="product"
|
||||||
|
product={product}
|
||||||
|
onChange={onChange}
|
||||||
|
onDelete={onDelete}
|
||||||
|
/>);
|
||||||
|
fireEvent.press(screen.getByText("product")); // Use getByText instead of findByText
|
||||||
|
fireEvent.changeText(screen.getByLabelText("Edit Value"), "new name");
|
||||||
|
expect(onChange).toHaveBeenCalled();
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
@ -3,5 +3,8 @@ module.exports = {
|
|||||||
preset: 'jest-expo',
|
preset: 'jest-expo',
|
||||||
"transformIgnorePatterns": [
|
"transformIgnorePatterns": [
|
||||||
"node_modules/(?!@ngrx|(?!deck.gl)|ng-dynamic)"
|
"node_modules/(?!@ngrx|(?!deck.gl)|ng-dynamic)"
|
||||||
|
],
|
||||||
|
"setupFiles": [
|
||||||
|
"./setup/jest.js"
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user