Skip to content
Merged
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
72 changes: 52 additions & 20 deletions __tests__/components/user/brain/UserPageBrainWrapper.test.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
import { useSeizeConnectContext } from "@/components/auth/SeizeConnectContext";
import UserPageBrainWrapper from "@/components/user/brain/UserPageBrainWrapper";
import { useIdentity } from "@/hooks/useIdentity";
import { render } from "@testing-library/react";
import { render, screen } from "@testing-library/react";

jest.mock("next/navigation", () => ({
useRouter: jest.fn(),
useParams: jest.fn(),
}));
jest.mock("@/components/auth/SeizeConnectContext", () => ({
useSeizeConnectContext: jest.fn(),
}));
jest.mock("@/hooks/useIdentity", () => ({ useIdentity: jest.fn() }));
jest.mock("@/components/user/brain/UserPageDrops", () => (props: any) => (
<div data-testid="drops" {...props} />
<div data-testid="drops">{props.profile?.id ?? "none"}</div>
));

const routerPush = jest.fn();
const useRouter = require("next/navigation").useRouter;
const useParams = require("next/navigation").useParams;
(useRouter as jest.Mock).mockReturnValue({
push: routerPush,
});
(useParams as jest.Mock).mockReturnValue({
user: "alice",
});

function renderWithContext(ctx: any) {
(useSeizeConnectContext as jest.Mock).mockReturnValue({
address: ctx.address,
connectionState: ctx.connectionState ?? "disconnected",
});
const AuthCtx = require("@/components/auth/Auth").AuthContext;
(useIdentity as jest.Mock).mockReturnValue({ profile: ctx.identity });
(useIdentity as jest.Mock).mockReturnValue({
profile: "hydratedIdentity" in ctx ? ctx.hydratedIdentity : ctx.identity,
});
return render(
<AuthCtx.Provider value={ctx.auth as any}>
<UserPageBrainWrapper profile={ctx.identity} />
Expand All @@ -39,33 +36,68 @@ function renderWithContext(ctx: any) {
}

describe("UserPageBrainWrapper", () => {
beforeEach(() => {
routerPush.mockClear();
it("renders a placeholder when brain stays unavailable", () => {
const { container } = renderWithContext({
address: "0x1",
connectionState: "connected",
auth: {
connectedProfile: null,
fetchingProfile: false,
showWaves: false,
},
identity: { id: "1" },
});

expect(screen.queryByTestId("drops")).not.toBeInTheDocument();
expect(container.querySelector(".tw-min-h-screen")).toBeInTheDocument();
});
it("redirects to rep when waves disabled", () => {

it("shows drops when waves enabled", () => {
renderWithContext({
address: "0x1",
connectionState: "connected",
auth: {
connectedProfile: null,
fetchingProfile: false,
showWaves: true,
},
identity: { id: "1" },
});

expect(screen.getByTestId("drops")).toBeInTheDocument();
expect(screen.getByTestId("drops")).toHaveTextContent("1");
});

it("keeps the placeholder while hydration is still pending", () => {
const { container } = renderWithContext({
address: undefined,
connectionState: "initializing",
auth: {
connectedProfile: null,
activeProfileProxy: null,
fetchingProfile: false,
showWaves: false,
},
identity: { id: "1" },
hydratedIdentity: null,
});
expect(routerPush).toHaveBeenCalledWith("/alice");

expect(screen.queryByTestId("drops")).not.toBeInTheDocument();
expect(container.querySelector(".tw-min-h-screen")).toBeInTheDocument();
});

it("shows drops when waves enabled", () => {
const { getByTestId } = renderWithContext({
it("falls back to the server profile when waves are available", () => {
renderWithContext({
address: "0x1",
connectionState: "connected",
auth: {
connectedProfile: null,
activeProfileProxy: null,
fetchingProfile: false,
showWaves: true,
},
identity: { id: "1" },
identity: { id: "server-profile" },
hydratedIdentity: null,
});
expect(getByTestId("drops")).toBeInTheDocument();
expect(routerPush).not.toHaveBeenCalled();

expect(screen.getByTestId("drops")).toHaveTextContent("server-profile");
});
});
159 changes: 151 additions & 8 deletions __tests__/components/user/layout/UserPageTabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,25 @@
jest.mock("@/components/auth/Auth", () => ({
useAuth: () => useAuthMock(),
}));
const useSeizeConnectContextMock = jest.fn();
jest.mock("@/components/auth/SeizeConnectContext", () => ({
useSeizeConnectContext: () => useSeizeConnectContextMock(),
}));
const capacitorMock = jest.fn();
jest.mock("@/hooks/useCapacitor", () => ({
__esModule: true,
default: () => capacitorMock(),
}));
jest.mock("@/components/user/layout/UserPageTab", () => ({
__esModule: true,
default: (p: any) => <div data-testid="tab">{p.tab.id}</div>,
default: (p: any) => (
<div
data-testid="tab"
data-active={p.activeTabId === p.tab.id ? "true" : "false"}
>
{p.tab.id}
</div>
),
}));
jest.mock("@/components/cookies/CookieConsentContext", () => ({
useCookieConsent: jest.fn(),
Expand All @@ -35,20 +46,38 @@
useCookieConsent,
} = require("@/components/cookies/CookieConsentContext");

const getTabIds = () =>
screen.getAllByTestId("tab").map((tab) => tab.textContent);

const getActiveTabIds = () =>
screen
.getAllByTestId("tab")
.filter((tab) => tab.getAttribute("data-active") === "true")

Check failure on line 55 in __tests__/components/user/layout/UserPageTabs.test.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `.dataset` over `getAttribute(…)`.

See more on https://sonarcloud.io/project/issues?id=6529-Collections_6529seize-frontend&issues=AZ0GT0xMgQqyHc8U23Mq&open=AZ0GT0xMgQqyHc8U23Mq&pullRequest=2139
.map((tab) => tab.textContent);

const renderTabs = ({
showWaves,
isIos,
country = "US",
connectedProfile = null,
fetchingProfile = false,
pathname = "/[user]",
address = undefined,
connectionState = "disconnected",
}: {
showWaves: boolean;
isIos: boolean;
country?: string;
connectedProfile?: any;
fetchingProfile?: boolean;
pathname?: string;
address?: string;
connectionState?:
| "initializing"
| "disconnected"
| "connecting"
| "connected"
| "error";
}) => {
const router = { push: jest.fn(), replace: jest.fn() };
(useRouter as jest.Mock).mockReturnValue(router);
Expand All @@ -67,6 +96,10 @@
connectedProfile,
fetchingProfile,
});
useSeizeConnectContextMock.mockReturnValue({
address,
connectionState,
});
return {
router,
...render(<UserPageTabs />),
Expand All @@ -76,15 +109,15 @@
describe("UserPageTabs", () => {
it("filters tabs based on context and platform", () => {
renderTabs({ showWaves: false, isIos: false });
const tabs = screen.getAllByTestId("tab").map((t) => t.textContent);
const tabs = getTabIds();
expect(tabs).not.toContain(USER_PAGE_TAB_IDS.BRAIN);
expect(tabs).not.toContain("stats");
expect(tabs).toContain(USER_PAGE_TAB_IDS.SUBSCRIPTIONS);
});

it("hides subscriptions tab on iOS non-US", () => {
renderTabs({ showWaves: true, isIos: true, country: "CA" });
const tabs = screen.getAllByTestId("tab").map((t) => t.textContent);
const tabs = getTabIds();
expect(tabs).not.toContain(USER_PAGE_TAB_IDS.SUBSCRIPTIONS);
});

Expand All @@ -97,7 +130,7 @@
wallets: [],
},
});
const tabs = screen.getAllByTestId("tab").map((t) => t.textContent);
const tabs = getTabIds();
expect(tabs).toContain(USER_PAGE_TAB_IDS.PROXY);
});

Expand All @@ -110,7 +143,7 @@
wallets: [{ wallet: "testuser" }],
},
});
const tabs = screen.getAllByTestId("tab").map((t) => t.textContent);
const tabs = getTabIds();
expect(tabs).toContain(USER_PAGE_TAB_IDS.PROXY);
});

Expand All @@ -123,13 +156,13 @@
wallets: [{ wallet: "0xSomeOtherWallet" }],
},
});
const tabs = screen.getAllByTestId("tab").map((t) => t.textContent);
const tabs = getTabIds();
expect(tabs).not.toContain(USER_PAGE_TAB_IDS.PROXY);
});

