diff --git a/src/test/playwright/e2e/exam/ExamAssessment.spec.ts b/src/test/playwright/e2e/exam/ExamAssessment.spec.ts index dd081b6bd467..ea6e00a07aea 100644 --- a/src/test/playwright/e2e/exam/ExamAssessment.spec.ts +++ b/src/test/playwright/e2e/exam/ExamAssessment.spec.ts @@ -53,12 +53,13 @@ test.beforeAll('Create course', async ({ browser }) => { studentOneName = (await users.getUserInfo(studentOne.username, page)).name!; }); -test.describe('Exam assessment', { tag: '@slow' }, () => { +test.describe('Exam assessment', () => { + test.describe.configure({ mode: 'serial' }); let programmingAssessmentSuccessful = false; let modelingAssessmentSuccessful = false; let textAssessmentSuccessful = false; - test.describe.serial('Programming exercise assessment', () => { + test.describe.serial('Programming exercise assessment', { tag: '@sequential' }, () => { test.beforeAll('Prepare exam', async ({ browser }) => { examEnd = dayjs().add(2, 'minutes'); const page = await newBrowserPage(browser); @@ -85,7 +86,7 @@ test.describe('Exam assessment', { tag: '@slow' }, () => { }); }); - test.describe.serial('Modeling exercise assessment', () => { + test.describe.serial('Modeling exercise assessment', { tag: '@slow' }, () => { test.beforeAll('Prepare exam', async ({ browser }) => { examEnd = dayjs().add(45, 'seconds'); const page = await newBrowserPage(browser); @@ -126,7 +127,7 @@ test.describe('Exam assessment', { tag: '@slow' }, () => { }); }); - test.describe.serial('Text exercise assessment', () => { + test.describe.serial('Text exercise assessment', { tag: '@slow' }, () => { test.beforeAll('Prepare exam', async ({ browser }) => { examEnd = dayjs().add(40, 'seconds'); const page = await newBrowserPage(browser); @@ -153,7 +154,7 @@ test.describe('Exam assessment', { tag: '@slow' }, () => { }); }); - test.describe('Quiz exercise assessment', () => { + test.describe('Quiz exercise assessment', { tag: '@slow' }, () => { let resultDate: Dayjs; test.beforeAll('Prepare exam', async ({ browser }) => { @@ -183,7 +184,7 @@ test.describe('Exam assessment', { tag: '@slow' }, () => { }); }); -test.describe('Exam grading', () => { +test.describe('Exam grading', { tag: '@fast' }, () => { test.describe.serial('Instructor sets grades and student receives a grade', () => { let exam: Exam; @@ -222,7 +223,7 @@ test.describe('Exam grading', () => { }); }); -test.describe('Exam statistics', { tag: '@slow' }, () => { +test.describe('Exam statistics', { tag: '@sequential' }, () => { let exercise: Exercise; const students = [studentOne, studentTwo, studentThree, studentFour]; diff --git a/src/test/playwright/e2e/exam/ExamParticipation.spec.ts b/src/test/playwright/e2e/exam/ExamParticipation.spec.ts index 35e033e50d00..0e137ed96528 100644 --- a/src/test/playwright/e2e/exam/ExamParticipation.spec.ts +++ b/src/test/playwright/e2e/exam/ExamParticipation.spec.ts @@ -17,7 +17,7 @@ import { ExamParticipationActions } from '../../support/pageobjects/exam/ExamPar const textFixture = 'loremIpsum.txt'; const textFixtureShort = 'loremIpsum-short.txt'; -test.describe('Exam participation', { tag: '@slow' }, () => { +test.describe('Exam participation', () => { let course: Course; let exerciseArray: Array = []; let studentTwoName: string; @@ -43,7 +43,7 @@ test.describe('Exam participation', { tag: '@slow' }, () => { studentFourName = studentFourInfo.name!; }); - test.describe('Early Hand-in', () => { + test.describe('Early Hand-in', { tag: '@slow' }, () => { let exam: Exam; const examTitle = 'exam' + generateUUID(); @@ -107,7 +107,6 @@ test.describe('Exam participation', { tag: '@slow' }, () => { await examParticipation.startParticipation(studentFour, course, exam); for (let j = 0; j < exerciseArray.length; j++) { const exercise = exerciseArray[j]; - // await await examNavigation.openFromOverviewByTitle(exercise.exerciseGroup!.title!); await examNavigation.openOverview(); } @@ -118,7 +117,7 @@ test.describe('Exam participation', { tag: '@slow' }, () => { }); }); - test.describe('Early hand-in with continue and reload page', () => { + test.describe('Early hand-in with continue and reload page', { tag: '@slow' }, () => { let exam: Exam; const examTitle = 'exam' + generateUUID(); @@ -222,7 +221,7 @@ test.describe('Exam participation', { tag: '@slow' }, () => { }); }); - test.describe('Normal Hand-in', () => { + test.describe('Normal Hand-in', { tag: '@sequential' }, () => { let exam: Exam; const examTitle = 'exam' + generateUUID(); @@ -259,7 +258,7 @@ test.describe('Exam participation', { tag: '@slow' }, () => { }); }); - test.describe('Exam announcements', () => { + test.describe('Exam announcements', { tag: '@slow' }, () => { let exam: Exam; const students = [studentOne, studentTwo]; diff --git a/src/test/playwright/e2e/exam/ExamResults.spec.ts b/src/test/playwright/e2e/exam/ExamResults.spec.ts index ddd83eb0711b..4b57dfc2e196 100644 --- a/src/test/playwright/e2e/exam/ExamResults.spec.ts +++ b/src/test/playwright/e2e/exam/ExamResults.spec.ts @@ -15,7 +15,7 @@ import { ProgrammingExerciseTaskStatus } from '../../support/pageobjects/exam/Ex import { Page } from '@playwright/test'; import { StudentExam } from 'app/entities/student-exam.model'; -test.describe('Exam Results', { tag: '@slow' }, () => { +test.describe('Exam Results', () => { let course: Course; test.beforeEach('Create course', async ({ browser }) => { @@ -126,44 +126,48 @@ test.describe('Exam Results', { tag: '@slow' }, () => { }, ); - test(`Check exam ${exerciseTypeString} exercise results`, async ({ page, login, examParticipation, examResultsPage }) => { - await login(studentOne); - await waitForExamEnd(examEndDate, page); - await page.goto(`/courses/${course.id}/exams/${exam.id}`); - await examParticipation.checkResultScore(testCase.resultScore, exercise.id!); + test( + `Check exam ${exerciseTypeString} exercise results`, + { tag: testCase.exerciseType === ExerciseType.PROGRAMMING ? '@sequential' : '@slow' }, + async ({ page, login, examParticipation, examResultsPage }) => { + await login(studentOne); + await waitForExamEnd(examEndDate, page); + await page.goto(`/courses/${course.id}/exams/${exam.id}`); + await examParticipation.checkResultScore(testCase.resultScore, exercise.id!); - switch (testCase.exerciseType) { - case ExerciseType.TEXT: - await examResultsPage.checkTextExerciseContent(exercise.id!, exercise.additionalData!.textFixture!); - await examResultsPage.checkAdditionalFeedback(exercise.id!, 7, 'Good job'); - break; - case ExerciseType.PROGRAMMING: - await examResultsPage.checkProgrammingExerciseAssessments(exercise.id!, 'Wrong', 7); - await examResultsPage.checkProgrammingExerciseAssessments(exercise.id!, 'Correct', 6); - const taskStatuses: ProgrammingExerciseTaskStatus[] = [ - ProgrammingExerciseTaskStatus.SUCCESS, - ProgrammingExerciseTaskStatus.SUCCESS, - ProgrammingExerciseTaskStatus.SUCCESS, - ProgrammingExerciseTaskStatus.FAILURE, - ProgrammingExerciseTaskStatus.FAILURE, - ProgrammingExerciseTaskStatus.FAILURE, - ProgrammingExerciseTaskStatus.FAILURE, - ]; - await examResultsPage.checkProgrammingExerciseTasks(exercise.id!, taskStatuses); - break; - case ExerciseType.QUIZ: - await examResultsPage.checkQuizExerciseScore(exercise.id!, 5, 10); - const studentAnswers = [true, false, true, false]; - const correctAnswers = [true, true, false, false]; - await examResultsPage.checkQuizExerciseAnswers(exercise.id!, studentAnswers, correctAnswers); - break; - case ExerciseType.MODELING: - await examResultsPage.checkAdditionalFeedback(exercise.id!, 5, 'Good'); - await examResultsPage.checkModellingExerciseAssessment(exercise.id!, 'class Class', 'Wrong', -1); - await examResultsPage.checkModellingExerciseAssessment(exercise.id!, 'abstract class Abstract', 'Neutral', 0); - break; - } - }); + switch (testCase.exerciseType) { + case ExerciseType.TEXT: + await examResultsPage.checkTextExerciseContent(exercise.id!, exercise.additionalData!.textFixture!); + await examResultsPage.checkAdditionalFeedback(exercise.id!, 7, 'Good job'); + break; + case ExerciseType.PROGRAMMING: + await examResultsPage.checkProgrammingExerciseAssessments(exercise.id!, 'Wrong', 7); + await examResultsPage.checkProgrammingExerciseAssessments(exercise.id!, 'Correct', 6); + const taskStatuses: ProgrammingExerciseTaskStatus[] = [ + ProgrammingExerciseTaskStatus.SUCCESS, + ProgrammingExerciseTaskStatus.SUCCESS, + ProgrammingExerciseTaskStatus.SUCCESS, + ProgrammingExerciseTaskStatus.FAILURE, + ProgrammingExerciseTaskStatus.FAILURE, + ProgrammingExerciseTaskStatus.FAILURE, + ProgrammingExerciseTaskStatus.FAILURE, + ]; + await examResultsPage.checkProgrammingExerciseTasks(exercise.id!, taskStatuses); + break; + case ExerciseType.QUIZ: + await examResultsPage.checkQuizExerciseScore(exercise.id!, 5, 10); + const studentAnswers = [true, false, true, false]; + const correctAnswers = [true, true, false, false]; + await examResultsPage.checkQuizExerciseAnswers(exercise.id!, studentAnswers, correctAnswers); + break; + case ExerciseType.MODELING: + await examResultsPage.checkAdditionalFeedback(exercise.id!, 5, 'Good'); + await examResultsPage.checkModellingExerciseAssessment(exercise.id!, 'class Class', 'Wrong', -1); + await examResultsPage.checkModellingExerciseAssessment(exercise.id!, 'abstract class Abstract', 'Neutral', 0); + break; + } + }, + ); if (testCase.exerciseType === ExerciseType.TEXT) { test('Check exam result overview', async ({ page, login, examAPIRequests, examResultsPage }) => { diff --git a/src/test/playwright/e2e/exam/ExamTestRun.spec.ts b/src/test/playwright/e2e/exam/ExamTestRun.spec.ts index af71769e8c3a..7b15b93ebc5f 100644 --- a/src/test/playwright/e2e/exam/ExamTestRun.spec.ts +++ b/src/test/playwright/e2e/exam/ExamTestRun.spec.ts @@ -15,7 +15,7 @@ import { expect } from '@playwright/test'; const textFixture = 'loremIpsum-short.txt'; const examTitle = 'exam' + generateUUID(); -test.describe('Exam test run', { tag: '@slow' }, () => { +test.describe('Exam test run', { tag: '@fast' }, () => { let course: Course; let exam: Exam; let exerciseArray: Array = []; diff --git a/src/test/playwright/e2e/exam/test-exam/TestExamCreationDeletion.spec.ts b/src/test/playwright/e2e/exam/test-exam/TestExamCreationDeletion.spec.ts index f122da826785..c60d95177283 100644 --- a/src/test/playwright/e2e/exam/test-exam/TestExamCreationDeletion.spec.ts +++ b/src/test/playwright/e2e/exam/test-exam/TestExamCreationDeletion.spec.ts @@ -23,7 +23,7 @@ const examData = { confirmationEndText: 'Exam confirmation end text', }; -test.describe('Test Exam creation/deletion', { tag: '@slow' }, () => { +test.describe('Test Exam creation/deletion', { tag: '@fast' }, () => { let course: Course; let exam: Exam; diff --git a/src/test/playwright/e2e/exam/test-exam/TestExamManagement.spec.ts b/src/test/playwright/e2e/exam/test-exam/TestExamManagement.spec.ts index 02e1e79fae0c..0b9ec4e08385 100644 --- a/src/test/playwright/e2e/exam/test-exam/TestExamManagement.spec.ts +++ b/src/test/playwright/e2e/exam/test-exam/TestExamManagement.spec.ts @@ -11,7 +11,7 @@ import { expect } from '@playwright/test'; const uid = generateUUID(); const examTitle = 'test-exam' + uid; -test.describe('Test Exam management', { tag: '@slow' }, () => { +test.describe('Test Exam management', { tag: '@fast' }, () => { let course: Course; let exam: Exam; diff --git a/src/test/playwright/e2e/exercise/ExerciseImport.spec.ts b/src/test/playwright/e2e/exercise/ExerciseImport.spec.ts index f74ebf23a9fb..d54c4f4268db 100644 --- a/src/test/playwright/e2e/exercise/ExerciseImport.spec.ts +++ b/src/test/playwright/e2e/exercise/ExerciseImport.spec.ts @@ -17,7 +17,7 @@ import { TextSubmission } from 'app/entities/text/text-submission.model'; import { QuizSubmission } from 'app/entities/quiz/quiz-submission.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; -test.describe('Import exercises', { tag: '@slow' }, () => { +test.describe('Import exercises', () => { let course: Course; let secondCourse: Course; let textExercise: TextExercise; @@ -39,7 +39,7 @@ test.describe('Import exercises', { tag: '@slow' }, () => { }); test.describe('Imports exercises', () => { - test('Imports text exercise', async ({ login, page, courseManagementExercises, textExerciseCreation, courseOverview, textExerciseEditor }) => { + test('Imports text exercise', { tag: '@fast' }, async ({ login, page, courseManagementExercises, textExerciseCreation, courseOverview, textExerciseEditor }) => { await login(instructor, `/course-management/${secondCourse.id}/exercises`); await courseManagementExercises.importTextExercise(); await courseManagementExercises.clickImportExercise(textExercise.id!); @@ -69,7 +69,7 @@ test.describe('Import exercises', { tag: '@slow' }, () => { expect(submissionResponse.status()).toBe(200); }); - test('Imports quiz exercise', async ({ login, page, courseManagementExercises, quizExerciseCreation, courseOverview, quizExerciseMultipleChoice }) => { + test('Imports quiz exercise', { tag: '@fast' }, async ({ login, page, courseManagementExercises, quizExerciseCreation, courseOverview, quizExerciseMultipleChoice }) => { await login(instructor, `/course-management/${secondCourse.id}/exercises`); await courseManagementExercises.importQuizExercise(); await courseManagementExercises.clickImportExercise(quizExercise.id!); @@ -92,54 +92,62 @@ test.describe('Import exercises', { tag: '@slow' }, () => { expect(submitResponse.status()).toBe(200); }); - test('Imports modeling exercise', async ({ login, page, courseManagementExercises, modelingExerciseCreation, courseOverview, modelingExerciseEditor }) => { - await login(instructor, `/course-management/${secondCourse.id}/exercises`); - await courseManagementExercises.importModelingExercise(); - await courseManagementExercises.clickImportExercise(modelingExercise.id!); - - await page.waitForTimeout(10000); - await expect(page.locator('#field_title')).toHaveValue(modelingExercise.title!); - await expect(page.locator('#field_points')).toHaveValue(`${modelingExercise.maxPoints!}`); - - await modelingExerciseCreation.setReleaseDate(dayjs()); - await modelingExerciseCreation.setDueDate(dayjs().add(1, 'days')); - await modelingExerciseCreation.setAssessmentDueDate(dayjs().add(2, 'days')); - - const importResponse = await modelingExerciseCreation.import(); - const exercise: ModelingExercise = await importResponse.json(); - await login(studentOne, `/courses/${secondCourse.id}/exercises/${exercise.id}`); - await courseOverview.startExercise(exercise.id!); - await courseOverview.openRunningExercise(exercise.id!); - await modelingExerciseEditor.addComponentToModel(exercise.id!, 1); - await modelingExerciseEditor.addComponentToModel(exercise.id!, 2); - await modelingExerciseEditor.addComponentToModel(exercise.id!, 3); - const submitResponse = await modelingExerciseEditor.submit(); - const submission: ModelingSubmission = await submitResponse.json(); - expect(submission.submitted).toBe(true); - expect(submitResponse.status()).toBe(200); - }); - - test('Imports programming exercise', async ({ login, page, courseManagementExercises, programmingExerciseCreation, courseOverview, programmingExerciseEditor }) => { - await login(instructor, `/course-management/${secondCourse.id}/exercises`); - await courseManagementExercises.importProgrammingExercise(); - await courseManagementExercises.clickImportExercise(programmingExercise.id!); - - await expect(page.locator('#field_points')).toHaveValue(`${programmingExercise.maxPoints!}`); - - await programmingExerciseCreation.setTitle('Import Test'); - await programmingExerciseCreation.setShortName('importtest' + generateUUID()); - await programmingExerciseCreation.setDueDate(dayjs().add(3, 'days')); - - const importResponse = await programmingExerciseCreation.import(); - const exercise: ProgrammingExercise = await importResponse.json(); - await login(studentOne, `/courses/${secondCourse.id}/exercises/${exercise.id}`); - await courseOverview.startExercise(exercise.id!); - await courseOverview.openRunningExercise(exercise.id!); - await programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, javaPartiallySuccessfulSubmission, async () => { - const resultScore = await programmingExerciseEditor.getResultScore(); - await expect(resultScore.getByText(javaPartiallySuccessfulSubmission.expectedResult)).toBeVisible(); - }); - }); + test( + 'Imports modeling exercise', + { tag: '@fast' }, + async ({ login, page, courseManagementExercises, modelingExerciseCreation, courseOverview, modelingExerciseEditor }) => { + await login(instructor, `/course-management/${secondCourse.id}/exercises`); + await courseManagementExercises.importModelingExercise(); + await courseManagementExercises.clickImportExercise(modelingExercise.id!); + + await page.waitForTimeout(10000); + await expect(page.locator('#field_title')).toHaveValue(modelingExercise.title!); + await expect(page.locator('#field_points')).toHaveValue(`${modelingExercise.maxPoints!}`); + + await modelingExerciseCreation.setReleaseDate(dayjs()); + await modelingExerciseCreation.setDueDate(dayjs().add(1, 'days')); + await modelingExerciseCreation.setAssessmentDueDate(dayjs().add(2, 'days')); + + const importResponse = await modelingExerciseCreation.import(); + const exercise: ModelingExercise = await importResponse.json(); + await login(studentOne, `/courses/${secondCourse.id}/exercises/${exercise.id}`); + await courseOverview.startExercise(exercise.id!); + await courseOverview.openRunningExercise(exercise.id!); + await modelingExerciseEditor.addComponentToModel(exercise.id!, 1); + await modelingExerciseEditor.addComponentToModel(exercise.id!, 2); + await modelingExerciseEditor.addComponentToModel(exercise.id!, 3); + const submitResponse = await modelingExerciseEditor.submit(); + const submission: ModelingSubmission = await submitResponse.json(); + expect(submission.submitted).toBe(true); + expect(submitResponse.status()).toBe(200); + }, + ); + + test( + 'Imports programming exercise', + { tag: '@sequential' }, + async ({ login, page, courseManagementExercises, programmingExerciseCreation, courseOverview, programmingExerciseEditor }) => { + await login(instructor, `/course-management/${secondCourse.id}/exercises`); + await courseManagementExercises.importProgrammingExercise(); + await courseManagementExercises.clickImportExercise(programmingExercise.id!); + + await expect(page.locator('#field_points')).toHaveValue(`${programmingExercise.maxPoints!}`); + + await programmingExerciseCreation.setTitle('Import Test'); + await programmingExerciseCreation.setShortName('importtest' + generateUUID()); + await programmingExerciseCreation.setDueDate(dayjs().add(3, 'days')); + + const importResponse = await programmingExerciseCreation.import(); + const exercise: ProgrammingExercise = await importResponse.json(); + await login(studentOne, `/courses/${secondCourse.id}/exercises/${exercise.id}`); + await courseOverview.startExercise(exercise.id!); + await courseOverview.openRunningExercise(exercise.id!); + await programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, javaPartiallySuccessfulSubmission, async () => { + const resultScore = await programmingExerciseEditor.getResultScore(); + await expect(resultScore.getByText(javaPartiallySuccessfulSubmission.expectedResult)).toBeVisible(); + }); + }, + ); }); test.afterEach('Delete Courses', async ({ courseManagementAPIRequests }) => { diff --git a/src/test/playwright/e2e/exercise/modeling/ModelingExerciseParticipation.spec.ts b/src/test/playwright/e2e/exercise/modeling/ModelingExerciseParticipation.spec.ts index aa45325d5ab4..c51fe9fc3f76 100644 --- a/src/test/playwright/e2e/exercise/modeling/ModelingExerciseParticipation.spec.ts +++ b/src/test/playwright/e2e/exercise/modeling/ModelingExerciseParticipation.spec.ts @@ -4,7 +4,7 @@ import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { admin, studentOne } from '../../../support/users'; import { test } from '../../../support/fixtures'; -test.describe('Modeling Exercise Participation', { tag: '@slow' }, () => { +test.describe('Modeling Exercise Participation', { tag: '@fast' }, () => { let course: Course; let modelingExercise: ModelingExercise; diff --git a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseAssessment.spec.ts b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseAssessment.spec.ts index d4575589cf42..0299bd423774 100644 --- a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseAssessment.spec.ts +++ b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseAssessment.spec.ts @@ -17,7 +17,7 @@ const tutorCodeFeedback = 'The input parameter should be mentioned in javadoc!'; const tutorCodeFeedbackPoints = -2; const complaint = "That feedback wasn't very useful!"; -test.describe('Programming exercise assessment', { tag: '@slow' }, () => { +test.describe('Programming exercise assessment', { tag: '@sequential' }, () => { let course: Course; let exercise: ProgrammingExercise; let dueDate: dayjs.Dayjs; diff --git a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseManagement.spec.ts b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseManagement.spec.ts index 695848b99d4d..aa8d06f10c7b 100644 --- a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseManagement.spec.ts +++ b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseManagement.spec.ts @@ -7,7 +7,7 @@ import { generateUUID } from '../../../support/utils'; import { expect } from '@playwright/test'; import { Exercise, ExerciseMode } from '../../../support/constants'; -test.describe('Programming Exercise Management', { tag: '@slow' }, () => { +test.describe('Programming Exercise Management', { tag: '@fast' }, () => { let course: Course; test.beforeEach('Create course', async ({ login, courseManagementAPIRequests }) => { diff --git a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts index b6a38b85fbf7..cd28fe48b5b0 100644 --- a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts +++ b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts @@ -20,7 +20,7 @@ import { Team } from 'app/entities/team.model'; import { ProgrammingExerciseOverviewPage } from '../../../support/pageobjects/exercises/programming/ProgrammingExerciseOverviewPage'; import { Participation } from 'app/entities/participation/participation.model'; -test.describe('Programming exercise participation', { tag: '@slow' }, () => { +test.describe('Programming exercise participation', { tag: '@sequential' }, () => { let course: Course; test.beforeEach('Create course', async ({ login, courseManagementAPIRequests }) => { diff --git a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts index e5cc38f72fbf..a5da3a899584 100644 --- a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts +++ b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts @@ -6,7 +6,7 @@ import { admin, studentOne } from '../../../support/users'; import { test } from '../../../support/fixtures'; import { expect } from '@playwright/test'; -test.describe('Static code analysis tests', { tag: '@slow' }, () => { +test.describe('Static code analysis tests', { tag: '@sequential' }, () => { let course: Course; let exercise: ProgrammingExercise; diff --git a/src/test/playwright/e2e/exercise/quiz-exercise/QuizExerciseAssessment.spec.ts b/src/test/playwright/e2e/exercise/quiz-exercise/QuizExerciseAssessment.spec.ts index 72f654f07575..594169db22ec 100644 --- a/src/test/playwright/e2e/exercise/quiz-exercise/QuizExerciseAssessment.spec.ts +++ b/src/test/playwright/e2e/exercise/quiz-exercise/QuizExerciseAssessment.spec.ts @@ -4,7 +4,7 @@ import shortAnswerQuizTemplate from '../../../fixtures/exercise/quiz/short_answe import { admin, studentOne, tutor } from '../../../support/users'; import { test } from '../../../support/fixtures'; -test.describe('Quiz Exercise Assessment', { tag: '@slow' }, () => { +test.describe('Quiz Exercise Assessment', { tag: '@fast' }, () => { let course: Course; test.beforeEach('Create course', async ({ login, courseManagementAPIRequests }) => { diff --git a/src/test/playwright/package.json b/src/test/playwright/package.json index 6721f5a919a0..f3161e557b77 100644 --- a/src/test/playwright/package.json +++ b/src/test/playwright/package.json @@ -15,12 +15,12 @@ "uuid": "11.0.3" }, "scripts": { - "playwright:test": "npm-run-all --serial --continue-on-error playwright:test:fast playwright:test:slow merge-reports", - "playwright:test:fast": "cross-env PLAYWRIGHT_JUNIT_OUTPUT_NAME=./test-reports/results-fast.xml playwright test e2e --project=fast-tests", - "playwright:test:slow": "cross-env PLAYWRIGHT_JUNIT_OUTPUT_NAME=./test-reports/results-slow.xml playwright test e2e --project=slow-tests --workers 1", + "playwright:test": "npm-run-all --serial --continue-on-error playwright:test:parallel playwright:test:sequential merge-reports", + "playwright:test:parallel": "cross-env PLAYWRIGHT_JUNIT_OUTPUT_NAME=./test-reports/results-parallel.xml playwright test e2e --project=fast-tests --project=slow-tests", + "playwright:test:sequential": "cross-env PLAYWRIGHT_JUNIT_OUTPUT_NAME=./test-reports/results-sequential.xml playwright test e2e --project=sequential-tests --workers 1", "playwright:open": "playwright test e2e --ui", "playwright:setup": "npx playwright install --with-deps chromium && playwright test init", - "merge-reports": "junit-merge ./test-reports/results-fast.xml ./test-reports/results-slow.xml -o ./test-reports/results.xml", + "merge-reports": "junit-merge ./test-reports/results-parallel.xml ./test-reports/results-sequential.xml -o ./test-reports/results.xml", "update": "ncu -i --format group" } } diff --git a/src/test/playwright/playwright.config.ts b/src/test/playwright/playwright.config.ts index 2e64acd023b8..a963e42fadcb 100644 --- a/src/test/playwright/playwright.config.ts +++ b/src/test/playwright/playwright.config.ts @@ -32,18 +32,28 @@ export default defineConfig({ /* Configure projects for fast and slow tests */ projects: [ - // Tests with @slow tag + // Tests with @fast tag or without any tags. These are the lightweight tests with lower timeout. + { + name: 'fast-tests', + grep: /@fast|^[^@]*$/, + timeout: (parseNumber(process.env.FAST_TEST_TIMEOUT_SECONDS) ?? 45) * 1000, + use: { ...devices['Desktop Chrome'] }, + }, + // Tests with @slow tag. These tests are expected to run longer + // than faster tests and have higher timeout. { name: 'slow-tests', grep: /@slow/, timeout: (parseNumber(process.env.SLOW_TEST_TIMEOUT_SECONDS) ?? 180) * 1000, use: { ...devices['Desktop Chrome'] }, }, - // Tests with @fast tag or without any tags + // Tests with @sequential tag. These tests are triggering programming exercise submissions. + // Running only one programming exercise evaluation at a time could make the tests more stable. + // Thus, it is recommended to run this project with a single worker. { - name: 'fast-tests', - grep: /@fast|^[^@]*$/, - timeout: (parseNumber(process.env.FAST_TEST_TIMEOUT_SECONDS) ?? 45) * 1000, + name: 'sequential-tests', + grep: /@sequential/, + timeout: (parseNumber(process.env.SLOW_TEST_TIMEOUT_SECONDS) ?? 180) * 1000, use: { ...devices['Desktop Chrome'] }, }, ],