Files
MeshTender/internal/e2e/console_sidebar_test.go
T

94 lines
3.6 KiB
Go

//go:build browser
package e2e
import (
"testing"
cdplog "github.com/chromedp/cdproto/log"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
)
// TestE2EConsoleSidebarOrgAdmin is the browser regression for the empty-sidebar
// bug: an org admin who reaches another member's participating repeater via the
// shared org must see the org-ceiling commands in the "Allowed commands" sidebar,
// not an empty list. Before the fix the sidebar (core.allowedCommands) omitted
// the org-participation path, so it rendered "No commands allowed here yet." even
// though the server would accept those commands when typed manually.
func TestE2EConsoleSidebarOrgAdmin(t *testing.T) {
srv := newE2EServer(t)
// The repeater owner: an org member whose repeater participates by default.
owner, err := srv.store.CreateUser(srv.ctx, "rep-owner", "")
if err != nil {
t.Fatalf("create owner: %v", err)
}
rep := srv.newRepeater(t, owner.ID, "Owner Rep")
// CreateOrg makes the creator (owner) an admin member; the owner's repeater
// participates automatically (not opted out).
org, err := srv.store.CreateOrg(srv.ctx, "Mesh Org", owner.ID)
if err != nil {
t.Fatalf("create org: %v", err)
}
// Put at least one command in the org member ceiling so any member/admin of the
// org is authorized to run it — deterministic regardless of catalog defaults.
cmds, err := srv.store.ListCommands(srv.ctx)
if err != nil || len(cmds) == 0 {
t.Fatalf("list commands: %v (n=%d)", err, len(cmds))
}
if err := srv.store.UpdateCommandFlags(srv.ctx, cmds[0].ID, false, false, true, false); err != nil {
t.Fatalf("set ceiling: %v", err)
}
// The reporter: a second admin of the same org, browsing. Not the owner, not a
// steward, with no per-command share — reaches the repeater only via the org.
reporter, cookie := srv.login(t, "reporter")
if err := srv.store.AddOrgMember(srv.ctx, org.ID, reporter.ID, "admin"); err != nil {
t.Fatalf("add reporter to org: %v", err)
}
// Precondition: the reporter can reach the repeater via org access (otherwise
// the console page 404s and the assertions below would hang on WaitVisible).
if _, err := srv.store.GetRepeaterForUser(srv.ctx, reporter.ID, rep.ID); err != nil {
t.Fatalf("reporter lacks org access to repeater: %v", err)
}
bctx, cancel, watch := startBrowser(t)
defer cancel()
url := srv.appURL + "/repeaters/" + rep.PublicID + "/console"
// The "Allowed commands" sidebar is always rendered (unlike #cmdinput, which is
// hidden until a WebSerial modem connects). Command chips carry data-template
// (the hook the console JS uses to fill the input); the empty state renders a
// "No commands allowed here yet" paragraph instead.
const countChips = `document.querySelectorAll('[data-testid="allowed-commands"] .chip[data-template]').length`
const emptyShown = `!!Array.prototype.find.call(document.querySelectorAll('[data-testid="allowed-commands"] p'), function (p) { return /No commands allowed here yet/.test(p.textContent); })`
var chips int
var empty bool
if err := chromedp.Run(bctx,
network.Enable(),
cdplog.Enable(),
setSessionCookie(cookie),
chromedp.Navigate(url),
chromedp.WaitVisible(`[data-testid="allowed-commands"]`, chromedp.ByQuery),
chromedp.Evaluate(countChips, &chips),
chromedp.Evaluate(emptyShown, &empty),
); err != nil {
t.Fatalf("browser run against %s: %v", url, err)
}
if chips == 0 {
t.Fatal("org admin console sidebar is empty (regression: org-participation path missing)")
}
if empty {
t.Fatalf("console shows the empty-state message despite %d command chips", chips)
}
watch.assertClean(t)
}