Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 74 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,98 +1,112 @@
# 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 <your-forked-repo-url>
```
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
│ ├── App.js
│ └── 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.
111 changes: 110 additions & 1 deletion cypress/e2e/login.cy.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,111 @@
describe('Login Component', () => {
})
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);
});
});
Binary file added media/Screenshot 2025-05-19 203309.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/Screenshot 2025-05-19 204045.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion src/components/LoginForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ function LoginForm({ onLogin }) {
}));
};

const handleSubmit = (e) => {
e.preventDefault();
onLogin(formData);
};

return (
<div className="login-form-container">
<form className="login-form">
<form className="login-form" onSubmit={handleSubmit}>
<h2>Login</h2>
<div className="form-group">
<label htmlFor="name">Name:</label>
Expand Down