test(cabana): cover the Roles form's holders list (quick-261028-rqg)
- TestRolesHoldersPartial (Docker-free): users partial field, view model guard, links, state lines, escaped strings, empty line, note - TestRolesHolders (Postgres): D-03 hiding, links by manage_users, states, empty role, 100-row cap with note, 403 without manage_roles
This commit is contained in:
@@ -336,3 +336,96 @@ func (e *screensEnv) reloadRoleByCode(t *testing.T, code string) cabana.BackendU
|
||||
}
|
||||
return role
|
||||
}
|
||||
|
||||
// TestRolesHolders: the Roles update form's users partial lists the role's
|
||||
// holders in the editor's D-03 scope, marks their states, links logins only
|
||||
// for editors holding backend.manage_users, shows the empty line, caps the
|
||||
// rows at 100 with a note and is closed to editors without
|
||||
// backend.manage_roles.
|
||||
func TestRolesHolders(t *testing.T) {
|
||||
env := newScreensEnv(t)
|
||||
role := env.seedRole(t, roleSeed{Name: "holders"})
|
||||
active := env.seedAdmin(t, adminSeed{Name: "holder-active", Role: role.ID})
|
||||
inactive := env.seedAdmin(t, adminSeed{Name: "holder-inactive", Role: role.ID, Inactive: true})
|
||||
deleted := env.seedAdmin(t, adminSeed{Name: "holder-deleted", Role: role.ID, Deleted: true})
|
||||
super := env.seedAdmin(t, adminSeed{Name: "holder-super", Role: role.ID, Superuser: true})
|
||||
other := env.seedAdmin(t, adminSeed{Name: "holder-other"})
|
||||
holders := []cabana.BackendUser{active, inactive, deleted, super}
|
||||
|
||||
superEditor := env.seedAdmin(t, adminSeed{Name: "holders-super-editor", Superuser: true})
|
||||
rolesOnly := env.seedAdmin(t, adminSeed{Name: "holders-roles-only",
|
||||
RolePermissions: map[string]int{cabana.PermissionManageRoles: 1}})
|
||||
rolesAndUsers := env.seedAdmin(t, adminSeed{Name: "holders-roles-users",
|
||||
RolePermissions: map[string]int{cabana.PermissionManageRoles: 1, cabana.PermissionManageUsers: 1}})
|
||||
outsider := env.seedAdmin(t, adminSeed{Name: "holders-outsider"})
|
||||
|
||||
partial := func(roleID uint, token string) string {
|
||||
t.Helper()
|
||||
body := env.expect(t, http.StatusOK, http.MethodGet, fmt.Sprintf("%s/partials/users?id=%d", rolesPath, roleID), token, nil)
|
||||
return fmt.Sprint(body["data"])
|
||||
}
|
||||
link := func(id uint) string { return fmt.Sprintf("/backend/summercms/cabana/users/%d/preview", id) }
|
||||
|
||||
// A superuser editor sees every holder, superusers included, with
|
||||
// their states and preview links; an admin of another role is absent.
|
||||
text := partial(role.ID, env.login(t, superEditor.Login))
|
||||
for _, holder := range holders {
|
||||
if !strings.Contains(text, holder.Login) || !strings.Contains(text, link(holder.ID)) {
|
||||
t.Fatalf("superuser editor: holder %s (link %s) missing: %s", holder.Login, link(holder.ID), text)
|
||||
}
|
||||
}
|
||||
for _, state := range []string{"Superuser", "Deactivated", "Deleted"} {
|
||||
if !strings.Contains(text, "text:"+state) {
|
||||
t.Fatalf("superuser editor: state %s missing: %s", state, text)
|
||||
}
|
||||
}
|
||||
if strings.Contains(text, other.Login) {
|
||||
t.Fatalf("superuser editor: admin of another role listed: %s", text)
|
||||
}
|
||||
|
||||
// D-03: a non-superuser editor never sees the superuser holder, and
|
||||
// without backend.manage_users gets no links.
|
||||
text = partial(role.ID, env.login(t, rolesOnly.Login))
|
||||
if strings.Contains(text, super.Login) || strings.Contains(text, "Superuser") {
|
||||
t.Fatalf("D-03: superuser holder shown to a non-superuser editor: %s", text)
|
||||
}
|
||||
if !strings.Contains(text, active.Login) || !strings.Contains(text, deleted.Login) || !strings.Contains(text, inactive.Login) {
|
||||
t.Fatalf("manage_roles editor: holders missing: %s", text)
|
||||
}
|
||||
if strings.Contains(text, "/summercms/cabana/users/") {
|
||||
t.Fatalf("manage_roles editor without manage_users got preview links: %s", text)
|
||||
}
|
||||
text = partial(role.ID, env.login(t, rolesAndUsers.Login))
|
||||
if strings.Contains(text, super.Login) {
|
||||
t.Fatalf("D-03: superuser holder shown to a non-superuser editor: %s", text)
|
||||
}
|
||||
if !strings.Contains(text, link(active.ID)) {
|
||||
t.Fatalf("manage_users editor: preview link missing: %s", text)
|
||||
}
|
||||
|
||||
// A role nobody holds shows the empty line.
|
||||
superToken := env.login(t, superEditor.Login)
|
||||
empty := env.seedRole(t, roleSeed{Name: "holders-empty"})
|
||||
if text := partial(empty.ID, superToken); !strings.Contains(text, "No administrator has this role.") {
|
||||
t.Fatalf("empty role: %s", text)
|
||||
}
|
||||
|
||||
// Without backend.manage_roles the partial route is denied.
|
||||
env.expectRefusal(t, http.StatusForbidden, http.MethodGet, fmt.Sprintf("%s/partials/users?id=%d", rolesPath, role.ID),
|
||||
env.login(t, outsider.Login), nil, "")
|
||||
|
||||
// 101 holders: the first 100 are listed, with the note naming the total.
|
||||
crowded := env.seedRole(t, roleSeed{Name: "holders-crowded"})
|
||||
prefix := "crowd-" + env.stamp + "-"
|
||||
for i := 0; i < 101; i++ {
|
||||
env.seedAdmin(t, adminSeed{Name: "crowd", Role: crowded.ID})
|
||||
}
|
||||
text = partial(crowded.ID, superToken)
|
||||
// Each listed login appears twice: as the login and in the email.
|
||||
if got := strings.Count(text, prefix); got != 200 {
|
||||
t.Fatalf("crowded role: %d login occurrences, want 200 (100 rows): %s", got, text)
|
||||
}
|
||||
if !strings.Contains(text, "Showing the first 100 of 101 administrators") {
|
||||
t.Fatalf("crowded role: note missing: %s", text)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user