Skip to content

[ENG-737] Questionnaire E2E fixtures and API tests - #3722

Draft
bodhish wants to merge 7 commits into
ENG-737from
bodhi/ENG-737-test-fixtures
Draft

[ENG-737] Questionnaire E2E fixtures and API tests#3722
bodhish wants to merge 7 commits into
ENG-737from
bodhi/ENG-737-test-fixtures

Conversation

@bodhish

@bodhish bodhish commented Aug 1, 2026

Copy link
Copy Markdown
Member

Stacked on #3719 (ENG-737). Makes the fixture and test surface good enough for the frontend to exercise the whole questionnaire feature deterministically.

1. Silent fixture-loading bug

QuestionnaireCreateSpec made auth_context required (no default), so every entry in data/questionnaire_fixtures.json failed validation — and load_questionnaires_from_file swallowed each failure with a bare except FixtureError: pass, so load_fixtures reported success while creating zero questionnaires. The create spec also stopped accepting organizations, silently dropping the visibility tagging.

Fix:

  • all 8 bundled entries now carry "auth_context": "instance";
  • create_questionnaire applies organizations through the set_organizations action after creation (create no longer accepts them), restoring non-superuser visibility;
  • both JSON loaders (load_questionnaires_from_file, load_templates_from_file) log a warning with the slug and error instead of swallowing failures.

2. Idempotent E2E fixture script

care/fixtures/scripts/questionnaire_e2e_fixtures.py — run after the default fixtures:

python manage.py load_fixtures --path care/fixtures/scripts/questionnaire_e2e_fixtures.py

Unlike default_fixtures.py, it is idempotent and additive: every create is preceded by an API lookup (questionnaires by slug, patient by phone number, encounters by patient + status) and skipped when present, so it is safe to run repeatedly against a populated dev database. Verified with two consecutive runs — the second is a clean no-op.

