Bayzat Frontend Test - Calculator
Overview
This project is a basic calculator application built using TypeScript and React.JS for the Bayzat Frontend Test assignment. The focus is on demonstrating TypeScript's static typing capabilities, handling JavaScript's calculation quirks, and implementing a clean, maintainable codebase with comprehensive testing.
Live Demo
π Deployed on Vercel: https://bayzat-calculator-jubstaa.vercel.app
Features
β
Core Requirements
- Basic Arithmetic Operations: Addition, subtraction, multiplication, and division
- Complex Expressions: Handles series of operations (e.g., 3 + 2 * 4 - 5) with proper operator precedence
- Edge Case Handling: Addresses JavaScript floating-point precision issues
- Responsive UI: Works seamlessly across desktop, tablet, and mobile devices
- Material-UI Integration: Clean, user-friendly interface using MUI components
π― Bonus Features
- Calculation Display: Shows full expression (e.g., 1 + 3 + 5) before showing result
- Keyboard Support: Full keyboard navigation and input support
- History Tracking: Maintains calculation history for reference
- Error Handling: User-friendly error messages for edge cases
Installation & Local Development
Prerequisites
- Node.js 18+ (or Docker)
- npm or yarn
Setup
Option 1: Local Development
# Clone the repository
git clone https://github.com/Jubstaaa/bayzat-calculator.git
cd calculator
# Install dependencies
npm install
# Start development server
npm run dev
Option 2: Docker (Recommended)
# Clone the repository
git clone https://github.com/Jubstaaa/bayzat-calculator.git
cd calculator
# Build Docker image
docker build -t calculator-app .
# Start development server
docker run -p 5173:5173 -v $(pwd):/app calculator-app
# Or use Docker Compose
docker-compose up app
The application runs at http://localhost:5173
Testing
Unit Tests (Jest)
# Run all unit tests
npm run test
# Run tests with coverage
npm run test:coverage
# Watch mode for development
npm run test:watch
E2E Tests (Cypress)
# Run E2E tests in headless mode
npm run test:e2e
# Open Cypress GUI for interactive testing
npm run cy:open
Note: E2E tests verify the accuracy of calculations and ensure the application's reliability across different scenarios.
Edge Cases Encountered & Solutions
1. JavaScript Floating-Point Precision Issues
Problem: 0.1 + 0.2 resulted in 0.30000000000000004 instead of 0.3
Solution: Implemented rounding to 10 decimal places to avoid floating-point precision issues.
2. Division by Zero Handling
Problem: JavaScript throws Infinity for division by zero, which isn't user-friendly
Solution: Custom error handling with user-friendly "Division by zero is not allowed" message.
3. Large Number Display
Problem: Very large numbers could overflow UI or become unreadable
Solution: Added wordBreak: 'break-all' CSS property to ensure large results wrap properly and remain readable.
4. Trailing Operators
Problem: Expressions ending with operators like 3+ would cause evaluation errors
Solution: Pre-evaluation sanitization that removes trailing operators before parsing.
5. Multiple Decimal Points
Problem: Users could input invalid numbers like 1.2.3
Solution: Input validation that prevents multiple decimal points within the same number.
6. Operator Precedence
Problem: JavaScript's default operator precedence might not match user expectations
Solution: JavaScript Function constructor automatically handles operator precedence correctly (multiplication/division before addition/subtraction).
Testing Approach
Unit Testing Strategy
- Jest Framework: Fast, reliable testing with excellent TypeScript support
- Component Testing: Isolated testing of Calculator component logic
- Utility Testing: Comprehensive testing of evaluation logic
- Edge Case Coverage: 50+ test cases covering all calculation scenarios
E2E Testing Strategy
- Cypress Framework: Real browser testing for authentic user interactions
- Calculation Accuracy: Validates that all arithmetic operations produce correct results
- UI Responsiveness: Ensures calculator works across different screen sizes
- Keyboard Support: Tests full keyboard navigation and input handling
- Error Scenarios: Verifies proper error handling for edge cases
Test Coverage Areas
- β
Basic arithmetic operations (+, -, Γ, Γ·)
- β
Complex expressions with operator precedence
- β
Parentheses handling and nested expressions
- β
Error handling (division by zero, invalid expressions)
- β
UI interactions and keyboard support
- β
Responsive design across devices
CI/CD Pipeline
GitHub Actions Workflow
The project uses GitHub Actions for automated testing, building, and deployment:
Workflow Trigger
- Automatic: On every push to
main branch
- Manual: Can be triggered manually via GitHub Actions tab
Pipeline Stages
π Checkout & Setup
- Repository checkout
- Node.js 20 setup with npm caching
π§ͺ Testing Phase
- Unit Tests: Jest framework with TypeScript support
- E2E Tests: Cypress for browser-based testing
- Development Server: Auto-starts for E2E test environment
ποΈ Build Phase
- TypeScript compilation (
tsc -b)
- Vite production build (
vite build)
- Output:
dist/ folder with optimized assets
π Deployment Phase
- Vercel Deploy Hook: Automatic deployment on successful build
- Environment: Production deployment
- Branch:
main branch only
Workflow File
.github/workflows/deploy.yml
Deployment Process
- Tests pass β Build succeeds β Auto-deploy to Vercel
- Failed tests prevent deployment (quality gate)
- Manual deployment available via GitHub Actions
Benefits
- β
Automated Quality Control: Tests run on every commit
- β
Consistent Deployments: Same process every time
- β
Rollback Capability: Vercel provides deployment history
- β
Team Collaboration: All team members can trigger deployments
- β
Cost Effective: No manual deployment overhead
Code Quality & Maintainability
TypeScript Implementation
- Strict Mode: Full TypeScript strict mode enabled for compile-time error catching
- Static Typing: Comprehensive type definitions for all calculator operations
- Interface Design: Clean interfaces for button definitions and state management
- Error Handling: Typed error handling with enum-based error messages
React Best Practices
- Functional Components: Modern React with hooks (useState, useCallback, useMemo)
- Performance Optimization: Memoized calculations and event handlers
- State Management: Clean state management with proper separation of concerns
- Component Structure: Modular, reusable component architecture
Code Organization
- Separation of Concerns: UI logic separated from calculation logic
- Modular Architecture: Clear separation between components, utilities, and tests
- Consistent Naming: Descriptive variable and function names
- Documentation: Comprehensive inline comments and JSDoc
Tools & Libraries Used
Core Technologies
- TypeScript: Chosen for static typing to catch calculation errors at compile time and improve code maintainability
- React 19: Latest React version for modern hooks and performance optimizations
- Vite: Fast build tool that provides excellent development experience with HMR
UI Framework
- Material-UI (MUI): Selected for consistent, accessible design system and responsive components that work across all devices
- Emotion: CSS-in-JS solution that MUI uses, providing better performance than styled-components
Testing
- Jest: Unit testing framework with excellent TypeScript support
- Cypress: E2E testing for real browser validation of calculator functionality
- eslint-plugin-cypress: Enforces Cypress best practices and prevents anti-patterns
Build & Development
- ESLint: Configured with TypeScript and React rules for code quality
- ts-jest: TypeScript support for Jest testing
Deployment Instructions
Vercel Deployment (Recommended)
Install Vercel CLI:
npm i -g vercel
Build the project:
npm run build
Deploy to Vercel:
vercel --prod
Environment Variables: No additional environment variables required
Alternative: Netlify Deployment
Build the project:
npm run build
Drag and drop the dist folder to Netlify dashboard
Set build command: npm run build
Set publish directory: dist
Improvements If Had More Time
- Memory Functions: Add M+, M-, MR, MC buttons for storing and recalling values
- Scientific Calculator: Implement square root, power, percentage, and trigonometric functions
- History Persistence: Save calculation history to localStorage for persistence across sessions
- Theme Switching: Dark/light mode toggle for better user experience
- Accessibility: Add ARIA labels, screen reader support, and keyboard navigation improvements
- Performance: Implement virtual scrolling for very long calculation histories
- Internationalization: Support for different number formats and locales
- Undo/Redo: Add undo/redo functionality for calculation steps
- Export: Allow users to export calculation history as CSV or PDF
- Mobile Optimization: Touch-friendly interface improvements for mobile devices
Project Structure
src/
βββ components/
β βββ Calculator.tsx # Main calculator component
βββ lib/
β βββ evaluator.ts # Simple calculator engine with enum-based error handling
βββ __tests__/
β βββ evaluator.test.ts # Unit tests for arithmetic logic
βββ assets/ # Static assets
βββ main.tsx # Application entry point
Docker Development
Docker Environment
This project comes with a Docker environment that's fully compatible with GitHub Actions. Using Docker provides:
- Consistent Development Environment: All developers work in the same environment
- GitHub Actions Compatibility: Identical to the environment tested in CI/CD pipeline
- Easy Setup: No need to install Node.js or npm locally
- Isolated Test Environment: All dependencies for Cypress tests included
Docker Services
# Development server
docker-compose up app
# Unit tests
docker-compose run --rm test
# E2E tests
docker-compose run --rm e2e
# Production build
docker-compose run --rm build
Docker Compose Configuration
- app: Development server (port 5173)
- test: Unit test environment
- e2e: E2E test environment (Cypress + Xvfb)
- build: Production build environment
Contributing
This is a take-home assignment for Bayzat Frontend Test. For questions or clarifications, please contact the development team.
License
This project is created for Bayzat Frontend Test assignment purposes.