Compare commits

...

4 Commits

Author SHA1 Message Date
Ubbe
881e7cacef Merge branch 'dev' into lluisagusti/secrt-1488-password-is-logged-by-consolelog-2 2025-08-15 14:20:32 +02:00
Lluis Agusti
8bab923477 chore: fix all the console logs... 2025-08-15 13:29:52 +02:00
Lluis Agusti
2d0c2166c8 chore: wip 2025-08-15 13:05:36 +02:00
Lluis Agusti
9be32e15b1 chore: disallow console errors 2025-08-15 12:45:04 +02:00
73 changed files with 202 additions and 542 deletions

View File

@@ -21,6 +21,8 @@
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
]
],
// Prevent console statements in production code
"no-console": "error"
}
}

View File

@@ -8,7 +8,6 @@ const nextConfig = {
"ddz4ak4pa3d19.cloudfront.net",
"upload.wikimedia.org",
"storage.googleapis.com",
"ideogram.ai", // for generated images
"picsum.photos", // for placeholder images
],

View File

@@ -99,8 +99,7 @@ export default function Page() {
agentRuns: (state?.agentRuns || 0) + 1,
});
router.push("/onboarding/6-congrats");
} catch (error) {
console.error("Error running agent:", error);
} catch {
toast({
title: "Error running agent",
description:

View File

@@ -14,12 +14,7 @@ export async function addDollars(formData: FormData) {
comments: formData.get("comments") as string,
};
const api = new BackendApi();
const resp = await api.addUserCredits(
data.user_id,
data.amount,
data.comments,
);
console.log(resp);
await api.addUserCredits(data.user_id, data.amount, data.comments);
revalidatePath("/admin/spending");
}

View File

@@ -52,6 +52,7 @@ export async function GET(request: Request) {
revalidatePath("/", "layout");
}
} catch (createUserError) {
// eslint-disable-next-line no-console
console.error("Error creating user:", createUserError);
// Continue with redirect even if createUser fails
}

View File

@@ -9,8 +9,6 @@ export async function GET(request: Request) {
const code = searchParams.get("code");
const state = searchParams.get("state");
console.debug("OAuth callback received:", { code, state });
const message: OAuthPopupResultMessage =
code && state
? { message_type: "oauth_popup_result", success: true, code, state }
@@ -20,8 +18,6 @@ export async function GET(request: Request) {
message: `Incomplete query: ${searchParams.toString()}`,
};
console.debug("Sending message to opener:", message);
// Return a response with the message as JSON and a script to close the window
return new NextResponse(
`

View File

@@ -25,7 +25,6 @@ export async function askOtto(
const response = await api.askOtto(ottoQuery);
return response;
} catch (error) {
console.error("Error in askOtto server action:", error);
return {
answer: error instanceof Error ? error.message : "Unknown error occurred",
documents: [],

View File

@@ -410,7 +410,6 @@ export default function AgentRunsPage(): React.ReactElement {
router.push(`/library/agents/${newAgent.id}`);
})
.catch((error) => {
console.error("Error copying agent:", error);
toast({
title: "Error copying agent",
description: `An error occurred while copying the agent: ${error.message}`,

View File

@@ -8,6 +8,7 @@ import { useToast } from "@/components/molecules/Toast/use-toast";
import { useState } from "react";
import { Graph } from "@/app/api/__generated__/models/graph";
import { sanitizeImportedGraph } from "@/lib/autogpt-server-api";
import * as Sentry from "@sentry/nextjs";
export const useLibraryUploadAgentDialog = () => {
const [isDroped, setisDroped] = useState(false);
@@ -95,7 +96,7 @@ export const useLibraryUploadAgentDialog = () => {
form.setValue("agentDescription", agent.description);
}
} catch (error) {
console.error("Error loading agent file:", error);
Sentry.captureException(error);
}
};
reader.readAsText(file);

View File

@@ -80,7 +80,6 @@ export async function providerLogin(provider: LoginProvider) {
return "not_allowed";
}
console.error("Error logging in", error);
return error.message;
}

View File

@@ -55,8 +55,7 @@ export default async function MarketplaceAgentPage({
const libraryAgent = user
? await api
.getLibraryAgentByStoreListingVersionID(agent.active_version_id || "")
.catch((error) => {
console.error("Failed to fetch library agent:", error);
.catch(() => {
return null;
})
: null;

View File

@@ -8,7 +8,6 @@ export const useSearchbar = () => {
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(searchQuery);
if (searchQuery.trim()) {
const encodedTerm = encodeURIComponent(searchQuery);

View File

@@ -9,6 +9,7 @@ import { SearchFilterChips } from "@/components/agptui/SearchFilterChips";
import { SortDropdown } from "@/components/agptui/SortDropdown";
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
import { Creator, StoreAgent } from "@/lib/autogpt-server-api";
import * as Sentry from "@sentry/nextjs";
type MarketplaceSearchPageSearchParams = { searchTerm?: string; sort?: string };
@@ -57,7 +58,7 @@ function SearchResults({
setAgents(agentsRes.agents || []);
setCreators(creatorsRes.creators || []);
} catch (error) {
console.error("Error fetching data:", error);
Sentry.captureException(error);
} finally {
setIsLoading(false);
}

View File

@@ -3,6 +3,7 @@ import { Metadata } from "next/types";
import { redirect } from "next/navigation";
import BackendAPI from "@/lib/autogpt-server-api";
import { ProfileInfoForm } from "@/components/agptui/ProfileInfoForm";
import * as Sentry from "@sentry/nextjs";
// Force dynamic rendering to avoid static generation issues with cookies
export const dynamic = "force-dynamic";
@@ -12,7 +13,7 @@ export const metadata: Metadata = { title: "Profile - AutoGPT Platform" };
export default async function UserProfilePage(): Promise<React.ReactElement> {
const api = new BackendAPI();
const profile = await api.getStoreProfile().catch((error) => {
console.error("Error fetching profile:", error);
Sentry.captureException(error);
return null;
});

View File

@@ -31,7 +31,7 @@ export async function sendResetEmail(email: string, turnstileToken: string) {
});
if (error) {
console.error("Error sending reset email", error);
Sentry.captureException(error);
return error.message;
}
},
@@ -61,7 +61,7 @@ export async function changePassword(password: string, turnstileToken: string) {
const { error } = await supabase.auth.updateUser({ password });
if (error) {
console.error("Error changing password", error);
Sentry.captureException(error);
return error.message;
}

View File

@@ -33,7 +33,7 @@ export async function signup(
const { data, error } = await supabase.auth.signUp(values);
if (error) {
console.error("Error signing up", error);
Sentry.captureException(error);
// FIXME: supabase doesn't return the correct error message for this case
if (error.message.includes("P0001")) {
return "not_allowed";

View File

@@ -1,6 +1,7 @@
import { exchangePasswordResetCode } from "@/lib/supabase/helpers";
import { getServerSupabase } from "@/lib/supabase/server/getServerSupabase";
import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
@@ -33,7 +34,7 @@ export async function GET(request: NextRequest) {
return NextResponse.redirect(`${origin}/reset-password`);
} catch (error) {
console.error("Password reset callback error:", error);
Sentry.captureException(error);
return NextResponse.redirect(
`${origin}/reset-password?error=Password reset failed`,
);

View File

@@ -1,3 +1,4 @@
import * as Sentry from "@sentry/nextjs";
import {
createRequestHeaders,
getServerAuthToken,
@@ -72,7 +73,7 @@ export const customMutator = async <T = any>(
const authHeaders = createRequestHeaders(token, !!data, contentType);
headers = { ...headers, ...authHeaders };
} catch (error) {
console.warn("Failed to get server auth token:", error);
Sentry.captureException(error);
}
}
@@ -92,7 +93,6 @@ export const customMutator = async <T = any>(
// 4. If the request succeeds on the server side, the data will be cached, and the client will use it instead of sending a request to the proxy.
if (!response.ok && isServerSide()) {
console.error("Request failed on server side", response, fullUrl);
throw new Error(`Request failed with status ${response.status}`);
}

View File

@@ -5,6 +5,7 @@ import {
} from "@/lib/autogpt-server-api/helpers";
import { getAgptServerBaseUrl } from "@/lib/env-config";
import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
function buildBackendUrl(path: string[], queryString: string): string {
const backendPath = path.join("/");
@@ -22,7 +23,7 @@ async function handleJsonRequest(
payload = await req.json();
} catch (error) {
// Handle cases where request body is empty, invalid JSON, or already consumed
console.warn("Failed to parse JSON from request body:", error);
Sentry.captureException(error);
payload = null;
}
@@ -99,7 +100,7 @@ function createResponse(
}
function createErrorResponse(error: unknown): NextResponse {
console.error("API proxy error:", error);
Sentry.captureException(error);
// If it's our custom ApiError, preserve the original status and response
if (error instanceof ApiError) {

View File

@@ -1,21 +1,15 @@
"use client";
import { useEffect } from "react";
import { IconCircleAlert } from "@/components/ui/icons";
import { Button } from "@/components/ui/button";
import Link from "next/link";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<div className="fixed inset-0 flex items-center justify-center bg-background">
<div className="w-full max-w-md px-4 text-center sm:px-6">

View File

@@ -1,3 +1,4 @@
import * as Sentry from "@sentry/nextjs";
import React, {
useState,
useEffect,
@@ -467,7 +468,6 @@ export const CustomNode = React.memo(
const handleInputClick = useCallback(
(key: string) => {
console.debug(`Opening modal for key: ${key}`);
setActiveKey(key);
const value = getValue(key, data.hardcodedValues);
setInputModalValue(
@@ -506,8 +506,6 @@ export const CustomNode = React.memo(
};
const deleteNode = useCallback(() => {
console.debug("Deleting node:", id);
// Remove the node
deleteElements({ nodes: [{ id }] });
}, [id, deleteElements]);
@@ -517,7 +515,9 @@ export const CustomNode = React.memo(
const currentNode = getNode(id);
if (!currentNode) {
console.error("Cannot copy node: current node not found");
Sentry.captureException(
new Error("Cannot copy node: current node not found"),
);
return;
}
@@ -564,19 +564,19 @@ export const CustomNode = React.memo(
hasNonNullNonObjectValue(value),
),
);
console.error(
"Block configuration errors for",
data.title,
":",
filteredErrors,
Sentry.captureException(
new Error(
`Block configuration errors for ${data.title}: ${JSON.stringify(
filteredErrors,
)}`,
),
);
}
if (hasOutputError) {
console.error(
"Block output contains error for",
data.title,
":",
outputData.error,
Sentry.captureException(
new Error(
`Block output contains error for ${data.title}: ${outputData.error}`,
),
);
}
}, [hasConfigErrors, hasOutputError, data.errors, outputData, data.title]);

View File

@@ -1,4 +1,5 @@
"use client";
import * as Sentry from "@sentry/nextjs";
import React, {
createContext,
useState,
@@ -135,10 +136,7 @@ const FlowEditor: React.FC<{
.getLibraryAgentByGraphID(flowID, flowVersion)
.then((libraryAgent) => setLibraryAgent(libraryAgent))
.catch((error) => {
console.warn(
`Failed to fetch LibraryAgent for graph #${flowID} v${flowVersion}`,
error,
);
Sentry.captureException(error);
});
}, [api, flowID, flowVersion]);
@@ -318,7 +316,6 @@ const FlowEditor: React.FC<{
);
if (existingConnection) {
console.warn("This exact connection already exists.");
return;
}
@@ -419,6 +416,7 @@ const FlowEditor: React.FC<{
if (replaceEdges.length > 0) {
// Reset node connections for all edges
// eslint-disable-next-line no-console
console.warn(
"useReactFlow().setRootEdges was used to overwrite all edges. " +
"Use addEdges, deleteElements, or reconnectEdge for incremental changes.",
@@ -485,7 +483,6 @@ const FlowEditor: React.FC<{
(blockId: string, nodeType: string, hardcodedValues: any = {}) => {
const nodeSchema = availableBlocks.find((node) => node.id === blockId);
if (!nodeSchema) {
console.error(`Schema not found for block ID: ${blockId}`);
return;
}

View File

@@ -112,8 +112,7 @@ export default function OttoChatWidget({
{ type: "assistant", content: data.answer },
]);
}
} catch (error) {
console.error("Unexpected error in chat widget:", error);
} catch {
setMessages((prev) => [
...prev.slice(0, -1),
{

View File

@@ -4,6 +4,7 @@ import React, { useEffect, useState } from "react";
import { Button } from "./ui/button";
import { QuestionMarkCircledIcon } from "@radix-ui/react-icons";
import { useRouter, usePathname } from "next/navigation";
import * as Sentry from "@sentry/nextjs";
const TallyPopupSimple = () => {
const [isFormVisible, setIsFormVisible] = useState(false);
@@ -34,7 +35,7 @@ const TallyPopupSimple = () => {
setIsFormVisible(false);
}
} catch (error) {
console.error("Error parsing Tally message:", error);
Sentry.captureException(error);
}
}
};

View File

@@ -19,6 +19,7 @@ import {
approveAgent,
rejectAgent,
} from "@/app/(platform)/admin/marketplace/actions";
import * as Sentry from "@sentry/nextjs";
export function ApproveRejectButtons({
version,
@@ -35,7 +36,7 @@ export function ApproveRejectButtons({
await approveAgent(formData);
router.refresh(); // Refresh the current route
} catch (error) {
console.error("Error approving agent:", error);
Sentry.captureException(error);
}
};
@@ -45,7 +46,7 @@ export function ApproveRejectButtons({
await rejectAgent(formData);
router.refresh(); // Refresh the current route
} catch (error) {
console.error("Error rejecting agent:", error);
Sentry.captureException(error);
}
};

View File

@@ -4,6 +4,7 @@ import { downloadAsAdmin } from "@/app/(platform)/admin/marketplace/actions";
import { Button } from "@/components/ui/button";
import { ExternalLink } from "lucide-react";
import { useState } from "react";
import * as Sentry from "@sentry/nextjs";
export function DownloadAgentAdminButton({
storeListingVersionId,
@@ -38,7 +39,7 @@ export function DownloadAgentAdminButton({
// Revoke the temporary URL
window.URL.revokeObjectURL(url);
} catch (error) {
console.error("Download failed:", error);
Sentry.captureException(error);
} finally {
setIsLoading(false);
}

View File

@@ -15,6 +15,7 @@ import { Textarea } from "@/components/ui/textarea";
import { Input } from "@/components/ui/input";
import { useRouter } from "next/navigation";
import { addDollars } from "@/app/(platform)/admin/spending/actions";
import * as Sentry from "@sentry/nextjs";
export function AdminAddMoneyButton({
userId,
@@ -41,7 +42,7 @@ export function AdminAddMoneyButton({
await addDollars(formData);
router.refresh(); // Refresh the current route
} catch (error) {
console.error("Error adding dollars:", error);
Sentry.captureException(error);
}
};

View File

@@ -1,3 +1,4 @@
import * as Sentry from "@sentry/nextjs";
import { z } from "zod";
import { cn } from "@/lib/utils";
import { useForm } from "react-hook-form";
@@ -120,7 +121,7 @@ export const AgentImportForm: React.FC<
form.setValue("agentName", graph.name);
form.setValue("agentDescription", graph.description);
} catch (error) {
console.error("Error loading agent file:", error);
Sentry.captureException(error);
}
};
// Load file

View File

@@ -70,8 +70,7 @@ export const AgentInfo: FC<AgentInfoProps> = ({
description: "Redirecting to your library...",
duration: 2000,
});
} catch (error) {
console.error("Failed to add agent to library:", error);
} catch {
toast({
title: "Error",
description: "Failed to add agent to library. Please try again.",
@@ -111,8 +110,7 @@ export const AgentInfo: FC<AgentInfoProps> = ({
title: "Download Complete",
description: "Your agent has been successfully downloaded.",
});
} catch (error) {
console.error(`Error downloading agent:`, error);
} catch {
toast({
title: "Error",
description: "Failed to download agent. Please try again.",

View File

@@ -9,6 +9,7 @@ import { Separator } from "@/components/ui/separator";
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
import { ProfileDetails } from "@/lib/autogpt-server-api/types";
import { Button } from "./Button";
import * as Sentry from "@sentry/nextjs";
export function ProfileInfoForm({ profile }: { profile: ProfileDetails }) {
const [isSubmitting, setIsSubmitting] = useState(false);
@@ -32,7 +33,7 @@ export function ProfileInfoForm({ profile }: { profile: ProfileDetails }) {
setProfileData(returnedProfile);
}
} catch (error) {
console.error("Error updating profile:", error);
Sentry.captureException(error);
} finally {
setIsSubmitting(false);
}
@@ -50,7 +51,7 @@ export function ProfileInfoForm({ profile }: { profile: ProfileDetails }) {
const returnedProfile = await api.updateStoreProfile(updatedProfile);
setProfileData(returnedProfile);
} catch (error) {
console.error("Error uploading image:", error);
Sentry.captureException(error);
}
}

View File

@@ -27,7 +27,6 @@ export const RatingCard: React.FC<RatingCardProps> = ({
const handleSubmit = async (rating: number) => {
if (rating > 0) {
console.log(`Rating submitted for ${agentName}:`, rating);
await api.reviewAgent("--", agentName, {
store_listing_version_id: storeListingVersionId,
score: rating,

View File

@@ -31,8 +31,6 @@ export const SearchBar: React.FC<SearchBarProps> = ({
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(searchQuery);
if (searchQuery.trim()) {
// Encode the search term and navigate to the desired path
const encodedTerm = encodeURIComponent(searchQuery);

View File

@@ -32,7 +32,6 @@ export const SearchFilterChips: React.FC<SearchFilterChipsProps> = ({
const handleFilterClick = (value: string) => {
setSelected(value);
onFilterChange?.(value);
console.log(`Filter selected: ${value}`);
};
return (

View File

@@ -28,7 +28,6 @@ export const SortDropdown: React.FC<{
const handleSelect = (option: SortOption) => {
setSelected(option);
onSort(option.value);
console.log(`Sorting by: ${option.label} (${option.value})`);
};
return (

View File

@@ -56,8 +56,6 @@ export default function WalletRefill() {
resolver: zodResolver(autoRefillSchema),
});
console.log("autoRefillForm");
// Pre-fill the auto-refill form with existing values
useEffect(() => {
if (

View File

@@ -55,7 +55,6 @@ export function GoogleAnalytics(props: GAParams) {
export function sendGAEvent(...args: any[]) {
if (currDataLayerName === undefined) {
console.warn(`Custom GA: GA has not been initialized`);
return;
}
@@ -63,6 +62,6 @@ export function sendGAEvent(...args: any[]) {
if (dataLayer) {
dataLayer.push(...args);
} else {
console.warn(`Custom GA: dataLayer ${currDataLayerName} does not exist`);
// ignore
}
}

View File

@@ -2,6 +2,7 @@
import { cn } from "@/lib/utils";
import { isServerSide } from "@/lib/utils/is-server-side";
import { useEffect, useRef, useState } from "react";
import * as Sentry from "@sentry/nextjs";
export interface TurnstileProps {
siteKey: string;
@@ -74,7 +75,7 @@ export function Turnstile({
try {
window.turnstile.reset(widgetIdRef.current);
} catch (err) {
console.warn("Failed to reset existing Turnstile widget:", err);
Sentry.captureException(err);
}
}
@@ -103,7 +104,7 @@ export function Turnstile({
try {
window.turnstile.remove(widgetIdRef.current);
} catch (err) {
console.warn("Failed to remove Turnstile widget:", err);
Sentry.captureException(err);
}
setWidgetId?.(null);
widgetIdRef.current = null;

View File

@@ -6,6 +6,7 @@ import { Button } from "../../../../atoms/Button/Button";
import { StepHeader } from "../StepHeader";
import { Skeleton } from "@/components/ui/skeleton";
import { useAgentSelectStep } from "./useAgentSelectStep";
import Image from "next/image";
interface Props {
onSelect: (agentId: string, agentVersion: number) => void;
@@ -142,7 +143,7 @@ export function AgentSelectStep({
aria-pressed={selectedAgentId === agent.id}
>
<div className="relative h-32 bg-zinc-400 sm:h-40">
<img
<Image
src={agent.imageSrc}
alt={agent.name}
className="h-full w-full object-cover"

View File

@@ -203,40 +203,33 @@ export const CredentialsInput: FC<{
const controller = new AbortController();
setOAuthPopupController(controller);
controller.signal.onabort = () => {
console.debug("OAuth flow aborted");
setOAuth2FlowInProgress(false);
popup.close();
};
const handleMessage = async (e: MessageEvent<OAuthPopupResultMessage>) => {
console.debug("Message received:", e.data);
if (
typeof e.data != "object" ||
!("message_type" in e.data) ||
e.data.message_type !== "oauth_popup_result"
) {
console.debug("Ignoring irrelevant message");
return;
}
if (!e.data.success) {
console.error("OAuth flow failed:", e.data.message);
setOAuthError(`OAuth flow failed: ${e.data.message}`);
setOAuth2FlowInProgress(false);
return;
}
if (e.data.state !== state_token) {
console.error("Invalid state token received");
setOAuthError("Invalid state token received");
setOAuth2FlowInProgress(false);
return;
}
try {
console.debug("Processing OAuth callback");
const credentials = await oAuthCallback(e.data.code, e.data.state);
console.debug("OAuth callback processed successfully");
onSelectCredentials({
id: credentials.id,
type: "oauth2",
@@ -244,7 +237,6 @@ export const CredentialsInput: FC<{
provider,
});
} catch (error) {
console.error("Error in OAuth callback:", error);
setOAuthError(
// type of error is unkown so we need to use String(error)
`Error in OAuth callback: ${
@@ -252,20 +244,17 @@ export const CredentialsInput: FC<{
}`,
);
} finally {
console.debug("Finalizing OAuth flow");
setOAuth2FlowInProgress(false);
controller.abort("success");
}
};
console.debug("Adding message event listener");
window.addEventListener("message", handleMessage, {
signal: controller.signal,
});
setTimeout(
() => {
console.debug("OAuth flow timed out");
controller.abort("timeout");
setOAuth2FlowInProgress(false);
setOAuthError("OAuth flow timed out");

View File

@@ -15,8 +15,8 @@ export async function getNavbarAccountData() {
}
try {
await prefetchGetV2GetUserProfileQuery(queryClient);
} catch (error) {
console.error("Error fetching profile:", error);
} catch {
// ignore for unauthenticated users
}
return {

View File

@@ -4,8 +4,6 @@ import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
export function useNavbar() {
const { isLoggedIn, isUserLoading } = useSupabase();
console.log("isLoggedIn", isLoggedIn);
const {
data: profileResponse,
isLoading: isProfileLoading,

View File

@@ -156,7 +156,7 @@ function renderControlledDialog() {
isOpen,
set: setIsOpen,
}}
onClose={() => console.log("Dialog closed")}
onClose={() => window.alert("Dialog closed")}
>
<Dialog.Content>
<div className="flex flex-col gap-4">

View File

@@ -116,14 +116,11 @@ export const SchedulesTable = ({
}
setIsLoading(true);
const agent = agents.find((a) => a.id == selectedAgent)!;
try {
await new Promise((resolve) => setTimeout(resolve, 100));
router.push(
`/build?flowID=${agent.graph_id}&flowVersion=${agent.graph_version}&open_scheduling=true`,
);
} catch (error) {
console.error("Navigation error:", error);
}
await new Promise((resolve) => setTimeout(resolve, 100));
router.push(
`/build?flowID=${agent.graph_id}&flowVersion=${agent.graph_version}&open_scheduling=true`,
);
};
return (

View File

@@ -13,6 +13,7 @@ import { useBackendAPI } from "@/lib/autogpt-server-api/context";
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import * as Sentry from "@sentry/nextjs";
import {
createContext,
ReactNode,
@@ -104,7 +105,7 @@ export default function OnboardingProvider({
}
}
} catch (error) {
console.error("Failed to fetch onboarding data:", error);
Sentry.captureException(error);
// Don't update state on error to prevent null access issues
}
};
@@ -140,7 +141,7 @@ export default function OnboardingProvider({
// Make the API call asynchronously to not block render
setTimeout(() => {
api.updateUserOnboarding(newState).catch((error) => {
console.error("Failed to update user onboarding:", error);
Sentry.captureException(error);
});
}, 0);
},

View File

@@ -553,8 +553,6 @@ export const startTutorial = (
for (const step of tour.steps) {
step.on("show", () => {
"use client";
console.debug("sendTutorialStep");
sendGAEvent("event", "tutorial_step_shown", { value: step.id });
});
}

View File

@@ -439,7 +439,6 @@ const FileInput: FC<FileInputProps> = ({ value, onChange, className }) => {
// Set the file URI as the value
onChange(result.file_uri);
} catch (error) {
console.error("Upload failed:", error);
setUploadError(error instanceof Error ? error.message : "Upload failed");
} finally {
setIsUploading(false);

View File

@@ -105,11 +105,13 @@ export default function useAgentGraph(
api
.subscribeToGraphExecution(flowExecutionID)
.then(() =>
// eslint-disable-next-line no-console
console.debug(
`Subscribed to updates for execution #${flowExecutionID}`,
),
)
.catch((error) =>
// eslint-disable-next-line no-console
console.error(
`Failed to subscribe to updates for execution #${flowExecutionID}:`,
error,
@@ -335,9 +337,6 @@ export default function useAgentGraph(
const addExecutionDataToNode = useCallback(
(node: CustomNode, executionData: NodeExecutionResult) => {
if (!executionData.output_data) {
console.warn(
`Execution data for node ${executionData.node_id} is empty, skipping update`,
);
return node;
}
@@ -392,11 +391,6 @@ export default function useAgentGraph(
(node) => node.data.backend_id === executionData.node_id,
)?.id;
if (!nodeId) {
console.error(
"Node not found for execution data:",
executionData,
"This shouldn't happen and means that the frontend and backend are out of sync.",
);
return nodes;
}
return nodes.map((node) =>
@@ -415,10 +409,7 @@ export default function useAgentGraph(
if (savedAgent?.id === flowID && savedAgent.version === flowVersion) return;
api.getGraph(flowID, flowVersion).then((graph) => {
console.debug("Fetching graph", flowID, "version", flowVersion);
if (graph.version === savedAgent?.version) return; // in case flowVersion is not set
console.debug("Loading graph", graph.id, "version", graph.version);
_loadGraph(graph);
});
}, [flowID, flowVersion, availableBlocks, api]);
@@ -556,7 +547,6 @@ export default function useAgentGraph(
)?.inputSchema;
if (!blockSchema) {
console.error(`Schema not found for block ID: ${node.data.block_id}`);
return {};
}
@@ -623,23 +613,14 @@ export default function useAgentGraph(
// Differences in IDs are ignored.
let newSavedAgent: Graph;
if (savedAgent && graphsEquivalent(savedAgent, payload)) {
console.warn("No need to save: Graph is the same as version on server");
newSavedAgent = savedAgent;
} else {
console.debug(
"Saving new Graph version; old vs new:",
savedAgent,
payload,
);
newSavedAgent = savedAgent
? await api.updateGraph(savedAgent.id, {
...payload,
id: savedAgent.id,
})
: await api.createGraph(payload);
console.debug("Response from the API:", newSavedAgent);
}
// Update the URL
@@ -715,7 +696,6 @@ export default function useAgentGraph(
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error("Error saving agent", error);
toast({
variant: "destructive",
title: "Error saving agent",
@@ -890,8 +870,7 @@ export default function useAgentGraph(
if (searchParams.get("open_scheduling") === "true") {
router.push("/monitoring");
}
} catch (error) {
console.error(error);
} catch {
toast({
variant: "destructive",
title: "Error scheduling agent",

View File

@@ -57,10 +57,6 @@ export default function useCredentials(
);
}
if (!discriminatedProvider) {
console.warn(
`Missing discriminator value from '${credsInputSchema.discriminator}': ` +
"hiding credentials input until it is set.",
);
return null;
}
providerName = discriminatedProvider;

View File

@@ -2,6 +2,7 @@ import { useState, useCallback, useEffect } from "react";
import { verifyTurnstileToken } from "@/lib/turnstile";
import { BehaveAs, getBehaveAs } from "@/lib/utils";
import { isServerSide } from "@/lib/utils/is-server-side";
import * as Sentry from "@sentry/nextjs";
interface UseTurnstileOptions {
action?: string;
@@ -84,7 +85,7 @@ export function useTurnstile({
try {
window.turnstile.reset(widgetId);
} catch (err) {
console.warn("Failed to reset Turnstile widget:", err);
Sentry.captureException(err);
}
}
}, [shouldRender, widgetId]);

View File

@@ -448,8 +448,7 @@ export default class BackendAPI {
try {
const result = this._get("/store/profile");
return result;
} catch (error) {
console.error("Error fetching store profile:", error);
} catch {
return Promise.resolve(null);
}
}
@@ -975,10 +974,6 @@ export default class BackendAPI {
path: string,
payload?: Record<string, any>,
) {
if (method !== "GET") {
console.debug(`${method} ${path} payload:`, payload);
}
if (isClient) {
return this._makeClientRequest(method, path, payload);
} else {
@@ -1124,10 +1119,8 @@ export default class BackendAPI {
if (serverToken && !error) {
token = serverToken;
} else if (error) {
console.warn("Failed to get WebSocket token from server:", error);
}
} catch (error) {
console.warn("Failed to get token for WebSocket connection:", error);
} catch {
// Continue with empty token, connection might still work
}
@@ -1137,7 +1130,6 @@ export default class BackendAPI {
this.webSocket.onopen = () => {
this.webSocket!.state = "connected";
console.info("[BackendAPI] WebSocket connected to", this.wsUrl);
this._startWSHeartbeat(); // Start heartbeat when connection opens
this._clearDisconnectIntent(); // Clear disconnect intent when connected
this.wsOnConnectHandlers.forEach((handler) => handler());
@@ -1146,11 +1138,13 @@ export default class BackendAPI {
this.webSocket.onclose = (event) => {
if (this.webSocket?.state == "connecting") {
// eslint-disable-next-line no-console
console.error(
`[BackendAPI] WebSocket failed to connect: ${event.reason}`,
event,
);
} else if (this.webSocket?.state == "connected") {
// eslint-disable-next-line no-console
console.warn(
`[BackendAPI] WebSocket connection closed: ${event.reason}`,
event,
@@ -1172,11 +1166,13 @@ export default class BackendAPI {
this.webSocket.onerror = (error) => {
if (this.webSocket?.state == "connected") {
// eslint-disable-next-line no-console
console.error("[BackendAPI] WebSocket error:", error);
}
};
this.webSocket.onmessage = (event) => this._handleWSMessage(event);
} catch (error) {
// eslint-disable-next-line no-console
console.error("[BackendAPI] Error connecting to WebSocket:", error);
reject(error);
}
@@ -1245,6 +1241,7 @@ export default class BackendAPI {
);
this.heartbeatTimeoutID = window.setTimeout(() => {
// eslint-disable-next-line no-console
console.warn("Heartbeat timeout - reconnecting");
this.webSocket?.close();
this.connectWebSocket();

View File

@@ -97,8 +97,7 @@ export async function getServerAuthToken(): Promise<string> {
}
return session.access_token;
} catch (error) {
console.error("Failed to get auth token:", error);
} catch {
return "no-token-found";
}
}
@@ -251,16 +250,11 @@ export async function makeAuthenticatedRequest(
if (isAuthenticationError(response, errorDetail)) {
if (isLogoutInProgress()) {
// Silently return null during logout to prevent error noise
console.debug(
"Authentication request failed during logout, ignoring:",
errorDetail,
);
return null;
}
// For authentication errors outside logout, log but don't throw
// This prevents crashes when session expires naturally
console.warn("Authentication failed:", errorDetail);
return null;
}
@@ -305,13 +299,6 @@ export async function makeAuthenticatedFileUpload(
}
if (response.status === 401 || response.status === 403) {
if (isLogoutInProgress()) {
console.debug(
"File upload authentication failed during logout, ignoring",
);
return "";
}
console.warn("File upload authentication failed:", errorMessage);
return "";
}

View File

@@ -1053,9 +1053,6 @@ export function determineDataType(schema: BlockIOSubSchema): DataType {
// $ref has sibling schema properties (which isn't technically allowed),
// so there will only be one item in allOf[].
// this should NEVER happen though, as $refs are resolved server-side.
console.warn(
`Detected 'allOf' wrapper: ${schema}. Normalizing use ${schema.allOf[0]} instead.`,
);
schema = schema.allOf[0];
}

View File

@@ -42,14 +42,12 @@ function MyComponent() {
// Regular API calls use secure server-side authentication
const handleGetGraphs = async () => {
const graphs = await api.listGraphs();
console.log(graphs);
};
// File uploads also work with secure authentication
const handleFileUpload = async (file: File) => {
try {
const mediaUrl = await api.uploadStoreSubmissionMedia(file);
console.log("Uploaded:", mediaUrl);
} catch (error) {
console.error("Upload failed:", error);
}

View File

@@ -48,8 +48,7 @@ export async function validateSession(
user,
isValid: true,
};
} catch (error) {
console.error("Session validation error:", error);
} catch {
const redirectPath = getRedirectPath(currentPath);
return {
user: null,
@@ -93,7 +92,6 @@ export async function getCurrentUser(): Promise<{
return { user };
} catch (error) {
console.error("Get current user error:", error);
return {
user: null,
error: error instanceof Error ? error.message : "Unknown error",
@@ -135,7 +133,6 @@ export async function getWebSocketToken(): Promise<{
return { token: session?.access_token || null };
} catch (error) {
console.error("Get WebSocket token error:", error);
return {
token: null,
error: error instanceof Error ? error.message : "Unknown error",
@@ -158,7 +155,6 @@ export async function serverLogout(options: ServerLogoutOptions = {}) {
if (!supabase) {
redirect("/login");
return;
}
try {
@@ -169,10 +165,10 @@ export async function serverLogout(options: ServerLogoutOptions = {}) {
revalidatePath("/");
if (error) {
console.error("Error logging out:", error);
Sentry.captureException(error);
}
} catch (error) {
console.error("Logout error:", error);
Sentry.captureException(error);
}
// Clear all cached data and redirect
@@ -214,7 +210,6 @@ export async function refreshSession() {
return { user };
} catch (error) {
console.error("Refresh session error:", error);
return {
user: null,
error: error instanceof Error ? error.message : "Unknown error",

View File

@@ -5,6 +5,7 @@ import { usePathname, useRouter } from "next/navigation";
import { useEffect, useMemo, useRef, useState } from "react";
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
import { getSupabaseUrl, getSupabaseAnonKey } from "@/lib/env-config";
import * as Sentry from "@sentry/nextjs";
import {
getCurrentUser,
refreshSession,
@@ -40,7 +41,7 @@ export function useSupabase() {
},
});
} catch (error) {
console.error("Error creating Supabase client", error);
Sentry.captureException(error);
return null;
}
}, []);
@@ -53,7 +54,7 @@ export function useSupabase() {
try {
await serverLogout(options);
} catch (error) {
console.error("Error logging out:", error);
Sentry.captureException(error);
} finally {
setUser(null);
router.refresh();
@@ -97,8 +98,7 @@ export function useSupabase() {
}
return true;
} catch (error) {
console.error("Session validation error:", error);
} catch {
setUser(null);
const redirectPath = getRedirectPath(pathname);
if (redirectPath) {
@@ -122,8 +122,7 @@ export function useSupabase() {
setUser(serverUser);
clearWebSocketDisconnectIntent();
return serverUser;
} catch (error) {
console.error("Get user error:", error);
} catch {
setUser(null);
return null;
}

View File

@@ -2,6 +2,7 @@ import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
import { getCookieSettings, isAdminPage, isProtectedPage } from "./helpers";
import { getSupabaseUrl, getSupabaseAnonKey } from "../env-config";
import * as Sentry from "@sentry/nextjs";
export async function updateSession(request: NextRequest) {
let supabaseResponse = NextResponse.next({
@@ -81,7 +82,7 @@ export async function updateSession(request: NextRequest) {
// If this is not done, you may be causing the browser and server to go out
// of sync and terminate the user's session prematurely!
} catch (error) {
console.error("Failed to run Supabase middleware", error);
Sentry.captureException(error);
}
return supabaseResponse;

View File

@@ -22,7 +22,6 @@ export async function getServerUser() {
const role = user.role || null;
return { user, role, error: null };
} catch (error) {
console.error("Unexpected error in getServerUser:", error);
return {
user: null,
role: null,

View File

@@ -32,14 +32,12 @@ export async function verifyTurnstileToken(
});
if (!response.ok) {
console.error("Turnstile verification failed:", await response.text());
return false;
}
const data = await response.json();
return data.success === true;
} catch (error) {
console.error("Error verifying Turnstile token:", error);
} catch {
return false;
}
}

View File

@@ -84,7 +84,6 @@ test.describe("Agent Dashboard", () => {
const beforeCount = await rows.count();
if (beforeCount === 0) {
console.log("No agents available; skipping delete flow.");
return;
}

View File

@@ -47,8 +47,6 @@ test.describe("Build", () => { //(1)!
const blocksToAdd = allBlocks.filter((_, index) =>
index % totalParts === (part - 1)
);
console.log(`Adding ${blocksToAdd.length} blocks starting with "${letter}" (part ${part}/${totalParts})`);
for (const block of blocksToAdd) {
await buildPage.addBlock(block);

View File

@@ -2,23 +2,15 @@ import { FullConfig } from "@playwright/test";
import { createTestUsers, saveUserPool, loadUserPool } from "./utils/auth";
async function globalSetup(config: FullConfig) {
console.log("🚀 Starting global test setup...");
try {
const existingUserPool = await loadUserPool();
if (existingUserPool && existingUserPool.users.length > 0) {
console.log(
`♻️ Found existing user pool with ${existingUserPool.users.length} users`,
);
console.log("✅ Using existing user pool");
return;
}
// Create test users using signup page
const numberOfUsers = (config.workers || 1) + 8; // workers + buffer
console.log(`👥 Creating ${numberOfUsers} test users via signup...`);
console.log("⏳ Note: This may take a few minutes in CI environments");
const users = await createTestUsers(numberOfUsers);
@@ -36,15 +28,7 @@ async function globalSetup(config: FullConfig) {
// Save user pool
await saveUserPool(users);
console.log("✅ Global setup completed successfully!");
console.log(`📊 Created ${users.length} test users via signup page`);
} catch (error) {
console.error("❌ Global setup failed:", error);
console.error("💡 This is likely due to:");
console.error(" 1. Backend services not fully ready");
console.error(" 2. Network timeouts in CI environment");
console.error(" 3. Database or authentication issues");
throw error;
}
}

View File

@@ -13,10 +13,6 @@ test.describe("Marketplace Basic Functionality", () => {
const marketplaceTitle = await marketplacePage.getMarketplaceTitle(page);
await isVisible(marketplaceTitle);
console.log(
"User can access marketplace page when logged out test passed ✅",
);
});
test("User can access marketplace page when logged in", async ({ page }) => {
@@ -32,10 +28,6 @@ test.describe("Marketplace Basic Functionality", () => {
const marketplaceTitle = await marketplacePage.getMarketplaceTitle(page);
await isVisible(marketplaceTitle);
console.log(
"User can access marketplace page when logged in test passed ✅",
);
});
test("Featured agents, top agents, and featured creators are visible", async ({
@@ -61,10 +53,6 @@ test.describe("Marketplace Basic Functionality", () => {
await isVisible(featuredCreatorsSection);
const creatorProfiles = await marketplacePage.getCreatorProfiles(page);
await hasMinCount(creatorProfiles, 1);
console.log(
"Featured agents, top agents, and featured creators are visible test passed ✅",
);
});
test("Can navigate and interact with marketplace elements", async ({
@@ -92,10 +80,6 @@ test.describe("Marketplace Basic Functionality", () => {
await firstCreatorProfile.click();
await page.waitForURL("**/marketplace/creator/**");
await matchesUrl(page, /\/marketplace\/creator\/.+/);
console.log(
"Can navigate and interact with marketplace elements test passed ✅",
);
});
test("Complete search flow works correctly", async ({ page }) => {
@@ -118,8 +102,6 @@ test.describe("Marketplace Basic Functionality", () => {
const results = await marketplacePage.getSearchResultsCount(page);
expect(results).toBeGreaterThan(0);
console.log("Complete search flow works correctly test passed ✅");
});
// We need to add a test search with filters, but the current business logic for filters doesn't work as expected. We'll add it once we modify that.
@@ -144,7 +126,5 @@ test.describe("Marketplace Edge Cases", () => {
const results = await marketplacePage.getSearchResultsCount(page);
expect(results).toBe(0);
console.log("Search for non-existent item shows no results test passed ✅");
});
});

View File

@@ -49,7 +49,6 @@ test.beforeEach(async ({ page }, testInfo: TestInfo) => {
test.afterAll(async () => {
// clear out the downloads folder
const downloadsFolder = process.cwd() + "/downloads";
console.log(`clearing out the downloads folder ${downloadsFolder}/monitor`);
await fs.rm(`${downloadsFolder}/monitor`, {
recursive: true,
@@ -88,8 +87,6 @@ test.skip("user can export and import agents", async ({
`${monitorPage.downloadsFolder}/monitor/${download.suggestedFilename()}`,
);
console.log(`downloaded file to ${download.suggestedFilename()}`);
expect(download.suggestedFilename()).toBeDefined();
expect(download.suggestedFilename()).toContain("test-agent-");
expect(download.suggestedFilename()).toContain("v1.json");
@@ -122,8 +119,6 @@ test.skip("user can export and import agents", async ({
expect(postImportAgents.length).toBeGreaterThan(preImportAgents.length);
console.log(`postImportAgents: ${JSON.stringify(postImportAgents)}`);
const importedAgent = postImportAgents.find(
(a: any) => a.name === `${baseName}-imported`,
);

View File

@@ -23,14 +23,9 @@ export class BuildPage extends BasePage {
}
async closeTutorial(): Promise<void> {
console.log(`closing tutorial`);
try {
await this.page
.getByRole("button", { name: "Skip Tutorial", exact: true })
.click();
} catch (error) {
console.info("Error closing tutorial:", error);
}
await this.page
.getByRole("button", { name: "Skip Tutorial", exact: true })
.click();
}
async openBlocksPanel(): Promise<void> {
@@ -51,7 +46,6 @@ export class BuildPage extends BasePage {
name: string = "Test Agent",
description: string = "",
): Promise<void> {
console.log(`💾 Saving agent '${name}' with description '${description}'`);
await this.page.getByTestId("blocks-control-save-button").click();
await this.page.getByTestId("save-control-name-input").fill(name);
await this.page
@@ -65,16 +59,12 @@ export class BuildPage extends BasePage {
return Object.values(this.cachedBlocks);
}
console.log(`Getting blocks from API request`);
// Make direct API request using the page's request context
const response = await this.page.request.get(
"http://localhost:3000/api/proxy/api/blocks",
);
const apiBlocks: APIBlock[] = await response.json();
console.log(`Found ${apiBlocks.length} blocks from API`);
// Convert API blocks to test Block format
const blocks = apiBlocks.map((block) => ({
id: block.id,
@@ -96,14 +86,11 @@ export class BuildPage extends BasePage {
async getFilteredBlocksFromAPI(
filterFn: (block: Block) => boolean,
): Promise<Block[]> {
console.log(`Getting filtered blocks from API`);
const blocks = await this.getBlocksFromAPI();
return blocks.filter(filterFn);
}
async addBlock(block: Block): Promise<void> {
console.log(`Adding block ${block.name} (${block.id}) to agent`);
await this.openBlocksPanel();
const searchInput = this.page.locator(
@@ -121,9 +108,6 @@ export class BuildPage extends BasePage {
const blockInEditor = this.page.getByTestId(block.id).first();
expect(blockInEditor).toBeAttached();
} else {
console.log(
`❌ ❌ Block ${block.name} (display: ${displayName}) returned from the API but not found in block list`,
);
}
}
@@ -133,27 +117,22 @@ export class BuildPage extends BasePage {
}
async getBlockInputs(blockId: string): Promise<string[]> {
console.log(`Getting block ${blockId} inputs`);
try {
const node = this.page.locator(`[data-blockid="${blockId}"]`).first();
const inputsData = await node.getAttribute("data-inputs");
return inputsData ? JSON.parse(inputsData) : [];
} catch (error) {
console.error("Error getting block inputs:", error);
} catch {
return [];
}
}
async selectBlockCategory(category: string): Promise<void> {
console.log(`Selecting block category: ${category}`);
await this.page.getByText(category, { exact: true }).click();
// Wait for the blocks to load after category selection
await this.page.waitForTimeout(3000);
}
async getBlocksForCategory(category: string): Promise<Block[]> {
console.log(`Getting blocks for category: ${category}`);
// Clear any existing search to ensure we see all blocks in the category
const searchInput = this.page.locator(
'[data-id="blocks-control-search-input"]',
@@ -171,8 +150,6 @@ export class BuildPage extends BasePage {
await blockFinder.first().waitFor();
const blocks = await blockFinder.all();
console.log(`found ${blocks.length} blocks in category ${category}`);
const results = await Promise.all(
blocks.map(async (block) => {
try {
@@ -194,6 +171,7 @@ export class BuildPage extends BasePage {
description: description.trim(),
};
} catch (elementError) {
// eslint-disable-next-line no-console
console.error("Error processing block:", elementError);
return null;
}
@@ -203,6 +181,7 @@ export class BuildPage extends BasePage {
// Filter out any null results from errors
return results.filter((block): block is Block => block !== null);
} catch (error) {
// eslint-disable-next-line no-console
console.error(`Error getting blocks for category ${category}:`, error);
return [];
}
@@ -216,7 +195,6 @@ export class BuildPage extends BasePage {
}
async getBlockById(blockId: string, dataId?: string): Promise<Locator> {
console.log(`getting block ${blockId} with dataId ${dataId}`);
return this.page.locator(await this._buildBlockSelector(blockId, dataId));
}
@@ -229,9 +207,6 @@ export class BuildPage extends BasePage {
value: string,
dataId?: string,
): Promise<void> {
console.log(
`filling block input ${placeholder} with value ${value} of block ${blockId}`,
);
const block = await this.getBlockById(blockId, dataId);
const input = block.getByPlaceholder(placeholder);
await input.fill(value);
@@ -243,9 +218,6 @@ export class BuildPage extends BasePage {
value: string,
dataId?: string,
): Promise<void> {
console.log(
`selecting value ${value} for input ${inputName} of block ${blockId}`,
);
// First get the button that opens the dropdown
const baseSelector = await this._buildBlockSelector(blockId, dataId);
@@ -263,6 +235,7 @@ export class BuildPage extends BasePage {
// The actual selector for the option might need adjustment based on the dropdown structure
await this.page.getByRole("option", { name: value }).click();
} catch (error) {
// eslint-disable-next-line no-console
console.error(
`Error selecting value "${value}" for input "${inputName}":`,
error,
@@ -276,7 +249,6 @@ export class BuildPage extends BasePage {
label: string,
value: string,
): Promise<void> {
console.log(`filling block input ${label} with value ${value}`);
const block = await this.getBlockById(blockId);
const input = block.getByLabel(label);
await input.fill(value);
@@ -286,9 +258,6 @@ export class BuildPage extends BasePage {
blockOutputId: string,
blockInputId: string,
): Promise<void> {
console.log(
`connecting block output ${blockOutputId} to block input ${blockInputId}`,
);
try {
// Locate the output element
const outputElement = this.page.locator(`[data-id="${blockOutputId}"]`);
@@ -297,6 +266,7 @@ export class BuildPage extends BasePage {
await outputElement.dragTo(inputElement);
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error connecting block output to input:", error);
}
}
@@ -309,10 +279,6 @@ export class BuildPage extends BasePage {
startDataId?: string,
endDataId?: string,
): Promise<void> {
console.log(
`connecting block output ${startBlockOutputName} of block ${startBlockId} to block input ${endBlockInputName} of block ${endBlockId}`,
);
const startBlockBase = await this._buildBlockSelector(
startBlockId,
startDataId,
@@ -322,16 +288,12 @@ export class BuildPage extends BasePage {
const startBlockOutputSelector = `${startBlockBase} [data-testid="output-handle-${startBlockOutputName.toLowerCase()}"]`;
const endBlockInputSelector = `${endBlockBase} [data-testid="input-handle-${endBlockInputName.toLowerCase()}"]`;
console.log("Start block selector:", startBlockOutputSelector);
console.log("End block selector:", endBlockInputSelector);
await this.page
.locator(startBlockOutputSelector)
.dragTo(this.page.locator(endBlockInputSelector));
}
async isLoaded(): Promise<boolean> {
console.log(`checking if build page is loaded`);
try {
await this.page.waitForLoadState("domcontentloaded", { timeout: 10_000 });
return true;
@@ -341,44 +303,37 @@ export class BuildPage extends BasePage {
}
async isRunButtonEnabled(): Promise<boolean> {
console.log(`checking if run button is enabled`);
const runButton = this.page.getByTestId("primary-action-run-agent");
return await runButton.isEnabled();
}
async runAgent(): Promise<void> {
console.log(`clicking run button`);
const runButton = this.page.getByTestId("primary-action-run-agent");
await runButton.click();
}
async fillRunDialog(inputs: Record<string, string>): Promise<void> {
console.log(`filling run dialog`);
for (const [key, value] of Object.entries(inputs)) {
await this.page.getByTestId(`agent-input-${key}`).fill(value);
}
}
async clickRunDialogRunButton(): Promise<void> {
console.log(`clicking run button`);
await this.page.getByTestId("agent-run-button").click();
}
async waitForCompletionBadge(): Promise<void> {
console.log(`waiting for completion badge`);
await this.page.waitForSelector(
'[data-id^="badge-"][data-id$="-COMPLETED"]',
);
}
async waitForSaveButton(): Promise<void> {
console.log(`waiting for save button`);
await this.page.waitForSelector(
'[data-testid="blocks-control-save-button"]:not([disabled])',
);
}
async isCompletionBadgeVisible(): Promise<boolean> {
console.log(`checking for completion badge`);
const completionBadge = this.page
.locator('[data-id^="badge-"][data-id$="-COMPLETED"]')
.first();
@@ -386,8 +341,6 @@ export class BuildPage extends BasePage {
}
async waitForVersionField(): Promise<void> {
console.log(`waiting for version field`);
// wait for the url to have the flowID
await this.page.waitForSelector(
'[data-testid="save-control-version-output"]',
@@ -413,8 +366,6 @@ export class BuildPage extends BasePage {
}
async waitForSaveDialogClose(): Promise<void> {
console.log(`waiting for save dialog to close`);
await this.page.waitForSelector(
'[data-id="save-control-popover-content"]',
{ state: "hidden" },
@@ -432,7 +383,6 @@ export class BuildPage extends BasePage {
}
async nextTutorialStep(): Promise<void> {
console.log(`clicking next tutorial step`);
await this.page.getByRole("button", { name: "Next" }).click();
}

View File

@@ -17,21 +17,14 @@ export class LibraryPage extends BasePage {
}
async isLoaded(): Promise<boolean> {
console.log(`checking if library page is loaded`);
try {
await this.page.waitForLoadState("domcontentloaded", { timeout: 10_000 });
await this.page.waitForLoadState("domcontentloaded", { timeout: 10_000 });
await this.page.waitForSelector('[data-testid="library-textbox"]', {
state: "visible",
timeout: 10_000,
});
await this.page.waitForSelector('[data-testid="library-textbox"]', {
state: "visible",
timeout: 10_000,
});
console.log("Library page is loaded successfully");
return true;
} catch (error) {
console.log("Library page failed to load:", error);
return false;
}
return true;
}
async navigateToLibrary(): Promise<void> {
@@ -53,7 +46,6 @@ export class LibraryPage extends BasePage {
}
async searchAgents(searchTerm: string): Promise<void> {
console.log(`searching for agents with term: ${searchTerm}`);
const { getRole } = getSelectors(this.page);
const searchInput = getRole("textbox", "Search agents");
await searchInput.fill(searchTerm);
@@ -62,7 +54,6 @@ export class LibraryPage extends BasePage {
}
async clearSearch(): Promise<void> {
console.log(`clearing search`);
try {
// Look for the clear button (X icon)
const clearButton = this.page.locator(".lucide.lucide-x");
@@ -79,6 +70,7 @@ export class LibraryPage extends BasePage {
// Wait for results to update
await this.page.waitForTimeout(500);
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error clearing search:", error);
}
}
@@ -96,19 +88,18 @@ export class LibraryPage extends BasePage {
}
async getCurrentSortOption(): Promise<string> {
console.log(`getting current sort option`);
try {
const sortCombobox = this.page.getByRole("combobox");
const currentOption = await sortCombobox.textContent();
return currentOption?.trim() || "";
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error getting current sort option:", error);
return "";
}
}
async openUploadDialog(): Promise<void> {
console.log(`opening upload dialog`);
await this.page.getByRole("button", { name: "Upload an agent" }).click();
// Wait for dialog to appear
@@ -128,7 +119,6 @@ export class LibraryPage extends BasePage {
}
async isUploadDialogVisible(): Promise<boolean> {
console.log(`checking if upload dialog is visible`);
try {
const dialog = this.page.getByRole("dialog", { name: "Upload Agent" });
return await dialog.isVisible();
@@ -138,10 +128,6 @@ export class LibraryPage extends BasePage {
}
async fillUploadForm(agentName: string, description: string): Promise<void> {
console.log(
`filling upload form with name: ${agentName}, description: ${description}`,
);
// Fill agent name
await this.page
.getByRole("textbox", { name: "Agent name" })
@@ -154,7 +140,6 @@ export class LibraryPage extends BasePage {
}
async isUploadButtonEnabled(): Promise<boolean> {
console.log(`checking if upload button is enabled`);
try {
const uploadButton = this.page.getByRole("button", {
name: "Upload Agent",
@@ -199,7 +184,6 @@ export class LibraryPage extends BasePage {
}
}
console.log(`found ${agents.length} agents`);
return agents;
}
@@ -210,16 +194,12 @@ export class LibraryPage extends BasePage {
}
async clickSeeRuns(agent: Agent): Promise<void> {
console.log(`clicking see runs for agent: ${agent.name}`);
// Find the "See runs" link for this specific agent
const agentCard = this.page.locator(`[href="${agent.seeRunsUrl}"]`).first();
await agentCard.click();
}
async clickOpenInBuilder(agent: Agent): Promise<void> {
console.log(`clicking open in builder for agent: ${agent.name}`);
// Find the "Open in builder" link for this specific agent
const builderLink = this.page
.locator(`[href="${agent.openInBuilderUrl}"]`)
@@ -238,12 +218,10 @@ export class LibraryPage extends BasePage {
}
async clickMonitoringLink(): Promise<void> {
console.log(`clicking monitoring link in alert`);
await this.page.getByRole("link", { name: "here" }).click();
}
async isMonitoringAlertVisible(): Promise<boolean> {
console.log(`checking if monitoring alert is visible`);
try {
const alertText = this.page.locator("text=/Prefer the old experience/");
return await alertText.isVisible();
@@ -253,7 +231,6 @@ export class LibraryPage extends BasePage {
}
async getSearchValue(): Promise<string> {
console.log(`getting search input value`);
try {
const searchInput = this.page.getByRole("textbox", {
name: "Search agents",
@@ -271,34 +248,22 @@ export class LibraryPage extends BasePage {
}
async scrollToBottom(): Promise<void> {
console.log(`scrolling to bottom to trigger pagination`);
await this.page.keyboard.press("End");
await this.page.waitForTimeout(1000);
}
async scrollDown(): Promise<void> {
console.log(`scrolling down to trigger pagination`);
await this.page.keyboard.press("PageDown");
await this.page.waitForTimeout(1000);
}
async scrollToLoadMore(): Promise<void> {
console.log(`scrolling to load more agents`);
// Get initial agent count
const initialCount = await this.getAgentCount();
console.log(`Initial agent count: ${initialCount}`);
// Scroll down to trigger pagination
await this.scrollToBottom();
// Wait for potential new agents to load
await this.page.waitForTimeout(2000);
// Check if more agents loaded
const newCount = await this.getAgentCount();
console.log(`New agent count after scroll: ${newCount}`);
return;
}
@@ -320,8 +285,6 @@ export class LibraryPage extends BasePage {
}
async getAgentsWithPagination(): Promise<Agent[]> {
console.log(`getting all agents with pagination`);
let allAgents: Agent[] = [];
let previousCount = 0;
let currentCount = 0;
@@ -336,21 +299,16 @@ export class LibraryPage extends BasePage {
allAgents = currentAgents;
currentCount = currentAgents.length;
console.log(`Attempt ${attempts + 1}: Found ${currentCount} agents`);
// Try to load more by scrolling
await this.scrollToLoadMore();
attempts++;
} while (currentCount > previousCount && attempts < maxAttempts);
console.log(`Total agents found with pagination: ${allAgents.length}`);
return allAgents;
}
async waitForPaginationLoad(): Promise<void> {
console.log(`waiting for pagination to load`);
// Wait for any loading states to complete
await this.page.waitForTimeout(1000);
@@ -372,8 +330,6 @@ export class LibraryPage extends BasePage {
previousCount = currentCount;
await this.page.waitForTimeout(500);
}
console.log(`Pagination load stabilized with ${currentCount} agents`);
}
async scrollAndWaitForNewAgents(): Promise<number> {
@@ -386,10 +342,6 @@ export class LibraryPage extends BasePage {
const finalCount = await this.getAgentCountByListLength();
const newAgentsLoaded = finalCount - initialCount;
console.log(
`Loaded ${newAgentsLoaded} new agents (${initialCount} -> ${finalCount})`,
);
return newAgentsLoaded;
}

View File

@@ -8,11 +8,6 @@ export class LoginPage {
}
async login(email: string, password: string) {
console.log(` Attempting login on ${this.page.url()} with`, {
email,
password,
});
// Wait for the form to be ready
await this.page.waitForSelector("form", { state: "visible" });
@@ -34,7 +29,10 @@ export class LoginPage {
await loginButton.waitFor({ state: "visible" });
// Attach navigation logger for debug purposes
this.page.on("load", (page) => console.log(` Now at URL: ${page.url()}`));
this.page.on("load", (page) => {
// eslint-disable-next-line no-console
console.log(` Now at URL: ${page.url()}`);
});
// Start waiting for navigation before clicking
const leaveLoginPage = this.page
@@ -43,6 +41,7 @@ export class LoginPage {
{ timeout: 10_000 },
)
.catch((reason) => {
// eslint-disable-next-line no-console
console.error(
`🚨 Navigation away from /login timed out (current URL: ${this.page.url()}):`,
reason,
@@ -50,18 +49,13 @@ export class LoginPage {
throw reason;
});
console.log(`🖱️ Clicking login button...`);
await loginButton.click();
console.log("⏳ Waiting for navigation away from /login ...");
await leaveLoginPage;
console.log(`⌛ Post-login redirected to ${this.page.url()}`);
await new Promise((resolve) => setTimeout(resolve, 200)); // allow time for client-side redirect
await this.page.waitForLoadState("load", { timeout: 10_000 });
console.log("➡️ Navigating to /marketplace ...");
await this.page.goto("/marketplace", { timeout: 10_000 });
console.log("✅ Login process complete");
}
}

View File

@@ -37,44 +37,38 @@ export class MonitorPage extends BasePage {
}
async isLoaded(): Promise<boolean> {
console.log(`checking if monitor page is loaded`);
try {
// Wait for the monitor page
await this.page.getByTestId("monitor-page").waitFor({
state: "visible",
timeout: 10_000,
});
// Wait for the monitor page
await this.page.getByTestId("monitor-page").waitFor({
state: "visible",
timeout: 10_000,
});
// Wait for table headers to be visible (indicates table structure is ready)
await this.page.locator("thead th").first().waitFor({
// Wait for table headers to be visible (indicates table structure is ready)
await this.page.locator("thead th").first().waitFor({
state: "visible",
timeout: 15_000,
});
// Wait for either a table row or an empty tbody to be present
await Promise.race([
// Wait for at least one row
this.page.locator("tbody tr[data-testid]").first().waitFor({
state: "visible",
timeout: 15_000,
});
// Wait for either a table row or an empty tbody to be present
await Promise.race([
// Wait for at least one row
this.page.locator("tbody tr[data-testid]").first().waitFor({
}),
// OR wait for an empty tbody (indicating no agents but table is loaded)
this.page
.locator("tbody[data-testid='agent-flow-list-body']:empty")
.waitFor({
state: "visible",
timeout: 15_000,
}),
// OR wait for an empty tbody (indicating no agents but table is loaded)
this.page
.locator("tbody[data-testid='agent-flow-list-body']:empty")
.waitFor({
state: "visible",
timeout: 15_000,
}),
]);
]);
return true;
} catch {
return false;
}
return true;
}
async listAgents(): Promise<Agent[]> {
console.log(`listing agents`);
// Wait for table rows to be available
const rows = await this.page.locator("tbody tr[data-testid]").all();
@@ -118,7 +112,6 @@ export class MonitorPage extends BasePage {
}
async listRuns(filter?: Agent): Promise<Run[]> {
console.log(`listing runs`);
// Wait for the runs table to be loaded - look for table header "Agent"
await this.page.locator("[data-testid='flow-runs-list-body']").waitFor({
timeout: 10000,
@@ -160,17 +153,14 @@ export class MonitorPage extends BasePage {
return runs;
}
async listSchedules(): Promise<Schedule[]> {
console.log(`listing schedules`);
return [];
}
async clickAgent(id: string) {
console.log(`selecting agent ${id}`);
await this.page.getByTestId(id).click();
}
async clickCreateAgent(): Promise<void> {
console.log(`clicking create agent`);
await this.page.getByRole("link", { name: "Create" }).click();
}
@@ -181,9 +171,6 @@ export class MonitorPage extends BasePage {
description?: string,
importType: ImportType = ImportType.AGENT,
) {
console.log(
`importing from directory: ${directory} file: ${file} name: ${name} description: ${description} importType: ${importType}`,
);
await this.page.getByTestId("create-agent-dropdown").click();
await this.page.getByTestId("import-agent-from-file").click();
@@ -191,47 +178,23 @@ export class MonitorPage extends BasePage {
.getByTestId("import-agent-file-input")
.setInputFiles(path.join(directory, file));
if (name) {
console.log(`filling agent name: ${name}`);
await this.page.getByTestId("agent-name-input").fill(name);
}
if (description) {
console.log(`filling agent description: ${description}`);
await this.page.getByTestId("agent-description-input").fill(description);
}
if (importType === ImportType.TEMPLATE) {
console.log(`clicking import as template switch`);
await this.page.getByTestId("import-as-template-switch").click();
}
console.log(`clicking import agent submit`);
await this.page.getByTestId("import-agent-submit").click();
}
async deleteAgent(agent: Agent) {
console.log(`deleting agent ${agent.id} ${agent.name}`);
}
async clickAllVersions(agent: Agent) {
console.log(`clicking all versions for agent ${agent.id} ${agent.name}`);
}
async openInBuilder(agent: Agent) {
console.log(`opening agent ${agent.id} ${agent.name} in builder`);
async deleteAgent() {
await this.page.getByTestId("delete-agent-button").click();
}
async exportToFile(agent: Agent) {
await this.clickAgent(agent.id);
console.log(`exporting agent id: ${agent.id} name: ${agent.name} to file`);
await this.page.getByTestId("export-button").click();
}
async selectRun(agent: Agent, run: Run) {
console.log(`selecting run ${run.id} for agent ${agent.id} ${agent.name}`);
}
async openOutputs(agent: Agent, run: Run) {
console.log(
`opening outputs for run ${run.id} of agent ${agent.id} ${agent.name}`,
);
}
}

View File

@@ -31,8 +31,7 @@ export class ProfilePage extends BasePage {
try {
await this.waitForPageToLoad();
return true;
} catch (error) {
console.error("Error loading profile page", error);
} catch {
return false;
}
}

View File

@@ -161,12 +161,14 @@ test("multi-tab logout with WebSocket cleanup", async ({ context }) => {
// Verify the profile menu is no longer visible (user is logged out)
await isHidden(getId2("profile-popout-menu-trigger"));
// Verify no WebSocket connection errors occurred during logout
test.expect(consoleErrors).toHaveLength(0);
if (consoleErrors.length > 0) {
// eslint-disable-next-line no-console
console.log("WebSocket errors during logout:", consoleErrors);
}
// Verify no WebSocket connection errors occurred during logout
test.expect(consoleErrors).toHaveLength(0);
// Clean up
await page1.close();
await page2.close();

View File

@@ -9,26 +9,22 @@ import { getSelectors } from "./utils/selectors";
import { hasUrl, isVisible } from "./utils/assertion";
test("user can signup successfully", async ({ page }) => {
try {
const testUser = await signupTestUser(page);
const { getText, getId } = getSelectors(page);
const testUser = await signupTestUser(page);
const { getText, getId } = getSelectors(page);
// Verify user was created
expect(testUser.email).toBeTruthy();
expect(testUser.password).toBeTruthy();
expect(testUser.createdAt).toBeTruthy();
// Verify user was created
expect(testUser.email).toBeTruthy();
expect(testUser.password).toBeTruthy();
expect(testUser.createdAt).toBeTruthy();
const marketplaceText = getText(
"Bringing you AI agents designed by thinkers from around the world",
);
const marketplaceText = getText(
"Bringing you AI agents designed by thinkers from around the world",
);
// Verify we're on marketplace and authenticated
await hasUrl(page, "/marketplace");
await isVisible(marketplaceText);
await isVisible(getId("profile-popout-menu-trigger"));
} catch (error) {
console.error("❌ Signup test failed:", error);
}
// Verify we're on marketplace and authenticated
await hasUrl(page, "/marketplace");
await isVisible(marketplaceText);
await isVisible(getId("profile-popout-menu-trigger"));
});
test("signup form validation works", async ({ page }) => {
@@ -58,69 +54,57 @@ test("signup form validation works", async ({ page }) => {
test("user can signup with custom credentials", async ({ page }) => {
const { getId } = getSelectors(page);
try {
const customEmail = generateTestEmail();
const customPassword = generateTestPassword();
const customEmail = generateTestEmail();
const customPassword = generateTestPassword();
const testUser = await signupTestUser(page, customEmail, customPassword);
const testUser = await signupTestUser(page, customEmail, customPassword);
// Verify correct credentials were used
expect(testUser.email).toBe(customEmail);
expect(testUser.password).toBe(customPassword);
// Verify correct credentials were used
expect(testUser.email).toBe(customEmail);
expect(testUser.password).toBe(customPassword);
// Verify successful signup
await hasUrl(page, "/marketplace");
await isVisible(getId("profile-popout-menu-trigger"));
} catch (error) {
console.error("❌ Custom credentials signup test failed:", error);
}
// Verify successful signup
await hasUrl(page, "/marketplace");
await isVisible(getId("profile-popout-menu-trigger"));
});
test("user can signup with existing email handling", async ({
page,
browser,
}) => {
try {
const testEmail = generateTestEmail();
const testPassword = generateTestPassword();
const testEmail = generateTestEmail();
const testPassword = generateTestPassword();
// First signup
const firstUser = await signupTestUser(page, testEmail, testPassword);
expect(firstUser.email).toBe(testEmail);
// First signup
const firstUser = await signupTestUser(page, testEmail, testPassword);
expect(firstUser.email).toBe(testEmail);
// Create new browser context for second signup (simulates new browser window)
const newContext = await browser.newContext();
const newPage = await newContext.newPage();
// Create new browser context for second signup (simulates new browser window)
const newContext = await browser.newContext();
const newPage = await newContext.newPage();
try {
const { getText, getField, getRole, getButton } = getSelectors(newPage);
const { getText, getField, getRole, getButton } = getSelectors(newPage);
// Second signup attempt with same email in new browser context
// Navigate to signup page
await newPage.goto("http://localhost:3000/signup");
// Second signup attempt with same email in new browser context
// Navigate to signup page
await newPage.goto("http://localhost:3000/signup");
// Wait for page to load
getText("Create a new account");
// Wait for page to load
getText("Create a new account");
// Fill form
const emailInput = getField("Email");
await emailInput.fill(testEmail);
const passwordInput = newPage.locator("#password");
await passwordInput.fill(testPassword);
const confirmPasswordInput = newPage.locator("#confirmPassword");
await confirmPasswordInput.fill(testPassword);
// Fill form
const emailInput = getField("Email");
await emailInput.fill(testEmail);
const passwordInput = newPage.locator("#password");
await passwordInput.fill(testPassword);
const confirmPasswordInput = newPage.locator("#confirmPassword");
await confirmPasswordInput.fill(testPassword);
// Agree to terms and submit
await getRole("checkbox").click();
const signupButton = getButton("Sign up");
await signupButton.click();
await isVisible(getText("User with this email already exists"));
} catch (_error) {
} finally {
// Clean up new browser context
await newContext.close();
}
} catch (error) {
console.error("❌ Duplicate email handling test failed:", error);
}
// Agree to terms and submit
await getRole("checkbox").click();
const signupButton = getButton("Sign up");
await signupButton.click();
await isVisible(getText("User with this email already exists"));
// Clean up new browser context
await newContext.close();
});

View File

@@ -45,14 +45,11 @@ export async function createTestUser(
await browser.close();
}
} catch (error) {
console.error(`❌ Error creating test user ${userEmail}:`, error);
throw error;
}
}
export async function createTestUsers(count: number): Promise<TestUser[]> {
console.log(`👥 Creating ${count} test users...`);
const users: TestUser[] = [];
let consecutiveFailures = 0;
@@ -61,21 +58,16 @@ export async function createTestUsers(count: number): Promise<TestUser[]> {
const user = await createTestUser();
users.push(user);
consecutiveFailures = 0; // Reset failure counter on success
console.log(`✅ Created user ${i + 1}/${count}: ${user.email}`);
// Small delay to prevent overwhelming the system
if (i < count - 1) {
await new Promise((resolve) => setTimeout(resolve, 500));
}
} catch (error) {
} catch {
consecutiveFailures++;
console.error(`❌ Failed to create user ${i + 1}/${count}:`, error);
// If we have too many consecutive failures, stop trying
if (consecutiveFailures >= 3) {
console.error(
`⚠️ Stopping after ${consecutiveFailures} consecutive failures`,
);
break;
}
@@ -84,7 +76,6 @@ export async function createTestUsers(count: number): Promise<TestUser[]> {
}
}
console.log(`🎉 Successfully created ${users.length}/${count} test users`);
return users;
}
@@ -109,9 +100,7 @@ export async function saveUserPool(
try {
fs.writeFileSync(finalPath, JSON.stringify(userPool, null, 2));
console.log(`✅ Successfully saved user pool to: ${finalPath}`);
} catch (error) {
console.error(`❌ Failed to save user pool to ${finalPath}:`, error);
throw error;
}
}
@@ -122,26 +111,16 @@ export async function loadUserPool(
const defaultPath = path.resolve(process.cwd(), ".auth", "user-pool.json");
const finalPath = filePath || defaultPath;
console.log(`📖 Loading user pool from: ${finalPath}`);
try {
if (!fs.existsSync(finalPath)) {
console.log(`⚠️ User pool file not found: ${finalPath}`);
return null;
}
const fileContent = fs.readFileSync(finalPath, "utf-8");
const userPool: UserPool = JSON.parse(fileContent);
console.log(
`✅ Successfully loaded ${userPool.users.length} users from: ${finalPath}`,
);
console.log(`📅 User pool created at: ${userPool.createdAt}`);
console.log(`🔖 User pool version: ${userPool.version}`);
return userPool;
} catch (error) {
console.error(`❌ Failed to load user pool from ${finalPath}:`, error);
} catch {
return null;
}
}

View File

@@ -20,8 +20,6 @@ export class SigninUtils {
* Perform login and verify success
*/
async loginAndVerify(testUser: TestUser): Promise<void> {
console.log(`🔐 Logging in as: ${testUser.email}`);
await this.page.goto("/login");
await this.loginPage.login(testUser.email, testUser.password);
@@ -33,16 +31,12 @@ export class SigninUtils {
state: "visible",
timeout: 5000,
});
console.log("✅ Login successful");
}
/**
* Perform logout and verify success
*/
async logoutAndVerify(): Promise<void> {
console.log("🚪 Logging out...");
// Open profile menu
await this.page.getByTestId("profile-popout-menu-trigger").click();
@@ -57,16 +51,12 @@ export class SigninUtils {
// Verify we're back on login page
await this.page.waitForURL("/login");
console.log("✅ Logout successful");
}
/**
* Complete authentication cycle: login -> logout -> login
*/
async fullAuthenticationCycle(testUser: TestUser): Promise<void> {
console.log("🔄 Starting full authentication cycle...");
// First login
await this.loginAndVerify(testUser);
@@ -75,8 +65,6 @@ export class SigninUtils {
// Login again
await this.loginAndVerify(testUser);
console.log("✅ Full authentication cycle completed");
}
/**

View File

@@ -45,10 +45,8 @@ export async function signupTestUser(
page.waitForURL(/\/marketplace/, { timeout: 15000 }),
]);
} catch (error) {
console.error(
"❌ Timeout waiting for redirect, current URL:",
page.url(),
);
// eslint-disable-next-line no-console
console.error("Timeout waiting for redirect, current URL:", page.url());
throw error;
}
@@ -95,7 +93,6 @@ export async function signupTestUser(
return testUser;
} catch (error) {
console.error(`❌ Error creating test user ${userEmail}:`, error);
throw error;
}
}
@@ -105,47 +102,34 @@ export async function signupAndNavigateToMarketplace(
email?: string,
password?: string,
): Promise<TestUser> {
console.log("🧪 Creating user and navigating to marketplace...");
// Create the user via signup and automatically navigate to marketplace
const testUser = await signupTestUser(page, email, password, true);
console.log("✅ User successfully created and authenticated in marketplace");
return testUser;
}
export async function validateSignupForm(page: any): Promise<void> {
console.log("🧪 Validating signup form...");
await page.goto("http://localhost:3000/signup");
// Test empty form submission
console.log("❌ Testing empty form submission...");
const signupButton = page.getByRole("button", { name: "Sign up" });
await signupButton.click();
// Should still be on signup page
const currentUrl = page.url();
if (currentUrl.includes("/signup")) {
console.log("✅ Empty form correctly blocked");
} else {
console.log("⚠️ Empty form was not blocked as expected");
}
// Test invalid email
console.log("❌ Testing invalid email...");
await page.getByLabel("Email").fill("invalid-email");
await signupButton.click();
// Should still be on signup page
const currentUrl2 = page.url();
if (currentUrl2.includes("/signup")) {
console.log("✅ Invalid email correctly blocked");
} else {
console.log("⚠️ Invalid email was not blocked as expected");
}
console.log("✅ Signup form validation completed");
}
export function generateTestEmail(): string {