docs(15-01): complete ux-driver-upload-feedback-fix plan
- SUMMARY.md created: one-line fix, two new tests, full suite green - STATE.md updated: Phase 15 complete, decisions logged - ROADMAP.md: Phase 15 marked 1/1 Complete 2026-04-16 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
---
|
||||
phase: 15-ux-driver-upload-feedback-fix
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- imptune/templates/printers_new.html
|
||||
- tests/test_printer_form.py
|
||||
autonomous: true
|
||||
requirements:
|
||||
- UX-01
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "GET /printers/new renders a #driver-list div with no style=\"display:none\" attribute"
|
||||
- "After uploading a driver on /printers/new, the OOB response fragment contains the driver name (upload confirmation visible)"
|
||||
- "The driver dropdown (OOB select) still refreshes after upload (no regression)"
|
||||
artifacts:
|
||||
- path: "imptune/templates/printers_new.html"
|
||||
provides: "Printer new page template with visible #driver-list anchor"
|
||||
contains: "id=\"driver-list\""
|
||||
- path: "tests/test_printer_form.py"
|
||||
provides: "Smoke tests for driver-list visibility and upload feedback"
|
||||
exports:
|
||||
- "test_printers_new_driver_list_visible"
|
||||
- "test_upload_feedback_visible_on_printers_new"
|
||||
key_links:
|
||||
- from: "imptune/templates/printers_new.html"
|
||||
to: "partials/driver_upload_with_oob.html"
|
||||
via: "HTMX hx-target=\"#driver-list\" outerHTML swap"
|
||||
pattern: "id=\"driver-list\""
|
||||
- from: "POST /drivers/upload?caller=printer_form"
|
||||
to: "driver_upload_with_oob.html primary fragment"
|
||||
via: "caller sentinel in upload handler"
|
||||
pattern: "caller == \"printer_form\""
|
||||
---
|
||||
|
||||
<objective>
|
||||
Close the integration gap: the `#driver-list` div on `/printers/new` is hidden (`style="display:none"`), so the HTMX outerHTML swap from the driver upload succeeds but the confirmation content (driver name, driver table) is invisible to the technician.
|
||||
|
||||
Purpose: A technician uploading a driver on `/printers/new` must see the upload confirmation — driver name + driver list table — immediately after uploading, without reloading the page. The OOB select refresh (dropdown update) must continue to work.
|
||||
|
||||
Output: One-line template change to `printers_new.html` (remove `style="display:none"`), two new integration assertions in `tests/test_printer_form.py`.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/phases/15-ux-driver-upload-feedback-fix/15-RESEARCH.md
|
||||
@.planning/phases/15-ux-driver-upload-feedback-fix/15-VALIDATION.md
|
||||
|
||||
<interfaces>
|
||||
<!-- Key contracts the executor needs. Extracted from codebase. -->
|
||||
|
||||
From imptune/templates/printers_new.html (line 87-99, current state):
|
||||
```html
|
||||
<form hx-post="/drivers/upload"
|
||||
hx-target="#driver-list"
|
||||
hx-encoding="multipart/form-data"
|
||||
hx-swap="outerHTML">
|
||||
<input type="hidden" name="caller" value="printer_form">
|
||||
<label>
|
||||
<span x-text="$store.i18n.t('upload_new_driver')">Upload New Driver</span>
|
||||
<input type="file" name="file" accept=".zip" required>
|
||||
</label>
|
||||
<button type="submit" class="secondary" x-text="$store.i18n.t('upload_driver')">Upload Driver</button>
|
||||
</form>
|
||||
<div id="driver-list" style="display:none"></div> <!-- BUG: hidden — line 98 -->
|
||||
</div>
|
||||
```
|
||||
|
||||
From tests/conftest.py — `client` fixture:
|
||||
```python
|
||||
@pytest.fixture
|
||||
def client(tmp_data_dir):
|
||||
from imptune.main import app
|
||||
with TestClient(app) as c:
|
||||
yield c
|
||||
```
|
||||
|
||||
From tests/test_driver_upload.py — helper `_make_driver_zip`:
|
||||
```python
|
||||
SAMPLE_INF = """\
|
||||
[Version]
|
||||
Signature="$Windows NT$"
|
||||
...
|
||||
[Strings]
|
||||
MFG="Test Manufacturer"
|
||||
DRIVER_NAME="Test LaserJet Pro"
|
||||
"""
|
||||
|
||||
def _make_driver_zip(
|
||||
inf_content: str = SAMPLE_INF,
|
||||
inf_name: str = "sample.inf",
|
||||
extra_files: dict[str, bytes] | None = None,
|
||||
) -> bytes:
|
||||
...
|
||||
```
|
||||
Note: `_make_driver_zip` is defined in `test_driver_upload.py` — do NOT import it.
|
||||
Replicate a minimal equivalent helper locally in `test_printer_form.py` (or inline the zip creation).
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: Add Wave 0 smoke tests for driver-list visibility and upload feedback</name>
|
||||
<files>tests/test_printer_form.py</files>
|
||||
<behavior>
|
||||
- test_printers_new_driver_list_visible: GET /printers/new returns 200 and the response HTML contains `id="driver-list"` but does NOT contain `id="driver-list" style="display:none"` — i.e., the anchor exists and is not hidden.
|
||||
- test_upload_feedback_visible_on_printers_new: POST /drivers/upload with a valid driver ZIP and `data={"caller": "printer_form"}` returns 200 and the response body contains the driver name from the INF ("Test LaserJet Pro") AND contains `hx-swap-oob="true"` (OOB select still present).
|
||||
</behavior>
|
||||
<action>
|
||||
Append two new test functions to the bottom of `tests/test_printer_form.py`.
|
||||
|
||||
**test_printers_new_driver_list_visible:**
|
||||
- GET /printers/new, assert 200
|
||||
- Assert `'id="driver-list"' in resp.text` (anchor exists)
|
||||
- Assert `'id="driver-list" style="display:none"' not in resp.text` (not hidden)
|
||||
|
||||
**test_upload_feedback_visible_on_printers_new:**
|
||||
- Build a minimal driver ZIP in-memory: create a `BytesIO` + `zipfile.ZipFile`, write one .inf file containing `DRIVER_NAME="Test LaserJet Pro"` using the same SAMPLE_INF-style content as in `test_driver_upload.py`. Do NOT import from `test_driver_upload.py` — replicate the ~10-line helper inline or as a local `_make_driver_zip_for_form_test` function at the top of the new block.
|
||||
- POST to `/drivers/upload` with `files={"file": ("driver.zip", zip_bytes, "application/zip")}` and `data={"caller": "printer_form"}`
|
||||
- Assert `resp.status_code == 200`
|
||||
- Assert `"Test LaserJet Pro" in resp.text` (upload confirmation contains driver name)
|
||||
- Assert `'hx-swap-oob="true"' in resp.text` (OOB select still present — regression guard)
|
||||
|
||||
Add required imports at top of file if not already present: `import io`, `import zipfile`.
|
||||
|
||||
**Run tests after writing — they MUST fail (RED) before the template fix.**
|
||||
Run: `pytest tests/test_printer_form.py::test_printers_new_driver_list_visible tests/test_printer_form.py::test_upload_feedback_visible_on_printers_new -x -q`
|
||||
|
||||
Expected: `test_printers_new_driver_list_visible` FAILS (div is currently hidden).
|
||||
Expected: `test_upload_feedback_visible_on_printers_new` may PASS already (server response is correct; visibility is DOM-side). If it passes, that is expected and acceptable — the server already returns the driver name in the fragment; the bug is only that the DOM target is hidden. Document this in a comment.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pytest tests/test_printer_form.py::test_printers_new_driver_list_visible tests/test_printer_form.py::test_upload_feedback_visible_on_printers_new -x -q</automated>
|
||||
</verify>
|
||||
<done>Both test functions exist in tests/test_printer_form.py. `test_printers_new_driver_list_visible` FAILS (RED — confirming the bug). `test_upload_feedback_visible_on_printers_new` PASSES (server fragment is correct). Test file has no import errors.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Remove display:none from #driver-list in printers_new.html and verify GREEN</name>
|
||||
<files>imptune/templates/printers_new.html</files>
|
||||
<action>
|
||||
Edit `imptune/templates/printers_new.html` line 98.
|
||||
|
||||
**Change:**
|
||||
```html
|
||||
<div id="driver-list" style="display:none"></div>
|
||||
```
|
||||
**To:**
|
||||
```html
|
||||
<div id="driver-list"></div>
|
||||
```
|
||||
|
||||
That is the complete change. Do NOT modify any other line. Do NOT touch `printer_form.html`. Do NOT touch `driver_upload_with_oob.html`. Do NOT touch `driver_list.html`.
|
||||
|
||||
After saving, run the full targeted test suite to confirm GREEN:
|
||||
`pytest tests/test_printer_form.py tests/test_driver_upload.py -x -q`
|
||||
|
||||
Then run the full suite (excluding e2e) to confirm no regression:
|
||||
`pytest tests/ -x -q --ignore=tests/e2e`
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pytest tests/test_printer_form.py tests/test_driver_upload.py -x -q</automated>
|
||||
</verify>
|
||||
<done>
|
||||
- `tests/test_printer_form.py::test_printers_new_driver_list_visible` PASSES (GREEN — div no longer hidden)
|
||||
- `tests/test_printer_form.py::test_upload_feedback_visible_on_printers_new` PASSES
|
||||
- `tests/test_driver_upload.py::test_upload_returns_oob_when_called_from_form` PASSES (no regression)
|
||||
- Full suite `pytest tests/ -x -q --ignore=tests/e2e` is green
|
||||
- `printers_new.html` line 98 reads `<div id="driver-list"></div>` with no style attribute
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. `pytest tests/test_printer_form.py -x -q` — all tests pass including the two new ones
|
||||
2. `pytest tests/test_driver_upload.py -x -q` — OOB regression test passes
|
||||
3. `pytest tests/ -x -q --ignore=tests/e2e` — full suite green
|
||||
4. `grep 'display:none' imptune/templates/printers_new.html` — returns no matches (the hidden style is gone)
|
||||
5. Manual smoke (optional): Open /printers/new in browser, upload a driver ZIP, confirm driver name + table appears without page reload
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- GET /printers/new: `#driver-list` div exists with no `style="display:none"` attribute
|
||||
- POST /drivers/upload with caller=printer_form: response fragment contains driver name (upload confirmation)
|
||||
- OOB select (`hx-swap-oob="true"`) still present in upload response (no regression)
|
||||
- All tests pass: `pytest tests/ -x -q --ignore=tests/e2e`
|
||||
- Single-line change in `printers_new.html` — no other files modified except test additions
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/15-ux-driver-upload-feedback-fix/15-01-SUMMARY.md` with:
|
||||
- What was changed (printers_new.html line 98, two new test functions)
|
||||
- Why (hidden div made upload confirmation invisible despite correct server response)
|
||||
- Tests added and their status
|
||||
- Regression: OOB select refresh unaffected
|
||||
- Full suite result
|
||||
</output>
|
||||
Reference in New Issue
Block a user