Navigation_test.tsx
1 import "../happyDomSetup.ts"; 2 import { 3 cleanup, 4 render, 5 screen, 6 waitFor, 7 within, 8 } from "@testing-library/react"; 9 import { expect } from "@std/expect"; 10 import { userEvent } from "@testing-library/user-event"; 11 12 import { allListings } from "@massmarket/schema/testFixtures"; 13 import type { CodecValue } from "@massmarket/utils/codec"; 14 import { random256BigInt, randUint64 } from "@massmarket/utils"; 15 import { Order, OrderedItem } from "@massmarket/schema"; 16 17 import Navigation from "./Navigation.tsx"; 18 import { createRouterWrapper, testClient } from "../testutils/mod.tsx"; 19 import { OrderState } from "../types.ts"; 20 Deno.test("Check that we can render the navigation bar", { 21 sanitizeResources: false, 22 sanitizeOps: false, 23 }, async (t) => { 24 const shopId = random256BigInt(); 25 26 const { 27 stateManager: merchantStateManager, 28 relayClient: merchantRelayClient, 29 } = await createRouterWrapper({ 30 shopId, 31 createShop: true, 32 enrollMerchant: true, 33 }); 34 35 merchantStateManager.addConnection(merchantRelayClient); 36 37 // populate state manager with listings 38 for (const [listingID, listing] of allListings.entries()) { 39 await merchantStateManager.set(["Listings", listingID], listing); 40 await merchantStateManager.set(["Inventory", listingID], 100); 41 } 42 43 // remove merchant's keycard to free up for customer 44 localStorage.removeItem(`keycard${shopId}`); 45 46 const { wrapper, stateManager, relayClient, testAccount } = 47 await createRouterWrapper({ 48 shopId, 49 }); 50 await relayClient.enrollKeycard(testClient, testAccount, true); 51 stateManager.addConnection(relayClient); 52 53 await waitFor(async () => { 54 const storedListings = await stateManager.get(["Listings"]) as Map< 55 bigint, 56 unknown 57 >; 58 expect(storedListings.size).toBe(allListings.size); 59 }); 60 61 // Create order and add items to it 62 const orderId = randUint64(); 63 const item1ID = 23; 64 const item2ID = 42; 65 const order = new Order( 66 orderId, 67 [ 68 new OrderedItem(item1ID, 32), 69 new OrderedItem(item2ID, 24), 70 ], 71 OrderState.Open, 72 ); 73 await stateManager.set(["Orders", orderId], order); 74 75 const { unmount } = render(<Navigation />, { wrapper }); 76 await screen.findByTestId("navigation"); 77 78 const user = userEvent.setup(); 79 await waitFor(async () => { 80 const cartToggle = screen.getByTestId("cart-toggle"); 81 expect(cartToggle).toBeDefined(); 82 await user.click(cartToggle); 83 }); 84 85 await t.step("Remove item from cart", async () => { 86 // Check that the cart items are rendered 87 const desktopCart = screen.getByTestId("desktop-cart"); 88 89 await waitFor(() => { 90 expect(desktopCart).toBeDefined(); 91 const cartItems = within(desktopCart).getAllByTestId("cart-item"); 92 expect(cartItems.length).toBe(2); 93 //check that the added quantity is displayed correctly 94 expect(cartItems[0].textContent).toEqual( 95 "test32Qty: 320.00000000000736ETH", 96 ); 97 expect(cartItems[1].textContent).toEqual( 98 "test4224Qty: 240.00000000001008ETH", 99 ); 100 }); 101 102 await waitFor(async () => { 103 const removeButton = within(desktopCart).getByTestId( 104 `remove-item-${item1ID}`, 105 ); 106 expect(removeButton).toBeDefined(); 107 await user.click(removeButton); 108 }); 109 110 await waitFor(() => { 111 const cartItems = within(desktopCart).getAllByTestId("cart-item"); 112 expect(cartItems.length).toBe(1); 113 expect(cartItems[0].textContent).toContain("test4224Qty"); 114 }); 115 }); 116 117 await t.step("Add quantity to item", async () => { 118 const desktopCart = screen.getByTestId("desktop-cart"); 119 120 await waitFor(async () => { 121 const addButton = within(desktopCart).getByTestId( 122 `add-quantity-${item2ID}`, 123 ); 124 expect(addButton).toBeDefined(); 125 await user.click(addButton); 126 }); 127 await waitFor(() => { 128 const quantity = within(desktopCart).getByTestId(`quantity-${item2ID}`); 129 expect(quantity.textContent).toContain("25"); 130 }); 131 // Check statemanager updated correctly. 132 const updatedOrder = await stateManager.get(["Orders", orderId]); 133 expect(updatedOrder).toBeDefined(); 134 const updatedOrderItems = Order.fromCBOR(updatedOrder!).Items; 135 expect(updatedOrderItems[0].ListingID).toBe(item2ID); 136 expect(updatedOrderItems[0].Quantity).toBe(25); 137 }); 138 139 await t.step("Remove quantity from item", async () => { 140 const desktopCart = screen.getByTestId("desktop-cart"); 141 142 await waitFor(async () => { 143 const minusQty = within(desktopCart).getByTestId( 144 `remove-quantity-${item2ID}`, 145 ); 146 expect(minusQty).toBeDefined(); 147 await user.click(minusQty); 148 }); 149 await waitFor(() => { 150 const quantity = within(desktopCart).getByTestId(`quantity-${item2ID}`); 151 expect(quantity.textContent).toContain("24"); 152 }); 153 // Check statemanager updated correctly. 154 const updatedOrder = await stateManager.get(["Orders", orderId]); 155 expect(updatedOrder).toBeDefined(); 156 const updatedOrderItems = Order.fromCBOR(updatedOrder!).Items; 157 expect(updatedOrderItems[0].ListingID).toBe(item2ID); 158 expect(updatedOrderItems[0].Quantity).toBe(24); 159 }); 160 161 await t.step("Clear cart", async () => { 162 const desktopCart = screen.getByTestId("desktop-cart"); 163 164 await waitFor(async () => { 165 const clearCart = within(desktopCart).getByTestId("clear-cart"); 166 await user.click(clearCart); 167 }); 168 await waitFor(() => { 169 const cartItems = within(desktopCart).queryAllByTestId("cart-item"); 170 expect(cartItems.length).toBe(0); 171 }); 172 const updatedOrder = await stateManager.get(["Orders", orderId]); 173 expect(updatedOrder).toBeDefined(); 174 const updatedOrderItems = Order.fromCBOR(updatedOrder!).Items; 175 expect(updatedOrderItems.length).toBe(0); 176 }); 177 178 await t.step("Checkout button", async () => { 179 await stateManager.set(["Orders", orderId, "Items"], [ 180 new OrderedItem(item1ID, 32).asCBORMap(), 181 new OrderedItem(item2ID, 24).asCBORMap(), 182 ]); 183 184 await waitFor(async () => { 185 const cartToggle = screen.getByTestId("cart-toggle"); 186 expect(cartToggle).toBeTruthy(); 187 await user.click(cartToggle); 188 }); 189 const desktopCart = screen.getByTestId("desktop-cart"); 190 191 await waitFor(async () => { 192 const checkoutButton = within(desktopCart).getByTestId( 193 "checkout-button", 194 ); 195 expect(checkoutButton).toBeDefined(); 196 await user.click(checkoutButton); 197 }); 198 //Check that the order was committed after clicking checkout button. 199 const updatedOrder = await stateManager.get(["Orders", orderId]); 200 expect(updatedOrder).toBeDefined(); 201 const state = Order.fromCBOR(updatedOrder!).State; 202 expect(state).toBe(OrderState.Committed); 203 }); 204 205 await t.step("clear cart when order is committed", async () => { 206 await waitFor(async () => { 207 const cartToggle = screen.getByTestId("cart-toggle"); 208 expect(cartToggle).toBeTruthy(); 209 await user.click(cartToggle); 210 }); 211 const desktopCart = screen.getByTestId("desktop-cart"); 212 213 await waitFor(async () => { 214 // Verify the cart header is displayed 215 const cartHeader = within(desktopCart).getByText("Cart"); 216 expect(cartHeader).toBeTruthy(); 217 // Try to clear cart that's already committed 218 const clearCart = within(desktopCart).getByTestId("clear-cart"); 219 expect(clearCart).toBeDefined(); 220 await user.click(clearCart); 221 }); 222 await waitFor(async () => { 223 const cartItems = within(desktopCart).queryAllByTestId("cart-item"); 224 expect(cartItems.length).toBe(0); 225 const orders = await stateManager.get(["Orders"]) as Map< 226 number, 227 unknown 228 >; 229 //Clearing cart of an already committed order should cancel the order and recreate a new order with no items. 230 expect(orders.size).toBe(2); 231 const o = orders.get(orderId) as CodecValue; 232 const order = Order.fromCBOR(o!); 233 expect(order.CanceledAt).toBeDefined(); 234 expect(order.State).toBe(OrderState.Canceled); 235 }); 236 }); 237 238 unmount(); 239 cleanup(); 240 });