diff --git a/README.md b/README.md index 20b4126..6ae3f61 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,94 @@ # zipBoard Junior Position Test Project -This is a test repository for the zipBoard junior position application process. This project demonstrates a simple React application with a login form and Cypress testing setup. +This repository contains my solution for the zipBoard junior position test. The project demonstrates my ability to debug issues and implement comprehensive testing in a React application. -## Important Note +## Bug Fix: Login Functionality -This repository is for testing purposes only. Please fork this repository to your own account and do not modify this original repository. All your work should be done in your forked version. +### Issue +The login functionality was not working properly - clicking the login button did not redirect users to the welcome screen. -## Required Technologies +### Solution +I identified and fixed the issue in the `LoginForm` component. The main problems were: +1. The form submission wasn't being handled +2. The `onLogin` prop was received but never used +3. Form data wasn't being passed to the parent component -To run this project locally, you need to have the following installed: +### Changes Made +I modified `src/components/LoginForm.js` to: +1. Add a `handleSubmit` function that prevents default form submission +2. Connect the form's `onSubmit` event to the handler +3. Pass the form data to the parent component via the `onLogin` prop -- Node.js (version 18 or higher) -- npm (comes with Node.js) -- Git +### Before and After +![Login Form Before Fix](media/Screenshot%202025-05-19%20203309.png) -## Getting Started +The video below demonstrates the fixed login functionality: -1. Fork this repository to your own account -2. Clone your forked repository: - ```bash - git clone - ``` -3. Install dependencies: - ```bash - npm install - ``` -4. Start the development server: - ```bash - npm start - ``` - The application will be available at [http://localhost:3000](http://localhost:3000) +https://github.com/user-attachments/assets/c88f44fe-d04d-4786-b648-52680efd2720 -## Testing with Cypress +## Cypress Testing Implementation -This project uses Cypress for end-to-end testing. To run the tests: +I implemented comprehensive end-to-end tests using Cypress to ensure the application's reliability and functionality. -1. Make sure the development server is running (`npm start`) -2. In a new terminal, you can run Cypress in two ways: +### Test Location +All tests are located in `cypress/e2e/login.cy.js` - ### Open Cypress Test Runner (Interactive Mode) - ```bash - npm run cypress:open - ``` - This will open the Cypress Test Runner UI where you can: - - Choose your preferred browser - - See all test files - - Run tests interactively - - Watch tests run in real-time +### Test Coverage +The test suite includes: +1. Initial form display verification +2. Form validation testing +3. Successful login flow +4. Form input handling +5. Logout functionality +6. Form state management +7. Special character handling +8. Long input validation + +### Test Execution +You can run the tests using: +```bash +npm run cypress:open # Opens Cypress Test Runner UI +npm run cypress:run # Runs tests in headless mode +npm run test:e2e # Runs tests with dev server +``` + +### Test Implementation +![Cypress Test Implementation](media/Screenshot%202025-05-19%20204045.png) + +The video below shows the Cypress tests in action: + +https://github.com/user-attachments/assets/62692b52-3a20-4af1-9700-ac622267b834 + +## Project Setup + +### Prerequisites +- Node.js (version 18 or higher) +- npm (comes with Node.js) - ### Run Tests in Headless Mode +### Installation +1. Clone the repository +2. Install dependencies: ```bash - npm run cypress:run + npm install ``` - This will run all tests in the terminal without opening the UI. - - ### Run Tests with Dev Server +3. Start the development server: ```bash - npm run test:e2e + npm start ``` - This command will: - 1. Start the development server - 2. Wait for it to be available - 3. Run all Cypress tests - 4. Shut down the server when done -## Project Structure +## Available Scripts +- `npm start` - Runs the app in development mode +- `npm test` - Runs the React testing suite +- `npm run build` - Builds the app for production +- `npm run cypress:open` - Opens Cypress Test Runner +- `npm run cypress:run` - Runs Cypress tests in headless mode +- `npm run test:e2e` - Runs Cypress tests with the dev server +## Project Structure ``` ├── src/ │ ├── components/ -│ │ ├── LoginForm.js +│ │ ├── LoginForm.js # Modified for login fix │ │ ├── LoginForm.css │ │ ├── Welcome.js │ │ └── Welcome.css @@ -77,22 +96,17 @@ This project uses Cypress for end-to-end testing. To run the tests: │ └── App.css ├── cypress/ │ ├── e2e/ -│ │ └── login.cy.js +│ │ └── login.cy.js # Comprehensive test suite │ └── support/ │ ├── commands.js │ └── e2e.js -└── package.json +└── media/ # Documentation media + ├── Screenshot 2025-05-19 203309.png + ├── Screenshot 2025-05-19 204045.png + ├── demo_fixed_error.mp4 + └── cypress_testing.mp4 ``` -## Available Scripts - -- `npm start` - Runs the app in development mode -- `npm test` - Runs the React testing suite -- `npm run build` - Builds the app for production -- `npm run cypress:open` - Opens Cypress Test Runner -- `npm run cypress:run` - Runs Cypress tests in headless mode -- `npm run test:e2e` - Runs Cypress tests with the dev server - ## License This project is for testing purposes only and is not licensed for public use. diff --git a/cypress/e2e/login.cy.js b/cypress/e2e/login.cy.js index c2fbb3a..c36b535 100644 --- a/cypress/e2e/login.cy.js +++ b/cypress/e2e/login.cy.js @@ -1,2 +1,111 @@ describe('Login Component', () => { -}) \ No newline at end of file + beforeEach(() => { + // Visit the app before each test + cy.visit('/'); + }); + + it('should display the login form with all required elements', () => { + // Check if the login form is visible + cy.get('.login-form').should('be.visible'); + + // Check if all form elements are present + cy.get('h2').should('contain', 'Login'); + cy.get('label[for="name"]').should('be.visible'); + cy.get('label[for="password"]').should('be.visible'); + cy.get('#name').should('be.visible'); + cy.get('#password').should('be.visible'); + cy.get('.login-button').should('be.visible'); + }); + + it('should show validation errors when submitting empty form', () => { + // Try to submit the form without entering any data + cy.get('.login-button').click(); + + // Check if the form is still visible (not submitted) + cy.get('.login-form').should('be.visible'); + + // Check if the required fields are marked as invalid + cy.get('#name').should('have.attr', 'required'); + cy.get('#password').should('have.attr', 'required'); + }); + + it('should successfully login with valid credentials', () => { + // Enter valid credentials + cy.get('#name').type('testuser'); + cy.get('#password').type('password123'); + + // Submit the form + cy.get('.login-button').click(); + + // Check if we're redirected to the welcome screen + cy.get('.welcome-container').should('be.visible'); + cy.get('.welcome-card h1').should('contain', 'Welcome, testuser!'); + }); + + it('should handle form input correctly', () => { + // Test name input + cy.get('#name') + .type('testuser') + .should('have.value', 'testuser'); + + // Test password input + cy.get('#password') + .type('password123') + .should('have.value', 'password123'); + }); + + it('should logout successfully', () => { + // First login + cy.get('#name').type('testuser'); + cy.get('#password').type('password123'); + cy.get('.login-button').click(); + + // Verify we're on the welcome screen + cy.get('.welcome-container').should('be.visible'); + + // Click logout button + cy.get('.logout-button').click(); + + // Verify we're back to the login form + cy.get('.login-form').should('be.visible'); + cy.get('.welcome-container').should('not.exist'); + }); + + it('should maintain form state when switching between fields', () => { + // Enter data in name field + cy.get('#name').type('testuser'); + + // Switch to password field + cy.get('#password').type('password123'); + + // Verify name field still has the entered value + cy.get('#name').should('have.value', 'testuser'); + }); + + it('should handle special characters in input fields', () => { + // Test special characters in name + cy.get('#name') + .type('test@user#$%') + .should('have.value', 'test@user#$%'); + + // Test special characters in password + cy.get('#password') + .type('pass@word#$%') + .should('have.value', 'pass@word#$%'); + }); + + it('should handle long input values', () => { + // Generate a long string + const longString = 'a'.repeat(100); + + // Test long name + cy.get('#name') + .type(longString) + .should('have.value', longString); + + // Test long password + cy.get('#password') + .type(longString) + .should('have.value', longString); + }); +}); \ No newline at end of file diff --git a/media/Screenshot 2025-05-19 203309.png b/media/Screenshot 2025-05-19 203309.png new file mode 100644 index 0000000..c95d5e0 Binary files /dev/null and b/media/Screenshot 2025-05-19 203309.png differ diff --git a/media/Screenshot 2025-05-19 204045.png b/media/Screenshot 2025-05-19 204045.png new file mode 100644 index 0000000..4c43ec4 Binary files /dev/null and b/media/Screenshot 2025-05-19 204045.png differ diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js index 26c8cc3..a51883e 100644 --- a/src/components/LoginForm.js +++ b/src/components/LoginForm.js @@ -15,9 +15,14 @@ function LoginForm({ onLogin }) { })); }; + const handleSubmit = (e) => { + e.preventDefault(); + onLogin(formData); + }; + return (
-
+

Login