From 698454e3a8bf0a6d3636f30f8796b194ed6557e0 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Thu, 16 May 2024 17:16:54 +0200 Subject: [PATCH 01/18] chore: add loads of changes to login mechanism for testing (possible options are admin, student, and all roles at the same time) #434 --- backend/authentication/views.py | 38 ++++++++++++++++++++----------- backend/ypovoli/settings.py | 31 ++++++++++++++++++------- frontend/cypress/support/e2e.ts | 8 ++++++- frontend/package.json | 1 + frontend/src/test/e2e/login.cy.ts | 4 ++-- 5 files changed, 58 insertions(+), 24 deletions(-) diff --git a/backend/authentication/views.py b/backend/authentication/views.py index 85af6b5a..8df4ebc2 100644 --- a/backend/authentication/views.py +++ b/backend/authentication/views.py @@ -1,3 +1,5 @@ +from api.models.assistant import Assistant +from api.models.teacher import Teacher from django.http import HttpResponseRedirect from authentication.cas.client import client @@ -66,20 +68,23 @@ def echo(self, request: Request) -> Response: raise AuthenticationFailed(token_serializer.errors) -def create_user(self, request) -> Response: +def create_user(self, request, data) -> User: """General function to create a user, log them in and which returns an empty html page""" # log in user, or retrieve if they already exist - user, created = User.objects.get_or_create(id=settings.TEST_USER_DATA["id"], defaults=settings.TEST_USER_DATA) + user, created = User.objects.get_or_create(id=data["id"], defaults=data) # if it has just been created, send the signal to user_created Signal(), to also activate it as a student if created: - user_created.send(sender=self, attributes=settings.TEST_USER_ATTRIBUTES, user=user) + user_created.send(sender=self, attributes={**data, **settings.TEST_STUDENT_ATTRIBUTES}, user=user) # login the user login(request, user) # return Response with empty html page - return Response('', + return user + + +response = Response('', status=HTTP_200_OK, headers={"Location": "/"}, content_type="text/html") @@ -88,14 +93,21 @@ class TestUser(ViewSet): permission_classes = [IsDebug] - @action(detail=False, methods=['GET'], permission_classes=[IsDebug], url_path='admin') - def login_admin(self, request, *__) -> Response: - """This endpoint lets you log in an admin""" - settings.TEST_USER_DATA["is_staff"] = True - return create_user(self, request) - - @action(detail=False, methods=['GET'], permission_classes=[IsDebug], url_path='student') + @action(detail=False, methods=['POST'], permission_classes=[IsDebug], url_path='student') def login_student(self, request, *__) -> Response: """This endpoint lets you log in as a student who's not an admin""" - settings.TEST_USER_DATA["is_staff"] = False - return create_user(self, request) + create_user(self, request, settings.TEST_STUDENT_DATA) + return response + + @action(detail=False, methods=['POST'], permission_classes=[IsDebug], url_path='multi') + def login_multi(self, request, *__) -> Response: + user = create_user(self, request, settings.TEST_MULTI_DATA) + Assistant.create(user) + Teacher.create(user) + return response + + @action(detail=False, methods=['POST'], permission_classes=[IsDebug], url_path='admin') + def login_admin(self, request, *__) -> Response: + """This endpoint lets you log in an admin""" + create_user(self, request, settings.TEST_ADMIN_DATA) + return response diff --git a/backend/ypovoli/settings.py b/backend/ypovoli/settings.py index f0e3186e..bd54444c 100644 --- a/backend/ypovoli/settings.py +++ b/backend/ypovoli/settings.py @@ -28,15 +28,30 @@ # TESTING TESTING_BASE_LINK = "http://testserver" -TEST_USER_DATA = { - "id": "1234", - "username": "test", - "email": "test@test", - "first_name": "test", - "last_name": "test", +TEST_ADMIN_DATA = { + "id": "0", + "username": "admin", + "email": "admin@test", + "first_name": "admin", + "last_name": "admin", + "is_staff": True } -TEST_USER_ATTRIBUTES = { - **TEST_USER_DATA, +TEST_STUDENT_DATA = { + "id": "1", + "username": "student", + "email": "student@test", + "first_name": "student", + "last_name": "student", +} +TEST_MULTI_DATA = { + "id": "2", + "username": "multi", + "email": "multi@test", + "first_name": "multi", + "last_name": "multi", +} +TEST_STUDENT_ATTRIBUTES = { + **TEST_STUDENT_DATA, "ugentStudentID": "1234" } diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts index f80f74f8..d22ebaa4 100644 --- a/frontend/cypress/support/e2e.ts +++ b/frontend/cypress/support/e2e.ts @@ -17,4 +17,10 @@ import './commands' // Alternatively you can use CommonJS syntax: -// require('./commands') \ No newline at end of file +// require('./commands') + +before(() => { + // log in a user of every type + // non-staff: student (basic login); student + assistant + teacher + // staff user +}) \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 38241a94..af61dcc4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,6 +11,7 @@ "test": "vitest run", "cypress:open": "cypress open", "cypress:test": "cypress run", + "cypress:install": "cypress install", "lint": "eslint src --ext .ts,.vue", "lint-fix": "eslint src --ext .ts,.vue --fix" }, diff --git a/frontend/src/test/e2e/login.cy.ts b/frontend/src/test/e2e/login.cy.ts index 107f1bf7..37ec2e8c 100644 --- a/frontend/src/test/e2e/login.cy.ts +++ b/frontend/src/test/e2e/login.cy.ts @@ -7,7 +7,7 @@ describe('login', () => { }); it('does not redirect to login page when logged in', () => { // log in as a test student - cy.visit('/api/auth/test-user/student/'); + cy.request('POST', '/api/auth/test-user/student/'); // visit dashboard cy.visit('/'); // should not be redirected to login page @@ -19,7 +19,7 @@ describe('login', () => { // intercept the retrieval of student info cy.intercept('/api/students/*/').as('student'); // log in as a test student - cy.visit('/api/auth/test-user/student/'); + cy.request('POST', '/api/auth/test-user/student/'); // visit dashboard cy.visit('/'); // wait for requests for student info to end From 133a2e6df8705008c2d908819b23a0fde4a4af39 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Fri, 17 May 2024 14:41:35 +0200 Subject: [PATCH 02/18] chore: login users beforehand (might delete this in the future actually) #434 --- frontend/cypress/support/e2e.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts index d22ebaa4..c42d4431 100644 --- a/frontend/cypress/support/e2e.ts +++ b/frontend/cypress/support/e2e.ts @@ -22,5 +22,11 @@ import './commands' before(() => { // log in a user of every type // non-staff: student (basic login); student + assistant + teacher + cy.request('POST', '/api/auth/test-user/student/') + cy.request('POST', '/api/auth/cas/logout/') + cy.request('POST', '/api/auth/test-user/multi/') + cy.request('POST', '/api/auth/cas/logout/') // staff user + cy.request('POST', '/api/auth/test-user/admin/') + cy.request('POST', '/api/auth/cas/logout/') }) \ No newline at end of file From 7de35934c0416cc1cd5768f2d9bec0b8ba79ff72 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Tue, 21 May 2024 12:05:50 +0200 Subject: [PATCH 03/18] chore: trying to fix adding data before tests #434 --- frontend/cypress.config.js | 3 +- frontend/cypress/support/e2e.ts | 32 -------------- frontend/src/test/e2e/setup/data.ts | 15 +++++++ frontend/src/test/e2e/setup/e2e.ts | 65 +++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 33 deletions(-) delete mode 100644 frontend/cypress/support/e2e.ts create mode 100644 frontend/src/test/e2e/setup/data.ts create mode 100644 frontend/src/test/e2e/setup/e2e.ts diff --git a/frontend/cypress.config.js b/frontend/cypress.config.js index 83abcaba..b0ad3430 100644 --- a/frontend/cypress.config.js +++ b/frontend/cypress.config.js @@ -2,7 +2,8 @@ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { - baseUrl: 'https://nginx', + baseUrl: 'https://localhost', specPattern: 'src/test/e2e/**/*.cy.{js,jsx,ts,tsx}', + supportFile: 'src/test/e2e/setup/e2e.ts', }, }); diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts deleted file mode 100644 index c42d4431..00000000 --- a/frontend/cypress/support/e2e.ts +++ /dev/null @@ -1,32 +0,0 @@ -// *********************************************************** -// This example support/e2e.ts is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands' - -// Alternatively you can use CommonJS syntax: -// require('./commands') - -before(() => { - // log in a user of every type - // non-staff: student (basic login); student + assistant + teacher - cy.request('POST', '/api/auth/test-user/student/') - cy.request('POST', '/api/auth/cas/logout/') - cy.request('POST', '/api/auth/test-user/multi/') - cy.request('POST', '/api/auth/cas/logout/') - // staff user - cy.request('POST', '/api/auth/test-user/admin/') - cy.request('POST', '/api/auth/cas/logout/') -}) \ No newline at end of file diff --git a/frontend/src/test/e2e/setup/data.ts b/frontend/src/test/e2e/setup/data.ts new file mode 100644 index 00000000..c544eb1a --- /dev/null +++ b/frontend/src/test/e2e/setup/data.ts @@ -0,0 +1,15 @@ +const date = new Date(); + +export const faculty = { + id: '0', + name: 'Faculty' +}; + +export const course = { + name: 'Course', + academic_startyear: date.getMonth() > 8 ? date.getFullYear() : date.getFullYear() - 1, + excerpt: 'This is a course', + faculty: faculty, + private_course: false +}; + diff --git a/frontend/src/test/e2e/setup/e2e.ts b/frontend/src/test/e2e/setup/e2e.ts new file mode 100644 index 00000000..bdf93215 --- /dev/null +++ b/frontend/src/test/e2e/setup/e2e.ts @@ -0,0 +1,65 @@ +// *********************************************************** +// This example support/e2e.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import '../../../../cypress/support/commands.ts' + +// Alternatively you can use CommonJS syntax: +// require('./commands') + +import { faculty, course, } from "./data.ts"; +import { client } from '@/config/axios.ts'; + +const post = (url: string, csrfToken: string | undefined, body = {}) => { + cy.request({ + method: 'POST', + url: url, + headers: { + 'X-CSRFToken': csrfToken, + }, + body: body, + }).then(response => { + console.log(response); + }) +} + +before(async () => { + await client.post('/api/auth/test-user/admin/') + + cy.visit('/'); + cy.getCookie('csrftoken').then((cookie) => { + debugger; + if (cookie) { + const csrfToken = cookie.value; + // log in as normal users to add 2 users to the database + post('/api/auth/test-user/student/', csrfToken); + post('/api/auth/cas/logout/', csrfToken); + post('/api/auth/test-user/multi/', csrfToken); + post('/api/auth/cas/logout/', csrfToken); + + // log in as an admin user to insert our test data into the database + post('/api/auth/test-user/admin/', csrfToken); + + // add test data + post('/api/faculties/', csrfToken, faculty); + post('/api/courses/', csrfToken, course); + + // logout for cleanup + post('/api/auth/cas/logout/', csrfToken); + } else { + console.log('cookie not found'); + } + }); +}) \ No newline at end of file From be8c9222bbcd34f6be296bf3d13290ad99b8aa53 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Tue, 21 May 2024 14:27:54 +0200 Subject: [PATCH 04/18] chore: more trial and error #434 --- frontend/cypress.config.js | 9 ++++++ frontend/src/test/e2e/setup/data.ts | 2 +- frontend/src/test/e2e/setup/e2e.ts | 45 +---------------------------- frontend/src/test/e2e/setup/seed.ts | 20 +++++++++++++ 4 files changed, 31 insertions(+), 45 deletions(-) create mode 100644 frontend/src/test/e2e/setup/seed.ts diff --git a/frontend/cypress.config.js b/frontend/cypress.config.js index b0ad3430..fe04e147 100644 --- a/frontend/cypress.config.js +++ b/frontend/cypress.config.js @@ -1,7 +1,16 @@ import { defineConfig } from 'cypress'; +import { client } from '@/config/axios.ts'; +import { seed } from '@/test/e2e/setup/seed.ts'; export default defineConfig({ e2e: { + setupNodeEvents(on, config) { + on('task', { + async 'db:seed'() { + await seed(client); + } + }) + }, baseUrl: 'https://localhost', specPattern: 'src/test/e2e/**/*.cy.{js,jsx,ts,tsx}', supportFile: 'src/test/e2e/setup/e2e.ts', diff --git a/frontend/src/test/e2e/setup/data.ts b/frontend/src/test/e2e/setup/data.ts index c544eb1a..86212f76 100644 --- a/frontend/src/test/e2e/setup/data.ts +++ b/frontend/src/test/e2e/setup/data.ts @@ -9,7 +9,7 @@ export const course = { name: 'Course', academic_startyear: date.getMonth() > 8 ? date.getFullYear() : date.getFullYear() - 1, excerpt: 'This is a course', - faculty: faculty, + faculty: faculty.id, private_course: false }; diff --git a/frontend/src/test/e2e/setup/e2e.ts b/frontend/src/test/e2e/setup/e2e.ts index bdf93215..0ce01a5b 100644 --- a/frontend/src/test/e2e/setup/e2e.ts +++ b/frontend/src/test/e2e/setup/e2e.ts @@ -19,47 +19,4 @@ import '../../../../cypress/support/commands.ts' // Alternatively you can use CommonJS syntax: // require('./commands') -import { faculty, course, } from "./data.ts"; -import { client } from '@/config/axios.ts'; - -const post = (url: string, csrfToken: string | undefined, body = {}) => { - cy.request({ - method: 'POST', - url: url, - headers: { - 'X-CSRFToken': csrfToken, - }, - body: body, - }).then(response => { - console.log(response); - }) -} - -before(async () => { - await client.post('/api/auth/test-user/admin/') - - cy.visit('/'); - cy.getCookie('csrftoken').then((cookie) => { - debugger; - if (cookie) { - const csrfToken = cookie.value; - // log in as normal users to add 2 users to the database - post('/api/auth/test-user/student/', csrfToken); - post('/api/auth/cas/logout/', csrfToken); - post('/api/auth/test-user/multi/', csrfToken); - post('/api/auth/cas/logout/', csrfToken); - - // log in as an admin user to insert our test data into the database - post('/api/auth/test-user/admin/', csrfToken); - - // add test data - post('/api/faculties/', csrfToken, faculty); - post('/api/courses/', csrfToken, course); - - // logout for cleanup - post('/api/auth/cas/logout/', csrfToken); - } else { - console.log('cookie not found'); - } - }); -}) \ No newline at end of file +cy.task('db:seed'); \ No newline at end of file diff --git a/frontend/src/test/e2e/setup/seed.ts b/frontend/src/test/e2e/setup/seed.ts new file mode 100644 index 00000000..7ab211b2 --- /dev/null +++ b/frontend/src/test/e2e/setup/seed.ts @@ -0,0 +1,20 @@ +import { AxiosInstance } from 'axios'; +import { faculty, course } from './data.ts'; + +export const seed = async (client: AxiosInstance) => { + // log in as normal users to add 2 users to the database + await client.post('/api/auth/test-user/student/'); + await client.post('/api/auth/cas/logout/'); + await client.post('/api/auth/test-user/multi/'); + await client.post('/api/auth/cas/logout/'); + + // log in as an admin user to insert our test data into the database + await client.post('/api/auth/test-user/admin/'); + + // add test data + await client.post('/api/faculties/', faculty); + await client.post('/api/courses/', course); + + // logout for cleanup + await client.post('/api/auth/cas/logout/'); +} \ No newline at end of file From b90e7a2e4767a1186d34d85f2bea8f2e88a6f6d4 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Tue, 21 May 2024 16:34:49 +0200 Subject: [PATCH 05/18] chore: struggling.. #434 --- backend/authentication/views.py | 11 ++++++----- frontend/cypress.config.js | 24 ++++++++++++++++++------ frontend/package-lock.json | 14 ++++++++++++++ frontend/package.json | 1 + frontend/src/test/e2e/setup/e2e.ts | 4 +++- frontend/src/test/e2e/setup/seed.ts | 4 ++-- 6 files changed, 44 insertions(+), 14 deletions(-) diff --git a/backend/authentication/views.py b/backend/authentication/views.py index 8df4ebc2..09663fdc 100644 --- a/backend/authentication/views.py +++ b/backend/authentication/views.py @@ -68,7 +68,7 @@ def echo(self, request: Request) -> Response: raise AuthenticationFailed(token_serializer.errors) -def create_user(self, request, data) -> User: +def create_user(self, request, data) -> tuple[User, bool]: """General function to create a user, log them in and which returns an empty html page""" # log in user, or retrieve if they already exist user, created = User.objects.get_or_create(id=data["id"], defaults=data) @@ -81,7 +81,7 @@ def create_user(self, request, data) -> User: login(request, user) # return Response with empty html page - return user + return user, created response = Response('', @@ -101,9 +101,10 @@ def login_student(self, request, *__) -> Response: @action(detail=False, methods=['POST'], permission_classes=[IsDebug], url_path='multi') def login_multi(self, request, *__) -> Response: - user = create_user(self, request, settings.TEST_MULTI_DATA) - Assistant.create(user) - Teacher.create(user) + user, created = create_user(self, request, settings.TEST_MULTI_DATA) + if created: + Assistant.create(user) + Teacher.create(user) return response @action(detail=False, methods=['POST'], permission_classes=[IsDebug], url_path='admin') diff --git a/frontend/cypress.config.js b/frontend/cypress.config.js index fe04e147..2a5270f6 100644 --- a/frontend/cypress.config.js +++ b/frontend/cypress.config.js @@ -1,17 +1,29 @@ +import path from 'path'; import { defineConfig } from 'cypress'; -import { client } from '@/config/axios.ts'; +import vitePreprocessor from 'cypress-vite'; + import { seed } from '@/test/e2e/setup/seed.ts'; export default defineConfig({ e2e: { setupNodeEvents(on, config) { - on('task', { - async 'db:seed'() { - await seed(client); + on('file:preprocessor', + vitePreprocessor('./vite.config.ts') + ); + on('before:run', + async (_) => { + await seed(); } - }) + ); + // on('task', { + // async 'db:seed'() { + // // import { seed } from '@/test/e2e/setup/seed.ts'; + // // import { client } from '@/config/axios.ts'; + // await seed(client); + // } + // }); }, - baseUrl: 'https://localhost', + baseUrl: 'https://nginx', specPattern: 'src/test/e2e/**/*.cy.{js,jsx,ts,tsx}', supportFile: 'src/test/e2e/setup/e2e.ts', }, diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6189c3b4..b38c986e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -33,6 +33,7 @@ "@typescript-eslint/eslint-plugin": "^6.21.0", "@vitejs/plugin-vue": "^5.0.4", "cypress": "^13.7.1", + "cypress-vite": "^1.5.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-config-standard-with-typescript": "^43.0.1", @@ -2812,6 +2813,19 @@ "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, + "node_modules/cypress-vite": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cypress-vite/-/cypress-vite-1.5.0.tgz", + "integrity": "sha512-vvTMqJZgI3sN2ylQTi4OQh8LRRjSrfrIdkQD5fOj+EC/e9oHkxS96lif1SyDF1PwailG1tnpJE+VpN6+AwO/rg==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.3", + "debug": "^4.3.4" + }, + "peerDependencies": { + "vite": "^2.9.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/cypress/node_modules/proxy-from-env": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index af61dcc4..a6a82480 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -41,6 +41,7 @@ "@typescript-eslint/eslint-plugin": "^6.21.0", "@vitejs/plugin-vue": "^5.0.4", "cypress": "^13.7.1", + "cypress-vite": "^1.5.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-config-standard-with-typescript": "^43.0.1", diff --git a/frontend/src/test/e2e/setup/e2e.ts b/frontend/src/test/e2e/setup/e2e.ts index 0ce01a5b..9cdf2787 100644 --- a/frontend/src/test/e2e/setup/e2e.ts +++ b/frontend/src/test/e2e/setup/e2e.ts @@ -19,4 +19,6 @@ import '../../../../cypress/support/commands.ts' // Alternatively you can use CommonJS syntax: // require('./commands') -cy.task('db:seed'); \ No newline at end of file +import { seed } from '@/test/e2e/setup/seed.ts'; + +seed().then(r => console.log(r)); \ No newline at end of file diff --git a/frontend/src/test/e2e/setup/seed.ts b/frontend/src/test/e2e/setup/seed.ts index 7ab211b2..1c0dadc7 100644 --- a/frontend/src/test/e2e/setup/seed.ts +++ b/frontend/src/test/e2e/setup/seed.ts @@ -1,7 +1,7 @@ -import { AxiosInstance } from 'axios'; import { faculty, course } from './data.ts'; +import { client } from '@/config/axios.ts'; -export const seed = async (client: AxiosInstance) => { +export const seed = async () => { // log in as normal users to add 2 users to the database await client.post('/api/auth/test-user/student/'); await client.post('/api/auth/cas/logout/'); From 245e1b20160ba03e957b3469afa86c3ef0589609 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Tue, 21 May 2024 18:04:12 +0200 Subject: [PATCH 06/18] chore: so close, but yet so far #407 --- frontend/cypress.config.js | 15 ++++++++------- frontend/src/test/e2e/setup/e2e.ts | 4 +++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/frontend/cypress.config.js b/frontend/cypress.config.js index 2a5270f6..28fed52a 100644 --- a/frontend/cypress.config.js +++ b/frontend/cypress.config.js @@ -2,7 +2,7 @@ import path from 'path'; import { defineConfig } from 'cypress'; import vitePreprocessor from 'cypress-vite'; -import { seed } from '@/test/e2e/setup/seed.ts'; +const preprocessor = vitePreprocessor('./vite.config.ts'); export default defineConfig({ e2e: { @@ -11,15 +11,16 @@ export default defineConfig({ vitePreprocessor('./vite.config.ts') ); on('before:run', - async (_) => { - await seed(); + () => { + preprocessor(); + import('@/test/e2e/setup/seed.ts').then(async (module) => { + await module.seed(); + }); } ); // on('task', { - // async 'db:seed'() { - // // import { seed } from '@/test/e2e/setup/seed.ts'; - // // import { client } from '@/config/axios.ts'; - // await seed(client); + // async 'db:seed'(seed) { + // await seed(); // } // }); }, diff --git a/frontend/src/test/e2e/setup/e2e.ts b/frontend/src/test/e2e/setup/e2e.ts index 9cdf2787..861119ae 100644 --- a/frontend/src/test/e2e/setup/e2e.ts +++ b/frontend/src/test/e2e/setup/e2e.ts @@ -21,4 +21,6 @@ import '../../../../cypress/support/commands.ts' import { seed } from '@/test/e2e/setup/seed.ts'; -seed().then(r => console.log(r)); \ No newline at end of file +it('fills database', () => { + cy.task('db:seed', seed); +}) From 2c3538df0a7e53abe1a8a5fc783164c549e7ec73 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Tue, 21 May 2024 18:05:49 +0200 Subject: [PATCH 07/18] chore: fix location of preprocessor #407 --- frontend/cypress.config.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/frontend/cypress.config.js b/frontend/cypress.config.js index 28fed52a..109b88b8 100644 --- a/frontend/cypress.config.js +++ b/frontend/cypress.config.js @@ -2,22 +2,19 @@ import path from 'path'; import { defineConfig } from 'cypress'; import vitePreprocessor from 'cypress-vite'; -const preprocessor = vitePreprocessor('./vite.config.ts'); - export default defineConfig({ e2e: { setupNodeEvents(on, config) { on('file:preprocessor', vitePreprocessor('./vite.config.ts') ); - on('before:run', - () => { - preprocessor(); - import('@/test/e2e/setup/seed.ts').then(async (module) => { - await module.seed(); - }); - } - ); + // on('before:run', + // () => { + // import('@/test/e2e/setup/seed.ts').then(async (module) => { + // await module.seed(); + // }); + // } + // ); // on('task', { // async 'db:seed'(seed) { // await seed(); From 573dc2032806744a8846c5bf079c67d1a94e14db Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Wed, 22 May 2024 11:20:35 +0200 Subject: [PATCH 08/18] chore: remove unnecessary node events #434 --- frontend/cypress.config.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/frontend/cypress.config.js b/frontend/cypress.config.js index 109b88b8..003983dd 100644 --- a/frontend/cypress.config.js +++ b/frontend/cypress.config.js @@ -1,4 +1,3 @@ -import path from 'path'; import { defineConfig } from 'cypress'; import vitePreprocessor from 'cypress-vite'; @@ -8,18 +7,6 @@ export default defineConfig({ on('file:preprocessor', vitePreprocessor('./vite.config.ts') ); - // on('before:run', - // () => { - // import('@/test/e2e/setup/seed.ts').then(async (module) => { - // await module.seed(); - // }); - // } - // ); - // on('task', { - // async 'db:seed'(seed) { - // await seed(); - // } - // }); }, baseUrl: 'https://nginx', specPattern: 'src/test/e2e/**/*.cy.{js,jsx,ts,tsx}', From 94745c22a57b114a0fa0f53f8d6866ff6a343cd3 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Wed, 22 May 2024 11:20:57 +0200 Subject: [PATCH 09/18] chore: test.sh script now deletes database and fills with realistic fixtures #434 --- test.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test.sh b/test.sh index 500e6073..1213123f 100755 --- a/test.sh +++ b/test.sh @@ -66,6 +66,10 @@ django_exit=0 if [ "$frontend" = true ]; then echo "Running frontend tests..." + echo "Filling up database with test data" + docker exec backend sh -c "python manage.py flush --no-input; python manage.py migrate; python manage.py loaddata + notifications/fixtures/$data/*; python manage.py loaddata authentication/fixtures/$data/*; python manage.py + loaddata api/fixtures/$data/*;" echo "Running Cypress tests..." docker-compose -f test.yml up --exit-code-from cypress --abort-on-container-exit cypress cypress_exit=$? From 472c3ce5f6fa1fa14e565ce04b9dcfe80d3eee0f Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Wed, 22 May 2024 15:53:26 +0200 Subject: [PATCH 10/18] test: automatically login all users, before every test file, so that they're available, but also automatically logout after every test #434 --- frontend/cypress/support/e2e.ts | 65 ++++++++++++++++++++++++++++++ frontend/src/test/e2e/login.cy.ts | 6 --- frontend/src/test/e2e/setup/e2e.ts | 26 ------------ 3 files changed, 65 insertions(+), 32 deletions(-) create mode 100644 frontend/cypress/support/e2e.ts delete mode 100644 frontend/src/test/e2e/setup/e2e.ts diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts new file mode 100644 index 00000000..edc31e4a --- /dev/null +++ b/frontend/cypress/support/e2e.ts @@ -0,0 +1,65 @@ +// *********************************************************** +// This example support/e2e.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands.ts' + +// Alternatively you can use CommonJS syntax: +// require('./commands') + +Cypress.on('uncaught:exception', (err, runnable) => { + // log uncaught error + console.error('Uncaught exception:', err.message); + + return !err.message.includes('401'); +}); + +const logout = () => { + cy.getCookie('csrftoken').then((cookie) => { + cy.getCookie('sessionid').then((cookie2) => { + if (cookie && cookie2) { + cy.request({ + method: 'POST', + url: '/api/auth/cas/logout/', + headers: { + 'Referer': Cypress.config('baseUrl'), + 'X-CSRFToken': cookie.value, + }, + }); + } + }) + + }); +} + +before(() => { + cy.intercept('POST', '/api/auth/cas/logout/', (req) => { + console.log('intercepted'); + req.headers['Referer'] = Cypress.config('baseUrl'); + + return req; + }); + + cy.request('POST', '/api/auth/test-user/student/'); + logout(); + cy.request('POST', '/api/auth/test-user/multi/'); + logout(); + cy.request('POST', '/api/auth/test-user/admin/'); + logout(); +}) + +afterEach(() => { + logout(); +}) diff --git a/frontend/src/test/e2e/login.cy.ts b/frontend/src/test/e2e/login.cy.ts index 37ec2e8c..b21c2c98 100644 --- a/frontend/src/test/e2e/login.cy.ts +++ b/frontend/src/test/e2e/login.cy.ts @@ -16,16 +16,10 @@ describe('login', () => { cy.get('#logout').click(); }); it('redirects to login page after logging out', () => { - // intercept the retrieval of student info - cy.intercept('/api/students/*/').as('student'); // log in as a test student cy.request('POST', '/api/auth/test-user/student/'); // visit dashboard cy.visit('/'); - // wait for requests for student info to end - cy.wait('@student'); - cy.wait('@student'); - cy.wait('@student'); // logout cy.get('#logout').click(); // should be on login page now diff --git a/frontend/src/test/e2e/setup/e2e.ts b/frontend/src/test/e2e/setup/e2e.ts deleted file mode 100644 index 861119ae..00000000 --- a/frontend/src/test/e2e/setup/e2e.ts +++ /dev/null @@ -1,26 +0,0 @@ -// *********************************************************** -// This example support/e2e.ts is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import '../../../../cypress/support/commands.ts' - -// Alternatively you can use CommonJS syntax: -// require('./commands') - -import { seed } from '@/test/e2e/setup/seed.ts'; - -it('fills database', () => { - cy.task('db:seed', seed); -}) From e21facdba4cbcef716c5f427d108f447e9ecd2be Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Wed, 22 May 2024 15:54:42 +0200 Subject: [PATCH 11/18] test: set path to supportFile correctly cypress #434 --- frontend/cypress.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/cypress.config.js b/frontend/cypress.config.js index 003983dd..fbde2fec 100644 --- a/frontend/cypress.config.js +++ b/frontend/cypress.config.js @@ -10,6 +10,5 @@ export default defineConfig({ }, baseUrl: 'https://nginx', specPattern: 'src/test/e2e/**/*.cy.{js,jsx,ts,tsx}', - supportFile: 'src/test/e2e/setup/e2e.ts', }, }); From 02ca508ce6cddda819f0e90d6ecd99457ab291a8 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Wed, 22 May 2024 15:56:48 +0200 Subject: [PATCH 12/18] test: removing logging out for cleaning up #434 --- frontend/src/test/e2e/login.cy.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/test/e2e/login.cy.ts b/frontend/src/test/e2e/login.cy.ts index b21c2c98..7c2f80d3 100644 --- a/frontend/src/test/e2e/login.cy.ts +++ b/frontend/src/test/e2e/login.cy.ts @@ -12,8 +12,6 @@ describe('login', () => { cy.visit('/'); // should not be redirected to login page cy.url().should('not.match', /^.*\/auth\/login$/); - // logout for cleaning up - cy.get('#logout').click(); }); it('redirects to login page after logging out', () => { // log in as a test student From bb3de5d726e165b0397a55a1f1c5b9dbdc024307 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Wed, 22 May 2024 17:12:35 +0200 Subject: [PATCH 13/18] test: add professor login endpoint #434 --- backend/authentication/views.py | 10 +++++++++- backend/ypovoli/settings.py | 15 +++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/backend/authentication/views.py b/backend/authentication/views.py index 09663fdc..ca985f31 100644 --- a/backend/authentication/views.py +++ b/backend/authentication/views.py @@ -75,7 +75,7 @@ def create_user(self, request, data) -> tuple[User, bool]: # if it has just been created, send the signal to user_created Signal(), to also activate it as a student if created: - user_created.send(sender=self, attributes={**data, **settings.TEST_STUDENT_ATTRIBUTES}, user=user) + user_created.send(sender=self, attributes={**data, "ugentStudentID": data.id}, user=user) # login the user login(request, user) @@ -99,8 +99,16 @@ def login_student(self, request, *__) -> Response: create_user(self, request, settings.TEST_STUDENT_DATA) return response + @action(detail=False, methods=['POST'], permission_classes=[IsDebug], url_path='professor') + def login_professor(self, request, *__) -> Response: + """This endpoint lets you log in as a professor""" + user, created = create_user(self, request, settings.TEST_PROFESSOR_DATA) + if created: + Teacher.create(user) + @action(detail=False, methods=['POST'], permission_classes=[IsDebug], url_path='multi') def login_multi(self, request, *__) -> Response: + """This endpoint lets you log in as a user who's a student, an assistant and a professor at the same time""" user, created = create_user(self, request, settings.TEST_MULTI_DATA) if created: Assistant.create(user) diff --git a/backend/ypovoli/settings.py b/backend/ypovoli/settings.py index bd54444c..36527c9f 100644 --- a/backend/ypovoli/settings.py +++ b/backend/ypovoli/settings.py @@ -37,23 +37,26 @@ "is_staff": True } TEST_STUDENT_DATA = { - "id": "1", + "id": "6", "username": "student", "email": "student@test", "first_name": "student", "last_name": "student", } +TEST_PROFESSOR_DATA = { + "id": "1", + "username": "professor", + "email": "professor@test", + "first_name": "professor", + "last_name": "professor", +} TEST_MULTI_DATA = { - "id": "2", + "id": "10", "username": "multi", "email": "multi@test", "first_name": "multi", "last_name": "multi", } -TEST_STUDENT_ATTRIBUTES = { - **TEST_STUDENT_DATA, - "ugentStudentID": "1234" -} # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = environ.get("DJANGO_SECRET_KEY", "lnZZ2xHc6HjU5D85GDE3Nnu4CJsBnm") From a7bbfe30a9d86768b2948f2449754a134a879d96 Mon Sep 17 00:00:00 2001 From: bsilkyn Date: Wed, 22 May 2024 17:12:41 +0200 Subject: [PATCH 14/18] test: cleanup #434 --- frontend/cypress/support/e2e.ts | 23 +++++++------------ frontend/src/test/e2e/setup/data.ts | 15 ------------ frontend/src/test/e2e/setup/seed.ts | 20 ---------------- frontend/src/views/layout/base/BaseHeader.vue | 10 ++++++-- test.sh | 4 ++-- 5 files changed, 18 insertions(+), 54 deletions(-) delete mode 100644 frontend/src/test/e2e/setup/data.ts delete mode 100644 frontend/src/test/e2e/setup/seed.ts diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts index edc31e4a..f553c558 100644 --- a/frontend/cypress/support/e2e.ts +++ b/frontend/cypress/support/e2e.ts @@ -44,21 +44,14 @@ const logout = () => { }); } -before(() => { - cy.intercept('POST', '/api/auth/cas/logout/', (req) => { - console.log('intercepted'); - req.headers['Referer'] = Cypress.config('baseUrl'); - - return req; - }); - - cy.request('POST', '/api/auth/test-user/student/'); - logout(); - cy.request('POST', '/api/auth/test-user/multi/'); - logout(); - cy.request('POST', '/api/auth/test-user/admin/'); - logout(); -}) +// before(() => { +// cy.request('POST', '/api/auth/test-user/student/'); +// logout(); +// cy.request('POST', '/api/auth/test-user/multi/'); +// logout(); +// cy.request('POST', '/api/auth/test-user/admin/'); +// logout(); +// }) afterEach(() => { logout(); diff --git a/frontend/src/test/e2e/setup/data.ts b/frontend/src/test/e2e/setup/data.ts deleted file mode 100644 index 86212f76..00000000 --- a/frontend/src/test/e2e/setup/data.ts +++ /dev/null @@ -1,15 +0,0 @@ -const date = new Date(); - -export const faculty = { - id: '0', - name: 'Faculty' -}; - -export const course = { - name: 'Course', - academic_startyear: date.getMonth() > 8 ? date.getFullYear() : date.getFullYear() - 1, - excerpt: 'This is a course', - faculty: faculty.id, - private_course: false -}; - diff --git a/frontend/src/test/e2e/setup/seed.ts b/frontend/src/test/e2e/setup/seed.ts deleted file mode 100644 index 1c0dadc7..00000000 --- a/frontend/src/test/e2e/setup/seed.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { faculty, course } from './data.ts'; -import { client } from '@/config/axios.ts'; - -export const seed = async () => { - // log in as normal users to add 2 users to the database - await client.post('/api/auth/test-user/student/'); - await client.post('/api/auth/cas/logout/'); - await client.post('/api/auth/test-user/multi/'); - await client.post('/api/auth/cas/logout/'); - - // log in as an admin user to insert our test data into the database - await client.post('/api/auth/test-user/admin/'); - - // add test data - await client.post('/api/faculties/', faculty); - await client.post('/api/courses/', course); - - // logout for cleanup - await client.post('/api/auth/cas/logout/'); -} \ No newline at end of file diff --git a/frontend/src/views/layout/base/BaseHeader.vue b/frontend/src/views/layout/base/BaseHeader.vue index 519ecbe0..2a9b20e2 100644 --- a/frontend/src/views/layout/base/BaseHeader.vue +++ b/frontend/src/views/layout/base/BaseHeader.vue @@ -107,7 +107,13 @@ const items = computed(() => [