UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

370 lines (332 loc) • 11.8 kB
import {expect} from '@instructure/ui-test-utils' import FillBlankInteractionType from '../fill_blank' import checkUserResponseTransform from '../../__tests__/sharedRecordTests' describe('FillBlankInteractionType', () => { const FITBRecordType = FillBlankInteractionType const intType = new FITBRecordType() describe('#getDefaultInteractionData', () => { it('returns one stemItem in stemItems when slug is "fill-blank" ', () => { const stemItems = intType.getDefaultInteractionData().stemItems expect(stemItems.length).to.be.equal(1) expect(stemItems[0].type).to.be.equal('text') expect(stemItems[0].value).to.be.equal('') expect(stemItems[0].position).to.be.equal(1) }) }) describe('#getDefaultScoringData', () => { it('returns the correct data', () => { expect(intType.getDefaultScoringData()).to.deep.eq({value: []}) }) }) describe('#getDefaultUserResponse', () => { it('returns the correct data', () => { expect(intType.getDefaultUserResponse()).to.deep.eq({value: []}) }) }) describe('#errors', () => { it('is valid with good data', () => { const validItemData = { itemBody: 'some item body', interactionData: { blanks: [{id: '1', itemBody: 'something'}], stemItems: [], }, scoringData: {}, } expect(intType.getErrors(validItemData)).to.be.empty() }) it('is invalid without blanks', () => { const dataWithoutBlanks = { itemBody: 'some item body', interactionData: { blanks: [], stemItems: [], }, scoringData: {}, } expect(intType.getErrors(dataWithoutBlanks).interactionData.blanks.$errors).to.be.eql([ 'You must have a blank. e.g.: "Roses are `red`, violets are `blue`"', ]) }) it('is invalid with a single choice in a dropdown', () => { const dataWithSingleBlank = { itemBody: 'some item body', interactionData: { blanks: [ { choices: [{itemBody: 'a single choice'}], }, ], stemItems: [], }, scoringData: {}, } expect( intType.getErrors(dataWithSingleBlank).interactionData.blanks[0].choices.$errors, ).to.be.eql(['You must have more than one choice']) }) it('is invalid with a possible choice that is an empty string', () => { const dataWithBodylessBlank = { itemBody: 'some item body', interactionData: { blanks: [ { choices: [{itemBody: 'a single choice'}, {itemBody: ''}], }, ], stemItems: [], }, scoringData: {}, } expect( intType.getErrors(dataWithBodylessBlank).interactionData.blanks[0].choices[1].itemBody[0], ).to.be.eql('Choice cannot be blank') }) describe('Levenshtein Distance', () => { const makeData = distanceVal => ({ itemBody: 'some item body', interactionData: { blanks: [{id: '1', itemBody: 'something'}], stemItems: [], }, scoringData: { value: [ { scoringAlgorithm: 'TextCloseEnough', scoringData: { blankText: 'correct answer', editDistance: distanceVal, }, }, ], }, }) it('is invalid with a non numeric editDistance', () => { const nonNumericData = makeData('some non numeric value') expect( intType.getErrors(nonNumericData).scoringData.value[0].scoringData.editDistance[0], ).to.be.eql('Levenshtein Distance must be a number') }) it('is invalid with a editDistance below 1', () => { const zeroDistanceData = makeData('0') expect( intType.getErrors(zeroDistanceData).scoringData.value[0].scoringData.editDistance[0], ).to.be.eql('Levenshtein Distance must be greater than zero') }) it('is invalid with a non-integer editDistance', () => { const nonIntData = makeData('1.2') expect( intType.getErrors(nonIntData).scoringData.value[0].scoringData.editDistance[0], ).to.be.eql('Levenshtein Distance must be an integer') }) it('is invalid with an editDistance greater than length of break content', () => { const nonIntData = makeData('100') expect( intType.getErrors(nonIntData).scoringData.value[0].scoringData.editDistance[0], ).to.be.eql('Levenshtein Distance must be less than the length of the blank text') }) }) it('is invalid without a correct choice for blank', () => { const withoutCorrectChoice = { itemBody: 'some item body', interactionData: { blanks: [{id: '1', itemBody: 'something'}], stemItems: [], }, scoringData: { value: [ { scoringAlgorithm: 'TextInChoices', scoringData: { blankText: 'correct answer', value: [], }, }, ], }, } expect( intType.getErrors(withoutCorrectChoice).scoringData.value[0].scoringData.value.$errors, ).to.be.eql(['You must have an answer']) }) it('is invalid with an empty correct choice for blank', () => { const withNullCorrectChoice = { itemBody: 'some item body', interactionData: { blanks: [{id: '1', itemBody: 'something'}], stemItems: [], }, scoringData: { value: [ { scoringAlgorithm: 'TextEntryMatches', scoringData: { blankText: 'correct answer', value: null, }, }, ], }, } expect( intType.getErrors(withNullCorrectChoice).scoringData.value[0].scoringData.value.$errors[0], ).to.be.eql('Correct value cannot be blank') }) it('is invalid with a specific correct choice that is an empty string', () => { const withEmptyCorrectChoice = { itemBody: 'some item body', interactionData: { blanks: [{id: '1', itemBody: 'something'}], stemItems: [], }, scoringData: { value: [ { scoringAlgorithm: 'TextInChoices', scoringData: { blankText: 'also valid', value: ['valid', 'also valid', ''], }, }, ], }, } expect( intType.getErrors(withEmptyCorrectChoice).scoringData.value[0].scoringData.value[2][0], ).to.be.eql('Correct value cannot be blank') }) it('does not run TextInChoices rules for non-TextInChoices', () => { const data = { itemBody: 'some item body', interactionData: { blanks: [{id: '1', itemBody: 'something'}], stemItems: [], }, scoringData: { value: [ { scoringAlgorithm: 'TextCloseEnough', scoringData: { blankText: 'correct answer', editDistance: 33, value: '', }, }, ], }, } expect(intType.getErrors(data).scoringData.value[0].scoringData.value).to.eql({ $errors: ['Correct value cannot be blank'], }) }) }) describe('#hasResponse', () => { it('returns true when all blanks have a response', () => { const resp = [ {id: 1, value: 'one'}, {id: 2, value: 'two'}, {id: 3, value: 'three'}, ] const intData = {blanks: [1, 2, 3]} expect(intType.hasResponse(resp, intData)).to.be.true() }) it('returns false when there is no response', () => { const resp = [] const intData = {blanks: [1, 2, 3]} expect(intType.hasResponse(resp, intData)).to.be.false() }) it('returns false when only partially answered', () => { const resp = [ {id: 1, value: 'one'}, {id: 2, value: 'two'}, ] const intData = {blanks: [1, 2, 3]} expect(intType.hasResponse(resp, intData)).to.be.false() }) it('returns false when previously answered, but deleted', () => { const resp = [ {id: 1, value: ''}, {id: 2, value: ''}, {id: 3, value: ''}, ] const intData = {blanks: [1, 2, 3]} expect(intType.hasResponse(resp, intData)).to.be.false() }) }) const interactionData = { stemItems: [ {id: 'stem_uuid-1', position: 1, type: 'text', value: ' '}, {id: 'stem_uuid0', position: 2, type: 'blank', blankId: 'fitb_uuid1'}, {id: 'stem_uuid1', position: 3, type: 'text', value: ' Columbus sailed in '}, {id: 'stem_uuid2', position: 4, type: 'blank', blankId: 'fitb_uuid2'}, {id: 'stem_uuid3', position: 5, type: 'text', value: ' from the country of '}, {id: 'stem_uuid4', position: 6, type: 'blank', blankId: 'fitb_uuid3'}, {id: 'stem_uuid5', position: 7, type: 'text', value: ' on the continent of '}, {id: 'stem_uuid6', position: 8, type: 'blank', blankId: 'fitb_uuid4'}, {id: 'stem_uuid7', position: 9, type: 'text', value: ' across the '}, {id: 'stem_uuid8', position: 10, type: 'blank', blankId: 'fitb_uuid5'}, {id: 'stem_uuid9', position: 11, type: 'text', value: ' and found '}, {id: 'stem_uuid10', position: 12, type: 'blank', blankId: 'fitb_uuid6'}, {id: 'stem_uuid11', position: 13, type: 'text', value: '.'}, {id: 'stem_uuid12', position: 14, type: 'text', value: ' Where the people were '}, {id: 'stem_uuid13', position: 15, type: 'blank', blankId: 'fitb_uuid7'}, {id: 'stem_uuid14', position: 16, type: 'text', value: '.'}, ], blanks: [ { id: 'fitb_uuid1', answerType: 'openEntry', }, { id: 'fitb_uuid2', answerType: 'openEntry', }, { id: 'fitb_uuid3', answerType: 'openEntry', }, { id: 'fitb_uuid4', answerType: 'openEntry', }, { id: 'fitb_uuid5', answerType: 'openEntry', }, { id: 'fitb_uuid6', choices: [ {id: 'choice_uuid11_brazil', position: 1, itemBody: 'Brazil'}, {id: 'choice_uuid12_austria', position: 2, itemBody: 'Austria'}, {id: 'choice_uuid13_america', position: 3, itemBody: 'America'}, ], answerType: 'wordbank', }, { id: 'fitb_uuid7', choices: [ {id: 'choice_uuid11_peaceful', position: 1, itemBody: 'peaceful'}, {id: 'choice_uuid12_war-torn', position: 2, itemBody: 'war-torn'}, {id: 'choice_uuid13_confused', position: 3, itemBody: 'confused'}, ], answerType: 'dropdown', }, ], } const validResponse = [{id: 'fitb_uuid1', value: 'Christopher', type: 'Text'}] const invalidResponse = [{id: 'uuid1', value: 'Christopher', type: 'Text'}] const validResponse2 = [{id: 'fitb_uuid7', value: 'choice_uuid11_peaceful', type: 'Text'}] const invalidResponse2 = [{id: 'fitb_uuid7', value: 'choice_uuid11_peaceful_not', type: 'Text'}] checkUserResponseTransform( new FITBRecordType(), {response: validResponse, interactionData, expected: 'Blank 1: Christopher'}, {response: invalidResponse, interactionData, expected: 'Blank 0: '}, out => out.props.children, ) checkUserResponseTransform( new FITBRecordType(), {response: validResponse2, interactionData, expected: 'Blank 7: peaceful'}, {response: invalidResponse2, interactionData, expected: 'Blank 7: '}, out => out.props.children, ) })