From fe8a8611fad9b913409ae03b7616f2eab4a2312d Mon Sep 17 00:00:00 2001 From: Zohaib Ijaz Date: Sun, 14 Jan 2024 07:43:01 +0500 Subject: [PATCH] Added unit tests for new components Fixed broken tests --- setupTest.ts | 18 +- src/app/__snapshots__/layout.test.tsx.snap | 166 ++- src/app/__snapshots__/page.test.tsx.snap | 1232 +++++++++++++---- src/app/layout.test.tsx | 4 + src/app/layout.tsx | 6 +- src/app/page.test.tsx | 142 +- src/components/Button/index.tsx | 2 +- src/components/Cart/Cart.test.tsx | 11 +- .../Cart/__snapshots__/Cart.test.tsx.snap | 200 +++ src/components/Cart/index.tsx | 18 +- src/components/CartItem/CartItem.test.tsx | 68 + .../__snapshots__/CartItem.test.tsx.snap | 126 ++ src/components/CartItem/index.tsx | 2 +- src/components/ColorFilter/index.tsx | 4 +- src/components/CountDot/index.tsx | 8 +- src/components/Icons/index.tsx | 30 + .../__snapshots__/ProductItem.test.tsx.snap | 175 ++- src/components/Products/Products.test.tsx | 125 +- .../__snapshots__/Products.test.tsx.snap | 421 +++--- .../ThemeSwitch/ThemeSwitch.test.tsx | 19 + src/components/ThemeSwitch/index.tsx | 32 +- src/store/ThemeProvider.test.tsx | 13 + .../__snapshots__/ThemeProvider.test.tsx.snap | 10 + src/store/index.tsx | 1 + 24 files changed, 2015 insertions(+), 818 deletions(-) create mode 100644 src/components/Cart/__snapshots__/Cart.test.tsx.snap create mode 100644 src/components/CartItem/CartItem.test.tsx create mode 100644 src/components/CartItem/__snapshots__/CartItem.test.tsx.snap create mode 100644 src/components/ThemeSwitch/ThemeSwitch.test.tsx create mode 100644 src/store/ThemeProvider.test.tsx create mode 100644 src/store/__snapshots__/ThemeProvider.test.tsx.snap diff --git a/setupTest.ts b/setupTest.ts index a05bcb7..a23b2d3 100644 --- a/setupTest.ts +++ b/setupTest.ts @@ -1,4 +1,18 @@ -import { expect } from 'vitest'; +import { expect, vi } from 'vitest'; import * as matchers from '@testing-library/jest-dom/matchers'; -expect.extend(matchers); \ No newline at end of file +expect.extend(matchers); + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}); diff --git a/src/app/__snapshots__/layout.test.tsx.snap b/src/app/__snapshots__/layout.test.tsx.snap index 249355b..d0ada7e 100644 --- a/src/app/__snapshots__/layout.test.tsx.snap +++ b/src/app/__snapshots__/layout.test.tsx.snap @@ -6,65 +6,129 @@ exports[`Layout > Layout should render 1`] = ` lang="en" > -
- -
-
-

- Test Message -

-
+ +
+ +
+
+
+ + +
+

+ Test Message +

+
+ diff --git a/src/app/__snapshots__/page.test.tsx.snap b/src/app/__snapshots__/page.test.tsx.snap index e2c9274..46fe13c 100644 --- a/src/app/__snapshots__/page.test.tsx.snap +++ b/src/app/__snapshots__/page.test.tsx.snap @@ -2,14 +2,126 @@ exports[`Page > HomePage should show all data 1`] = `
+
+
+ + +

+ E-Store +

+
+
+ +
+ +
+
+
+
+

Products

@@ -29,13 +141,13 @@ exports[`Page > HomePage should show all data 1`] = ` role="log" />
Select Color @@ -93,62 +205,56 @@ exports[`Page > HomePage should show all data 1`] = `
- Product Image -
-
+ Product Image +
+

Black Sheet Strappy Textured Glitter Bodycon Dress

-
-
-

- Color: -

@@ -158,17 +264,8 @@ exports[`Page > HomePage should show all data 1`] = ` Black
-
-
-

- Price: -

£ HomePage should show all data 1`] = `

+
0
-
-
-
- Product Image -
-
+ Product Image +
+

Stone Ribbed Strappy Cut Out Detail Bodycon Dress

-
-
-

- Color: -

@@ -298,17 +387,8 @@ exports[`Page > HomePage should show all data 1`] = ` Stone
-
-
-

