diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/components/Header.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/components/Header.jsx index 6f0aa0b..b169902 100755 --- a/2-copy-of-code/lesson-09/ecommerce-project/src/components/Header.jsx +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/components/Header.jsx @@ -13,27 +13,33 @@ export function Header({ cart }) {
- + -
- + Orders - +
{totalQuantity}
Cart
diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/components/Header.test.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/components/Header.test.jsx new file mode 100644 index 0000000..d27f205 --- /dev/null +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/components/Header.test.jsx @@ -0,0 +1,46 @@ +import { it, expect, describe, beforeEach } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { MemoryRouter } from 'react-router'; +import { Header } from './Header'; + +describe('Header component', () => { + let cart; + + beforeEach(() => { + cart = [{ + productId: 'e43638ce-6aa0-4b85-b27f-e1d07eb678c6', + quantity: 2, + deliveryOptionId: '1' + }, { + productId: '15b6fc6f-327a-4ec4-896f-486349e85a3d', + quantity: 3, + deliveryOptionId: '2' + }]; + }); + + it('displays the header correctly', () => { + render( + +
+ + ); + + const logo = screen.getByTestId('header-logo'); + expect(logo).toHaveAttribute('src', 'images/logo-white.png'); + + const mobileLogo = screen.getByTestId('header-mobile-logo'); + expect(mobileLogo).toHaveAttribute('src', 'images/mobile-logo-white.png'); + + expect(screen.getByTestId('header-search-bar')).toBeInTheDocument(); + expect(screen.getByTestId('header-search-button')).toBeInTheDocument(); + + const ordersLink = screen.getByTestId('header-orders-link'); + expect(ordersLink).toHaveTextContent('Orders'); + expect(ordersLink).toHaveAttribute('href', '/orders'); + + const cartLink = screen.getByTestId('header-cart-link'); + expect(cartLink).toHaveTextContent('Cart'); + expect(cartLink).toHaveTextContent('5'); + expect(cartLink).toHaveAttribute('href', '/checkout'); + }); +}); \ No newline at end of file diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/CheckoutPage.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/CheckoutPage.jsx index 1abbdda..4cb64fd 100755 --- a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/CheckoutPage.jsx +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/CheckoutPage.jsx @@ -27,7 +27,8 @@ export function CheckoutPage({ cart, loadCart }) { <> Checkout -
+
diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/CheckoutPage.test.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/CheckoutPage.test.jsx new file mode 100644 index 0000000..bd937d1 --- /dev/null +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/CheckoutPage.test.jsx @@ -0,0 +1,124 @@ +import { it, expect, describe, vi, beforeEach } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { MemoryRouter } from 'react-router'; +import axios from 'axios'; +import { CheckoutPage } from './CheckoutPage'; + +vi.mock('axios'); + +describe('CheckoutPage component', () => { + let loadCart; + let cart; + let deliveryOptions; + let paymentSummary; + + beforeEach(() => { + loadCart = vi.fn(); + + cart = [{ + productId: 'e43638ce-6aa0-4b85-b27f-e1d07eb678c6', + quantity: 2, + deliveryOptionId: '1', + product: { + id: "e43638ce-6aa0-4b85-b27f-e1d07eb678c6", + image: "images/products/athletic-cotton-socks-6-pairs.jpg", + name: "Black and Gray Athletic Cotton Socks - 6 Pairs", + rating: { + stars: 4.5, + count: 87 + }, + priceCents: 1090, + keywords: ["socks", "sports", "apparel"] + } + }, { + productId: '15b6fc6f-327a-4ec4-896f-486349e85a3d', + quantity: 1, + deliveryOptionId: '2', + product: { + id: "15b6fc6f-327a-4ec4-896f-486349e85a3d", + image: "images/products/intermediate-composite-basketball.jpg", + name: "Intermediate Size Basketball", + rating: { + stars: 4, + count: 127 + }, + priceCents: 2095, + keywords: ["sports", "basketballs"] + } + }]; + + deliveryOptions = [{ + id: '1', + deliveryDays: 7, + priceCents: 0, + estimatedDeliveryTimeMs: 1747597994451, + }, { + id: '2', + deliveryDays: 3, + priceCents: 499, + estimatedDeliveryTimeMs: 1747252394451, + }, { + id: '3', + deliveryDays: 1, + priceCents: 999, + estimatedDeliveryTimeMs: 1747079594451, + }]; + + paymentSummary = { + totalItems: 3, + productCostCents: 4275, + shippingCostCents: 499, + totalCostBeforeTaxCents: 4774, + taxCents: 477, + totalCostCents: 5251 + }; + + axios.get.mockImplementation(async (url) => { + if (url === '/api/delivery-options?expand=estimatedDeliveryTime') { + return { data: deliveryOptions }; + } + if (url === '/api/payment-summary') { + return { data: paymentSummary }; + } + }); + }); + + it('displays the page correctly', async () => { + render( + + + + ); + + // findByTestId() = waits until it finds a single element. + const paymentSummary = await screen.findByTestId('payment-summary-product-cost'); + + expect(axios.get).toHaveBeenNthCalledWith( + 1, + '/api/delivery-options?expand=estimatedDeliveryTime' + ); + expect(axios.get).toHaveBeenNthCalledWith( + 2, + '/api/payment-summary' + ); + + // Check the order summary is overall correct (since OrderSummary + // is tested in more detail in OrderSummary.test.jsx) + expect(screen.getByText('Review your order')).toBeInTheDocument(); + expect( + screen.getByText('Black and Gray Athletic Cotton Socks - 6 Pairs') + ).toBeInTheDocument(); + expect( + screen.getByText('Intermediate Size Basketball') + ).toBeInTheDocument(); + + // Check the payment summary is overall correct (since PaymentSummary + // is tested in more detail in PaymentSummary.test.jsx) + expect(paymentSummary).toBeInTheDocument(); + expect(screen.getByText('Payment Summary')).toBeInTheDocument(); + expect(screen.getByTestId('payment-summary-product-cost')) + .toHaveTextContent('Items (3):'); + expect(screen.getByTestId('payment-summary-shipping-cost')) + .toHaveTextContent('$4.99'); + }); +}); \ No newline at end of file diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/DeliveryOptions.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/DeliveryOptions.jsx index 0cea3d0..341355e 100755 --- a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/DeliveryOptions.jsx +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/DeliveryOptions.jsx @@ -24,12 +24,15 @@ export function DeliveryOptions({ cartItem, deliveryOptions, loadCart }) { return (
+ onClick={updateDeliveryOption} + data-testid="delivery-option"> {}} className="delivery-option-input" - name={`delivery-option-${cartItem.productId}`} /> + name={`delivery-option-${cartItem.productId}`} + data-testid="delivery-option-input" + />
{dayjs(deliveryOption.estimatedDeliveryTimeMs).format('dddd, MMMM D')} diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/DeliveryOptions.test.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/DeliveryOptions.test.jsx new file mode 100644 index 0000000..9421f5e --- /dev/null +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/DeliveryOptions.test.jsx @@ -0,0 +1,101 @@ +import { it, expect, describe, vi, beforeEach } from 'vitest'; +import { render, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import axios from 'axios'; +import { DeliveryOptions } from './DeliveryOptions'; + +vi.mock('axios'); + +describe('DeliveryOptions component', () => { + let cartItem; + let deliveryOptions; + let loadCart; + let user; + + beforeEach(() => { + cartItem = { + productId: 'e43638ce-6aa0-4b85-b27f-e1d07eb678c6', + quantity: 2, + deliveryOptionId: '2', + }; + + deliveryOptions = [{ + id: '1', + deliveryDays: 7, + priceCents: 0, + estimatedDeliveryTimeMs: 1747597994451, + }, { + id: '2', + deliveryDays: 3, + priceCents: 499, + estimatedDeliveryTimeMs: 1747252394451, + }, { + id: '3', + deliveryDays: 1, + priceCents: 999, + estimatedDeliveryTimeMs: 1747079594451, + }]; + + loadCart = vi.fn(); + user = userEvent.setup(); + }); + + it('renders delivery options correctly', () => { + render( + + ); + + expect(screen.getByText('Choose a delivery option:')).toBeInTheDocument(); + + const deliveryOptionElems = screen.getAllByTestId('delivery-option'); + expect(deliveryOptionElems.length).toBe(3); + + expect(deliveryOptionElems[0]).toHaveTextContent('Sunday, May 18'); + expect(deliveryOptionElems[0]).toHaveTextContent('FREE Shipping'); + expect( + within(deliveryOptionElems[0]).getByTestId('delivery-option-input').checked + ).toBe(false); + + expect(deliveryOptionElems[1]).toHaveTextContent('Wednesday, May 14'); + expect(deliveryOptionElems[1]).toHaveTextContent('$4.99 - Shipping'); + expect( + within(deliveryOptionElems[1]).getByTestId('delivery-option-input').checked + ).toBe(true); + + expect(deliveryOptionElems[2]).toHaveTextContent('Monday, May 12'); + expect(deliveryOptionElems[2]).toHaveTextContent('$9.99 - Shipping'); + expect( + within(deliveryOptionElems[2]).getByTestId('delivery-option-input').checked + ).toBe(false); + }); + + it('updates the delivery option', async () => { + render( + + ); + + const deliveryOptionElems = screen.getAllByTestId('delivery-option'); + + await user.click(deliveryOptionElems[2]); + expect(axios.put).toHaveBeenCalledWith( + '/api/cart-items/e43638ce-6aa0-4b85-b27f-e1d07eb678c6', + { deliveryOptionId: '3' } + ); + expect(loadCart).toHaveBeenCalledTimes(1); + + await user.click(deliveryOptionElems[0]); + expect(axios.put).toHaveBeenCalledWith( + '/api/cart-items/e43638ce-6aa0-4b85-b27f-e1d07eb678c6', + { deliveryOptionId: '1' } + ); + expect(loadCart).toHaveBeenCalledTimes(2); + }); +}); \ No newline at end of file diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/OrderSummary.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/OrderSummary.jsx index 1d4bef4..dada123 100755 --- a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/OrderSummary.jsx +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/OrderSummary.jsx @@ -18,30 +18,35 @@ export function OrderSummary({ cart, deliveryOptions, loadCart }) { }; return ( -
+
Delivery date: {dayjs(selectedDeliveryOption.estimatedDeliveryTimeMs).format('dddd, MMMM D')}
+ src={cartItem.product.image} + data-testid="cart-item-image" />
-
+
{cartItem.product.name}
-
+
{formatMoney(cartItem.product.priceCents)}
- + Quantity: {cartItem.quantity} Update Delete diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/OrderSummary.test.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/OrderSummary.test.jsx new file mode 100644 index 0000000..dcb9f89 --- /dev/null +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/checkout/OrderSummary.test.jsx @@ -0,0 +1,165 @@ +import { it, expect, describe, vi, beforeEach } from 'vitest'; +import { render, screen, within } from '@testing-library/react'; +import { MemoryRouter } from 'react-router'; +import userEvent from '@testing-library/user-event'; +import axios from 'axios'; +import { OrderSummary } from './OrderSummary'; + +vi.mock('axios'); + +describe('OrderSummary component', () => { + let cart; + let deliveryOptions; + let loadCart; + let user; + + beforeEach(() => { + cart = [{ + productId: 'e43638ce-6aa0-4b85-b27f-e1d07eb678c6', + quantity: 2, + deliveryOptionId: '1', + product: { + id: "e43638ce-6aa0-4b85-b27f-e1d07eb678c6", + image: "images/products/athletic-cotton-socks-6-pairs.jpg", + name: "Black and Gray Athletic Cotton Socks - 6 Pairs", + rating: { + stars: 4.5, + count: 87 + }, + priceCents: 1090, + keywords: ["socks", "sports", "apparel"] + } + }, { + productId: '15b6fc6f-327a-4ec4-896f-486349e85a3d', + quantity: 1, + deliveryOptionId: '2', + product: { + id: "15b6fc6f-327a-4ec4-896f-486349e85a3d", + image: "images/products/intermediate-composite-basketball.jpg", + name: "Intermediate Size Basketball", + rating: { + stars: 4, + count: 127 + }, + priceCents: 2095, + keywords: ["sports", "basketballs"] + } + }]; + + deliveryOptions = [{ + id: '1', + deliveryDays: 7, + priceCents: 0, + estimatedDeliveryTimeMs: 1747597994451, + }, { + id: '2', + deliveryDays: 3, + priceCents: 499, + estimatedDeliveryTimeMs: 1747252394451, + }, { + id: '3', + deliveryDays: 1, + priceCents: 999, + estimatedDeliveryTimeMs: 1747079594451, + }]; + + loadCart = vi.fn(); + user = userEvent.setup(); + }); + + it('renders cart items correctly', () => { + render( + + + + ); + + const cartItemContainers = screen.getAllByTestId('cart-item-container'); + expect(cartItemContainers.length).toBe(2); + + expect( + within(cartItemContainers[0]).getByTestId('cart-item-image') + ).toHaveAttribute('src', 'images/products/athletic-cotton-socks-6-pairs.jpg'); + expect( + within(cartItemContainers[0]).getByTestId('cart-item-name') + ).toHaveTextContent('Black and Gray Athletic Cotton Socks - 6 Pairs'); + expect( + within(cartItemContainers[0]).getByTestId('cart-item-price') + ).toHaveTextContent('$10.90'); + expect( + within(cartItemContainers[0]).getByTestId('cart-item-quantity') + ).toHaveTextContent('Quantity: 2'); + + let deliveryOptionInputs = within(cartItemContainers[0]) + .getAllByTestId('delivery-option-input'); + expect(deliveryOptionInputs.length).toBe(3); + expect(deliveryOptionInputs[0].checked).toBe(true); + expect(deliveryOptionInputs[1].checked).toBe(false); + expect(deliveryOptionInputs[2].checked).toBe(false); + + expect( + within(cartItemContainers[1]).getByTestId('cart-item-image') + ).toHaveAttribute('src', 'images/products/intermediate-composite-basketball.jpg'); + expect( + within(cartItemContainers[1]).getByTestId('cart-item-name') + ).toHaveTextContent('Intermediate Size Basketball'); + expect( + within(cartItemContainers[1]).getByTestId('cart-item-price') + ).toHaveTextContent('$20.95'); + expect( + within(cartItemContainers[1]).getByTestId('cart-item-quantity') + ).toHaveTextContent('Quantity: 1'); + + deliveryOptionInputs = within(cartItemContainers[1]) + .getAllByTestId('delivery-option-input'); + expect(deliveryOptionInputs.length).toBe(3); + expect(deliveryOptionInputs[0].checked).toBe(false); + expect(deliveryOptionInputs[1].checked).toBe(true); + expect(deliveryOptionInputs[2].checked).toBe(false); + }); + + it('deletes a cart item', async () => { + render( + + + + ); + + const cartItemContainers = screen.getAllByTestId('cart-item-container'); + expect(cartItemContainers.length).toBe(2); + + await user.click( + within(cartItemContainers[0]).getByTestId('cart-item-delete-quantity-link') + ); + expect(axios.delete).toHaveBeenCalledWith( + '/api/cart-items/e43638ce-6aa0-4b85-b27f-e1d07eb678c6' + ); + expect(loadCart).toHaveBeenCalledTimes(1); + + await user.click( + within(cartItemContainers[1]).getByTestId('cart-item-delete-quantity-link') + ); + expect(axios.delete).toHaveBeenCalledWith( + '/api/cart-items/15b6fc6f-327a-4ec4-896f-486349e85a3d' + ); + expect(loadCart).toHaveBeenCalledTimes(2); + }); + + it('does not render anything if cart is empty', () => { + render( + + + + ); + + // We can't use getAllByTestId because if it doesn't find anything, + // it will cause an error. Instead we use queryAllByTestId. This + // does the same thing as getAllByTestId it doesn't cause an error + // if it doesn't find anything, it just returns an empty array. + expect(screen.queryAllByTestId('cart-item-container').length).toBe(0); + }); +}); \ No newline at end of file diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/home/ProductsGrid.test.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/home/ProductsGrid.test.jsx new file mode 100644 index 0000000..98211cb --- /dev/null +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/home/ProductsGrid.test.jsx @@ -0,0 +1,52 @@ +import { it, expect, describe, vi, beforeEach } from 'vitest'; +import { render, screen, within } from '@testing-library/react'; +import { ProductsGrid } from './ProductsGrid'; + +describe('ProductsGrid component', () => { + let products; + let loadCart; + + beforeEach(() => { + products = [{ + id: "e43638ce-6aa0-4b85-b27f-e1d07eb678c6", + image: "images/products/athletic-cotton-socks-6-pairs.jpg", + name: "Black and Gray Athletic Cotton Socks - 6 Pairs", + rating: { + stars: 4.5, + count: 87 + }, + priceCents: 1090, + keywords: ["socks", "sports", "apparel"] + }, + { + id: "15b6fc6f-327a-4ec4-896f-486349e85a3d", + image: "images/products/intermediate-composite-basketball.jpg", + name: "Intermediate Size Basketball", + rating: { + stars: 4, + count: 127 + }, + priceCents: 2095, + keywords: ["sports", "basketballs"] + }]; + + loadCart = vi.fn(); + }); + + it('renders the products', async () => { + render(); + + const productContainers = await screen.findAllByTestId('product-container'); + expect(productContainers).toHaveLength(2); + + expect( + within(productContainers[0]) + .getByText('Black and Gray Athletic Cotton Socks - 6 Pairs') + ).toBeInTheDocument(); + + expect( + within(productContainers[1]) + .getByText('Intermediate Size Basketball') + ).toBeInTheDocument(); + }); +}); \ No newline at end of file diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/orders/OrdersPage.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/orders/OrdersPage.jsx index a38ceb6..1fe893d 100755 --- a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/orders/OrdersPage.jsx +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/orders/OrdersPage.jsx @@ -27,23 +27,28 @@ export function OrdersPage({ cart }) {
{orders.map((order) => { return ( -
+
Order Placed:
-
{dayjs(order.orderTimeMs).format('MMMM D')}
+
+ {dayjs(order.orderTimeMs).format('MMMM D')} +
Total:
-
{formatMoney(order.totalCostCents)}
+
+ {formatMoney(order.totalCostCents)} +
Order ID:
-
{order.id}
+
{order.id}
@@ -55,7 +60,8 @@ export function OrdersPage({ cart }) {
-
+
{orderProduct.product.name}
diff --git a/2-copy-of-code/lesson-09/ecommerce-project/src/pages/orders/OrdersPage.test.jsx b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/orders/OrdersPage.test.jsx new file mode 100644 index 0000000..37ded28 --- /dev/null +++ b/2-copy-of-code/lesson-09/ecommerce-project/src/pages/orders/OrdersPage.test.jsx @@ -0,0 +1,139 @@ +import { it, expect, describe, vi, beforeEach } from 'vitest'; +import { render, screen, within } from '@testing-library/react'; +import { MemoryRouter } from 'react-router'; +import axios from 'axios'; +import { OrdersPage } from './OrdersPage'; + +vi.mock('axios'); + +describe('OrdersPage component', () => { + let cart; + let orders; + + beforeEach(() => { + cart = [{ + productId: 'e43638ce-6aa0-4b85-b27f-e1d07eb678c6', + quantity: 2, + deliveryOptionId: '1' + }, { + productId: '15b6fc6f-327a-4ec4-896f-486349e85a3d', + quantity: 1, + deliveryOptionId: '2' + }]; + + orders = [{ + id: "27cba69d-4c3d-4098-b42d-ac7fa62b7664", + orderTimeMs: 1723456800000, + totalCostCents: 3506, + products: [{ + productId: "e43638ce-6aa0-4b85-b27f-e1d07eb678c6", + quantity: 1, + estimatedDeliveryTimeMs: 1723716000000, + product: { + id: "e43638ce-6aa0-4b85-b27f-e1d07eb678c6", + image: "images/products/athletic-cotton-socks-6-pairs.jpg", + name: "Black and Gray Athletic Cotton Socks - 6 Pairs", + rating: { + stars: 4.5, + count: 87 + }, + priceCents: 1090 + } + }, { + productId: "83d4ca15-0f35-48f5-b7a3-1ea210004f2e", + quantity: 2, + estimatedDeliveryTimeMs: 1723456800000, + product: { + id: "83d4ca15-0f35-48f5-b7a3-1ea210004f2e", + image: "images/products/adults-plain-cotton-tshirt-2-pack-teal.jpg", + name: "Adults Plain Cotton T-Shirt - 2 Pack", + rating: { + stars: 4.5, + count: 56 + }, + priceCents: 799 + } + }] + }, { + id: "b6b6c212-d30e-4d4a-805d-90b52ce6b37d", + orderTimeMs: 1718013600000, + totalCostCents: 4190, + products: [{ + productId: "15b6fc6f-327a-4ec4-896f-486349e85a3d", + quantity: 2, + estimatedDeliveryTimeMs: 1718618400000, + product: { + id: "15b6fc6f-327a-4ec4-896f-486349e85a3d", + image: "images/products/intermediate-composite-basketball.jpg", + name: "Intermediate Size Basketball", + rating: { + stars: 4, + count: 127 + }, + priceCents: 2095 + } + }] + }]; + + axios.get.mockImplementation(async (urlPath) => { + if (urlPath === '/api/orders?expand=products') { + return { data: orders }; + } + }); + }); + + it('renders order details correctly', async () => { + render( + + + + ); + + expect(screen.getByText('Your Orders')).toBeInTheDocument(); + + const orderContainers = await screen.findAllByTestId('order-container'); + expect(orderContainers.length).toBe(2); + + // Check the details of the first order. + expect( + within(orderContainers[0]).getByTestId('order-date') + ).toHaveTextContent('August 12'); + expect( + within(orderContainers[0]).getByTestId('order-total') + ).toHaveTextContent('$35.06'); + expect( + within(orderContainers[0]).getByTestId('order-id') + ).toHaveTextContent('27cba69d-4c3d-4098-b42d-ac7fa62b7664'); + + let orderProducts = within(orderContainers[0]) + .getAllByTestId('order-product-details'); + expect(orderProducts.length).toBe(2); + expect( + within(orderProducts[0]) + .getByText('Black and Gray Athletic Cotton Socks - 6 Pairs') + ).toBeInTheDocument(); + expect( + within(orderProducts[1]) + .getByText('Adults Plain Cotton T-Shirt - 2 Pack') + ).toBeInTheDocument(); + + // Check the details of the second order. + expect( + within(orderContainers[1]).getByTestId('order-date') + ).toHaveTextContent('June 10'); + expect( + within(orderContainers[1]).getByTestId('order-total') + ).toHaveTextContent('$41.90'); + expect( + within(orderContainers[1]).getByTestId('order-id') + ).toHaveTextContent('b6b6c212-d30e-4d4a-805d-90b52ce6b37d'); + + orderProducts = within(orderContainers[1]) + .getAllByTestId('order-product-details'); + expect(orderProducts.length).toBe(1); + expect( + within(orderProducts[0]) + .getByText('Intermediate Size Basketball') + ).toBeInTheDocument(); + }); +}); \ No newline at end of file