Hardening Sprint:
Edge Cases & Stress Testing
Break your app on purpose. Find every edge case, every failure point, every crash. Then fix them all before tomorrow's final presentations.
Goal: Break It, Then Fix It
Your app works for the "happy path" (the ideal user doing exactly what you expect). But real users are unpredictable: they paste emojis into search boxes, they have terrible internet, and they click buttons 47 times in a row.
Today's Mission
- Systematically test every feature of your application
- Try to break it with weird inputs, slow connections, and invalid API keys
- Log every failure in a structured testing log
- Fix the critical bugs before tomorrow's presentations
Today's Sprint: Apply to Your Project
Test your specific project pipeline end-to-end: from satellite data ingestion to AI analysis to dashboard output.
The Chaos Engineering Mindset
Chaos engineering is the discipline of experimenting on a system to build confidence in its ability to withstand turbulent conditions in production.2 For your project, this means deliberately causing failures to discover weaknesses before your users (or your instructor) do.
Three Principles for Today
Hypothesize Failure Modes
Before you test, ask: "What could go wrong?" List every scenario: empty inputs, network timeouts, invalid API keys, browser differences, and mobile screens.
Introduce Controlled Failures
Use Chrome DevTools throttling to simulate slow networks. Pass intentionally bad data. Revoke API keys. Test on your phone.
Observe, Record, Fix
Document what happened. Was there a graceful error message? Did the app crash? Fix the worst issues first, using a triage approach: critical bugs before cosmetic ones.
Step 1: The Happy Path Test
Start with the baseline: does the core feature work end-to-end when everything goes perfectly?
What to verify
- Open your deployed GitHub Pages URL (not localhost!)
- Enter a normal, expected query into your AI chat
- Verify the AI response appears correctly and is relevant
- Check that the map loads and displays data properly
- Click every button, link, and interactive element once
- Verify the entire flow from landing to final output
Common Happy Path Failures
- API key is hardcoded but expired or rate-limited
- Map tiles fail to load due to CORS or missing attribution
- JavaScript errors prevent the page from loading at all (check the Console!)
- CSS file path is wrong after deploying to GitHub Pages
Step 2 & 3: Edge Cases & Network Stress
Edge Case Inputs to Try
- Empty string: submit with nothing typed
- Very long text: paste 5,000 characters
- Special characters:
<script>alert('xss')</script> - Emojis: 🌎🌍🛰 as input
- Numbers only: "12345678"
- SQL injection attempt:
'; DROP TABLE users;-- - Rapid repeated clicks: click submit 20 times fast
- Non-English text: Arabic, Chinese, or Cyrillic characters
Network Stress Tests
Open Chrome DevTools (F12), go to the Network tab:
- Slow 3G: simulates 2,000ms RTT latency, ~400 kbps throughput
- Offline: toggle the "Offline" checkbox
- Custom throttle: create a profile with 2G speeds
Step 5: Cross-Browser
Test on at least two different browsers (Chrome + Firefox or Safari). CSS features like backdrop-filter may behave differently.
Step 4: API Failure Simulation
What happens when external services fail? Your Gemini API call, your map tile provider, your satellite data source: any of these can go down at any time.3
Tests to Run
Invalid API Key
Temporarily change your Gemini API key to "INVALID_KEY_12345". Does your app show a helpful error, or does it silently fail?
Rate Limit Exceeded
Send 20 rapid requests. The free Gemini API tier has rate limits. Does your app handle 429 "Too Many Requests" responses gracefully?
Malformed API Response
What if the AI returns an unexpected format? Does your code use try/catch around JSON parsing?
CORS Errors on Deployment
Some API calls that work on localhost fail when deployed to GitHub Pages due to CORS restrictions. Always test the deployed version.
Testing Log Template
Use this structured template to record every test you run. Copy it into a Google Doc or a Markdown file in your repo. This becomes evidence of your testing process.
| Feature | Input / Action | Expected Result | Actual Result | Status |
|---|---|---|---|---|
| AI Chat | Ask "What is NDVI?" | Correct explanation appears | Response shows in chat | ✔ PASS |
| AI Chat | Submit empty string | Error or placeholder message | API returns 400 error, no UI feedback | ✘ FAIL |
| Map | Zoom to max level | Tiles load smoothly | Grey tiles appear | ✘ FAIL |
| Map | Click marker | Popup with info appears | Popup displays correctly | ✔ PASS |
| Mobile | Open on iPhone Safari | Layout adapts, all features work | Chat input hidden by keyboard | ✘ FAIL |
Adding Debug Logging
Console logging is your best friend during testing. Use a structured logging wrapper so you can easily turn debug output on and off, and so every log message has a category tag for quick filtering.
// Debug logging wrapper // Set to false before final deployment to silence logs const DEBUG = true; function log(category, message, data) { if (DEBUG) { console.log(`[${category}] ${message}`, data || ''); } } // Usage examples: log('AI', 'Sending prompt', { prompt, model: 'gemini-2.0-flash' }); log('MAP', 'Adding marker', { lat, lng }); log('ERROR', 'API call failed', { status, error }); log('UI', 'Button clicked', { buttonId: 'send-btn' }); log('NETWORK', 'Fetch started', { url });
[ERROR] to see only error logs. This makes debugging much faster when you have many log entries.DEBUG = false to prevent console noise for end users. Never log sensitive data like full API keys.Issue: API Response Takes Too Long
AbortController API to set a maximum wait time, and show a visual loading indicator while the request is in progress.// Show loading state const sendBtn = document.getElementById('send-btn'); sendBtn.disabled = true; sendBtn.textContent = 'Thinking...'; // Set up a 15-second timeout using AbortController const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 15000); try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), signal: controller.signal }); const data = await response.json(); // Handle successful response... } catch (err) { if (err.name === 'AbortError') { showError('Request timed out. Please try again.'); } else { showError('Something went wrong: ' + err.message); } } finally { clearTimeout(timeout); sendBtn.disabled = false; sendBtn.textContent = 'Send'; }
AbortController is a native browser API (no library needed). The finally block ensures the button is always re-enabled, whether the request succeeded, failed, or timed out.4Issues: Map Markers & Chat Scrolling
// Track all markers in an array const markers = []; function addMarker(lat, lng, label) { const m = L.marker([lat, lng]) .addTo(map) .bindPopup(label); markers.push(m); } function clearMarkers() { markers.forEach(m => map.removeLayer(m) ); markers.length = 0; } // Call clearMarkers() before adding // new results from a fresh query
// Auto-scroll chat to bottom function scrollToBottom() { const container = document .getElementById('chat-messages'); container.scrollTop = container.scrollHeight; } // Call after adding every message function addMessage(text, sender) { const div = document .createElement('div'); div.className = `message ${sender}`; div.textContent = text; container.appendChild(div); scrollToBottom(); }
Issue: App Crashes on Mobile
The Essential Mobile Fix
First, make sure your HTML <head> includes the viewport meta tag. Without it, mobile browsers render the page at desktop width and then scale it down.
<!-- This MUST be in your <head> --> <meta name="viewport" content="width=device-width, initial-scale=1.0">
Responsive CSS Essentials
/* Stack columns on small screens */ @media (max-width: 768px) { .app-layout { grid-template-columns: 1fr; /* single column */ grid-template-rows: auto 1fr auto; } .sidebar { display: none; /* hide on mobile */ } .chat-input { font-size: 16px; /* prevents iOS zoom on focus */ } /* Make tap targets at least 44x44pt (Apple HIG); 1pt = 1px at 1x density */ button, .clickable { min-height: 44px; min-width: 44px; } }
Knowledge Check: Testing & Debugging
1. You set a 15-second timeout using AbortController, but the API responds in 3 seconds. What happens to the timeout?
finally block calls clearTimeout(), cancelling the pending timer
finally block runs whether the fetch succeeds or fails, and it calls clearTimeout() to cancel the pending timer. Without this cleanup, the timer would still fire (option A), though it would not cause a crash since the controller's signal is already used.finally block: it always runs and calls clearTimeout(timeout), which cancels the timer before it fires. The browser does not cancel timers automatically.2. What CSS property value prevents iOS Safari from auto-zooming when a user taps on a text input?
zoom: none
font-size: 16px (or larger)
touch-action: none
user-scalable=no in the viewport meta
user-scalable=no also prevents zoom, it is an accessibility anti-pattern because it blocks intentional pinch-zoom.font-size: 16px. iOS Safari zooms in on inputs with a font-size smaller than 16px. Setting it to 16px or larger prevents this auto-zoom without sacrificing accessibility.Automating the Chaos (CI/CD Basics)
In enterprise projects like TERRA, manual testing is not enough. You cannot rely on developers to manually run every test before deploying. You need Continuous Integration and Continuous Deployment (CI/CD).
What is CI/CD?
- Continuous Integration (CI): Every time you push code to GitHub, an automated server runs your tests and checks for errors. If it fails, the code is blocked from merging.
- Continuous Deployment (CD): If all tests pass, the code is automatically deployed to the live server (like GitHub Pages).
GitHub Actions Pipeline
We use GitHub Actions to build our CI/CD pipeline. It uses YAML files to define automated jobs.
The Enterprise Starter Workflow
We have provided a starter template for your project. Copy it to .github/workflows/main.yml in your repository.
# A simplified look at what the pipeline does: jobs: lint-and-scan: # 1. Runs your tests and checks for syntax errors build: # 2. Builds your application bundle if tests pass deploy: # 3. Automatically deploys to GitHub Pages
Security Scanning & Code Quality
Real-world applications have strict security constraints. A pipeline doesn't just test if the code works, it tests if the code is safe.
- Static Analysis (Linting): Tools check your code against formatting rules and catch common errors before they run.
- Dependency Scanning (Dependabot): Automatically checks if any libraries you use have known vulnerabilities.
- CodeQL: A semantic code analysis engine that finds security vulnerabilities in your codebase.
Quality Checklist Before Final Presentations
Go through every item on this list. Click to check off items as you verify them. Every checked box is one less thing that can go wrong during your presentation tomorrow.
- Core feature works end-to-end on the deployed URL
- Error messages are user-friendly (not raw stack traces)
- Loading states are visible (spinners, disabled buttons, "Thinking..." text)
- App works on mobile (viewport meta tag, responsive CSS)
- No console errors in the browser Developer Tools
- All navigation links and buttons work correctly
- Deployed to GitHub Pages and the live URL loads correctly
- Map loads with correct tile layer and attribution
- API key is valid and not exceeding rate limits
- Tested on at least two different browsers
- Empty and edge-case inputs are handled gracefully
- README.md is up to date with project description and screenshots
Knowledge Check: Hardening Best Practices
3. Your app makes an API call, but you forgot to wrap it in try/catch. The API returns a 500 error. What happens in the browser?
response.ok manually
response.ok or response.status to detect server errors. This is a very common source of bugs!4response.ok to detect server errors.Summary of Big Ideas
Glossary & References
Glossary of Key Terms
References
- [1] Basiri, A., et al. (2016). "Chaos Engineering." IEEE Software, 33(3), 35-41. doi:10.1109/MS.2016.60
- [2] Rosenthal, C., & Jones, N. (2020). Chaos Engineering: System Resiliency in Practice. O'Reilly Media. O'Reilly
- [3] Google. (2026). "Gemini API: Error Handling." Google AI for Developers. ai.google.dev
- [4] MDN Web Docs. (2026). "AbortController." Mozilla Developer Network. developer.mozilla.org
- [5] Google Chrome Developers. (2026). "Simulate Mobile Devices with Device Mode." Chrome DevTools. developer.chrome.com
- [6] MDN Web Docs. (2026). "Using the Fetch API." Mozilla Developer Network. developer.mozilla.org
- [7] Apple. (2026). "Human Interface Guidelines: Tap Targets." Apple Developer. developer.apple.com
Kent Beck
Software Engineering Visionary
Kent Beck created Test-Driven Development (TDD) and Extreme Programming (XP), two practices that transformed how software teams build reliable code. His philosophy of 'make it work, make it right, make it fast' remains a guiding principle for developers worldwide.
Global Data, Local Impact
Applying EO to Community Challenges
Earth Observation provides a macroscopic view of environmental trends, but its true power lies in downscaling this data to affect local policy and design, such as urban planning and sustainable workplaces.
Regional Decisions Scenario
Scenario: Sustainable Workspace Siting
Your startup needs to establish a new hybrid work hub. You must balance employee commute times, environmental impact (using the IPAT equation), and existing green infrastructure.
Your Task:
- Identify 3 potential sites using EO vegetation indices.
- Calculate the estimated carbon footprint of hybrid commuting.
- Propose a Placemaking strategy for the hub.
Big Ideas & Glossary
Summary of Big Ideas
- Data is only as valuable as its application.
- Space technology has direct terrestrial benefits.
Glossary of Terms
Auto-Graded Quiz
π Daily Reflection
What was your biggest takeaway from this session, and how does it apply to the TERRA project? Write your response below. Your instructor will review this to track your progress.