it("hides proxy tab when not connected", () => {
renderTabs({ showWaves: false, isIos: false });
const tabs = screen.getAllByTestId("tab").map((t) => t.textContent);
const tabs = getTabIds();
expect(tabs).not.toContain(USER_PAGE_TAB_IDS.PROXY);
});

Expand All @@ -141,11 +174,121 @@
fetchingProfile: true,
});

const tabs = screen.getAllByTestId("tab").map((t) => t.textContent);
const tabs = getTabIds();
expect(tabs).toContain(USER_PAGE_TAB_IDS.PROXY);
expect(router.replace).not.toHaveBeenCalled();
});

it("avoids redirecting away from brain while wallet state is initializing", () => {
const { router } = renderTabs({
showWaves: false,
isIos: false,
pathname: "/testuser/brain",
connectionState: "initializing",
});

const tabs = getTabIds();
const activeTabs = getActiveTabIds();
expect(tabs).toContain(USER_PAGE_TAB_IDS.BRAIN);
expect(activeTabs).toEqual([USER_PAGE_TAB_IDS.BRAIN]);
expect(router.replace).not.toHaveBeenCalled();
});

it("avoids redirecting away from brain while wallet state is connecting", () => {
const { router } = renderTabs({
showWaves: false,
isIos: false,
pathname: "/testuser/brain",
connectionState: "connecting",
});

const tabs = getTabIds();
const activeTabs = getActiveTabIds();
expect(tabs).toContain(USER_PAGE_TAB_IDS.BRAIN);
expect(activeTabs).toEqual([USER_PAGE_TAB_IDS.BRAIN]);
expect(router.replace).not.toHaveBeenCalled();
});