It seeds (all slugs e2e- prefixed, deterministic question ids via UUID5):

  • e2e-kitchen-sink-instance / e2e-kitchen-sink-facility — every simple question type, choice/quantity with custom options (one initial_selected, UCUM unit), nested groups with containerClasses layout presets, enable_when coverage (boolean Yes/No, numeric greater/less, string equals, 2-condition any behavior, disabled_display: protected), repeating choice/string, and a LOINC-bound observation question (8867-4 Heart rate, literal code — no terminology-server dependency at create time);
  • e2e-subject-location / e2e-subject-device / e2e-subject-facility — one facility questionnaire per remaining subject type;
  • e2e-org-scope (facility_organization context, General Medicine) and e2e-user-scope (user context, created as care-fac-admin through a second API client — the Doctor role lacks can_write_questionnaire);
  • e2e-versioned — two follow-up PUTs, ending at internal_revision 3 with 2 archived revisions;
  • e2e-pagination-001…018 — enough active facility questionnaires to page past the default page size of 14;
  • one patient with fresh planned and in_progress encounters in FACILITY WITH PATIENTS / General Medicine (re-minted when older than 60 days, so the frontend's 90-day created_date window always matches).

Supporting changes: CareFixtureBase.put(), and care_fixture_context now also no-ops QuestionnaireLock — its release is deferred to transaction.on_commit, which never fires inside the fixture transaction, deadlocking a second update on the same questionnaire.

3. API test coverage

The redesign had no tests for its own surfaces, and the pre-existing suite was fully red against it (62 of 63 tests: missing auth_context, missing question ids after the default was removed, and reverses against the removed slug lookup).

  • test_questionnaire_api.py repaired: payloads carry auth_context + question ids, reverses use external_id, and the permission tests match the new authorization model (hidden-not-403 for unauthorized objects, instance questionnaires and organization management superuser-only, visibility via set_organizations).
  • New test_questionnaire_scoping_api.py (20 tests): auth_context required on create; facility/user contexts require a facility and facility_organization context requires an organization; patient subject_type only at instance level; updates ignore auth_context/subject_type; revision snapshot on question change (internal_revision bump, archived row, parent_revision filter, past revisions hidden from the default list and immutable) and no snapshot on metadata-only updates; auth_context + facility list filters; slug uniqueness scoped per auth context and per facility.

How to run

# fixtures (twice to see the no-op)
docker compose exec backend python manage.py load_fixtures --path care/fixtures/scripts/questionnaire_e2e_fixtures.py

# tests
docker compose exec backend python manage.py test \
  care.emr.tests.test_questionnaire_api care.emr.tests.test_questionnaire_scoping_api --parallel 1

All 84 tests pass; ruff check is clean on the changed files.

🤖 Generated with Claude Code

bodhish and others added 3 commits August 1, 2026 23:13
QuestionnaireCreateSpec made auth_context a required field, so every entry
in data/questionnaire_fixtures.json failed validation and load_fixtures
silently created zero questionnaires. The create spec also stopped
accepting "organizations", so the visibility tagging passed by
default_fixtures.py was silently dropped.

- Add auth_context: instance to all 8 bundled questionnaire fixtures.
- create_questionnaire now applies organizations through the
  set_organizations action after creation, restoring visibility for
  non-superusers.
- load_questionnaires_from_file / load_templates_from_file log a warning
  with the slug and error instead of swallowing FixtureError, so fixture
  data loss is visible in the command output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
care/fixtures/scripts/questionnaire_e2e_fixtures.py seeds a deterministic
e2e- prefixed questionnaire dataset for frontend E2E tests:

- kitchen-sink questionnaires (instance + facility) covering every simple
  question type, groups with containerClasses layout presets, enable_when
  (boolean Yes/No, numeric greater/less, string equals, any-behavior,
  protected disabled_display), repeating questions and a LOINC-bound
  observation question
- facility questionnaires for the location/device/facility subject types
- facility_organization- and user-scoped questionnaires (the user-scoped
  one is created as care-fac-admin through a second API client; the
  Doctor role lacks can_write_questionnaire)
- e2e-versioned with two archived revisions (internal_revision 3)
- 18 pagination questionnaires (default page size is 14)
- one patient with fresh planned and in_progress encounters wired to
  FACILITY WITH PATIENTS / General Medicine

Unlike default_fixtures.py the script is idempotent and additive: every
create is preceded by an API lookup and skipped when the record exists,
so it is safe to run repeatedly against a populated dev database. Stale
E2E encounters are re-minted once older than 60 days to stay inside the
frontend's 90 day created_date window.

Supporting changes:
- CareFixtureBase.put() for revision-creating questionnaire updates
- care_fixture_context now also no-ops QuestionnaireLock: its release is
  deferred to transaction.on_commit which never fires inside the fixture
  transaction, deadlocking a second update on the same questionnaire

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The questionnaire redesign had no coverage for its own surfaces, and the
pre-existing suite was fully red (62 of 63 tests) against the new
QuestionnaireCreateSpec. This repairs the existing tests and adds a new
module covering the redesigned behaviour.

Repairs to test_questionnaire_api.py:
- payloads now send the required auth_context and per-question ids
  (auth_context is required with no default; the question id default was
  removed), via a shared _prepare_questionnaire_definition helper
- reverses migrated from the removed slug lookup to external_id
- permission tests updated to the new authorization model: unauthorized
  questionnaires are hidden (404/empty list instead of a blanket 403 from
  the removed permissions_controller), instance questionnaires and their
  organization management are superuser-only, and visibility is granted
  through set_organizations after creation

New test_questionnaire_scoping_api.py:
- auth_context required on create; facility/user contexts require a
  facility; facility_organization context requires an organization
- patient subject_type only allowed at the instance level
- updates ignore auth_context/subject_type (immutable after create)
- facility questionnaire visibility via set_facility_organizations,
  cross-facility isolation, user questionnaires visible only to their
  creator
- revision snapshot on question change: internal_revision bump, archived
  row with latest_revision set, parent_revision list filter, past
  revisions hidden from the default list and rejected on update;
  metadata-only updates do not snapshot
- auth_context + facility list filters
- slug uniqueness scoped per auth_context and per facility

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c1b57f85-4256-4343-a2ac-52faaa9db29f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

bodhish and others added 4 commits August 2, 2026 02:06
…s valueset

New idempotent seeds for frontend unit-semantics E2E coverage:

- e2e-dose-units: instance valueset with three enumerated UCUM units
  (mg/g/kg) — small enough for the frontend to render as inline unit
  chips. The compose carries an explicit empty exclude because
  ValueSet.create_composition iterates compose.exclude unguarded and
  $expand breaks without it.
- e2e-units: facility questionnaire with an integer (/min) and a decimal
  (Cel) question carrying a question-level unit, plus a quantity question
  whose answer_value_set is the bounded valueset (default unit mg).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ink, patient-subject

Extends the questionnaire E2E fixture script with 19 new idempotent,
slug-keyed questionnaires backing the structured-rearchitecture Playwright
suite: one per-type fixture for each of the 11 core structured question
types, required variants for the five types getting full new test
coverage, an unknown-plugin-type fixture for hard-block/unknown-type
specs, a structured kitchen-sink for session/draft/merge specs, and an
instance-scoped patient-subject fixture so the patient-fill spec no
longer has to author its questionnaire live through the API.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…anion

Pins the other half of the hard-block behavior alongside e2e-structured-unknown:
a non-required structured question stuck on the same unregistered plugin type is
skipped, and Save succeeds with only the plain answer. Lets fillHardBlock.spec.ts
migrate both of its cases to fixtures instead of just the required one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant