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
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import ProfileNameWithAiMarker from "@/components/common/profile/ProfileNameWithAiMarker";
import { ApiProfileClassification } from "@/generated/models/ApiProfileClassification";

describe("ProfileNameWithAiMarker", () => {
it("includes an accessible AI label while keeping the emoji decorative", () => {
render(
<a href="/ai-bot">
<ProfileNameWithAiMarker classification={ApiProfileClassification.Ai}>
ai-bot
</ProfileNameWithAiMarker>
</a>
);

expect(
screen.getByRole("link", { name: /ai profile ai-bot/i })
).toBeInTheDocument();
expect(screen.getByText("AI profile")).toHaveClass("tw-sr-only");
expect(screen.getByText("🤖")).toHaveAttribute("aria-hidden", "true");
});

it("does not add an AI label for non-AI profiles", () => {
render(
<a href="/human">
<ProfileNameWithAiMarker
classification={ApiProfileClassification.Pseudonym}
>
human
</ProfileNameWithAiMarker>
</a>
);

expect(screen.getByRole("link", { name: "human" })).toBeInTheDocument();
expect(screen.queryByText("AI profile")).not.toBeInTheDocument();
expect(screen.queryByText("🤖")).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,43 +1,56 @@
import { render, screen } from '@testing-library/react';
import type { ApiIdentity } from '@/generated/models/ApiIdentity';
import { ApiProfileClassification } from '@/generated/models/ApiProfileClassification';
import { CLASSIFICATIONS } from '@/entities/IProfile';
import UserPageHeaderName from '@/components/user/user-page-header/name/UserPageHeaderName';
import { render, screen } from "@testing-library/react";
import type { ApiIdentity } from "@/generated/models/ApiIdentity";
import { ApiProfileClassification } from "@/generated/models/ApiProfileClassification";
import { CLASSIFICATIONS } from "@/entities/IProfile";
import UserPageHeaderName from "@/components/user/user-page-header/name/UserPageHeaderName";

jest.mock('@/components/user/user-page-header/name/UserPageHeaderNameWrapper', () => ({
__esModule: true,
default: (props: any) => <div data-testid="name-wrapper">{props.children}</div>,
}));
jest.mock(
"@/components/user/user-page-header/name/UserPageHeaderNameWrapper",
() => ({
__esModule: true,
default: (props: any) => (
<div data-testid="name-wrapper">{props.children}</div>
),
})
);

jest.mock('@/components/user/user-page-header/name/classification/UserPageClassificationWrapper', () => ({
__esModule: true,
default: (props: any) => <div data-testid="classification">{props.children}</div>,
}));
jest.mock(
"@/components/user/user-page-header/name/classification/UserPageClassificationWrapper",
() => ({
__esModule: true,
default: (props: any) => (
<div data-testid="classification">{props.children}</div>
),
})
);

jest.mock('@/components/user/utils/user-cic-type/UserCICTypeIconWrapper', () => ({
__esModule: true,
default: () => <div data-testid="cic-icon" />,
}));
jest.mock(
"@/components/user/utils/user-cic-type/UserCICTypeIconWrapper",
() => ({
__esModule: true,
default: () => <div data-testid="cic-icon" />,
})
);

const baseProfile: ApiIdentity = {
id: '1',
id: "1",
handle: null,
normalised_handle: null,
pfp: null,
cic: 0,
rep: 0,
level: 0,
tdh: 0,
consolidation_key: '',
display: '',
primary_wallet: '',
consolidation_key: "",
display: "",
primary_wallet: "",
banner1: null,
banner2: null,
classification: ApiProfileClassification.Pseudonym,
sub_classification: null,
};

function renderComponent(profile: Partial<ApiIdentity>, mainAddress = '0xabc') {
function renderComponent(profile: Partial<ApiIdentity>, mainAddress = "0xabc") {
const combined = { ...baseProfile, ...profile } as ApiIdentity;
return render(
<UserPageHeaderName
Expand All @@ -50,22 +63,45 @@ function renderComponent(profile: Partial<ApiIdentity>, mainAddress = '0xabc') {
);
}

describe('UserPageHeaderName', () => {
it('shows handle and classification when handle exists', () => {
renderComponent({ handle: 'Alice', classification: ApiProfileClassification.Bot });
expect(screen.getByText('Alice')).toBeInTheDocument();
describe("UserPageHeaderName", () => {
it("shows handle and classification when handle exists", () => {
renderComponent({
handle: "Alice",
classification: ApiProfileClassification.Bot,
});
expect(screen.getByText("Alice")).toBeInTheDocument();
expect(
screen.getByText(CLASSIFICATIONS[ApiProfileClassification.Bot].title)
).toBeInTheDocument();
});

it('shows display when handle missing', () => {
renderComponent({ handle: null, display: 'Display Name' });
expect(screen.getByText('Display Name')).toBeInTheDocument();
it("shows display when handle missing", () => {
renderComponent({ handle: null, display: "Display Name" });
expect(screen.getByText("Display Name")).toBeInTheDocument();
});

it('falls back to main address when no other name', () => {
renderComponent({ handle: null, display: '' }, '0x123');
expect(screen.getByText('0x123')).toBeInTheDocument();
it("falls back to main address when no other name", () => {
renderComponent({ handle: null, display: "" }, "0x123");
expect(screen.getByText("0x123")).toBeInTheDocument();
});

it("shows a robot emoji for AI classification", () => {
renderComponent({
handle: "Robo",
classification: ApiProfileClassification.Ai,
});

expect(screen.getByText("🤖")).toBeInTheDocument();
expect(screen.getByText("AI profile")).toHaveClass("tw-sr-only");
expect(screen.getByTestId("name-wrapper")).toHaveTextContent("Robo");
});

it("does not show a robot emoji for non-AI classifications", () => {
renderComponent({
handle: "Alice",
classification: ApiProfileClassification.Organization,
});

expect(screen.queryByText("🤖")).not.toBeInTheDocument();
});
});
21 changes: 20 additions & 1 deletion __tests__/components/waves/drop/SingleWaveDropAuthor.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { SingleWaveDropAuthor } from "@/components/waves/drop/SingleWaveDropAuthor";
import { ApiProfileClassification } from "@/generated/models/ApiProfileClassification";

jest.mock("next/link", () => ({
__esModule: true,
Expand Down Expand Up @@ -33,14 +34,19 @@ jest.mock("@/components/utils/tooltip/UserProfileTooltipWrapper", () => ({
}));

describe("SingleWaveDropAuthor", () => {
const createDrop = (handle: string | null, primaryAddress: string) =>
const createDrop = (
handle: string | null,
primaryAddress: string,
classification: ApiProfileClassification = ApiProfileClassification.Pseudonym
) =>
({
id: "drop-1",
author: {
handle,
primary_address: primaryAddress,
pfp: null,
level: 3,
classification,
},
}) as any;

Expand Down Expand Up @@ -69,4 +75,17 @@ describe("SingleWaveDropAuthor", () => {
"0x1111111111111111111111111111111111111111"
);
});

it("renders a robot emoji before the name for AI profiles", () => {
render(
<SingleWaveDropAuthor
drop={createDrop("ai-bot", "0xabc", ApiProfileClassification.Ai)}
/>
);

expect(screen.getByText("🤖")).toBeInTheDocument();
expect(
screen.getByRole("link", { name: /ai profile ai-bot/i })
).toBeInTheDocument();
});
});
110 changes: 110 additions & 0 deletions __tests__/components/waves/drops/DropMinimalIdentityRow.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { ApiProfileClassification } from "@/generated/models/ApiProfileClassification";
import DropMinimalIdentityRow from "@/components/waves/drops/DropMinimalIdentityRow";

jest.mock("next/link", () => ({
__esModule: true,
default: ({ href, children, ...props }: any) => (
<a href={href} {...props}>
{children}
</a>
),
}));

jest.mock("next/navigation", () => ({
useRouter: () => ({
push: jest.fn(),
}),
}));

jest.mock("@/components/utils/tooltip/UserProfileTooltipWrapper", () => ({
__esModule: true,
default: ({ user, children }: any) => (
<div data-testid="tooltip-wrapper" data-user={user}>
{children}
</div>
),
}));

jest.mock("@/components/waves/drops/time/WaveDropTime", () => ({
__esModule: true,
default: () => <div data-testid="wave-drop-time" />,
}));

describe("DropMinimalIdentityRow", () => {
const createDrop = (
handle: string | null,
primaryAddress: string,
classification: ApiProfileClassification
) =>
({
id: "drop-1",
created_at: 1710000000000,
author: {
id: "profile-1",
handle,
primary_address: primaryAddress,
classification,
},
}) as any;

it("renders a robot emoji before the author name for AI profiles", () => {
render(
<DropMinimalIdentityRow
drop={createDrop("ai-bot", "0xabc", ApiProfileClassification.Ai)}
/>
);

expect(screen.getByText("🤖")).toBeInTheDocument();
expect(
screen.getByRole("link", { name: /ai profile ai-bot/i })
).toBeInTheDocument();
});

it("does not render a robot emoji for non-AI profiles", () => {
render(
<DropMinimalIdentityRow
drop={createDrop("human", "0xabc", ApiProfileClassification.Pseudonym)}
/>
);

expect(screen.getByRole("link", { name: "human" })).toBeInTheDocument();
expect(screen.getByTestId("tooltip-wrapper")).not.toHaveTextContent("🤖");
});

it("uses the handle for the tooltip lookup when present", () => {
render(
<DropMinimalIdentityRow
drop={createDrop("alice", "0xabc", ApiProfileClassification.Pseudonym)}
/>
);

expect(screen.getByTestId("tooltip-wrapper")).toHaveAttribute(
"data-user",
"alice"
);
});

it("uses the primary address for the tooltip lookup when the handle is missing", () => {
render(
<DropMinimalIdentityRow
drop={createDrop(
null,
"0x1111111111111111111111111111111111111111",
ApiProfileClassification.Pseudonym
)}
/>
);

expect(
screen.getByRole("link", {
name: "0x1111111111111111111111111111111111111111",
})
).toBeInTheDocument();
expect(screen.getByTestId("tooltip-wrapper")).toHaveAttribute(
"data-user",
"0x1111111111111111111111111111111111111111"
);
});
});
Loading
Loading