diff --git a/met-web/jest.config.ts b/met-web/jest.config.ts index aa3653754..c4144dc5d 100644 --- a/met-web/jest.config.ts +++ b/met-web/jest.config.ts @@ -188,6 +188,8 @@ const config: Config.InitialOptions = { // Whether to use watchman for file crawling // watchman: true, + + testTimeout: 10000, }; export default config; diff --git a/met-web/tests/unit/components/factory.ts b/met-web/tests/unit/components/factory.ts index 9fb1623b4..64e63e3de 100644 --- a/met-web/tests/unit/components/factory.ts +++ b/met-web/tests/unit/components/factory.ts @@ -22,6 +22,7 @@ const tenant: Tenant = { name: 'Tenant 1', title: 'Tenant Title', description: 'Tenant Description', + short_name: 'tenant1', }; const survey: Survey = { diff --git a/met-web/tests/unit/components/tenantManagement/TenantDetail.test.tsx b/met-web/tests/unit/components/tenantManagement/TenantDetail.test.tsx new file mode 100644 index 000000000..a230952c8 --- /dev/null +++ b/met-web/tests/unit/components/tenantManagement/TenantDetail.test.tsx @@ -0,0 +1,127 @@ +import React, { ReactNode } from 'react'; +import { render, waitFor, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import * as reactRedux from 'react-redux'; +import * as reactRouter from 'react-router'; +import * as tenantService from 'services/tenantService'; +import TenantDetail from '../../../../src/components/tenantManagement/Detail'; +import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { USER_ROLES } from 'services/userService/constants'; + +const mockTenant = { + id: 1, + name: 'Tenant One', + title: 'Title One', + description: 'Description One', + contact_name: 'Contact One', + short_name: 'tenantone', + contact_email: 'contactone@example.com', + logo_url: 'https://example.com/logo.png', + logo_credit: 'Photographer One', + logo_description: 'Logo Description One', +}; + +jest.mock('axios'); + +jest.mock('@mui/material', () => ({ + ...jest.requireActual('@mui/material'), + Box: ({ children }: { children: ReactNode }) =>
{children}
, + Grid: ({ children }: { children: ReactNode }) =>
{children}
, + Skeleton: ({ children }: { children: ReactNode }) =>
{children}
, +})); + +jest.mock('components/common/Typography/', () => ({ + Header1: ({ children }: { children: ReactNode }) =>

{children}

, + Header2: ({ children }: { children: ReactNode }) =>

{children}

, + BodyText: ({ children }: { children: ReactNode }) =>

{children}

, +})); + +jest.mock('components/common/Layout', () => ({ + ResponsiveContainer: ({ children }: { children: ReactNode }) =>
{children}
, + DetailsContainer: ({ children }: { children: ReactNode }) =>
{children}
, + Detail: ({ children }: { children: ReactNode }) =>
{children}
, +})); + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(() => { + return { + roles: [USER_ROLES.SUPER_ADMIN], + }; + }), + useDispatch: jest.fn(), +})); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: jest.fn(() => { + return { tenantId: mockTenant.short_name }; + }), + useNavigate: jest.fn(), +})); + +jest.mock('services/tenantService', () => ({ + getTenant: jest.fn(), + deleteTenant: jest.fn(), +})); + +jest.mock('services/notificationService/notificationSlice', () => ({ + openNotification: jest.fn(), +})); + +jest.mock('services/notificationModalService/notificationModalSlice', () => ({ + openNotificationModal: jest.fn(), +})); + +// Mocking BreadcrumbTrail component +jest.mock('components/common/Navigation/Breadcrumb', () => ({ + BreadcrumbTrail: ({ children }: { children: ReactNode }) =>
{children}
, +})); + +describe('Tenant Detail Page tests', () => { + const dispatch = jest.fn(); + const navigate = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + jest.spyOn(reactRedux, 'useDispatch').mockReturnValue(dispatch); + jest.spyOn(reactRouter, 'useNavigate').mockReturnValue(navigate); + jest.spyOn(tenantService, 'getTenant').mockResolvedValue(mockTenant); + }); + + test('Tenant detail is rendered', async () => { + render( + + + } /> + + , + ); + + await waitFor(() => { + const tenantNames = screen.getAllByText('Tenant One'); + expect(tenantNames).toHaveLength(2); + expect(screen.getByText('Title One')).toBeVisible(); + expect(screen.getByText('Description One')).toBeVisible(); + expect(screen.getByText('Contact One')).toBeVisible(); + expect(screen.getByText('contactone@example.com')).toBeVisible(); + expect(screen.getByText('Photographer One')).toBeVisible(); + expect(screen.getByText('Logo Description One')).toBeVisible(); + }); + }); + + test('Loading state is rendered initially', () => { + jest.spyOn(tenantService, 'getTenant').mockReturnValue(new Promise(() => {})); // Mock unresolved promise + + render( + + + } /> + + , + ); + + const loadingTexts = screen.getAllByText('Loading...'); + expect(loadingTexts.length).toBeGreaterThan(0); + }); +}); diff --git a/met-web/tests/unit/components/tenantManagement/TenantListing.test.tsx b/met-web/tests/unit/components/tenantManagement/TenantListing.test.tsx new file mode 100644 index 000000000..9c011a3a2 --- /dev/null +++ b/met-web/tests/unit/components/tenantManagement/TenantListing.test.tsx @@ -0,0 +1,89 @@ +import React, { ReactNode } from 'react'; +import { render, waitFor, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { setupEnv } from '../setEnvVars'; +import * as reactRedux from 'react-redux'; +import * as reactRouter from 'react-router'; +import * as tenantService from 'services/tenantService'; +import TenantListingPage from '../../../../src/components/tenantManagement/Listing'; +import { USER_ROLES } from 'services/userService/constants'; +import { MemoryRouter } from 'react-router-dom'; + +const mockTenantOne = { + id: 1, + name: 'Tenant One', + title: 'Title One', + description: 'Description One', + contact_name: 'Contact One', + short_name: 'tenantone', +}; + +const mockTenantTwo = { + id: 2, + name: 'Tenant Two', + title: 'Title Two', + description: 'Description Two', + contact_name: 'Contact Two', + short_name: 'tenanttwo', +}; + +jest.mock('axios'); + +jest.mock('@mui/material', () => ({ + ...jest.requireActual('@mui/material'), + Link: ({ children }: { children: ReactNode }) => { + return {children}; + }, +})); + +jest.mock('components/common', () => ({ + ...jest.requireActual('components/common'), + PrimaryButtonOld: ({ children, onClick }: { children: ReactNode; onClick: () => void }) => { + return ; + }, +})); + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(() => { + return { + roles: [USER_ROLES.SUPER_ADMIN], + }; + }), +})); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: jest.fn(), + useLocation: jest.fn(() => ({ + search: '', + })), +})); + +describe('Tenant Listing Page tests', () => { + jest.spyOn(reactRedux, 'useSelector').mockImplementation(() => jest.fn()); + jest.spyOn(reactRedux, 'useDispatch').mockImplementation(() => jest.fn()); + jest.spyOn(reactRouter, 'useNavigate').mockImplementation(() => jest.fn()); + jest.spyOn(tenantService, 'getAllTenants').mockReturnValue(Promise.resolve([mockTenantOne, mockTenantTwo])); + + beforeEach(() => { + setupEnv(); + }); + + test('Tenant table is rendered', async () => { + render( + + + , + ); + + await waitFor(() => { + expect(screen.getByText('Tenant One')).toBeVisible(); + expect(screen.getByText('Tenant Two')).toBeVisible(); + expect(screen.getByText('Description One')).toBeVisible(); + expect(screen.getByText('Description Two')).toBeVisible(); + + expect(screen.getByText('Add Instance')).toBeVisible(); + }); + }); +});