[Playwright] Remove cypress files from e2e

This commit is contained in:
Aaro Koivukangas
2026-08-09 01:48:41 +03:00
committed by Aaro Koivukangas
parent 24a6522757
commit 91ae0f37a3
10 changed files with 0 additions and 2832 deletions
File diff suppressed because it is too large Load Diff
-165
View File
@@ -1,165 +0,0 @@
import { test, expect } from '@playwright/test'
/// <reference types="cypress" />
const fillName = async page => {
const name = `TEST-${new Date().getTime()}`
cy.contains('Insert a name for this custom population if you wish to save it')
cy.cs('custom-population-name-input').type(name)
return name
}
const save = async page => {
cy.get('button').contains('Save').click()
}
const selectSavedPopulation = async (page, name) => {
cy.cs('history-search').type(`${name}{enter}`)
}
const deleteAllSearches = async page => {
cy.cs('history-search').click()
cy.get('.MuiAutocomplete-popper > .MuiPaper-root')
.find('li[role=option]')
.then($lis => {
const labels = [...$lis].map(li => li.textContent?.trim() || '')
labels.forEach((label, index) => {
if (index !== 0) cy.cs('history-search').click()
page.locator('text=.MuiAutocomplete-popper li[role=option]', label).click()
page.locator('text=button', 'text=Delete').click()
})
})
}
const fillForm = async (page, content, separator) => {
cy.cs('student-number-input').type(content.join(separator))
}
const search = async page => {
cy.cs('search-button').click()
}
const searchFor = (studentnumbers, separator) => {
fillForm(page)
search(page)
}
const hasLanded = async page => {
cy.contains('Credit accumulation')
cy.contains('Programme distribution')
cy.contains('Courses of population')
cy.contains('Students')
}
const containsAmountOfStudents = async (page, amount = 0) => {
cy.contains(`Credit accumulation (for ${amount} students)`)
}
const containsSpecificStudents = async (page, studentnumbers = []) => {
cy.contains(`Students (${studentnumbers.length})`)
.parent()
.then($parentDiv => {
if (!$parentDiv.hasClass('active')) page.locator(`Students (${studentnumbers.length})`).click()
})
studentnumbers.forEach(s => cy.contains(s))
}
const checkRightsNotification = async (page, studentNumbers) => {
cy.cs('rights-notification').within(() => {
cy.contains(
'The following students information could not be displayed. This could be either because they do not exist, or you do not have the right to view their information.'
)
cy.get('ul').within(() => {
studentNumbers.forEach(number => cy.get('li').contains(number))
})
})
}
test.describe('Custom population tests', () => {
const nonExistentStudentNumbers = ['123', 'X', '-']
test.beforeEach(async ({ page }) => {
cy.init('/custompopulation')
cy.url().should('include', '/custompopulation')
cy.contains('Custom population')
})
test.afterAll(() => {
page.goto('/custompopulation')
cy.url().should('include', '/custompopulation')
cy.contains('Custom population')
deleteAllSearches(page)
})
test.describe('Custom population searching', () => {
test('Finds a proper population', async ({ page }) => {
cy.fixture('customPopulations').then(({ studentNumbersForCSStudentsSet1: students }) => {
searchFor(students, '\n')
hasLanded(page)
containsAmountOfStudents(page)
containsSpecificStudents(page)
})
})
test("Doesn't return non-existing students", async ({ page }) => {
cy.fixture('customPopulations').then(({ studentNumbersForCSStudentsSet1: students }) => {
searchFor([...students, ...nonExistentStudentNumbers], ' ')
hasLanded(page)
containsAmountOfStudents(page)
containsSpecificStudents(page)
checkRightsNotification(page)
})
})
test("Doesn't find empty custom population", async ({ page }) => {
searchFor(nonExistentStudentNumbers, ',')
checkRightsNotification(page)
cy.contains('Credit accumulation').should('not.exist')
cy.contains('Programme distribution').should('not.exist')
cy.contains('Courses of population').should('not.exist')
cy.get('button').contains('Back to search form')
})
test("Doesn't return students user has no right to", async ({ page }) => {
// These students exist in the database, but the user doesn't have the right to view them
const studentsForEduBachStudents = ['014990067', '013069465', '014853890']
// Two semicolons on purpose, the page should be able to handle it
searchFor(studentsForEduBachStudents, ';;')
checkRightsNotification(page)
cy.contains('Credit accumulation').should('not.exist')
cy.contains('Programme distribution').should('not.exist')
cy.contains('Courses of population').should('not.exist')
cy.get('button').contains('Back to search form')
})
})
test.describe('Custom population search saving', () => {
test('Saves a custom population search', async ({ page }) => {
cy.fixture('customPopulations').then(({ studentNumbersForCSStudentsSet1: students }) => {
cy.contains(
'Insert student numbers to use for the population. Each student number needs to be separated with a comma, a semicolon, a space, or a line break.'
)
const name = fillName()
fillForm(page)
save(page)
selectSavedPopulation(page)
search(page)
cy.contains(`Custom population: ${name}`)
containsAmountOfStudents(page)
containsSpecificStudents(page)
page.goto('/custompopulation')
cy.contains('Custom population')
selectSavedPopulation(page)
search(page)
cy.contains(`Custom population: ${name}`)
containsAmountOfStudents(page)
containsSpecificStudents(page)
})
})
test('Updates a custom population search', async ({ page }) => {
cy.fixture('customPopulations').then(
({ studentNumbersForCSStudentsSet1: students1, studentNumbersForCSStudentsSet2: students2 }) => {
const name = fillName()
fillForm(page)
save(page)
selectSavedPopulation(page)
search(page)
cy.contains(`Custom population: ${name}`)
containsAmountOfStudents(page)
containsSpecificStudents(page)
page.locator('text=Back to search form').click()
selectSavedPopulation(page)
fillForm(page)
save(page)
page.goto('/custompopulation')
cy.contains('Custom population')
selectSavedPopulation(page)
search(page)
cy.contains(`Custom population: ${name}`)
containsAmountOfStudents(page)
containsSpecificStudents(page)
}
)
})
})
})
-247
View File
@@ -1,247 +0,0 @@
import { test, expect } from '@playwright/test'
/// <reference types="cypress" />
const path = require('path')
const timestamp = new Date().toLocaleDateString('en-CA', { year: 'numeric', month: '2-digit', day: '2-digit' }) // YYYY-MM-DD, taking the local time zone into account
const downloadsFolder = '/tmp/cypress/downloads'
test.describe('Faculty statistics', () => {
test.describe('Faculty list', () => {
test.beforeEach(async ({ page }) => {
cy.init('/faculties')
})
test('contains faculty names and faculty codes', async ({ page }) => {
cy.contains('Faculties')
cy.contains('Teologinen tiedekunta')
cy.contains('H10')
cy.contains('Oikeustieteellinen tiedekunta')
cy.contains('H20')
cy.contains('Lääketieteellinen tiedekunta')
cy.contains('H30')
cy.contains('Humanistinen tiedekunta')
cy.contains('H40')
cy.contains('Matemaattis-luonnontieteellinen tiedekunta')
cy.contains('H50')
cy.contains('Farmasian tiedekunta')
cy.contains('H55')
cy.contains('Bio- ja ympäristötieteellinen tiedekunta')
cy.contains('H57')
cy.contains('Kasvatustieteellinen tiedekunta')
cy.contains('H60')
cy.contains('Valtiotieteellinen tiedekunta')
cy.contains('H70')
cy.contains('Svenska social- och kommunalhögskolan')
cy.contains('H74')
cy.contains('Maatalous-metsätieteellinen tiedekunta')
cy.contains('H80')
cy.contains('Eläinlääketieteellinen tiedekunta')
cy.contains('H90')
})
test('contains a working link to faculty page', async ({ page }) => {
cy.contains('Faculties')
page.locator('text=a', 'text=Teologinen tiedekunta').click()
cy.location('pathname').should('eq', '/faculties/hy-org-1000000580')
cy.contains('Teologinen tiedekunta')
cy.contains('H10')
})
})
test.describe('Basic information tab', () => {
test.describe('Admin user', () => {
test.beforeEach(async ({ page }) => {
cy.init('/faculties', 'admin')
page.locator('text=a', 'text=El\u00E4inl\u00E4\u00E4ketieteellinen tiedekunta').click()
})
test('Correct tabs are shown', async ({ page }) => {
cy.cs('faculty-tabs').should('contain', 'Basic information')
cy.cs('faculty-tabs').should('contain', 'Students by starting year')
cy.cs('faculty-tabs').should('contain', 'Graduation times')
cy.cs('faculty-tabs').should('contain', 'Update statistics')
})
})
test.describe('Basic user', () => {
test.beforeEach(async ({ page }) => {
cy.init('/faculties')
page.locator('text=a', 'text=Matemaattis-luonnontieteellinen tiedekunta').click()
})
test.describe('Info boxes', () => {
test('Students of the faculty', async ({ page }) => {
cy.cs('students-of-the-faculty-info-box-button').click()
cy.cs('students-of-the-faculty-info-box-content').contains('Taulukon luvut on')
})
test('Graduated of the faculty', async ({ page }) => {
cy.cs('graduated-of-the-faculty-info-box-button').click()
cy.cs('graduated-of-the-faculty-info-box-content').contains('Sisältää kyseisenä')
})
test('Thesis writers of the faculty', async ({ page }) => {
cy.cs('thesis-writers-of-the-faculty-info-box-button').click()
cy.cs('thesis-writers-of-the-faculty-info-box-content').contains('Sisältää kyseisenä')
})
test('Credits produced by the faculty', async ({ page }) => {
cy.cs('credits-produced-by-the-faculty-info-box-button').click()
cy.cs('credits-produced-by-the-faculty-info-box-content').contains('Sisältää opintopisteet')
})
})
test('All graphs and tables are shown', async ({ page }) => {
cy.cs('students-of-the-faculty-line-graph-section').should('be.visible')
cy.cs('students-of-the-faculty-interactive-data-table').should('be.visible')
cy.cs('graduated-of-the-faculty-line-graph-section').should('be.visible')
cy.cs('graduated-of-the-faculty-interactive-data-table').should('be.visible')
cy.cs('thesis-writers-of-the-faculty-line-graph-section').should('be.visible')
cy.cs('thesis-writers-of-the-faculty-interactive-data-table').should('be.visible')
cy.cs('credits-produced-by-the-faculty-stacked-bar-chart-section').should('be.visible')
cy.cs('credits-produced-by-the-faculty-interactive-data-table').should('be.visible')
})
test('Correct tabs are shown', async ({ page }) => {
cy.cs('faculty-tabs').should('contain', 'Basic information')
cy.cs('faculty-tabs').should('contain', 'Students by starting year')
cy.cs('faculty-tabs').should('contain', 'Graduation times')
cy.cs('faculty-tabs').should('not.contain', 'Update statistics')
})
test('Toggle years works', async ({ page }) => {
cy.cs('credits-produced-by-the-faculty-interactive-data-table').should('contain', '2022 - 2023')
cy.cs('thesis-writers-of-the-faculty-interactive-data-table').should('contain', '2022 - 2023')
cy.cs('students-of-the-faculty-interactive-data-table').should('contain', '2022 - 2023')
cy.cs('graduated-of-the-faculty-interactive-data-table').should('contain', '2022 - 2023')
cy.cs('year-toggle').click()
cy.cs('credits-produced-by-the-faculty-interactive-data-table').should('contain', '2022')
cy.cs('thesis-writers-of-the-faculty-interactive-data-table').should('contain', '2022')
cy.cs('students-of-the-faculty-interactive-data-table').should('contain', '2022')
cy.cs('graduated-of-the-faculty-interactive-data-table').should('contain', '2022')
})
test('Toggle programmes works', async ({ page }) => {
cy.cs('faculty-programmes-shown-info').should('not.exist')
cy.cs('programme-toggle').click()
cy.cs('faculty-programmes-shown-info').should('be.visible')
})
test('Toggle study rights works', async ({ page }) => {
cy.cs('faculty-exclude-specials-info').should('not.exist')
cy.cs('study-right-toggle').click()
cy.cs('faculty-exclude-specials-info').should('be.visible')
})
test.skip('Data can be exported to Excel files', async ({ page }) => {
// TODO: Fix this test
const sections = [
'StudentsOfTheFaculty',
'GraduatedOfTheFaculty',
'ThesisWritersOfTheFaculty',
'CreditsProducedByTheFaculty',
]
sections.forEach(section => {
cy.cs(`${section}Graph`).within(() => {
page.locator('[aria-label="View chart menu, Chart"]').click({ force: true })
page.locator('text=li.highcharts-menu-item', 'text=Download XLS').click()
const downloadedFile = `oodikone_${section}_H50_${timestamp}.xls`
cy.readFile(path.join(downloadsFolder, downloadedFile))
})
})
})
})
})
test.describe('Students by starting year tab', () => {
test.beforeEach(async ({ page }) => {
cy.init('/faculties')
page.locator('text=a', 'text=Matemaattis-luonnontieteellinen tiedekunta').click()
page.locator('text=Students by starting year').click()
})
test('Export button', async ({ page }) => {
cy.cs('faculty-student-table-export-button').should('be.visible').and('not.be.disabled').click()
const downloadedFile = `oodikone_H50_programme_stats_${timestamp}.xlsx`
cy.readFile(path.join(downloadsFolder, downloadedFile))
})
test('Info box', async ({ page }) => {
cy.cs('faculty-student-table-info-box-button').click()
cy.cs('faculty-student-table-info-box-content').contains('Opiskelijat, joiden')
})
test.skip('Study right toggle', async ({ page }) => {
// TODO: Implement
})
test.skip('Graduated toggle', async ({ page }) => {
// TODO: Implement
})
test.skip('Hoverable country list', async ({ page }) => {
// TODO: Implement
})
test.skip('Expandable rows', async ({ page }) => {
// TODO: Implement
})
test.skip('Population links', async ({ page }) => {
// TODO: Implement
})
test('Percentage toggle works', async ({ page }) => {
cy.cs('faculty-student-stats-table').should('be.visible')
cy.cs('faculty-student-stats-table').should('not.contain', '92.3 %')
cy.cs('percentage-toggle').click()
cy.cs('faculty-student-stats-table').should('contain', '92.3 %')
})
})
test.describe('Progress tab', () => {
test.beforeEach(async ({ page }) => {
cy.init('/faculties')
page.locator('text=a', 'text=Matemaattis-luonnontieteellinen tiedekunta').click()
page.locator('text=Progress').click()
})
test.skip('Export button', async ({ page }) => {
// TODO: Fix this test
cy.cs('FacultyProgress-export-button').should('be.visible').and('not.be.disabled').click()
const downloadedFile = `oodikone_H50_progress_tab_${timestamp}.xlsx`
cy.readFile(path.join(downloadsFolder, downloadedFile))
})
test.skip('Info boxes', async ({ page }) => {
cy.cs('FacultyProgress-info-box-button').click()
cy.cs('FacultyProgress-info-box-content').contains('Kuvaa tiedekuntaan')
// TODO: Click open the accordion first
cy.cs('BachelorMastersProgress-info-box-button').click()
cy.cs('BachelorMastersProgress-info-box-content').contains('The starting year is the')
})
test.skip('Progress bar charts exist', async ({ page }) => {
// TODO: Click open the accordion first
cy.cs('FacultyBachelorsProgressBarChart').should('be.visible')
cy.cs('FacultyBachelorMastersProgressBarChart').should('be.visible')
cy.cs('FacultyMastersProgressBarChart').should('be.visible')
cy.cs('FacultyBachelorsProgressBarChart').should('be.visible')
})
test.skip('Progress tables exist', async ({ page }) => {
// TODO: Click open the accordion first
cy.cs('FacultyBachelorsProgressTable').should('be.visible')
cy.cs('FacultyBachelorMasterProgressTable').should('be.visible')
cy.cs('FacultyMastersProgressTable').should('be.visible')
cy.cs('FacultyBachelorsProgressTable').should('be.visible')
})
test.skip('Graduated toggle', async ({ page }) => {
// TODO: Implement
})
test.skip('Study right toggle', async ({ page }) => {
// TODO: Implement
})
})
test.describe('Graduation times tab', () => {
test.beforeEach(async ({ page }) => {
cy.init('/faculties')
page.locator('text=a', 'text=Matemaattis-luonnontieteellinen tiedekunta').click()
page.locator('text=Graduation times').click()
})
test.skip('Export button', async ({ page }) => {
// TODO: Fix this test
cy.cs('average-graduation-times-export-button').should('be.visible').and('not.be.disabled').click()
const downloadedFile = `oodikone_H50_graduation_times_${timestamp}.xlsx`
cy.readFile(path.join(downloadsFolder, downloadedFile))
})
test('Info boxes', async ({ page }) => {
cy.cs('average-graduation-times-info-box-button').click()
cy.cs('average-graduation-times-info-box-content').contains('Opiskelijoiden keskimääräiset')
})
test.skip('Study times toggle', async ({ page }) => {
// TODO: Implement
})
test.skip('Year toggle', async ({ page }) => {
// TODO: Implement
})
test.skip('Degree programme toggle', async ({ page }) => {
// TODO: Implement
})
test('Graphs are visible', async ({ page }) => {
cy.cs('bachelor-graduation-times-section').should('be.visible')
// ! No test data for bachelor + master
cy.cs('master-graduation-times-section').should('be.visible')
cy.cs('doctor-graduation-times-section').should('be.visible')
})
})
})
-373
View File
@@ -1,373 +0,0 @@
import { test, expect } from '@playwright/test'
/// <reference types="cypress" />
const setClockToMockedDate = async page => {
const MOCKED_DATE = new Date('2024-08-30')
cy.clock(MOCKED_DATE, ['Date'])
}
const checkFilteredStudentCount = async (page, studentCount) => {
cy.contains(`Students (${studentCount})`)
}
test.describe("Population statistics with a master's programme", () => {
const pathToMathMSc2020 = '/populations?years=2020&programme=MH50_001&semesters=FALL&semesters=SPRING'
const defaultAmountOfStudents = 26
const expectedBaMaStudents = 24
const expectedMasterOnlyStudents = 2
test.beforeAll(() => cy.init(pathToMathMSc2020))
test('Study track filter works', async ({ page }) => {
cy.cs('studyTrackFilter-header').click()
cy.selectFromDropdown('studyTrackFilter', 'Matematiikka ja soveltava matematiikka (MAST-MSM)', true)
checkFilteredStudentCount(page)
cy.cs('studyTrackFilter-clear').click()
cy.cs('studyTrackFilter-header').click()
})
test('Study right type filter works', async ({ page }) => {
cy.cs('studyRightTypeFilter-header').click()
expect(page.locator('input[name="studyRightTypeFilter"][value="0"]')).toBeChecked()
page.locator('input[name="studyRightTypeFilter"][value="1"]').click()
expect(page.locator('input[name="studyRightTypeFilter"][value="1"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="studyRightTypeFilter"][value="2"]').click()
expect(page.locator('input[name="studyRightTypeFilter"][value="2"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="studyRightTypeFilter"][value="0"]').click()
expect(page.locator('input[name="studyRightTypeFilter"][value="0"]')).toBeChecked()
checkFilteredStudentCount(page)
cy.cs('studyRightTypeFilter-header').click()
})
})
test.describe.skip('Population Statistics', () => {
const pathToMathBSc2020 = '/populations?years=2020&programme=KH50_001&semesters=FALL&semesters=SPRING'
const defaultAmountOfStudents = 27
const graduated = 16
const transferred = 3
test.beforeAll(() => cy.init(pathToMathBSc2020))
test.beforeEach(async ({ page }) => setClockToMockedDate())
test.skip('Study right type filter is not visible', async ({ page }) => {
cy.contains('Study right type').should('not.exist')
})
test.skip('Transfer filter works and is set to "not transferred" by default', async ({ page }) => {
cy.cs('transferredToProgrammeFilter-filter-card').should('have.attr', 'data-active', 'true')
expect(page.locator('input[name="transferredToProgrammeFilter"][value="Not transferred"]')).toBeChecked()
checkFilteredStudentCount(page)
cy.cs('transferredToProgrammeFilter-filter-card').should('have.attr', 'data-active', 'true')
expect(page.locator('input[name="transferredToProgrammeFilter"][value="Not transferred"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="transferredToProgrammeFilter"][value="Transferred"]').click()
expect(page.locator('input[name="transferredToProgrammeFilter"][value="Transferred"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="transferredToProgrammeFilter"][value="All"]').click()
expect(page.locator('input[name="transferredToProgrammeFilter"][value="All"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="transferredToProgrammeFilter"][value="Not transferred"]').click()
expect(page.locator('input[name="transferredToProgrammeFilter"][value="Not transferred"]')).toBeChecked()
checkFilteredStudentCount(page)
})
test('Graduation filter works', async ({ page }) => {
cy.cs('graduatedFromProgrammeFilter-header').click()
page.locator('input[name="graduatedFromProgrammeFilter"][value="1"]').click()
expect(page.locator('input[name="graduatedFromProgrammeFilter"][value="1"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="graduatedFromProgrammeFilter"][value="-1"]').click()
expect(page.locator('input[name="graduatedFromProgrammeFilter"][value="-1"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="graduatedFromProgrammeFilter"][value="0"]').click()
expect(page.locator('input[name="graduatedFromProgrammeFilter"][value="0"]')).toBeChecked()
checkFilteredStudentCount(page)
cy.cs('graduatedFromProgrammeFilter-header').click()
})
test('Enrollment filter works', async ({ page }) => {
cy.cs('enrollmentStatusFilter-header').click()
cy.selectFromDropdown('enrollmentStatusFilter-status', 0)
cy.selectFromDropdown('enrollmentStatusFilter-semester', 'Syksy 2023', true)
checkFilteredStudentCount(page)
cy.cs('enrollmentStatusFilter-clear').click()
cy.cs('enrollmentStatusFilter-header').click()
checkFilteredStudentCount(page)
})
test('Credit filter works', async ({ page }) => {
cy.cs('creditsEarnedFilter-header').click()
checkFilteredStudentCount(page)
cy.setRangeSelect('creditsEarnedFilter', 50, 150, 12)
cy.cs('creditsEarnedFilter-clear').click()
cy.cs('creditsEarnedFilter-header').click()
checkFilteredStudentCount(page)
})
test('Age filter works', async ({ page }) => {
cy.cs('ageFilter-header').click()
checkFilteredStudentCount(page)
cy.setRangeSelect('ageFilter', 23, 30, 21)
cy.cs('ageFilter-clear').click()
cy.cs('ageFilter-header').click()
checkFilteredStudentCount(page)
})
test('Gender filter works', async ({ page }) => {
cy.cs('genderFilter-header').click()
cy.selectFromDropdown('genderFilter', 0)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 1)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 2)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 3)
checkFilteredStudentCount(page)
cy.cs('genderFilter-clear').click()
cy.cs('genderFilter-header').click()
checkFilteredStudentCount(page)
})
test('Starting year filter works', async ({ page }) => {
cy.cs('startYearAtUniFilter-header').click()
cy.selectFromDropdown('startYearAtUniFilter', 0)
checkFilteredStudentCount(page)
cy.selectFromDropdown('startYearAtUniFilter', 7)
checkFilteredStudentCount(page)
cy.cs('startYearAtUniFilter-clear').click()
cy.cs('startYearAtUniFilter-header').click()
checkFilteredStudentCount(page)
})
test('Admission type filter works', async ({ page }) => {
cy.cs('admissionTypeFilter-header').click()
cy.selectFromDropdown('admissionTypeFilter', 0)
checkFilteredStudentCount(page)
cy.selectFromDropdown('admissionTypeFilter', 1)
checkFilteredStudentCount(page)
cy.cs('admissionTypeFilter-clear').click()
cy.cs('admissionTypeFilter-header').click()
checkFilteredStudentCount(page)
})
test('Courses filter works', async ({ page }) => {
const courses = [
{ code: 'MAT21012', name: 'Differentiaaliyhtälöt I' },
{ code: 'MFK-M204', name: 'Matematiikkaa kaikkialla' },
]
cy.cs('courseFilter-header').click()
cy.selectFromAutocomplete('courseFilter', `${courses[0].code} - ${courses[0].name}`)
checkFilteredStudentCount(page)
cy.selectFromDropdown(`courseFilter-${courses[0].code}`, 1)
checkFilteredStudentCount(page)
cy.selectFromAutocomplete('courseFilter', `${courses[1].code} - ${courses[1].name}`)
checkFilteredStudentCount(page)
cy.selectFromDropdown(`courseFilter-${courses[1].code}`, 1)
checkFilteredStudentCount(page)
cy.cs(`courseFilter-${courses[1].code}-clear`).click()
checkFilteredStudentCount(page)
cy.cs('courseFilter-clear').click()
cy.cs('courseFilter-header').click()
checkFilteredStudentCount(page)
})
test('Filter combinations work', async ({ page }) => {
checkFilteredStudentCount(page)
cy.cs('graduatedFromProgrammeFilter-header').click()
page.locator('input[name="graduatedFromProgrammeFilter"][value="1"]').click()
expect(page.locator('input[name="graduatedFromProgrammeFilter"][value="1"]')).toBeChecked()
checkFilteredStudentCount(page)
cy.cs('ageFilter-header').click()
cy.setRangeSelect('ageFilter', 23, 30, 12)
cy.cs('graduatedFromProgrammeFilter-clear').click()
cy.cs('graduatedFromProgrammeFilter-header').click()
cy.cs('ageFilter-clear').click()
cy.cs('ageFilter-header').click()
checkFilteredStudentCount(page)
})
test('"Reset All Filters" button works', async ({ page }) => {
cy.cs('genderFilter-header').click()
cy.selectFromDropdown('genderFilter', 0)
checkFilteredStudentCount(page)
cy.cs('startYearAtUniFilter-header').click()
cy.selectFromDropdown('startYearAtUniFilter', 7)
checkFilteredStudentCount(page)
cy.cs('reset-all-filters').click()
cy.cs('genderFilter-header').click()
cy.cs('startYearAtUniFilter-header').click()
checkFilteredStudentCount(page)
})
})
test.describe('Population Statistics with Bachelor + Master', () => {
const pathToMathBSc2017 =
'/populations?years=2017&programme=KH50_001&showBachelorAndMaster=true&semesters=FALL&semesters=SPRING'
const defaultAmountOfStudents = 47
test.beforeAll(() => cy.init(pathToMathBSc2017))
test('Graduation filter works', async ({ page }) => {
cy.cs('graduatedFromProgrammeFilter-header').click()
page.locator('input[name="graduatedFromProgrammeFilter"][value="1"]').click()
expect(page.locator('input[name="graduatedFromProgrammeFilter"][value="1"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="graduatedFromProgrammeFilter"][value="2"]').click()
expect(page.locator('input[name="graduatedFromProgrammeFilter"][value="2"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="graduatedFromProgrammeFilter"][value="-1"]').click()
expect(page.locator('input[name="graduatedFromProgrammeFilter"][value="-1"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="graduatedFromProgrammeFilter"][value="-2"]').click()
expect(page.locator('input[name="graduatedFromProgrammeFilter"][value="-2"]')).toBeChecked()
checkFilteredStudentCount(page)
cy.cs('graduatedFromProgrammeFilter-clear').click()
cy.cs('graduatedFromProgrammeFilter-header').click()
checkFilteredStudentCount(page)
})
test('Study right status filter works', async ({ page }) => {
checkFilteredStudentCount(page)
cy.cs('studyRightStatusFilter-header').click()
page.locator('input[name="studyRightStatusFilter"][value="Active Bachelor study right"]').click()
expect(page.locator('input[name="studyRightStatusFilter"][value="Active Bachelor study right"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="studyRightStatusFilter"][value="Active Master study right"]').click()
expect(page.locator('input[name="studyRightStatusFilter"][value="Active Master study right"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="studyRightStatusFilter"][value="Passive Bachelor study right"]').click()
expect(page.locator('input[name="studyRightStatusFilter"][value="Passive Bachelor study right"]')).toBeChecked()
checkFilteredStudentCount(page)
page.locator('input[name="studyRightStatusFilter"][value="Passive Master study right"]').click()
expect(page.locator('input[name="studyRightStatusFilter"][value="Passive Master study right"]')).toBeChecked()
checkFilteredStudentCount(page)
cy.cs('studyRightStatusFilter-clear').click()
cy.cs('studyRightStatusFilter-header').click()
checkFilteredStudentCount(page)
})
})
test.describe.skip('Course Statistics', () => {
const pathToLimits2021 =
'/coursepopulation?coursecodes=%5B"MAT11003"%2C"57116"%2C"57016"%2C"AYMAT11003"%5D&from=72&separate=false&to=72&unifyCourses=unifyStats'
const defaultAmountOfStudents = 48
test.beforeAll(() => cy.init(pathToLimits2021))
test.beforeEach(async ({ page }) => setClockToMockedDate())
test('Grade filter works', async ({ page }) => {
checkFilteredStudentCount(page)
cy.cs('gradeFilter-header').click()
cy.cs('gradeFilter-5').click()
checkFilteredStudentCount(page)
cy.cs('gradeFilter-3').click()
checkFilteredStudentCount(page)
cy.cs('gradeFilter-3').click()
cy.cs('gradeFilter-5').click()
cy.cs('gradeFilter-clear').should('not.exist')
cy.cs('gradeFilter-header').click()
checkFilteredStudentCount(page)
})
test('Programme filter works and defaults to "Attainment"', async ({ page }) => {
checkFilteredStudentCount(page)
cy.cs('programmeFilter-header').click()
cy.cs('programmeFilter-mode-selector').children().eq(0).should('contain', 'Attainment')
cy.selectFromDropdown('programmeFilter', 1, true)
checkFilteredStudentCount(page)
cy.cs('programmeFilter-clear').click()
cy.cs('programmeFilter-header').click()
checkFilteredStudentCount(page)
})
test('Age filter works', async ({ page }) => {
cy.cs('ageFilter-header').click()
checkFilteredStudentCount(page)
cy.setRangeSelect('ageFilter', 23, 30, 36)
cy.cs('ageFilter-clear').click()
cy.cs('ageFilter-header').click()
checkFilteredStudentCount(page)
})
test('Gender filter works', async ({ page }) => {
cy.cs('genderFilter-header').click()
cy.selectFromDropdown('genderFilter', 0)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 1)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 2)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 3)
checkFilteredStudentCount(page)
cy.cs('genderFilter-clear').click()
cy.cs('genderFilter-header').click()
checkFilteredStudentCount(page)
})
test('Starting year filter works', async ({ page }) => {
cy.cs('startYearAtUniFilter-header').click()
cy.selectFromDropdown('startYearAtUniFilter', 0)
checkFilteredStudentCount(page)
cy.selectFromDropdown('startYearAtUniFilter', 10)
checkFilteredStudentCount(page)
cy.cs('startYearAtUniFilter-clear').click()
cy.cs('startYearAtUniFilter-header').click()
checkFilteredStudentCount(page)
})
test('Filter combinations work', async ({ page }) => {
cy.cs('ageFilter-header').click()
checkFilteredStudentCount(page)
cy.setRangeSelect('ageFilter', 23, 30, 36)
cy.cs('gradeFilter-header').click()
cy.cs('gradeFilter-5').click()
checkFilteredStudentCount(page)
cy.cs('gradeFilter-clear').click()
cy.cs('gradeFilter-header').click()
cy.cs('ageFilter-clear').click()
cy.cs('ageFilter-header').click()
checkFilteredStudentCount(page)
})
})
test.describe('Custom Population Statistics', () => {
let defaultAmountOfStudents
test.beforeAll(() => {
cy.init('/custompopulation')
cy.fixture('customPopulations').then(({ studentNumbersForCSStudentsSet1, studentNumbersForCSStudentsSet2 }) => {
const students = [...studentNumbersForCSStudentsSet1, ...studentNumbersForCSStudentsSet2]
defaultAmountOfStudents = students.length
cy.cs('student-number-input').click()
cy.cs('student-number-input').type(students.join('{enter}'))
cy.cs('search-button').click()
})
})
test.beforeEach(async ({ page }) => setClockToMockedDate())
test('Age filter works', async ({ page }) => {
cy.cs('ageFilter-header').click()
cy.setRangeSelect('ageFilter', 24, 28, 5)
cy.cs('ageFilter-clear').click()
cy.cs('ageFilter-header').click()
checkFilteredStudentCount(page)
})
test('Programme filter works and defaults to "Active Study Right"', async ({ page }) => {
cy.cs('programmeFilter-header').click()
cy.cs('programmeFilter-mode-selector').children().eq(0).should('contain', 'Active Study Right')
cy.selectFromDropdown('programmeFilter', 1, true)
checkFilteredStudentCount(page)
cy.cs('programmeFilter-clear').click()
cy.cs('programmeFilter-header').click()
checkFilteredStudentCount(page)
})
test('Gender filter works', async ({ page }) => {
cy.cs('genderFilter-header').click()
cy.selectFromDropdown('genderFilter', 0)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 1)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 2)
checkFilteredStudentCount(page)
cy.selectFromDropdown('genderFilter', 3)
checkFilteredStudentCount(page)
cy.cs('genderFilter-clear').click()
cy.cs('genderFilter-header').click()
checkFilteredStudentCount(page)
})
test('Starting year filter works', async ({ page }) => {
cy.cs('startYearAtUniFilter-header').click()
cy.selectFromDropdown('startYearAtUniFilter', 0)
checkFilteredStudentCount(page)
cy.cs('startYearAtUniFilter-clear').click()
cy.cs('startYearAtUniFilter-header').click()
checkFilteredStudentCount(page)
})
test('Courses filter works', async ({ page }) => {
const courses = [
{ code: 'MAT11005', name: 'Integraalilaskenta' },
{ code: 'MAT21007', name: 'Mitta ja integraali' },
]
cy.cs('courseFilter-header').click()
cy.selectFromAutocomplete('courseFilter', `${courses[0].code} - ${courses[0].name}`)
checkFilteredStudentCount(page)
cy.selectFromDropdown(`courseFilter-${courses[0].code}`, 1)
checkFilteredStudentCount(page)
cy.selectFromAutocomplete('courseFilter', `${courses[1].code} - ${courses[1].name}`)
checkFilteredStudentCount(page)
cy.selectFromDropdown(`courseFilter-${courses[1].code}`, 3)
checkFilteredStudentCount(page)
cy.cs(`courseFilter-${courses[1].code}-clear`).click()
checkFilteredStudentCount(page)
cy.cs('courseFilter-clear').click()
cy.cs('courseFilter-header').click()
checkFilteredStudentCount(page)
})
})
-78
View File
@@ -1,78 +0,0 @@
import { test, expect } from '@playwright/test'
/// <reference types="cypress" />
const chooseSemester = async (page, semester, fromOrTo) => {
cy.cs(`semester-${fromOrTo}`).click()
cy.cs(`select-opt-${semester}`).click()
cy.cs(`select-opt-${semester}`).should('not.have.class', 'visible')
}
const checkNumbers = async (page, numbers, numberOfColumns, mode) => {
const offset = 1 // skip first col with codes / names
cy.cs(`ooditable-${mode}`).find('table').find('tbody').as('tbody')
cy.get('@tbody').find('tr').first().as('totalRow')
cy.get('@totalRow').find('td').should('have.length', numberOfColumns)
cy.get('@totalRow').find('td').eq(0).should('contain', 'All courses total')
numbers.forEach((number, index) => {
cy.get('@totalRow')
.find('td')
.eq(index + offset)
.should('contain', number)
})
}
test.describe('When language center is opened', () => {
test.describe('as an admin user', () => {
test.beforeEach(async ({ page }) => {
cy.init('/languagecenterview', 'admin')
cy.cs('completions-button').click()
})
test.describe('Faculties tab', () => {
test.beforeEach(async ({ page }) => {
chooseSemester(page)
chooseSemester(page)
})
test('Initial view is correct', async ({ page }) => {
cy.contains('All courses total')
cy.contains('Academic and Professional')
cy.contains('AYKK-RUKIRJ')
})
test('Faculties tab shows numbers', async ({ page }) => {
cy.get('table > tbody > tr:first').within(() => {
expect(page.locator('td')).toHaveCount(15)
cy.get('td').eq(0).contains('All courses total')
const numbers = [2076, 36, 9, 34, 759, 15, 40, 6, 51, 1, 24, 1059, 42, 0]
numbers.forEach((number, index) => {
cy.get('td')
.eq(index + 1)
.contains(number)
})
})
})
test('Faculties tab "exceeding" button works', async ({ page }) => {
cy.cs('difference-button').click()
checkNumbers(page)
})
test('Faculties tab semester selector changes numbers', async ({ page }) => {
chooseSemester(page)
checkNumbers(page)
})
})
test.describe('Semester tab', () => {
test.beforeEach(async ({ page }) => {
page.locator('text=By semesters').click()
chooseSemester(page)
chooseSemester(page)
})
test('Semester tab shows numbers', async ({ page }) => {
checkNumbers(page)
})
})
})
test.describe('with a user with no rights', () => {
test('"Access denied" is shown', async ({ page }) => {
cy.init('/languagecenterview', 'norights')
cy.contains('Access denied')
cy.contains("You don't currently have permission to view this page.")
page.locator('text=Special populations').click()
cy.contains('Language center view').should('not.exist')
})
})
})
-192
View File
@@ -1,192 +0,0 @@
import { test, expect } from '@playwright/test'
import assert from 'node:assert/strict'
/// <reference types="cypress" />
const selectCourseStatus = async (page, courseCode, status) => {
cy.cs(`courseFilter-${courseCode}-selector`).click()
cy.get(`[role="listbox"][aria-labelledby=courseFilter-${courseCode}]`).within(() => {
cy.get('li').contains(status).click()
})
}
test.describe('Numbers should match between', () => {
test.describe('Programme courses, Course statistics and Course population (no substitutions, all years)', () => {
const courseData = [
// Code, name, total students, passed, not completed, failed*, enrolled no grade* (not used by Programme courses)
['Course', 'MAT11001', 'Johdatus yliopistomatematiikkaan', 272, 253, 1 + 18, 1, 18],
['Course', 'MAT11003', 'Raja-arvot', 270, 249, 1 + 20, 1, 20],
['Course', 'MAT11004', 'Differentiaalilaskenta', 262, 248, 1 + 13, 1, 13],
['Course', 'MAT21002', 'Sarjat', 256, 250, 0 + 6, 0, 6],
['Course', 'MAT11005', 'Integraalilaskenta', 251, 234, 0 + 17, 0, 17],
['Course', 'MAT11002', 'Lineaarialgebra ja matriisilaskenta I', 247, 242, 1 + 4, 1, 4],
['Course', 'MAT12003', 'Todennäköisyyslaskenta I', 234, 227, 3 + 4, 3, 4],
['Course', 'MAT21001', 'Lineaarialgebra ja matriisilaskenta II', 230, 216, 4 + 10, 4, 10],
['Course', 'MAT21003', 'Vektorianalyysi I', 228, 202, 3 + 23, 3, 23],
['Course', 'MAT20005', 'Akateemiset taidot', 201, 178, 0 + 23, 0, 23],
['Module', 'MAT110', 'Matematiikka, perusopinnot', 195, 195, 0 + 0, 0, 0],
['Course', 'MAT21014', 'Johdatus logiikkaan I', 188, 170, 0 + 18, 0, 18],
]
// Check test data is correct
courseData.forEach(entry => {
assert.strictEqual(entry.length, 8)
assert.strictEqual(entry.at(6) + entry.at(7), entry.at(5))
})
test('in Programme courses', async ({ page }) => {
// Move to Math bachelor programme's programme courses
cy.init('/study-programme')
page.locator('text=a', 'text=Matemaattisten tieteiden kandiohjelma').click()
cy.cs('ProgrammeCoursesTab').click()
// Wait for tab to load
cy.contains('Programme courses by credit type')
// Sort by Total students
cy.get('thead').within(() => {
cy.get('tr')
.eq(0)
.within(() => {
cy.get('th').eq(3).click()
})
})
cy.get('tbody').within(() => {
courseData.forEach((course, index) => {
cy.get('tr')
.eq(index)
.within(() => {
// Check a course's fields
course.forEach((field, fieldIndex) => {
// Failed, Enrolled no grade values not used
if (fieldIndex <= 5) {
cy.get('td').eq(fieldIndex).contains(field)
}
})
})
})
})
})
test('in Course statistics', async ({ page }) => {
courseData.forEach(([_courseOrModule, code, name, total, passed, _notCompleted, failed, enrolledNoGrade]) => {
// Move to Course statistics
cy.init(`/coursestatistics?courseCodes=%5B%22${code}%22%5D&combineSubstitutions=false`, 'basic')
cy.url().should('include', `/coursestatistics?courseCodes=%5B%22${code}%22%5D`)
cy.contains('Course statistics')
cy.contains(name) // course name
cy.cs('FromYearSelector').click()
cy.cs('FromYearSelectorOption2017-2018').click()
cy.get('tbody').within(() => {
cy.get('tr')
.eq(0)
.within(() => {
cy.get('td').eq(1).contains(total)
cy.get('td').eq(2).contains(passed)
cy.get('td').eq(3).contains(failed) // jump over combined Not completed
cy.get('td').eq(4).contains(enrolledNoGrade)
})
})
})
})
test('in Course population', async ({ page }) => {
courseData.forEach(([_courseOrModule, code, name, total, passed, _notCompleted, failed, enrolledNoGrade]) => {
// Academic years between 2017-2023
cy.init(
// year - 1949 yields the correct year code
`/coursepopulation?from=${2017 - 1949}&to=${2023 - 1949}&coursecodes=%5B%22${code}%22%5D&includeSubstitutions=false`,
'basic'
)
cy.contains(name) // Course name
// Select course from Course-filter
cy.cs('courseFilter-filter-card').click()
cy.cs('courseFilter-selector').click()
cy.cs('courseFilter-popper').within(() => {
page.locator('text=li', `${code} - ${name}`).click()
})
selectCourseStatus(page)
cy.contains(`Students (${total})`)
selectCourseStatus(page)
cy.contains(`Students (${passed})`)
selectCourseStatus(page)
cy.contains(`Students (${failed})`)
selectCourseStatus(page)
cy.contains(`Students (${enrolledNoGrade})`)
})
})
})
test.describe('Programme courses, Course statistics and Course population (no substitutions, single years)', () => {
// MAT21003, Vektorianalyysi I
const yearlyData = [
// Year, Total students, Passed, Failed, Enrolled no grade, Not completed (failed + enrolled n.g.)
[2017, 1, 0, 1, 0, 1 + 0],
[2018, 31, 27, 4, 0, 4 + 0],
[2019, 58, 56, 2, 0, 2 + 0],
[2020, 63, 62, 1, 0, 1 + 0],
[2021, 41, 35, 0, 6, 0 + 6],
[2022, 28, 21, 0, 7, 0 + 7],
[2023, 21, 1, 0, 20, 0 + 20],
]
// Check test data is correct
yearlyData.forEach(entry => {
assert.strictEqual(entry.length, 6)
assert.strictEqual(entry.at(3) + entry.at(4), entry.at(5))
})
test('in Programme courses', async ({ page }) => {
cy.init('/study-programme')
page.locator('text=a', 'text=Matemaattisten tieteiden kandiohjelma').click()
cy.cs('ProgrammeCoursesTab').click()
yearlyData.forEach(([year, total, passed, _failed, _enrolledNoGrade, notCompleted]) => {
cy.cs('to-year-select').click()
cy.cs(`to-year-select-option-${year}`).click()
cy.cs('from-year-select').click()
cy.cs(`from-year-select-option-${year}`).click()
cy.get('tbody')
.contains('tr', 'MAT21003')
.scrollIntoView()
.within(() => {
cy.get('td').eq(3).contains(total)
cy.get('td').eq(4).contains(passed)
cy.get('td').eq(5).contains(notCompleted)
})
})
})
test('in Course statistics', async ({ page }) => {
yearlyData.forEach(([year, total, passed, failed, enrolledNoGrade, _notCompleted]) => {
cy.init(`/coursestatistics?courseCodes=%5B%22MAT21003%22%5D&combineSubstitutions=false`, 'basic')
const yearString = `${year}-${year + 1}`
cy.cs('ToYearSelector').click()
cy.cs(`ToYearSelectorOption${yearString}`).click()
cy.cs('FromYearSelector').click()
cy.cs(`FromYearSelectorOption${yearString}`).click()
cy.contains('Student statistics')
expect(page.locator('tbody tr')).toHaveCount(2)
// Take the total entry in the table to have enrolled, no grade always be a number
cy.get('tbody')
.contains('tr', 'Total')
.within(() => {
cy.get('td').eq(1).contains(total)
cy.get('td').eq(2).contains(passed)
cy.get('td').eq(3).contains(failed)
cy.get('td').eq(4).contains(enrolledNoGrade)
})
})
})
test('in Course population', async ({ page }) => {
yearlyData.forEach(([year, total, passed, failed, enrolledNoGrade, _notCompleted]) => {
cy.init(
// year - 1949 yields the correct year code
`/coursepopulation?from=${year - 1949}&to=${year - 1949}&coursecodes=%5B%22MAT21003%22%5D&includeSubstitutions=false`,
'basic'
)
cy.contains('Vektorianalyysi I') // Course name
// Select course from Course-filter
cy.cs('courseFilter-filter-card').click()
cy.cs('courseFilter-selector').click()
cy.cs('courseFilter-popper').within(() => {
page.locator('text=li', 'text=MAT21003 - Vektorianalyysi I').click()
})
selectCourseStatus(page)
cy.contains(`Students (${total})`)
selectCourseStatus(page)
cy.contains(`Students (${passed})`)
selectCourseStatus(page)
cy.contains(`Students (${failed})`)
selectCourseStatus(page)
cy.contains(`Students (${enrolledNoGrade})`)
})
})
})
})
-134
View File
@@ -1,134 +0,0 @@
const { test, expect } = require('@playwright/test')
const userHeaders = [
{
uid: 'admin',
displayname: 'Admin User',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'grp-oodikone-users;grp-oodikone-basic-users;grp-toska',
mail: 'grp-toska+mockadminuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-6666666',
},
{
uid: 'basic',
displayname: 'Basic User',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'grp-oodikone-users;grp-oodikone-basic-users',
mail: 'grp-toska+mockbasicuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-1234567',
},
{
uid: 'onlycoursestatistics',
displayname: 'Onlycoursestatistics User',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'grp-oodikone-basic-users',
mail: 'grp-toska+mockonlycoursestatisticsuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-7654321',
},
{
uid: 'norights',
displayname: 'Norights User',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'grp-oodikone-users',
mail: 'grp-toska+mocknorightuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-0000000',
},
{
uid: 'onlyiamrights',
displayname: 'Only IAM rights user',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'hy-employees;hy-mltdk-mat-jory',
mail: 'grp-toska+mockonlyiamrightsuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-1111111',
},
{
uid: 'onlystudyguidancegroups',
displayname: 'Study Guidance Groups User',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'grp-oodikone-users',
mail: 'grp-toska+mockonlystudyguidancegroupsuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-2222222',
},
]
const getBaseRoutes = [
['/', {}],
['/changelog', {}],
['/completedcoursessearch', {}],
['/university', {}],
['/feedback', {}],
['/populations', { roles: ['fullSisuAccess'], programmeRights: [] }],
['/study-programme', { roles: ['fullSisuAccess'], programmeRights: [] }],
['/study-programme/KH50_001', { roles: ['fullSisuAccess'], programmeRights: ['KH50_001'] }],
['/coursepopulation', { roles: ['fullSisuAccess'], programmeRights: [] }],
['/users', { roles: ['admin'] }],
['/users/334', { roles: ['admin'] }],
['/updater', { roles: ['admin'] }],
['/coursestatistics', { roles: ['fullSisuAccess', 'courseStatistics'], programmeRights: [] }],
['/faculties', { roles: ['fullSisuAccess', 'facultyStatistics'] }],
['/faculties/hy-org-1000000911', { roles: ['fullSisuAccess', 'facultyStatistics'] }],
['/students', { roles: ['fullSisuAccess', 'studyGuidanceGroups'], programmeRights: [] }],
['/students/545400', { roles: ['fullSisuAccess', 'studyGuidanceGroups'], programmeRights: [] }],
['/custompopulation', { roles: ['fullSisuAccess', 'studyGuidanceGroups'], programmeRights: [] }],
['/teachers', { roles: ['teachers'] }],
['/teachers/hy-hlo-1463447', { roles: ['teachers'] }],
['/studyguidancegroups', { roles: ['studyGuidanceGroups'] }],
['/studyguidancegroups/otm-b3b52ff5-88f6-4d52-bd18-0588023b6322', { userId: '', roles: ['studyGuidanceGroups'] }],
['/close-to-graduation', { roles: ['fullSisuAccess', 'studyGuidanceGroups'] }],
['/languagecenterview', { iamGroups: ['grp-kielikeskus-esihenkilot'] }],
]
const specialNeedsRoutes = [
'populations',
'study-programme',
'coursepopulation',
'coursestatistics',
'students',
'custompopulation',
]
const initAs = async (page, path, userId = 'basic') => {
const headers = userHeaders.find(user => user.uid === userId)
if (!headers) throw new Error(`${userId} is not valid user id`)
await page.setExtraHTTPHeaders(headers)
await page.goto(path)
}
for (const user of userHeaders) {
if (user.uid === 'admin') continue
test.describe(`${user.displayname} has access only to views that were intended`, () => {
let userInfo
test.beforeAll(async ({ request }) => {
const response = await request.get('/api/login', { headers: user })
const body = await response.json()
userInfo = body?.user
})
for (const [route, requirements] of getBaseRoutes) {
test(`Checking access ${route}`, async ({ page }) => {
await initAs(page, route, user.uid)
const requiredUserId = !requirements.userId || requirements.userId === userInfo.userId
const requiredRoles = !requirements.roles || requirements.roles.some(role => userInfo.roles?.includes(role))
const requiredRights =
!requirements.requireProgrammeRights ||
userInfo.roles?.includes('fullSisuAccess') ||
requirements.programmeRights.every(role => userInfo.programmeRights?.includes(role))
const isSpecialRoute = specialNeedsRoutes.some(path => route.includes(path))
const hasCoreAccess = isSpecialRoute ? requiredRoles || requiredRights : requiredRoles && requiredRights
const shouldHaveAccess = hasCoreAccess && requiredUserId
if (shouldHaveAccess) {
await expect(page.getByText('Something broke')).toHaveCount(0)
await expect(page.getByText('Access denied')).toHaveCount(0)
} else {
await expect(page.getByText('Access denied')).toBeVisible()
}
})
}
})
}
-272
View File
@@ -1,272 +0,0 @@
import { test, expect } from '@playwright/test'
/// <reference types="cypress" />
const student = {
firstNames: 'Varpu Roope',
lastName: 'Mårtensson',
studentNumber: '550003',
sisPersonId: 'hy-hlo-115926826',
email: 'sisutestidata134902@testisisudata.fi',
}
const typeToSearch = async (page, text) => {
cy.cs('student-search').type(text)
}
const typeStudentNumberAndClick = async (page, studentNumber) => {
typeToSearch(page)
page.locator('text=td', studentNumber).click()
}
test.describe('Students tests', () => {
test.describe('When using basic user', () => {
test.beforeEach(async ({ page }) => {
cy.init('')
page.locator('text=Students').click()
cy.url().should('include', '/students')
cy.contains('Show student names')
})
test('Students search form is usable', async ({ page }) => {
typeToSearch(page)
cy.contains('Student number')
cy.contains('Last name').should('not.exist')
cy.contains('First names').should('not.exist')
cy.contains('Started')
cy.contains('Credits')
cy.contains('Active study rights')
cy.contains(student.firstNames).should('not.exist')
cy.contains(student.lastName).should('not.exist')
cy.cs('toggleStudentNames').click()
cy.contains(student.firstNames)
cy.contains('Student number')
cy.contains('Last name')
cy.contains('First names')
cy.contains('Started')
cy.contains('Credits')
cy.contains('Active study rights')
cy.contains(student.firstNames)
cy.contains(student.lastName)
cy.cs('toggleStudentNames').click()
cy.contains('Student number')
cy.contains('Last name').should('not.exist')
cy.contains('First names').should('not.exist')
cy.contains('Started')
cy.contains('Credits')
cy.contains('Active study rights')
cy.contains(student.firstNames).should('not.exist')
cy.contains(student.lastName).should('not.exist')
})
test('Search term must be at least 4 characters long', async ({ page }) => {
typeToSearch(page)
cy.contains('Search term is not accurate enough')
typeToSearch(page)
expect(page.locator('table tbody tr')).toHaveCount(1)
})
test('Can search with student number too', async ({ page }) => {
typeToSearch(page)
cy.contains(student.studentNumber)
})
test('Can get student specific page by clicking student', async ({ page }) => {
typeStudentNumberAndClick(page)
cy.contains('Matemaattisten tieteiden kandiohjelma (01.08.2020–31.07.2027)')
cy.contains(student.lastName).should('not.exist')
cy.contains(student.firstNames).should('not.exist')
cy.contains(student.email).should('not.exist')
cy.cs('toggleStudentNames').click()
cy.contains(student.lastName)
cy.contains(student.firstNames)
cy.contains(student.email)
cy.cs('toggleStudentNames').click()
cy.contains(student.lastName).should('not.exist')
cy.contains(student.firstNames).should('not.exist')
cy.contains(student.email).should('not.exist')
})
test("'Update student' button is not shown", async ({ page }) => {
typeStudentNumberAndClick(page)
cy.cs('student-info-card').within(() => {
cy.contains('button', 'Update student').should('not.exist')
})
})
test('Can get back to search menu', async ({ page }) => {
typeStudentNumberAndClick(page)
cy.go('back')
cy.contains('Student number').should('not.exist')
cy.contains('Credits').should('not.exist')
})
test('Can jump to course', async ({ page }) => {
typeStudentNumberAndClick(page)
cy.contains('Tilastollinen päättely I (MAT12004)')
.parent()
.siblings()
.last()
.within(() => {
page.locator('a').click()
})
cy.url().should('include', '/coursestatistics')
cy.contains('MAT12004') // Tilastollinen päättely I
cy.contains('AYMAT12004') // Avoin yo: Tilastollinen päättely I
cy.contains('57046') // Johdatus tilastolliseen päättelyyn
})
test('Has correct Sisu link', async ({ page }) => {
typeStudentNumberAndClick(page)
cy.cs('sisu-link')
.should('have.attr', 'href')
.and('include', `https://sisu.helsinki.fi/tutor/role/staff/student/${student.sisPersonId}/basic/basic-info`)
})
test('Semester enrollments can be toggled', async ({ page }) => {
typeStudentNumberAndClick(page)
const programmes = [
'Oikeustieteen tohtoriohjelma',
'Matemaattisten tieteiden kandiohjelma',
'Oikeustieteen maisterin koulutusohjelmaOikeusnotaarin koulutusohjelma',
]
cy.cs('student-info-card').within(() => {
page.locator('text=Enrollments').click()
cy.get('table tbody tr')
.should('have.length', 3)
.each(($tr, index) => {
cy.wrap($tr).within(() => {
cy.get('td').eq(0).should('have.text', programmes[index])
})
})
})
})
test("Searching with bad name doesn't yield results", async ({ page }) => {
typeToSearch(page)
cy.contains('Student number').should('not.exist')
})
test("Searching with bad student number doesn't yield results", async ({ page }) => {
typeToSearch(page)
cy.contains('Student number').should('not.exist')
})
test('Can jump to population page', async ({ page }) => {
typeStudentNumberAndClick(page)
cy.cs('study-rights-section').within(() => {
cy.contains('Matemaattisten tieteiden kandiohjelma')
.parent()
.within(() => cy.get('a').click())
})
cy.contains('Matemaattisten tieteiden kandiohjelma')
cy.contains('Class of 2020 - 2021, 30 students')
})
test('Grade graph works in all three different modes', async ({ page }) => {
typeStudentNumberAndClick(page)
page.locator('text=button', 'text=Grade graph').click()
page.locator('text=button', 'text=Show group mean').click()
cy.cs('group-size-input').within(() => {
cy.contains('label', 'Group size')
expect(page.locator('input')).toHaveValue('5')
})
cy.cs('group-size-input').within(() => {
cy.contains('label', 'Group size')
page.locator('input').fill('')
page.locator('input').type('10')
expect(page.locator('input')).toHaveValue('10')
})
page.locator('text=button', 'text=Show semester mean').click()
})
test.describe('Bachelor Honours section', () => {
test("Shows 'Qualified for Honours' tag and main modules info when the student is qualified", async ({
page,
}) => {
page.goto('/students/495976')
cy.contains('h2', 'Bachelor Honours')
cy.contains('[data-cy=honours-chip-qualified]', 'Qualified for Honours')
page.locator('text=Study modules').click()
cy.get('[data-cy=main-modules] tbody tr')
.should('have.length', 3)
.each(($tr, index) => {
const info = [
['07.05.2020', 'Matemaattisten tieteiden kandiohjelma (KH50_001)', 'Hyv.'],
['08.05.2018', 'Matematiikka, perusopinnot (MAT110)', '4'],
['25.02.2020', 'Matematiikka, aineopinnot (MAT210)', '4'],
]
cy.wrap($tr).within(() => {
info[index].forEach((text, i) => {
cy.get('td').eq(i).contains(text)
})
})
})
})
test("Shows 'Did not graduate in time' when the student has graduated but not in time", async ({ page }) => {
page.goto('/students/540355')
cy.contains('h2', 'Bachelor Honours')
cy.contains('[data-cy=honours-chip-not-qualified]', 'Not qualified for Honours')
cy.contains('[data-cy=honours-chip-error]', 'Did not graduate in time')
})
test("Shows 'Module grades too low' when the student has graduated in time but has too low grades", async ({
page,
}) => {
page.goto('/students/547934')
cy.contains('h2', 'Bachelor Honours')
cy.contains('[data-cy=honours-chip-not-qualified]', 'Not qualified for Honours')
cy.contains('[data-cy=honours-chip-error]', 'Module grades too low')
})
test("Shows 'Might need further inspection' when the student has graduated in time but has more than four main modules", async ({
page,
}) => {
page.goto('/students/478837')
cy.contains('h2', 'Bachelor Honours')
cy.contains('[data-cy=honours-chip-inspection]', 'Might need further inspection')
})
test("Shows 'Has not graduated' when the student has not graduated", async ({ page }) => {
page.goto(`students/${student.studentNumber}`)
cy.contains('h2', 'Bachelor Honours')
cy.contains('[data-cy=honours-chip-not-qualified]', 'Not qualified for Honours')
cy.contains('[data-cy=honours-chip-error]', 'Has not graduated')
})
})
})
test.describe('When using admin user', () => {
test.beforeEach(async ({ page }) => {
cy.init('/students', 'admin')
})
test('Does not crash if student has no study rights or courses', async ({ page }) => {
typeStudentNumberAndClick(page)
cy.contains('Credits: 0')
})
test("'Update student' button is shown", async ({ page }) => {
typeStudentNumberAndClick(page)
cy.cs('student-info-card').within(() => {
cy.contains('button', 'Update student')
})
})
test('Bachelor Honours section is not shown for students outside of Faculty of Science', async ({ page }) => {
page.goto('/students/453146')
cy.contains('h2', 'Bachelor Honours').should('not.exist')
})
test('When a study plan is selected, courses included in the study plan are highlighted with a blue background', async ({
page,
}) => {
page.goto('/students/550789')
cy.contains('Study rights')
cy.get('[data-cy=KH40_005-0]').contains('Kulttuurien tutkimuksen kandiohjelma')
cy.get('[data-cy=KH40_005-0]').within(() => {
cy.get('td').eq(1).click()
})
cy.contains('table tbody tr', 'Kandidaatintutkielma (KUKA-LIS222)').should(
'have.css',
'background-color',
'rgb(232, 244, 255)'
)
})
test("If there's a study plan corresponding to the degree programme, completed credits are displayed", async ({
page,
}) => {
page.goto('/students/550789')
cy.contains('Study rights')
cy.get('[data-cy=KH40_005-0]').contains('Kulttuurien tutkimuksen kandiohjelma')
cy.get('[data-cy=KH40_005-0]').within(() => {
cy.get('td')
.eq(4)
.contains(/^185 cr$/)
})
})
test("If there's a study plan corresponding to the degree programme and the student hasn't graduated, percentage of completion is also displayed", async ({
page,
}) => {
page.goto('/students/458723')
cy.contains('Study rights')
cy.get('[data-cy=KH20_001-0]').contains('Oikeusnotaarin koulutusohjelma')
cy.get('[data-cy=KH20_001-0]').within(() => {
cy.get('td').eq(4).contains('69% (125 cr)')
})
})
})
})
-166
View File
@@ -1,166 +0,0 @@
const { test, expect } = require('@playwright/test')
const studyGuidanceGroupsFixture = require('../cypress/fixtures/studyGuidanceGroups.json')
const userHeaders = {
admin: {
uid: 'admin',
displayname: 'Admin User',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'grp-oodikone-users;grp-oodikone-basic-users;grp-toska',
mail: 'grp-toska+mockadminuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-6666666',
},
basic: {
uid: 'basic',
displayname: 'Basic User',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'grp-oodikone-users;grp-oodikone-basic-users',
mail: 'grp-toska+mockbasicuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-1234567',
},
onlystudyguidancegroups: {
uid: 'onlystudyguidancegroups',
displayname: 'Study Guidance Groups User',
'shib-session-id': 'mock-playwright-session',
hygroupcn: 'grp-oodikone-users',
mail: 'grp-toska+mockonlystudyguidancegroupsuser@helsinki.fi',
hypersonsisuid: 'hy-hlo-2222222',
},
}
const initAs = async (page, path, userId = 'basic') => {
const headers = userHeaders[userId]
if (!headers) throw new Error(`${userId} is not valid user id`)
await page.setExtraHTTPHeaders(headers)
await page.goto(path)
}
const mockStudyGuidanceGroups = async page => {
await page.route('**/api/studyguidancegroups', route =>
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(studyGuidanceGroupsFixture),
})
)
}
test.describe('Study guidance group tests', () => {
test.describe('Study guidance group overview page', () => {
test.describe('without study guidance groups', () => {
test('shows the correct notification', async ({ page }) => {
await initAs(page, '/studyguidancegroups', 'admin')
await expect(page.getByText('Study guidance groups')).toBeVisible()
await expect(page.getByText('You do not have access to any study guidance groups.')).toBeVisible()
})
})
test.describe('without correct rights', () => {
test('shows the correct notification', async ({ page }) => {
await initAs(page, '/studyguidancegroups')
await expect(page.getByText('Access denied')).toBeVisible()
await expect(
page.getByText(
"You don't currently have permission to view this page. If you believe this is a mistake, please contact oodikone@helsinki.fi."
)
).toBeVisible()
})
})
test.describe('with study guidance groups', () => {
test.beforeEach(async ({ page }) => {
await mockStudyGuidanceGroups(page)
await initAs(page, '/studyguidancegroups', 'onlystudyguidancegroups')
})
test('shows the correct data', async ({ page }) => {
await expect(page.getByText('Study guidance groups')).toBeVisible()
const studyGuidanceGroupsTableContent = [
['MAT kandit 2020', '3', 'Matemaattisten tieteiden kandiohjelma', '2020 - 2021'],
['Oma ohjausryhmä', '2', 'Add degree programme', 'Add starting year'],
]
for (const row of studyGuidanceGroupsTableContent) {
const tableRow = page.locator('[data-cy="study-guidance-group-overview-data-table"] tbody tr').filter({
hasText: row[0],
})
await expect(tableRow).toHaveCount(1)
for (const value of row) {
await expect(tableRow.getByText(value)).toBeVisible()
}
}
})
test('has working links to single study guidance groups', async ({ page }) => {
await page.locator('[data-cy="study-guidance-group-link-sgg-cypress-1"]').click()
await expect(page).toHaveURL(/\/studyguidancegroups\/sgg-cypress-1$/)
})
})
})
test.describe('Page for single study guidance group', () => {
test.beforeEach(async ({ page }) => {
await mockStudyGuidanceGroups(page)
})
test('has a working back button', async ({ page }) => {
await initAs(page, '/studyguidancegroups/sgg-cypress-1', 'onlystudyguidancegroups')
await page.getByRole('button', { name: 'Back to groups' }).click()
await expect(page).toHaveURL(/\/studyguidancegroups$/)
})
test.describe('without associated degree programme and year', () => {
test.beforeEach(async ({ page }) => {
await initAs(page, '/studyguidancegroups/sgg-cypress-2', 'onlystudyguidancegroups')
})
test('shows the correct panes', async ({ page }) => {
await expect(page.getByText('Oma ohjausryhmä')).toBeVisible()
await expect(page.locator('[data-cy="Credit accumulation (for 2 students)"]')).toBeVisible()
await expect(page.locator('[data-cy="Age distribution"]')).toBeVisible()
await expect(page.locator('[data-cy="Courses of population"]')).toBeVisible()
await expect(page.getByText('Students (2)')).toBeVisible()
await expect(page.locator('[data-cy="Credit statistics"]')).toHaveCount(0)
})
test.skip('students table has the correct tabs')
test.skip('general tab of the students table has the correct columns')
})
test.describe('with associated degree programme and year', () => {
test.beforeEach(async ({ page }) => {
await initAs(page, '/studyguidancegroups/sgg-cypress-1', 'onlystudyguidancegroups')
})
test('shows the correct labels', async ({ page }) => {
await expect(page.getByRole('heading', { level: 4, name: 'MAT kandit 2020' })).toBeVisible()
await expect(page.locator('.MuiChip-root').first()).toContainText('Matemaattisten tieteiden kandiohjelma')
await expect(page.locator('.MuiChip-root').last()).toContainText('2020 - 2021')
})
test('shows the correct panes', async ({ page }) => {
await expect(page.locator('[data-cy="Credit accumulation (for 3 students)"]')).toBeVisible()
await expect(page.locator('[data-cy="Credit statistics"]')).toBeVisible()
await expect(page.locator('[data-cy="Age distribution"]')).toBeVisible()
await expect(page.locator('[data-cy="Courses of population"]')).toBeVisible()
await expect(page.getByText('Students (3)')).toBeVisible()
})
test("clicking the 'Show credits starting from the associated academic year' filter", async ({ page }) => {
await expect(page.locator('[data-cy="ParticipationDate-filter-card"][data-active="false"]')).toBeVisible()
await page.locator('[data-cy="Credit accumulation (for 3 students)"]').click()
await page.getByText('Show credits starting from the associated academic year').click()
await expect(page.locator('[data-cy="ParticipationDate-filter-card"][data-active="true"]')).toBeVisible()
await expect(page.locator('.date-picker').first().locator('input')).toHaveValue('01.08.2020')
await expect(page.getByText('Reset All Filters')).toBeVisible()
await page.getByText('Show credits starting from the associated academic year').click()
await expect(page.locator('[data-cy="ParticipationDate-filter-card"][data-active="false"]')).toBeVisible()
})
test.skip('students table has the correct tabs')
test.skip('general tab of the students table has the correct columns')
})
})
})
-85
View File
@@ -1,85 +0,0 @@
import { test, expect } from '@playwright/test'
/// <reference types="cypress" />
const progressLevels = ['bachelors', 'bachelor-masters', 'masters', 'doctoral']
const checkProgressBarCharts = async page => {
progressLevels.forEach(level => cy.cs(`faculty-${level}-progress-bar-chart-section`))
}
const checkProgressTables = async page => {
progressLevels.forEach(level => cy.cs(`${level}-faculty-progress-table`))
}
const graduationTimesLevels = ['bachelor', 'bcMsCombo', 'master', 'doctor']
const checkGraduationCharts = async (page, mode) => {
graduationTimesLevels.forEach(level => {
cy.cs(`${level}-${mode}-bar-chart`).within(() => {
// Check that bar has loaded
cy.contains('Loading content').should('not.exist')
})
})
}
test.describe('University view', () => {
test.beforeEach(async ({ page }) => {
cy.init('/university')
cy.contains('University')
})
test.describe('Faculty progress tab', () => {
test('contains all the correct progress bar charts', async ({ page }) => {
checkProgressBarCharts(page)
})
test('contains all the correct progress tables', async ({ page }) => {
checkProgressTables(page)
})
test("'All study rights / Special study rights excluded' toggle works", async ({ page }) => {
cy.cs('study-right-toggle').click()
checkProgressBarCharts(page)
checkProgressTables(page)
})
test.skip('years in the tables can be clicked to show faculty level breakdown', async ({ page }) => {
cy.cs('study-right-toggle').click()
cy.cs('bachelors-faculty-progress-table-show-button3').click()
cy.contains('29.5%').hover()
cy.contains('Matemaattis-luonnontieteellinen tiedekunta')
cy.contains('H50')
cy.contains('0 Credits: 0')
cy.contains('1 ≤ Credits < 45: 13')
cy.contains('45 ≤ Credits < 90: 10')
cy.contains('90 ≤ Credits < 135: 16')
cy.contains('135 ≤ Credits < 180: 3')
cy.contains('180 ≤ Credits: 2')
})
test('info boxes contain correct information', async ({ page }) => {
cy.cs('faculty-progress-info-box-button').click()
cy.cs('faculty-progress-info-box-content').contains('Kuvaa tiedekuntaan kuuluvien')
cy.cs('faculty-bachelor-masters-progress-info-box-button').click()
cy.cs('faculty-bachelor-masters-progress-info-box-content').contains('The starting year is the')
})
})
test.describe('Faculty graduations tab', () => {
test.beforeEach(async ({ page }) => {
cy.cs('faculty-graduations-tab').click()
})
test.describe('Different modes work', () => {
test('Breakdown', async ({ page }) => {
cy.cs('graduation-mode-selector').within(() => {
cy.cs('select-breakdown').click()
})
checkGraduationCharts(page)
})
test('Median', async ({ page }) => {
cy.cs('graduation-mode-selector').within(() => {
cy.cs('select-median').click()
})
checkGraduationCharts(page)
})
test('Average', async ({ page }) => {
cy.cs('graduation-mode-selector').within(() => {
cy.cs('select-average').click()
})
checkGraduationCharts(page)
})
})
test('info boxes contain correct information', async ({ page }) => {
cy.cs('average-graduation-times-info-box-button').hover()
cy.cs('average-graduation-times-info-box-content').contains('Opiskelijoiden keskimääräiset valmistumisajat')
})
})
})