fix(tests): replace the blocking wait_window with an on_close callback; correct the dialog-commit assertion #47

Merged
ykp merged 3 commits from fix-protected-dialog-empty into master 2026-09-29 11:53:21 +02:00
Owner

Follow-up to the merged #46 (its CI ran after the merge and reported two failures). Same branch, one new commit (5747949).

1. test_edit_dialog_commits_on_ok — TclError: bad window path name

The #46 fix added a blocking wait_window(dialog) after the dialog constructor. The monkeypatched fake returned an already-destroyed Toplevel, and wait_window on a destroyed path raises TclError: bad window path name.

Restructure (behavior-preserving, no blocking):

  • ProtectedBandsDialog takes an optional on_close callback — fired after destroy() for OK, Cancel and the WM close button alike (the WM_DELETE_WINDOW protocol routes to the same dismiss path).
  • The main window holds the reference (self._protected_dialog: ProtectedBandsDialog | None) and refreshes the count label from the callback. The modal behavior stays with grab_set (after wait_visibility — the original #46 fix), the gc-reference concern is covered by the held reference, and the refresh-after-close semantics are preserved — minus the blocking wait that monkeypatched tests (and any embedded caller) cannot survive.
  • The fake-dialog test reverts to the plain lambda (returns None).

2. test_real_dialog_opens_with_content — assert 3 == 2

The test's own arithmetic: 1 initial + 1 added via _on_add + 1 appended = 3 records, asserted 2. Fixed the count and the comment; the copy-vs-project isolation checks stay.

Also dropped a bogus protocol("WM_DELETE_WINDOW")() direct-invoke probe (protocol with one argument returns the handler string — not callable).

Gate

  • pytest: 1278 passed / 64 skipped (headless tier), coverage 93.51 %
  • ruff + mypy: clean
  • The real-dialog tests run in the CI widget tier (tkinter + display).
Follow-up to the merged #46 (its CI ran after the merge and reported two failures). Same branch, one new commit (`5747949`). ## 1. `test_edit_dialog_commits_on_ok` — `TclError: bad window path name` The #46 fix added a blocking `wait_window(dialog)` after the dialog constructor. The monkeypatched fake returned an **already-destroyed Toplevel**, and `wait_window` on a destroyed path raises `TclError: bad window path name`. **Restructure (behavior-preserving, no blocking):** - `ProtectedBandsDialog` takes an optional `on_close` callback — fired after `destroy()` for **OK, Cancel and the WM close button alike** (the `WM_DELETE_WINDOW` protocol routes to the same dismiss path). - The main window **holds the reference** (`self._protected_dialog: ProtectedBandsDialog | None`) and refreshes the count label from the callback. The modal behavior stays with `grab_set` (after `wait_visibility` — the original #46 fix), the gc-reference concern is covered by the held reference, and the refresh-after-close semantics are preserved — minus the blocking wait that monkeypatched tests (and any embedded caller) cannot survive. - The fake-dialog test reverts to the plain lambda (returns `None`). ## 2. `test_real_dialog_opens_with_content` — `assert 3 == 2` The test's own arithmetic: **1 initial + 1 added via `_on_add` + 1 appended = 3 records**, asserted 2. Fixed the count and the comment; the copy-vs-project isolation checks stay. Also dropped a bogus `protocol("WM_DELETE_WINDOW")()` direct-invoke probe (`protocol` with one argument *returns* the handler string — not callable). ## Gate - `pytest`: **1278 passed / 64 skipped** (headless tier), coverage **93.51 %** - `ruff` + `mypy`: clean - The real-dialog tests run in the CI widget tier (tkinter + display).
CI (Python 3.11 + tkinter) on PR #46 caught two issues in the fix
commit:

1. test_edit_dialog_commits_on_ok — wait_window(dialog) blocked on the
   monkeypatched fake: the fake returned an already-destroyed Toplevel
   and wait_window on a destroyed path raises TclError (bad window path
   name). Restructured: the dialog takes an optional on_close callback
   (fired after destroy for OK, Cancel AND the WM close button alike —
   the WM_DELETE_WINDOW protocol routes to the same dismiss path), and
   the main window holds the reference (self._protected_dialog, typed
   ProtectedBandsDialog | None) and refreshes from the callback. No
   blocking wait — grab_set still provides the modality, the reference
   prevents gc, and the refresh-after-close semantics are preserved.
   The fake-dialog test reverts to the plain lambda (returns None).

2. test_real_dialog_opens_with_content — the test's own arithmetic: 1
   initial + 1 added via _on_add + 1 appended = 3 records, asserted 2.
   Fixed the count and the comment; the copy-vs-project isolation
   checks stay.

Also dropped a bogus protocol('WM_DELETE_WINDOW')() direct-invoke probe
(protocol with one arg RETURNS the handler string — not callable).

Gate: pytest 1278 passed / 64 skipped (headless tier), coverage
93.51 %; ruff + mypy clean.
Merge branch 'master' into fix-protected-dialog-empty
Some checks failed
test / test (ubuntu-latest) (pull_request) Failing after 3m3s
1afe5fbe68
fix(tests): the fake dialog must accept the on_close kwarg
All checks were successful
test / test (ubuntu-latest) (pull_request) Successful in 2m48s
1f9787b0ba
_on_edit_protected_bands passes on_close=... (the #47 restructure);
the monkeypatched fake only took (parent, project) → TypeError. The
fake now swallows extra kwargs (**_kwargs) so future constructor
additions can't break it again.
ykp merged commit 4353e92d1d into master 2026-09-29 11:53:21 +02:00
ykp deleted branch fix-protected-dialog-empty 2026-09-29 11:53:21 +02:00
Sign in to join this conversation.
No description provided.