diff --git a/.github/workflows/backend-linting.yaml b/.github/workflows/backend-linting.yaml index 38901c22..f46741db 100644 --- a/.github/workflows/backend-linting.yaml +++ b/.github/workflows/backend-linting.yaml @@ -11,6 +11,8 @@ jobs: test: runs-on: self-hosted steps: + - name: Add permission to remove contents of previous action script + run: echo ${{ secrets.SUDO }} | sudo -S chown -R $USER:$USER /home/selab2/actions-runner/_work/UGent-7/ - uses: actions/checkout@v4 - name: Set up Python 3.11 uses: actions/setup-python@v4 diff --git a/.github/workflows/backend-tests.yaml b/.github/workflows/backend-tests.yaml deleted file mode 100644 index 6cbbb7f5..00000000 --- a/.github/workflows/backend-tests.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: backend-tests - -on: - push: - branches: [main, development] - pull_request: - branches: [main, development] - workflow_dispatch: - -jobs: - test: - runs-on: self-hosted - steps: - - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v4 - with: - python-version: "3.11" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install poetry - poetry install --directory=./backend - - name: Compile translations - run: django-admin compilemessages - - name: Execute tests - run: cd backend; python manage.py test diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 00000000..d787cc08 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,18 @@ +name: tests + +on: + push: + branches: [main, development] + pull_request: + branches: [main, development] + workflow_dispatch: + +jobs: + test: + runs-on: self-hosted + steps: + - name: Add permission to remove contents of previous action script + run: echo ${{ secrets.SUDO }} | sudo -S chown -R $USER:$USER /home/selab2/actions-runner/_work/UGent-7/ + - uses: actions/checkout@v4 + - name: Run tests + run: echo ${{ secrets.SUDO }} | sudo -S ./test.sh -c diff --git a/backend/api/migrations/0010_rename_errortemplate_errortemplates_and_more.py b/backend/api/migrations/0010_rename_errortemplate_errortemplates_and_more.py new file mode 100644 index 00000000..781683cc --- /dev/null +++ b/backend/api/migrations/0010_rename_errortemplate_errortemplates_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 5.0.3 on 2024-04-05 16:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("api", "0009_merge_0008_add_extra_checks_0008_course_faculty"), + ] + + operations = [ + migrations.RenameModel( + old_name="errortemplate", + new_name="ErrorTemplates", + ), + migrations.RenameField( + model_name="extracheck", + old_name="docker_image_id", + new_name="docker_image", + ), + migrations.AlterField( + model_name="dockerimage", + name="custom", + field=models.BooleanField(default=True), + ), + ] diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9dc299c9..1e9209bf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -38,6 +38,7 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-vue": "^9.24.0", + "jsdom": "^24.0.0", "sass": "^1.72.0", "typescript": "^5.2.2", "vite": "^5.1.1", @@ -1806,6 +1807,18 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -2621,6 +2634,18 @@ "node": ">=4" } }, + "node_modules/cssstyle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -2701,6 +2726,19 @@ "node": ">=0.10" } }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -2781,6 +2819,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -4328,6 +4372,31 @@ "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==" }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/http-signature": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", @@ -4342,6 +4411,19 @@ "node": ">=0.10" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", @@ -4351,6 +4433,18 @@ "node": ">=8.12.0" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4691,6 +4785,12 @@ "node": ">=8" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4859,6 +4959,55 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, + "node_modules/jsdom": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.0.0.tgz", + "integrity": "sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==", + "dev": true, + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.7", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.16.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5367,6 +5516,12 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -5588,6 +5743,18 @@ "node": ">=6" } }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -6149,6 +6316,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6259,6 +6432,18 @@ "node": ">=14.0.0" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/semver": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", @@ -6580,6 +6765,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/synckit": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", @@ -6686,6 +6877,18 @@ "node": ">= 4.0.0" } }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -7333,6 +7536,70 @@ "npm": ">= 3.0.0" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7421,6 +7688,27 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", @@ -7430,6 +7718,12 @@ "node": ">=12" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/frontend/package.json b/frontend/package.json index f46b10ad..b0f1e460 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -45,6 +45,7 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-vue": "^9.24.0", + "jsdom": "^24.0.0", "sass": "^1.72.0", "typescript": "^5.2.2", "vite": "^5.1.1", diff --git a/frontend/src/composables/services/faculties.service.ts b/frontend/src/composables/services/faculties.service.ts index 9b298378..23fc274c 100644 --- a/frontend/src/composables/services/faculties.service.ts +++ b/frontend/src/composables/services/faculties.service.ts @@ -6,7 +6,7 @@ import { get, getList, create, deleteId } from '@/composables/services/helpers.t interface FacultyState { faculties: Ref; faculty: Ref; - getFacultyByID: (name: string) => Promise; + getFacultyByID: (id: string) => Promise; getFaculties: () => Promise; createFaculty: (facultyData: Faculty) => Promise; deleteFaculty: (id: string) => Promise; @@ -16,8 +16,8 @@ export function useFaculty(): FacultyState { const faculties = ref(null); const faculty = ref(null); - async function getFacultyByID(name: string): Promise { - const endpoint = endpoints.faculties.retrieve.replace('{name}', name); + async function getFacultyByID(id: string): Promise { + const endpoint = endpoints.faculties.retrieve.replace('{id}', id); await get(endpoint, faculty, Faculty.fromJSON); } diff --git a/frontend/src/config/endpoints.ts b/frontend/src/config/endpoints.ts index 29d1df7f..e1152735 100644 --- a/frontend/src/config/endpoints.ts +++ b/frontend/src/config/endpoints.ts @@ -40,7 +40,7 @@ export const endpoints = { }, faculties: { index: '/api/faculties/', - retrieve: '/api/faculties/{name}', + retrieve: '/api/faculties/{id}', }, groups: { retrieve: '/api/groups/{id}/', diff --git a/frontend/src/test/e2e/dummy.cy.ts b/frontend/src/test/e2e/dummy.cy.ts new file mode 100644 index 00000000..2c3e1731 --- /dev/null +++ b/frontend/src/test/e2e/dummy.cy.ts @@ -0,0 +1 @@ +describe('dummy e2e test', () => {}); diff --git a/frontend/src/test/e2e/login.cy.ts b/frontend/src/test/e2e/login.cy.ts deleted file mode 100644 index 8bf35f54..00000000 --- a/frontend/src/test/e2e/login.cy.ts +++ /dev/null @@ -1,30 +0,0 @@ -// cypress uses mocha and chai assertions by default -// vitest are also based on these assertions, but they modified it a bit -// expect().toBe in vitest would be expect().to.be in cypress -// check out https://www.chaijs.com/api/bdd/ for more in detail explanation for assertions -describe('login page', () => { - beforeEach(() => { - // these are e2e tests, they have access to the whole website, not a single component - // for specific tests, we want to go to a specific parts of the website though - // we use cy.visit for this, with input an absolute or relative url with https://localhost as current baseUrl - cy.visit('/auth/login'); - }); - - it('routes to course when button clicked', () => { - // we can check for elements in a web page using a selector or the contents of the element you're searching for - cy.contains('UGent login'); // .click() - - // then you can check whether the new url is correct - // currently it seems to take too long to load, though - // cy.url().should("include", "https://login.microsoft.com/") - }); - - it('routes to dashboard when pressing dashboard button', () => { - cy.contains('Dashboard').click(); - cy.url() - // we check whether it ends with "/" - .should('match', /\/$/) - // we check whether we're not still on the login page - .should('not.include', '/auth/login'); - }); -}); diff --git a/frontend/src/test/unit/admin_service.test.ts b/frontend/src/test/unit/admin_service.test.ts index 415f300d..2c5a62c4 100644 --- a/frontend/src/test/unit/admin_service.test.ts +++ b/frontend/src/test/unit/admin_service.test.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { describe, it, expect, beforeEach } from 'vitest'; import { useAdmin } from '@/composables/services/admins.service.ts'; +import { User } from '../../types/users/User'; const { admins, @@ -53,4 +54,37 @@ describe('admin', (): void => { expect(admins.value?.[0]?.create_time).toEqual(new Date('July 21, 2024 01:15:00')); expect(admins.value?.[1]?.faculties).toEqual([]); }); + + it('create admin', async () => { + const exampleAdmin = new User( + '101', // id + 'sample_admin', // username + 'sample.admin@UGent.be', // email + 'Sample', // first_name + 'Admin', // last_name + 2024, // last_enrolled + true, // is_staff + ['user'], // roles + [], // faculties + new Date('April 2, 2023 01:15:00'), // create_time + new Date('April 2, 2024 01:15:00'), // last_login + ); + + await getAdmins(); + expect(admins).not.toBeNull(); + expect(Array.isArray(admins.value)).toBe(true); + const prevLength = admins.value?.length ?? 0; + + await createAdmin(exampleAdmin); + await getAdmins(); + + expect(admins).not.toBeNull(); + expect(Array.isArray(admins.value)).toBe(true); + expect(admins.value?.length).toBe(prevLength + 1); + + expect(admins.value?.[prevLength]?.first_name).toBe('Sample'); + expect(admins.value?.[prevLength]?.last_name).toBe('Admin'); + expect(admins.value?.[prevLength]?.email).toBe('sample.admin@UGent.be'); + expect(admins.value?.[prevLength]?.is_staff).toBe(true); + }); }); diff --git a/frontend/src/test/unit/assistant_service.test.ts b/frontend/src/test/unit/assistant_service.test.ts index cd8ec120..5629f0ea 100644 --- a/frontend/src/test/unit/assistant_service.test.ts +++ b/frontend/src/test/unit/assistant_service.test.ts @@ -1,6 +1,8 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { describe, it, expect, beforeEach } from 'vitest'; import { useAssistant } from '@/composables/services/assistant.service.ts'; +import { User } from '../../types/users/User'; +import { Assistant } from '@/types/users/Assistant'; const { assistants, @@ -91,4 +93,38 @@ describe('assistant', (): void => { expect(assistants.value?.[1]?.courses).toEqual([]); expect(assistants.value?.[1]?.faculties).toEqual([]); }); + + it('create assistant', async () => { + const exampleAssistant = new Assistant( + '102', + 'sample_assistant', + 'sample.assistant@UGent.be', + 'Sample', + 'Assistant', + 2023, + true, + [], + [], + [], + new Date('April 2, 2023 01:15:00'), + new Date('April 2, 2024 01:15:00'), + ); + + await getAssistants(); + expect(assistants).not.toBeNull(); + expect(Array.isArray(assistants.value)).toBe(true); + const prevLength = assistants.value?.length ?? 0; + + await createAssistant(exampleAssistant); + await getAssistants(); + + expect(assistants).not.toBeNull(); + expect(Array.isArray(assistants.value)).toBe(true); + expect(assistants.value?.length).toBe(prevLength + 1); + + expect(assistants.value?.[prevLength]?.first_name).toBe('Sample'); + expect(assistants.value?.[prevLength]?.last_name).toBe('Assistant'); + expect(assistants.value?.[prevLength]?.email).toBe('sample.assistant@UGent.be'); + expect(assistants.value?.[prevLength]?.roles).toContain('assistant'); + }); }); diff --git a/frontend/src/test/unit/faculty_service.test.ts b/frontend/src/test/unit/faculty_service.test.ts index 13c12807..c5f819b9 100644 --- a/frontend/src/test/unit/faculty_service.test.ts +++ b/frontend/src/test/unit/faculty_service.test.ts @@ -14,7 +14,7 @@ const { describe('faculty', (): void => { it('gets faculty data by id', async () => { - await getFacultyByID('wetenschappen'); + await getFacultyByID('sciences'); expect(faculty.value).not.toBeNull(); expect(faculty.value?.name).toBe('wetenschappen'); }); diff --git a/frontend/src/test/unit/setup.ts b/frontend/src/test/unit/setup.ts index 983ca216..40558bd5 100644 --- a/frontend/src/test/unit/setup.ts +++ b/frontend/src/test/unit/setup.ts @@ -1,8 +1,12 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ import { afterAll, afterEach, beforeAll } from 'vitest'; import { setupServer } from 'msw/node'; import { HttpResponse, http } from 'msw'; +import { createApp } from 'vue'; +import { createPinia } from 'pinia'; import { endpoints } from '@/config/endpoints.ts'; +import { JSDOM } from 'jsdom'; const baseUrl = 'http://localhost'; @@ -64,6 +68,7 @@ const courses = [ students: ['1', '2', '3', '000201247011'], projects: ['0', '1'], parent_course: null, + faculty: null, name: 'Math', academic_startyear: 2023, description: 'Math course', @@ -75,6 +80,7 @@ const courses = [ students: [], projects: [], parent_course: '3', + faculty: null, name: 'Sel2', academic_startyear: 2023, description: 'Software course', @@ -86,6 +92,7 @@ const courses = [ students: [], projects: [], parent_course: null, + faculty: null, name: 'Sel1', academic_startyear: 2022, description: 'Software course', @@ -97,6 +104,7 @@ const courses = [ students: [], projects: [], parent_course: '1', + faculty: null, name: 'Math', academic_startyear: 2024, description: 'Math course', @@ -108,6 +116,7 @@ const courses = [ students: [], projects: [], parent_course: '12', + faculty: null, name: 'Math', academic_startyear: 2025, description: 'Math course', @@ -119,6 +128,7 @@ const courses = [ students: [], projects: [], parent_course: null, + faculty: null, name: 'Club brugge', academic_startyear: 2023, description: null, @@ -130,13 +140,17 @@ const courses = [ students: [], projects: [], parent_course: null, + faculty: null, name: 'vergeet barbara', academic_startyear: 2023, description: null, }, ]; -const faculties = [{ name: 'wetenschappen' }, { name: 'voetbal' }]; +const faculties = [ + { id: 'sciences', name: 'wetenschappen' }, + { id: 'football', name: 'voetbal' }, +]; const students = [ { @@ -150,8 +164,10 @@ const students = [ last_enrolled: 2023, create_time: new Date('July 21, 2024 01:15:00'), studentId: null, + roles: ['student'], courses: ['1', '2', '3'], groups: ['0'], + faculties: [], }, { id: '2', @@ -164,8 +180,10 @@ const students = [ last_enrolled: 2023, create_time: new Date('July 21, 2024 01:15:00'), studentId: null, + roles: ['student'], courses: [], groups: [], + faculties: [], }, { id: '000201247011', @@ -178,8 +196,10 @@ const students = [ last_enrolled: 2023, create_time: new Date('July 21, 2024 01:15:00'), studentId: '02012470', + roles: ['student'], courses: [], groups: [], + faculties: [], }, { id: '3', @@ -192,8 +212,10 @@ const students = [ last_enrolled: 2023, create_time: new Date('July 21, 2024 01:15:00'), studentId: null, + roles: ['student'], courses: [], groups: [], + faculties: [], }, ]; @@ -442,8 +464,8 @@ export const restHandlers = [ http.get(baseUrl + endpoints.submissions.byGroup.replace('{groupId}', ':id'), ({ params }) => { return HttpResponse.json(submissions.filter((x) => x.group === params.id)); }), - http.get(baseUrl + endpoints.faculties.retrieve.replace('{name}', ':name'), ({ params }) => { - return HttpResponse.json(faculties.find((x) => x.name === params.name)); + http.get(baseUrl + endpoints.faculties.retrieve.replace('{id}', ':id'), ({ params }) => { + return HttpResponse.json(faculties.find((x) => x.id === params.id)); }), http.get(baseUrl + endpoints.faculties.index, () => { return HttpResponse.json(faculties); @@ -463,6 +485,29 @@ export const restHandlers = [ http.get(baseUrl + endpoints.assistants.index, () => { return HttpResponse.json(assistants); }), + http.post(baseUrl + endpoints.admins.index, async ({ request }) => { + const buffer = await request.arrayBuffer(); + const requestBody = new TextDecoder().decode(buffer); + const newAdmin = JSON.parse(requestBody); + newAdmin.is_staff = true; + admins.push(newAdmin); + return HttpResponse.json(admins); + }), + http.post(baseUrl + endpoints.assistants.index, async ({ request }) => { + const buffer = await request.arrayBuffer(); + const requestBody = new TextDecoder().decode(buffer); + const newAssistant = JSON.parse(requestBody); + newAssistant.roles = ['assistant']; + assistants.push(newAssistant); + return HttpResponse.json(assistants); + }), + http.post(baseUrl + endpoints.students.index, async ({ request }) => { + const buffer = await request.arrayBuffer(); + const requestBody = new TextDecoder().decode(buffer); + const newStudent = JSON.parse(requestBody); + students.push(newStudent); + return HttpResponse.json(students); + }), /* http.post(baseUrl + endpoints.groups.byProject.replace('{projectId}', ':id'), @@ -479,6 +524,18 @@ const server = setupServer(...restHandlers); beforeAll(() => { server.listen({ onUnhandledRequest: 'error' }); + + // Set up jdom + const dom = new JSDOM(`
`); + global.document = dom.window.document; + global.window = dom.window as unknown as Window & typeof globalThis; + + // Set up the app with pinia + const pinia = createPinia(); + const app = createApp({ + template: '

App

', + }); + app.use(pinia); }); afterAll(() => { diff --git a/frontend/src/test/unit/student_service.test.ts b/frontend/src/test/unit/student_service.test.ts index f966e4bc..a10cc132 100644 --- a/frontend/src/test/unit/student_service.test.ts +++ b/frontend/src/test/unit/student_service.test.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { describe, it, expect, beforeEach } from 'vitest'; import { useStudents } from '@/composables/services/students.service.ts'; +import { Student } from '@/types/users/Student'; const { students, @@ -157,4 +158,39 @@ describe('students', (): void => { expect(students.value?.[3]?.groups).toEqual([]); expect(students.value?.[3]?.faculties).toEqual([]); }); + + it('create student', async () => { + const exampleStudent = new Student( + '103', + 'sample_student', + 'sample.student@UGent.be', + 'Sample', + 'Student', + false, + 2024, + new Date('April 2, 2023 01:15:00'), + new Date('April 2, 2024 01:15:00'), + '12345', + ['student'], + [], + [], + [], + ); + + await getStudents(); + expect(students).not.toBeNull(); + expect(Array.isArray(students.value)).toBe(true); + const prevLength = students.value?.length ?? 0; + + await createStudent(exampleStudent); + await getStudents(); + + expect(students).not.toBeNull(); + expect(Array.isArray(students.value)).toBe(true); + expect(students.value?.length).toBe(prevLength + 1); + + expect(students.value?.[prevLength]?.first_name).toBe('Sample'); + expect(students.value?.[prevLength]?.last_name).toBe('Student'); + expect(students.value?.[prevLength]?.email).toBe('sample.student@UGent.be'); + }); });