Skip to content

[QTI] Editor saves leading and trailing whitespace in answer values #6264

Description

@AlexVelezLl

❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.

Target branch: unstable

Observed behavior

The QTI editor writes text-entry answers and inline choice options to the item XML with any whitespace the author typed around them:

  • Text entry: an answer typed as Paris is saved as <qti-value>Paris </qti-value>, while its <qti-map-entry map-key="Paris"> is trimmed. On reload the parser trims <qti-value>, so what the editor shows no longer matches what is stored.
  • Inline choice: an option typed as a is saved as <qti-inline-choice>a </qti-inline-choice>. Validation already trims option text, so a and a are flagged as duplicates, yet both are saved as different values.
  • Publish: the derived Perseus item for a text-entry question copies the untrimmed <qti-value> into its answers (perseus_derive._correct_values doesn't strip).

Errors and logs

None.

Expected behavior

Text-entry answers and inline choice option text are trimmed when the item is serialized, so the stored XML matches what the editor validates and shows after a reload. Rich-text content (prompts, choices, ordering items, hints) is out of scope.

This matches the legacy editor, which never stored surrounding whitespace: its Markdown serializer trimmed every field on save, numeric answers came from an <input type="number">, and parse_valid_number strips them on publish.

User-facing consequences

  • Learners can be marked wrong for a correct answer: QTI string matching is exact, so a stored Paris may not match a learner's Paris.
  • Authors see an answer that differs from the stored one after reopening the question.

Steps to reproduce

  1. Open a channel's exercise and add a text-entry question.
  2. Enter an answer with a trailing space, e.g. Paris , and save.
  3. Inspect the item's raw_data: <qti-value> holds Paris and map-key holds Paris.
  4. Repeat with an inline choice question whose option has surrounding spaces: the <qti-inline-choice> text keeps them.

Acceptance Criteria

  • Saving a text-entry question writes each <qti-value> and its map-key without leading or trailing whitespace
  • Saving an inline choice question writes each <qti-inline-choice> text without leading or trailing whitespace
  • The editor doesn't remove whitespace while the author is still typing
  • Publishing a text-entry item whose stored <qti-value> has surrounding whitespace produces trimmed Perseus answers
  • Tests cover each of the above

Context

  • Text entry: frontend/shared/views/QTIEditor/interactions/textEntry/parse.js (buildTextEntryInteractionXML)
  • Inline choice: frontend/shared/views/QTIEditor/interactions/inlineChoice/parse.js (buildInlineChoiceInteractionXML)
  • Publish derivation: contentcuration/utils/assessment/qti/perseus_derive.py (_correct_values)

AI usage

I used Claude Code to trace how each QTI editor interaction handles whitespace on parse and serialization, compare it with the removed legacy editor, and draft this issue. I reviewed the findings and edited the draft.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions