Skip to content

fix(tests): cotton integration tier exercises real compilation (#79) - #80

Merged
fsecada01 merged 2 commits into
masterfrom
fix/component-framework-ui-phase-79-cotton-app-installed-apps
Aug 19, 2026
Merged

fix(tests): cotton integration tier exercises real compilation (#79)#80
fsecada01 merged 2 commits into
masterfrom
fix/component-framework-ui-phase-79-cotton-app-installed-apps

Conversation

@fsecada01

Copy link
Copy Markdown
Owner

Summary

  • tests/integration/cotton_app/settings.py never listed django_cotton in INSTALLED_APPS, so its AppConfig.ready() never ran and Django's template engine treated <c-cf.*> tags as inert literal text — test_cotton_integration.py's assertions were satisfied by uncompiled markup, not real cotton output.
  • Added django_cotton to INSTALLED_APPS and COTTON_SNAKE_CASED_NAMES = False (matching the precedent already set in tests/e2e/_e2e_django_settings.py), and added a regression assertion to each of the three existing tests proving the raw <c-cf.*> tag is compiled away, not passed through.
  • Registering django_cotton surfaced a bigger, previously-latent problem: django_cotton.apps.LoaderAppConfig.ready() mutates settings.TEMPLATES in place and resets Django's global template-engine cache — a permanent, process-wide side effect the moment it's in INSTALLED_APPS. justfile's test-all recipe ran tests/unit and tests/integration in one pytest tests/ process, so once cotton was registered its loader/builtins leaked into every unit test's render_to_string call, breaking ~400 unrelated unit tests.
  • .github/workflows/ci.yml was never affected — it already runs each tier as its own step (separate process) — but test-all needed the same separation to match. Fixed test-all to invoke pytest once per tier, and corrected tests/integration/conftest.py's docstring, which had documented a conftest "race" that doesn't actually matter once tiers never share a process.

Test plan

  • pytest tests/integration/test_cotton_integration.py -v — all 3 tests pass against real compiled markup (confirmed the new assert b"<c-cf..." not in r.content assertions fail without the INSTALLED_APPS fix, pass with it)
  • pytest tests/unit -q — 2826 passed, 13 skipped, run alone
  • pytest tests/integration -q — 25 passed, run alone
  • ruff check src tests / ruff format --check src tests — clean
  • Confirmed via debug instrumentation that the previous conftest docstring's claimed configure-order was empirically false, and that the real fix is process separation (matching CI), not fixing the race

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ur2c6d3peuerUGgRdJ6Fvs

fsecada01 and others added 2 commits August 19, 2026 17:14
…est-all by process (#79)

tests/integration/cotton_app/settings.py never listed django_cotton in
INSTALLED_APPS, so its AppConfig.ready() never ran and DTL treated
<c-cf.*> tags as inert literal text — test_cotton_integration.py's
assertions were passing against uncompiled markup.

Registering it exposed a bigger problem: django-cotton's
AppConfig.ready() mutates settings.TEMPLATES in place and resets
Django's global template-engine cache, a permanent process-wide side
effect. justfile's test-all recipe ran tests/unit and
tests/integration in one pytest process, so once cotton was
registered its loader/builtins leaked into every unit test's
render_to_string call and broke ~400 of them. CI was never affected —
ci.yml already runs each tier as its own step — but test-all needed
the same separation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ur2c6d3peuerUGgRdJ6Fvs
…ion invariant

/review on PR #80 found the invariant was only convention (justfile/CI
recipe discipline), not enforced — a bare `pytest` (pyproject.toml's
testpaths = ["tests"]) or `pytest tests/` still collects both tiers
into one process and reintroduces the settings.TEMPLATES leak,
producing ~400 confusing unit-test failures instead of an obvious
error. Verified: `pytest -q` now fails fast with a clear
pytest.UsageError instead of the silent breakage; both tiers still
pass individually.

Also corrected CLAUDE.md's now-stale claim that only E2E exercises
real <c-vars> compilation — the integration tier does too as of this
PR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ur2c6d3peuerUGgRdJ6Fvs
@fsecada01

Copy link
Copy Markdown
Owner Author

/review findings

4 findings surfaced, 2 verified via direct reproduction:

  1. [Fixed in 9f37bac] The "tiers must never share a process" invariant was only convention (justfile/CI recipe discipline), not enforced in code. A bare pytest invocation — the literal default under pyproject.toml's testpaths = ["tests"] — still collected tests/unit and tests/integration into one process and reintroduced the exact settings.TEMPLATES leak this PR fixes, reproducing as 415 failed / 2660 passed. Added a pytest_collection_modifyitems guard in tests/integration/conftest.py that raises a clear pytest.UsageError if both tiers get collected together, instead of letting it silently produce hundreds of confusing failures. Verified: bare pytest now fails fast with the explanatory error; both tiers still pass individually.

  2. Not fixed — accepted as existing convention. just test-all's new 3-line recipe stops at the first failing tier (confirmed empirically: just aborts a recipe on the first non-zero exit line) rather than reporting all tiers' failures like the old single pytest tests/ invocation did. This matches the repo's existing check: lint lint-templates test recipe, which has the same stop-at-first-failure behavior today — not a novel regression, just extending an already-established local-dev tradeoff. CI is unaffected either way (it never calls test-all; it runs each tier as its own workflow step).

  3. [Fixed in 9f37bac] CLAUDE.md's Testing Strategy section claimed "Only E2E actually exercises <c-vars> compilation" — stale as of this PR, since the integration tier now does too. Corrected.

  4. Not fixed — accepted as minor duplication. INSTALLED_APPS/COTTON_SNAKE_CASED_NAMES/comment block is now duplicated near-verbatim between tests/integration/cotton_app/settings.py and tests/e2e/_e2e_django_settings.py. Real, but a 3-line duplication between two settings files scoped to their own tiers doesn't justify a shared-base abstraction for two call sites.

All gates re-verified after the fixes: pytest tests/unit (2826 passed, 13 skipped), pytest tests/integration (25 passed), bare pytest now fails fast with the guard's message, ruff check/ruff format --check clean.

@fsecada01
fsecada01 merged commit 73a2192 into master Aug 19, 2026
6 of 7 checks passed
@fsecada01
fsecada01 deleted the fix/component-framework-ui-phase-79-cotton-app-installed-apps branch August 19, 2026 23:07
@fsecada01 fsecada01 added the bug Something isn't working label Aug 20, 2026
fsecada01 added a commit that referenced this pull request Aug 20, 2026
attrs passthrough on the interactive set — Button, Select, Textarea,
FormField, Icon, Badge, Box, CheckboxGroup (#70, #72, #73, #76, #77,
#82) — plus the two coverage-gap fixes found along the way (#78/#81
JinjaX docs, #79/#80 cotton integration compiler). Fully additive:
attrs defaults to {} everywhere, so every existing call site renders
byte-identically. #70 stays open for the remaining components.

Verified before tagging: 3186 passed / 13 skipped (unit), 40 passed
(integration), 236 passed / 33 skipped (E2E chromium, both js modes),
ruff check/format clean, djlint clean on both template trees (126
cotton + 105 jinja, 0 errors), mkdocs build --strict clean, and the
release workflow's own wheel guard run locally against `uv build` —
237 shipped templates and assets, all present, twine check passed on
both sdist and wheel.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant