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();
+ });
+ });
+});