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

Assessment edit page fixes #2163

Merged
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
2 changes: 2 additions & 0 deletions app/views/course/assessment/assessments/_edit.json.jbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ json.attributes do
end

json.mode_switching @assessment.allow_mode_switching?
json.gamified current_course.gamified?

json.folder_attributes do
json.folder_id @assessment.folder.id
json.materials @assessment.materials.order(:name) do |material|
Expand Down
2 changes: 1 addition & 1 deletion app/views/course/assessment/assessments/index.html.slim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
= page_header format_inline_text(@category.title) do
- if can?(:create, Course::Assessment.new(tab: @tab))
div.pull-right
div.new-btn data="#{{ tab_id: @tab.id, category_id: @category.id }.to_json}"
div.new-btn data="#{{ gamified: current_course.gamified?, tab_id: @tab.id, category_id: @category.id }.to_json}"

= display_assessment_tabs

Expand Down
8 changes: 8 additions & 0 deletions client/.eslintrc.test
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,13 @@
"rules": {
"react/no-find-dom-node": "off",
"react/jsx-filename-extension": "off",
"import/no-extraneous-dependencies": "off",
"import/extensions": "off",
"import/no-unresolved": [
"error",
{
"ignore": [ 'utils/' ]
}
]
},
}
55 changes: 55 additions & 0 deletions client/app/__test__/utils/__test__/shallowUntil.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { PropTypes } from 'react';
import shallowUntil from '../shallowUntil';

describe('#shallowUntil', () => {
const Div = () => <div />;
const hoc = Component => () => <Component />;

it('shallow renders the current wrapper one level deep', () => {
const EnhancedDiv = hoc(Div);
const wrapper = shallowUntil(<EnhancedDiv />, 'Div');
expect(wrapper.contains(<div />)).toBeTruthy();
});

it('shallow renders the current wrapper several levels deep', () => {
const EnhancedDiv = hoc(hoc(hoc(Div)));
const wrapper = shallowUntil(<EnhancedDiv />, 'Div');
expect(wrapper.contains(<div />)).toBeTruthy();
});

it('shallow renders the current wrapper even if the selector never matches', () => {
const EnhancedDiv = hoc(Div);
const wrapper = shallowUntil(<EnhancedDiv />, 'NotDiv');
expect(wrapper.contains(<div />)).toBeTruthy();
});

it('stops shallow rendering when it encounters a DOM element', () => {
const wrapper = shallowUntil(<div><Div /></div>, 'Div');
expect(wrapper.contains(<div><Div /></div>)).toBeTruthy();
});

describe('with context', () => {
const Foo = () => <Div />;
Foo.contextTypes = { open: PropTypes.bool.isRequired };

class Bar extends React.Component {
static childContextTypes = { open: PropTypes.bool }
getChildContext = () => ({ open: true })
render = () => <Foo />
}

it('passes down context from the root component', () => {
const EnhancedFoo = hoc(Foo);
const wrapper = shallowUntil(<EnhancedFoo />, { context: { open: true } }, 'Foo');
expect(wrapper.context('open')).toEqual(true);
expect(wrapper.contains(<Div />)).toBeTruthy();
});

it('passes down context from an intermediary component', () => {
const EnhancedBar = hoc(Bar);
const wrapper = shallowUntil(<EnhancedBar />, 'Foo');
expect(wrapper.context('open')).toEqual(true);
expect(wrapper.contains(<Div />)).toBeTruthy();
});
});
});
41 changes: 41 additions & 0 deletions client/app/__test__/utils/shallowUntil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { shallow } from 'enzyme';

// See https://github.com/airbnb/enzyme/issues/539 and the `until` helper was borrowed from there.
function until(selector, {context} = this.options) {
if (!selector || this.isEmptyRender() || typeof this.node.type === 'string')
return this;

const instance = this.instance();
if (instance.getChildContext) {
context = {
...context,
...instance.getChildContext(),
}
}

return this.is(selector)
? this.shallow({context})
: until.call(this.shallow({context}), selector, {context})
}



