diff --git a/.github/workflows/pipeline-config.yml b/.github/workflows/pipeline-config.yml index f723181..5d6387a 100644 --- a/.github/workflows/pipeline-config.yml +++ b/.github/workflows/pipeline-config.yml @@ -93,9 +93,29 @@ jobs: - name: Build the app run: npm run build || (echo "Build failed. Check the logs above." && exit 1) + jest: + name: Jest unit tests + runs-on: ubuntu-latest + needs: [common] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.10.0' + + - name: Run Jest tests + run: npx jest + docker_build: name: Build docker image runs-on: ubuntu-latest + needs: [common] steps: - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 0484d3d..c22ddac 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ dist dist-ssr *.local .env -coverage # Editor directories and files .vscode/* diff --git a/coverage/lcov-report/base.css b/coverage/lcov-report/base.css deleted file mode 100644 index f418035..0000000 --- a/coverage/lcov-report/base.css +++ /dev/null @@ -1,224 +0,0 @@ -body, html { - margin:0; padding: 0; - height: 100%; -} -body { - font-family: Helvetica Neue, Helvetica, Arial; - font-size: 14px; - color:#333; -} -.small { font-size: 12px; } -*, *:after, *:before { - -webkit-box-sizing:border-box; - -moz-box-sizing:border-box; - box-sizing:border-box; - } -h1 { font-size: 20px; margin: 0;} -h2 { font-size: 14px; } -pre { - font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; - margin: 0; - padding: 0; - -moz-tab-size: 2; - -o-tab-size: 2; - tab-size: 2; -} -a { color:#0074D9; text-decoration:none; } -a:hover { text-decoration:underline; } -.strong { font-weight: bold; } -.space-top1 { padding: 10px 0 0 0; } -.pad2y { padding: 20px 0; } -.pad1y { padding: 10px 0; } -.pad2x { padding: 0 20px; } -.pad2 { padding: 20px; } -.pad1 { padding: 10px; } -.space-left2 { padding-left:55px; } -.space-right2 { padding-right:20px; } -.center { text-align:center; } -.clearfix { display:block; } -.clearfix:after { - content:''; - display:block; - height:0; - clear:both; - visibility:hidden; - } -.fl { float: left; } -@media only screen and (max-width:640px) { - .col3 { width:100%; max-width:100%; } - .hide-mobile { display:none!important; } -} - -.quiet { - color: #7f7f7f; - color: rgba(0,0,0,0.5); -} -.quiet a { opacity: 0.7; } - -.fraction { - font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 10px; - color: #555; - background: #E8E8E8; - padding: 4px 5px; - border-radius: 3px; - vertical-align: middle; -} - -div.path a:link, div.path a:visited { color: #333; } -table.coverage { - border-collapse: collapse; - margin: 10px 0 0 0; - padding: 0; -} - -table.coverage td { - margin: 0; - padding: 0; - vertical-align: top; -} -table.coverage td.line-count { - text-align: right; - padding: 0 5px 0 20px; -} -table.coverage td.line-coverage { - text-align: right; - padding-right: 10px; - min-width:20px; -} - -table.coverage td span.cline-any { - display: inline-block; - padding: 0 5px; - width: 100%; -} -.missing-if-branch { - display: inline-block; - margin-right: 5px; - border-radius: 3px; - position: relative; - padding: 0 4px; - background: #333; - color: yellow; -} - -.skip-if-branch { - display: none; - margin-right: 10px; - position: relative; - padding: 0 4px; - background: #ccc; - color: white; -} -.missing-if-branch .typ, .skip-if-branch .typ { - color: inherit !important; -} -.coverage-summary { - border-collapse: collapse; - width: 100%; -} -.coverage-summary tr { border-bottom: 1px solid #bbb; } -.keyline-all { border: 1px solid #ddd; } -.coverage-summary td, .coverage-summary th { padding: 10px; } -.coverage-summary tbody { border: 1px solid #bbb; } -.coverage-summary td { border-right: 1px solid #bbb; } -.coverage-summary td:last-child { border-right: none; } -.coverage-summary th { - text-align: left; - font-weight: normal; - white-space: nowrap; -} -.coverage-summary th.file { border-right: none !important; } -.coverage-summary th.pct { } -.coverage-summary th.pic, -.coverage-summary th.abs, -.coverage-summary td.pct, -.coverage-summary td.abs { text-align: right; } -.coverage-summary td.file { white-space: nowrap; } -.coverage-summary td.pic { min-width: 120px !important; } -.coverage-summary tfoot td { } - -.coverage-summary .sorter { - height: 10px; - width: 7px; - display: inline-block; - margin-left: 0.5em; - background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; -} -.coverage-summary .sorted .sorter { - background-position: 0 -20px; -} -.coverage-summary .sorted-desc .sorter { - background-position: 0 -10px; -} -.status-line { height: 10px; } -/* yellow */ -.cbranch-no { background: yellow !important; color: #111; } -/* dark red */ -.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } -.low .chart { border:1px solid #C21F39 } -.highlighted, -.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ - background: #C21F39 !important; -} -/* medium red */ -.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } -/* light red */ -.low, .cline-no { background:#FCE1E5 } -/* light green */ -.high, .cline-yes { background:rgb(230,245,208) } -/* medium green */ -.cstat-yes { background:rgb(161,215,106) } -/* dark green */ -.status-line.high, .high .cover-fill { background:rgb(77,146,33) } -.high .chart { border:1px solid rgb(77,146,33) } -/* dark yellow (gold) */ -.status-line.medium, .medium .cover-fill { background: #f9cd0b; } -.medium .chart { border:1px solid #f9cd0b; } -/* light yellow */ -.medium { background: #fff4c2; } - -.cstat-skip { background: #ddd; color: #111; } -.fstat-skip { background: #ddd; color: #111 !important; } -.cbranch-skip { background: #ddd !important; color: #111; } - -span.cline-neutral { background: #eaeaea; } - -.coverage-summary td.empty { - opacity: .5; - padding-top: 4px; - padding-bottom: 4px; - line-height: 1; - color: #888; -} - -.cover-fill, .cover-empty { - display:inline-block; - height: 12px; -} -.chart { - line-height: 0; -} -.cover-empty { - background: white; -} -.cover-full { - border-right: none !important; -} -pre.prettyprint { - border: none !important; - padding: 0 !important; - margin: 0 !important; -} -.com { color: #999 !important; } -.ignore-none { color: #999; font-weight: normal; } - -.wrapper { - min-height: 100%; - height: auto !important; - height: 100%; - margin: 0 auto -48px; -} -.footer, .push { - height: 48px; -} diff --git a/coverage/lcov-report/block-navigation.js b/coverage/lcov-report/block-navigation.js deleted file mode 100644 index cc12130..0000000 --- a/coverage/lcov-report/block-navigation.js +++ /dev/null @@ -1,87 +0,0 @@ -/* eslint-disable */ -var jumpToCode = (function init() { - // Classes of code we would like to highlight in the file view - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; - - // Elements to highlight in the file listing view - var fileListingElements = ['td.pct.low']; - - // We don't want to select elements that are direct descendants of another match - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` - - // Selecter that finds elements on the page to which we can jump - var selector = - fileListingElements.join(', ') + - ', ' + - notSelector + - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` - - // The NodeList of matching elements - var missingCoverageElements = document.querySelectorAll(selector); - - var currentIndex; - - function toggleClass(index) { - missingCoverageElements - .item(currentIndex) - .classList.remove('highlighted'); - missingCoverageElements.item(index).classList.add('highlighted'); - } - - function makeCurrent(index) { - toggleClass(index); - currentIndex = index; - missingCoverageElements.item(index).scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'center' - }); - } - - function goToPrevious() { - var nextIndex = 0; - if (typeof currentIndex !== 'number' || currentIndex === 0) { - nextIndex = missingCoverageElements.length - 1; - } else if (missingCoverageElements.length > 1) { - nextIndex = currentIndex - 1; - } - - makeCurrent(nextIndex); - } - - function goToNext() { - var nextIndex = 0; - - if ( - typeof currentIndex === 'number' && - currentIndex < missingCoverageElements.length - 1 - ) { - nextIndex = currentIndex + 1; - } - - makeCurrent(nextIndex); - } - - return function jump(event) { - if ( - document.getElementById('fileSearch') === document.activeElement && - document.activeElement != null - ) { - // if we're currently focused on the search input, we don't want to navigate - return; - } - - switch (event.which) { - case 78: // n - case 74: // j - goToNext(); - break; - case 66: // b - case 75: // k - case 80: // p - goToPrevious(); - break; - } - }; -})(); -window.addEventListener('keydown', jumpToCode); diff --git a/coverage/lcov-report/components/shared/appBar/constants/constants.tsx.html b/coverage/lcov-report/components/shared/appBar/constants/constants.tsx.html deleted file mode 100644 index 643e063..0000000 --- a/coverage/lcov-report/components/shared/appBar/constants/constants.tsx.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - -
-- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 | 1x - -1x -1x -1x -1x - - - - - - - -1x - - - - - -1x - - - - | import { ErrorOutline, WarningAmber } from '@mui/icons-material'; - -export enum TimerStatesEnum { - Critical = 'critical', - Warning = 'warning', - Normal = 'normal', -} - -export interface ITimerStylesKeys { - color: string; - icon?: JSX.Element; -} - -export const timerStylesByState: Record<TimerStatesEnum, ITimerStylesKeys> = { - [TimerStatesEnum.Critical]: { color: '#f70000', icon: <ErrorOutline sx={{ color: '#f70000', mr: 1 }} /> }, - [TimerStatesEnum.Warning]: { color: '#ff9800', icon: <WarningAmber sx={{ color: '#ff9800', mr: 1 }} /> }, - [TimerStatesEnum.Normal]: { color: 'black' }, -}; - -export const timeThresholds = [ - { minutes: 5, state: TimerStatesEnum.Critical }, - { minutes: 10, state: TimerStatesEnum.Warning }, -]; - |
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -File | -- | Statements | -- | Branches | -- | Functions | -- | Lines | -- |
---|---|---|---|---|---|---|---|---|---|
constants.tsx | -
-
- |
- 100% | -7/7 | -100% | -2/2 | -100% | -1/1 | -100% | -7/7 | -
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 | 1x -1x -1x - - - - - - - -1x -2x -2x -2x - -2x - - -1x -10x - - | import { intervalToDuration } from 'date-fns'; -import _ from 'lodash'; -import { TimerStatesEnum, timeThresholds } from '../constants/constants'; - -interface ICaluclateTimeLeft { - minutes: number; - seconds: number; - formattedTime: string; -} - -export const calculateTimeLeft = (expirationDate: Date): ICaluclateTimeLeft => { - const now = new Date(); - const { minutes = 0, seconds = 0 } = intervalToDuration({ start: now, end: expirationDate }); - const formattedTime = `${_.padStart(minutes.toString(), 2, '0')}:${_.padStart(seconds.toString(), 2, '0')}`; - - return { minutes, seconds, formattedTime }; -}; - -export const getTimerState = (minutes: number): TimerStatesEnum => { - return _.find(timeThresholds, threshold => minutes <= threshold.minutes)?.state ?? TimerStatesEnum.Normal; -}; - |
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -File | -- | Statements | -- | Branches | -- | Functions | -- | Lines | -- |
---|---|---|---|---|---|---|---|---|---|
Timer.Utils.tsx | -
-
- |
- 100% | -13/13 | -50% | -2/4 | -100% | -3/3 | -100% | -10/10 | -
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 | -1x -1x - -1x -6x - -6x - -15x - -12x - - - - | import { IEvent } from 'components/viewsComponents/events/constants/EventsData'; -import { isAfter, isBefore } from 'date-fns'; -import _ from 'lodash'; - -export const getClosestEvents = (events: IEvent[]): IEvent[] => { - const now = new Date(); - - return _(events) - .filter(event => { - return isAfter(event.start, now) || (isBefore(event.start, now) && isAfter(event.end, now)); - }) - .orderBy(event => event.start.getTime()) - .take(3) - .value(); -}; - |
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -File | -- | Statements | -- | Branches | -- | Functions | -- | Lines | -- |
---|---|---|---|---|---|---|---|---|---|
EventsHelpers.ts | -
-
- |
- 100% | -8/8 | -100% | -3/3 | -100% | -3/3 | -100% | -7/7 | -
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 | -1x - -1x -6x -1x - - -13x - -5x -1x - - -4x - -4x - - | import { IGrade } from 'contract/interfaces/academics/Academics'; -import _ from 'lodash'; - -export const calculateAverageGrade = (gradesList: IGrade[]): string => { - if (gradesList.length === 0) { - return '0.00'; - } - - const validGrades = gradesList.map(grade => grade.grade).filter(Number); - - if (validGrades.length === 0) { - return '0.00'; - } - - const average = _.mean(validGrades); - - return average.toFixed(2); -}; - |
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -File | -- | Statements | -- | Branches | -- | Functions | -- | Lines | -- |
---|---|---|---|---|---|---|---|---|---|
GradesHelpers.ts | -
-
- |
- 100% | -11/11 | -100% | -2/2 | -100% | -2/2 | -100% | -9/9 | -
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 | 3x -3x -3x -3x -3x -3x -3x -3x - -3x - -3x -3x -3x -3x -3x - -3x - -3x -3x -3x -3x -3x - -3x - -3x -3x -3x - -3x - | export enum RolesEnum { - ADMIN = 'ADMIN', - USER = 'USER', - TEACHER = 'TEACHER', - STUDENT = 'STUDENT', - EMPLOYEE = 'EMPLOYEE', - EXTERNAL_PARTICIPANT = 'EXTERNAL_PARTICIPANT', - COMPANY = 'COMPANY', -} -export const rolesEnumArray = Object.values(RolesEnum); - -export enum GradeValueEnum { - Poor = 2, - Fair = 3, - Good = 4, - Excellent = 5, -} -export const gradeValueEnumArray = Object.values(GradeValueEnum) as GradeValueEnum[]; - -export enum PassDateAttemptEnum { - FirstAttempt = 0, - SecondAttempt = 1, - ThirdAttempt = 2, - FourthAttempt = 3, -} -export const passDateAttemptEnumArray = Object.values(PassDateAttemptEnum) as PassDateAttemptEnum[]; - -export enum GenderEnum { - Men = 'Men', - Women = 'Women', -} -export const genderEnumArray = Object.values(GenderEnum); - |
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -File | -- | Statements | -- | Branches | -- | Functions | -- | Lines | -- |
---|---|---|---|---|---|---|---|---|---|
Enums.ts | -
-
- |
- 100% | -25/25 | -100% | -8/8 | -100% | -4/4 | -100% | -25/25 | -
- Press n or j to go to the next uncovered block, b, p or k for the previous block. -
- -File | -- | Statements | -- | Branches | -- | Functions | -- | Lines | -- |
---|---|---|---|---|---|---|---|---|---|
components/shared/appBar/constants | -
-
- |
- 100% | -7/7 | -100% | -2/2 | -100% | -1/1 | -100% | -7/7 | -
components/shared/appBar/utils | -
-
- |
- 100% | -13/13 | -50% | -2/4 | -100% | -3/3 | -100% | -10/10 | -
components/viewsComponents/dashboard/utils | -
-
- |
- 100% | -8/8 | -100% | -3/3 | -100% | -3/3 | -100% | -7/7 | -
components/viewsComponents/grades/utils | -
-
- |
- 100% | -11/11 | -100% | -2/2 | -100% | -2/2 | -100% | -9/9 | -
contract/enums | -
-
- |
- 100% | -25/25 | -100% | -8/8 | -100% | -4/4 | -100% | -25/25 | -
redux/stateSlices/auth | -
-
- |
- 100% | -27/27 | -50% | -3/6 | -100% | -7/7 | -100% | -27/27 | -
redux/stateSlices/view | -
-
- |
- 100% | -11/11 | -50% | -1/2 | -100% | -4/4 | -100% | -10/10 | -
redux/utils/JWT | -
-
- |
- 100% | -9/9 | -100% | -2/2 | -100% | -1/1 | -100% | -9/9 | -
utils/date | -
-
- |
- 100% | -10/10 | -100% | -1/1 | -100% | -2/2 | -100% | -7/7 | -
utils/decorators | -
-
- |
- 100% | -8/8 | -100% | -1/1 | -100% | -2/2 | -100% | -6/6 | -