From dc9cfad401b0bdbdc2f0db07de5ec9c298664748 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 27 Jun 2024 19:00:29 -0700 Subject: [PATCH] covered product editor test cases. --- app/(tabs)/index.tsx | 2 +- components/ProductAttributeEditor.tsx | 36 +++++++------ components/ProductEditor.tsx | 1 + components/ProductEditorItem.tsx | 34 +++++++------ .../__tests__/ProductAttributeEditor-test.tsx | 51 ++++++++++++++----- jest.config.js | 3 ++ 6 files changed, 81 insertions(+), 46 deletions(-) diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 3a920d6..e1b6827 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -5,7 +5,7 @@ import { MeasurementInput } from '@/components/LengthInput'; import { setupStore, useAppDispatch } from '../store'; import { selectProducts } from '@/features/product/productSlice'; import { Product } from '@/lib/product'; -import { ProductTile } from '@/components/ProductTyle'; +import { ProductTile } from '@/components/ProductTile'; import { Measure, area, length } from 'enheter'; export default function HomeScreen() { diff --git a/components/ProductAttributeEditor.tsx b/components/ProductAttributeEditor.tsx index c494ed3..8cba163 100644 --- a/components/ProductAttributeEditor.tsx +++ b/components/ProductAttributeEditor.tsx @@ -1,40 +1,44 @@ import { Product } from "@/lib/product"; import Ionicons from "@expo/vector-icons/Ionicons"; import React from "react"; -import { ChangeEvent, SetStateAction, useState } from "react"; -import { NativeSyntheticEvent, StyleSheet, Text, TextInput, TextInputChangeEventData, TextInputProps, TouchableHighlight, View } from "react-native"; +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 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 [newValue, setNewValue] = useState(value); - const doChange = (e : any) => { - setNewValue(e.target.value); + const doChange = (e: any) => { + setNewValue(e); + onChange && onChange(product.id, key, e); } return ( - - {key} - + {key} + setDoEdit(!doEdit)} + aria-label="Property Value" + > + {doEdit ? + ({newValue}) : + () + } + onDelete && onDelete(product.id, key, value)} aria-label="Delete Attribute"> - {doEdit ? - ( - {newValue} - ) : ( - - ) - } ) diff --git a/components/ProductEditor.tsx b/components/ProductEditor.tsx index 85f6a33..1fbe551 100644 --- a/components/ProductEditor.tsx +++ b/components/ProductEditor.tsx @@ -5,6 +5,7 @@ import { FlatListComponent, StyleSheet, Text } from "react-native"; import { FlatList } from "react-native-reanimated/lib/typescript/Animated"; import { SafeAreaView } from "react-native-safe-area-context"; import { ProductEditorItem } from "./ProductEditorItem"; +import React from "react"; export const ProductEditor = () => { const products = useAppSelector(selectProducts) as Product []; diff --git a/components/ProductEditorItem.tsx b/components/ProductEditorItem.tsx index b068523..532cdaa 100644 --- a/components/ProductEditorItem.tsx +++ b/components/ProductEditorItem.tsx @@ -1,21 +1,21 @@ import { Product } from "@/lib/product" import { useState } from "react" -import { StyleSheet, Text, TouchableHighlight } from "react-native" -import { FlatList } from "react-native-reanimated/lib/typescript/Animated"; -import ProductAttributeEditor from "./ProductAttributeEditor"; +import { FlatList, StyleSheet, Text, TouchableHighlight, View } from "react-native" +import {ProductAttributeEditor} from "./ProductAttributeEditor"; +import React from "react"; -export type ProductUpdatedFunc = (product_id : string, product : Product) => any; -export type ProductDeletedFunc = (product_id : string) => any; +export type ProductUpdatedFunc = (product_id: string, product: Product) => any; +export type ProductDeletedFunc = (product_id: string) => any; export type ProductEditorItemProps = { - product : Product, + product: Product, onProductUpdated?: ProductUpdatedFunc, onProductDeleted?: ProductDeletedFunc, } 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) { product.attributes[key] = newValue; @@ -25,14 +25,17 @@ export const ProductEditorItem = ({ product, onProductUpdated, onProductDeleted function onAttributeDelete(product_id: string, key: string) { product.removeAttribute(key); - onProductUpdated && onProductUpdated(product_id, product); + onProductDeleted && onProductDeleted(product_id); } return ( - setShowAttributes(true)} - > - {product.attributes.name || `Product ${product.id}`} + + setShowAttributes(!showAttributes)} + aria-label="Product Item" + > + {product.attributes.name || `Product ${product.id}`} + {showAttributes && ( ( )} + keyExtractor={(item) => `${product.id}-${item.key}`} /> ) } - + ) } diff --git a/components/__tests__/ProductAttributeEditor-test.tsx b/components/__tests__/ProductAttributeEditor-test.tsx index 59c68a9..b531148 100644 --- a/components/__tests__/ProductAttributeEditor-test.tsx +++ b/components/__tests__/ProductAttributeEditor-test.tsx @@ -1,27 +1,50 @@ import { Product } from "@/lib/product" -import ProductAttributeEditor from "../ProductAttributeEditor" -import { renderWithProviders } from "./util" +import {ProductAttributeEditor} from "../ProductAttributeEditor" 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 { emitTypingEvents } from "@testing-library/react-native/build/user-event/type/type"; describe("Product editor tests", () => { - it("Product attributes render", () => { + it("Product attributes can be deleted", async () => { const product = new Product( 100, area("squareFoot", 4 * 7) ); const onChange = jest.fn(); const onDelete = jest.fn(); - renderWithProviders( - ); - expect(screen.findByLabelText("Delete Attribute")).not.toBeNull(); - + render( + ); + 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( + ); + fireEvent.press(screen.getByText("product")); // Use getByText instead of findByText + fireEvent.changeText(screen.getByLabelText("Edit Value"), "new name"); + expect(onChange).toHaveBeenCalled(); }) + }) \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 3494840..0e5eed8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -3,5 +3,8 @@ module.exports = { preset: 'jest-expo', "transformIgnorePatterns": [ "node_modules/(?!@ngrx|(?!deck.gl)|ng-dynamic)" + ], + "setupFiles": [ + "./setup/jest.js" ] };