- Price: -

£ HomePage should show all data 1`] = `

+
0
-
-
-
- Product Image -
-
+ Product Image +
+

Black Frill Tie Shoulder Bodycon Dress

-
-
-

- Color: -

@@ -438,17 +510,8 @@ exports[`Page > HomePage should show all data 1`] = ` Black
-
-
-

- Price: -

£ HomePage should show all data 1`] = `

+
0
-
-
-
- Product Image -
-
+ Product Image +
+

Red Pin Stripe Belt T Shirt Dress

-
-
-

- Color: -

@@ -578,17 +633,8 @@ exports[`Page > HomePage should show all data 1`] = ` Red
-
-
-

- Price: -

£ HomePage should show all data 1`] = `

+
0
-
-
+
+
+`; + +exports[`Page > HomePage should show all data 2`] = ` +
+
+
+ -

+ + + + + + + + + + + +

- Cart Total: -

-

+ +

+ +
+ +
+
+
+
+

+
+
+

+ Products +

+
+ + +
+
+
+ Select Color +
+
+ +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+ Product Image +
+
+

+ Black Sheet Strappy Textured Glitter Bodycon Dress +

+
+
+
+ + Black + +
+

+ £ + + 10.00 + +

+
+ +
+
+ + + 0 + + +
+
+
+
+
+
+
+ Product Image +
+
+

+ Stone Ribbed Strappy Cut Out Detail Bodycon Dress +

+
+
+
+ + Stone + +
+

+ £ + + 4.00 + +

+
+ +
+
+ + + 0 + + +
+
+
+
+
+
+
+ Product Image +
+
+

+ Black Frill Tie Shoulder Bodycon Dress +

+
+
+
+ + Black + +
+

+ £ + + 7.99 + +

+
+ +
+
+ + + 0 + + +
+
+
+
+
+
+
+ Product Image +
+
+

+ Red Pin Stripe Belt T Shirt Dress +

+
+
+
+ + Red + +
+

+ £ + + 17.00 + +

