Skip to content

Commit

Permalink
add instruction text for options and word-type dropdowns; [close #105,
Browse files Browse the repository at this point in the history
  • Loading branch information
cjshaw committed Jul 31, 2017
1 parent a9b520c commit bcf0338
Show file tree
Hide file tree
Showing 16 changed files with 296 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,24 @@ export class Question extends React.Component {
[types.shortAnswer]: ShortAnswer,
[types.fileUpload]: FileUpload,
[types.audioUpload]: AudioUpload,
[types.movableWordSandbox]: MovableWordSandbox,
[types.movableWordSentence]: WordSentence,
[types.dragAndDrop]: DragAndDrop,
[types.imageSequence]: ImageSequence,
};

static optionInstructionsLeft = {
[types.movableFillBlank]: 'fitbLeft',
[types.movableWordSentence]: 'mwLeft',
[types.multipleAnswer]: 'mcmaLeft',
[types.multipleChoice]: 'mcLeft',
[types.imageSequence]: 'imageSequenceLeft',
};

static optionInstructionsRight = {
[types.movableFillBlank]: 'fitbRight',
[types.movableWordSandbox]: 'mwRight',
[types.movableWordSentence]: 'mwRight'
};

static stateDrivenTypes = [
types.movableWordSentence,
types.imageSequence,
Expand Down Expand Up @@ -250,6 +262,48 @@ export class Question extends React.Component {
return { [toDelete.id]: toDelete };
}

contentInstructions() {
const { item } = this.props;
const leftInstructionsKey = _.get(Question.optionInstructionsLeft,
item.type,
null);
const rightInstructionsKey = _.get(Question.optionInstructionsRight,
item.type,
null);
const instructionStrings = this.props.localizeStrings('optionInstructions');
let leftInstructions = (
<div className="au-c-question__option-instructions-left" />
);
let rightInstructions;

if (leftInstructionsKey) {
leftInstructions = (
<div className="au-c-question__option-instructions-left">
{instructionStrings[leftInstructionsKey]}
</div>
);
}
if (rightInstructionsKey) {
rightInstructions = (
<div className="au-c-question__option-instructions-right">
{instructionStrings[rightInstructionsKey]}
</div>
);
}

if (this.props.isActive &&
_.keys(item.question.choices).length > 0 &&
(leftInstructions || rightInstructions)) {
return (
<div className="au-c-question__option-instructions">
{leftInstructions}
{rightInstructions}
</div>
);
}
return null;
}

content() {
const { bankId, item } = this.props;
const Component = Question.questionComponents[this.props.item.type];
Expand All @@ -270,6 +324,7 @@ export class Question extends React.Component {
language={this.state.language}
save={() => this.saveStateItem()}
duplicateAnswers={this.getDuplicateAnswers()}
instructions={this.contentInstructions()}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { shallow } from 'enzyme';
import { Question } from './_question';
import shortAnswer from './short_answer';
Expand All @@ -9,9 +10,18 @@ describe('question component', () => {
let props;
let result;
let movedUp;
let itemUpdated;
let itemUpdated
let iframe;
let div;

beforeEach(() => {
// for iframe / instructions tests:
// https://stackoverflow.com/a/33404017
// https://stackoverflow.com/a/39671492
iframe = document.createElement('iframe');
document.body.appendChild(iframe);
div = document.createElement('div');

movedUp = false;
itemUpdated = false;
props = {
Expand Down Expand Up @@ -109,4 +119,174 @@ describe('question component', () => {
const div = result.find('.is-active');
expect(div.length).toBe(1);
});

it('generates no instructions when inactive, without choices', () => {
props.item.type = 'multipleChoice';
props.item.question.choices = {};
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
expect(instructions).toBe(null);
});

it('generates no instructions when inactive, even with choices', () => {
props.item.type = 'multipleChoice';
props.item.question.choices = {
123: 'foo'
};
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
expect(instructions).toBe(null);
});

it('generates no instructions when active, with no choices', () => {
props.item.type = 'multipleChoice';
props.item.question.choices = {};
props.isActive = true;
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
expect(instructions).toBe(null);
});

it('generates instructions when active with choices, MC', () => {
props.item.type = 'multipleChoice';
props.item.question.choices = {
123: 'foo'
};
props.isActive = true;
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
iframe.contentDocument.body.appendChild(div);
ReactDOM.render(instructions, div);

const instructionBlock = div.querySelectorAll('.au-c-question__option-instructions');
expect(instructionBlock.length).toBe(1);

// this should always be there, to provide left-padding for
// components with right-only instructions, like MW Sandbox
const instructionLeft = div.querySelectorAll('.au-c-question__option-instructions-left');
expect(instructionLeft.length).toBe(1);

const instructionRight = div.querySelectorAll('.au-c-question__option-instructions-right');
expect(instructionRight.length).toBe(0);
});

it('generates instructions when active with choices, MC multi-answer', () => {
props.item.type = 'multipleAnswer';
props.item.question.choices = {
123: 'foo'
};
props.isActive = true;
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
iframe.contentDocument.body.appendChild(div);
ReactDOM.render(instructions, div);

const instructionBlock = div.querySelectorAll('.au-c-question__option-instructions');
expect(instructionBlock.length).toBe(1);

// this should always be there, to provide left-padding for
// components with right-only instructions, like MW Sandbox
const instructionLeft = div.querySelectorAll('.au-c-question__option-instructions-left');
expect(instructionLeft.length).toBe(1);

const instructionRight = div.querySelectorAll('.au-c-question__option-instructions-right');
expect(instructionRight.length).toBe(0);
});

it('generates instructions when active with choices, FITB', () => {
props.item.type = 'movableFillBlank';
props.item.question.choices = {
123: 'foo'
};
props.isActive = true;
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
iframe.contentDocument.body.appendChild(div);
ReactDOM.render(instructions, div);

const instructionBlock = div.querySelectorAll('.au-c-question__option-instructions');
expect(instructionBlock.length).toBe(1);

// this should always be there, to provide left-padding for
// components with right-only instructions, like MW Sandbox
const instructionLeft = div.querySelectorAll('.au-c-question__option-instructions-left');
expect(instructionLeft.length).toBe(1);

const instructionRight = div.querySelectorAll('.au-c-question__option-instructions-right');
expect(instructionRight.length).toBe(1);
});

it('generates instructions when active with choices, image sequence', () => {
props.item.type = 'imageSequence';
props.item.question.choices = {
123: 'foo'
};
props.isActive = true;
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
iframe.contentDocument.body.appendChild(div);
ReactDOM.render(instructions, div);

const instructionBlock = div.querySelectorAll('.au-c-question__option-instructions');
expect(instructionBlock.length).toBe(1);

// this should always be there, to provide left-padding for
// components with right-only instructions, like MW Sandbox
const instructionLeft = div.querySelectorAll('.au-c-question__option-instructions-left');
expect(instructionLeft.length).toBe(1);

const instructionRight = div.querySelectorAll('.au-c-question__option-instructions-right');
expect(instructionRight.length).toBe(0);
});

it('generates instructions when active with choices, MW sandbox', () => {
props.item.type = 'movableWordSandbox';
props.item.question.choices = {
123: 'foo'
};
props.isActive = true;
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
iframe.contentDocument.body.appendChild(div);
ReactDOM.render(instructions, div);

const instructionBlock = div.querySelectorAll('.au-c-question__option-instructions');
expect(instructionBlock.length).toBe(1);

// this should always be there, to provide left-padding for
// components with right-only instructions, like MW Sandbox
const instructionLeft = div.querySelectorAll('.au-c-question__option-instructions-left');
expect(instructionLeft.length).toBe(1);

const instructionRight = div.querySelectorAll('.au-c-question__option-instructions-right');
expect(instructionRight.length).toBe(1);
});

it('generates instructions when active with choices, MW sentence', () => {
props.item.type = 'movableWordSentence';
props.item.question.choices = {
123: 'foo'
};
props.isActive = true;
result = shallow(<Question {...props} />);
const instructions = result.instance().contentInstructions();
iframe.contentDocument.body.appendChild(div);
ReactDOM.render(instructions, div);

const instructionBlock = div.querySelectorAll('.au-c-question__option-instructions');
expect(instructionBlock.length).toBe(1);

// this should always be there, to provide left-padding for
// components with right-only instructions, like MW Sandbox
const instructionLeft = div.querySelectorAll('.au-c-question__option-instructions-left');
expect(instructionLeft.length).toBe(1);

const instructionRight = div.querySelectorAll('.au-c-question__option-instructions-right');
expect(instructionRight.length).toBe(1);
});

afterEach(() => {
// https://stackoverflow.com/a/33404017
document.body.removeChild(iframe);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ImageSequence extends React.Component {
isActive: React.PropTypes.bool,
language: React.PropTypes.string.isRequired,
duplicateAnswers: React.PropTypes.arrayOf(React.PropTypes.string),
instructions: React.PropTypes.shape({}),
};

constructor(props) {
Expand Down Expand Up @@ -65,6 +66,7 @@ class ImageSequence extends React.Component {
render() {
return (
<div style={{ display: this.props.isActive ? 'block' : 'none' }}>
{this.props.instructions}
<ImageOrder
language={this.props.language}
activateChoice={choiceId => this.activateChoice(choiceId)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ describe('image sequence component', () => {
activateChoice: () => {},
save: () => {},
language: 'eng',
instructions: 'do something'
};
result = shallow(<ImageSequence {...props} />);
});
Expand All @@ -66,4 +67,8 @@ describe('image sequence component', () => {
feedback.at(0).nodes[0].props.updateItem();
expect(calledFunc).toBeTruthy();
});

it('does render the passed-in instructions', () => {
expect(result.text()).toContain('do something');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class MovableFillBlank extends React.Component {
isActive: React.PropTypes.bool,
activeChoice: React.PropTypes.string,
language: React.PropTypes.string.isRequired,
instructions: React.PropTypes.shape({}),
};

render() {
Expand All @@ -37,6 +38,7 @@ class MovableFillBlank extends React.Component {
<div>
<div className="au-c-question__answers au-c-fill-in-the-blank__answers">
<div className="au-no-outline" onBlur={e => this.props.blurOptions(e)} tabIndex="-1">
{this.props.instructions}
{
_.map(_.orderBy(question.choices, 'order'), choice => (
<Option
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ describe('movable_fill_blank component', () => {
isActive: false,
activeChoice: '',
language: 'eng',
instructions: 'do something'
};
result = shallow(<MovableFillBlank {...props} />);
});
Expand Down Expand Up @@ -111,4 +112,8 @@ describe('movable_fill_blank component', () => {
add.at(0).nodes[0].props.createChoice();
expect(calledFunc).toBeTruthy();
});

it('does render the passed-in instructions', () => {
expect(result.text()).toContain('do something');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class MovableWordSentence extends React.Component {
activeChoice: React.PropTypes.string,
language: React.PropTypes.string.isRequired,
duplicateAnswers: React.PropTypes.arrayOf(React.PropTypes.string),
instructions: React.PropTypes.shape({}),

};

render() {
Expand All @@ -38,6 +40,7 @@ class MovableWordSentence extends React.Component {
className="au-c-question__answers au-c-movable__answers"
onBlur={e => this.props.blurOptions(e)} tabIndex="-1"
>
{this.props.instructions}
{
_.map(question.choices, choice => (
<Option
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ describe('movable word sentece component', () => {
activeChoice: '',
save: () => {},
language: 'eng',
instructions: 'do something'
};
result = shallow(<MovableWordSentence {...props} />);
});
Expand Down Expand Up @@ -109,4 +110,8 @@ describe('movable word sentece component', () => {
result.find('.au-c-movable__answers').simulate('blur', { target: { value: 'Preposition' } });
expect(calledFunc).toBeTruthy();
});

it('does render the passed-in instructions', () => {
expect(result.text()).toContain('do something');
});
});
Loading

0 comments on commit bcf0338

Please sign in to comment.