diff --git a/src/App.test.tsx b/src/App.test.tsx index aab3310e..fd322424 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -4,7 +4,7 @@ import App from "./App"; import { QueryClient, QueryClientProvider } from "react-query"; test("renders the App", () => { - const queryClient = new QueryClient(); // Initialize a new QueryClient + const queryClient = new QueryClient(); render( diff --git a/src/__mocks__/data/Sources.json b/src/__mocks__/data/Sources.json index 35b44573..153ee1a7 100644 --- a/src/__mocks__/data/Sources.json +++ b/src/__mocks__/data/Sources.json @@ -5,7 +5,7 @@ "key": "val" }, "description": "", - "name": "test-cass", + "name": "test-case", "schema": "schema321", "type": "io.debezium.connector.cassandra.CassandraConnector", "vaults": [] diff --git a/src/__test__/unit/moduleMocks.ts b/src/__test__/unit/moduleMocks.ts new file mode 100644 index 00000000..8564e730 --- /dev/null +++ b/src/__test__/unit/moduleMocks.ts @@ -0,0 +1,17 @@ +import { vi } from 'vitest'; + +export const mockNavigate = vi.fn(); + +export const setupMocks = () => { + vi.mock("react-router-dom", async () => { + const actual = await vi.importActual("react-router-dom"); + return { + ...actual, + useNavigate: () => mockNavigate, + }; + }); + + vi.mock("./AppContext", () => ({ + useData: vi.fn(), + })); +}; \ No newline at end of file diff --git a/src/appLayout/AppHeader.test.tsx b/src/appLayout/AppHeader.test.tsx new file mode 100644 index 00000000..39b2e56a --- /dev/null +++ b/src/appLayout/AppHeader.test.tsx @@ -0,0 +1,81 @@ +import { render, screen, fireEvent } from "@testing-library/react"; +import { expect, test, vi, describe, beforeEach } from "vitest"; +import { MemoryRouter } from "react-router-dom"; + +// Mocking modules +vi.mock("react-router-dom", async () => { + const actual = await vi.importActual("react-router-dom"); + return { + ...actual, + useNavigate: () => mockNavigate, + }; +}); + +vi.mock("./AppContext", () => ({ + useData: vi.fn(), +})); + +// Mock functions +const mockNavigate = vi.fn(); +const mockToggleSidebar = vi.fn(); +const mockHandleNotificationBadgeClick = vi.fn(); +const mockGetNotificationBadgeVariant = vi.fn(); +const mockAddNotification = vi.fn(); + +// Import AppHeader after mocking dependencies +import AppHeader from "./AppHeader"; +import { useData } from "./AppContext"; + +// Helper function to render AppHeader +const renderAppHeader = (darkMode = false) => { + vi.mocked(useData).mockReturnValue({ + navigationCollapsed: false, + darkMode, + setDarkMode: vi.fn(), + updateNavigationCollapsed: vi.fn(), + }); + + render( + + + + ); +}; + +describe("AppHeader", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + test("renders the AppHeader component with logo", () => { + renderAppHeader(); + const logoImage = screen.getByAltText("Debezium Logo"); + expect(logoImage).toBeInTheDocument(); + }); + + test("toggles sidebar when button is clicked", () => { + renderAppHeader(); + const toggleButton = screen.getByLabelText("Global navigation"); + fireEvent.click(toggleButton); + expect(mockToggleSidebar).toHaveBeenCalledTimes(1); + }); + + test("handles notification badge click", () => { + renderAppHeader(); + const notificationBadge = screen.getByLabelText("Notifications"); + fireEvent.click(notificationBadge); + expect(mockHandleNotificationBadgeClick).toHaveBeenCalledTimes(1); + }); + + test("navigates to home page when logo is clicked", () => { + renderAppHeader(); + const logoImage = screen.getByAltText("Debezium Logo"); + fireEvent.click(logoImage); + expect(mockNavigate).toHaveBeenCalledWith("/"); + }); +}); \ No newline at end of file diff --git a/src/appLayout/AppNotification.test.tsx b/src/appLayout/AppNotification.test.tsx new file mode 100644 index 00000000..5c34a6bc --- /dev/null +++ b/src/appLayout/AppNotification.test.tsx @@ -0,0 +1,238 @@ +import { + render, + screen, + fireEvent, + act, + waitFor, +} from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import AppNotification from "./AppNotification"; +import { NotificationProps } from "./AppNotificationContext"; + +// Mock notifications +const mockNotifications: NotificationProps[] = [ + { + key: "1", + variant: "info", + title: "Test Notification 1", + srTitle: "Screen Reader Title 1", + description: "This is a test notification", + timestamp: "5 minutes ago", + isNotificationRead: false, + }, + { + key: "2", + variant: "success", + title: "Test Notification 2", + srTitle: "Screen Reader Title 2", + description: "This is another test notification", + timestamp: "10 minutes ago", + isNotificationRead: true, + }, +]; + +describe("AppNotification", () => { + const mockSetNotifications = vi.fn(); + const mockSetDrawerExpanded = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders correctly with notifications", () => { + render( + + ); + + expect(screen.getByText("Test Notification 1")).toBeDefined(); + expect(screen.getByText("Test Notification 2")).toBeDefined(); + expect(screen.getByText("This is a test notification")).toBeDefined(); + expect(screen.getByText("This is another test notification")).toBeDefined(); + }); + + it("displays correct unread notification count", () => { + render( + + ); + + expect(screen.getByText("1 unread")).toBeDefined(); + }); + + it("marks a notification as read when clicked", () => { + const setNotifications = vi.fn((updater) => { + const updatedNotifications = updater(mockNotifications); + render( + + ); + }); + + render( + + ); + + expect(screen.getByText("1 unread")).toBeDefined(); + + fireEvent.click(screen.getByText("Test Notification 1")); + + expect(setNotifications).toHaveBeenCalled(); + expect(screen.getByText("0 unread")).toBeDefined(); + }); + + it('removes a notification when "Clear" is clicked', async () => { + let currentNotifications = [...mockNotifications]; + const setNotifications = vi.fn((updater) => { + currentNotifications = updater(currentNotifications); + rerender( + + ); + }); + + const { rerender } = render( + + ); + + expect(screen.getByText("Test Notification 1")).toBeInTheDocument(); + + // Open the dropdown for the first notification + await act(async () => { + fireEvent.click(screen.getAllByLabelText(/Notification \d+ actions/)[0]); + }); + + // Click the "Clear" option + await act(async () => { + fireEvent.click(screen.getByText("Clear")); + }); + + expect(setNotifications).toHaveBeenCalled(); + + // Wait for the component to update + await waitFor(() => { + expect(screen.queryByText("Test Notification 1")).not.toBeInTheDocument(); + }); + }); + + it('marks all notifications as read when "Mark all read" is clicked', async () => { + let currentNotifications = [...mockNotifications]; + const setNotifications = vi.fn((updater) => { + currentNotifications = updater(currentNotifications); + rerender( + + ); + }); + + const { rerender } = render( + + ); + + // Open the main dropdown + await act(async () => { + fireEvent.click(screen.getByLabelText("Notification drawer actions")); + }); + + // Wait for any pending updates + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 0)); + }); + + await act(async () => { + fireEvent.click(screen.getByText("Mark all read")); + }); + + expect(setNotifications).toHaveBeenCalled(); + expect(screen.getByText("0 unread")).toBeDefined(); + expect(screen.getByText("Test Notification 1")).toBeDefined(); + expect(screen.getByText("Test Notification 2")).toBeDefined(); + }); + + it('clears all notifications when "Clear all" is clicked', async () => { + let currentNotifications = [...mockNotifications]; + const setNotifications = vi.fn((newNotificationsOrUpdater) => { + if (typeof newNotificationsOrUpdater === "function") { + currentNotifications = newNotificationsOrUpdater(currentNotifications); + } else { + currentNotifications = newNotificationsOrUpdater; + } + rerender( + + ); + }); + + const { rerender } = render( + + ); + + expect(screen.getByText("1 unread")).toBeDefined(); + + await act(async () => { + fireEvent.click(screen.getByLabelText("Notification drawer actions")); + }); + + await act(async () => { + fireEvent.click(screen.getByText("Clear all")); + }); + + expect(setNotifications).toHaveBeenCalled(); + await waitFor(() => { + expect(screen.getByText("0 unread")).toBeDefined(); + expect(screen.getByText("No notifications found")).toBeDefined(); + expect( + screen.getByText("There are currently no notifications.") + ).toBeDefined(); + }); + }); + + it("renders empty state when there are no notifications", () => { + render( + + ); + + expect(screen.getByText("No notifications found")).toBeDefined(); + expect( + screen.getByText("There are currently no notifications.") + ).toBeDefined(); + }); +}); diff --git a/src/pages/Destination/Destinations.test.tsx b/src/pages/Destination/Destinations.test.tsx new file mode 100644 index 00000000..34bc4a60 --- /dev/null +++ b/src/pages/Destination/Destinations.test.tsx @@ -0,0 +1,147 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { Destinations } from "./Destinations"; +import { useQuery } from "react-query"; +import { useDeleteData } from "src/apis"; +import { useNotification } from "../../appLayout/AppNotificationContext"; +import destinationsMock from "../../__mocks__/data/Destinations.json"; +import pipelinesMock from "../../__mocks__/data/Pipelines.json"; // Add this import + +vi.mock("react-router-dom", () => ({ + useNavigate: () => vi.fn(), +})); + +// Mock the react-query hooks and QueryClient +vi.mock("react-query", async (importOriginal) => { + const mod = await importOriginal(); + return { + ...mod, + useQuery: vi.fn(), + QueryClient: vi.fn().mockImplementation(() => ({ + // Add any methods you need to mock from QueryClient + invalidateQueries: vi.fn(), + })), + }; +}); + +vi.mock("src/apis", () => ({ + useDeleteData: vi.fn(), +})); + +vi.mock("../../appLayout/AppNotificationContext", () => ({ + useNotification: vi.fn(), +})); + +describe("Sources", () => { + const mockDestinations = destinationsMock; + const mockPipelines = pipelinesMock; // Add this line + + beforeEach(() => { + vi.clearAllMocks(); + + // Mock useQuery to return sources + vi.mocked(useQuery).mockImplementation((key) => { + if (key === "destinations") { + return { + data: mockDestinations, + error: null, + isLoading: false, + } as any; + } else if (key === "pipelines") { + return { + data: mockPipelines, + error: null, + isLoading: false, + } as any; + } + return { data: undefined, error: null, isLoading: false } as any; + }); + + vi.mocked(useDeleteData).mockReturnValue({ + mutate: vi.fn(), + } as any); + + vi.mocked(useNotification).mockReturnValue({ + addNotification: vi.fn(), + } as any); + }); + + it("displays loading state when data is being fetched", () => { + vi.mocked(useQuery).mockReturnValue({ + data: undefined, + error: null, + isLoading: true, + } as any); + + render(); + + expect(screen.getByText("Loading")).toBeInTheDocument(); + }); + + it("displays error message when API fails", async () => { + // Mock the useQuery hook to simulate an API failure for destinations + vi.mocked(useQuery).mockImplementation((key) => { + if (key === "destinations") { + return { + data: undefined, + error: new Error("Failed to fetch destinations"), + isLoading: false, + } as any; + } + // Keep the original implementation for other queries + return { data: undefined, error: null, isLoading: false } as any; + }); + + render(); + + await waitFor(() => { + expect(screen.getByText("Error: Failed to fetch destinations")).toBeInTheDocument(); + }); + }); + + it("renders destinations when data is loaded", async () => { + render(); + + await waitFor(() => { + expect(screen.getByText("test-infi")).toBeInTheDocument(); + expect(screen.getByText("2 Items")).toBeInTheDocument(); + }); + }); + + it("filters destinations based on search input", async () => { + render(); + + const searchInput = screen.getByPlaceholderText("Find by name"); + fireEvent.change(searchInput, { target: { value: "test" } }); + + await waitFor(() => { + expect(screen.getByText("test-infi")).toBeInTheDocument(); + }); + }); + + it("filters destinations for unknown search input and clears search", async () => { + render(); + + const searchInput = screen.getByPlaceholderText("Find by name"); + fireEvent.change(searchInput, { target: { value: "xxx" } }); + + await waitFor(() => { + expect(screen.getByText("0 Items")).toBeInTheDocument(); + expect( + screen.getByText("No matching destination is present.") + ).toBeInTheDocument(); + expect(screen.getByText("Clear search")).toBeInTheDocument(); + }); + + const clearButton = screen.getByText("Clear search"); + fireEvent.click(clearButton); + + await waitFor(() => { + expect(searchInput).toHaveValue(""); + expect(screen.getByText("2 Items")).toBeInTheDocument(); + }); + }); + + +}); diff --git a/src/pages/NotFound/NotFound.test.tsx b/src/pages/NotFound/NotFound.test.tsx new file mode 100644 index 00000000..231aad6f --- /dev/null +++ b/src/pages/NotFound/NotFound.test.tsx @@ -0,0 +1,46 @@ +import { render, screen } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { NotFound } from "./NotFound"; +import { MemoryRouter } from "react-router-dom"; +import { useData } from "../../appLayout/AppContext"; + +vi.mock("react-router-dom", async () => { + const actual = await vi.importActual("react-router-dom"); + return { + ...actual, + useNavigate: () => vi.fn(), + }; +}); + +vi.mock("../../appLayout/AppContext", () => ({ + useData: vi.fn(), +})); + +describe("NotFound Component", () => { + beforeEach(() => { + vi.mocked(useData).mockReturnValue({ + darkMode: false, + navigationCollapsed: false, + setDarkMode: vi.fn(), + updateNavigationCollapsed: vi.fn(), + }); + }); + + it("renders the component with correct content", () => { + render( + + + + ); + + expect( + screen.getByText( + "We didn't find a page that matches the address you navigated to." + ) + ).toBeInTheDocument(); + expect(screen.getByText("Take me home")).toBeInTheDocument(); + expect(screen.getByText("Source")).toBeInTheDocument(); + expect(screen.getByText("Destination")).toBeInTheDocument(); + expect(screen.getByText("Pipeline")).toBeInTheDocument(); + }); +}); diff --git a/src/pages/Pipeline/Pipelines.test.tsx b/src/pages/Pipeline/Pipelines.test.tsx new file mode 100644 index 00000000..1ac83f63 --- /dev/null +++ b/src/pages/Pipeline/Pipelines.test.tsx @@ -0,0 +1,84 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { Pipelines } from "./Pipelines"; +import { useQuery } from "react-query"; +import { useDeleteData } from "src/apis"; +import { useNotification } from "../../appLayout/AppNotificationContext"; +import pipelinesMock from "../../__mocks__/data/Pipelines.json"; + +vi.mock("react-router-dom", () => ({ + useNavigate: () => vi.fn(), +})); + +vi.mock("react-query", async (importOriginal) => { + const mod = await importOriginal(); + return { + ...mod, + useQuery: vi.fn(), + QueryClient: vi.fn().mockImplementation(() => ({ + invalidateQueries: vi.fn(), + })), + }; +}); + +vi.mock("src/apis", () => ({ + useDeleteData: vi.fn(), +})); + +vi.mock("../../appLayout/AppNotificationContext", () => ({ + useNotification: vi.fn(), +})); + +describe("Pipelines", () => { + const mockPipelines = pipelinesMock; + + beforeEach(() => { + vi.clearAllMocks(); + + vi.mocked(useQuery).mockReturnValue({ + data: mockPipelines, + error: null, + isLoading: false, + } as any); + + vi.mocked(useDeleteData).mockReturnValue({ + mutate: vi.fn(), + } as any); + + vi.mocked(useNotification).mockReturnValue({ + addNotification: vi.fn(), + } as any); + }); + + it("renders pipelines when data is loaded", async () => { + render(); + + await waitFor(() => { + expect(screen.getByText("indra-ui-test")).toBeInTheDocument(); + }); + }); + + it("displays loading state when data is being fetched", () => { + vi.mocked(useQuery).mockReturnValue({ + data: undefined, + error: null, + isLoading: true, + } as any); + + render(); + + expect(screen.getByText("Loading...")).toBeInTheDocument(); + }); + + it("filters pipelines based on search input", async () => { + render(); + + const searchInput = screen.getByPlaceholderText("Find by name"); + fireEvent.change(searchInput, { target: { value: "test" } }); + + await waitFor(() => { + expect(screen.getByText("indra-ui-test")).toBeInTheDocument(); + }); + }); +}); diff --git a/src/pages/Pipeline/Pipelines.tsx b/src/pages/Pipeline/Pipelines.tsx index e43a81e1..c5f120a9 100644 --- a/src/pages/Pipeline/Pipelines.tsx +++ b/src/pages/Pipeline/Pipelines.tsx @@ -346,7 +346,7 @@ const Pipelines: React.FunctionComponent = () => { - +
diff --git a/src/pages/Source/Sources.test.tsx b/src/pages/Source/Sources.test.tsx new file mode 100644 index 00000000..3059df1b --- /dev/null +++ b/src/pages/Source/Sources.test.tsx @@ -0,0 +1,144 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { Sources } from "./Sources"; +import { useQuery } from "react-query"; +import { useDeleteData } from "src/apis"; +import { useNotification } from "../../appLayout/AppNotificationContext"; +import sourcesMock from "../../__mocks__/data/Sources.json"; +import pipelinesMock from "../../__mocks__/data/Pipelines.json"; // Add this import + +vi.mock("react-router-dom", () => ({ + useNavigate: () => vi.fn(), +})); + +vi.mock("react-query", async (importOriginal) => { + const mod = await importOriginal(); + return { + ...mod, + useQuery: vi.fn(), + QueryClient: vi.fn().mockImplementation(() => ({ + invalidateQueries: vi.fn(), + })), + }; +}); + +vi.mock("src/apis", () => ({ + useDeleteData: vi.fn(), +})); + +vi.mock("../../appLayout/AppNotificationContext", () => ({ + useNotification: vi.fn(), +})); + +describe("Sources", () => { + const mockSources = sourcesMock; + const mockPipelines = pipelinesMock; + + beforeEach(() => { + vi.clearAllMocks(); + + vi.mocked(useQuery).mockImplementation((key) => { + if (key === "sources") { + return { + data: mockSources, + error: null, + isLoading: false, + } as any; + } else if (key === "pipelines") { + return { + data: mockPipelines, + error: null, + isLoading: false, + } as any; + } + return { data: undefined, error: null, isLoading: false } as any; + }); + + vi.mocked(useDeleteData).mockReturnValue({ + mutate: vi.fn(), + } as any); + + vi.mocked(useNotification).mockReturnValue({ + addNotification: vi.fn(), + } as any); + }); + + it("displays loading state when data is being fetched", () => { + vi.mocked(useQuery).mockReturnValue({ + data: undefined, + error: null, + isLoading: true, + } as any); + + render(); + + expect(screen.getByText("Loading")).toBeInTheDocument(); + }); + + it("displays error message when API fails", async () => { + // Mock the useQuery hook to simulate an API failure for sources + vi.mocked(useQuery).mockImplementation((key) => { + if (key === "sources") { + return { + data: undefined, + error: new Error("Failed to fetch sources"), + isLoading: false, + } as any; + } + // Keep the original implementation for other queries + return { data: undefined, error: null, isLoading: false } as any; + }); + + render(); + + await waitFor(() => { + expect( + screen.getByText("Error: Failed to fetch sources") + ).toBeInTheDocument(); + }); + }); + + it("renders pipelines when data is loaded", async () => { + render(); + + await waitFor(() => { + expect(screen.getByText("test-source-mongo")).toBeInTheDocument(); + expect(screen.getByText("2 Items")).toBeInTheDocument(); + }); + }); + + it("filters Sources based on search input", async () => { + render(); + + const searchInput = screen.getByPlaceholderText("Find by name"); + fireEvent.change(searchInput, { target: { value: "source" } }); + + await waitFor(() => { + expect(screen.getByText("test-source-mongo")).toBeInTheDocument(); + }); + }); + + it("filters sources for unknown search input and clears search", async () => { + render(); + + const searchInput = screen.getByPlaceholderText("Find by name"); + fireEvent.change(searchInput, { target: { value: "xxx" } }); + + await waitFor(() => { + expect(screen.getByText("0 Items")).toBeInTheDocument(); + expect( + screen.getByText("No matching source is present.") + ).toBeInTheDocument(); + expect(screen.getByText("Clear search")).toBeInTheDocument(); + }); + + const clearButton = screen.getByText("Clear search"); + fireEvent.click(clearButton); + + await waitFor(() => { + expect(searchInput).toHaveValue(""); + expect(screen.getByText("2 Items")).toBeInTheDocument(); + }); + }); +}); diff --git a/src/pages/Source/Sources.tsx b/src/pages/Source/Sources.tsx index 4880acde..86470f97 100644 --- a/src/pages/Source/Sources.tsx +++ b/src/pages/Source/Sources.tsx @@ -103,19 +103,6 @@ const Sources: React.FunctionComponent = () => { /> ) : ( <> - {/* - Source - {isLoading || sourcesList.length > 0 ? ( - - Lists the available sources configured in the cluster - streaming change events from a source database. You can search - a source by its name or sort the list by the count of active - pipelines using a source. - - ) : ( - <> - )} - */} { + const actual = await vi.importActual("react-router-dom"); + return { + ...actual, + useNavigate: () => vi.fn(), + }; +}); + +vi.mock("../../appLayout/AppContext", () => ({ + useData: vi.fn(), +})); + +describe("Transformation Component", () => { + beforeEach(() => { + vi.mocked(useData).mockReturnValue({ + darkMode: false, + navigationCollapsed: false, + setDarkMode: vi.fn(), + updateNavigationCollapsed: vi.fn(), + }); + }); + + it("renders the Transformation component with correct content", () => { + render( + + + + ); + + expect(screen.getByAltText("Coming Soon")).toBeInTheDocument(); + expect(screen.getByText("No transformation available")).toBeInTheDocument(); + expect(screen.getByText("Add Transformation")).toBeInTheDocument(); + expect(screen.getByText("Go to source")).toBeInTheDocument(); + expect(screen.getByText("Go to destination")).toBeInTheDocument(); + expect(screen.getByText("Go to pipeline")).toBeInTheDocument(); + }); +}); diff --git a/src/pages/Vault/Valuts.test.tsx b/src/pages/Vault/Valuts.test.tsx new file mode 100644 index 00000000..1f5f5963 --- /dev/null +++ b/src/pages/Vault/Valuts.test.tsx @@ -0,0 +1,46 @@ +import { render, screen } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { Vaults } from "./Vaults"; +import { MemoryRouter } from "react-router-dom"; +import { useData } from "../../appLayout/AppContext"; + +vi.mock("react-router-dom", async () => { + const actual = await vi.importActual("react-router-dom"); + return { + ...actual, + useNavigate: () => vi.fn(), + }; +}); + +vi.mock("../../appLayout/AppContext", () => ({ + useData: vi.fn(), +})); + +describe("Vaults Component", () => { + beforeEach(() => { + vi.mocked(useData).mockReturnValue({ + darkMode: false, + navigationCollapsed: false, + setDarkMode: vi.fn(), + updateNavigationCollapsed: vi.fn(), + }); + }); + + it("renders the Vaults component with correct content", () => { + render( + + + + ); + + expect(screen.getByAltText("Coming Soon")).toBeInTheDocument(); + expect(screen.getByText("No vaults available")).toBeInTheDocument(); + expect( + screen.getByText(/No vaults is configure for this cluster yet/) + ).toBeInTheDocument(); + expect(screen.getByText("Add vaults")).toBeInTheDocument(); + expect(screen.getByText("Go to source")).toBeInTheDocument(); + expect(screen.getByText("Go to destination")).toBeInTheDocument(); + expect(screen.getByText("Go to pipeline")).toBeInTheDocument(); + }); +});
Name