+
+ +
+
+ + + 0 + + +
+
+
+
+
diff --git a/src/app/layout.test.tsx b/src/app/layout.test.tsx index fb87461..7d19b70 100644 --- a/src/app/layout.test.tsx +++ b/src/app/layout.test.tsx @@ -3,6 +3,10 @@ import { expect, describe, test, vi, beforeEach } from 'vitest'; import { Product } from '@/components/ProductItem'; import Layout from './layout'; +vi.mock('@/store/ThemeProvider', () => ({ + Provider: vi.fn(({ children }: { children: React.ReactNode }) => children), +})); + describe('Layout', () => { beforeEach(() => { vi.mock('next/font/google', () => ({ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 4c49f1b..4c61a5e 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,12 +1,12 @@ import type { Metadata } from 'next'; -import { Urbanist } from 'next/font/google'; +import { Roboto } from 'next/font/google'; import Header from '@/components/Header'; import { CartProvider } from '@/store'; -import { Provider as ThemeProvider } from '@/store/ThemeProvider'; +import { Provider as ThemeProvider } from '@/store'; import './globals.css'; -const font = Urbanist({ +const font = Roboto({ weight: ['400', '500'], subsets: ['latin'], }); diff --git a/src/app/page.test.tsx b/src/app/page.test.tsx index 0a3baa4..4933788 100644 --- a/src/app/page.test.tsx +++ b/src/app/page.test.tsx @@ -1,12 +1,14 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, fireEvent } from '@testing-library/react'; import { expect, describe, test, vi, beforeEach, afterEach } from 'vitest'; import { Product } from '@/components/ProductItem'; +import { CartProvider, ProductsProvider } from '@/store'; +import Header from '@/components/Header'; import Page from './page'; const fetch = vi.fn(); const actualFetch = global.fetch; -describe('Page', () => { +describe.only('Page', () => { beforeEach(() => { global.fetch = fetch; }); @@ -16,9 +18,116 @@ describe('Page', () => { test('HomePage should show all data', async () => { fetch.mockResolvedValue(createFetchResponse(products)); const Result = await Page(); - const { container } = render(Result); + const { container } = render(Result, { + wrapper: ({ children }) => ( + + +
+ {children} + + + ), + }); // save snapshot expect(container).toMatchSnapshot(); + + expect(screen.getByText('Products')).toBeDefined; + // expect(screen.getByText('Cart Total:')).toBeDefined; + expect(screen.getByTestId('products-list').childNodes.length).toEqual( + products.length + ); + + /* + PLT-1: Viewing product listings + Given I am on the home page + Then I am shown a list of product items (image, name, price, qty in bag) + */ + expect(screen.getByTestId('products-list').childNodes.length).toEqual( + products.length + ); + products.forEach(matchProduct({ container })); + /* + PLT-2: Filter by colour + Given I am viewing all the product listings + When I choose to filter to show only black items + Then I am only shown listings for black items + */ + // Select Black color + const input = container.querySelector('.rs__input')!; + fireEvent.click(input); + fireEvent.change(input, { target: { value: 'Black' } }); + fireEvent.keyDown(input, { key: 'Enter', code: 'Enter', charCode: 13 }); + expect(screen.getByTestId('products-list').childNodes.length).toEqual( + products.filter((item) => item.colour === 'Black').length + ); + // Clear filter + fireEvent.mouseDown(container.querySelector('.rs__clear-indicator')!); + expect(screen.getByTestId('products-list').childNodes.length).toEqual( + products.length + ); + /* + PLT-3: Add to cart + Given I am viewing the products listings + When I press + + Then my basket qty for this item is incremented + And my total is updated to reflect the new items in my basket + */ + + // Add one item to cart + const product = products[0]; + const addBtn = screen.getByTestId(`product-${product.id}-add`); + + fireEvent.click(addBtn); + fireEvent.click(addBtn); + expect( + screen.getByTestId(`product-${product.id}-count`).textContent + ).toEqual('2'); + fireEvent.click(screen.getByTestId('cart-button')); + expect(screen.getByTestId('cart-total').textContent).toEqual( + (2 * product.price).toFixed(2) + ); + fireEvent.click(screen.getByTestId('cart-button')); + /* + PLT-3: Reduce quantity + Given I am viewing the products listings + When I press - + Then my basket qty for this item is decremented + And my total is updated to reflect the new items in my basket + */ + const removeBtn = screen.getByTestId(`product-${product.id}-remove`); + fireEvent.click(removeBtn); + expect( + screen.getByTestId(`product-${product.id}-count`).textContent + ).toEqual('1'); + fireEvent.click(screen.getByTestId('cart-button')); + expect(screen.getByTestId('cart-total').textContent).toEqual( + (1 * product.price).toFixed(2) + ); + fireEvent.click(screen.getByTestId('cart-button')); + /* + PLT-4: Remove from basket + Given I am viewing the products listings + When I press remove + Then all items of this type are removed from my basket + And my total is updated to reflect the new items in my basket + */ + const clearBtn = screen.getByTestId(`product-${product.id}-clear`); + fireEvent.click(clearBtn); + expect( + screen.getByTestId(`product-${product.id}-count`).textContent + ).toEqual('0'); + fireEvent.click(screen.getByTestId('cart-button')); + expect(screen.getByTestId('cart-total').textContent).toEqual( + (0).toFixed(2) + ); + fireEvent.click(screen.getByTestId('cart-button')); + expect( + screen + .getByTestId(`product-${product.id}-remove`) + .hasAttribute('disabled') + ).toBeTruthy(); + // Create snapshot + expect(container).toMatchSnapshot(); }); test('HomePage should show error message if api fails', async () => { fetch.mockRejectedValue(new Error('Something went wrong.')); @@ -29,6 +138,33 @@ describe('Page', () => { expect(container).toMatchSnapshot(); }); }); + +const matchProduct = + ({ container }: { container: HTMLElement }) => + (product: Product) => { + expect(screen.getByText(product.name)).toBeDefined; + // Verify product price + expect( + screen.getByTestId(`product-${product.id}-price`).textContent + ).toEqual(product.price.toFixed(2)); + // verify image src and alt text + const image = screen.getByTestId(`product-${product.id}-img`); + expect(decodeURIComponent(image.getAttribute('src') as string)).contain( + product.img + ); + expect(image.getAttribute('alt')).toEqual('Product Image'); + // Verify product colour + expect( + container.querySelector( + `[data-testid="product-${product.id}-color"] .color-value` + )!.textContent + ).toEqual(product.colour); + // Verify product count + expect( + screen.getByTestId(`product-${product.id}-count`).textContent + ).toEqual('0'); + }; + function createFetchResponse(data: Product[]) { return { json: () => new Promise((resolve) => resolve(data)) }; } diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index b2d7c7a..2f33bcf 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -15,7 +15,7 @@ export default function Button({ return ( + + 10 + +
+
+
+
+
+
+ Product Image +
+

+ Product 1 +

+
+
+
+ + Black + +
+

+ £ + + 10.00 + +

+
+ +
+
+ + + 10 + + +
+
+
+
+
+
+

+ Cart Total: +

+

+ £ + + 100.00 + +

+
+
+
+
+
+
+`; diff --git a/src/components/Cart/index.tsx b/src/components/Cart/index.tsx index ceb882b..d8867e9 100644 --- a/src/components/Cart/index.tsx +++ b/src/components/Cart/index.tsx @@ -20,17 +20,17 @@ export default function CartPopover() { {({ open }) => ( <> - - + + {itemsCount > 0 && ( - + )} { + const useCartSpy = vi.spyOn(store, 'useCart'); + const mockCart = { + total: 100, + cart: [cartItem], + addItem: vi.fn(), + removeItem: vi.fn(), + clearItem: vi.fn(), + }; + useCartSpy.mockReturnValue(mockCart); + test('CartItem should show all data for given product', () => { + const { container } = render(); + // Verify product name + expect(screen.getByText(product.name)).toBeDefined; + // Verify product price + expect( + screen.getByTestId(`product-${product.id}-price`).textContent + ).toEqual(product.price.toFixed(2)); + // verify image src and alt text + const image = screen.getByTestId(`product-${product.id}-img`); + expect(decodeURIComponent(image.getAttribute('src') as string)).contain( + product.img + ); + expect(image.getAttribute('alt')).toEqual('Product Image'); + // Verify product colour + expect(container.querySelector('.color-value')!.textContent).toEqual( + product.colour + ); + // Verify product count + expect( + screen.getByTestId(`product-${product.id}-count`).textContent + ).toEqual(cartItem.count.toString()); + // Verify actions/buttons + const addButton = screen.getByLabelText('Add One Item'); + expect(addButton).toBeDefined; + fireEvent.click(addButton); + expect(mockCart.addItem.mock.calls[0][0]).toEqual(product); + const removeButton = screen.getByLabelText('Remove One Item'); + expect(removeButton).toBeDefined; + fireEvent.click(removeButton); + expect(mockCart.removeItem.mock.calls[0][0]).toEqual(product); + const clearButton = screen.getByTestId(`product-${product.id}-clear`); + expect(clearButton).toBeDefined; + fireEvent.click(clearButton); + expect(mockCart.clearItem.mock.calls[0][0]).toEqual(product); + + // Create snapshot + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/components/CartItem/__snapshots__/CartItem.test.tsx.snap b/src/components/CartItem/__snapshots__/CartItem.test.tsx.snap new file mode 100644 index 0000000..3eea778 --- /dev/null +++ b/src/components/CartItem/__snapshots__/CartItem.test.tsx.snap @@ -0,0 +1,126 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`CartItem > CartItem should show all data for given product 1`] = ` +
+
+
+ Product Image +
+

+ Product 1 +

+
+
+
+ + Black + +
+

+ £ + + 10.00 + +

+
+ +
+
+ + + 10 + + +
+
+
+
+
+`; diff --git a/src/components/CartItem/index.tsx b/src/components/CartItem/index.tsx index c30cda0..4bb7d17 100644 --- a/src/components/CartItem/index.tsx +++ b/src/components/CartItem/index.tsx @@ -16,7 +16,7 @@ type Props = { export default function CartItem({ product, className }: Props) { const { addItem, removeItem, clearItem, cart } = useCart(); const count = useMemo( - () => cart.find((item) => item.id === product.id)?.count || 0, + () => Number(cart.find((item) => item.id === product.id)?.count), [cart, product] ); const handleAddItem = useCallback(() => addItem(product), [addItem, product]); diff --git a/src/components/ColorFilter/index.tsx b/src/components/ColorFilter/index.tsx index 5a0102e..aff3104 100644 --- a/src/components/ColorFilter/index.tsx +++ b/src/components/ColorFilter/index.tsx @@ -53,13 +53,13 @@ export default function ProductFilter({ classNames={{ control: (state) => classNames( - '!rounded-md bg-white dark:bg-gray-700 !border-gray-500 dark:!border-gray-600', + '!rounded-md bg-white dark:bg-gray-800 !border-gray-300 dark:!border-gray-600', { '!border-gray-800 dark:!border-gray-500 !rounded-md !shadow-[0_0_0_1px_#000000] dark:!shadow-[0_0_0_1px_#333]': state.isFocused, } ), - placeholder: (state) => 'text-gray-700 dark:text-gray-300', + placeholder: (state) => 'text-gray-300 dark:text-gray-500', menu: (state) => '!bg-white dark:!bg-gray-900', option: (state) => classNames( diff --git a/src/components/CountDot/index.tsx b/src/components/CountDot/index.tsx index 406b7d6..9198787 100644 --- a/src/components/CountDot/index.tsx +++ b/src/components/CountDot/index.tsx @@ -1,13 +1,13 @@ -import classNames from 'classnames'; import React from 'react'; +import classNames from 'classnames'; -type Props = { +type Props = React.ComponentPropsWithoutRef<'span'> & { count: number; - className?: string; }; -export default function CountDot({ count, className }: Props) { +export default function CountDot({ count, className, ...rest }: Props) { return ( ); } +export function Sun({ className }: IconProps) { + return ( + + ); +} +export function Moon({ className }: IconProps) { + return ( + + ); +} diff --git a/src/components/ProductItem/__snapshots__/ProductItem.test.tsx.snap b/src/components/ProductItem/__snapshots__/ProductItem.test.tsx.snap index 3208d3c..49ba8b6 100644 --- a/src/components/ProductItem/__snapshots__/ProductItem.test.tsx.snap +++ b/src/components/ProductItem/__snapshots__/ProductItem.test.tsx.snap @@ -3,17 +3,18 @@ exports[`ProductItem > ProductItem should show all data for given product 1`] = `
Product Image ProductItem should show all data for given product 1`] = sizes="100vw" src="/_next/image?url=%2Flogo.png&w=3840&q=75" srcset="/_next/image?url=%2Flogo.png&w=640&q=75 640w, /_next/image?url=%2Flogo.png&w=750&q=75 750w, /_next/image?url=%2Flogo.png&w=828&q=75 828w, /_next/image?url=%2Flogo.png&w=1080&q=75 1080w, /_next/image?url=%2Flogo.png&w=1200&q=75 1200w, /_next/image?url=%2Flogo.png&w=1920&q=75 1920w, /_next/image?url=%2Flogo.png&w=2048&q=75 2048w, /_next/image?url=%2Flogo.png&w=3840&q=75 3840w" - style="position: absolute; height: 100%; width: 100%; left: 0px; top: 0px; right: 0px; bottom: 0px; object-fit: cover; object-position: 50% 30%; color: transparent;" + style="position: absolute; height: 100%; width: 100%; left: 0px; top: 0px; right: 0px; bottom: 0px; object-fit: cover; object-position: 50% 20%; color: transparent;" />
-
-

- Product 1 -

-
+ Product 1 +
-

- Color: -

-
- - Black - -
+ Black +
-
-

- Price: -

-

- £ - - 10.00 - -

-
+ 10.00 + +

-
- - - 10 + + Remove -
+
+ -
+ + + + + 10 +
diff --git a/src/components/Products/Products.test.tsx b/src/components/Products/Products.test.tsx index bd36c56..0e556a6 100644 --- a/src/components/Products/Products.test.tsx +++ b/src/components/Products/Products.test.tsx @@ -10,14 +10,6 @@ const { ProductsProvider, CartProvider } = store; Note: Added integration test for given use cases/user stories here */ describe('Products', () => { - // const useCartSpy = vi.spyOn(store, 'useProductsStore'); - // useCartSpy.mockReturnValue({ - // products, - // filteredProducts: [product], - // color: undefined, - // setProducts: vi.fn(), - // setColor: vi.fn(), - // }); test('Products should get data form store and show all products', async () => { const { container } = render( @@ -26,126 +18,11 @@ describe('Products', () => { ); - expect(screen.getByText('Products')).toBeDefined; - // expect(screen.getByText('Cart Total:')).toBeDefined; - expect(screen.getByTestId('products-list').childNodes.length).toEqual( - products.length - ); - - /* - PLT-1: Viewing product listings - Given I am on the home page - Then I am shown a list of product items (image, name, price, qty in bag) - */ - expect(screen.getByTestId('products-list').childNodes.length).toEqual( - products.length - ); - products.forEach(matchProduct({ container })); - /* - PLT-2: Filter by colour - Given I am viewing all the product listings - When I choose to filter to show only black items - Then I am only shown listings for black items - */ - // Select Black color - const input = container.querySelector('.rs__input')!; - fireEvent.click(input); - fireEvent.change(input, { target: { value: 'Black' } }); - fireEvent.keyDown(input, { key: 'Enter', code: 'Enter', charCode: 13 }); - expect(screen.getByTestId('products-list').childNodes.length).toEqual( - products.filter((item) => item.colour === 'Black').length - ); - // Clear filter - fireEvent.mouseDown(container.querySelector('.rs__clear-indicator')!); - expect(screen.getByTestId('products-list').childNodes.length).toEqual( - products.length - ); - /* - PLT-3: Add to cart - Given I am viewing the products listings - When I press + - Then my basket qty for this item is incremented - And my total is updated to reflect the new items in my basket - */ - - // Add one item to cart - const product = products[0]; - const addBtn = screen.getByTestId(`product-${product.id}-add`); - - fireEvent.click(addBtn); - fireEvent.click(addBtn); - expect( - screen.getByTestId(`product-${product.id}-count`).textContent - ).toEqual('2'); - expect(screen.getByTestId('cart-total').textContent).toEqual( - (2 * product.price).toFixed(2) - ); - /* - PLT-3: Reduce quantity - Given I am viewing the products listings - When I press - - Then my basket qty for this item is decremented - And my total is updated to reflect the new items in my basket - */ - const removeBtn = screen.getByTestId(`product-${product.id}-remove`); - fireEvent.click(removeBtn); - expect( - screen.getByTestId(`product-${product.id}-count`).textContent - ).toEqual('1'); - expect(screen.getByTestId('cart-total').textContent).toEqual( - (1 * product.price).toFixed(2) - ); - /* - PLT-4: Remove from basket - Given I am viewing the products listings - When I press remove - Then all items of this type are removed from my basket - And my total is updated to reflect the new items in my basket - */ - const clearBtn = screen.getByTestId(`product-${product.id}-clear`); - fireEvent.click(clearBtn); - expect( - screen.getByTestId(`product-${product.id}-count`).textContent - ).toEqual('0'); - expect(screen.getByTestId('cart-total').textContent).toEqual( - (0).toFixed(2) - ); - expect( - screen - .getByTestId(`product-${product.id}-remove`) - .hasAttribute('disabled') - ).toBeTruthy(); - // Create snapshot + // // Create snapshot expect(container).toMatchSnapshot(); }); }); -const matchProduct = - ({ container }: { container: HTMLElement }) => - (product: Product) => { - expect(screen.getByText(product.name)).toBeDefined; - // Verify product price - expect( - screen.getByTestId(`product-${product.id}-price`).textContent - ).toEqual(product.price.toFixed(2)); - // verify image src and alt text - const image = screen.getByTestId(`product-${product.id}-img`); - expect(decodeURIComponent(image.getAttribute('src') as string)).contain( - product.img - ); - expect(image.getAttribute('alt')).toEqual('Product Image'); - // Verify product colour - expect( - container.querySelector( - `[data-testid="product-${product.id}-color"] .color-value` - )!.textContent - ).toEqual(product.colour); - // Verify product count - expect( - screen.getByTestId(`product-${product.id}-count`).textContent - ).toEqual('0'); - }; - const products: Product[] = [ { id: 1, diff --git a/src/components/Products/__snapshots__/Products.test.tsx.snap b/src/components/Products/__snapshots__/Products.test.tsx.snap index 1d42327..2e72e6f 100644 --- a/src/components/Products/__snapshots__/Products.test.tsx.snap +++ b/src/components/Products/__snapshots__/Products.test.tsx.snap @@ -3,10 +3,10 @@ exports[`Products > Products should get data form store and show all products 1`] = `

Products

@@ -26,13 +26,13 @@ exports[`Products > Products should get data form store and show all products 1` role="log" />
Select Color @@ -55,7 +55,7 @@ exports[`Products > Products should get data form store and show all products 1` id="react-select-color-filter-input" role="combobox" spellcheck="false" - style="opacity: 0; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;" + style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;" tabindex="0" type="text" value="" @@ -90,62 +90,56 @@ exports[`Products > Products should get data form store and show all products 1`
- Product Image -
-
+ Product Image +
+

Black Sheet Strappy Textured Glitter Bodycon Dress

-
-
-

- Color: -

@@ -155,17 +149,8 @@ exports[`Products > Products should get data form store and show all products 1` Black
-
-

- Price: -

-

£ Products should get data form store and show all products 1`

+
0
-
-
-
- Product Image -
-
+ Product Image +
+

Stone Ribbed Strappy Cut Out Detail Bodycon Dress

-
-
-

- Color: -

@@ -295,17 +272,8 @@ exports[`Products > Products should get data form store and show all products 1` Stone
-
-
-

- Price: -

£ Products should get data form store and show all products 1`

+
0
-
-
-
- Product Image -
-
+ Product Image +
+

Black Frill Tie Shoulder Bodycon Dress

-
-
-

- Color: -

@@ -435,17 +395,8 @@ exports[`Products > Products should get data form store and show all products 1` Black
-
-

- Price: -

-

£ Products should get data form store and show all products 1`

+
0
-
-
-
- Product Image -
-
+ Product Image +
+

Red Pin Stripe Belt T Shirt Dress

-
-
-

- Color: -

@@ -575,17 +518,8 @@ exports[`Products > Products should get data form store and show all products 1` Red
-
-

- Price: -

-

£ Products should get data form store and show all products 1`

+
0
-
-
-

- Cart Total: -

-

- £ - - 0.00 - -

-
`; diff --git a/src/components/ThemeSwitch/ThemeSwitch.test.tsx b/src/components/ThemeSwitch/ThemeSwitch.test.tsx new file mode 100644 index 0000000..1a8cacd --- /dev/null +++ b/src/components/ThemeSwitch/ThemeSwitch.test.tsx @@ -0,0 +1,19 @@ +import { fireEvent, render, screen } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import { Provider } from '@/store'; +import ThemeSwitch from './index'; + +describe('ThemeSwitch', () => { + test('ThemeSwitch should render moon icon in light mode', async () => { + render( + + + + ); + expect(screen.getByText('Moon')).toBeDefined; + fireEvent.click(screen.getByText('Moon')); + expect(screen.getByText('Sun')).toBeDefined; + fireEvent.click(screen.getByText('Sun')); + expect(screen.getByText('Moon')).toBeDefined; + }); +}); diff --git a/src/components/ThemeSwitch/index.tsx b/src/components/ThemeSwitch/index.tsx index 3d4b5ba..6e74960 100644 --- a/src/components/ThemeSwitch/index.tsx +++ b/src/components/ThemeSwitch/index.tsx @@ -1,38 +1,26 @@ -import React, { useContext } from 'react'; +import React from 'react'; import { useTheme } from 'next-themes'; -// import { ThemeContext } from '@/store/ThemeProvider'; import Button from '@/components/Button'; +import { Moon, Sun } from '@/components/Icons'; export default function ThemeSwitch() { - // const { theme, toggleTheme } = useContext(ThemeContext); const { theme, setTheme } = useTheme(); return ( ); diff --git a/src/store/ThemeProvider.test.tsx b/src/store/ThemeProvider.test.tsx new file mode 100644 index 0000000..bdc96ad --- /dev/null +++ b/src/store/ThemeProvider.test.tsx @@ -0,0 +1,13 @@ +import { render } from '@testing-library/react'; +import { expect, test } from 'vitest'; +import { Provider as ThemeProvider } from './ThemeProvider'; + +test('ThemeProvider should render without error', async () => { + const { container } = render( + +

+
+ ); + // save snapshot + expect(container).toMatchSnapshot(); +}); diff --git a/src/store/__snapshots__/ThemeProvider.test.tsx.snap b/src/store/__snapshots__/ThemeProvider.test.tsx.snap new file mode 100644 index 0000000..5d934f0 --- /dev/null +++ b/src/store/__snapshots__/ThemeProvider.test.tsx.snap @@ -0,0 +1,10 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`ThemeProvider should render without error 1`] = ` +
+ +

+

+`; diff --git a/src/store/index.tsx b/src/store/index.tsx index 0fe276e..644e5f4 100644 --- a/src/store/index.tsx +++ b/src/store/index.tsx @@ -1,3 +1,4 @@ 'use client'; export * from './CartProvider'; export * from './ProductsProvider'; +export * from './ThemeProvider';