You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -43,42 +43,42 @@ that prefix; numbers are never reused or shifted when other sections grow.
43
43
|`CALL-01`| Test passes | function body returns cleanly |`PASSED`|`PASSED`| OK |
44
44
|`CALL-02`| Assert failure in call phase |`assert 1 == 2`|`FAILED`|`FAILED`| OK |
45
45
|`CALL-03`| Generic exception in call phase |`raise ValueError("boom")`|`ERROR`|`ERROR`| OK |
46
-
|`CALL-04`|`pytest.fail("...")` from body |`pytest.fail("intentional failure")`|`ERROR`|`FAILED`|Gap|
46
+
|`CALL-04`|`pytest.fail("...")` from body |`pytest.fail("intentional failure")`|`FAILED`|`FAILED`|OK |
47
47
|`CALL-05`|`SystemExit` from the test body |`sys.exit(1)`|`ERROR`|`ERROR` (baseline; `ABORTED` planned later) | OK |
48
-
|`CALL-06`|`KeyboardInterrupt` in body |`raise KeyboardInterrupt`|`PASSED` (session aborts before the plugin sees the interrupt) |`ERROR` when the plugin sees the interrupt; document that a session-aborting interrupt may leave the step in `IN_PROGRESS`|Gap|
48
+
|`CALL-06`|`KeyboardInterrupt` in body |`raise KeyboardInterrupt`|`IN_PROGRESS` (session aborts before the plugin sees the interrupt) |`ERROR` when the plugin sees the interrupt; a session-aborting interrupt leaves the step in `IN_PROGRESS`|OK|
49
49
50
50
## Skip paths
51
51
52
52
| Case | Scenario | Trigger | Observed today | Target | Status |
|`SKIP-01`| Collection-time skip |`@pytest.mark.skip(reason=...)`|`SKIPPED` (only the makereport hook records a step; no autouse step ran) |`SKIPPED`| OK |
55
55
|`SKIP-02`| Conditional collection-time skip |`@pytest.mark.skipif(True, reason=...)`|`SKIPPED` (same route as `@pytest.mark.skip`) |`SKIPPED`| OK |
56
-
|`SKIP-03`| Runtime skip in body |`pytest.skip("...")`| Outer step `ERROR`; a nested step with the same name records `SKIPPED`| Outer step `SKIPPED`; no duplicate nested step |Gap|
57
-
|`SKIP-04`| Skip raised inside a fixture |`@pytest.fixture` calls `pytest.skip("...")`| Outer step `PASSED`; a nested `SKIPPED`step is created by the makereport hook | Outer step `SKIPPED` (setup-phase skip); no duplicate nested step |Gap|
56
+
|`SKIP-03`| Runtime skip in body |`pytest.skip("...")`| Outer step `SKIPPED`; no duplicate nested step | Outer step `SKIPPED`; no duplicate nested step |OK |
57
+
|`SKIP-04`| Skip raised inside a fixture |`@pytest.fixture` calls `pytest.skip("...")`| Outer step `SKIPPED` (setup-phase skip); no duplicate nested step | Outer step `SKIPPED` (setup-phase skip); no duplicate nested step |OK |
58
58
59
59
## xfail / xpass
60
60
61
61
| Case | Scenario | Trigger | Observed today | Target | Status |
|`XFAIL-01`| xfail-marked test that fails |`@pytest.mark.xfail` + `assert 1 == 2`| Outer step `FAILED`; nested `SKIPPED` substep from the makereport hook | Outer step `PASSED` (test fulfilled the xfail expectation); no duplicate nested step |Gap|
64
-
|`XFAIL-02`| Strict xfail that unexpectedly passes |`@pytest.mark.xfail(strict=True)` + `assert True`| Outer step `PASSED` (plugin never sees pytest's "strict xpass" failure attached to the report) | Outer step `FAILED` (mark no longer matches reality — either the bug was fixed or the test stopped testing what it claimed) |Gap|
65
-
|`XFAIL-03`| Non-strict xfail that unexpectedly passes |`@pytest.mark.xfail()` + `assert True`| Outer step `PASSED`(pytest reports outcome="passed" with `wasxfail` set; plugin ignores it)| Outer step `PASSED` (`strict=False` doesn't insist on the failure) | OK |
66
-
|`XFAIL-04`|`xfail(raises=...)` with wrong exception |`@pytest.mark.xfail(raises=ValueError)` + `raise KeyError`|Outer step `ERROR` (treated as a generic non-assertion exception) |`FAILED` (the `raises=` mismatch is a real test failure) |Gap|
67
-
|`XFAIL-05`|`xfail(run=False)`|`@pytest.mark.xfail(run=False)` (body never executed) |`SKIPPED` (only the makereport hook records a step)|`SKIPPED` (the test never ran) | OK |
63
+
|`XFAIL-01`| xfail-marked test that fails |`@pytest.mark.xfail` + `assert 1 == 2`| Outer step `PASSED` (test fulfilled the xfail expectation); no duplicate nested step| Outer step `PASSED` (test fulfilled the xfail expectation); no duplicate nested step |OK |
64
+
|`XFAIL-02`| Strict xfail that unexpectedly passes |`@pytest.mark.xfail(strict=True)` + `assert True`| Outer step `FAILED` (mark no longer matches reality — either the bug was fixed or the test stopped testing what it claimed) | Outer step `FAILED` (mark no longer matches reality — either the bug was fixed or the test stopped testing what it claimed) |OK |
65
+
|`XFAIL-03`| Non-strict xfail that unexpectedly passes |`@pytest.mark.xfail()` + `assert True`| Outer step `PASSED`| Outer step `PASSED` (`strict=False` doesn't insist on the failure) | OK |
66
+
|`XFAIL-04`|`xfail(raises=...)` with wrong exception |`@pytest.mark.xfail(raises=ValueError)` + `raise KeyError`|`FAILED` (the `raises=` mismatch is a real test failure) |`FAILED` (the `raises=` mismatch is a real test failure) |OK|
67
+
|`XFAIL-05`|`xfail(run=False)`|`@pytest.mark.xfail(run=False)` (body never executed) |`SKIPPED` (the test never ran) |`SKIPPED` (the test never ran) | OK |
68
68
69
69
## Setup / teardown phases
70
70
71
71
| Case | Scenario | Trigger | Observed today | Target | Status |
|`PHASE-01`| Setup-phase fixture failure (RuntimeError) |`@pytest.fixture` raises before `yield`; test body never runs | Outer step does not exist or lands `PASSED`; the plugin does not consult `report.when`|`ERROR`with`phase=setup` annotation | Gap|
74
-
|`PHASE-02`| Teardown-phase fixture failure |`@pytest.fixture` raises after `yield`; test body passed | Outer step `PASSED` — it closes before the failing teardown runs, so the error is invisible |`FAILED`with`phase=teardown` annotation | Gap|
75
-
|`PHASE-03`| Call-phase fail **plus** teardown-phase fail |`assert 1 == 2` in body AND `@pytest.fixture` raises after `yield`| Outer step `FAILED` (the call-phase failure dominates); the teardown error is silently lost |`FAILED` with a `phase=teardown` annotation so the teardown error is also visible | Gap|
73
+
|`PHASE-01`| Setup-phase fixture failure (RuntimeError) |`@pytest.fixture` raises before `yield`; test body never runs | Outer step `ERROR`; the plugin reads the setup-phase report and maps `failed` → `ERROR`|`ERROR`(a`phase=setup` annotation is a planned follow-up) | OK |
74
+
|`PHASE-02`| Teardown-phase fixture failure |`@pytest.fixture` raises after `yield`; test body passed | Outer step `FAILED`; after teardown the plugin upgrades a passed step when the teardown report shows `failed`|`FAILED`(a`phase=teardown` annotation is a planned follow-up) | OK |
75
+
|`PHASE-03`| Call-phase fail **plus** teardown-phase fail |`assert 1 == 2` in body AND `@pytest.fixture` raises after `yield`| Outer step `FAILED` (the call-phase failure dominates); the teardown error is not yet surfaced separately|`FAILED`; surfacing the teardown error alongside is a planned follow-up | OK|
76
76
77
77
## Collection / fixture-resolution failures
78
78
79
79
| Case | Scenario | Trigger | Observed today | Target | Status |
|`COLL-01`| Missing fixture |`def test_x(nonexistent_fixture):`| Outer step `PASSED` — the autouse `step`fixture's setup still runs before pytest detects the missing fixture; the user sees a green step for a test that never executed |`ERROR` with `phase=setup`|Gap|
81
+
|`COLL-01`| Missing fixture |`def test_x(nonexistent_fixture):`| Outer step `ERROR` — the missing fixture surfaces as a setup-phase failure, which the plugin now maps to `ERROR`|`ERROR` (a `phase=setup` annotation is a planned follow-up)|OK |
0 commit comments