Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance: add support for selection questions in group activities & grading and extend corresponding test suite #4446

Merged
merged 4 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,7 @@ function GroupActivityGradingStack({
return
}

if (type === ElementType.FreeText) {
return {
[elementId]: {
type: type,
response: decision?.freeTextResponse,
valid: true,
},
}
} else if (type === ElementType.Sc || type === ElementType.Mc) {
if (type === ElementType.Sc || type === ElementType.Mc) {
return {
[elementId]: {
type: type,
Expand Down Expand Up @@ -123,6 +115,22 @@ function GroupActivityGradingStack({
valid: true,
},
}
} else if (type === ElementType.FreeText) {
return {
[elementId]: {
type: type,
response: decision?.freeTextResponse,
valid: true,
},
}
} else if (type === ElementType.Selection) {
return {
[elementId]: {
type: type,
response: decision?.selectionResponse,
valid: true,
},
}
}
},
[submission?.decisions]
Expand Down Expand Up @@ -222,6 +230,7 @@ function GroupActivityGradingStack({
{element.elementData.name}
</H3>
<StudentElement
preview
element={element}
elementIx={ix}
studentResponse={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ function GroupActivityGrading() {
[groupActivity?.activityInstances]
)

console.log(submissions)

if (loading)
return (
<Layout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ function GroupActivityStack({
valid: true,
},
}
} else if (decision.type === ElementType.Selection) {
return {
...acc,
[decision.instanceId]: {
type: decision.type,
response: decision.selectionResponse ?? undefined,
valid: true,
},
}
} else if (decision.type === ElementType.Content) {
return {
...acc,
Expand Down Expand Up @@ -272,6 +281,14 @@ function GroupActivityStack({
type: ElementType.Content,
contentReponse: value.response,
}
} else if (value.type === ElementType.Selection) {
return {
instanceId: parseInt(instanceId),
type: ElementType.Selection,
selectionResponse: Object.values(
value.response!
).filter((entry) => typeof entry !== 'undefined'),
}
} else {
return {
instanceId: parseInt(instanceId),
Expand Down
79 changes: 71 additions & 8 deletions cypress/cypress/e2e/J-group-activity-workflow.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ const FTQuestionTitle = uuid()
const FTQuestion = 'FT Question Group Activity'
const CTQuestionTitle = uuid()
const CTQuestion = 'CT Question Group Activity'
const SEQuestion = 'SE Question Group Activity'
const SEQuestionTitle = 'SE ' + uuid()
const SEQuestionInputs = 3
const SECollection = 'SE Collection Group Activity'
const SECollectionDescription = 'SE Collection Group Activity Description'
const SECollectionOptions = [
'SE Group Activity Option 1',
'SE Group Activity Option 2',
'SE Group Activity Option 3',
'SE Group Activity Option 4',
'SE Group Activity Option 5',
]
const SECollectionSolutions = [0, 1, 2, 4]

const currentYear = new Date().getFullYear()
const testCourse = 'Testkurs'
Expand Down Expand Up @@ -57,15 +70,16 @@ const flaggingTextNew = 'This is a NEW test flagging message'
const freeTextAnswer = 'Testanswer to Free-Text Question'
const numericalAnswer = '100'

const maxPoints = ['200', '100', '100', '300', '100', '200']
const scores1 = ['100', '100', '50', '200', '80', '200']
const scores2 = ['50', '25', '25', '75', '25', '50']
const maxPoints = ['200', '100', '100', '300', '100', '100', '200']
const scores1 = ['100', '100', '50', '200', '80', '100', '200']
const scores2 = ['50', '25', '25', '75', '25', '30', '50']
const comments1 = [
'Great job at question 1!',
undefined,
undefined,
'Great job at question 4!',
'Good job at question 5!',
'Great job with the seleciton question!',
undefined,
]
const comments2 = [
Expand All @@ -74,6 +88,7 @@ const comments2 = [
'This is not correct for question 3...',
undefined,
undefined,
undefined,
'This is not correct for question 6...',
]
const gradingComment1 = 'This is a test grading comment'
Expand Down Expand Up @@ -177,6 +192,28 @@ describe('Create and solve a group activity', () => {
title: CTQuestionTitle,
content: CTQuestion,
})

// create answer collection
cy.get('[data-cy="resources"]').click()
cy.createAnswerCollection({
name: SECollection,
description: SECollectionDescription,
entries: SECollectionOptions,
access: messages.manage.resources.accessPRIVATE,
accessCy: 'private',
})

// create selection question
cy.get('[data-cy="library"]').click()
cy.createQuestionSE({
title: SEQuestionTitle,
content: SEQuestion,
numberOfInputs: SEQuestionInputs,
collectionName: SECollection,
correctAnswers: SECollectionOptions.filter((_, i) =>
SECollectionSolutions.includes(i)
),
})
Comment on lines +195 to +216
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Edge case testing is indeed missing from selection question creation tests

Current tests only cover the happy path with a fixed input size of 3. Consider adding the following test scenarios:

  • Boundary conditions: Test with 0, 1, and maximum allowed inputs
  • Invalid inputs: Test handling of invalid selection counts
  • Empty collections: Verify behavior when the answer collection is empty
  • Duplicate selections: Ensure proper handling of duplicate answer selections
🔗 Analysis chain

Verify test coverage for edge cases in selection question creation.

While the basic creation flow is tested, consider adding tests for:

  • Maximum/minimum number of inputs
  • Duplicate selections
  • Empty collection handling
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for existing edge case tests
rg -A 5 "SEQuestionInputs.*=.*[01]|SEQuestionInputs.*=.*100" cypress/
rg "duplicate.*selection|empty.*collection" cypress/

Length of output: 126


Script:

#!/bin/bash
# Find all SE (Selection Element) related test files and patterns
echo "=== Selection Element Test Files ==="
fd ".*\.cy\.ts$" cypress/ --exec rg -l "createQuestionSE|SEQuestion"

echo -e "\n=== Test Data Definitions ==="
rg "SEQuestion.*=.*{" -A 5 cypress/

echo -e "\n=== Validation Patterns ==="
rg "validation|invalid|error.*SEQuestion" cypress/

echo -e "\n=== Test Constants ==="
rg "const.*SEQuestion" -A 3 cypress/

Length of output: 2553


Script:

#!/bin/bash
# Check createQuestionSE implementation
echo "=== Question Creation Implementation ==="
rg -A 10 "createQuestionSE.*=.*{" cypress/

echo -e "\n=== Command Implementation ==="
rg -A 10 "commands.*createQuestionSE" cypress/

Length of output: 369


Script:

#!/bin/bash
# Search for implementation with fixed pattern
echo "=== Custom Command Implementation ==="
rg "createQuestionSE" cypress/support/

echo -e "\n=== Type Definitions ==="
fd -e ts -e d.ts cypress/ --exec rg "interface.*Question|type.*Question"

Length of output: 658

})

// ! Part 1: Group Activity Creation
Expand Down Expand Up @@ -293,6 +330,7 @@ describe('Create and solve a group activity', () => {
KPRIMQuestionTitle,
NRQuestionTitle,
FTQuestionTitle,
SEQuestionTitle,
],
},
],
Expand Down Expand Up @@ -484,8 +522,11 @@ describe('Create and solve a group activity', () => {
.should('contain', FTQuestionTitle.substring(0, 20))
cy.get(`[data-cy="element-5-stack-0"]`)
.should('exist')
.should('contain', SCQuestionTitle.substring(0, 20))
.should('contain', SEQuestionTitle.substring(0, 20))
cy.get(`[data-cy="element-6-stack-0"]`)
.should('exist')
.should('contain', SCQuestionTitle.substring(0, 20))
cy.get(`[data-cy="element-7-stack-0"]`)
.should('exist')
.should('contain', CTQuestionTitle.substring(0, 20))
cy.get('[data-cy="next-or-submit"]').click()
Expand All @@ -507,7 +548,13 @@ describe('Create and solve a group activity', () => {
cy.get('[data-cy="toggle-kp-3-answer-4-incorrect"]').click()
cy.get('[data-cy="input-numerical-4"]').type(numericalAnswer)
cy.get('[data-cy="free-text-input-5"]').click().type(freeTextAnswer)
cy.get('[data-cy="sc-6-answer-option-1"]').click()
cy.get('[data-cy="selection-6-field-1"]').click()
cy.get(`[data-cy="select-answer-${SECollectionOptions[0]}"]`).click()
cy.get('[data-cy="selection-6-field-2"]').click()
cy.get(`[data-cy="select-answer-${SECollectionOptions[1]}"]`).click()
cy.get('[data-cy="selection-6-field-3"]').click()
cy.get(`[data-cy="select-answer-${SECollectionOptions[4]}"]`).click()
cy.get('[data-cy="sc-7-answer-option-1"]').click()
cy.get('[data-cy="submit-group-activity"]').click()
}

Expand All @@ -521,7 +568,10 @@ describe('Create and solve a group activity', () => {
cy.get('[data-cy="toggle-kp-3-answer-4-incorrect"]').should('be.disabled')
cy.get('[data-cy="input-numerical-4"]').should('be.disabled')
cy.get('[data-cy="free-text-input-5"]').should('be.disabled')
cy.get('[data-cy="sc-6-answer-option-1"]').should('be.disabled')
cy.get('[data-cy="selection-6-field-1"]').should('be.disabled')
cy.get('[data-cy="selection-6-field-2"]').should('be.disabled')
cy.get('[data-cy="selection-6-field-3"]').should('be.disabled')
cy.get('[data-cy="sc-7-answer-option-1"]').should('be.disabled')
}

function checkPersistentAnswers() {
Expand Down Expand Up @@ -551,8 +601,18 @@ describe('Create and solve a group activity', () => {
.should('be.disabled')
.contains(freeTextAnswer)

cy.get('[data-cy="sc-6-answer-option-1"]').should('be.disabled')
cy.get('[data-cy="sc-6-answer-option-2"]').should('be.disabled')
cy.get('[data-cy="selection-6-field-1"]')
.should('be.disabled')
.contains(SECollectionOptions[0])
cy.get('[data-cy="selection-6-field-2"]')
.should('be.disabled')
.contains(SECollectionOptions[1])
cy.get('[data-cy="selection-6-field-3"]')
.should('be.disabled')
.contains(SECollectionOptions[4])

cy.get('[data-cy="sc-7-answer-option-1"]').should('be.disabled')
cy.get('[data-cy="sc-7-answer-option-2"]').should('be.disabled')
}

function checkGradingVisualization(
Expand Down Expand Up @@ -967,6 +1027,9 @@ describe('Create and solve a group activity', () => {
'exist'
)

// check that the answers are persistent and the fields disabled
checkPersistentAnswers()

// check grading
checkGradingVisualization(scores1, comments1, gradingComment1)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mutation GradeGroupActivitySubmission(
choicesResponse
numericalResponse
contentResponse
selectionResponse
}

resultsComputedAt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ query GetGradingGroupActivity($id: String!) {
choicesResponse
numericalResponse
contentResponse
selectionResponse
}

resultsComputedAt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ query GroupActivityDetails($activityId: String!, $groupId: String!) {
choicesResponse
numericalResponse
contentResponse
selectionResponse
}

resultsComputedAt
Expand Down
20 changes: 20 additions & 0 deletions packages/graphql/src/ops.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -8455,6 +8455,26 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "selectionResponse",
"description": null,
"args": [],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "type",
"description": null,
Expand Down
Loading
Loading