it("avoids redirecting away from brain while profile access is still loading", () => {
const { router } = renderTabs({
showWaves: false,
isIos: false,
pathname: "/testuser/brain",
address: "0x1",
connectionState: "connected",
fetchingProfile: true,
});

const tabs = getTabIds();
const activeTabs = getActiveTabIds();
expect(tabs).toContain(USER_PAGE_TAB_IDS.BRAIN);
expect(activeTabs).toEqual([USER_PAGE_TAB_IDS.BRAIN]);
expect(router.replace).not.toHaveBeenCalled();
});

it("redirects away from the brain tab after loading when waves stay unavailable", async () => {
const { rerender, router } = renderTabs({
showWaves: false,
isIos: false,
pathname: "/testuser/brain",
address: "0x1",
connectionState: "connected",
fetchingProfile: true,
});

useAuthMock.mockReturnValue({
showWaves: false,
connectedProfile: null,
fetchingProfile: false,
});
useSeizeConnectContextMock.mockReturnValue({
address: "0x1",
connectionState: "connected",
});

rerender(<UserPageTabs />);

await waitFor(() => {
expect(getTabIds()).not.toContain(USER_PAGE_TAB_IDS.BRAIN);
expect(getActiveTabIds()).toEqual([USER_PAGE_TAB_IDS.REP]);
expect(router.replace).toHaveBeenCalledWith("/testuser");
});
});

it("shows the brain tab and avoids redirect once waves become available", async () => {
const { rerender, router } = renderTabs({
showWaves: false,
isIos: false,
pathname: "/testuser/brain",
address: "0x1",
connectionState: "connected",
fetchingProfile: true,
});

useAuthMock.mockReturnValue({
showWaves: true,
connectedProfile: {
normalised_handle: "testuser",
wallets: [{ wallet: "0x1" }],
},
fetchingProfile: false,
});
useSeizeConnectContextMock.mockReturnValue({
address: "0x1",
connectionState: "connected",
});

rerender(<UserPageTabs />);

await waitFor(() => {
const tabs = getTabIds();
const activeTabs = getActiveTabIds();
expect(tabs).toContain(USER_PAGE_TAB_IDS.BRAIN);
expect(activeTabs).toEqual([USER_PAGE_TAB_IDS.BRAIN]);
expect(router.replace).not.toHaveBeenCalled();
});
});

it("redirects away from the proxy tab after loading when the profile is not owned", async () => {
const { rerender, router } = renderTabs({
showWaves: false,
Expand Down
Loading
Loading