Module 9
Unit Testing, Github, Github Portfolio, More App Building
๐ Deploying Your Portfolio to GitHub Pages
What is GitHub Pages?
GitHub Pages is a free static site hosting service provided by GitHub. It allows you to host websites directly from your GitHub repositories. Perfect for portfolios, documentation, and personal projects!
Key Benefits:
- Free Hosting: No cost for hosting your portfolio
- Custom Domain: Use your own domain name (optional)
- Automatic Updates: Your site updates when you push to GitHub
- HTTPS: Secure connections by default
- Easy Setup: Simple configuration process
How to Deploy Your Portfolio
Step 1: Create a GitHub Repository
# Create a new repository on GitHub
# Repository name: yourusername.github.io
# This special name creates a user/organization site
Step 2: Upload Your Portfolio Files
# Clone the repository
git clone https://github.com/yourusername/yourusername.github.io.git
# Add your portfolio files
# - index.html (main page)
# - CSS files
# - JavaScript files
# - Images and other assets
# Commit and push
git add .
git commit -m "Add portfolio files"
git push origin main
Step 3: Enable GitHub Pages
- Go to your repository on GitHub
- Click Settings tab
- Scroll down to Pages section
- Under Source, select Deploy from a branch
- Choose main branch
- Click Save
Step 4: Access Your Site
Your portfolio will be available at: https://yourusername.github.io
Note: It may take a few minutes for your site to be published.
Here is mine if you need to see how it looks on GitHub
Here is the code
The most common errors is not using index.html and also not creating a git repository from the file location.
Repository Structure for GitHub Pages
yourusername.github.io/
โโโ index.html # Main portfolio page
โโโ css/
โ โโโ styles.css # Your styles
โโโ js/
โ โโโ script.js # Your JavaScript
โโโ images/
โ โโโ profile.jpg # Portfolio images
โโโ projects/
โ โโโ project1.html # Project pages
โโโ README.md # Repository description
Important Files:
- index.html: Your main portfolio page (required)
- README.md: Describes your portfolio and projects
- CSS/JS files: Styling and functionality
- Images: Screenshots, logos, profile pictures
Custom Domain (Optional)
Using Your Own Domain
Want to use your own domain like www.yourname.com
?
- Purchase a domain from a domain registrar (GoDaddy, Namecheap, etc.)
- Add a CNAME file to your repository:
# Create a file named 'CNAME' (no extension)
# Add your domain name inside:
www.yourname.com
- Configure DNS with your domain registrar:
# Add these DNS records:
Type: CNAME
Name: www
Value: yourusername.github.io
Type: A
Name: @
Value: 185.199.108.153
Best Practices for Portfolio Deployment
โ
Do's
- Use semantic HTML for better accessibility
- Optimize images for web (compress, use appropriate formats)
- Test your site on different devices and browsers
- Include a contact form or contact information
- Keep your projects updated with recent work
- Use descriptive commit messages
โ Don'ts
- Don't include sensitive information (API keys, passwords)
- Don't use copyrighted images without permission
- Don't forget to test your site after deployment
- Don't ignore mobile responsiveness
- Don't use overly complex animations that slow down the site
UI Test
๐งช Understanding Software Testing
Unit Tests vs Integration Tests
Unit Tests
Unit tests focus on testing individual functions or components in isolation.
// Example: Testing a single function
function add(a, b) {
return a + b;
}
// Unit test
assertEquals(add(2, 3), 5);
assertEquals(add(-1, 1), 0);
Integration Tests
Integration tests verify that multiple components work together correctly.
// Example: Testing user registration flow
function testUserRegistration() {
// Test form validation
const formData = { email: "test@example.com", password: "123456" };
const validation = validateForm(formData);
// Test database connection
const user = saveUserToDatabase(formData);
// Test email sending
const emailSent = sendWelcomeEmail(user.email);
// Integration test - all parts work together
assertTrue(validation && user && emailSent);
}
Frontend vs Backend Testing
Aspect |
Frontend Testing |
Backend Testing |
What to Test |
User interface, user interactions, visual elements, client-side logic |
API endpoints, database operations, business logic, server performance |
Tools |
Jest, Cypress, Playwright, Selenium, React Testing Library |
Jest, Mocha, Supertest, Postman, database testing tools |
Test Types |
Component tests, UI tests, E2E tests, visual regression tests |
API tests, database tests, unit tests, load tests |
Example |
Test if button click shows correct modal |
Test if API returns correct user data |
Frontend Testing Examples
Component Testing (React)
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
test('button shows correct text and handles click', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
fireEvent.click(screen.getByText('Click me'));
expect(handleClick).toHaveBeenCalled();
});
UI Testing (Cypress)
describe('Login Form', () => {
it('should show error for invalid email', () => {
cy.visit('/login');
cy.get('[data-testid=email]').type('invalid-email');
cy.get('[data-testid=submit]').click();
cy.get('[data-testid=error]').should('contain', 'Invalid email');
});
});
Backend Testing Examples
API Testing (Node.js/Express)
const request = require('supertest');
const app = require('./app');
describe('User API', () => {
test('GET /api/users returns user list', async () => {
const response = await request(app)
.get('/api/users')
.expect(200);
expect(response.body).toHaveProperty('users');
expect(Array.isArray(response.body.users)).toBe(true);
});
});
Database Testing
describe('User Model', () => {
test('should create user with valid data', async () => {
const userData = {
email: 'test@example.com',
name: 'Test User'
};
const user = await User.create(userData);
expect(user.email).toBe(userData.email);
expect(user.name).toBe(userData.name);
});
});
Testing Best Practices
- Test Pyramid: Many unit tests, fewer integration tests, even fewer E2E tests
- Arrange-Act-Assert: Structure your tests clearly
- Test Isolation: Each test should be independent
- Meaningful Names: Test names should describe what they're testing
- Mock External Dependencies: Don't test third-party services
- Test Edge Cases: Don't just test the happy path
๐งฉ Arrange-Act-Assert Pattern (AAA)
The Arrange-Act-Assert pattern is a fundamental testing structure that makes tests clear, readable, and maintainable. It divides every test into three distinct sections:
1. Arrange - Set Up Your Test Data
This is where you prepare everything needed for your test. Think of it as "getting ready."
// ARRANGE - Set up test data and conditions
const user = {
name: "John Doe",
email: "john@example.com",
age: 25
};
const expectedResult = "Hello, John Doe!";
2. Act - Execute the Code Being Tested
This is where you actually call the function or perform the action you want to test.
// ACT - Call the function we're testing
const result = greetUser(user.name);
3. Assert - Verify the Results
This is where you check if the result matches what you expected.
// ASSERT - Check if the result is correct
expect(result).toBe(expectedResult);
Complete Example
describe('User Greeting', () => {
test('should greet user with their name', () => {
// ARRANGE
const user = { name: "Alice", email: "alice@example.com" };
const expectedGreeting = "Hello, Alice!";
// ACT
const actualGreeting = createGreeting(user.name);
// ASSERT
expect(actualGreeting).toBe(expectedGreeting);
});
});
Why Use Arrange-Act-Assert?
๐ฏ Benefits
- Clarity: Anyone reading the test immediately understands what's being tested
- Consistency: All tests follow the same structure, making them easier to maintain
- Debugging: When a test fails, you know exactly which part failed (setup, execution, or verification)
- Documentation: Tests serve as living documentation of how your code should work
๐ซ Common Anti-Patterns to Avoid
// BAD: Mixed concerns, hard to read
test('user test', () => {
const user = { name: "Bob" };
const result = greetUser(user.name);
expect(result).toBe("Hello, Bob!");
const user2 = { name: "Alice" };
const result2 = greetUser(user2.name);
expect(result2).toBe("Hello, Alice!");
});
// GOOD: Clear AAA structure
test('should greet Bob correctly', () => {
// ARRANGE
const user = { name: "Bob" };
const expected = "Hello, Bob!";
// ACT
const result = greetUser(user.name);
// ASSERT
expect(result).toBe(expected);
});
test('should greet Alice correctly', () => {
// ARRANGE
const user = { name: "Alice" };
const expected = "Hello, Alice!";
// ACT
const result = greetUser(user.name);
// ASSERT
expect(result).toBe(expected);
});
Real-World AAA Examples
Frontend Component Test
test('button should show loading state when clicked', () => {
// ARRANGE
const mockOnClick = jest.fn();
render(<Button onClick={mockOnClick}>Submit</Button>);
const button = screen.getByText('Submit');
// ACT
fireEvent.click(button);
// ASSERT
expect(button).toHaveTextContent('Loading...');
expect(mockOnClick).toHaveBeenCalledTimes(1);
});
Backend API Test
test('POST /api/users should create new user', async () => {
// ARRANGE
const userData = {
name: 'Jane Smith',
email: 'jane@example.com'
};
const expectedResponse = {
id: expect.any(Number),
name: userData.name,
email: userData.email
};
// ACT
const response = await request(app)
.post('/api/users')
.send(userData);
// ASSERT
expect(response.status).toBe(201);
expect(response.body).toMatchObject(expectedResponse);
});
Database Test
test('should save user to database', async () => {
// ARRANGE
const userData = {
name: 'Test User',
email: 'test@example.com'
};
// ACT
const savedUser = await User.create(userData);
// ASSERT
expect(savedUser.id).toBeDefined();
expect(savedUser.name).toBe(userData.name);
expect(savedUser.email).toBe(userData.email);
});
AAA in Different Testing Scenarios
Test Type |
Arrange |
Act |
Assert |
Unit Test |
Create test data, mock dependencies |
Call the function |
Check return value |
Integration Test |
Set up database, create test records |
Call API endpoint |
Verify database state and response |
UI Test |
Navigate to page, set up test data |
Click buttons, fill forms |
Check DOM changes, verify state |
E2E Test |
Start application, prepare test environment |
Perform user actions |
Verify complete user journey |