Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 41 additions & 69 deletions tests/utils/groups.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,4 @@
import { TEST_CONFIG } from "../config/test-env";

const ADMIN_HEADERS = {
"Content-Type": "application/json",
apikey: TEST_CONFIG.SUPABASE_SERVICE_ROLE_KEY,
Authorization: `Bearer ${TEST_CONFIG.SUPABASE_SERVICE_ROLE_KEY}`,
};

async function getUserIdByEmail(email: string): Promise<string> {
const response = await fetch(
`${TEST_CONFIG.SUPABASE_URL}/rest/v1/profiles?email=eq.${encodeURIComponent(email)}&select=id`,
{ headers: ADMIN_HEADERS },
);

if (!response.ok) {
throw new Error(
`Failed to look up profile for ${email}: ${response.status}`,
);
}

const [profile] = (await response.json()) as { id: string }[];

if (!profile) {
throw new Error(`No profile found for ${email}`);
}

return profile.id;
}
import { adminClient } from "./supabaseAdmin";

// Creates a group and adds the given user as its sole member, so
// single-group auto-activation kicks in for them.
Expand All @@ -35,38 +8,26 @@ export async function createGroupWithMember(
): Promise<{ groupId: string; groupName: string }> {
const userId = await getUserIdByEmail(email);

const groupResponse = await fetch(
`${TEST_CONFIG.SUPABASE_URL}/rest/v1/groups`,
{
method: "POST",
headers: { ...ADMIN_HEADERS, Prefer: "return=representation" },
body: JSON.stringify({
name: groupName,
slug: groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
created_by: userId,
}),
},
);

if (!groupResponse.ok) {
throw new Error(`Failed to create test group: ${groupResponse.status}`);
const { data: group, error: groupError } = await adminClient
.from("groups")
.insert({
name: groupName,
slug: groupName.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
created_by: userId,
})
.select("id")
.single();

if (groupError) {
throw new Error(`Failed to create test group: ${groupError.message}`);
}

const [group] = (await groupResponse.json()) as { id: string }[];

const memberResponse = await fetch(
`${TEST_CONFIG.SUPABASE_URL}/rest/v1/group_members`,
{
method: "POST",
headers: { ...ADMIN_HEADERS, Prefer: "return=minimal" },
body: JSON.stringify({ group_id: group.id, user_id: userId }),
},
);
const { error: memberError } = await adminClient
.from("group_members")
.insert({ group_id: group.id, user_id: userId });

if (!memberResponse.ok) {
throw new Error(
`Failed to add test group member: ${memberResponse.status}`,
);
if (memberError) {
throw new Error(`Failed to add test group member: ${memberError.message}`);
}

return { groupId: group.id, groupName };
Expand All @@ -79,18 +40,29 @@ export async function addMemberToGroup(
): Promise<void> {
const userId = await getUserIdByEmail(email);

const memberResponse = await fetch(
`${TEST_CONFIG.SUPABASE_URL}/rest/v1/group_members`,
{
method: "POST",
headers: { ...ADMIN_HEADERS, Prefer: "return=minimal" },
body: JSON.stringify({ group_id: groupId, user_id: userId }),
},
);
const { error } = await adminClient
.from("group_members")
.insert({ group_id: groupId, user_id: userId });

if (error) {
throw new Error(`Failed to add test group member: ${error.message}`);
}
}

async function getUserIdByEmail(email: string): Promise<string> {
const { data: profile, error } = await adminClient
.from("profiles")
.select("id")
.eq("email", email)
.maybeSingle();

if (error) {
throw new Error(`Failed to look up profile for ${email}: ${error.message}`);
}

if (!memberResponse.ok) {
throw new Error(
`Failed to add test group member: ${memberResponse.status}`,
);
if (!profile) {
throw new Error(`No profile found for ${email}`);
}

return profile.id;
}
9 changes: 1 addition & 8 deletions tests/utils/linkWizardArtist.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import { createClient } from "@supabase/supabase-js";
import type { Database } from "../../src/integrations/supabase/types";
import { TEST_CONFIG } from "../config/test-env";

const adminClient = createClient<Database>(
TEST_CONFIG.SUPABASE_URL,
TEST_CONFIG.SUPABASE_SERVICE_ROLE_KEY,
);
import { adminClient } from "./supabaseAdmin";

// Seeded via supabase/seed.sql: festival "test", edition "2025" ("Boom Festival 2025"),
// stage "Club Stage".
Expand Down
70 changes: 27 additions & 43 deletions tests/utils/login.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Page, expect } from "@playwright/test";
import { TEST_CONFIG } from "../config/test-env";
import { fetchOtpCode } from "./otp";
import { adminClient } from "./supabaseAdmin";

// Signs in via the OTP flow, pre-onboarding the voter so onboarding never shows here.
export async function signIn(page: Page, email = generateTestEmail()) {
Expand Down Expand Up @@ -85,63 +86,46 @@ export function generateTestEmail(
return `${TEST_CONFIG.TEST_USER_EMAIL_BASE}-${suffix}@${TEST_CONFIG.TEST_USER_EMAIL_DOMAIN}`;
}

const ADMIN_HEADERS = {
"Content-Type": "application/json",
apikey: TEST_CONFIG.SUPABASE_SERVICE_ROLE_KEY,
Authorization: `Bearer ${TEST_CONFIG.SUPABASE_SERVICE_ROLE_KEY}`,
};

// Pre-creates an already-onboarded voter via the admin API so OTP sign-in never shows onboarding.
async function createPreOnboardedUser(email: string): Promise<string> {
const username = email.split("@")[0];

const createResponse = await fetch(
`${TEST_CONFIG.SUPABASE_URL}/auth/v1/admin/users`,
{
method: "POST",
headers: ADMIN_HEADERS,
body: JSON.stringify({
email,
email_confirm: true,
user_metadata: { username },
}),
},
);

if (!createResponse.ok) {
const { data, error: createError } = await adminClient.auth.admin.createUser({
email,
email_confirm: true,
user_metadata: { username },
});

if (createError) {
throw new Error(
`Failed to pre-create onboarded test user ${email}: ${createResponse.status}`,
`Failed to pre-create onboarded test user ${email}: ${createError.message}`,
);
}

const { id } = (await createResponse.json()) as { id: string };
const { error: updateError } = await adminClient
.from("profiles")
.update({ completed_onboarding: true })
.eq("id", data.user.id);

await fetch(`${TEST_CONFIG.SUPABASE_URL}/rest/v1/profiles?id=eq.${id}`, {
method: "PATCH",
headers: { ...ADMIN_HEADERS, Prefer: "return=minimal" },
body: JSON.stringify({ completed_onboarding: true }),
});
if (updateError) {
throw new Error(
`Failed to mark test user ${email} onboarded: ${updateError.message}`,
);
}

return id;
return data.user.id;
}

async function grantAdminRole(userId: string): Promise<void> {
const response = await fetch(
`${TEST_CONFIG.SUPABASE_URL}/rest/v1/admin_roles`,
{
method: "POST",
headers: { ...ADMIN_HEADERS, Prefer: "return=minimal" },
body: JSON.stringify({
user_id: userId,
role: "admin",
created_by: userId,
}),
},
);

if (!response.ok) {
const { error } = await adminClient.from("admin_roles").insert({
user_id: userId,
role: "admin",
created_by: userId,
});

if (error) {
throw new Error(
`Failed to grant admin role to test user ${userId}: ${response.status} ${await response.text()}`,
`Failed to grant admin role to test user ${userId}: ${error.message}`,
);
}
}
8 changes: 8 additions & 0 deletions tests/utils/supabaseAdmin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createClient } from "@supabase/supabase-js";
import type { Database } from "../../src/integrations/supabase/types";
import { TEST_CONFIG } from "../config/test-env";

export const adminClient = createClient<Database>(
TEST_CONFIG.SUPABASE_URL,
TEST_CONFIG.SUPABASE_SERVICE_ROLE_KEY,
);
Loading