Why are unit tests important but not a panacea?
A bug found by a unit test costs minutes to fix. The same bug in production costs hours of incident response, compensations, and lost trust. In an online store project, a discount calculation error passed manual testing, went to production, and processed 37 orders at zero price in 4 hours. An automated test for edge cases would have caught it on the first push. With 7+ years in web application testing and over 200 projects delivered, we’ve seen this pattern repeat across industries.
Jest is the standard for JavaScript/TypeScript, but unit tests are justified only where there is isolated logic: transformation functions, validators, business rules, utilities. Testing React components with Jest + Testing Library is correct for behavioral tests: "button appears after loading", "form shows error on empty email". Snapshot tests (toMatchSnapshot) are a trap: they break on any layout change and become noise that developers update without looking. Code coverage is a poor quality metric: 80% coverage can be achieved with tests that check nothing. Coverage shows that code executed, not that it works correctly.
| Criteria | Jest | Vitest |
|---|---|---|
| Speed for large projects | Medium (Babel transformation) | 10–20x faster (ES modules) |
| Integration with Vite | Via plugin | Native |
| Monorepos | Requires configuration | Out of the box |
Vitest as an alternative to Jest for Vite projects: 10–20x faster due to native ES modules without Babel transformation. For monorepos with thousands of tests, the speed difference is noticeable. Wikipedia on unit testing describes the theoretical foundation — we apply it with real CI pipelines.
How to set up E2E tests that are not flaky?
Playwright outperforms Cypress on key parameters: native multi-tab, multi-origin, iframe support; parallel execution at test level; WebKit, Firefox, Chromium out of the box; no iframe for the app — tests run in a real browser.
Playwright codegen records actions and generates a test — a good starting point, but generated code needs refactoring. Locators by text content are fragile: getByRole('button', { name: 'Place order' }) is more robust than locator('.btn-primary').
Page Object Model is the standard for organizing E2E tests. Each page is a separate class with methods instead of direct locators. When a button moves from header to sidebar — change in one place, not across all tests.
Flaky tests typically arise from race conditions between request and render, animations without wait, and dependency on external APIs. Solution: page.waitForResponse() instead of page.waitForTimeout(), mocking external APIs via page.route().
// Bad
await page.click('#submit');
await page.waitForTimeout(2000);
await expect(page.locator('.success')).toBeVisible();
// Good
await page.click('#submit');
await page.waitForResponse(resp =>
resp.url().includes('/api/orders') && resp.status() === 201
);
await expect(page.getByRole('alert', { name: /order created/i })).toBeVisible();
Our engineers guarantee test stability in CI. Playwright’s official documentation covers all API details — we use it daily on projects with millions of users.
How do Core Web Vitals affect ranking?
Google uses Core Web Vitals in ranking. Lighthouse CLI in CI pipeline: on every deploy we check that LCP < 2.5s, CLS < 0.1, INP < 200ms. Google Chrome study: 53% of users leave a site if it takes longer than 3 seconds to load — our tests prevent such losses.
Real problems that Lighthouse finds:
- Hero image without
width/heightattributes: CLS 0.35 on load. - JavaScript bundle 2.1MB synchronously blocking parsing: INP 450ms.
- Fonts without
font-display: swap: invisible text until font loads (FOIT). - Unoptimized hero image 4MB: LCP 8.2s.
Lighthouse CI (lhci) saves metric history and posts a comment to PR with degradation. For one e‑commerce client, optimizing these metrics improved conversion by 18% and reduced server costs by $12k annually.
What does load testing solve?
k6 is a load testing tool with a JavaScript API. Scenarios are written as code, versioned in git, run in CI. Three main scenarios:
- Spike test — sharp load increase: 0 → 1000 users in 30 seconds. Simulates a campaign launch. Shows system's ability to handle spikes.
- Soak test — stable load for 2–4 hours. Detects memory leaks, connection pool exhaustion, performance degradation.
- Stress test — load above expected (150–200% of peak). Shows breaking point and graceful degradation.
Thresholds:
thresholds: {
http_req_duration: ['p95<500', 'p99<1000'],
http_req_failed: ['rate<0.01'],
}
p95 < 500ms means 95% of requests respond faster than half a second. If threshold is not met, k6 exits with error code, CI pipeline fails.
In one online store project, we detected API degradation at the 4th hour of the test: p95 increased from 200ms to 2s due to connection leaks. After optimization, the client saved $15k per year on incident response and extra infrastructure.
Testing pyramid in a project
| Level | Tool | Quantity | Speed |
|---|---|---|---|
| Unit | Vitest/Jest | Many (thousands) | <5 min |
| Integration | Vitest + supertest | Medium | 5–15 min |
| E2E | Playwright | Few (happy path) | 10–30 min |
| Load | k6 | On schedule | 30–60 min |
| Performance | Lighthouse CI | On every deploy | 5 min |
What does the work include?
- Audit of current coverage and identification of critical user flows.
- Writing unit tests for key business logic, integration tests for API, E2E for user scenarios.
- Setting up parallel execution in CI (sharded workers for Playwright).
- Load testing with report and recommendations.
- Test case documentation, training your team on test practices.
- 1-month warranty support after implementation.
- Delivery of all test artefacts (code, CI configs, run histories).
How do we work?
- Analysis — audit of current testing, identification of weak spots, priority setting.
- Design — tool selection, test plan writing, approval.
- Implementation — writing tests, CI integration.
- Testing — running all levels, result analysis, bug fixing.
- Deployment — going live, metric monitoring, team training.
Timeline
Setting up a full test pipeline (Jest + Playwright + k6 + Lighthouse CI) from scratch: 2–4 weeks. E2E test coverage of an existing project (20–30 scenarios): 3–6 weeks. Load testing with report and recommendations: 1–2 weeks. Cost calculated individually after audit.
Ready to discuss your project? Leave a request — we will audit your current web application testing for free and propose a plan that can save up to 60% on incident costs. Get a consultation on web application testing — contact us today.







