diff options
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/meshbay-hub/tests/harness/invite_link_probe.py | 23 | ||||
| -rw-r--r-- | packages/meshbay-hub/tests/test_invite_link_flow.py | 17 |
2 files changed, 35 insertions, 5 deletions
diff --git a/packages/meshbay-hub/tests/harness/invite_link_probe.py b/packages/meshbay-hub/tests/harness/invite_link_probe.py index 97ee893..b0a833e 100644 --- a/packages/meshbay-hub/tests/harness/invite_link_probe.py +++ b/packages/meshbay-hub/tests/harness/invite_link_probe.py @@ -13,6 +13,9 @@ Loads the shipped `app.js` in a real browser with `fetch` stubbed, twice: signed_out — a link, no session signed_in — the same link, a session; then the Join button is clicked + signed_in_listed — the same, with the hub listing the group once joined, as + it does: the group page opens and the address shows its handle + (`#/name@owner`, group-link.js) invite_link_probe.py @@ -56,7 +59,15 @@ window.fetch = async (url, init = {}) => { calls.push({ url: u, body: init.body ? String(init.body) : '' }); if (u.includes('/v1/users/me/preferences')) return json({}); if (u.includes('/v1/users/me')) return json({ user_id: 'u-1', role: 'user' }); - if (u.includes('/v1/groups/mine')) return json({ groups: [] }); + // Joined, the hub lists the group — in the one case that says so. The others + // keep an empty list, so the address stays the `#/group/<id>` the Join + // button navigated to and is read before the router could rewrite it. + if (u.includes('/v1/groups/mine')) return json({ groups: + CASE === 'signed_in_listed' && calls.some((c) => c.url.includes('/redeem')) + ? [{ id: '__GROUP__', name: 'Some Group', owner_username: 'the-owner', + visibility: 'private', created_at: '2026-01-01T00:00:00+00:00', + description: '' }] + : [] }); if (u.includes('/v1/invite-links/preview')) return json({ group_id: '__GROUP__', group_name: 'Some Group', inviter: 'the-owner', expires_at: '2099-01-01T00:00:00+00:00', already_member: false }); @@ -65,7 +76,7 @@ window.fetch = async (url, init = {}) => { if (u.includes('/nodes')) return json({ nodes: [] }); return json({}); }; -if (CASE === 'signed_in') { +if (CASE.startsWith('signed_in')) { localStorage.setItem('mb_auth', JSON.stringify({ username: 'invitee-account', userId: 'u-1', token: 'tok', refreshToken: 'ref', role: 'user' })); @@ -98,6 +109,12 @@ const text = () => document.getElementById('app').innerText; out.join_button = Boolean(join); if (join) { join.click(); await wait(1500); } out.hash_after_click = location.hash; + if (CASE === 'signed_in_listed') { + await wait(1500); + out.hash_settled = decodeURI(location.hash); + out.group_page = Boolean(document.querySelector('.group-header')); + out.history_length = history.length; + } out.redeem_bodies = calls.filter((c) => c.url.includes('/redeem')).map((c) => c.body); } out.code_in_a_hub_request = calls.some( @@ -169,7 +186,7 @@ def _run(case: str) -> dict | None: def main() -> int: with socketserver.TCPServer(("127.0.0.1", PORT), H) as srv: threading.Thread(target=srv.serve_forever, daemon=True).start() - results = [_run("signed_out"), _run("signed_in")] + results = [_run("signed_out"), _run("signed_in"), _run("signed_in_listed")] if not all(results): print(json.dumps({"error": "no measurement", "got": results}), file=sys.stderr) return 1 diff --git a/packages/meshbay-hub/tests/test_invite_link_flow.py b/packages/meshbay-hub/tests/test_invite_link_flow.py index 42f461c..cc8b432 100644 --- a/packages/meshbay-hub/tests/test_invite_link_flow.py +++ b/packages/meshbay-hub/tests/test_invite_link_flow.py @@ -33,14 +33,14 @@ def cases(): return out -@pytest.mark.parametrize("case", ["signed_out", "signed_in"]) +@pytest.mark.parametrize("case", ["signed_out", "signed_in", "signed_in_listed"]) def test_the_code_is_out_of_the_address_and_kept_in_the_tab(cases, case): c = cases[case] assert c["hash_after_load"] == "#/invite" assert c["pending"] and c["pending"]["c"] == "K7P2-9WQX" -@pytest.mark.parametrize("case", ["signed_out", "signed_in"]) +@pytest.mark.parametrize("case", ["signed_out", "signed_in", "signed_in_listed"]) def test_the_code_never_reaches_the_hub(cases, case): assert cases[case]["code_in_a_hub_request"] is False @@ -59,3 +59,16 @@ def test_a_signed_in_reader_joins_with_one_click_and_lands_on_the_group(cases): assert c["join_button"] assert c["redeem_bodies"] == ['{"ticket":"AbCdEfGhIjKlMnOpQr-_12"}'] assert c["hash_after_click"] == "#/group/0f8fad5b-d9cb-469f-a165-70867728950e" + + +def test_once_listed_the_joined_group_opens_under_its_handle(cases): + """The group links (group-link.js) rewrite `#/group/<id>` to the handle as + soon as the hub lists the group. Joining from an invitation must land on + the group page all the same, under that handle, with the rewrite adding + no history entry of its own — and still without the code reaching the hub.""" + c = cases["signed_in_listed"] + assert c["join_button"] + assert c["hash_settled"] == "#/Some Group@the-owner" + assert c["group_page"] is True + # The page load, then the Join button's navigation; the rewrite replaces. + assert c["history_length"] == 2 |