mirror of
https://github.com/Sea-Haven-Industries/meal-order-manager.git
synced 2026-10-07 16:18:54 +00:00
test(form): cover a11y labels, status region, and desc toggle
Structural checks for dual status nodes and no alert(); Playwright for init-time qty labels, aria-pressed chips, overflow More/Less, and failed-submit text landing in role=alert.
This commit is contained in:
parent
d05de42104
commit
cf8ad2baea
1 changed files with 119 additions and 0 deletions
|
|
@ -171,6 +171,26 @@ class TestGenerateFormStructural:
|
||||||
assert "data-meal-index" in html
|
assert "data-meal-index" in html
|
||||||
assert "data-qty-delta" in html
|
assert "data-qty-delta" in html
|
||||||
|
|
||||||
|
def test_a11y_status_and_live_total_markup(self):
|
||||||
|
html = _render()
|
||||||
|
assert 'id="form-status-alert"' in html
|
||||||
|
assert 'id="form-status-info"' in html
|
||||||
|
assert 'id="admin-status-alert"' in html
|
||||||
|
assert 'id="admin-status-info"' in html
|
||||||
|
assert 'role="alert"' in html
|
||||||
|
assert 'role="status"' in html
|
||||||
|
assert 'aria-live="polite"' in html
|
||||||
|
assert 'id="success-heading"' in html
|
||||||
|
assert 'tabindex="-1"' in html
|
||||||
|
|
||||||
|
def test_no_alert_dialogs_in_form_scripts(self):
|
||||||
|
form_js = (SERVER_DIR / "templates" / "form.js").read_text()
|
||||||
|
admin_js = (SERVER_DIR / "templates" / "admin.js").read_text()
|
||||||
|
assert "alert(" not in form_js
|
||||||
|
assert "alert(" not in admin_js
|
||||||
|
# confirm() retained for destructive admin delete / zero-qty save.
|
||||||
|
assert "confirm(" in admin_js
|
||||||
|
|
||||||
def test_design_tokens_only_in_definitions(self):
|
def test_design_tokens_only_in_definitions(self):
|
||||||
css = (SERVER_DIR / "templates" / "form.css").read_text()
|
css = (SERVER_DIR / "templates" / "form.css").read_text()
|
||||||
# Strip :root block, then assert brand/muted/border hexes are gone
|
# Strip :root block, then assert brand/muted/border hexes are gone
|
||||||
|
|
@ -273,6 +293,105 @@ class TestGenerateFormPlaywright:
|
||||||
assert page.locator("#count-display").inner_text() == "2 meals"
|
assert page.locator("#count-display").inner_text() == "2 meals"
|
||||||
assert page.locator("#total-display").inner_text() == "$10.80"
|
assert page.locator("#total-display").inner_text() == "$10.80"
|
||||||
|
|
||||||
|
def test_qty_labels_present_after_init(self, browser_page):
|
||||||
|
page = browser_page
|
||||||
|
card = page.locator('[data-meal-index="0"]')
|
||||||
|
assert (
|
||||||
|
card.locator('[data-qty-delta="-1"]').get_attribute("aria-label")
|
||||||
|
== "Remove one Chicken Bowl"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
card.locator('[data-qty-delta="1"]').get_attribute("aria-label")
|
||||||
|
== "Add one Chicken Bowl"
|
||||||
|
)
|
||||||
|
assert card.locator(".qty").get_attribute("aria-label") == "Quantity of Chicken Bowl"
|
||||||
|
|
||||||
|
def test_filter_chip_aria_pressed(self, browser_page):
|
||||||
|
page = browser_page
|
||||||
|
all_btn = page.locator("#filters button", has_text="All Meals")
|
||||||
|
assert all_btn.get_attribute("aria-pressed") == "true"
|
||||||
|
other = page.locator("#filters button").nth(1)
|
||||||
|
other_label = other.inner_text()
|
||||||
|
other.click()
|
||||||
|
page.wait_for_function(
|
||||||
|
"""(label) => {
|
||||||
|
const active = document.querySelector('#filters button.active');
|
||||||
|
return active && active.textContent === label
|
||||||
|
&& active.getAttribute('aria-pressed') === 'true';
|
||||||
|
}""",
|
||||||
|
arg=other_label,
|
||||||
|
)
|
||||||
|
assert all_btn.get_attribute("aria-pressed") == "false"
|
||||||
|
assert other.get_attribute("aria-pressed") == "true"
|
||||||
|
all_btn.click()
|
||||||
|
page.wait_for_function(
|
||||||
|
"""() => {
|
||||||
|
const active = document.querySelector('#filters button.active');
|
||||||
|
return active && active.textContent === 'All Meals'
|
||||||
|
&& active.getAttribute('aria-pressed') === 'true';
|
||||||
|
}"""
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_desc_more_only_when_overflow(self, browser_page):
|
||||||
|
page = browser_page
|
||||||
|
# Ensure All Meals filter so both short and long cards are visible.
|
||||||
|
page.locator("#filters button", has_text="All Meals").click()
|
||||||
|
page.wait_for_selector('[data-meal-index="0"]')
|
||||||
|
page.wait_for_selector('[data-meal-index="1"]')
|
||||||
|
short_card = page.locator('[data-meal-index="0"]')
|
||||||
|
long_card = page.locator('[data-meal-index="1"]')
|
||||||
|
page.wait_for_function(
|
||||||
|
"""() => {
|
||||||
|
const long = document.querySelector('[data-meal-index="1"] .meal-desc-toggle');
|
||||||
|
return !!long;
|
||||||
|
}"""
|
||||||
|
)
|
||||||
|
assert short_card.locator(".meal-desc-toggle").count() == 0
|
||||||
|
toggle = long_card.locator(".meal-desc-toggle")
|
||||||
|
assert toggle.inner_text() == "More"
|
||||||
|
assert toggle.get_attribute("aria-expanded") == "false"
|
||||||
|
toggle.click()
|
||||||
|
assert toggle.inner_text() == "Less"
|
||||||
|
assert toggle.get_attribute("aria-expanded") == "true"
|
||||||
|
assert "is-expanded" in (
|
||||||
|
long_card.locator(".meal-desc").get_attribute("class") or ""
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_submit_failure_lands_in_alert_region(self, browser_page):
|
||||||
|
page = browser_page
|
||||||
|
page.route(
|
||||||
|
"**/api/submit-order**",
|
||||||
|
lambda route: route.fulfill(
|
||||||
|
status=500,
|
||||||
|
content_type="application/json",
|
||||||
|
body='{"error":"Simulated submit failure"}',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
page.locator("#emp-name").select_option(label="Ada Lovelace")
|
||||||
|
page.evaluate(
|
||||||
|
"""() => {
|
||||||
|
document.querySelectorAll('[data-meal-index] .qty').forEach((input) => {
|
||||||
|
input.value = '0';
|
||||||
|
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||||
|
});
|
||||||
|
}"""
|
||||||
|
)
|
||||||
|
page.wait_for_function(
|
||||||
|
"() => document.getElementById('count-display').textContent === '0 meals'"
|
||||||
|
)
|
||||||
|
page.locator('[data-meal-index="0"] [data-qty-delta="1"]').click()
|
||||||
|
page.wait_for_function(
|
||||||
|
"() => document.getElementById('count-display').textContent === '1 meal'"
|
||||||
|
)
|
||||||
|
page.locator("#submit-btn").click()
|
||||||
|
page.wait_for_function(
|
||||||
|
"""() => document.getElementById('form-status-alert').textContent
|
||||||
|
=== 'Simulated submit failure'"""
|
||||||
|
)
|
||||||
|
assert page.locator("#form-status-alert").inner_text() == "Simulated submit failure"
|
||||||
|
assert page.locator("#form-status-info").inner_text() == ""
|
||||||
|
page.unroute("**/api/submit-order**")
|
||||||
|
|
||||||
def test_qty_typein_clamps_negative(self, browser_page):
|
def test_qty_typein_clamps_negative(self, browser_page):
|
||||||
page = browser_page
|
page = browser_page
|
||||||
# Reset first card via type-in
|
# Reset first card via type-in
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue