Skip to content

Scoring & state

<qti-outcome-processing>

Declared inside <qti-assessment-test> (per the QTI spec), this element is invisible (display: none) and does nothing until outcomeProcessing() is called on the enclosing <qti-test>. That method finds the <qti-outcome-processing> element and calls process() on it, which in turn runs process() on each of its child rule elements in document order — the same rule-execution model used by item-level response processing.

qti-test-variables

A test-level expression, used inside <qti-outcome-processing> rules to aggregate a variable across multiple items — e.g. summing every item’s SCORE.

AttributeNotes
variable-identifierThe item-level variable to aggregate (e.g. SCORE).
include-category / exclude-categorySpace-separated category lists to filter which item refs contribute. An item ref qualifies when it carries one of the included categories and none of the excluded ones; its own category is a space-separated list too, and matching any entry is enough.
weight-identifierOptional per-item weight, read from each qti-assessment-item-ref’s weights map — its <qti-weight> children, keyed by identifier. An item ref that declares no such weight counts as 1.

getResult() walks every qti-assessment-item-ref in the enclosing <qti-assessment-test>, filters by category, applies weights, and sums the named variable’s value across the matching items’ current testContext. An item whose value is not a number contributes nothing rather than turning the total into NaN.

qti-number-selected

A test-level expression returning how many item references the test selected — the count of the same set qti-test-variables aggregates over, and right before any item has been attempted.

AttributeNotes
section-identifierOnly count item refs inside the <qti-assessment-section> with this identifier; every section when absent.
include-category / exclude-categoryThe same space-separated category filters qti-test-variables uses, with the same any-match / both-must-hold semantics.

section-identifier works on qti-test-variables too — both elements select their item refs the same way.

qti-number-presented

A test-level expression returning how many of those item references have been presented to the candidate. It takes the same section-identifier, include-category and exclude-category attributes as qti-number-selected.

An item counts as presented once its completionStatus has left not_attempted: presenting an item starts its first attempt. Items a linear test part passed over (a false qti-pre-condition, a qti-branch-rule that jumped past them) and items the candidate has not reached are not counted. Use it for totals over the candidate’s own route — for example a maximum score of one point per presented item, so branched-over items do not count against the candidate:

<qti-set-outcome-value identifier="MAXSCORE">
<qti-number-presented exclude-category="unscored" />
</qti-set-outcome-value>

Totals over items that were not presented

Items load when the candidate reaches them. Until then the test context holds no outcome values for them, so a sum such as MAXSCORE over qti-test-variables only covers the items seen so far. QTI gives an item that was not presented its declared defaults, but nothing at test level carries those defaults: qti-weight only multiplies, qti-variable-mapping only renames, and qti-outcome-maximum reads the item too. Fetching every item at results time just to read its declarations is a request per item; prefer, in this order:

  1. Put the total in the content. Declare it as the test outcome’s default, which outcome processing resets to before every run:

    <qti-outcome-declaration identifier="MAXSCORE" base-type="float" cardinality="single">
    <qti-default-value><qti-value>20</qti-value></qti-default-value>
    </qti-outcome-declaration>

    When every item is worth the same, count instead of sum: qti-number-selected for the whole test, or qti-number-presented for the candidate’s own route through a test with branch rules.

  2. Prepare it with the package. Read the item declarations once when the package is built or served, and hand them to the test before the first item loads: as variables of the items in a state you assign to qtiTest.state, or with qtiTest.updateItemVariables(itemRefId, values) on cito-test-loaded. Outcome processing then reads them like any other value. (initContext on test-navigation cannot carry them: it only feeds the computed context.)

qti-test-feedback

Test-level feedback, declared in <qti-assessment-test>. It renders nothing where it is declared: where and when to show it is the host’s decision. After outcomeProcessing(), qtiTest.getTestFeedback(access) returns the ones that apply — access is atEnd (the default) or during, and leaving it out returns both:

qtiTest.outcomeProcessing();
const atEnd = qtiTest.getTestFeedback('atEnd').map(feedback => feedback.innerHTML);

A feedback applies when its outcome-identifier holds its identifier (show-hide="show"), or does not (show-hide="hide"); feedback.matches(value) answers that for any value.

<test-check-item>

A “submit this attempt” button. On click it:

  1. Dispatches test-end-attempt (bubbles) — picked up by <test-navigation>, which calls processResponse(true, ...) on the active item.
  2. Dispatches test-show-correct-response with detail: true — reveals the item’s correct response.
  3. Toggles .show on every [view]-tagged element inside the current <test-container>, making scorer-only content visible immediately.

test-scoring-buttons

Renders a human-scoring UI for the active item, driven by a <template> child (via Heximal templates) so the markup is fully up to you — the component only supplies the data: { scores, score, disabled }, where scores is [0..MAXSCORE] and disabled is true unless the item’s SCORE outcome has externalScored === 'human'.

Clicking an <input> inside the template dispatches test-update-outcome-variable with { assessmentItemRefId, outcomeVariableId: 'SCORE', value }, which <test-navigation> applies to the active item.

<test-scoring-buttons>
<template>
<!-- receives { scores, score, disabled } -->
</template>
</test-scoring-buttons>

test-scoring-feedback

Renders feedback text for the active item based on completion status, SCORE, and externalScored. The actual copy is supplied via data-* attributes on the element itself — data-text-no-response, data-text-correct, data-text-incorrect, data-score-unknown, data-in-progress — so wording is fully caller-controlled; the component only picks which one applies.

test-show-correct-response — deprecated

Marked @deprecated in source. It toggled correct-response visibility via a shown state and test-show-correct-response event, but the codebase is moving toward the <template>-driven pattern used by test-scoring-buttons/test-view-toggle. Check with the team before reaching for it in new work.