This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
import { defineConfig } from 'cypress';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
allowCypressEnv: false,
|
||||||
|
|
||||||
|
e2e: {
|
||||||
|
baseUrl: 'http://localhost:5173',
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
// implement node event listeners here
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// cypress/e2e/example_counter.cy.js or .cy.ts for TypeScript
|
||||||
|
describe('ExampleCounter', () => {
|
||||||
|
// Describes the test suite
|
||||||
|
it('renders and increments the counter', () => {
|
||||||
|
// Describes the individual test case
|
||||||
|
|
||||||
|
// 1. Visit the page where the component is rendered.
|
||||||
|
// Change '/' to the path where your component is displayed.
|
||||||
|
cy.visit('/');
|
||||||
|
// 2. Check if the initial text is present.
|
||||||
|
cy.contains('p', 'Counter: 0');
|
||||||
|
// 3. Click on the button.
|
||||||
|
cy.get('[data-testid="button-inc"]', { name: /Increment/i }).click();
|
||||||
|
// 4. Check if the text has changed.
|
||||||
|
cy.contains('p', 'Counter: 1');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// ***********************************************
|
||||||
|
// This example commands.js shows you how to
|
||||||
|
// create various custom commands and overwrite
|
||||||
|
// existing commands.
|
||||||
|
//
|
||||||
|
// For more comprehensive examples of custom
|
||||||
|
// commands please read more here:
|
||||||
|
// https://on.cypress.io/custom-commands
|
||||||
|
// ***********************************************
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a parent command --
|
||||||
|
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a child command --
|
||||||
|
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a dual command --
|
||||||
|
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This will overwrite an existing command --
|
||||||
|
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// ***********************************************************
|
||||||
|
// This example support/e2e.js is processed and
|
||||||
|
// loaded automatically before your test files.
|
||||||
|
//
|
||||||
|
// This is a great place to put global configuration and
|
||||||
|
// behavior that modifies Cypress.
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off
|
||||||
|
// automatically serving support files with the
|
||||||
|
// 'supportFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/configuration
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// Import commands.js using ES2015 syntax:
|
||||||
|
import './commands'
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,8 @@
|
|||||||
"@types/react-dom": "^19.2.5",
|
"@types/react-dom": "^19.2.5",
|
||||||
"@vitejs/plugin-react": "^6.1.0",
|
"@vitejs/plugin-react": "^6.1.0",
|
||||||
"@vitest/ui": "^4.1.11",
|
"@vitest/ui": "^4.1.11",
|
||||||
|
"axios-mock-adapter": "^2.1.0",
|
||||||
|
"cypress": "^15.21.0",
|
||||||
"jsdom": "^30.0.1",
|
"jsdom": "^30.0.1",
|
||||||
"oxlint": "^1.79.0",
|
"oxlint": "^1.79.0",
|
||||||
"sass-embedded": "^1.103.1",
|
"sass-embedded": "^1.103.1",
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import Button from './components/buttons/Button';
|
import Button from './components/buttons/Button';
|
||||||
import ExampleComponent from './components/examples/ExampleComponent';
|
import ExampleComponent from './components/examples/ExampleComponent';
|
||||||
import FormContact from './components/forms/FormContact';
|
import ExampleCounter from './components/examples/ExampleCounter';
|
||||||
|
import InputAmount from './components/inputs/InputAmount';
|
||||||
|
|
||||||
|
// import FormContact from './components/forms/FormContact';
|
||||||
|
// import ListUser from './components/lists/ListUser';
|
||||||
|
|
||||||
function App(props) {
|
function App(props) {
|
||||||
// const { } = props;
|
// const { } = props;
|
||||||
@@ -8,11 +12,17 @@ function App(props) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="container py-5">
|
<div className="container py-5">
|
||||||
|
<ExampleCounter />
|
||||||
|
<hr />
|
||||||
|
<InputAmount />
|
||||||
|
<hr />
|
||||||
<ExampleComponent />
|
<ExampleComponent />
|
||||||
<hr />
|
<hr />
|
||||||
|
{/* <ListUser /> */}
|
||||||
|
<hr />
|
||||||
<Button />
|
<Button />
|
||||||
<hr />
|
<hr />
|
||||||
<FormContact />
|
{/* <FormContact /> */}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
const ExampleAsyncComponent = () => {
|
||||||
|
const [data, setData] = useState('');
|
||||||
|
useEffect(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
setData('Data loaded');
|
||||||
|
}, 250);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div className="example-async-component">
|
||||||
|
<p>{data}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ExampleAsyncComponent;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
const ExampleCounter = () => {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
setCount(count + 1);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Counter: {count}</p>
|
||||||
|
<button type="button" className="btn btn-dark button-inc" onClick={handleClick} data-testid="button-inc">
|
||||||
|
Increment
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ExampleCounter;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
const ExampleUserList = (props) => {
|
||||||
|
const [users, setUsers] = useState([]);
|
||||||
|
useEffect(() => {
|
||||||
|
axios
|
||||||
|
.get('https://dummyjson.com/users?limit=3')
|
||||||
|
.then((response) => setUsers(response.data.users));
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<ul className="list-group list-group-flush list-user">
|
||||||
|
{users.map((user) => (
|
||||||
|
<li key={user.id} className="list-group-item">
|
||||||
|
{user.firstName}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ExampleUserList;
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { FaMinus, FaPlus } from 'react-icons/fa6';
|
||||||
|
const InputAmount = () => {
|
||||||
|
const [amount, setAmount] = useState(0);
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
if (!isNaN(value)) {
|
||||||
|
setAmount(Number(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickIncrement = () => {
|
||||||
|
setAmount(amount + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickDecrement = () => {
|
||||||
|
setAmount(amount - 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="m-input-amount">
|
||||||
|
<div className="input-group mb-3">
|
||||||
|
<span className="input-group-text">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-dark button-dec"
|
||||||
|
onClick={handleClickDecrement}
|
||||||
|
disabled={amount === 0}>
|
||||||
|
<FaMinus />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="form-control input-amount"
|
||||||
|
aria-label="Amount"
|
||||||
|
onChange={handleChange}
|
||||||
|
value={amount}
|
||||||
|
/>
|
||||||
|
<span className="input-group-text">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-dark button-inc"
|
||||||
|
onClick={handleClickIncrement}
|
||||||
|
disabled={amount === 10}>
|
||||||
|
<FaPlus />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InputAmount;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// ExampleAsyncComponent.test.jsx
|
||||||
|
import { it, describe } from 'vitest';
|
||||||
|
import { render, screen, waitFor } from '@testing-library/react';
|
||||||
|
import ExampleAsyncComponent from '../components/examples/ExampleAsyncComponent'; // Adjust the path
|
||||||
|
|
||||||
|
// example async component
|
||||||
|
// const ExampleAsyncComponent = () => {
|
||||||
|
// const [data, setData] = useState('');
|
||||||
|
// useEffect(() => {
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setData('Data loaded');
|
||||||
|
// }, 500);
|
||||||
|
// }, []);
|
||||||
|
// return <div>{data}</div>;
|
||||||
|
// };
|
||||||
|
|
||||||
|
describe('ExampleAsyncComponent', () => {
|
||||||
|
it('should render data after loading', async () => {
|
||||||
|
// async function!
|
||||||
|
render(<ExampleAsyncComponent />);
|
||||||
|
|
||||||
|
// waitFor waits for the callback to not throw an error
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText('Data loaded')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { describe, it, afterEach } from 'vitest';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
|
import ExampleUserList from '../components/examples/ExampleUserList';
|
||||||
|
|
||||||
|
// Create a new instance of the MockAdapter
|
||||||
|
const mock = new MockAdapter(axios);
|
||||||
|
|
||||||
|
// Clean up after each test case to prevent interference between tests
|
||||||
|
afterEach(() => {
|
||||||
|
mock.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ExampleUserList', () => {
|
||||||
|
it('should load and display user data', async () => {
|
||||||
|
render(<ExampleUserList />);
|
||||||
|
const mockData = { users: [{ id: 1, firstName: 'John' }] };
|
||||||
|
// Configure the mock: When this specific URL is requested, return 200 and our mockData
|
||||||
|
// This intercepts the network call, so no real internet request happens
|
||||||
|
mock.onGet('https://dummyjson.com/users?limit=3').reply(200, mockData);
|
||||||
|
|
||||||
|
const userElement = await screen.findByText(/John/i);
|
||||||
|
|
||||||
|
expect(userElement).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// InputAmount.test.jsx
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { it, expect, describe } from 'vitest';
|
||||||
|
import InputAmount from '../components/inputs/InputAmount'; // Adjust the path
|
||||||
|
|
||||||
|
describe('InputAmount', () => {
|
||||||
|
it('should matches the snapshot', () => {
|
||||||
|
const { container } = render(<InputAmount />);
|
||||||
|
|
||||||
|
screen.debug();
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { describe, it, afterEach } from 'vitest';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
|
import ListUser from '../components/lists/ListUser';
|
||||||
|
|
||||||
|
// Create a new instance of the MockAdapter
|
||||||
|
const mock = new MockAdapter(axios);
|
||||||
|
|
||||||
|
// Clean up after each test case to prevent interference between tests
|
||||||
|
afterEach(() => {
|
||||||
|
mock.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ListUser', () => {
|
||||||
|
it('should load and display user data', async () => {
|
||||||
|
render(<ListUser />);
|
||||||
|
const mockData = { users: [{ id: 1, firstName: 'John' }] };
|
||||||
|
// Configure the mock: When this specific URL is requested, return 200 and our mockData
|
||||||
|
// This intercepts the network call, so no real internet request happens
|
||||||
|
mock.onGet('https://dummyjson.com/users?limit=3').reply(200, mockData);
|
||||||
|
|
||||||
|
const userElement = await screen.findByText(/John/i);
|
||||||
|
|
||||||
|
expect(userElement).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`InputAmount > should matches the snapshot 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="m-input-amount"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="input-group mb-3"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="input-group-text"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-dark button-dec"
|
||||||
|
disabled=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
fill="currentColor"
|
||||||
|
height="1em"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="0"
|
||||||
|
viewBox="0 0 448 512"
|
||||||
|
width="1em"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
aria-label="Amount"
|
||||||
|
class="form-control input-amount"
|
||||||
|
type="number"
|
||||||
|
value="0"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="input-group-text"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-dark button-inc"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
fill="currentColor"
|
||||||
|
height="1em"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="0"
|
||||||
|
viewBox="0 0 448 512"
|
||||||
|
width="1em"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 144L48 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l144 0 0 144c0 17.7 14.3 32 32 32s32-14.3 32-32l0-144 144 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-144 0 0-144z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
@@ -10,5 +10,7 @@ export default defineConfig({
|
|||||||
environment: 'jsdom', // use jsdom as the test environment
|
environment: 'jsdom', // use jsdom as the test environment
|
||||||
setupFiles: './src/test/setup.js', // if you have a setup file
|
setupFiles: './src/test/setup.js', // if you have a setup file
|
||||||
// more options here
|
// more options here
|
||||||
|
// testTimeout: 2000, // 10 Sekunden für alle Tests
|
||||||
|
// hookTimeout: 2000, // Optional: Timeout für beforeAll, afterAll, etc.
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user