browser-tests/tests/sync_board.rs
//! ★ **The sync board in a real browser** (Holger v2.0 H6, the coordinator's B6): holger, an
//! upstream with one enrolled downstream, issues an invalidation that the downstream never
//! acknowledges; past the deadline the console's Admin → Sync pane draws holger's own board
//! (`GET /-/sync/board`): the downstream's line in the server's state word, the invalidation
//! that has not reached it, and the ALARM. The console decides none of it.
use holger_ui_browser_tests::browser::{Browser, Tab, NEVER};
use holger_ui_browser_tests::rig::{Rig, CONSOLE};
use monetize_site_buy::testkit::STRIPE;
const COORDINATE: &str = "pypi/demo_pkg-1.0.0-py3-none-any.whl";
/// The login's register panel (as `console.rs` drives it).
async fn register(tab: &Tab, user: &str) {
tab.until("the register button", "!!document.getElementById('register')").await;
tab.js("document.getElementById('reg').open = true").await.unwrap();
tab.fill("#user", user).await;
tab.click("#register").await;
tab.until("registered", holger_ui_browser_tests::browser::SIGNED_IN_OR_REGISTERED).await;
if !tab.signed_in().await {
// A real press: the sign-in starts its passkey only inside the person's gesture (RA2-6).
tab.press("#login").await;
tab.until("holger's session in this tab", holger_ui_browser_tests::browser::SIGNED_IN).await;
}
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn the_sync_pane_draws_holgers_board_and_the_alarm_for_an_unacknowledged_invalidation() {
let rig = Rig::start_upstream_of("dc3", 1).await;
rig.invalidate(COORDINATE, "found after its approval");
// The deadline (1 s) passes with no acknowledgement from dc3.
tokio::time::sleep(std::time::Duration::from_millis(2_500)).await;
let browser = Browser::launch().await.expect("chromium starts");
let owner = browser.tab().await.unwrap();
owner.open(&rig.at("/login")).await.unwrap();
owner.until("the bootstrap door", "!document.getElementById('reg').hidden").await;
owner.fill("#token", CONSOLE).await;
owner.js("document.getElementById('role').value = 'admin'").await.unwrap();
register(&owner, "owner").await;
owner.open(&rig.at("/admin")).await.unwrap();
owner.until("the admin panes", "[...document.querySelectorAll('nav.tabs button')].some(b => b.textContent === 'Sync')").await;
owner.click_text("Sync").await;
owner.until("the sync board", "!!document.querySelector('.sync-board') || !!document.querySelector('.sync-board-none')").await;
let text = owner.text().await;
assert!(owner.shown(".sync-board").await, "the board is drawn: {text}");
// ★ The ALARM, in holger's own words, and dc3's line marked by it.
let alarm = owner.js("(document.querySelector('.sync-alarm') || {}).textContent || ''").await.unwrap();
let alarm = alarm.as_str().unwrap();
assert!(alarm.starts_with("ALARM: dc3: 1 invalidation(s) not acknowledged within 1 s"), "the alarm banner: {alarm:?}\n{text}");
let row = owner.js("(() => { const r = document.querySelector('tr[data-downstream=\"dc3\"]'); return r ? [r.className, r.textContent] : null; })()").await.unwrap();
assert_eq!(row[0], "alarm", "dc3's line carries the alarm: {row}");
let line = row[1].as_str().unwrap();
assert!(line.contains("alarm") && line.contains("none yet") && line.contains("0 of 1 reached"), "{line}");
assert!(line.contains(&format!("{COORDINATE} (malware)")) && line.contains("OVERDUE"), "the pending invalidation: {line}");
// The invalidation's own line: reached nobody, waits for dc3.
assert!(text.contains("malware: found after its approval") && text.contains("dc3"), "{text}");
owner.assert_no_link_to(NEVER).await.unwrap();
browser.assert_nothing_went_to(NEVER, &rig.base, STRIPE);
}