This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,9 @@
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "vitest",
|
||||
"test:watch": "vitest --watch",
|
||||
"test:ui": "vitest --ui",
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "oxlint",
|
||||
@@ -17,6 +20,9 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^8.1.0",
|
||||
"@rolldown/plugin-babel": "^0.3.0",
|
||||
"@testing-library/jest-dom": "^7.0.1",
|
||||
"@testing-library/react": "^16.3.3",
|
||||
"@testing-library/user-event": "^14.6.8",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"@types/node": "^26.6.6",
|
||||
"@types/react": "^19.3.0",
|
||||
@@ -24,6 +30,7 @@
|
||||
"@vitejs/plugin-react": "^6.2.1",
|
||||
"@vitest/ui": "^5.1.0",
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"jsdom": "^30.1.3",
|
||||
"oxlint": "^1.91.0",
|
||||
"typescript": "~7.0.2",
|
||||
"vite": "^8.3.6",
|
||||
|
||||
@@ -5,24 +5,20 @@ import Footer from '../components/Footer';
|
||||
|
||||
const categories = [
|
||||
{
|
||||
imgSrc:
|
||||
'https://images.unsplash.com/photo-1530011940847-04cba36df39f?q=80&w=1920',
|
||||
imgAlt:
|
||||
'Two female models sitting on a bed. Photo by Billie (@billiebodybrand) on Unsplash.',
|
||||
imgSrc: 'https://images.unsplash.com/photo-1530011940847-04cba36df39f?q=80&w=1920',
|
||||
imgAlt: 'Two female models sitting on a bed. Photo by Billie (@billiebodybrand) on Unsplash.',
|
||||
href: '/women',
|
||||
linkText: 'Women Clothing',
|
||||
},
|
||||
{
|
||||
imgSrc:
|
||||
'https://images.unsplash.com/photo-1595909315417-2edd382a56dc?q=80&w=1920',
|
||||
imgSrc: 'https://images.unsplash.com/photo-1595909315417-2edd382a56dc?q=80&w=1920',
|
||||
imgAlt:
|
||||
'Jumping rope, smartphone, sports bra, a pair of sneakers, and a water bottle. Photo by erica steeves on Unsplash.',
|
||||
href: '/accessories',
|
||||
linkText: 'Accessories',
|
||||
},
|
||||
{
|
||||
imgSrc:
|
||||
'https://images.unsplash.com/photo-1467779009031-53938b78ca38?q=80&w=1920',
|
||||
imgSrc: 'https://images.unsplash.com/photo-1467779009031-53938b78ca38?q=80&w=1920',
|
||||
imgAlt: 'Group of men sitting in a van. Photo by Luke Porter on Unsplash.',
|
||||
href: '/men',
|
||||
linkText: 'Men Clothing',
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import Hero from '../components/Hero';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { it, expect, describe } from 'vitest';
|
||||
|
||||
// import '@testing-library/jest-dom/vitest';
|
||||
|
||||
// Test Suite
|
||||
describe('Hero', () => {
|
||||
it('should render h1 element', () => {
|
||||
render(<Hero />);
|
||||
|
||||
const heading = screen.getByRole('heading', { level: 1 });
|
||||
expect(heading).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the company name when passed', () => {
|
||||
render(<Hero companyName="My Company" />);
|
||||
|
||||
screen.debug();
|
||||
|
||||
// Arrange
|
||||
const heading = screen.getByRole('heading', { level: 1 });
|
||||
|
||||
// Act & Assert
|
||||
expect(heading).toHaveTextContent('My Company');
|
||||
// expect(heading).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the company name "Vogue Junction" as default', () => {
|
||||
render(<Hero />);
|
||||
// Arrange
|
||||
const heading = screen.getByRole('heading', { level: 1 });
|
||||
// Act & Assert
|
||||
expect(heading).toHaveTextContent(/Vogue Junction/i);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
// import { fireEvent } from '@testing-library/react';
|
||||
import { screen, render } from '@testing-library/react';
|
||||
import { userEvent } from '@testing-library/user-event';
|
||||
|
||||
import { fakeProduct } from './__mocks__/product.mock';
|
||||
|
||||
// component
|
||||
import ImageGallery from '../components/ImageGallery';
|
||||
|
||||
const product = fakeProduct;
|
||||
|
||||
const renderComponent = () => {
|
||||
render(<ImageGallery product={product} />);
|
||||
// screen.debug();
|
||||
|
||||
const images = screen.getAllByAltText(product.title);
|
||||
return {
|
||||
images,
|
||||
mainImage: images[images.length - 1],
|
||||
buttons: screen.getAllByRole('button'),
|
||||
};
|
||||
};
|
||||
|
||||
describe('ImageGallery', () => {
|
||||
it('should render three buttons', () => {
|
||||
// Arrange
|
||||
const { buttons } = renderComponent();
|
||||
// Act & Assert
|
||||
expect(buttons).toHaveLength(3);
|
||||
});
|
||||
it('should render four images', () => {
|
||||
// Arrange
|
||||
const { images } = renderComponent();
|
||||
// Act & Assert
|
||||
expect(images).toHaveLength(4);
|
||||
});
|
||||
it('should render the first image as main image', () => {
|
||||
// Arrange
|
||||
const { mainImage } = renderComponent();
|
||||
|
||||
expect(mainImage).toBeInTheDocument();
|
||||
expect(mainImage).toHaveAttribute(
|
||||
'src',
|
||||
product.images[0], // 'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/1.png',
|
||||
);
|
||||
});
|
||||
it('should change the main image when the last image was clicked', async () => {
|
||||
// Arrange
|
||||
const { mainImage, buttons } = renderComponent();
|
||||
|
||||
const user = userEvent.setup();
|
||||
|
||||
// fireEvent.click(buttons[2]);
|
||||
await user.click(buttons[2]); // best practice
|
||||
|
||||
expect(mainImage).toHaveAttribute(
|
||||
'src',
|
||||
product.images[2], // 'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/3.png',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import { fakeProducts } from './__mocks__/products.mock';
|
||||
import ProductList from '../components/ProductList';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
const products = fakeProducts;
|
||||
|
||||
describe('ProductList', () => {
|
||||
it('should render the correct number of products', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<ProductList data={products} />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
// screen.debug();
|
||||
const headings = screen.getAllByRole('heading', { level: 3 });
|
||||
|
||||
expect(headings).toHaveLength(products.length);
|
||||
});
|
||||
|
||||
it('should render the product list cards correctly with the title, image and price', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<ProductList data={products} />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
products.forEach((product) => {
|
||||
const { title, thumbnail, price } = product;
|
||||
const image = screen.getByAltText(title);
|
||||
|
||||
expect(screen.getByText(title)).toBeInTheDocument(); // title
|
||||
expect(image).toBeInTheDocument(); // image alt text
|
||||
expect(image).toHaveAttribute('src', thumbnail); // image src
|
||||
expect(screen.getByText(`$${price}`)).toBeInTheDocument(); // price
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
export const fakeProduct = {
|
||||
id: 174,
|
||||
title: 'Prada Women Bag',
|
||||
description:
|
||||
"The Prada Women Bag is an iconic designer bag that exudes elegance and luxury. Crafted with precision and featuring the Prada logo, it's a statement piece for fashion enthusiasts.",
|
||||
category: 'womens-bags',
|
||||
price: 599.99,
|
||||
discountPercentage: 18.3,
|
||||
rating: 3.52,
|
||||
stock: 43,
|
||||
tags: ['fashion accessories', 'designer bags'],
|
||||
brand: 'Prada',
|
||||
sku: 'WXX4YTJM',
|
||||
weight: 4,
|
||||
dimensions: { width: 23.45, height: 16.1, depth: 5.78 },
|
||||
warrantyInformation: '1 week warranty',
|
||||
shippingInformation: 'Ships overnight',
|
||||
availabilityStatus: 'In Stock',
|
||||
reviews: [
|
||||
{
|
||||
rating: 5,
|
||||
comment: 'Excellent quality!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Samantha Howard',
|
||||
reviewerEmail: 'samantha.howard@x.dummyjson.com',
|
||||
},
|
||||
{
|
||||
rating: 4,
|
||||
comment: 'Would buy again!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Henry Hill',
|
||||
reviewerEmail: 'henry.hill@x.dummyjson.com',
|
||||
},
|
||||
{
|
||||
rating: 3,
|
||||
comment: 'Not worth the price!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Lucas Ramirez',
|
||||
reviewerEmail: 'lucas.ramirez@x.dummyjson.com',
|
||||
},
|
||||
],
|
||||
returnPolicy: '7 days return policy',
|
||||
minimumOrderQuantity: 1,
|
||||
meta: {
|
||||
createdAt: new Date('2024-05-23T08:56:21.627Z'),
|
||||
updatedAt: new Date('2024-05-23T08:56:21.627Z'),
|
||||
barcode: '4590351278063',
|
||||
qrCode: 'https://assets.dummyjson.com/public/qr-code.png',
|
||||
},
|
||||
images: [
|
||||
'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/1.png',
|
||||
'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/2.png',
|
||||
'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/3.png',
|
||||
],
|
||||
thumbnail: 'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/thumbnail.png',
|
||||
};
|
||||
@@ -0,0 +1,168 @@
|
||||
export const fakeProducts = [
|
||||
{
|
||||
id: 174,
|
||||
title: 'Prada Women Bag',
|
||||
description:
|
||||
"The Prada Women Bag is an iconic designer bag that exudes elegance and luxury. Crafted with precision and featuring the Prada logo, it's a statement piece for fashion enthusiasts.",
|
||||
category: 'womens-bags',
|
||||
price: 599.99,
|
||||
discountPercentage: 18.3,
|
||||
rating: 3.52,
|
||||
stock: 43,
|
||||
tags: ['fashion accessories', 'designer bags'],
|
||||
brand: 'Prada',
|
||||
sku: 'WXX4YTJM',
|
||||
weight: 4,
|
||||
dimensions: { width: 23.45, height: 16.1, depth: 5.78 },
|
||||
warrantyInformation: '1 week warranty',
|
||||
shippingInformation: 'Ships overnight',
|
||||
availabilityStatus: 'In Stock',
|
||||
reviews: [
|
||||
{
|
||||
rating: 5,
|
||||
comment: 'Excellent quality!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Samantha Howard',
|
||||
reviewerEmail: 'samantha.howard@x.dummyjson.com',
|
||||
},
|
||||
{
|
||||
rating: 4,
|
||||
comment: 'Would buy again!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Henry Hill',
|
||||
reviewerEmail: 'henry.hill@x.dummyjson.com',
|
||||
},
|
||||
{
|
||||
rating: 3,
|
||||
comment: 'Not worth the price!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Lucas Ramirez',
|
||||
reviewerEmail: 'lucas.ramirez@x.dummyjson.com',
|
||||
},
|
||||
],
|
||||
returnPolicy: '7 days return policy',
|
||||
minimumOrderQuantity: 1,
|
||||
meta: {
|
||||
createdAt: new Date('2024-05-23T08:56:21.627Z'),
|
||||
updatedAt: new Date('2024-05-23T08:56:21.627Z'),
|
||||
barcode: '4590351278063',
|
||||
qrCode: 'https://assets.dummyjson.com/public/qr-code.png',
|
||||
},
|
||||
images: [
|
||||
'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/1.png',
|
||||
'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/2.png',
|
||||
'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/3.png',
|
||||
],
|
||||
thumbnail: 'https://cdn.dummyjson.com/products/images/womens-bags/Prada%20Women%20Bag/thumbnail.png',
|
||||
},
|
||||
{
|
||||
id: 90,
|
||||
title: 'Puma Future Rider Trainers',
|
||||
description:
|
||||
'The Puma Future Rider Trainers offer a blend of retro style and modern comfort. Perfect for casual wear, these trainers provide a fashionable and comfortable option for everyday use.',
|
||||
category: 'mens-shoes',
|
||||
price: 89.99,
|
||||
discountPercentage: 3.64,
|
||||
rating: 4.85,
|
||||
stock: 10,
|
||||
tags: ['footwear', 'casual shoes'],
|
||||
brand: 'Puma',
|
||||
sku: '64ORN32I',
|
||||
weight: 8,
|
||||
dimensions: { width: 14.58, height: 25.54, depth: 19.57 },
|
||||
warrantyInformation: '2 year warranty',
|
||||
shippingInformation: 'Ships in 1 month',
|
||||
availabilityStatus: 'In Stock',
|
||||
reviews: [
|
||||
{
|
||||
rating: 5,
|
||||
comment: 'Very happy with my purchase!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Lucas Allen',
|
||||
reviewerEmail: 'lucas.allen@x.dummyjson.com',
|
||||
},
|
||||
{
|
||||
rating: 4,
|
||||
comment: 'Awesome product!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Mason Pearson',
|
||||
reviewerEmail: 'mason.pearson@x.dummyjson.com',
|
||||
},
|
||||
{
|
||||
rating: 4,
|
||||
comment: 'Very satisfied!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Hunter Gordon',
|
||||
reviewerEmail: 'hunter.gordon@x.dummyjson.com',
|
||||
},
|
||||
],
|
||||
returnPolicy: '90 days return policy',
|
||||
minimumOrderQuantity: 9,
|
||||
meta: {
|
||||
createdAt: new Date('2024-05-23T08:56:21.627Z'),
|
||||
updatedAt: new Date('2024-05-23T08:56:21.627Z'),
|
||||
barcode: '3562849555769',
|
||||
qrCode: 'https://assets.dummyjson.com/public/qr-code.png',
|
||||
},
|
||||
images: [
|
||||
'https://cdn.dummyjson.com/products/images/mens-shoes/Puma%20Future%20Rider%20Trainers/1.png',
|
||||
'https://cdn.dummyjson.com/products/images/mens-shoes/Puma%20Future%20Rider%20Trainers/2.png',
|
||||
'https://cdn.dummyjson.com/products/images/mens-shoes/Puma%20Future%20Rider%20Trainers/3.png',
|
||||
'https://cdn.dummyjson.com/products/images/mens-shoes/Puma%20Future%20Rider%20Trainers/4.png',
|
||||
],
|
||||
thumbnail: 'https://cdn.dummyjson.com/products/images/mens-shoes/Puma%20Future%20Rider%20Trainers/thumbnail.png',
|
||||
},
|
||||
{
|
||||
id: 101,
|
||||
title: 'Apple AirPods Max Silver',
|
||||
description:
|
||||
'The Apple AirPods Max in Silver are premium over-ear headphones with high-fidelity audio, adaptive EQ, and active noise cancellation. Experience immersive sound in style.',
|
||||
category: 'mobile-accessories',
|
||||
price: 549.99,
|
||||
discountPercentage: 11.7,
|
||||
rating: 3.11,
|
||||
stock: 7,
|
||||
tags: ['electronics', 'over-ear headphones'],
|
||||
brand: 'Apple',
|
||||
sku: 'HPK82VDE',
|
||||
weight: 4,
|
||||
dimensions: { width: 7.73, height: 18.36, depth: 17.87 },
|
||||
warrantyInformation: '3 months warranty',
|
||||
shippingInformation: 'Ships in 1 month',
|
||||
availabilityStatus: 'In Stock',
|
||||
reviews: [
|
||||
{
|
||||
rating: 1,
|
||||
comment: 'Waste of money!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Harper Kelly',
|
||||
reviewerEmail: 'harper.kelly@x.dummyjson.com',
|
||||
},
|
||||
{
|
||||
rating: 3,
|
||||
comment: 'Not as described!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Abigail Rivera',
|
||||
reviewerEmail: 'abigail.rivera@x.dummyjson.com',
|
||||
},
|
||||
{
|
||||
rating: 5,
|
||||
comment: 'Excellent quality!',
|
||||
date: new Date('2024-05-23T08:56:21.627Z'),
|
||||
reviewerName: 'Nora Russell',
|
||||
reviewerEmail: 'nora.russell@x.dummyjson.com',
|
||||
},
|
||||
],
|
||||
returnPolicy: '90 days return policy',
|
||||
minimumOrderQuantity: 2,
|
||||
meta: {
|
||||
createdAt: new Date('2024-05-23T08:56:21.627Z'),
|
||||
updatedAt: new Date('2024-05-23T08:56:21.627Z'),
|
||||
barcode: '9261269777547',
|
||||
qrCode: 'https://assets.dummyjson.com/public/qr-code.png',
|
||||
},
|
||||
images: ['https://cdn.dummyjson.com/products/images/mobile-accessories/Apple%20AirPods%20Max%20Silver/1.png'],
|
||||
thumbnail:
|
||||
'https://cdn.dummyjson.com/products/images/mobile-accessories/Apple%20AirPods%20Max%20Silver/thumbnail.png',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,11 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { add } from '../utils/helpers';
|
||||
|
||||
describe('add', () => {
|
||||
it('should return 3 when 2 and 1 passed', () => {
|
||||
expect(add(1, 2)).toBe(3);
|
||||
});
|
||||
it('should return 0.3 when 0.2 and 0.1 passed', () => {
|
||||
expect(add(0.2, 0.1)).toBe(0.3);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import { expect, afterEach } from 'vitest';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import * as matchers from '@testing-library/jest-dom/matchers';
|
||||
|
||||
// types für Testfunktionen
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
|
||||
// add jest-dom matchers to expect
|
||||
expect.extend(matchers);
|
||||
|
||||
// Add cleanup function to run after each test
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
// More setup code here, if needed
|
||||
@@ -0,0 +1,19 @@
|
||||
import { it, test, expect, describe } from 'vitest';
|
||||
|
||||
// Testsuite
|
||||
describe('main', () => {
|
||||
// Testcase
|
||||
test('main should pass', () => {
|
||||
// AAA
|
||||
// Arrange
|
||||
const initValue = true;
|
||||
// Acting - Assertion
|
||||
expect(initValue).toBe(true);
|
||||
});
|
||||
|
||||
it('should return a number', () => {
|
||||
expect(1).toBeTypeOf('number');
|
||||
});
|
||||
});
|
||||
|
||||
// console.log(fn()); // => true
|
||||
@@ -0,0 +1,11 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { multiply } from '../utils/helpers';
|
||||
|
||||
describe('multiply', () => {
|
||||
it('should return 10 when 2 and 5 are passed', () => {
|
||||
expect(multiply(2, 5)).toBe(10);
|
||||
});
|
||||
it('should return a number', () => {
|
||||
expect(multiply(1, 2)).toBeTypeOf('number');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
export const multiply = (a: number, b: number): number => {
|
||||
return Number(a) * Number(b);
|
||||
};
|
||||
export const add = (a: number, b: number): number => {
|
||||
return parseFloat((Number(a) + Number(b)).toFixed(10));
|
||||
};
|
||||
|
||||
export default {
|
||||
//multiply: multiply
|
||||
multiply,
|
||||
add,
|
||||
};
|
||||
@@ -1,11 +1,13 @@
|
||||
import react, { reactCompilerPreset } from '@vitejs/plugin-react'
|
||||
import babel from '@rolldown/plugin-babel'
|
||||
import { defineConfig } from 'vite'
|
||||
import react, { reactCompilerPreset } from '@vitejs/plugin-react';
|
||||
import babel from '@rolldown/plugin-babel';
|
||||
import { defineConfig } from 'vitest/config'; // nicht mehr vite
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
babel({ presets: [reactCompilerPreset()] })
|
||||
],
|
||||
})
|
||||
plugins: [react(), babel({ presets: [reactCompilerPreset()] })],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
setupFiles: './src/tests/config/setupTests.ts',
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user