feat(client): show and execute backend project tests (#35673)

This commit is contained in:
Valeriy 2019-06-11 18:46:36 +03:00 committed by mrugesh
parent 1abe4971f4
commit 839e81426e
6 changed files with 44 additions and 83 deletions

View File

@ -12,6 +12,7 @@ import {
consoleOutputSelector,
initTests,
updateChallengeMeta,
updateProjectFormValues,
backendNS
} from '../redux';
import { createGuideUrl } from '../utils';
@ -24,6 +25,7 @@ import Output from '../components/Output';
import CompletionModal from '../components/CompletionModal';
import HelpModal from '../components/HelpModal';
import ProjectToolPanel from '../project/Tool-Panel';
import ProjectForm from '../project/ProjectForm';
import {
createFormValidator,
isValidURL,
@ -32,6 +34,8 @@ import {
} from '../../../components/formHelpers';
import Spacer from '../../../components/helpers/Spacer';
import { backend } from '../../../../utils/challengeTypes';
import '../components/test-frame.css';
// provided by redux form
@ -52,6 +56,7 @@ const propTypes = {
tests: PropTypes.array,
title: PropTypes.string,
updateChallengeMeta: PropTypes.func.isRequired,
updateProjectFormValues: PropTypes.func.isRequired,
...reduxFormPropTypes
};
@ -74,7 +79,8 @@ const mapDispatchToActions = {
challengeMounted,
executeChallenge,
initTests,
updateChallengeMeta
updateChallengeMeta,
updateProjectFormValues
};
const formFields = ['solution'];
@ -150,6 +156,7 @@ export class BackEnd extends Component {
data: {
challengeNode: {
fields: { blockName, slug },
challengeType,
title,
description,
instructions
@ -158,7 +165,8 @@ export class BackEnd extends Component {
output,
tests,
submitting,
executeChallenge
executeChallenge,
updateProjectFormValues
} = this.props;
// TODO: Should be tied to user.isSignedIn
@ -177,13 +185,21 @@ export class BackEnd extends Component {
description={description}
instructions={instructions}
/>
<Form
buttonText={`${buttonCopy} (Ctrl + Enter)`}
formFields={formFields}
id={backendNS}
options={options}
submit={executeChallenge}
/>
{challengeType === backend ? (
<Form
buttonText={`${buttonCopy}`}
formFields={formFields}
id={backendNS}
options={options}
submit={executeChallenge}
/>
) : (
<ProjectForm
isFrontEnd={false}
onSubmit={executeChallenge}
updateProjectForm={updateProjectFormValues}
/>
)}
<ProjectToolPanel guideUrl={createGuideUrl(slug)} />
<br />
<Output

View File

@ -1,32 +1,18 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Form
// isValidURL,
// makeRequired,
// createFormValidator
} from '../../../components/formHelpers';
import { Form } from '../../../components/formHelpers';
const propTypes = {
isFrontEnd: PropTypes.bool,
isSubmitting: PropTypes.bool,
openModal: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
updateProjectForm: PropTypes.func.isRequired
};
const frontEndFields = ['solution'];
const backEndFields = ['solution', 'githubLink'];
// const fieldValidators = {
// solution: makeRequired(isValidURL)
// };
// const backEndFieldValidators = {
// ...fieldValidators,
// githubLink: makeRequired(isValidURL)
// };
const options = {
types: {
solution: 'url',
@ -38,64 +24,20 @@ const options = {
export class ProjectForm extends Component {
constructor(props) {
super(props);
this.state = {
keysDown: {
Control: false,
Enter: false
}
};
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
this.props.updateProjectForm({});
window.addEventListener('keydown', this.handleKeyDown);
window.addEventListener('keyup', this.handleKeyUp);
}
componentDidUpdate() {
this.props.updateProjectForm({});
}
componentWillUnmount() {
window.removeEventListener('keydown', this.handleKeyDown);
window.removeEventListener('keyup', this.handleKeyUp);
}
handleKeyDown(e) {
if (e.key === 'Control') {
this.setState(state => ({
...state,
keysDown: { ...state.keysDown, Control: true }
}));
}
if (e.key === 'Enter') {
this.setState(state => ({
...state,
keysDown: { ...state.keysDown, Enter: true }
}));
}
}
handleKeyUp(e) {
if (e.key === 'Control') {
this.setState(state => ({
...state,
keysDown: { ...state.keysDown, Control: false }
}));
}
if (e.key === 'Enter') {
this.setState(state => ({
...state,
keysDown: { ...state.keysDown, Enter: false }
}));
}
this.props.updateProjectForm({});
}
handleSubmit(values) {
const {
keysDown: { Control, Enter }
} = this.state;
if ((Control && Enter) || !Enter) {
this.props.openModal('completion');
this.props.updateProjectForm(values);
}
this.props.updateProjectForm(values);
this.props.onSubmit();
}
render() {
const { isSubmitting, isFrontEnd } = this.props;
@ -104,14 +46,11 @@ export class ProjectForm extends Component {
: "I've completed this challenge";
return (
<Form
buttonText={`${buttonCopy} (Ctrl + Enter)`}
buttonText={`${buttonCopy}`}
formFields={isFrontEnd ? frontEndFields : backEndFields}
id={isFrontEnd ? 'front-end-form' : 'back-end-form'}
options={options}
submit={this.handleSubmit}
// validate={createFormValidator(
// isFrontEnd ? fieldValidators : backEndFieldValidators
// )}
/>
);
}

View File

@ -117,7 +117,7 @@ export class Project extends Component {
/>
<ProjectForm
isFrontEnd={isFrontEnd}
openModal={openCompletionModal}
onSubmit={openCompletionModal}
updateProjectForm={updateProjectFormValues}
/>
<ToolPanel guideUrl={createGuideUrl(slug)} />

View File

@ -192,10 +192,15 @@ export const challengeDataSelector = state => {
...challengeData,
url
};
} else if (
challengeType === challengeTypes.frontEndProject ||
challengeType === challengeTypes.backendEndProject
) {
} else if (challengeType === challengeTypes.backEndProject) {
const values = projectFormValuesSelector(state);
const { solution: url } = values;
challengeData = {
...challengeData,
...values,
url
};
} else if (challengeType === challengeTypes.frontEndProject) {
challengeData = {
...challengeData,
...projectFormValuesSelector(state)

View File

@ -61,7 +61,8 @@ const buildFunctions = {
[challengeTypes.bonfire]: buildJSChallenge,
[challengeTypes.html]: buildDOMChallenge,
[challengeTypes.modern]: buildDOMChallenge,
[challengeTypes.backend]: buildBackendChallenge
[challengeTypes.backend]: buildBackendChallenge,
[challengeTypes.backEndProject]: buildBackendChallenge
};
export async function buildChallenge(challengeData) {

View File

@ -40,7 +40,7 @@ exports.viewTypes = {
[js]: 'classic',
[bonfire]: 'classic',
[frontEndProject]: 'project',
[backEndProject]: 'project',
[backEndProject]: 'backend',
[modern]: 'modern',
[step]: 'step',
[quiz]: 'quiz',