/**
* Shallow renders the component until the component matches the selector.
* This is useful when the component you want to test is nested inside another component.
* example:
* ```
* const component = <Provider>
* <MyComponent />
* </Provider>
* ```
* In the above case, `shallow(component)` will render the <Provider />, and
* `shallowUntil(component, 'MyComponent')` will render <MyComponent />
*/
export default function shallowUntil(component, options, selector) {
if (selector === undefined) {
selector = options;
options = undefined;
}
return until.call(shallow(component, options), selector);
}
1 change: 1 addition & 0 deletions client/app/bundles/course/assessment/assessments-edit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ $(document).ready(() => {
<ProviderWrapper store={store}>
<AssessmentEditPage
modeSwitching={data.mode_switching}
gamified={data.gamified}
folderAttributes={data.folder_attributes}
conditionAttributes={data.condition_attributes}
initialValues={{ ...data.attributes, password_protected: !!data.attributes.password }}
Expand Down
1 change: 1 addition & 0 deletions client/app/bundles/course/assessment/assessments-index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ $(document).ready(() => {
const Page = () => (
<ProviderWrapper store={store}>
<AssessmentIndexPage
gamified={attributes.gamified}
categoryId={attributes.category_id}
tabId={attributes.tab_id}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class AssessmentForm extends React.Component {
onSubmit: PropTypes.func.isRequired,
// If the Form is in editing mode, `published` button will be displayed.
editing: PropTypes.bool,
// if the EXP fields should be displayed
gamified: PropTypes.bool,
// If allow to switch between autoraded and manually graded mode.
modeSwitching: PropTypes.bool,
folderAttributes: PropTypes.shape({
Expand All @@ -103,6 +105,10 @@ class AssessmentForm extends React.Component {
}),
};

static defaultProps = {
gamified: true,
}

onStartAtChange = (_, newStartAt) => {
const { start_at: startAt, end_at: endAt, bonus_end_at: bonusEndAt, dispatch } = this.props;
const newStartTime = newStartAt && newStartAt.getTime();
Expand Down Expand Up @@ -196,7 +202,7 @@ class AssessmentForm extends React.Component {
}

render() {
const { handleSubmit, onSubmit, modeSwitching, submitting, editing, folderAttributes,
const { handleSubmit, onSubmit, gamified, modeSwitching, submitting, editing, folderAttributes,
conditionAttributes } = this.props;

return (
Expand Down Expand Up @@ -232,35 +238,41 @@ class AssessmentForm extends React.Component {
style={styles.flexChild}
disabled={submitting}
/>
<Field
name="bonus_end_at"
component={DateTimePicker}
floatingLabelText={<FormattedMessage {...translations.bonusEndAt} />}
style={styles.flexChild}
disabled={submitting}
/>
</div>
<div style={styles.flexGroup}>
<Field
name="base_exp"
component={TextField}
floatingLabelText={<FormattedMessage {...translations.baseExp} />}
type="number"
style={styles.flexChild}
disabled={submitting}
/>
<Field
name="time_bonus_exp"
component={TextField}
floatingLabelText={<FormattedMessage {...translations.timeBonusExp} />}
type="number"
style={styles.flexChild}
disabled={submitting}
/>
{
gamified &&
<Field
name="bonus_end_at"
component={DateTimePicker}
floatingLabelText={<FormattedMessage {...translations.bonusEndAt} />}
style={styles.flexChild}
disabled={submitting}
/>
}
</div>
{
gamified &&
<div style={styles.flexGroup}>
<Field
name="base_exp"
component={TextField}
floatingLabelText={<FormattedMessage {...translations.baseExp} />}
type="number"
style={styles.flexChild}
disabled={submitting}
/>
<Field
name="time_bonus_exp"
component={TextField}
floatingLabelText={<FormattedMessage {...translations.timeBonusExp} />}
type="number"
style={styles.flexChild}
disabled={submitting}
/>
</div>
}

{
this.props.editing &&
editing &&
<Field
name="published"
component={Toggle}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,19 @@ jest.mock('lib/components/redux-form/RichTextField', () => {
});

describe('<AssessmentEdit />', () => {
const store = storeCreator({});
const id = 1;
const intitialValues = {
id,
title: 'Assessement',
description: 'Awesome assessment',
autograded: false,
start_at: new Date(),
base_exp: 0,
time_bonus_exp: 0,
};

it('renders the edit page', async () => {
const store = storeCreator({});
const id = 1;
const intitialValues = {
id,
title: 'Assessement',
description: 'Awesome assessment',
autograded: false,
start_at: new Date(),
base_exp: 0,
time_bonus_exp: 0,
};
const editPage = mount(
<ProviderWrapper store={store}>
<AssessmentEdit
Expand Down Expand Up @@ -58,4 +59,37 @@ describe('<AssessmentEdit />', () => {
expect(spy).toHaveBeenCalledWith(id,
{ assessment: { ...intitialValues, title: newTitle, autograded: true, password: null } });
});

it('renders the gamified fields by default', () => {
const editPage = mount(
<ProviderWrapper store={store}>
<AssessmentEdit
id={id}
modeSwitching
initialValues={intitialValues}
/>
</ProviderWrapper>
);

expect(editPage.find('input[name="bonus_end_at"]').length).toBeGreaterThan(0);
expect(editPage.find('input[name="base_exp"]').length).toBeGreaterThan(0);
expect(editPage.find('input[name="time_bonus_exp"]').length).toBeGreaterThan(0);
});

it('does not render the gamified fields', () => {
const editPage = mount(
<ProviderWrapper store={store}>
<AssessmentEdit
id={id}
gamified={false}
modeSwitching
initialValues={intitialValues}
/>
</ProviderWrapper>
);

expect(editPage.find('input[name="bonus_end_at"]')).toHaveLength(0);
expect(editPage.find('input[name="base_exp"]')).toHaveLength(0);
expect(editPage.find('input[name="time_bonus_exp"]')).toHaveLength(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class EditPage extends React.Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
intl: intlShape,
// If the gamification feature is enabled in the course.
gamified: PropTypes.bool,
// If allow to switch between autoraded and manually graded mode.
modeSwitching: PropTypes.bool,
// An array of materials of current assessment.
Expand Down Expand Up @@ -53,13 +55,14 @@ class EditPage extends React.Component {
};

render() {
const { modeSwitching, initialValues, folderAttributes,
const { gamified, modeSwitching, initialValues, folderAttributes,
conditionAttributes, dispatch } = this.props;

return (
<div>
<AssessmentForm
editing
gamified={gamified}
onSubmit={this.onFormSubmit}
modeSwitching={modeSwitching}
folderAttributes={folderAttributes}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class PopupDialog extends React.Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
intl: intlShape,
// If the gamification feature is enabled in the course.
gamified: PropTypes.bool,
categoryId: PropTypes.number.isRequired,
tabId: PropTypes.number.isRequired,
pristine: PropTypes.bool,
Expand Down Expand Up @@ -108,6 +110,7 @@ class PopupDialog extends React.Component {
contentStyle={styles.dialog}
>
<AssessmentForm
gamified={this.props.gamified}
modeSwitching
onSubmit={this.onFormSubmit}
initialValues={initialValues}
Expand Down
21 changes: 0 additions & 21 deletions client/app/lib/components/redux-form/Toggle.js

This file was deleted.

Loading