ListingDetail_test.tsx
1 import "../happyDomSetup.ts"; 2 import { cleanup, render, screen, waitFor } from "@testing-library/react"; 3 import { expect } from "@std/expect"; 4 import { userEvent } from "@testing-library/user-event"; 5 6 import { random256BigInt } from "@massmarket/utils"; 7 import { Listing, Order } from "@massmarket/schema"; 8 import { allListings } from "@massmarket/schema/testFixtures"; 9 import type { CodecKey, CodecValue } from "@massmarket/utils/codec"; 10 11 import ListingDetail from "./ListingDetail.tsx"; 12 import { createRouterWrapper, testClient } from "../testutils/mod.tsx"; 13 import { formatUnits } from "viem"; 14 import { OrderState } from "../types.ts"; 15 16 Deno.test("Check that we can render the listing details screen", { 17 sanitizeResources: false, 18 sanitizeOps: false, 19 }, async () => { 20 const shopId = random256BigInt(); 21 22 const { 23 stateManager: merchantStateManager, 24 relayClient: merchantRelayClient, 25 } = await createRouterWrapper({ 26 shopId, 27 createShop: true, 28 enrollMerchant: true, 29 }); 30 merchantStateManager.addConnection(merchantRelayClient); 31 let listing: Listing; 32 const listingId = 23; 33 if (!allListings.has(listingId)) { 34 throw new Error(`Listing ${listingId} not found`); 35 } 36 for (const [key, entry] of allListings.entries()) { 37 await merchantStateManager.set(["Listings", key], entry); 38 if (key === listingId) { 39 listing = entry as Listing; 40 } 41 } 42 43 await merchantStateManager.set(["Inventory", listingId], 30); 44 45 // Remove merchant's keycard to free up for customer 46 localStorage.removeItem(`keycard${shopId}`); 47 48 // Set up customer 49 const { wrapper, stateManager, relayClient, testAccount } = 50 await createRouterWrapper({ 51 shopId, 52 path: `/?itemId=${listingId}`, 53 }); 54 await relayClient.enrollKeycard(testClient, testAccount, true); 55 await relayClient.connect(); 56 await relayClient.authenticate(); 57 stateManager.addConnection(relayClient); 58 59 await waitFor(async () => { 60 const storedListings = await stateManager.get(["Listings"]) as Map< 61 number, 62 unknown 63 >; 64 expect(storedListings.size).toBe(allListings.size); 65 }); 66 const { unmount } = render(<ListingDetail />, { wrapper }); 67 68 await screen.findByTestId("listing-detail-page"); 69 await waitFor(() => { 70 const price = screen.getByTestId("price"); 71 expect(price.textContent).toBe(formatUnits(listing.Price, 18)); 72 const description = screen.getByTestId("description"); 73 expect(description.textContent).toBe(listing.Metadata.Description); 74 const title = screen.getByTestId("title"); 75 expect(title.textContent).toBe(listing.Metadata.Title); 76 }); 77 78 let allOrders = await stateManager.get(["Orders"]) as Map<string, unknown>; 79 expect(allOrders.size).toBe(0); 80 81 // Test adding to cart 82 const user = userEvent.setup(); 83 84 // initial quantity chosen for item 85 const initialQty = 2; 86 // how much the quantity is increased with on the user's second pass 87 const qtyIncreasedBy = 7; 88 const qtyIncreasedBy2 = 3; 89 90 let successToast; 91 let successToastText; 92 const purchaseQty = await screen.findByTestId("purchaseQty"); 93 expect(purchaseQty).toBeTruthy(); 94 await user.clear(purchaseQty); 95 await user.type(purchaseQty, `${initialQty}`); 96 const addToCart = screen.getByTestId("addToCart"); 97 await user.click(addToCart); 98 // wait for the success toast to appear 99 successToast = await screen.findByTestId("success-toast"); 100 expect(successToast).toBeTruthy(); 101 // the success toast text should have its message begin with `${initialQty}` 102 // first off: the toast text should begin with `${initialQty}` since initialQty > 1) 103 successToastText = await screen.findByText( 104 `${initialQty} items added`, 105 ); 106 expect(successToastText.textContent?.startsWith(`${initialQty}`)) 107 .toBeTruthy(); 108 109 allOrders = await stateManager.get(["Orders"]) as Map<string, unknown>; 110 expect(allOrders.size).toBe(1); 111 112 const orderId = Array.from(allOrders.keys())[0]; 113 const orderData = await stateManager.get(["Orders", orderId]); 114 expect(orderData).toBeDefined(); 115 116 const order = Order.fromCBOR(orderData!); 117 expect(order.Items[0].ListingID).toBe(listingId); 118 expect(order.Items[0].Quantity).toBe(initialQty); 119 120 // Update quantity 121 122 const purchaseQty2 = await screen.findByTestId("purchaseQty"); 123 expect(purchaseQty2).toBeTruthy(); 124 await user.clear(purchaseQty2); 125 await user.type(purchaseQty2, `${qtyIncreasedBy}`); 126 const addToCart2 = screen.getByTestId("addToCart"); 127 await user.click(addToCart2); 128 // wait for the success toast to appear 129 successToast = await screen.findByTestId("success-toast"); 130 expect(successToast).toBeTruthy(); 131 // now: its text should begin with `${qtyIncreasedBy}` 132 successToastText = await screen.findByText( 133 `${qtyIncreasedBy} items added`, 134 ); 135 expect(successToastText.textContent?.startsWith(`${qtyIncreasedBy}`)) 136 .toBeTruthy(); 137 138 const d = await stateManager.get(["Orders", orderId]); 139 expect(d).toBeDefined(); 140 const items = Order.fromCBOR(d!).Items; 141 expect(items[0].ListingID).toBe(listingId); 142 expect(items[0].Quantity).toBe(initialQty + qtyIncreasedBy); 143 144 // Commit order and try to update quantity. Tests cancelAndRecreateOrder fn 145 await stateManager.set( 146 ["Orders", orderId, "State"], 147 OrderState.Committed, 148 ); 149 const purchaseQty3 = await screen.findByTestId("purchaseQty"); 150 expect(purchaseQty3).toBeTruthy(); 151 await user.clear(purchaseQty3); 152 153 // Third quantity update 154 await user.type(purchaseQty3, `${qtyIncreasedBy2}`); 155 const addToCart3 = screen.getByTestId("addToCart"); 156 await user.click(addToCart3); 157 // wait for the success toast to appear 158 successToast = await screen.findByTestId("success-toast"); 159 expect(successToast).toBeTruthy(); 160 // finally: its text should begin with `${qtyIncreasedBy2}` 161 successToastText = await screen.findByText( 162 `${qtyIncreasedBy2} items added`, 163 ); 164 expect(successToastText.textContent?.startsWith(`${qtyIncreasedBy2}`)) 165 .toBeTruthy(); 166 167 let updatedOrders; 168 await waitFor(async () => { 169 updatedOrders = await stateManager.get(["Orders"]) as Map< 170 CodecKey, 171 CodecValue 172 >; 173 expect(updatedOrders.size).toBe(2); 174 }); 175 const orderIds = Array.from(updatedOrders!.keys()).filter((id) => 176 id !== orderId 177 ); 178 expect(orderIds.length).toBe(1); 179 const newOrderId = orderIds[0] as number; 180 await waitFor(async () => { 181 const newOrderData = await stateManager.get(["Orders", newOrderId]) as Map< 182 CodecKey, 183 CodecValue 184 >; 185 const newOrder = Order.fromCBOR(newOrderData); 186 // Since quantity was updated 3 times, it should be the addition of the 3 quantities tested. 187 const totalQuantity = initialQty + qtyIncreasedBy + qtyIncreasedBy2; 188 expect(newOrder.Items[0].Quantity).toBe(totalQuantity); 189 }); 190 191 unmount(); 192 193 cleanup(); 194 });