feat: add copy functionality for phone and Telegram username in ContactLinks component
- Implemented copy buttons for phone number and Telegram username in the ContactLinks component, enhancing user interaction. - Integrated tooltip feedback to indicate successful copy actions. - Updated tests to cover new copy functionality and ensure proper rendering of copy buttons based on props. - Added localization support for new copy-related strings in the i18n messages.
This commit is contained in:
@@ -4,13 +4,19 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from "vitest";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import { render, screen, fireEvent, act } from "@testing-library/react";
|
||||
import { ContactLinks } from "./ContactLinks";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { resetAppStore } from "@/test/test-utils";
|
||||
|
||||
function renderWithTooltip(ui: React.ReactElement) {
|
||||
return render(<TooltipProvider>{ui}</TooltipProvider>);
|
||||
}
|
||||
|
||||
const openPhoneLinkMock = vi.fn();
|
||||
const openTelegramProfileMock = vi.fn();
|
||||
const triggerHapticLightMock = vi.fn();
|
||||
const copyToClipboardMock = vi.fn();
|
||||
|
||||
vi.mock("@/lib/open-phone-link", () => ({
|
||||
openPhoneLink: (...args: unknown[]) => openPhoneLinkMock(...args),
|
||||
@@ -21,6 +27,9 @@ vi.mock("@/lib/telegram-link", () => ({
|
||||
vi.mock("@/lib/telegram-haptic", () => ({
|
||||
triggerHapticLight: () => triggerHapticLightMock(),
|
||||
}));
|
||||
vi.mock("@/lib/copy-to-clipboard", () => ({
|
||||
copyToClipboard: (...args: unknown[]) => copyToClipboardMock(...args),
|
||||
}));
|
||||
|
||||
describe("ContactLinks", () => {
|
||||
beforeEach(() => {
|
||||
@@ -28,6 +37,7 @@ describe("ContactLinks", () => {
|
||||
openPhoneLinkMock.mockClear();
|
||||
openTelegramProfileMock.mockClear();
|
||||
triggerHapticLightMock.mockClear();
|
||||
copyToClipboardMock.mockClear();
|
||||
});
|
||||
|
||||
it("returns null when phone and username are missing", () => {
|
||||
@@ -100,4 +110,118 @@ describe("ContactLinks", () => {
|
||||
expect(openTelegramProfileMock).toHaveBeenCalledWith("alice_dev");
|
||||
expect(triggerHapticLightMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("showCopyButtons with layout block", () => {
|
||||
it("renders copy phone button with aria-label when phone is present", () => {
|
||||
renderWithTooltip(
|
||||
<ContactLinks
|
||||
phone="+79991234567"
|
||||
username={null}
|
||||
layout="block"
|
||||
showCopyButtons
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
screen.getByRole("button", { name: /Copy phone number|Скопировать номер/i })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders copy Telegram button with aria-label when username is present", () => {
|
||||
renderWithTooltip(
|
||||
<ContactLinks
|
||||
phone={null}
|
||||
username="alice_dev"
|
||||
layout="block"
|
||||
showCopyButtons
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
screen.getByRole("button", {
|
||||
name: /Copy Telegram username|Скопировать логин Telegram/i,
|
||||
})
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls copyToClipboard with raw phone and triggerHapticLight when copy phone is clicked", async () => {
|
||||
copyToClipboardMock.mockResolvedValue(true);
|
||||
renderWithTooltip(
|
||||
<ContactLinks
|
||||
phone="+79991234567"
|
||||
username={null}
|
||||
layout="block"
|
||||
showCopyButtons
|
||||
/>
|
||||
);
|
||||
const copyBtn = screen.getByRole("button", {
|
||||
name: /Copy phone number|Скопировать номер/i,
|
||||
});
|
||||
await act(async () => {
|
||||
fireEvent.click(copyBtn);
|
||||
});
|
||||
|
||||
expect(copyToClipboardMock).toHaveBeenCalledWith("+79991234567");
|
||||
expect(triggerHapticLightMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls copyToClipboard with @username when copy Telegram is clicked", async () => {
|
||||
copyToClipboardMock.mockResolvedValue(true);
|
||||
renderWithTooltip(
|
||||
<ContactLinks
|
||||
phone={null}
|
||||
username="alice_dev"
|
||||
layout="block"
|
||||
showCopyButtons
|
||||
/>
|
||||
);
|
||||
const copyBtn = screen.getByRole("button", {
|
||||
name: /Copy Telegram username|Скопировать логин Telegram/i,
|
||||
});
|
||||
await act(async () => {
|
||||
fireEvent.click(copyBtn);
|
||||
});
|
||||
|
||||
expect(copyToClipboardMock).toHaveBeenCalledWith("@alice_dev");
|
||||
expect(triggerHapticLightMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows Copied text in tooltip after successful copy", async () => {
|
||||
copyToClipboardMock.mockResolvedValue(true);
|
||||
renderWithTooltip(
|
||||
<ContactLinks
|
||||
phone="+79991234567"
|
||||
username={null}
|
||||
layout="block"
|
||||
showCopyButtons
|
||||
/>
|
||||
);
|
||||
const copyBtn = screen.getByRole("button", {
|
||||
name: /Copy phone number|Скопировать номер/i,
|
||||
});
|
||||
await act(async () => {
|
||||
fireEvent.click(copyBtn);
|
||||
});
|
||||
|
||||
const tooltip = await screen.findByRole("tooltip", {
|
||||
name: /Copied|Скопировано/i,
|
||||
});
|
||||
expect(tooltip).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show copy buttons when showCopyButtons is false", () => {
|
||||
render(
|
||||
<ContactLinks
|
||||
phone="+79991234567"
|
||||
username="bob"
|
||||
layout="block"
|
||||
showCopyButtons={false}
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
screen.queryByRole("button", { name: /Copy phone number|Скопировать номер/i })
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByRole("button", { name: /Copy Telegram username|Скопировать логин Telegram/i })
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user