Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger-ui

browser-tests/tests/sync_revoke.rs

//! ★ **The sync board's Revoke button in a real browser**: holger, an upstream with one
//! enrolled downstream `dc4`, behind the console router. The owner, signed in as an admin,
//! opens Admin → Sync in two tabs. In the first, Revoke: holger's door
//! (`POST /-/sync/downstreams/revoke`) revokes `dc4` and the page says so in holger's words;
//! holger no longer lists it. In the second tab (still drawn from before), Revoke again: holger
//! refuses (`dc4` is not a live downstream any more) and the page shows that refusal, verbatim,
//! instead of nothing.

use holger_ui_browser_tests::browser::{Browser, Tab, NEVER};
use holger_ui_browser_tests::rig::{Rig, CONSOLE};
use monetize_site_buy::testkit::STRIPE;

const DOWNSTREAM: &str = "dc4";

/// 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;
    }
}

/// Admin → Sync, the board drawn with `dc4`'s line.
async fn sync_pane(tab: &Tab, rig: &Rig) {
    tab.open(&rig.at("/admin")).await.unwrap();
    tab.until("the admin panes", "[...document.querySelectorAll('nav.tabs button')].some(b => b.textContent === 'Sync')").await;
    tab.click_text("Sync").await;
    tab.until("dc4's line", &format!("!!document.querySelector('tr[data-downstream=\"{DOWNSTREAM}\"] button')")).await;
}

/// `dc4`'s Revoke button. A row holger marks invitable also has "Invite" before it
/// (HOL-PRODUCTS-7, c20021b), so "the row's button" is not Revoke: the danger button is.
fn revoke_button() -> String {
    format!("tr[data-downstream=\"{DOWNSTREAM}\"] button.danger")
}

const SAID: &str = "(document.querySelector('.sync-revoke-said') || {}).textContent || ''";

#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn revoke_on_the_sync_board_says_holgers_answer_and_its_refusal() {
    let rig = Rig::start_upstream_of(DOWNSTREAM, 3600).await;
    let (status, board) = rig.console_get("/-/sync/board");
    assert!(status == 200 && board.contains(&format!("\"{DOWNSTREAM}\"")), "holger lists dc4 first: {status} {board}");

    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;
    sync_pane(&owner, &rig).await;
    // The same person's second tab, drawn before the revocation.
    let stale = browser.tab().await.unwrap();
    sync_pane(&stale, &rig).await;

    // ★ Revoke: holger revokes dc4 and the page says so.
    owner.click(&revoke_button()).await;
    owner.until("the revocation's answer", &format!("({SAID}).length > 0")).await;
    let said = owner.js(SAID).await.unwrap();
    let said = said.as_str().unwrap().to_owned();
    assert!(said.contains(DOWNSTREAM) && said.contains("revoked"), "the page says holger's answer: {said:?}\n{}", owner.text().await);
    assert!(!owner.shown(".err.sync-revoke-said").await, "a revocation holger made is no refusal: {said}");
    let (status, board) = rig.console_get("/-/sync/board");
    assert!(status == 200 && !board.contains(&format!("\"{DOWNSTREAM}\"")), "holger lists dc4 no more: {board}");

    // ★ The stale tab's Revoke: holger refuses, and the page shows the refusal.
    stale.click(&revoke_button()).await;
    stale.until("the refusal", "!!document.querySelector('.err.sync-revoke-said')").await;
    let refusal = stale.js(SAID).await.unwrap();
    let refusal = refusal.as_str().unwrap();
    assert!(refusal.contains("is not a live downstream of this Holger"), "holger's own sentence: {refusal:?}");
    assert!(refusal.contains("404"), "and its status: {refusal:?}");

    owner.assert_no_link_to(NEVER).await.unwrap();
    browser.assert_nothing_went_to(NEVER, &rig.base, STRIPE);
}