From a7c7df2bcd41af8894587b07cee737144849a1cd Mon Sep 17 00:00:00 2001 From: Jerome Tissot Date: Fri, 23 Aug 2024 11:14:42 +0200 Subject: [PATCH] =?UTF-8?q?WILD=5F017:=20Refacto=20-=20Ajout=20test=20pagi?= =?UTF-8?q?nation,=20fix=20test=20li=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- back/src/__tests__/Url.test.ts | 103 ++- back/src/__tests__/UrlResolver.test.ts | 54 +- back/src/database/seeder/dataInput.ts | 7 + back/src/database/seeder/fixtures.ts | 20 + back/src/index.ts | 2 +- docker-compose.test.yaml | 4 + front/src/__tests__/CustomPagination.test.tsx | 54 ++ front/src/__tests__/ListURL.test.tsx | 644 +++++++++--------- front/src/__tests__/UrlHistory.test.tsx | 21 +- front/src/components/landing/ListUrl.tsx | 2 +- front/src/generated/graphql-types.ts | 1 + front/src/hooks/useScreenDimensions.ts | 2 +- 13 files changed, 541 insertions(+), 376 deletions(-) create mode 100644 front/src/__tests__/CustomPagination.test.tsx diff --git a/.gitignore b/.gitignore index faefffd..57f2085 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env .env.test -data/* \ No newline at end of file +data/* +docker-compose-local.test.yaml \ No newline at end of file diff --git a/back/src/__tests__/Url.test.ts b/back/src/__tests__/Url.test.ts index 3033731..e903d13 100644 --- a/back/src/__tests__/Url.test.ts +++ b/back/src/__tests__/Url.test.ts @@ -1,6 +1,6 @@ import dataSource from "../database/dataSource"; import { Url } from "../entities/Url"; -import { ILike } from "typeorm"; + describe("Integration Test Url Entity", () => { beforeAll(async () => { @@ -10,35 +10,102 @@ describe("Integration Test Url Entity", () => { await dataSource.destroy(); }); - it("find method should return a list of Url", async () => { - const urls = await Url.find({ - order: { createdAt: "DESC" }, + it("getPaginateUrls method should return a list of Url", async () => { + const paginateUrls = await Url.getPaginateUrls(1); + + // Check if the result has the expected structure + expect(paginateUrls).toHaveProperty('urls'); + expect(paginateUrls).toHaveProperty('totalPages'); + expect(paginateUrls).toHaveProperty('currentPage'); + expect(paginateUrls).toHaveProperty('previousPage'); + expect(paginateUrls).toHaveProperty('nextPage'); + expect(Array.isArray(paginateUrls.urls)).toBe(true); + + // Check if values have the expected structure + paginateUrls.urls.forEach((url) => { + expect(url).toHaveProperty('id'); + expect(url).toHaveProperty('name'); + expect(url).toHaveProperty('path'); }); + }); - // Check if the result is an array - expect(Array.isArray(urls)).toBeTruthy(); + it("getPaginateUrls method whith searchText should return a list of Url", async () => { + const paginateUrls = await Url.getPaginateUrls(1, "a"); - // Check if values are instances of Url - urls.forEach((url) => { - expect(url).toBeInstanceOf(Url); + // Check if the result has the expected structure + expect(paginateUrls).toHaveProperty('urls'); + expect(paginateUrls).toHaveProperty('totalPages'); + expect(paginateUrls).toHaveProperty('currentPage'); + expect(paginateUrls).toHaveProperty('previousPage'); + expect(paginateUrls).toHaveProperty('nextPage'); + expect(Array.isArray(paginateUrls.urls)).toBe(true); + + // Check if values have the expected structure + paginateUrls.urls.forEach((url) => { + expect(url).toHaveProperty('id'); + expect(url).toHaveProperty('name'); + expect(url).toHaveProperty('path'); }); }); - it("find with where method and order should return a list of Url in clause", async () => { - const urls = await Url.find({ - where: [{ name: ILike(`%Fa%`) }, { path: ILike(`%Fa%`) }], - order: { createdAt: "DESC" }, + it("getPaginateUrls method whith searchText and sortField should return a list of Url", async () => { + const paginateUrls = await Url.getPaginateUrls(1, "a", "name"); + + // Check if the result has the expected structure + expect(paginateUrls).toHaveProperty('urls'); + expect(paginateUrls).toHaveProperty('totalPages'); + expect(paginateUrls).toHaveProperty('currentPage'); + expect(paginateUrls).toHaveProperty('previousPage'); + expect(paginateUrls).toHaveProperty('nextPage'); + expect(Array.isArray(paginateUrls.urls)).toBe(true); + + // Check if values have the expected structure + paginateUrls.urls.forEach((url) => { + expect(url).toHaveProperty('id'); + expect(url).toHaveProperty('name'); + expect(url).toHaveProperty('path'); }); + }); - // Check if the result is an array - expect(Array.isArray(urls)).toBeTruthy(); + it("getPaginateUrls method whith connected user and private url should return a list of Url", async () => { + const paginateUrls = await Url.getPaginateUrls(1, "a", "name", true, "741fbb42-1dd9-40c5-a29e-604407a7bc8c"); - // Check if values are instances of Url - urls.forEach((url) => { - expect(url).toBeInstanceOf(Url); + // Check if the result has the expected structure + expect(paginateUrls).toHaveProperty('urls'); + expect(paginateUrls).toHaveProperty('totalPages'); + expect(paginateUrls).toHaveProperty('currentPage'); + expect(paginateUrls).toHaveProperty('previousPage'); + expect(paginateUrls).toHaveProperty('nextPage'); + expect(Array.isArray(paginateUrls.urls)).toBe(true); + + // Check if values have the expected structure + paginateUrls.urls.forEach((url) => { + expect(url).toHaveProperty('id'); + expect(url).toHaveProperty('name'); + expect(url).toHaveProperty('path'); }); }); + it("getPaginateUrls method whith connected user and public url should return a list of Url", async () => { + const paginateUrls = await Url.getPaginateUrls(1, "a", "name", false, "741fbb42-1dd9-40c5-a29e-604407a7bc8c"); + + // Check if the result has the expected structure + expect(paginateUrls).toHaveProperty('urls'); + expect(paginateUrls).toHaveProperty('totalPages'); + expect(paginateUrls).toHaveProperty('currentPage'); + expect(paginateUrls).toHaveProperty('previousPage'); + expect(paginateUrls).toHaveProperty('nextPage'); + expect(Array.isArray(paginateUrls.urls)).toBe(true); + + // Check if values have the expected structure + paginateUrls.urls.forEach((url) => { + expect(url).toHaveProperty('id'); + expect(url).toHaveProperty('name'); + expect(url).toHaveProperty('path'); + }); + }); + + it("findOneByOrFail method should return a single Url", async () => { const url = await Url.findOneByOrFail({ id: "737fbb42-1dd9-40c5-a29e-604407a7bc7b", diff --git a/back/src/__tests__/UrlResolver.test.ts b/back/src/__tests__/UrlResolver.test.ts index a7f34fb..ea65d24 100644 --- a/back/src/__tests__/UrlResolver.test.ts +++ b/back/src/__tests__/UrlResolver.test.ts @@ -1,5 +1,7 @@ import { Url } from "../entities/Url"; +import PaginateUrls from "@/types/PaginatesUrls"; import UrlResolver from "../resolvers/UrlResolver"; +import { MyContext, JwtPayload } from ".."; type PartialUrl = Partial; @@ -9,6 +11,23 @@ const mockUrl: PartialUrl = { path: "https://example.com", }; const mockUrls: PartialUrl[] = [mockUrl]; +const mockPaginateUrls: PaginateUrls = { + urls: mockUrls as Url[], + totalPages: 1, + currentPage: 1, + previousPage: 1, + nextPage: 1, +}; + +const mockContext: MyContext = { + res: { + setHeader: jest.fn(), + }, + payload: { + id: "testId", + email: "test@test.fr", + } as JwtPayload, +}; describe("Unit Test Url Resolver", () => { let urlResolver: UrlResolver; @@ -21,19 +40,38 @@ describe("Unit Test Url Resolver", () => { jest.restoreAllMocks(); }); - it("Query urls should return an array of Url", async () => { - jest.spyOn(Url, "find").mockImplementation(() => - Promise.resolve(mockUrls as Url[]), + it("Query urls whith context should return a pagination of urls", async () => { + jest.spyOn(Url, "getPaginateUrls").mockImplementation(() => + Promise.resolve(mockPaginateUrls as PaginateUrls), + ); + + const result = await urlResolver.urls(mockContext, false, 1, "", ""); + expect(result).toEqual(mockPaginateUrls); + }); + + it("Query urls whith context should throw an error when fetching urls fails", async () => { + jest.spyOn(Url, "getPaginateUrls").mockRejectedValue( + new Error("Internal server error"), + ); + await expect(urlResolver.urls(mockContext, false, 1, "", "")).rejects.toThrow( + "Internal server error", + ); + }); + + it("Query urls whithout context should return a pagination of urls", async () => { + jest.spyOn(Url, "getPaginateUrls").mockImplementation(() => + Promise.resolve(mockPaginateUrls as PaginateUrls), ); - const result = await urlResolver.urls(); - expect(result).toEqual(mockUrls); + + const result = await urlResolver.urls({} as MyContext, false, 1, "", ""); + expect(result).toEqual(mockPaginateUrls); }); - it("Query urls should throw an error when fetching urls fails", async () => { - jest.spyOn(Url, "find").mockRejectedValue( + it("Query urls whithout context should throw an error when fetching urls fails", async () => { + jest.spyOn(Url, "getPaginateUrls").mockRejectedValue( new Error("Internal server error"), ); - await expect(urlResolver.urls()).rejects.toThrow( + await expect(urlResolver.urls({} as MyContext, false, 1, "", "")).rejects.toThrow( "Internal server error", ); }); diff --git a/back/src/database/seeder/dataInput.ts b/back/src/database/seeder/dataInput.ts index 937d696..b272e11 100644 --- a/back/src/database/seeder/dataInput.ts +++ b/back/src/database/seeder/dataInput.ts @@ -12,3 +12,10 @@ export const historiesData = [ response: "Facebook response", }, ]; + +export const userData = { + id: "e5fb990e-f9d9-4858-82d1-1fd1755485a5", + username: "test", + email: "test@test.fr", + hashedPassword: "hashedPasswordTest", +}; \ No newline at end of file diff --git a/back/src/database/seeder/fixtures.ts b/back/src/database/seeder/fixtures.ts index 6cb8e1b..cf8e6ed 100644 --- a/back/src/database/seeder/fixtures.ts +++ b/back/src/database/seeder/fixtures.ts @@ -1,4 +1,6 @@ import { Url } from "../../entities/Url"; +import { User } from "../../entities/User"; +import { UserUrl } from "../../entities/UserUrl"; import { History } from "../../entities/History"; import dataSource from "../dataSource"; import { urlsData, historiesData } from "./dataInput"; @@ -21,6 +23,24 @@ async function generateFixtures() { return url; }), ); + await Url.create({ + id: "737fbb42-1dd9-40c5-a29e-604407a7bc7b", + name: "TestUrl for fetch private urls", + path: "https://excalidraw.com" + }); + + await User.save({ + id: "741fbb42-1dd9-40c5-a29e-604407a7bc8c", + username: "testuser", + email: "testuser@test.fr", + hashedPassword: "hashedPasswordTest", + }); + + await UserUrl.save({ + userId: "741fbb42-1dd9-40c5-a29e-604407a7bc8c", + urlId: "737fbb42-1dd9-40c5-a29e-604407a7bc7b", + }); + await History.save({ ...historiesData[0], url: savedUrls[0] }); await History.save({ ...historiesData[1], url: savedUrls[1] }); console.log("Fixtures generated successfully!"); diff --git a/back/src/index.ts b/back/src/index.ts index 4fb16c0..cedf763 100644 --- a/back/src/index.ts +++ b/back/src/index.ts @@ -10,7 +10,7 @@ import HistoryResolver from "./resolvers/HistoryResolver"; import UserResolver from "./resolvers/UserResolver"; import UserUrlResolver from "./resolvers/UserUrlResolver"; -interface JwtPayload { +export interface JwtPayload { id: string; email: string; } diff --git a/docker-compose.test.yaml b/docker-compose.test.yaml index 0bd2244..7ecf64a 100644 --- a/docker-compose.test.yaml +++ b/docker-compose.test.yaml @@ -12,6 +12,8 @@ services: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_DB: ${POSTGRES_DB} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + TZ: Europe/Paris + LC_ALL: fr_FR.UTF-8 depends_on: database-test: condition: service_healthy @@ -23,6 +25,8 @@ services: environment: APP_ENV: ${APP_ENV} VITE_API_URL: ${VITE_API_URL} + TZ: Europe/Paris + LC_ALL: fr_FR.UTF-8 database-test: container_name: database-test diff --git a/front/src/__tests__/CustomPagination.test.tsx b/front/src/__tests__/CustomPagination.test.tsx new file mode 100644 index 0000000..1c158d4 --- /dev/null +++ b/front/src/__tests__/CustomPagination.test.tsx @@ -0,0 +1,54 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { describe, it, expect, vi } from 'vitest'; +import CustomPagination from '@/components/custom/CustomPagination'; + + +vi.mock('@/hooks/useScreenDimensions', () => ({ + default: () => ({ width: 1024 }) +})); + +describe('CustomPagination', () => { + const defaultProps = { + currentPage: 3, + totalPages: 10, + previousPage: 2, + nextPage: 4, + onPageChange: vi.fn(), + }; + + it('renders correctly', () => { + render(); + expect(screen.getByText('3')).toHaveAttribute('aria-current', 'page'); + expect(screen.getByText('Précédent')).toBeInTheDocument(); + expect(screen.getByText('Suivant')).toBeInTheDocument(); + }); + + it('calls onPageChange with correct page number when clicking on a page', () => { + render(); + fireEvent.click(screen.getByText('4')); + expect(defaultProps.onPageChange).toHaveBeenCalledWith(4); + }); + + it('calls onPageChange with Previous page when clicking Précédent', () => { + render(); + fireEvent.click(screen.getByText('Précédent')); + expect(defaultProps.onPageChange).toHaveBeenCalledWith(2); + }); + + it('calls onPageChange with next page when clicking Next', () => { + render(); + fireEvent.click(screen.getByText('Suivant')); + expect(defaultProps.onPageChange).toHaveBeenCalledWith(4); + }); + + it('renders ellipsis when there are many pages', () => { + render(); + expect(screen.getAllByText('More pages')).toHaveLength(1); + }); + + it('renders first and last page numbers', () => { + render(); + expect(screen.getByText('1')).toBeInTheDocument(); + expect(screen.getByText('10')).toBeInTheDocument(); + }); +}); \ No newline at end of file diff --git a/front/src/__tests__/ListURL.test.tsx b/front/src/__tests__/ListURL.test.tsx index 9942df4..b0a94fb 100644 --- a/front/src/__tests__/ListURL.test.tsx +++ b/front/src/__tests__/ListURL.test.tsx @@ -1,349 +1,315 @@ -import React from "react"; -import { render, screen, fireEvent } from "@testing-library/react"; -import { MemoryRouter } from "react-router-dom"; // Import as value -import URLList from "@/components/landing/ListUrl"; -import * as graphqlTypes from "@/generated/graphql-types"; -import { vi, describe, it, expect, afterEach } from "vitest"; -import create from "zustand"; -import { act } from "react-dom/test-utils"; - -vi.mock("@/generated/graphql-types", async () => { - const actual = await vi.importActual("@/generated/graphql-types"); - return { - ...actual, - useGetAllURlsQuery: vi.fn(), - }; -}); - -// Define the mock for useListUrlsStore -const setQueryFilterMock = vi.fn(); -const useListUrlsStoreMock = create(() => ({ - queryFilter: "", - setQueryFilter: setQueryFilterMock, -})); - -vi.mock("@/stores/url/useListUrlsStore", () => ({ - __esModule: true, - default: useListUrlsStoreMock, -})); - -describe("URLList", () => { - afterEach(() => { - vi.clearAllMocks(); +import { describe, it, expect } from 'vitest'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { MockedProvider } from '@apollo/client/testing'; +import URLList from '@/components/landing/ListUrl'; +import { GET_ALL_URLS } from '@/graphql/queries'; + +const mockUrls = { + urls: { + urls: [ + { + id: '1', + name: 'Test URL 1', + path: '/test1', + createdAt: new Date().toISOString(), + histories: [ + { + id: 'history1', + response: 'OK', + status_code: 200, + created_at: new Date().toISOString() + } + ] + }, + { + id: '2', + name: 'Test URL 2', + path: '/test2', + createdAt: new Date().toISOString(), + histories: [ + { + id: 'history2', + response: 'Not Found', + status_code: 404, + created_at: new Date().toISOString() + } + ] + }, + ], + totalPages: 2, + currentPage: 1, + previousPage: null, + nextPage: 2, + }, + }; + +const sortedUrls = { + urls: { + urls: [ + { + id: '1', + name: 'Test URL 1', + path: '/test1', + createdAt: new Date().toISOString(), + histories: [ + { + id: 'history1', + response: 'OK', + status_code: 200, + created_at: new Date().toISOString() + } + ] + }, + { + id: '2', + name: 'Test URL 2', + path: '/test2', + createdAt: new Date().toISOString(), + histories: [ + { + id: 'history2', + response: 'Not Found', + status_code: 404, + created_at: new Date().toISOString() + } + ] + }, + ], + totalPages: 2, + currentPage: 1, + previousPage: null, + nextPage: 2, + }, + }; + +const filteredMockUrls = { + urls: { + urls: [ + { + id: '1', + name: 'Test URL 1', + path: '/test1', + createdAt: new Date().toISOString(), + histories: [ + { + id: 'history1', + response: 'OK', + status_code: 200, + created_at: new Date().toISOString() + } + ] + }, + ], + totalPages: 1, + currentPage: 1, + previousPage: null, + nextPage: null, + }, +}; + +const nextPageUrls = { + urls: { + urls: [ + { + id: '3', + name: 'Test URL 3', + path: '/test3', + createdAt: new Date().toISOString(), + histories: [ + { + id: 'history3', + response: 'OK', + status_code: 200, + created_at: new Date().toISOString() + } + ] + }, + { + id: '4', + name: 'Test URL 4', + path: '/test4', + createdAt: new Date().toISOString(), + histories: [ + { + id: 'history4', + response: 'Not Found', + status_code: 404, + created_at: new Date().toISOString() + } + ] + }, + ], + totalPages: 2, + currentPage: 2, + previousPage: 1, + nextPage: null, + }, +}; + +describe('Unit tests URLList', () => { + const defaultMock = { + request: { + query: GET_ALL_URLS, + variables: { searchText: '', sortField: '', currentPage: 1 }, + }, + result: { data: mockUrls }, + }; + + it('renders URLs', async () => { + render( + + + + } /> + + + + ); + await waitFor(() => { + expect(screen.getByText('Test URL 1')).toBeInTheDocument(); + expect(screen.getByText('Test URL 2')).toBeInTheDocument(); }); - - it("should render loading state", () => { - vi.mocked(graphqlTypes.useGetAllURlsQuery).mockReturnValue({ - loading: true, - } as any); - render( - - - , - ); - expect(screen.getByText("Loading")).toBeInTheDocument(); + }); + + it('displays correct status for each URL', async () => { + render( + + + + } /> + + + + ); + await waitFor(() => { + expect(screen.getByText('Status 200')).toBeInTheDocument(); + expect(screen.getByText('Status 404')).toBeInTheDocument(); }); - - it("should render error state", () => { - vi.mocked(graphqlTypes.useGetAllURlsQuery).mockReturnValue({ - error: new Error("Error"), - } as any); - render( - - - , - ); - expect(screen.getByText("Error")).toBeInTheDocument(); + }); + + it('Should display error whith error response', async () => { + const errorMock = { + request: { + query: GET_ALL_URLS, + variables: { searchText: '', sortField: '', currentPage: 1 }, + }, + error: new Error("request error"), + }; + render( + + + + } /> + + + + ); + await waitFor(() => { + expect(screen.getByText('Error')).toBeInTheDocument(); }); - - it("should render URL list", () => { - const mockData = { - urls: [ - { - id: "1", - name: "Test URL 1", - path: "/test1", - createdAt: new Date().toISOString(), - histories: [{ status_code: 200 }], - }, - { - id: "2", - name: "Test URL 2", - path: "/test2", - createdAt: new Date().toISOString(), - histories: [{ status_code: 200 }], - }, - ], - }; - vi.mocked(graphqlTypes.useGetAllURlsQuery).mockReturnValue({ - data: mockData, - loading: false, - } as any); - render( - - - , - ); - expect(screen.getByText("Test URL 1")).toBeInTheDocument(); - expect(screen.getByText("Test URL 2")).toBeInTheDocument(); + }); + + it('displays only filtered URL', async () => { + + const filteredMock = { + request: { + query: GET_ALL_URLS, + variables: { searchText: 'Test URL 1', sortField: '', currentPage: 1 }, + }, + result: { data: filteredMockUrls }, + }; + + render( + + + + } /> + + + + ); + + await waitFor(() => { + expect(screen.getByText('Test URL 1')).toBeInTheDocument(); + expect(screen.getByText('Test URL 2')).toBeInTheDocument(); }); - - it("should handle search", async () => { - const mockData = { - urls: [ - { - id: "1", - name: "Test URL 1", - path: "/test1", - createdAt: new Date().toISOString(), - histories: [{ status_code: 200 }], - }, - { - id: "2", - name: "Test URL 2", - path: "/test2", - createdAt: new Date().toISOString(), - histories: [{ status_code: 200 }], - }, - ], - }; - vi.mocked(graphqlTypes.useGetAllURlsQuery).mockReturnValue({ - data: mockData, - loading: false, - } as any); - - const handleSearchMock = vi.fn(); - - render( - - - , - ); - - const searchInput = screen.getByRole("textbox"); - await fireEvent.change(searchInput, { - target: { value: "Test URL 1" }, - }); - - expect(handleSearchMock).toHaveBeenCalledWith("Test URL 1"); - - act(() => { - useListUrlsStoreMock.setState({ queryFilter: "Test URL 1" }); - }); - - render( - - - , - ); - - expect(screen.getByText("Test URL 1")).toBeInTheDocument(); - expect(screen.queryByText("Test URL 2")).not.toBeInTheDocument(); + + fireEvent.change(screen.getByPlaceholderText('Rechercher...'), { + target: { value: 'Test URL 1' } }); - - it("should handle pagination", async () => { - const mockData = { - urls: Array.from({ length: 48 }, (_, i) => ({ - id: `${i + 1}`, - name: `Test URL ${i + 1}`, - path: `/test${i + 1}`, - createdAt: new Date(Date.now() - i * 60000).toISOString(), - histories: [{ status_code: 200 }], - })), - }; - vi.mocked(graphqlTypes.useGetAllURlsQuery).mockReturnValue({ - data: mockData, - loading: false, - } as any); - - render( - - - , - ); - - await screen.findByText("Test URL 1"); - expect(screen.getByText("Test URL 1")).toBeInTheDocument(); - expect(screen.getByText("Test URL 24")).toBeInTheDocument(); - expect(screen.queryByText("Test URL 25")).not.toBeInTheDocument(); - - const nextPageButton = screen.getByText("2"); - await fireEvent.click(nextPageButton); - - await screen.findByText("Test URL 25"); - expect(screen.getByText("Test URL 25")).toBeInTheDocument(); - expect(screen.getByText("Test URL 48")).toBeInTheDocument(); - expect(screen.queryByText("Test URL 24")).not.toBeInTheDocument(); - - const previousPageButton = screen.getByText("1"); - await fireEvent.click(previousPageButton); - - await screen.findByText("Test URL 1"); - expect(screen.getByText("Test URL 1")).toBeInTheDocument(); - expect(screen.getByText("Test URL 24")).toBeInTheDocument(); - expect(screen.queryByText("Test URL 25")).not.toBeInTheDocument(); - - const nextPageText = screen.getByText("Suivant"); - await fireEvent.click(nextPageText); - - await screen.findByText("Test URL 25"); - expect(screen.getByText("Test URL 25")).toBeInTheDocument(); - expect(screen.getByText("Test URL 48")).toBeInTheDocument(); - expect(screen.queryByText("Test URL 24")).not.toBeInTheDocument(); - - const previousPageText = screen.getByText("Précédent"); - await fireEvent.click(previousPageText); - - await screen.findByText("Test URL 1"); - expect(screen.getByText("Test URL 1")).toBeInTheDocument(); - expect(screen.getByText("Test URL 24")).toBeInTheDocument(); - expect(screen.queryByText("Test URL 25")).not.toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByText('Test URL 1')).toBeInTheDocument(); + expect(screen.queryByText('Test URL 2')).not.toBeInTheDocument(); }); - - it("should display correct status for different HTTP status codes", async () => { - const mockData = { - urls: [ - { - id: "1", - name: "URL with 200 status", - path: "/test1", - createdAt: new Date().toISOString(), - histories: [{ status_code: 200 }], - }, - { - id: "2", - name: "URL with 300 status", - path: "/test2", - createdAt: new Date().toISOString(), - histories: [{ status_code: 300 }], - }, - { - id: "3", - name: "URL with 400 status", - path: "/test3", - createdAt: new Date().toISOString(), - histories: [{ status_code: 400 }], - }, - { - id: "4", - name: "URL with 500 status", - path: "/test4", - createdAt: new Date().toISOString(), - histories: [{ status_code: 500 }], - }, - { - id: "5", - name: "URL with unknown status", - path: "/test5", - createdAt: new Date().toISOString(), - histories: [{ status_code: 999 }], - }, - { - id: "6", - name: "URL with status null", - path: "/test6", - createdAt: new Date().toISOString(), - histories: [], - }, - ], - }; - - vi.mocked(graphqlTypes.useGetAllURlsQuery).mockReturnValue({ - data: mockData, - loading: false, - } as any); - - render( - - - , - ); - - const url200 = await screen.findByText("URL with 200 status"); - expect(url200).toBeInTheDocument(); - expect(screen.getByText("Status 200")).toBeInTheDocument(); - const statusIndicators = screen.getAllByTestId("status-indicator"); - expect(statusIndicators[0]).toHaveClass("bg-green-500"); - - const url300 = await screen.findByText("URL with 300 status"); - expect(url300).toBeInTheDocument(); - expect(screen.getByText("Status 300")).toBeInTheDocument(); - expect(statusIndicators[1]).toHaveClass("bg-yellow-500"); - - const url400 = await screen.findByText("URL with 400 status"); - expect(url400).toBeInTheDocument(); - expect(screen.getByText("Status 400")).toBeInTheDocument(); - expect(statusIndicators[2]).toHaveClass("bg-red-500"); - - const url500 = await screen.findByText("URL with 500 status"); - expect(url500).toBeInTheDocument(); - expect(screen.getByText("Status 500")).toBeInTheDocument(); - expect(statusIndicators[3]).toHaveClass("bg-red-500"); - - const url999 = await screen.findByText("URL with unknown status"); - expect(url999).toBeInTheDocument(); - expect(screen.getByText("Status 999")).toBeInTheDocument(); - expect(statusIndicators[4]).toHaveClass("bg-gray-500"); - - const urlNull = await screen.findByText("URL with status null"); - expect(urlNull).toBeInTheDocument(); - expect(statusIndicators[5]).toHaveClass("bg-gray-500"); + }); + + it('displays URL when sortField is selected', async () => { + const sortedMock = { + request: { + query: GET_ALL_URLS, + variables: { searchText: '', sortField: 'name', currentPage: 1 }, + }, + result: { data: sortedUrls }, + }; + render( + + + + } /> + + + + ); + + await waitFor(() => { + expect(screen.getByText('Choisir un tri')).toBeInTheDocument(); + expect(screen.getByText('Test URL 1')).toBeInTheDocument(); + expect(screen.getByText('Test URL 2')).toBeInTheDocument(); + }); + + window.HTMLElement.prototype.scrollIntoView = function() {}; // Fix for scrollIntoView error + + fireEvent.click(screen.getByRole('combobox')); + + fireEvent.keyDown(screen.getByRole('combobox'), { key: 'Enter' }); + + await waitFor(() => { + expect(screen.getByText('Trier par nom')).toBeInTheDocument(); + expect(screen.getByText('Test URL 1')).toBeInTheDocument(); + expect(screen.getByText('Test URL 2')).toBeInTheDocument(); + }); + }); + + it('displays Page 2 URL when next page is clicked', async () => { + const paginateMock = { + request: { + query: GET_ALL_URLS, + variables: { searchText: '', sortField: '', currentPage: 2 }, + }, + result: { data: nextPageUrls }, + }; + render( + + + + } /> + + + + ); + + await waitFor(() => { + expect(screen.getByText('Test URL 1')).toBeInTheDocument(); + expect(screen.getByText('Test URL 2')).toBeInTheDocument(); }); - it("should handle sort change", async () => { - const mockData = { - urls: [ - { - id: "1", - name: "Test URL B", - path: "/testB", - createdAt: new Date(Date.now() - 10000).toISOString(), // Older - histories: [{ status_code: 200 }], - }, - { - id: "2", - name: "Test URL A", - path: "/testA", - createdAt: new Date().toISOString(), // Newer - histories: [{ status_code: 201 }], - }, - ], - }; - vi.mocked(graphqlTypes.useGetAllURlsQuery).mockReturnValue({ - data: mockData, - loading: false, - } as any); - render( - - - , - ); - - const items = screen.getAllByText(/Test URL/i); - expect(items[0]).toHaveTextContent("Test URL B"); - expect(items[1]).toHaveTextContent("Test URL A"); - - const selectTrigger1 = screen.getByRole("combobox"); - await fireEvent.click(selectTrigger1); - - await fireEvent.keyDown(selectTrigger1, { key: "ArrowUp" }); - await fireEvent.keyDown(selectTrigger1, { key: "ArrowUp" }); - await fireEvent.keyDown(selectTrigger1, { key: "Enter" }); - - const selectTrigger2 = screen.getByText("Trier par code de statut"); - await fireEvent.click(selectTrigger2); - - const reSortedItems = screen.getAllByText(/Test URL/i); - expect(reSortedItems[0]).toHaveTextContent("Test URL B"); - expect(reSortedItems[1]).toHaveTextContent("Test URL A"); - - const dateOption = screen.getByText("Trier par date de création", { - selector: "span#radix-\\:rq\\:", - }); - await fireEvent.click(dateOption); + fireEvent.click(screen.getByText('Suivant')); - const reReSortedItems = screen.getAllByText(/Test URL/i); - expect(reReSortedItems[0]).toHaveTextContent("Test URL B"); - expect(reReSortedItems[1]).toHaveTextContent("Test URL A"); + await waitFor(() => { + expect(screen.getByText('Test URL 3')).toBeInTheDocument(); + expect(screen.getByText('Test URL 4')).toBeInTheDocument(); }); -}); + }) +}); \ No newline at end of file diff --git a/front/src/__tests__/UrlHistory.test.tsx b/front/src/__tests__/UrlHistory.test.tsx index bdfb6ed..9e6617d 100644 --- a/front/src/__tests__/UrlHistory.test.tsx +++ b/front/src/__tests__/UrlHistory.test.tsx @@ -1,6 +1,7 @@ import { describe, it, expect } from "vitest"; import UrlHistory from "../pages/UrlHistory"; import { render, screen } from "@testing-library/react"; +import { MemoryRouter } from 'react-router-dom'; import { MockedProvider } from "@apollo/client/testing"; import { GET_ONE_URL } from "@/graphql/queries"; @@ -23,13 +24,13 @@ describe("Tests UrlHistory", () => { histories: [ { id: "82075add-02ed-4a2e-9127-1a0e70df060d", - created_at: "2023-07-09", + created_at: "2023-08-21T13:10:29.911Z", status_code: 200, response: "Success", }, { id: "82075add-02ed-4a2e-9127-1a0e70df268g", - created_at: "2023-07-08", + created_at: "2024-08-21T13:10:29.911Z", status_code: 404, response: "Not Found", }, @@ -41,17 +42,19 @@ describe("Tests UrlHistory", () => { }; render( - + + + , ); expect(await screen.findByText("En attente...")).toBeInTheDocument(); expect( - await screen.findByText("Date : 09/07/2023 à 02:00:00"), + await screen.findByText("Date : 21/08/2023 à 15:10:29"), ).toBeInTheDocument(); expect(await screen.findByText("200")).toBeInTheDocument(); expect(await screen.findByText("Success")).toBeInTheDocument(); expect( - await screen.findByText("Date : 08/07/2023 à 02:00:00"), + await screen.findByText("Date : 21/08/2024 à 15:10:29"), ).toBeInTheDocument(); expect(await screen.findByText("404")).toBeInTheDocument(); expect(await screen.findByText("Not Found")).toBeInTheDocument(); @@ -74,7 +77,9 @@ describe("Tests UrlHistory", () => { }; render( - + + + , ); @@ -106,7 +111,9 @@ describe("Tests UrlHistory", () => { }; render( - + + + , ); expect(await screen.findByText("En attente...")).toBeInTheDocument(); diff --git a/front/src/components/landing/ListUrl.tsx b/front/src/components/landing/ListUrl.tsx index a974c68..449d4d2 100644 --- a/front/src/components/landing/ListUrl.tsx +++ b/front/src/components/landing/ListUrl.tsx @@ -84,7 +84,7 @@ const URLList: React.FC = () => { />
- {data + {data && data.urls.urls ? data.urls.urls.map((item) => (