Why We Replaced the Testing Suite
Background
The testing/ submodule was inherited from the third-party handover (Elevare Group → MWE). It arrived as a working Cypress/Cucumber setup but was written for the specific state of the codebase at handover time — with selectors, credentials, and assumptions baked in that were never documented.
Starting in April 2026, we began running the existing suite against the live development environment and immediately hit a cascade of failures. Debugging those failures revealed structural problems that made patching the existing suite more expensive than replacing it.
What Was Wrong With testing/
1. Fragile CSS class selectors throughout
Chakra UI generates stable-looking but build-time-deterministic class names (e.g. css-6q9ebm, css-1sggvv9, css-18lxp4n). These classes are derived from the component tree and change whenever the tree changes — a dependency update, a new import, or a layout restructure is enough to break them.
The existing page objects were full of these classes:
roleTitle: () => cy.get('p.chakra-text.css-6q9ebm'), // breaks on any Chakra upgrade
canvaElement: () => cy.get('.css-1sggvv9'), // breaks on any layout change
canvaElementSign: () => cy.get('.css-18lxp4n'), // happened to be the "Clear" buttonWhen a test failed, the first question was always "did the selector break, or did the feature break?" That's the wrong question to be asking.
2. Captcha bypass was never wired correctly
The Django serializer used allow_blank=False on the captcha_token field (DRF default). In test environments where VITE_RECAPTCHA_KEY is not set, the React app sends an empty string. This hit field-level validation before the MWE_TESTING bypass logic ran, causing every application form submission to silently fail with a 400 response. The form appeared to be stuck on Step 1. This required a backend fix (allow_blank=True) that was never part of the original handover.
3. Date inputs passed in the wrong format
Cypress's cy.type() on <input type="date"> requires YYYY-MM-DD. The feature files passed MM/DD/YYYY. Every date-related step failed with a Cypress internal error that took time to trace to the feature file.
4. The signature step destroyed its own work
canvaElementSign — intended to "save" the drawn signature — was actually the Clear button on the SignatureField component. The step drew a valid signature and then immediately erased it. The form schema required a non-empty signature, so Step 4 could never submit.
5. testState had to be reverse-engineered and bolted on
Tests that generate a user (e.g. the application form) and then verify that user later (e.g. the approval flow) need a way to share the runtime-generated email address between steps. The existing suite had no shared state mechanism — each step definition read from Cypress.env(), which is static. A testState module had to be created and wired into step definitions after the fact to make the full flow work.
6. Monorepo overhead for a single app
The testing/ submodule used Turbo + pnpm workspaces for what is currently one app (apps/novahomecare). The workspace tooling added setup overhead with no benefit.
7. 18 env vars for mostly duplicated values
The .env file carried 18 variables, several of which were duplicates (adminUsernameNova and adminUsername point to the same credential). This made setup error-prone and the .env.development.example was missing from the repo at handover time.
8. No step reuse — login repeated in every feature
Every feature file re-implemented the full login sequence as four separate steps rather than sharing a common Background. This meant 22+ copies of the same step chain, and any change to the login flow (e.g. the roleTitle selector) broke tests across every folder.
What testing-v2/ Does Differently
Stable selectors only
Page objects use semantic HTML and stable attributes:
| Element | Old selector | New selector |
|---|---|---|
| Role display in header | p.chakra-text.css-6q9ebm | cy.get('header').contains(role) |
| Signature canvas | .css-1sggvv9 | cy.get('canvas') |
| Sidebar logo | n/a (not tested) | cy.get('aside img') |
| Sidebar nav | n/a (brittle class) | cy.get('aside nav') |
| Notifications bell | brittle class | cy.get('header a[href*="notification"]') |
The rule: if a selector would break on a dependency update or a CSS-in-JS rebuild, it does not belong in a test.
Maintained Cucumber preprocessor
Switched from cypress-cucumber-preprocessor (TheBrainFamily — archived, no updates since 2022) to @badeball/cypress-cucumber-preprocessor (actively maintained, Cypress 13+ compatible, ESBuild-based bundler).
Shared auth steps — no repetition
Login is defined once in step_definitions/common/auth_steps.js and referenced via Background: in any feature that needs an authenticated state. No copy-paste.
Flat, simple structure
No monorepo tooling. One package.json, one cypress.config.js, tests run with a single compose command:
docker compose run --rm e2e-v23 env vars instead of 18
BASE_URL=http://localhost:3000
NOVA_ORG_TOKEN=5ae807a7-df99-4bc2-8d51-fa808b81a41e
ADMIN_EMAIL=superadmin@novavirtual.site
ADMIN_PASSWORD=a1234Additional personas (employee, marketer) will be added as dedicated fixtures/users.json entries when those test flows are built.
What Happens to testing/
The testing/ submodule remains in the parent repo as a read-only reference. It is not run in CI and is not maintained. It serves as a catalogue of the intended test coverage from the handover — a useful reference for which journeys still need to be ported to v2.
Do not fix bugs in testing/. If a journey is worth testing, port it to testing-v2/ with clean selectors and step definitions.
Migration Status
| Journey | testing/ | testing-v2/ |
|---|---|---|
| Login page — elements present | ✅ | ✅ 01_login |
| Login — invalid credentials | ✅ | ✅ 01_login |
| Login — admin success | ✅ (fragile) | ✅ 01_login |
| Dashboard appearance (sidebar, logo, profile, bell) | ✅ (fragile) | ✅ 02_dashboard |
| Application form (Steps 1–4) | ✅ (patched) | ⬜ |
| Applicant approval flow | ✅ (patched) | ⬜ |
| Create employee | ✅ | ⬜ |
| Employee documents | ✅ | ⬜ |
| Competency checklist | ✅ | ⬜ |
| Client / Patient profile | ✅ | ⬜ |
| Marketer referral form | ✅ | ⬜ |
| Work schedule | ✅ | ⬜ |
| Grievances | ✅ | ⬜ |
| Messages | ✅ | ⬜ |
| HR / Payroll / Compliance | ✅ | ⬜ |
| Forgot password | ✅ | ⬜ |
| Notifications | ✅ | ⬜ |
Journeys will be added to testing-v2/ incrementally, in order of user-facing importance.