-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into chore/GEO-1145-announcement-diagrams
- Loading branch information
Showing
15 changed files
with
301 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 0 additions & 24 deletions
24
admin-frontend/src/components/dashboard/NumEmployerLogins.vue
This file was deleted.
Oops, something went wrong.
75 changes: 75 additions & 0 deletions
75
admin-frontend/src/components/dashboard/NumEmployerLogons.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<template> | ||
<v-card class="ptap-widget"> | ||
<v-card-text class="h-100 d-flex flex-column"> | ||
<div class="widget-header flex-grow-0 flex-shrink-0"> | ||
Total number of employers who have logged on to date | ||
</div> | ||
<div | ||
class="d-flex flex-column justify-center align-center text-primary flex-grow-1 flex-shrink-0" | ||
> | ||
<v-skeleton-loader v-if="isLoading" type="avatar"></v-skeleton-loader> | ||
<div v-if="!isLoading"> | ||
<span v-if="hasError"> | ||
<v-tooltip text="Unable to load the data"> | ||
<template #activator="{ props }"> | ||
<v-icon | ||
icon="mdi-alert" | ||
size="x-large" | ||
color="grey" | ||
v-bind="props" | ||
@click="refresh" | ||
></v-icon> | ||
</template> | ||
</v-tooltip> | ||
</span> | ||
<span v-if="!hasError" class="widget-value">{{ | ||
numEmployersWhoHaveLoggedOn | ||
}}</span> | ||
</div> | ||
</div> | ||
</v-card-text> | ||
</v-card> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import ApiService from '../../services/apiService'; | ||
import { ref, onMounted } from 'vue'; | ||
import { EmployerMetrics } from '../../types/employers'; | ||
onMounted(() => { | ||
refresh(); | ||
}); | ||
const numEmployersWhoHaveLoggedOn = ref<number | null>(); | ||
const hasError = ref<boolean>(false); | ||
const isLoading = ref<boolean>(false); | ||
async function refresh() { | ||
hasError.value = false; | ||
isLoading.value = true; | ||
try { | ||
const employerMetrics: EmployerMetrics = | ||
await ApiService.getEmployerMetrics(); | ||
numEmployersWhoHaveLoggedOn.value = | ||
employerMetrics?.num_employers_logged_on_to_date; | ||
} catch (e) { | ||
hasError.value = true; | ||
} finally { | ||
isLoading.value = false; | ||
} | ||
} | ||
defineExpose({ | ||
refresh, | ||
}); | ||
</script> | ||
|
||
<style lang="scss"> | ||
.widget-header { | ||
font-size: 1.2em; | ||
} | ||
.widget-value { | ||
font-size: 6em; | ||
font-weight: bold; | ||
} | ||
</style> |
55 changes: 55 additions & 0 deletions
55
admin-frontend/src/components/dashboard/__tests__/NumEmployerLogons.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { createTestingPinia } from '@pinia/testing'; | ||
import { render, screen, waitFor } from '@testing-library/vue'; | ||
import { afterEach, describe, expect, it, vi } from 'vitest'; | ||
import { createVuetify } from 'vuetify'; | ||
import * as components from 'vuetify/components'; | ||
import * as directives from 'vuetify/directives'; | ||
import { EmployerMetrics } from '../../../types/employers'; | ||
import NumEmployerLogons from '../NumEmployerLogons.vue'; | ||
|
||
global.ResizeObserver = require('resize-observer-polyfill'); | ||
const pinia = createTestingPinia(); | ||
const vuetify = createVuetify({ components, directives }); | ||
|
||
const mockEmployerMetrics: EmployerMetrics = { | ||
num_employers_logged_on_to_date: 6, | ||
}; | ||
const mockGetEmployerMetrics = vi.fn().mockResolvedValue(mockEmployerMetrics); | ||
|
||
vi.mock('../../../services/apiService', () => ({ | ||
default: { | ||
getEmployerMetrics: (...args) => { | ||
return mockGetEmployerMetrics(...args); | ||
}, | ||
}, | ||
})); | ||
|
||
const wrappedRender = () => { | ||
return render(NumEmployerLogons, { | ||
global: { | ||
plugins: [pinia, vuetify], | ||
}, | ||
}); | ||
}; | ||
|
||
describe('NumEmployerLogons', () => { | ||
afterEach(() => { | ||
vi.clearAllMocks(); | ||
}); | ||
|
||
it('displays the number of employers who have logged on to date', async () => { | ||
await wrappedRender(); | ||
expect(mockGetEmployerMetrics).toHaveBeenCalled(); | ||
|
||
await waitFor(() => { | ||
expect( | ||
screen.getByText( | ||
`${mockEmployerMetrics.num_employers_logged_on_to_date}`, | ||
{ | ||
exact: true, | ||
}, | ||
), | ||
).toBeInTheDocument(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export type EmployerMetrics = { | ||
num_employers_logged_on_to_date: number; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
backend/src/v1/routes/dashboard/employer-metrics-routes.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import express, { Application } from 'express'; | ||
import request from 'supertest'; | ||
import router from './employer-metrics-routes'; | ||
|
||
let app: Application; | ||
const getEmployerMetricsMock = jest.fn(); | ||
jest.mock('../../services/employer-service', () => ({ | ||
employerService: { | ||
getEmployerMetrics: (...args) => getEmployerMetricsMock(...args), | ||
}, | ||
})); | ||
describe('employer-metrics-routes', () => { | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
app = express(); | ||
app.use('/dashboard', router); | ||
}); | ||
|
||
describe('GET /employer-metrics', () => { | ||
describe('200', () => { | ||
it('should return the announcement metrics', async () => { | ||
// Arrange | ||
getEmployerMetricsMock.mockResolvedValueOnce({}); | ||
|
||
// Act | ||
const response = await request(app).get('/dashboard/employer-metrics'); | ||
|
||
// Assert | ||
expect(getEmployerMetricsMock).toHaveBeenCalledTimes(1); | ||
expect(response.status).toBe(200); | ||
}); | ||
}); | ||
describe('500', () => { | ||
it('should return 500 if an error occurs', async () => { | ||
// Arrange | ||
getEmployerMetricsMock.mockRejectedValueOnce( | ||
new Error('An error occurred'), | ||
); | ||
|
||
// Act | ||
const response = await request(app).get('/dashboard/employer-metrics'); | ||
|
||
// Assert | ||
expect(response.status).toBe(500); | ||
expect(response.body).toEqual({ | ||
error: 'An error occurred while fetching the employer metrics', | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
22 changes: 22 additions & 0 deletions
22
backend/src/v1/routes/dashboard/employer-metrics-routes.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Router } from 'express'; | ||
import { logger } from '../../../logger'; | ||
import { employerService } from '../../services/employer-service'; | ||
|
||
const router = Router(); | ||
|
||
/** | ||
* Get employer metrics | ||
*/ | ||
router.get('/employer-metrics', async (req, res) => { | ||
try { | ||
const metrics = await employerService.getEmployerMetrics(); | ||
res.json(metrics); | ||
} catch (error) { | ||
logger.error(error); | ||
res.status(500).send({ | ||
error: 'An error occurred while fetching the employer metrics', | ||
}); | ||
} | ||
}); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
import { Router } from 'express'; | ||
import announcementMetricsRouter from './announcement-metrics-routes'; | ||
import employerMetricsRouter from './employer-metrics-routes'; | ||
import reportsMetricsRouter from './report-metrics-routes'; | ||
|
||
const router = Router(); | ||
|
||
router.use(announcementMetricsRouter); | ||
router.use(reportsMetricsRouter); | ||
router.use(employerMetricsRouter); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { employerService } from '../services/employer-service'; | ||
import { EmployerMetrics } from '../types/employers'; | ||
|
||
const mockCountPayTransparencyCompanies = jest.fn(); | ||
|
||
jest.mock('../prisma/prisma-client-readonly-replica', () => ({ | ||
__esModule: true, | ||
...jest.requireActual('../prisma/prisma-client-readonly-replica'), | ||
default: { | ||
pay_transparency_company: { | ||
count: () => mockCountPayTransparencyCompanies(), | ||
}, | ||
}, | ||
})); | ||
|
||
describe('employer-service', () => { | ||
describe('getEmployerMetrics', () => { | ||
it('delegates request to the database', async () => { | ||
const numCompaniesLoggedOnToDate = 16; | ||
mockCountPayTransparencyCompanies.mockResolvedValue( | ||
numCompaniesLoggedOnToDate, | ||
); | ||
const employerMetrics: EmployerMetrics = | ||
await employerService.getEmployerMetrics(); | ||
expect(employerMetrics.num_employers_logged_on_to_date).toBe( | ||
numCompaniesLoggedOnToDate, | ||
); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.