After Lab 3.2 — Recap
After Lab 3.2 — Recap
You added type checking and automated tests to the pipeline and saw how fast checks prevent broken builds from deploying.
What You Should Understand
The Test Pyramid in Practice
Your pipeline now runs:
- Type checking (seconds): Catches type errors without executing code
- Unit tests (seconds): Tests functions in isolation (config validation, route logic)
- Integration tests (10-30 seconds): Test complete paths not just individual units
Why this order?: Fail fast. If TypeScript compilation fails in 3 seconds, don't waste 30 seconds running integration tests.
E2E Tests
Critical user journeys across the entire system
Integration Tests
Verify component interactions and data flow
Unit Tests
Fast, isolated testing of individual components
Quality Gates Before Security Scans
Principle: Run cheapest, fastest checks first. No point scanning dependencies if the code doesn't compile.
Reflection Questions
Why run type checking separately instead of just running `npm test` which also type-checks?
Speed and clarity:
tsc --noEmitruns in ~3 seconds and only checks typesnpm testruns tests (slower) and may hide type errors in passing test output
Running typecheck as a separate step provides immediate feedback on type errors before running tests. In CI logs, you see exactly what failed.
What happens if you have 1,000 unit tests and 10 integration tests, all passing, but no type checking?
False confidence: Tests may pass with runtime values but still have type safety holes:
// No type error in tests, but unsafe
function getUserAge(user: any): number {
return user.age; // Runtime error if user.age is undefined
}
// Tests pass because mock has .age
test('returns user age', () => {
expect(getUserAge({ age: 25 })).toBe(25);
});TypeScript would catch user: any (should be User interface). Tests only validate the cases you wrote, not all possible inputs.
Should integration tests run before or after deployment to dev?
Both:
- Pre-deployment integration tests (Lab 3.2): Test app in isolated pipeline environment (no external dependencies) — verifies code works in principle
- Post-deployment smoke tests (Lab 3.5): Test app in real dev environment (with database, Key Vault, networking) — verifies code works in practice
Pre-deployment tests are faster and catch obvious issues. Post-deployment tests validate the deployed environment.
Small Bonus
Check the Test Plans and you will see that Azure DevOps can integrate test reports directly into the portal! Pretty cool.
Common Issues
| Issue | Symptom | Cause | Fix |
|---|---|---|---|
| Type check fails in pipeline but not locally | tsc errors in CI, not on dev machine | Different TypeScript versions or tsconfig.json | Pin TypeScript version in package.json, commit tsconfig.json |
| Integration tests timeout | Tests hang after 30 seconds | Server not closing after tests, port conflict | Use server.close() in test teardown, assign random port |
| Tests pass locally, fail in pipeline | Different environment (env vars, file paths) | Missing .env file, hardcoded paths | Use process.env with defaults, avoid absolute paths |
| Tests run twice (once in Validate, once in Build) | Wasted time | Duplicate npm test script call | Remove npm test from Build stage, only in Validate |
Bridge to Lab 3.3
Your code compiles and passes tests. Now we scan it for security vulnerabilities — hardcoded secrets, SQL injection risks, vulnerable dependencies.