<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/my-experience-writing-automated-tests-for-a-spa-xevl2tw5c" -->

---
title: My experience writing automated tests for a SPA | daily.dev
description: A developer shares detailed notes on building an automated test suite for Réécoute, a React-based single-page audio player app. The suite uses Playwright...
canonical: https://daily.dev/posts/my-experience-writing-automated-tests-for-a-spa-xevl2tw5c
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: My experience writing automated tests for a SPA | daily.dev
og:description: A developer shares detailed notes on building an automated test suite for Réécoute, a React-based single-page audio player app. The suite uses Playwright...
og:url: https://daily.dev/posts/my-experience-writing-automated-tests-for-a-spa-xevl2tw5c
og:image: https://api.daily.dev/og/posts/xeVL2tw5C.png
og:image:alt: My experience writing automated tests for a SPA
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# My experience writing automated tests for a SPA

**[Lobsters](https://daily.dev/sources/lobsters)** · 9 min read · 0 upvotes · 0 comments

## Summary

A developer shares detailed notes on building an automated test suite for Réécoute, a React-based single-page audio player app. The suite uses Playwright against a real browser rather than mocking the frontend, testing full user journeys end-to-end. Key decisions covered: no isolated test environments (tests share a database and never clean up), custom mocks for external services (S3, Stripe, Twilio) plus test-only API routes for emails and passkeys, running only Chromium for speed, using fullyParallel mode, and a retries:2 CI setting to handle flakiness. Also discusses a hydration bug where inputs are disabled until React is ready, a Docker/socat setup for running headless Chromium in CI, and tricks like simulating mouse drag gestures and reading OTP codes via a test-only email API.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://reecoute.fr/tech_blog/2026-09-28_my-experience-writing-automated-tests-for-a-spa>

## Questions this post answers

### How can I test a React single-page app end-to-end without mocking the backend?

Run tests against the whole stack using a real web browser with Playwright rather than isolating frontend and backend. One approach uses shared test data with no database transactions or cleanup between tests, helper functions to create objects like users and sessions, and global realistic mocks only for genuinely external services like S3, Stripe, and Twilio.

_Developers weighing full-stack test strategies for their SPA can dig deeper into approaches like this on daily.dev._

### How do I prevent a hydration bug where user input is lost before React initializes on a server-rendered page with client-side JavaScript?

Disable form inputs by default and only enable them once the React component mounts, using a small useReady hook that sets a ready flag inside useEffect via setTimeout. This ensures a testing tool like Playwright, or a real user, waits until the input is actually enabled before typing, avoiding edits being silently dropped during hydration.

_Teams debugging SSR hydration timing issues can find practical fixes like this through daily.dev._

### How can I make a Playwright test suite faster and more reliable in CI?

Enable fullyParallel so tests within the same file run concurrently, restrict the browser matrix to Chromium only instead of the default 3-4 browsers (yielding 3-4x speedup with minimal loss of coverage), and set the retries option to 2 in CI so flaky failures are retried individually rather than failing the whole run.

_Anyone tuning Playwright CI speed and flakiness can explore configuration tips like these via daily.dev._

## Community take

How the wider developer community reacted, aggregated from 2 discussions and 12 comments across lobsters, hackernews (as of 2026-09-30).

**TL;DR:** Developers largely praised the approach of never cleaning up test data and testing against a real shared environment, while raising practical concerns about data conflicts, load-testing conflation, flaky end-to-end tests, and production-like test user management.

**Sentiment:** 55% positive · 40% mixed · 5% skeptical

**The case for**

- Not cleaning up test data lets you inspect the full system state (including the DB) when a test fails.
- Creating fresh, self-contained data per test enabled massive parallelization in a similar setup someone tried before.
- This approach is seen as a reasonable tradeoff for a young, small project.

**The pushback**

- Reusing a shared environment for both testing and load-testing is considered an old code smell.
- Avoiding conflicts with existing data is harder than avoiding reliance on it, especially as an app grows more social.
- End-to-end browser tests are inherently nondeterministic, so flakiness can't just be fixed later without addressing root causes.
- Managing test user accounts/credentials that persist alongside real data raises liability concerns.

**By community**

- lobsters (mixed): Mostly appreciative of the no-cleanup, real-browser testing philosophy, but with substantive pushback on data conflicts, load-testing conflation, flakiness, and test-user data management.
- hackernews (mixed): No comments were available to gauge sentiment.

**Hottest debate:** Whether letting test data 'just accumulate' in a shared environment is a pragmatic strength or a liability once data conflicts, load-testing conflation, and lingering test user accounts are considered.

**Open questions**

- What data actually accumulates, and are user accounts/credentials included among it?
- Is there a well-known login for test users, and how are those credentials stored?
- Are you still testing the same things a year later that you were testing on day one?
- What's the concrete plan for eliminating test flakiness given the inherent nondeterminism of end-to-end browser tests?

**Highlights**

> Fantastic approach. I did something similar at a previous gig. Never cleaning up, being robust to existing server state, and generating fresh data for each specific test case also helped us, as in this case, to [massively parallelize our test suite](https://medium.com/whatnot-engineering/running-all-the-tests-at-once-we-can-do-it-5b297f60f5e9). > Basically, I write tests just like anyone would use the app in production: each test creates its own objects without relying on any existing data, never touches data it did not create, and never cleans up anything. Data just accumulates. This strategy works really well for apps like Réécoute, where nothing is actually public. This is my love language ;) Also regarding the discussion of fakes: a lot of people complain about singleton fakes, due to the fact that they won't reflect changes in the real behavior of downstream systems (until you, the developer, become aware of them). That, and the concern about run-times (where it seems playwright parallelization helps a lot) are a common push-back that I get when I adopt this testing approach. (I touch on this a bit in the linked blog post). META: I wrote up a longer comment previously but got stuck on an Anubis page that wouldn't progress (no bar, no nothing). Clicking 'back' took me back to the lobsters main page. Something is busted, it seems.
> — [pzel on lobsters · 2 points, 2 comments](https://lobste.rs/s/vlywx2/my_experience_writing_automated_tests#c_tkd5qg)

> > each test creates its own objects without relying on any existing data, never touches data it did not create, and never cleans up anything. Data just accumulates. I don't get this from my experience. At my current job the dev team set up the QA server that way and stuck us with it because "it doubles as load-testing" (which is such an old code smell I felt nostalgic when I heard it) and I feel like "without relying on any existing data" is great, but "without running into conflicts with existing data" is the harder part. I also wonder if you're testing the same thing a year later that you were on day one.
> — [tclancy on lobsters · 1 points, 2 comments](https://lobste.rs/s/vlywx2/my_experience_writing_automated_tests#c_pnmm8n)

> > I could probably eliminate flakes entirely if I spent a few hours on it, but I’m not sure it's worth the effort right now. What’s your plan for eliminating flakes? End to end browser applications are inherently nondeterministic. There are no ways to get around that. It’s not an “I’ll figure it out later” thing. There’s no solution out there, other than solving the problem at its root. Look into what [Antithesis is doing if you want to know what that looks like](https://antithesis.com/blog/deterministic_hypervisor/?utm_source=adwords&utm_medium=ppc&utm_campaign=42+%7C+ATS+%7C+SEARCH+%7C+BRAND&utm_term=antithesis+testing&_gl=1*14wn56p*_up*MQ..*_gs*MQ..&gclid=CjwKCAjww-3VBhAcEiwAwUUIu5lGGS1YHar-JbOQ4pal_-qlPkz_RRHPh3Dw9WU2JK5sKrISgcufWxoC2A0QAvD_BwE&gbraid=0AAAAA9ytAD8qPNOgDHmv676k6hmNL7eXW). It’s that or start mocking out half of the universe so you can do deterministic simulation testing.
> — [amw-zero on lobsters · 1 points](https://lobste.rs/s/vlywx2/my_experience_writing_automated_tests#c_8jyrzb)

> > Basically, I write tests just like anyone would use the app in production: each test creates its own objects without relying on any existing data, never touches data it did not create, and never cleans up anything. Data just accumulates. This strategy works really well for apps like Réécoute, where nothing is actually public. What data actually accumulates? Are user accounts/credentials among the accumulating data? Do you have a well-known login for test users, and how do you store the creds? Or do users just pile up in production too? I haven't found a strategy I like for automatically authenticating against a production system, and leaving test users strewn around feels like a liability.
> — [coby on lobsters · 1 points](https://lobste.rs/s/vlywx2/my_experience_writing_automated_tests#c_3qrbhi)

> Great writeup, we need more blogs on writing actual end-to-end tests practically. I did go hard on end-to-end tests for a personal project a few years back, where I initially started with standing up the whole stack via docker-compose but sadly it did not scale. Then I replaced the whole thing with [Testing Without Mocks](https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks), but I was inexperienced in this methodology so I may not have followed it in spirit. Right now at work we're exploring [Fakes](https://pierrezemb.fr/posts/why-fakes-beat-mocks-and-testcontainers/) extensively. It's very similar to global mocks, but with contract tests to keep mocks honest. I plan to write on this once it's a bit more widespread, but the theory is solid IMO. My main takeaway is that the testing story may not be perfect, but it's better than pushing code obliviously, or manually testing until you're bored to death.
> — [frontsideair on lobsters · 1 points](https://lobste.rs/s/vlywx2/my_experience_writing_automated_tests#c_tt9brn)

**Source threads**

- [lobsters](https://lobste.rs/s/vlywx2/my_experience_writing_automated_tests) · 37 points · 12 comments
- [hackernews](https://news.ycombinator.com/item?id=49890167) · 2 points · 0 comments

## Similar posts on daily.dev

- [Playwright for WordPress: A Practical Guide to Automating End-to-End Tests](https://daily.dev/posts/playwright-for-wordpress-a-practical-guide-to-automating-end-to-end-tests-kgz1psqyv) · Software Testing Magazine · 1 upvotes · 0 comments
- [Software Testing with Playwright](https://daily.dev/posts/software-testing-with-playwright-lpwkoin9d) · freeCodeCamp · 6 upvotes · 0 comments
- [Migrating from Enzyme to Playwright: How We Modernized Frontend Testing at Agoda](https://daily.dev/posts/migrating-from-enzyme-to-playwright-how-we-modernized-frontend-testing-at-agoda-asbkezb4t) · agoda · 1 upvotes · 0 comments
- [Test Automation Structure for Single Code Base Projects](https://daily.dev/posts/test-automation-structure-for-single-code-base-projects-l4yfzv1rh) · Trendyol Tech · 83 upvotes · 1 comments

---

Tags: [#webdev](https://daily.dev/tags/webdev), [#react](https://daily.dev/tags/react), [#testing](https://daily.dev/tags/testing)

[View this post on daily.dev](https://daily.dev/posts/my-experience-writing-automated-tests-for-a-spa-xevl2tw5c)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"My experience writing automated tests for a SPA","url":"https://daily.dev/posts/my-experience-writing-automated-tests-for-a-spa-xevl2tw5c","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/my-experience-writing-automated-tests-for-a-spa-xevl2tw5c"},"datePublished":"2026-09-29T17:11:07.715Z","dateModified":"2026-09-30T09:12:54.867Z","description":"A developer shares detailed notes on building an automated test suite for Réécoute, a React-based single-page audio player app. The suite uses Playwright...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/879f2680be6dad791cc7aa79b1e750b9?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/879f2680be6dad791cc7aa79b1e750b9?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/my-experience-writing-automated-tests-for-a-spa-xevl2tw5c","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"webdev,react,testing","timeRequired":"PT9M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"My experience writing automated tests for a SPA"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/my-experience-writing-automated-tests-for-a-spa-xevl2tw5c#faq","mainEntity":[{"@type":"Question","name":"How can I test a React single-page app end-to-end without mocking the backend?","acceptedAnswer":{"@type":"Answer","text":"Run tests against the whole stack using a real web browser with Playwright rather than isolating frontend and backend. One approach uses shared test data with no database transactions or cleanup between tests, helper functions to create objects like users and sessions, and global realistic mocks only for genuinely external services like S3, Stripe, and Twilio. Developers weighing full-stack test strategies for their SPA can dig deeper into approaches like this on daily.dev."}},{"@type":"Question","name":"How do I prevent a hydration bug where user input is lost before React initializes on a server-rendered page with client-side JavaScript?","acceptedAnswer":{"@type":"Answer","text":"Disable form inputs by default and only enable them once the React component mounts, using a small useReady hook that sets a ready flag inside useEffect via setTimeout. This ensures a testing tool like Playwright, or a real user, waits until the input is actually enabled before typing, avoiding edits being silently dropped during hydration. Teams debugging SSR hydration timing issues can find practical fixes like this through daily.dev."}},{"@type":"Question","name":"How can I make a Playwright test suite faster and more reliable in CI?","acceptedAnswer":{"@type":"Answer","text":"Enable fullyParallel so tests within the same file run concurrently, restrict the browser matrix to Chromium only instead of the default 3-4 browsers (yielding 3-4x speedup with minimal loss of coverage), and set the retries option to 2 in CI so flaky failures are retried individually rather than failing the whole run. Anyone tuning Playwright CI speed and flakiness can explore configuration tips like these via daily.dev."}}]}
```

