snapshot of https://github.com/marmelab/atomic-crm.git (main, 2026-09-18; blobs > 131072B omitted)
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
This commit is contained in:
264
e2e/fixtures.ts
Normal file
264
e2e/fixtures.ts
Normal file
@@ -0,0 +1,264 @@
|
||||
import { test as base, expect, type Page } from "@playwright/test";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const adminSupabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL ?? "http://127.0.0.1:54341",
|
||||
process.env.SERVICE_ROLE_KEY!,
|
||||
{ auth: { autoRefreshToken: false, persistSession: false } },
|
||||
);
|
||||
|
||||
// Tables in FK-safe deletion order (children before parents)
|
||||
const TABLES = [
|
||||
"tasks",
|
||||
"contact_notes",
|
||||
"deal_notes",
|
||||
"deals",
|
||||
"contacts",
|
||||
"companies",
|
||||
"tags",
|
||||
"favicons_excluded_domains",
|
||||
"configuration",
|
||||
"sales",
|
||||
];
|
||||
|
||||
async function resetDb() {
|
||||
for (const table of TABLES) {
|
||||
// Supabase client delete need a where clause to get executed, so we use one that will match on all rows (id is not null)
|
||||
await adminSupabase.from(table).delete().not("id", "is", null);
|
||||
}
|
||||
|
||||
// Delete all auth users (cascades to sales via DB trigger)
|
||||
const { data } = await adminSupabase.auth.admin.listUsers();
|
||||
await Promise.all(
|
||||
data.users.map((user) => adminSupabase.auth.admin.deleteUser(user.id)),
|
||||
);
|
||||
}
|
||||
|
||||
async function createUser({
|
||||
email,
|
||||
password,
|
||||
}: {
|
||||
email: string;
|
||||
password: string;
|
||||
}) {
|
||||
const { data, error } = await adminSupabase.auth.admin.createUser({
|
||||
email,
|
||||
password,
|
||||
email_confirm: true,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to create user: ${error.message}`);
|
||||
}
|
||||
|
||||
return data.user;
|
||||
}
|
||||
|
||||
async function createSales({
|
||||
first_name,
|
||||
last_name,
|
||||
email,
|
||||
password,
|
||||
administrator = false,
|
||||
}: {
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
email: string;
|
||||
password: string;
|
||||
administrator?: boolean;
|
||||
}) {
|
||||
const { data: userData, error: userError } =
|
||||
await adminSupabase.auth.admin.createUser({
|
||||
email,
|
||||
password,
|
||||
email_confirm: true,
|
||||
});
|
||||
|
||||
if (userError) {
|
||||
throw new Error(`Failed to create sales: ${userError.message}`);
|
||||
}
|
||||
|
||||
const { data, error } = await adminSupabase
|
||||
.from("sales")
|
||||
.update({ first_name, last_name, administrator })
|
||||
.eq("user_id", userData.user?.id)
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to create sales: ${error.message}`);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async function createNotes({
|
||||
contactId,
|
||||
salesId,
|
||||
notes,
|
||||
}: {
|
||||
contactId: string | number;
|
||||
salesId: string | number;
|
||||
notes: {
|
||||
text: string;
|
||||
date?: string;
|
||||
status?: "cold" | "warm" | "hot";
|
||||
}[];
|
||||
}) {
|
||||
if (notes.length === 0) return;
|
||||
|
||||
const { error } = await adminSupabase.from("contact_notes").insert(
|
||||
notes.map(({ text, date, status = "cold" }) => ({
|
||||
contact_id: contactId,
|
||||
sales_id: salesId,
|
||||
text,
|
||||
date,
|
||||
status,
|
||||
})),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to create notes: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function createCompany({
|
||||
name,
|
||||
salesId,
|
||||
}: {
|
||||
name: string;
|
||||
salesId: string | number;
|
||||
}) {
|
||||
const { data, error } = await adminSupabase
|
||||
.from("companies")
|
||||
.insert({ name, sales_id: salesId })
|
||||
.select("id")
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to create company: ${error.message}`);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async function createContact({
|
||||
first_name,
|
||||
last_name,
|
||||
title = "",
|
||||
company_id = null,
|
||||
sales_id,
|
||||
notes = [],
|
||||
}: {
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
title?: string;
|
||||
company_id?: string | number | null;
|
||||
sales_id: string | number;
|
||||
notes?: {
|
||||
text: string;
|
||||
date?: string;
|
||||
status?: "cold" | "warm" | "hot";
|
||||
}[];
|
||||
}) {
|
||||
const { data, error } = await adminSupabase
|
||||
.from("contacts")
|
||||
.insert({
|
||||
first_name,
|
||||
last_name,
|
||||
title,
|
||||
company_id,
|
||||
sales_id,
|
||||
first_seen: new Date().toISOString(),
|
||||
last_seen: new Date().toISOString(),
|
||||
has_newsletter: false,
|
||||
tags: [],
|
||||
gender: "unknown",
|
||||
status: "cold",
|
||||
background: "",
|
||||
email_jsonb: [],
|
||||
phone_jsonb: [],
|
||||
})
|
||||
.select("id")
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Failed to create contact: ${error.message}`);
|
||||
}
|
||||
|
||||
await createNotes({
|
||||
contactId: data.id,
|
||||
salesId: sales_id,
|
||||
notes,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const getMenuMethod = ({ page }: { page: Page; isMobile: boolean }) => ({
|
||||
goToDashboard: async () => {
|
||||
await page.getByRole("link", { name: "Dashboard" }).click();
|
||||
await page.waitForLoadState("networkidle");
|
||||
},
|
||||
goToContacts: async () => {
|
||||
await page.getByRole("link", { name: "Contacts" }).click();
|
||||
await page.waitForLoadState("networkidle");
|
||||
},
|
||||
});
|
||||
|
||||
const dismissToast = async (page: Page, content: string) => {
|
||||
await expect(page.getByText(content)).toBeVisible();
|
||||
await page.getByLabel("Close toast").first().click();
|
||||
// Since we are in optimistic UI, dismissing the toast trigger the request to the api linked to the toast message
|
||||
await page.waitForLoadState("networkidle");
|
||||
};
|
||||
|
||||
export const test = base.extend<{
|
||||
resetDb: void;
|
||||
createUser: typeof createUser;
|
||||
createSales: typeof createSales;
|
||||
createCompany: typeof createCompany;
|
||||
createContact: typeof createContact;
|
||||
createNotes: typeof createNotes;
|
||||
menu: ReturnType<typeof getMenuMethod>;
|
||||
dismissToast: (content: string) => Promise<void>;
|
||||
}>({
|
||||
resetDb: [
|
||||
// The first argument to a Playwright fixture function must use object destructuring ({}) — _ is not allowed.
|
||||
// Playwright uses this to statically analyze which fixtures are requested.
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
async ({}, use) => {
|
||||
await resetDb();
|
||||
await use();
|
||||
},
|
||||
{ auto: true },
|
||||
],
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
createUser: async ({}, cb) => {
|
||||
await cb(createUser);
|
||||
},
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
createSales: async ({}, cb) => {
|
||||
await cb(createSales);
|
||||
},
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
createCompany: async ({}, cb) => {
|
||||
await cb(createCompany);
|
||||
},
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
createContact: async ({}, cb) => {
|
||||
await cb(createContact);
|
||||
},
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
createNotes: async ({}, cb) => {
|
||||
await cb(createNotes);
|
||||
},
|
||||
menu: async ({ page, isMobile }, cb) => {
|
||||
await cb(getMenuMethod({ page, isMobile }));
|
||||
},
|
||||
dismissToast: async ({ page }, cb) => {
|
||||
await cb((content: string) => dismissToast(page, content));
|
||||
},
|
||||
});
|
||||
|
||||
export { expect };
|
||||
Reference in New Issue
Block a user