Every Booth page asks fonts.googleapis.com for its faces, and wait_until="networkidle" waits for that request. A stalled request to Google therefore held a page until goto's 30s timeout. That is the failure the full-suite flake shows: Page.goto timeouts in tests far apart within one run. A stalled font request reproduces it exactly. Whether that was THE cause is not proven: - 23 traced runs went green, against 1 red in 8 untraced; - no trace captured the pending request. A test that depends on Google being reachable is wrong regardless. Both browser fixtures now launch Chromium with every hostname but 127.0.0.1 failing DNS at once. Pages fall back to the system font stacks the tokens declare. Positive control in each file: an external host fails with ERR_NAME_NOT_RESOLVED in under 3s, and a Booth page still goes idle. Mutation-proved (r2b.toml 28/28). 776 passed.
285 lines
11 KiB
TOML
285 lines
11 KiB
TOML
# R2b — the Desk row, Reveal all, the theme toggle: every falsifier the
|
|
# contract claims (docs/contracts/r2b_desk_reveal_theme.contract.md), and the
|
|
# change each forbids. Merge 1 is D2 + D2b (the blur half); merge 2 adds D1 + D3.
|
|
|
|
unit = "reveal all, the booth blur toggle (merge 1)"
|
|
|
|
[[mutation]]
|
|
label = "D2 reveal all does not lift the tile's blur"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_reveals_every_blurred_surface_and_survives_the_next_page"
|
|
old = '''
|
|
.reveal-all .item.blurred img,.reveal-all .item.blurred video,'''
|
|
new = '''
|
|
.reveal-all-OFF .item.blurred img,.reveal-all .item.blurred video,'''
|
|
|
|
[[mutation]]
|
|
label = "D2 no pre-paint re-application: the next page of the reel is blurred again"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_reveals_every_blurred_surface_and_survives_the_next_page"
|
|
old = '''
|
|
if (b !== null && sessionStorage.getItem('booth.reveal:' + b) === '1') d.classList.add('reveal-all');'''
|
|
new = '''
|
|
if (false) d.classList.add('reveal-all');'''
|
|
|
|
[[mutation]]
|
|
label = "D2 the reveal is not scoped to the booth (any reveal in the tab reveals every booth)"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_on_booth_a_does_not_reveal_booth_b_or_the_desk"
|
|
old = '''
|
|
if (b !== null && sessionStorage.getItem('booth.reveal:' + b) === '1') d.classList.add('reveal-all');'''
|
|
new = '''
|
|
if (b !== null && sessionStorage.length > 0) d.classList.add('reveal-all');'''
|
|
|
|
[[mutation]]
|
|
label = "D2 per-tile reveal buttons do not stand down under reveal all"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_survives_an_in_place_save"
|
|
old = '''
|
|
.reveal-all .item.blurred .reveal,.reveal-all #vreveal{display:none}'''
|
|
new = '''
|
|
.reveal-all-OFF .item.blurred .reveal,.reveal-all #vreveal{display:none}'''
|
|
|
|
[[mutation]]
|
|
label = "D2 blur again wipes each item's own reveal"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_blur_again_restores_each_items_own_reveal"
|
|
old = '''
|
|
var on = d.classList.toggle('reveal-all');
|
|
try {'''
|
|
new = '''
|
|
var on = d.classList.toggle('reveal-all');
|
|
document.querySelectorAll('.item.revealed').forEach(function (i) { i.classList.remove('revealed'); });
|
|
try {'''
|
|
|
|
[[mutation]]
|
|
label = "D2 a storage write that throws swallows the click"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_never_shows_without_js_and_a_storage_failure_still_applies_the_click"
|
|
old = '''
|
|
var on = d.classList.toggle('reveal-all');
|
|
try {'''
|
|
new = '''
|
|
sessionStorage.setItem(key, '1');
|
|
var on = d.classList.toggle('reveal-all');
|
|
try {'''
|
|
|
|
[[mutation]]
|
|
label = "D2 the control shows without JS (server markup not hidden)"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_never_shows_without_js_and_a_storage_failure_still_applies_the_click"
|
|
old = '''
|
|
{% if all_items | selectattr('blurred') | list %}<button type="button" class="reveal-all-btn" data-reveal-all hidden title='''
|
|
new = '''
|
|
{% if all_items | selectattr('blurred') | list %}<button type="button" class="reveal-all-btn" data-reveal-all title='''
|
|
|
|
[[mutation]]
|
|
label = "D2 the control is markup even when nothing is blurred"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_reveal_all_is_in_the_markup_only_when_something_is_blurred_and_always_hidden"
|
|
old = '''
|
|
{% if all_items | selectattr('blurred') | list %}<button'''
|
|
new = '''
|
|
{% if true %}<button'''
|
|
|
|
[[mutation]]
|
|
label = "D2 the review page does not carry data-booth"
|
|
file = "booth/templates/view.html"
|
|
test = "tests/test_flow.py::test_reveal_all_is_in_the_markup_only_when_something_is_blurred_and_always_hidden"
|
|
old = '''
|
|
{% block html_attrs %} data-booth="{{ name }}"{% endblock %}'''
|
|
new = '''
|
|
{% block html_attrs %}{% endblock %}'''
|
|
|
|
[[mutation]]
|
|
label = "D2b the header control's label does not follow the server's fog state"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_the_booth_blur_toggle_works_without_js_and_lands_back_on_the_review"
|
|
old = '''
|
|
<input type="hidden" name="on" value="{{ '0' if booth_blurred else '1' }}">
|
|
<button title="{{ 'un-blur the whole booth'''
|
|
new = '''
|
|
<input type="hidden" name="on" value="1">
|
|
<button title="{{ 'un-blur the whole booth'''
|
|
|
|
[[mutation]]
|
|
label = "D2b the review's control drops `back` (fogging ejects you from the review)"
|
|
file = "booth/templates/view.html"
|
|
test = "tests/test_flow.py::test_the_booth_blur_toggle_works_without_js_and_lands_back_on_the_review"
|
|
old = '''
|
|
<input type="hidden" name="back" value="{{ file }}">'''
|
|
new = '''
|
|
'''
|
|
|
|
[[mutation]]
|
|
label = "D2b the Desk row does not say a booth is fogged"
|
|
file = "booth/templates/index.html"
|
|
test = "tests/test_flow.py::test_the_booth_blur_toggle_works_without_js_and_lands_back_on_the_review"
|
|
old = '''
|
|
{% if b.booth_blurred %}<span class="badge badge-blur"'''
|
|
new = '''
|
|
{% if false %}<span class="badge badge-blur"'''
|
|
|
|
[[mutation]]
|
|
label = "D2b an item blurred only by the booth offers a per-item un-blur that does nothing"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_under_a_fogged_booth_each_items_blur_control_tells_the_truth"
|
|
old = '''
|
|
{% if it.blurred and not it.blurred_self %}'''
|
|
new = '''
|
|
{% if false %}'''
|
|
|
|
[[mutation]]
|
|
label = "D2b the per-item control reads the composed blur, not the item's own"
|
|
file = "booth/app.py"
|
|
test = "tests/test_flow.py::test_under_a_fogged_booth_each_items_blur_control_tells_the_truth"
|
|
old = '''
|
|
"blurred_self": it.rel in own_blur,'''
|
|
new = '''
|
|
"blurred_self": it.blurred,'''
|
|
|
|
# ---- folds: the heid code-review ("BLITZ-2") and bug-hunt ("FENRIR-6") panels on merge 1
|
|
|
|
[[mutation]]
|
|
label = "a board holding files loses the blur controls its labels point at"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_a_board_with_files_gets_the_blur_controls_its_labels_point_at"
|
|
old = '''
|
|
{% if all_items %}
|
|
{# The fog form IS a region'''
|
|
new = '''
|
|
{% if not board %}
|
|
{# The fog form IS a region'''
|
|
|
|
[[mutation]]
|
|
label = "a blurred doc's own page renders clear"
|
|
file = "booth/templates/doc.html"
|
|
test = "tests/test_flow.py::test_a_blurred_docs_own_page_is_blurred_too"
|
|
old = '''
|
|
<div class="docbody{% if blurred %} is-blurred{% endif %}" id="docbody">'''
|
|
new = '''
|
|
<div class="docbody" id="docbody">'''
|
|
|
|
[[mutation]]
|
|
label = "the review offers Reveal all when only a doc (off the ring) is blurred"
|
|
file = "booth/templates/view.html"
|
|
test = "tests/test_flow.py::test_reveal_all_renders_where_it_can_act"
|
|
old = '''
|
|
{% if film | selectattr('blurred') | list %}<button'''
|
|
new = '''
|
|
{% if true %}<button'''
|
|
|
|
[[mutation]]
|
|
label = "the fog form is a GET (changes nothing with scripts off)"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_the_booth_blur_toggle_works_without_js_and_lands_back_on_the_review"
|
|
old = '''<form class="blur-all{% if booth_blurred %} is-on{% endif %}" method="post" action="/b/{{ name_url }}/blurbooth">
|
|
<input type="hidden" name="on" value="{{ '0' if booth_blurred else '1' }}">
|
|
<button title="{{ 'un-blur the whole booth — per-item'''
|
|
new = '''<form class="blur-all{% if booth_blurred %} is-on{% endif %}" method="get" action="/b/{{ name_url }}/blurbooth">
|
|
<input type="hidden" name="on" value="{{ '0' if booth_blurred else '1' }}">
|
|
<button title="{{ 'un-blur the whole booth — per-item'''
|
|
|
|
[[mutation]]
|
|
label = "the swap stops carrying an item's own reveal"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_an_items_own_reveal_survives_an_in_place_save"
|
|
old = '''
|
|
['revealed', 'is-closed'].forEach(function (c) {'''
|
|
new = '''
|
|
['is-closed'].forEach(function (c) {'''
|
|
|
|
[[mutation]]
|
|
label = "a storage READ that throws raises out of the pre-paint script"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_never_shows_without_js_and_a_storage_failure_still_applies_the_click"
|
|
old = '''
|
|
try {
|
|
if (b !== null && sessionStorage.getItem('booth.reveal:' + b) === '1') d.classList.add('reveal-all');
|
|
} catch (e) {}'''
|
|
new = '''
|
|
if (b !== null && sessionStorage.getItem('booth.reveal:' + b) === '1') d.classList.add('reveal-all');'''
|
|
|
|
[[mutation]]
|
|
label = "fogging writes through a planted marker link"
|
|
file = "booth/app.py"
|
|
test = "tests/test_flow.py::test_fogging_never_writes_through_a_planted_marker_link"
|
|
old = '''
|
|
try:
|
|
os.lstat(marker)
|
|
return True
|
|
except FileNotFoundError:
|
|
pass
|
|
try:
|
|
os.close(os.open(marker, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o644))
|
|
except FileExistsError:
|
|
pass # lost a race to another fog: still fogged
|
|
return True'''
|
|
new = '''
|
|
marker.touch(exist_ok=True)
|
|
return True'''
|
|
|
|
[[mutation]]
|
|
label = "the fog landing echoes `back` unchecked"
|
|
file = "booth/app.py"
|
|
test = "tests/test_flow.py::test_the_fog_landing_is_built_from_the_ring_never_echoed"
|
|
old = '''
|
|
if back and back in review_chain(booth_items(booth)):'''
|
|
new = '''
|
|
if back:'''
|
|
|
|
[[mutation]]
|
|
label = "the fog form is outside every region (a swap leaves its label stale)"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_the_booth_blur_toggle_works_without_js_and_lands_back_on_the_review"
|
|
old = '''
|
|
<span class="region-wrap" data-region="blur-booth"><form class="blur-all'''
|
|
new = '''
|
|
<span class="region-wrap"><form class="blur-all'''
|
|
|
|
[[mutation]]
|
|
label = "Space on a focused review button moves to the next item"
|
|
file = "booth/templates/view.html"
|
|
test = "tests/test_flow_browser.py::test_space_on_a_focused_review_button_presses_it_and_does_not_move_on"
|
|
old = '''e.target !== player && !(e.target.closest && e.target.closest('button, a, summary'))) {'''
|
|
new = '''e.target !== player) {'''
|
|
|
|
[[mutation]]
|
|
label = "the top-bar controls squeeze into multi-line stacks at phone width"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_the_review_and_doc_top_bars_fit_a_phone"
|
|
old = '''
|
|
.blur-all button,.reveal-all-btn{white-space:nowrap}
|
|
@media (max-width:600px){.reveal-all-btn .ra-note{display:none}}'''
|
|
new = '''
|
|
'''
|
|
|
|
[[mutation]]
|
|
label = "the Desk strip under another booth's reveal is lifted by a whisker (blur(0px) is not blurred)"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_on_booth_a_does_not_reveal_booth_b_or_the_desk"
|
|
old = '''
|
|
.blurred-thumb{filter:blur(16px)}'''
|
|
new = '''
|
|
.blurred-thumb{filter:blur(0px)}'''
|
|
|
|
# ---- the flake: the test browser has no internet (positive control per file)
|
|
|
|
[[mutation]]
|
|
label = "the flow test browser can reach the internet (Google Fonts can stall networkidle)"
|
|
file = "tests/test_flow_browser.py"
|
|
test = "tests/test_flow_browser.py::test_the_test_browser_has_no_internet"
|
|
old = '''
|
|
b = pw.chromium.launch(args=OFFLINE)'''
|
|
new = '''
|
|
b = pw.chromium.launch()'''
|
|
|
|
[[mutation]]
|
|
label = "the embed test browser can reach the internet"
|
|
file = "tests/test_embed_browser.py"
|
|
test = "tests/test_embed_browser.py::test_the_test_browser_has_no_internet"
|
|
old = '''
|
|
b = pw.chromium.launch(args=OFFLINE)'''
|
|
new = '''
|
|
b = pw.chromium.launch()'''
|