feat(client): show and execute backend project tests (#35673)
This commit is contained in:
		@@ -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}
 | 
			
		||||
              />
 | 
			
		||||
              {challengeType === backend ? (
 | 
			
		||||
                <Form
 | 
			
		||||
                buttonText={`${buttonCopy} (Ctrl + Enter)`}
 | 
			
		||||
                  buttonText={`${buttonCopy}`}
 | 
			
		||||
                  formFields={formFields}
 | 
			
		||||
                  id={backendNS}
 | 
			
		||||
                  options={options}
 | 
			
		||||
                  submit={executeChallenge}
 | 
			
		||||
                />
 | 
			
		||||
              ) : (
 | 
			
		||||
                <ProjectForm
 | 
			
		||||
                  isFrontEnd={false}
 | 
			
		||||
                  onSubmit={executeChallenge}
 | 
			
		||||
                  updateProjectForm={updateProjectFormValues}
 | 
			
		||||
                />
 | 
			
		||||
              )}
 | 
			
		||||
              <ProjectToolPanel guideUrl={createGuideUrl(slug)} />
 | 
			
		||||
              <br />
 | 
			
		||||
              <Output
 | 
			
		||||
 
 | 
			
		||||
@@ -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.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
 | 
			
		||||
        // )}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -117,7 +117,7 @@ export class Project extends Component {
 | 
			
		||||
          />
 | 
			
		||||
          <ProjectForm
 | 
			
		||||
            isFrontEnd={isFrontEnd}
 | 
			
		||||
            openModal={openCompletionModal}
 | 
			
		||||
            onSubmit={openCompletionModal}
 | 
			
		||||
            updateProjectForm={updateProjectFormValues}
 | 
			
		||||
          />
 | 
			
		||||
          <ToolPanel guideUrl={createGuideUrl(slug)} />
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ exports.viewTypes = {
 | 
			
		||||
  [js]: 'classic',
 | 
			
		||||
  [bonfire]: 'classic',
 | 
			
		||||
  [frontEndProject]: 'project',
 | 
			
		||||
  [backEndProject]: 'project',
 | 
			
		||||
  [backEndProject]: 'backend',
 | 
			
		||||
  [modern]: 'modern',
 | 
			
		||||
  [step]: 'step',
 | 
			
		||||
  [quiz]: 'quiz',
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user