refactor(tests): use getByRole instead of getByText for interactive elements

- Refactor ~47 test cases across 7 test files to use getByRole
- Improve accessibility testing coverage following Testing Library best practices
- Make tests more robust against text changes (i18n, copy updates)
- Test elements as users (especially screen readers) interact with them
This commit is contained in:
lenhanphung
2025-10-16 15:00:58 +07:00
committed by Benoit TELLIER
parent 4c18bf3a52
commit b9905cbb7a
7 changed files with 52 additions and 46 deletions
+4 -4
View File
@@ -75,7 +75,7 @@ describe("EventDuplication", () => {
preloadedState
);
fireEvent.click(screen.getByText("Duplicate event"));
fireEvent.click(screen.getByRole("menuitem", { name: /Duplicate event/i }));
expect(screen.getAllByText(/Duplicate Event/i)[1]).toBeInTheDocument();
});
@@ -93,10 +93,10 @@ describe("EventDuplication", () => {
preloadedState
);
fireEvent.click(screen.getByText("Duplicate event"));
fireEvent.click(screen.getByRole("menuitem", { name: /Duplicate event/i }));
// Cancel button only appears in expanded mode
fireEvent.click(screen.getByText("More options"));
fireEvent.click(screen.getByRole("button", { name: /More options/i }));
fireEvent.click(screen.getByRole("button", { name: /Cancel/i }));
@@ -166,7 +166,7 @@ describe("EventDisplayModal", () => {
);
fireEvent.click(screen.getByTestId("MoreVertIcon"));
fireEvent.click(screen.getByText("Duplicate event"));
fireEvent.click(screen.getByRole("menuitem", { name: /Duplicate event/i }));
expect(screen.getAllByText(/Duplicate Event/i)[1]).toBeInTheDocument();
expect(
screen.getByDisplayValue(
+1 -1
View File
@@ -103,7 +103,7 @@ async function setupEventPopover(
fireEvent.change(titleInput, { target: { value: "Meeting" } });
// Click More options to expand the dialog
const showMoreButton = screen.getByText("More options");
const showMoreButton = screen.getByRole("button", { name: /More options/i });
fireEvent.click(showMoreButton);
// Check Repeat checkbox to show repeat options
@@ -70,7 +70,7 @@ describe("CalendarPopover", () => {
});
fireEvent.click(colorButtons[0]);
fireEvent.click(screen.getByText(/Create/));
fireEvent.click(screen.getByRole("button", { name: /Create/i }));
expect(spy).toHaveBeenCalled();
@@ -80,7 +80,7 @@ describe("CalendarPopover", () => {
it("calls onClose when Cancel clicked", () => {
renderPopover();
fireEvent.click(screen.getByText(/Cancel/i));
fireEvent.click(screen.getByRole("button", { name: /Cancel/i }));
expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick");
});
@@ -168,7 +168,7 @@ describe("CalendarPopover (editing mode)", () => {
});
// Save
fireEvent.click(screen.getByText(/Save/i));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() =>
expect(spy).toHaveBeenCalledWith(
@@ -229,7 +229,7 @@ describe("CalendarPopover - Tabs Scenarios", () => {
fireEvent.change(screen.getByLabelText(/Name/i), {
target: { value: "Temp Calendar" },
});
fireEvent.click(screen.getByText(/Cancel/i));
fireEvent.click(screen.getByRole("button", { name: /Cancel/i }));
expect(mockOnClose).toHaveBeenCalled();
@@ -291,7 +291,7 @@ describe("CalendarPopover - Tabs Scenarios", () => {
expect(publicButton).toHaveAttribute("aria-pressed", "false");
// Save
fireEvent.click(screen.getByText(/Save/i));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() =>
expect(patchSpy).toHaveBeenCalledWith(
+10 -8
View File
@@ -184,7 +184,7 @@ describe("Event Preview Display", () => {
return () => Promise.resolve(payload) as any;
});
fireEvent.click(screen.getByTestId("MoreVertIcon"));
fireEvent.click(screen.getByText("Delete event"));
fireEvent.click(screen.getByRole("menuitem", { name: /Delete event/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -545,7 +545,9 @@ describe("Event Preview Display", () => {
);
fireEvent.click(screen.getByTestId("MoreVertIcon"));
const emailButton = screen.getByText("Email attendees");
const emailButton = screen.getByRole("menuitem", {
name: /Email attendees/i,
});
expect(emailButton).toBeInTheDocument();
fireEvent.click(emailButton);
@@ -1041,7 +1043,7 @@ describe("Event Full Display", () => {
preloadedState
);
act(() => {
fireEvent.click(screen.getByText("Show More"));
fireEvent.click(screen.getByRole("button", { name: /Show More/i }));
});
await waitFor(() => {
@@ -1054,7 +1056,7 @@ describe("Event Full Display", () => {
// EventDisplay modal doesn't have Repeat checkbox, only RepeatEvent component
// which shows repetition settings when repetition data exists
// Since test event has no repetition data, RepeatEvent component won't show Repeat checkbox
fireEvent.click(screen.getByText("Show Less"));
fireEvent.click(screen.getByRole("button", { name: /Show Less/i }));
});
it("can edit title when user is organizer", () => {
@@ -1193,7 +1195,7 @@ describe("Event Full Display", () => {
const option = await screen.findByText("Calendar Two");
fireEvent.click(option);
fireEvent.click(screen.getByText("Save"));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() => {
expect(spyPut).toHaveBeenCalled();
@@ -1277,7 +1279,7 @@ describe("Event Full Display", () => {
preloadedRecurrence
);
fireEvent.click(screen.getByText("Save"));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() => {
expect(spyUpdateSeries).toHaveBeenCalled();
@@ -1383,7 +1385,7 @@ describe("Event Full Display", () => {
);
// Verify the timezone select shows Asia/Bangkok
fireEvent.click(screen.getByText("Show More"));
fireEvent.click(screen.getByRole("button", { name: /Show More/i }));
// The timezone select should have Asia/Bangkok selected
// Since the component uses formatLocalDateTime, the displayed time will be in local format
@@ -1442,7 +1444,7 @@ describe("Event Full Display", () => {
);
act(() => {
fireEvent.click(screen.getByText("Show More"));
fireEvent.click(screen.getByRole("button", { name: /Show More/i }));
});
expect(screen.getByText("Something went wrong")).toBeInTheDocument();
+13 -9
View File
@@ -117,17 +117,21 @@ describe("EventPopover", () => {
expect(titleInput).toBeInTheDocument();
// Description input is only visible after clicking "Add description" button
const addDescriptionButton = screen.getByText("Add description");
const addDescriptionButton = screen.getByRole("button", {
name: /Add description/i,
});
expect(addDescriptionButton).toBeInTheDocument();
const calendarSelect = screen.getByRole("combobox", { name: /calendar/i });
expect(calendarSelect).toBeInTheDocument();
// Check button
expect(screen.getByText("More options")).toBeInTheDocument();
expect(
screen.getByRole("button", { name: /More options/i })
).toBeInTheDocument();
// Extended mode
fireEvent.click(screen.getByText("More options"));
fireEvent.click(screen.getByRole("button", { name: /More options/i }));
// Back button appears
expect(screen.getByLabelText("show less")).toBeInTheDocument();
@@ -160,7 +164,7 @@ describe("EventPopover", () => {
expect(screen.getByLabelText("Title")).toHaveValue("My Event");
// Click "Add description" button first
fireEvent.click(screen.getByText("Add description"));
fireEvent.click(screen.getByRole("button", { name: /Add description/i }));
fireEvent.change(screen.getByLabelText("Description"), {
target: { value: "Event Description" },
@@ -219,7 +223,7 @@ describe("EventPopover", () => {
return () => Promise.resolve(payload) as any;
});
fireEvent.click(screen.getByText("Save"));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -280,7 +284,7 @@ describe("EventPopover", () => {
});
// Click "Add description" button first
fireEvent.click(screen.getByText("Add description"));
fireEvent.click(screen.getByRole("button", { name: /Add description/i }));
fireEvent.change(screen.getByLabelText("Description"), {
target: { value: newEvent.description },
});
@@ -293,7 +297,7 @@ describe("EventPopover", () => {
return () => Promise.resolve(payload) as any;
});
fireEvent.click(screen.getByText("Save"));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -331,9 +335,9 @@ describe("EventPopover", () => {
renderPopover();
// Cancel button only appears in expanded mode
fireEvent.click(screen.getByText("More options"));
fireEvent.click(screen.getByRole("button", { name: /More options/i }));
fireEvent.click(screen.getByText("Cancel"));
fireEvent.click(screen.getByRole("button", { name: /Cancel/i }));
expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick");
});
@@ -162,7 +162,7 @@ describe("Recurrence Event Behavior Tests", () => {
);
fireEvent.click(screen.getByLabelText("This event"));
fireEvent.click(screen.getByText("Ok"));
fireEvent.click(screen.getByRole("button", { name: /Ok/i }));
await waitFor(() => {
expect(mockEventAction).toHaveBeenCalledWith("solo");
@@ -188,7 +188,7 @@ describe("Recurrence Event Behavior Tests", () => {
);
fireEvent.click(screen.getByLabelText("All the events"));
fireEvent.click(screen.getByText("Ok"));
fireEvent.click(screen.getByRole("button", { name: /Ok/i }));
await waitFor(() => {
expect(mockEventAction).toHaveBeenCalledWith("all");
@@ -265,7 +265,7 @@ describe("Recurrence Event Behavior Tests", () => {
);
fireEvent.click(screen.getByTestId("MoreVertIcon"));
fireEvent.click(screen.getByText("Delete event"));
fireEvent.click(screen.getByRole("menuitem", { name: /Delete event/i }));
await waitFor(() => {
expect(
@@ -339,7 +339,7 @@ describe("Recurrence Event Behavior Tests", () => {
);
fireEvent.click(screen.getByTestId("MoreVertIcon"));
fireEvent.click(screen.getByText("Delete event"));
fireEvent.click(screen.getByRole("menuitem", { name: /Delete event/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -371,7 +371,7 @@ describe("Recurrence Event Behavior Tests", () => {
);
fireEvent.click(screen.getByTestId("MoreVertIcon"));
fireEvent.click(screen.getByText("Delete event"));
fireEvent.click(screen.getByRole("menuitem", { name: /Delete event/i }));
await waitFor(() => {
expect(
@@ -380,7 +380,7 @@ describe("Recurrence Event Behavior Tests", () => {
});
fireEvent.click(screen.getByLabelText("This event"));
fireEvent.click(screen.getByText("Ok"));
fireEvent.click(screen.getByRole("button", { name: /Ok/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -414,7 +414,7 @@ describe("Recurrence Event Behavior Tests", () => {
);
fireEvent.click(screen.getByTestId("MoreVertIcon"));
fireEvent.click(screen.getByText("Delete event"));
fireEvent.click(screen.getByRole("menuitem", { name: /Delete event/i }));
await waitFor(() => {
expect(
@@ -423,7 +423,7 @@ describe("Recurrence Event Behavior Tests", () => {
});
fireEvent.click(screen.getByLabelText("All the events"));
fireEvent.click(screen.getByText("Ok"));
fireEvent.click(screen.getByRole("button", { name: /Ok/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -461,7 +461,7 @@ describe("Recurrence Event Behavior Tests", () => {
});
fireEvent.click(screen.getByLabelText("This event"));
fireEvent.click(screen.getByText("Ok"));
fireEvent.click(screen.getByRole("button", { name: /Ok/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -503,7 +503,7 @@ describe("Recurrence Event Behavior Tests", () => {
});
fireEvent.click(screen.getByLabelText("All the events"));
fireEvent.click(screen.getByText("Ok"));
fireEvent.click(screen.getByRole("button", { name: /Ok/i }));
await waitFor(() => {
expect(getEventSpy).toHaveBeenCalled();
@@ -555,7 +555,7 @@ describe("Recurrence Event Behavior Tests", () => {
target: { value: "Updated Single Instance" },
});
fireEvent.click(screen.getByText("Save"));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -599,7 +599,7 @@ describe("Recurrence Event Behavior Tests", () => {
target: { value: "Updated All Instances" },
});
fireEvent.click(screen.getByText("Save"));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() => {
expect(spy).toHaveBeenCalled();
@@ -621,7 +621,7 @@ describe("Recurrence Event Behavior Tests", () => {
basePreloadedState
);
fireEvent.click(screen.getByText("Show More"));
fireEvent.click(screen.getByRole("button", { name: /Show More/i }));
expect(screen.getByText(/repeat every/i)).toBeInTheDocument();
expect(screen.getByText(/end:/i)).toBeInTheDocument();
@@ -836,7 +836,7 @@ describe("Recurrence Event Behavior Tests", () => {
}
);
fireEvent.click(screen.getByText("Show More"));
fireEvent.click(screen.getByRole("button", { name: /Show More/i }));
// Repetition section should not be visible for non-owner
expect(screen.queryByLabelText(/Repetition/i)).not.toBeInTheDocument();
@@ -1006,7 +1006,7 @@ describe("Recurrence Event Behavior Tests", () => {
// Select "All the events"
fireEvent.click(screen.getByLabelText("All the events"));
fireEvent.click(screen.getByText("Ok"));
fireEvent.click(screen.getByRole("button", { name: /Ok/i }));
await waitFor(() => {
// Update modal should open
@@ -1055,7 +1055,7 @@ describe("Recurrence Event Behavior Tests", () => {
const option = await screen.findByText("Calendar 2");
fireEvent.click(option);
fireEvent.click(screen.getByText("Save"));
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
await waitFor(() => {
expect(moveEventSpy).toHaveBeenCalled();
@@ -289,7 +289,7 @@ describe("EventUpdateModal Recurring to Non-Recurring Conversion", () => {
expect(repeatCheckbox).not.toBeChecked();
// Click Save button
const saveButton = screen.getByText("Save");
const saveButton = screen.getByRole("button", { name: /Save/i });
await act(async () => {
fireEvent.click(saveButton);
@@ -403,7 +403,7 @@ describe("EventUpdateModal Recurring to Non-Recurring Conversion", () => {
fireEvent.click(repeatCheckbox);
});
const saveButton = screen.getByText("Save");
const saveButton = screen.getByRole("button", { name: /Save/i });
await act(async () => {
fireEvent.click(saveButton);
@@ -518,7 +518,7 @@ describe("EventUpdateModal Recurring to Non-Recurring Conversion", () => {
fireEvent.click(repeatCheckbox);
});
const saveButton = screen.getByText("Save");
const saveButton = screen.getByRole("button", { name: /Save/i });
await act(async () => {
fireEvent.click(saveButton);