BaseModal.test.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import { render, screen, act } from "@testing-library/react";
  2. import userEvent from "@testing-library/user-event";
  3. import { describe, it, vi, expect } from "vitest";
  4. import BaseModal from "#/components/modals/base-modal/BaseModal";
  5. describe("BaseModal", () => {
  6. it("should render if the modal is open", () => {
  7. const { rerender } = render(
  8. <BaseModal isOpen={false} onOpenChange={vi.fn} title="Settings" />,
  9. );
  10. expect(screen.queryByText("Settings")).not.toBeInTheDocument();
  11. rerender(<BaseModal title="Settings" onOpenChange={vi.fn} isOpen />);
  12. expect(screen.getByText("Settings")).toBeInTheDocument();
  13. });
  14. it("should render an optional subtitle", () => {
  15. render(
  16. <BaseModal
  17. isOpen
  18. onOpenChange={vi.fn}
  19. title="Settings"
  20. subtitle="Subtitle"
  21. />,
  22. );
  23. expect(screen.getByText("Subtitle")).toBeInTheDocument();
  24. });
  25. it("should render actions", async () => {
  26. const onPrimaryClickMock = vi.fn();
  27. const onSecondaryClickMock = vi.fn();
  28. const primaryAction = {
  29. action: onPrimaryClickMock,
  30. label: "Save",
  31. };
  32. const secondaryAction = {
  33. action: onSecondaryClickMock,
  34. label: "Cancel",
  35. };
  36. render(
  37. <BaseModal
  38. isOpen
  39. onOpenChange={vi.fn}
  40. title="Settings"
  41. actions={[primaryAction, secondaryAction]}
  42. />,
  43. );
  44. expect(screen.getByText("Save")).toBeInTheDocument();
  45. expect(screen.getByText("Cancel")).toBeInTheDocument();
  46. await act(async () => {
  47. await userEvent.click(screen.getByText("Save"));
  48. });
  49. expect(onPrimaryClickMock).toHaveBeenCalledTimes(1);
  50. await act(async () => {
  51. await userEvent.click(screen.getByText("Cancel"));
  52. });
  53. expect(onSecondaryClickMock).toHaveBeenCalledTimes(1);
  54. });
  55. it("should close the modal after an action is performed", async () => {
  56. const onOpenChangeMock = vi.fn();
  57. render(
  58. <BaseModal
  59. isOpen
  60. onOpenChange={onOpenChangeMock}
  61. title="Settings"
  62. actions={[
  63. {
  64. label: "Save",
  65. action: () => {},
  66. closeAfterAction: true,
  67. },
  68. ]}
  69. />,
  70. );
  71. await act(async () => {
  72. await userEvent.click(screen.getByText("Save"));
  73. });
  74. expect(onOpenChangeMock).toHaveBeenCalledTimes(1);
  75. });
  76. it("should render children", () => {
  77. render(
  78. <BaseModal isOpen onOpenChange={vi.fn} title="Settings">
  79. <div>Children</div>
  80. </BaseModal>,
  81. );
  82. expect(screen.getByText("Children")).toBeInTheDocument();
  83. });
  84. it("should disable the action given the condition", () => {
  85. const { rerender } = render(
  86. <BaseModal
  87. isOpen
  88. onOpenChange={vi.fn}
  89. title="Settings"
  90. actions={[
  91. {
  92. label: "Save",
  93. action: () => {},
  94. isDisabled: true,
  95. },
  96. ]}
  97. />,
  98. );
  99. expect(screen.getByText("Save")).toBeDisabled();
  100. rerender(
  101. <BaseModal
  102. isOpen
  103. onOpenChange={vi.fn}
  104. title="Settings"
  105. actions={[
  106. {
  107. label: "Save",
  108. action: () => {},
  109. isDisabled: false,
  110. },
  111. ]}
  112. />,
  113. );
  114. expect(screen.getByText("Save")).not.toBeDisabled();
  115. });
  116. it.skip("should not close if the backdrop or escape key is pressed", () => {
  117. const onOpenChangeMock = vi.fn();
  118. render(
  119. <BaseModal
  120. isOpen
  121. onOpenChange={onOpenChangeMock}
  122. title="Settings"
  123. isDismissable={false}
  124. />,
  125. );
  126. act(() => {
  127. userEvent.keyboard("{esc}");
  128. });
  129. // fails because the nextui component wraps the modal content in an aria-hidden div
  130. expect(screen.getByRole("dialog")).toBeVisible();
  131. });
  132. });