fix(challenges): put finishing touches on react & redux challenges
This commit is contained in:
@ -50,7 +50,7 @@
|
||||
},
|
||||
"tests": [
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); return mockedComponent.find('div').text() === '' })(), 'message: The <code>DisplayMessages</code> component should render an empty <code>div</code> element.');",
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/ /g,''); return noWhiteSpace.includes('constructor(props)') && noWhiteSpace.includes('super(props'); })(), 'message: The <code>DisplayMessages</code> constructor should be called properly with <code>super</code>, passing in <code>props</code>.');",
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\\s/g,''); return noWhiteSpace.includes('constructor(props)') && noWhiteSpace.includes('super(props'); })(), 'message: The <code>DisplayMessages</code> constructor should be called properly with <code>super</code>, passing in <code>props</code>.');",
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const initialState = mockedComponent.state(); return typeof initialState === 'object' && initialState.input === '' && Array.isArray(initialState.messages) && initialState.messages.length === 0; })(), 'message: The <code>DisplayMessages</code> component should have an initial state equal to <code>{input: \"\", messages: []}</code>.');"
|
||||
],
|
||||
"solutions": [
|
||||
@ -258,7 +258,7 @@
|
||||
},
|
||||
"tests": [
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').length === 1; })(), 'message: The <code>AppWrapper</code> should render.');",
|
||||
"getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return getUserInput('index').replace(/ /g,'').includes('<Providerstore={store}>'); })(), 'message: The <code>Provider</code> wrapper component should have a prop of <code>store</code> passed to it, equal to the Redux store.');",
|
||||
"getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return getUserInput('index').replace(/\\s/g,'').includes('<Providerstore={store}>'); })(), 'message: The <code>Provider</code> wrapper component should have a prop of <code>store</code> passed to it, equal to the Redux store.');",
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').find('DisplayMessages').length === 1; })(), 'message: <code>DisplayMessages</code> should render as a child of <code>AppWrapper</code>.');",
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('div').length === 1 && mockedComponent.find('h2').length === 1 && mockedComponent.find('button').length === 1 && mockedComponent.find('ul').length === 1; })(), 'message: The <code>DisplayMessages</code> component should render an h2, input, button, and <code>ul</code> element.');"
|
||||
],
|
||||
|
@ -12,7 +12,7 @@
|
||||
"src": "https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.js"
|
||||
}
|
||||
],
|
||||
"template": "<body><div id='root'></div>${ source }</body>",
|
||||
"template": "<body><div id='root'></div><div id='challenge-node'></div>${ source }</body>",
|
||||
"challenges": [
|
||||
{
|
||||
"id": "587d7dbc367417b2b2512bb1",
|
||||
@ -143,11 +143,7 @@
|
||||
"releasedOn": "December 25, 2017",
|
||||
"description": [
|
||||
"So far, you've learned that JSX is a convenient tool to write readable HTML within JavaScript. With React, we can render this JSX directly to the HTML DOM using React's rendering API known as ReactDOM.",
|
||||
"ReactDOM offers a simple method to render React elements to the DOM which looks like this: <code>ReactDOM.render(componentToRender, targetNode)</code>.",
|
||||
"<ul>",
|
||||
"<li>The first argument is the React element or component that you want to render.</li>",
|
||||
"<li>The second argument is the DOM node that you want to render the component within.</li>",
|
||||
"</ul>",
|
||||
"ReactDOM offers a simple method to render React elements to the DOM which looks like this: <code>ReactDOM.render(componentToRender, targetNode)</code>, where the first argument is the React element or component that you want to render, and the second argument is the DOM node that you want to render the component to.",
|
||||
"As you would expect, <code>ReactDOM.render()</code> must be called after the JSX element declarations, just like how you must declare variables before using them.",
|
||||
"<hr>",
|
||||
"The code editor has a simple JSX component. Use the <code>ReactDOM.render()</code> method to render this component to the page. You can pass defined JSX elements directly in as the first argument and use <code>document.getElementById()</code> to select the DOM node to render them to. There is a <code>div</code> with <code>id='challenge-node'</code> available for you to use. Make sure you don't change the <code>JSX</code> constant."
|
||||
@ -166,8 +162,7 @@
|
||||
");",
|
||||
"// change code below this line",
|
||||
""
|
||||
],
|
||||
"tail": "ReactDOM.render(JSX, document.getElementById('root'))"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
@ -251,9 +246,9 @@
|
||||
" remove comment and change code above this line */}",
|
||||
" </div>",
|
||||
");",
|
||||
"",
|
||||
"ReactDOM.render(JSX, document.getElementById('root'));"
|
||||
]
|
||||
""
|
||||
],
|
||||
"tail": "ReactDOM.render(JSX, document.getElementById('root'))"
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
@ -680,8 +675,7 @@
|
||||
"",
|
||||
"// change code below this line",
|
||||
""
|
||||
],
|
||||
"tail": "ReactDOM.render(<TypesOfFood />, document.getElementById('root'))"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
@ -716,8 +710,7 @@
|
||||
"contents": [
|
||||
"// change code below this line",
|
||||
""
|
||||
],
|
||||
"tail": "ReactDOM.render(<MyComponent />, document.getElementById('root'))"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
@ -1129,8 +1122,8 @@
|
||||
"tests": [
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('CampSite').length === 1; })(), 'message: The <code>CampSite</code> component should render.');",
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('Camper').length === 1; })(), 'message: The <code>Camper</code> component should render.');",
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/ /g, '').replace(/\\r?\\n|\\r/g, ''); const verify1 = 'Camper.defaultProps={name:\\'CamperBot\\'}'; const verify2 = 'Camper.defaultProps={name:\"CamperBot\"}'; return (noWhiteSpace.includes(verify1) || noWhiteSpace.includes(verify2)); })(), 'message: The <code>Camper</code> component should include default props which assign the string <code>CamperBot</code> to the key <code>name</code>.');",
|
||||
"getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); const noWhiteSpace = getUserInput('index').replace(/ /g, '').replace(/\\r?\\n|\\r/g, ''); const verifyDefaultProps = 'Camper.propTypes={name:PropTypes.string.isRequired'; return noWhiteSpace.includes(verifyDefaultProps); })(), 'message: The <code>Camper</code> component should include prop types which require the <code>name</code> prop to be of type <code>string</code>.');",
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\\s/g, ''); const verify1 = 'Camper.defaultProps={name:\\'CamperBot\\'}'; const verify2 = 'Camper.defaultProps={name:\"CamperBot\"}'; return (noWhiteSpace.includes(verify1) || noWhiteSpace.includes(verify2)); })(), 'message: The <code>Camper</code> component should include default props which assign the string <code>CamperBot</code> to the key <code>name</code>.');",
|
||||
"getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); const noWhiteSpace = getUserInput('index').replace(/\\s/g, ''); const verifyDefaultProps = 'Camper.propTypes={name:PropTypes.string.isRequired}'; return noWhiteSpace.includes(verifyDefaultProps); })(), 'message: The <code>Camper</code> component should include prop types which require the <code>name</code> prop to be of type <code>string</code>.');",
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('p').text() === mockedComponent.find('Camper').props().name; })(), 'message: The <code>Camper</code> component should contain a <code>p</code> element with only the text from the <code>name</code> prop.');"
|
||||
],
|
||||
"solutions": [
|
||||
@ -1235,7 +1228,7 @@
|
||||
"tests": [
|
||||
"assert(Enzyme.mount(React.createElement(MyComponent)).state('name') === 'freeCodeCamp', 'message: <code>MyComponent</code> should have a key <code>name</code> with value <code>freeCodeCamp</code> stored in its state.');",
|
||||
"assert(/<div><h1>.*<\\/h1><\\/div>/.test(Enzyme.mount(React.createElement(MyComponent)).html()), 'message: <code>MyComponent</code> should render an <code>h1</code> header enclosed in a single <code>div</code>.');",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === '<div><h1>TestName</h1></div>', 'message: The rendered <code>h1</code> header should contain text rendered from the component's state.'); };"
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === '<div><h1>TestName</h1></div>', 'message: The rendered <code>h1</code> header should contain text rendered from the component's state.');};"
|
||||
],
|
||||
"solutions": [
|
||||
"class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n name: 'freeCodeCamp'\n }\n }\n render() {\n return (\n <div>\n { /* change code below this line */ }\n <h1>{this.state.name}</h1>\n { /* change code above this line */ }\n </div>\n );\n }\n};"
|
||||
@ -1289,7 +1282,7 @@
|
||||
"assert(Enzyme.mount(React.createElement(MyComponent)).state('name') === 'freeCodeCamp', 'message: <code>MyComponent</code> should have a key <code>name</code> with value <code>freeCodeCamp</code> stored in its state.');",
|
||||
"assert(/<div><h1>.*<\\/h1><\\/div>/.test(Enzyme.mount(React.createElement(MyComponent)).html()), 'message: <code>MyComponent</code> should render an <code>h1</code> header enclosed in a single <code>div</code>.');",
|
||||
"getUserInput => assert(/<h1>\\n*\\s*\\{\\s*name\\s*\\}\\s*\\n*<\\/h1>/.test(getUserInput('index')), 'message: The rendered <code>h1</code> tag should include a reference to <code>{name}</code>.');",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === '<div><h1>TestName</h1></div>', 'message: The rendered <code>h1</code> header should contain text rendered from the component's state.'); };"
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === '<div><h1>TestName</h1></div>', 'message: The rendered <code>h1</code> header should contain text rendered from the component's state.'); };"
|
||||
],
|
||||
"solutions": [
|
||||
"class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n name: 'freeCodeCamp'\n }\n }\n render() {\n // change code below this line\n const name = this.state.name;\n // change code above this line\n return (\n <div>\n { /* change code below this line */ }\n <h1>{name}</h1>\n { /* change code above this line */ }\n </div>\n );\n }\n};"
|
||||
@ -1346,7 +1339,7 @@
|
||||
"tests": [
|
||||
"assert(Enzyme.mount(React.createElement(MyComponent)).state('name') === 'Initial State', 'message: The state of <code>MyComponent</code> should initialize with the key value pair <code>{ name: Initial State }</code>.');",
|
||||
"assert(Enzyme.mount(React.createElement(MyComponent)).find('h1').length === 1, 'message: <code>MyComponent</code> should render an <code>h1</code> header.');",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()); }; const firstValue = await first(); assert(/<h1>TestName<\\/h1>/.test(firstValue), 'message: The rendered <code>h1</code> header should contain text rendered from the component's state.'); };",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'TestName' }); return waitForIt(() => mockedComponent.html()); }; const firstValue = await first(); assert(/<h1>TestName<\\/h1>/.test(firstValue), 'message: The rendered <code>h1</code> header should contain text rendered from the component's state.'); };",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: 'Before' }); return waitForIt(() => mockedComponent.state('name')); }; const second = () => { mockedComponent.setState({ name: 'React Rocks!' }); return waitForIt(() => mockedComponent.state('name')); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === 'Before' && secondValue === 'React Rocks!', 'message: Calling the <code>handleClick</code> method on <code>MyComponent</code> should set the name property in state to equal <code>React Rocks!</code>.'); }; "
|
||||
],
|
||||
"solutions": [
|
||||
@ -1658,9 +1651,9 @@
|
||||
"tests": [
|
||||
"assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyForm)); return (mockedComponent.find('div').children().find('form').length === 1 && mockedComponent.find('div').children().find('h1').length === 1 && mockedComponent.find('form').children().find('input').length === 1 && mockedComponent.find('form').children().find('button').length === 1) })(), 'message: <code>MyForm</code> should return a <code>div</code> element which contains a <code>form</code> and an <code>h1</code> tag. The form should include an <code>input</code> and a <code>button</code>.');",
|
||||
"assert(Enzyme.mount(React.createElement(MyForm)).state('input') === '' && Enzyme.mount(React.createElement(MyForm)).state('submit') === '', 'message: The state of <code>MyForm</code> should initialize with <code>input</code> and <code>submit</code> properties, both set to empty strings.');",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); return waitForIt(() => mockedComponent.state('input'))}; const _2 = () => { mockedComponent.find('input').simulate('change', { target: { value: 'TestInput' }}); return waitForIt(() => ({ state: mockedComponent.state('input'), inputVal: mockedComponent.find('input').props().value }))}; const before = await _1(); const after = await _2(); assert(before === '' && after.state === 'TestInput' && after.inputVal === 'TestInput', 'message: Typing in the <code>input</code> element should update the <code>input</code> property of the component's state.'); }; ",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); return waitForIt(() => mockedComponent.state('input'))}; const _2 = () => { mockedComponent.find('input').simulate('change', { target: { value: 'TestInput' }}); return waitForIt(() => ({ state: mockedComponent.state('input'), inputVal: mockedComponent.find('input').props().value }))}; const before = await _1(); const after = await _2(); assert(before === '' && after.state === 'TestInput' && after.inputVal === 'TestInput', 'message: Typing in the <code>input</code> element should update the <code>input</code> property of the component's state.'); }; ",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); mockedComponent.setState({submit: ''}); mockedComponent.find('input').simulate('change', {target: {value: 'SubmitInput'}}); return waitForIt(() => mockedComponent.state('submit'))}; const _2 = () => { mockedComponent.find('form').simulate('submit'); return waitForIt(() => mockedComponent.state('submit'))}; const before = await _1(); const after = await _2(); assert(before === '' && after === 'SubmitInput', 'message: Submitting the form should run <code>handleSubmit</code> which should set the <code>submit</code> property in state equal to the current input.'); };",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); mockedComponent.setState({submit: ''}); mockedComponent.find('input').simulate('change', {target: {value: 'TestInput'}}); return waitForIt(() => mockedComponent.find('h1').text())}; const _2 = () => { mockedComponent.find('form').simulate('submit'); return waitForIt(() => mockedComponent.find('h1').text())}; const before = await _1(); const after = await _2(); assert(before === '' && after === 'TestInput', 'message: The <code>h1</code> header should render the value of the <code>submit</code> field from the component's state.'); }; "
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); mockedComponent.setState({submit: ''}); mockedComponent.find('input').simulate('change', {target: {value: 'TestInput'}}); return waitForIt(() => mockedComponent.find('h1').text())}; const _2 = () => { mockedComponent.find('form').simulate('submit'); return waitForIt(() => mockedComponent.find('h1').text())}; const before = await _1(); const after = await _2(); assert(before === '' && after === 'TestInput', 'message: The <code>h1</code> header should render the value of the <code>submit</code> field from the component's state.'); }; "
|
||||
],
|
||||
"solutions": [
|
||||
"class MyForm extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n input: '',\n submit: ''\n };\n this.handleChange = this.handleChange.bind(this);\n this.handleSubmit = this.handleSubmit.bind(this);\n }\n handleChange(event) {\n this.setState({\n input: event.target.value\n });\n }\n handleSubmit(event) {\n event.preventDefault()\n this.setState({\n submit: this.state.input\n });\n }\n render() {\n return (\n <div>\n <form onSubmit={this.handleSubmit}>\n <input\n value={this.state.input}\n onChange={this.handleChange} />\n <button type='submit'>Submit!</button>\n </form>\n <h1>{this.state.submit}</h1>\n </div>\n );\n }\n};"
|
||||
@ -1739,7 +1732,7 @@
|
||||
"description": [
|
||||
"You can pass <code>state</code> as props to child components, but you're not limited to passing data. You can also pass handler functions or any method that's defined on a React component to a child component. This is how you allow child components to interact with their parent components. You pass methods to a child just like a regular prop. It's assigned a name and you have access to that method name under <code>this.props</code> in the child component.",
|
||||
"<hr>",
|
||||
"There are three components outlined in the code editor. The <code>MyApp</code> component is the parent that will render the <code>GetInput</code> and <code>RenderInput</code> child components. Add the <code>GetInput</code> component to the render method in <code>MyApp</code>, then pass it a prop called <code>input</code> assigned to <code>inputValue</code> from <code>MyApp</code>'s <code>state</code>. Also create a prop called <code>handleChange</code> and pass the input handler <code>handleChange</code> to it.",
|
||||
"There are three components outlined in the code editor. The <code>MyApp</code> component is the parent that will render the <code>GetInput</code> and <code>RenderInput</code> child components. Add the <code>GetInput</code> component to the render method in <code>MyApp</code>, then pass it a prop called <code>input</code> assigned to <code>inputValue</code> from <code>MyApp</code>'s <code>state</code>. Also create a prop called <code>handleChange</code> and pass the input handler <code>handleChange</code> to it.",
|
||||
"Next, add <code>RenderInput</code> to the render method in <code>MyApp</code>, then create a prop called <code>input</code> and pass the <code>inputValue</code> from <code>state</code> to it. Once you are finished you will be able to type in the <code>input</code> field in the <code>GetInput</code> component, which then calls the handler method in its parent via props. This updates the input in the <code>state</code> of the parent, which is passed as props to both children. Observe how the data flows between the components and how the single source of truth remains the <code>state</code> of the parent component. Admittedly, this example is a bit contrived, but should serve to illustrate how data and callbacks can be passed between React components."
|
||||
],
|
||||
"files": {
|
||||
@ -1917,7 +1910,7 @@
|
||||
"tests": [
|
||||
"assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return (mockedComponent.find('div').length === 1 && mockedComponent.find('h1').length === 1); })(), 'message: <code>MyComponent</code> should render a <code>div</code> element which wraps an <code>h1</code> tag.');",
|
||||
"assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return new RegExp('setTimeout(.|\\n)+setState(.|\\n)+activeUsers').test(String(mockedComponent.instance().componentDidMount)); })(), 'message: Component state should be updated with a timeout function in <code>componentDidMount</code>.');",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ activeUsers: 1237 }); return waitForIt(() => mockedComponent.find('h1').text()); }; const second = () => { mockedComponent.setState({ activeUsers: 1000 }); return waitForIt(() => mockedComponent.find('h1').text()); }; const firstValue = await first(); const secondValue = await second(); assert(new RegExp('1237').test(firstValue) && new RegExp('1000').test(secondValue), 'message: The <code>h1</code> tag should render the <code>activeUsers</code> value from <code>MyComponent</code>'s state.); }; "
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ activeUsers: 1237 }); return waitForIt(() => mockedComponent.find('h1').text()); }; const second = () => { mockedComponent.setState({ activeUsers: 1000 }); return waitForIt(() => mockedComponent.find('h1').text()); }; const firstValue = await first(); const secondValue = await second(); assert(new RegExp('1237').test(firstValue) && new RegExp('1000').test(secondValue), 'message: The <code>h1</code> tag should render the <code>activeUsers</code> value from <code>MyComponent</code>'s state.'); }; "
|
||||
],
|
||||
"solutions": [
|
||||
"class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n activeUsers: null\n };\n }\n componentDidMount() {\n setTimeout( () => {\n this.setState({\n activeUsers: 1273\n });\n }, 2500);\n }\n render() {\n return (\n <div>\n <h1>Active Users: {this.state.activeUsers}</h1>\n </div>\n );\n }\n};"
|
||||
@ -2340,9 +2333,9 @@
|
||||
},
|
||||
"tests": [
|
||||
"assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).find('MagicEightBall').length, 1, 'message: The <code>MagicEightBall</code> compponent should exist and should render to the page.');",
|
||||
"assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(0).name(), 'input', \"message: <code>MagicEightBall</code>'s first child should be an <code>input</code> element.\");",
|
||||
"assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(2).name(), 'button', \"message: <code>MagicEightBall</code>'s third child should be a <code>button</code> element.\");",
|
||||
"assert(Enzyme.mount(React.createElement(MagicEightBall)).state('randomIndex') === '' && Enzyme.mount(React.createElement(MagicEightBall)).state('userInput') === '', \"message: <code>MagicEightBall</code>'s state should be initialized with a property of <code>userInput</code> and a property of <code>randomIndex</code> both set to a value of an empty string.\");",
|
||||
"assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(0).name(), 'input', \"message: <code>MagicEightBall</code>'s first child should be an <code>input</code> element.\");",
|
||||
"assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(2).name(), 'button', \"message: <code>MagicEightBall</code>'s third child should be a <code>button</code> element.\");",
|
||||
"assert(Enzyme.mount(React.createElement(MagicEightBall)).state('randomIndex') === '' && Enzyme.mount(React.createElement(MagicEightBall)).state('userInput') === '', \"message: <code>MagicEightBall</code>'s state should be initialized with a property of <code>userInput</code> and a property of <code>randomIndex</code> both set to a value of an empty string.\");",
|
||||
"assert(Enzyme.mount(React.createElement(MagicEightBall)).find('p').length === 1 && Enzyme.mount(React.createElement(MagicEightBall)).find('p').text() === '', 'message: When <code>MagicEightBall</code> is first mounted to the DOM, it should return an empty <code>p</code> element.');",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MagicEightBall)); const simulate = () => { comp.find('input').simulate('change', { target: { value: 'test?' }}); comp.find('button').simulate('click'); }; const result = () => comp.find('p').text(); const _1 = () => { simulate(); return waitForIt(() => result()) }; const _2 = () => { simulate(); return waitForIt(() => result()) }; const _3 = () => { simulate(); return waitForIt(() => result()) }; const _4 = () => { simulate(); return waitForIt(() => result()) }; const _5 = () => { simulate(); return waitForIt(() => result()) }; const _6 = () => { simulate(); return waitForIt(() => result()) }; const _7 = () => { simulate(); return waitForIt(() => result()) }; const _8 = () => { simulate(); return waitForIt(() => result()) }; const _9 = () => { simulate(); return waitForIt(() => result()) }; const _10 = () => { simulate(); return waitForIt(() => result()) }; const _1_val = await _1(); const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); const _5_val = await _5(); const _6_val = await _6(); const _7_val = await _7(); const _8_val = await _8(); const _9_val = await _9(); const _10_val = await _10(); const actualAnswers = [_1_val, _2_val, _3_val, _4_val, _5_val, _6_val, _7_val, _8_val, _9_val, _10_val]; const hasIndex = actualAnswers.filter((answer, i) => possibleAnswers.indexOf(answer) !== -1); const notAllEqual = new Set(actualAnswers); assert(notAllEqual.size > 1 && hasIndex.length === 10, 'message: When text is entered into the <code>input</code> element and the button is clicked, the <code>MagicEightBall</code> compponent should return a <code>p</code> element that contains a random element from the <code>possibleAnswers</code> array.'); }; "
|
||||
],
|
||||
@ -2402,7 +2395,7 @@
|
||||
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('MyComponent').length === 1; })(), 'message: <code>MyComponent</code> should exist and render.');",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: true}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(mockedComponent.find('div').length === 1 && mockedComponent.find('div').children().length === 2 && mockedComponent.find('button').length === 1 && mockedComponent.find('h1').length === 1, 'message: When <code>display</code> is set to <code>true</code>, a <code>div</code>, <code>button</code>, and <code>h1</code> should render.'); }; ",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: false}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(mockedComponent.find('div').length === 1 && mockedComponent.find('div').children().length === 1 && mockedComponent.find('button').length === 1 && mockedComponent.find('h1').length === 0, 'message: When <code>display</code> is set to <code>false</code>, only a <code>div</code> and <code>button</code> should render.'); }; ",
|
||||
"getUserInput => assert(getUserInput('index').includes('if') === true && getUserInput('index').includes('else') === true, 'message: The render method should use an <code>if/else</code> statement to check the condition of <code>this.state.display</code>.');"
|
||||
"getUserInput => assert(getUserInput('index').includes('if') && getUserInput('index').includes('else'), 'message: The render method should use an <code>if/else</code> statement to check the condition of <code>this.state.display</code>.');"
|
||||
],
|
||||
"solutions": [
|
||||
"class MyComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n display: true\n }\n this.toggleDisplay = this.toggleDisplay.bind(this); \n }\n toggleDisplay() {\n this.setState({\n display: !this.state.display\n });\n }\n render() {\n // change code below this line\n if (this.state.display) {\n return (\n <div>\n <button onClick={this.toggleDisplay}>Toggle Display</button>\n <h1>Displayed!</h1>\n </div>\n );\n } else {\n return (\n <div>\n <button onClick={this.toggleDisplay}>Toggle Display</button>\n </div>\n );\n }\n }\n};"
|
||||
@ -2538,10 +2531,10 @@
|
||||
},
|
||||
"tests": [
|
||||
"assert(Enzyme.mount(React.createElement(CheckUserAge)).find('div').find('input').length === 1 && Enzyme.mount(React.createElement(CheckUserAge)).find('div').find('button').length === 1, 'message: The <code>CheckUserAge</code> component should render with a single <code>input</code> element and a single <code>button</code> element.');",
|
||||
"assert(Enzyme.mount(React.createElement(CheckUserAge)).state().input === '' && Enzyme.mount(React.createElement(CheckUserAge)).state().userAge === '', \"message: The <code>CheckUserAge</code> component's state should be initialized with a property of <code>userAge</code> and a property of <code>input</code>, both set to a value of an empty string.\");",
|
||||
"assert(Enzyme.mount(React.createElement(CheckUserAge)).find('button').text() === 'Submit', \"message: When the <code>CheckUserAge</code> component is first rendered to the DOM, the <code>button</code>'s inner text should be Submit.\");",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find('button').text(); const enter3AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 3 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter17AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 17 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge3 = await enter3AndClickButton(); const userAge17 = await enter17AndClickButton(); assert(initialButton === 'Submit' && userAge3 === 'You Shall Not Pass' && userAge17 === 'You Shall Not Pass', 'message: When a number of less than 18 is entered into the <code>input</code> element and the <code>button</code> is clicked, the <code>button</code>'s inner text should read <code>You Shall Not Pass</code>.); }; ",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find('button').text(); const enter18AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 18 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter35AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 35 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge18 = await enter18AndClickButton(); const userAge35 = await enter35AndClickButton(); assert(initialButton === 'Submit' && userAge18 === 'You May Enter' && userAge35 === 'You May Enter', 'message: When a number greater than or equal to 18 is entered into the <code>input</code> element and the <code>button</code> is clicked, the <code>button</code>'s inner text should read <code>You May Enter</code>.); }; ",
|
||||
"assert(Enzyme.mount(React.createElement(CheckUserAge)).state().input === '' && Enzyme.mount(React.createElement(CheckUserAge)).state().userAge === '', 'message: The <code>CheckUserAge</code> component's state should be initialized with a property of <code>userAge</code> and a property of <code>input</code>, both set to a value of an empty string.');",
|
||||
"assert(Enzyme.mount(React.createElement(CheckUserAge)).find('button').text() === 'Submit', 'message: When the <code>CheckUserAge</code> component is first rendered to the DOM, the <code>button</code>'s inner text should be Submit.');",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find('button').text(); const enter3AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 3 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter17AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 17 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge3 = await enter3AndClickButton(); const userAge17 = await enter17AndClickButton(); assert(initialButton === 'Submit' && userAge3 === 'You Shall Not Pass' && userAge17 === 'You Shall Not Pass', 'message: When a number of less than 18 is entered into the <code>input</code> element and the <code>button</code> is clicked, the <code>button</code>'s inner text should read <code>You Shall Not Pass</code>.'); }; ",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find('button').text(); const enter18AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 18 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter35AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 35 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge18 = await enter18AndClickButton(); const userAge35 = await enter35AndClickButton(); assert(initialButton === 'Submit' && userAge18 === 'You May Enter' && userAge35 === 'You May Enter', 'message: When a number greater than or equal to 18 is entered into the <code>input</code> element and the <code>button</code> is clicked, the <code>button</code>'s inner text should read <code>You May Enter</code>.'); }; ",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const enter18AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 18 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const changeInputDontClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 5 }}); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const enter10AndClickButton = () => { mockedComponent.find('input').simulate('change', {target: { value: 10 }}); mockedComponent.find('button').simulate('click'); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find('button').text(); }); }; const userAge18 = await enter18AndClickButton(); const changeInput1 = await changeInputDontClickButton(); const userAge10 = await enter10AndClickButton(); const changeInput2 = await changeInputDontClickButton(); assert(userAge18 === 'You May Enter' && changeInput1 === 'Submit' && userAge10 === 'You Shall Not Pass' && changeInput2 === 'Submit', 'message: Once a number has been submitted, and the value of the <code>input</code> is once again changed, the <code>button</code> should return to reading <code>Submit</code>.'); }; ",
|
||||
"assert(new RegExp(/(\\s|;)if(\\s|\\()/).test(Enzyme.mount(React.createElement(CheckUserAge)).instance().render.toString()) === false, 'message: Your code should not contain any <code>if/else</code> statements.');"
|
||||
],
|
||||
@ -2844,7 +2837,7 @@
|
||||
"The <code>map</code> array method is a powerful tool that you will use often when working with React. Another method related to <code>map</code> is <code>filter</code>, which filters the contents of an array based on a condition, then returns a new array. For example, if you have an array of users that all have a property <code>online</code> which can be set to <code>true</code> or <code>false</code>, you can filter only those users that are online by writing:",
|
||||
"<code>let onlineUsers = users.filter(user => user.online);",
|
||||
"<hr>",
|
||||
"In the code editor, <code>MyComponent</code>'s <code>state</code> is initialized with an array of users. Some users are online and some aren't. Filter the array so you see only the users who are online. To do this, first use <code>filter</code> to return a new array containing only the users whose <code>online</code> property is <code>true</code>. Then, in the <code>renderOnline</code> variable, map over the filtered array, and return a <code>li</code> element for each user that contains the text of their <code>username</code>. Be sure to include a unique <code>key</code> as well, like in the last challenges."
|
||||
"In the code editor, <code>MyComponent</code>'s <code>state</code> is initialized with an array of users. Some users are online and some aren't. Filter the array so you see only the users who are online. To do this, first use <code>filter</code> to return a new array containing only the users whose <code>online</code> property is <code>true</code>. Then, in the <code>renderOnline</code> variable, map over the filtered array, and return a <code>li</code> element for each user that contains the text of their <code>username</code>. Be sure to include a unique <code>key</code> as well, like in the last challenges."
|
||||
],
|
||||
"files": {
|
||||
"indexjsx": {
|
||||
@ -2903,9 +2896,9 @@
|
||||
},
|
||||
"tests": [
|
||||
"assert.strictEqual(Enzyme.mount(React.createElement(MyComponent)).find('MyComponent').length, 1, 'message: <code>MyComponent</code> should exist and render to the page.');",
|
||||
"assert(Array.isArray(Enzyme.mount(React.createElement(MyComponent)).state('users')) === true && Enzyme.mount(React.createElement(MyComponent)).state('users').length === 6, \"message: <code>MyComponent</code>'s state should be initialized to an array of six users.\");",
|
||||
"assert(Array.isArray(Enzyme.mount(React.createElement(MyComponent)).state('users')) === true && Enzyme.mount(React.createElement(MyComponent)).state('users').length === 6, \"message: <code>MyComponent</code>'s state should be initialized to an array of six users.\");",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: 'Jeff', online: bool }, { username: 'Alan', online: bool }, { username: 'Mary', online: bool }, { username: 'Jim', online: bool }, { username: 'Laura', online: bool } ]}); const result = () => comp.find('li').length; const _1 = result(); const _2 = () => { comp.setState(users(true)); return waitForIt(() => result()) }; const _3 = () => { comp.setState(users(false)); return waitForIt(() => result()) }; const _4 = () => { comp.setState({ users: [] }); return waitForIt(() => result()) }; const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); assert(comp.find('div').length === 1 && comp.find('h1').length === 1 && comp.find('ul').length === 1 && _1 === 4 && _2_val === 5 && _3_val === 0 && _4_val === 0, 'message: <code>MyComponent</code> should return a <code>div</code>, an <code>h1</code>, and then an unordered list containing <code>li</code> elements for every user whose online status is set to <code>true</code>.'); }; ",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: 'Jeff', online: bool }, { username: 'Alan', online: bool }, { username: 'Mary', online: bool }, { username: 'Jim', online: bool }, { username: 'Laura', online: bool } ]}); const ul = () => { comp.setState(users(true)); return waitForIt(() => comp.find('ul').html()) }; const html = await ul(); assert(html === '<ul><li>Jeff</li><li>Alan</li><li>Mary</li><li>Jim</li><li>Laura</li></ul>, 'message: <code>MyComponent</code> should render <code>li</code> elements that contain the username of each online user.); }; ",
|
||||
"async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: 'Jeff', online: bool }, { username: 'Alan', online: bool }, { username: 'Mary', online: bool }, { username: 'Jim', online: bool }, { username: 'Laura', online: bool } ]}); const ul = () => { comp.setState(users(true)); return waitForIt(() => comp.find('ul').html()) }; const html = await ul(); assert(html === '<ul><li>Jeff</li><li>Alan</li><li>Mary</li><li>Jim</li><li>Laura</li></ul>, 'message: <code>MyComponent</code> should render <code>li</code> elements that contain the username of each online user.'); }; ",
|
||||
"assert((() => { const ul = Enzyme.mount(React.createElement(MyComponent)).find('ul'); console.log(ul.debug()); const keys = new Set([ ul.childAt(0).key(), ul.childAt(1).key(), ul.childAt(2).key(), ul.childAt(3).key() ]); return keys.size === 4; })(), 'message: Each list item element should have a unique <code>key</code> attribute.');"
|
||||
],
|
||||
"solutions": [
|
||||
|
@ -195,7 +195,7 @@
|
||||
"tests": [
|
||||
"assert(loginAction().type === 'LOGIN', 'message: Calling the function <code>loginAction</code> should return an object with <code>type</code> property set to the string <code>LOGIN</code>.');",
|
||||
"assert(store.getState().login === false, 'message: The store should be initialized with an object with property <code>login</code> set to <code>false</code>.');",
|
||||
"getUserInput => assert((function() { let noWhiteSpace = getUserInput('index').replace(/ /g,''); return noWhiteSpace.includes('store.dispatch(loginAction())') || noWhiteSpace.includes('store.dispatch({type: \\'LOGIN\\'})') === true })(), 'message: The <code>store.dispatch()</code> method should be used to dispatch an action of type <code>LOGIN</code>.');"
|
||||
"getUserInput => assert((function() { let noWhiteSpace = getUserInput('index').replace(/\\s/g,''); return noWhiteSpace.includes('store.dispatch(loginAction())') || noWhiteSpace.includes('store.dispatch({type: \\'LOGIN\\'})') === true })(), 'message: The <code>store.dispatch()</code> method should be used to dispatch an action of type <code>LOGIN</code>.');"
|
||||
],
|
||||
"solutions": [
|
||||
"const store = Redux.createStore(\n (state = {login: false}) => state\n);\n\nconst loginAction = () => {\n return {\n type: 'LOGIN'\n }\n};\n\n// Dispatch the action here:\nstore.dispatch(loginAction());"
|
||||
@ -381,8 +381,8 @@
|
||||
"assert((function() { const initialState = store.getState(); store.dispatch(loginUser()); const afterLogin = store.getState(); return initialState.authenticated === false && afterLogin.authenticated === true })(), 'message: Dispatching <code>loginUser</code> should update the <code>login</code> property in the store state to <code>true</code>.');",
|
||||
"assert((function() { store.dispatch(loginUser()); const loggedIn = store.getState(); store.dispatch(logoutUser()); const afterLogout = store.getState(); return loggedIn.authenticated === true && afterLogout.authenticated === false })(), 'message: Dispatching <code>logoutUser</code> should update the <code>login</code> property in the store state to <code>false</code>.');",
|
||||
"getUserInput => assert((function() { return typeof authReducer === 'function' && getUserInput('index').toString().includes('switch') && getUserInput('index').toString().includes('case') && getUserInput('index').toString().includes('default') })(), 'message: The <code>authReducer</code> function should handle multiple action types with a switch statement.');",
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').toString().replace(/ /g,''); return (noWhiteSpace.includes('constLOGIN=\\'LOGIN\\'') || noWhiteSpace.includes('constLOGIN=\"LOGIN\"')) && (noWhiteSpace.includes('constLOGOUT=\\'LOGOUT\\'') || noWhiteSpace.includes('constLOGOUT=\"LOGOUT\"')) })(), 'message: <code>LOGIN</code> and <code>LOGOUT</code> should be declared as <code>const</code> values and should be assigned strings of <code>LOGIN</code>and <code>LOGOUT</code>.');",
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').toString().replace(/ /g,''); return noWhiteSpace.includes('caseLOGIN:') && noWhiteSpace.includes('caseLOGOUT:') && noWhiteSpace.includes('type:LOGIN') && noWhiteSpace.includes('type:LOGOUT') })(), 'message: The action creators and the reducer should reference the <code>LOGIN</code> and <code>LOGOUT</code> constants.');"
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').toString().replace(/\\s/g,''); return (noWhiteSpace.includes('constLOGIN=\\'LOGIN\\'') || noWhiteSpace.includes('constLOGIN=\"LOGIN\"')) && (noWhiteSpace.includes('constLOGOUT=\\'LOGOUT\\'') || noWhiteSpace.includes('constLOGOUT=\"LOGOUT\"')) })(), 'message: <code>LOGIN</code> and <code>LOGOUT</code> should be declared as <code>const</code> values and should be assigned strings of <code>LOGIN</code>and <code>LOGOUT</code>.');",
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').toString().replace(/\\s/g,''); return noWhiteSpace.includes('caseLOGIN:') && noWhiteSpace.includes('caseLOGOUT:') && noWhiteSpace.includes('type:LOGIN') && noWhiteSpace.includes('type:LOGOUT') })(), 'message: The action creators and the reducer should reference the <code>LOGIN</code> and <code>LOGOUT</code> constants.');"
|
||||
],
|
||||
"solutions": [
|
||||
"const LOGIN = 'LOGIN';\nconst LOGOUT = 'LOGOUT';\n\nconst defaultState = {\n authenticated: false\n};\n\nconst authReducer = (state = defaultState, action) => {\n\n switch (action.type) {\n\n case LOGIN:\n return {\n authenticated: true\n }\n\n case LOGOUT:\n return {\n authenticated: false\n }\n\n default:\n return state;\n\n }\n\n};\n\nconst store = Redux.createStore(authReducer);\n\nconst loginUser = () => {\n return {\n type: LOGIN\n }\n};\n\nconst logoutUser = () => {\n return {\n type: LOGOUT\n }\n};"
|
||||
@ -514,7 +514,7 @@
|
||||
"assert((function() { const initalState = store.getState().count; store.dispatch({type: INCREMENT}); store.dispatch({type: INCREMENT}); const firstState = store.getState().count; store.dispatch({type: DECREMENT}); const secondState = store.getState().count; return firstState === initalState + 2 && secondState === firstState - 1 })(), 'message: The <code>counterReducer</code> should increment and decrement the <code>state</code>.');",
|
||||
"assert((function() { store.dispatch({type: LOGIN}); const loggedIn = store.getState().auth.authenticated; store.dispatch({type: LOGOUT}); const loggedOut = store.getState().auth.authenticated; return loggedIn === true && loggedOut === false })(), 'message: The <code>authReducer</code> should toggle the <code>state</code> of <code>authenticated</code> between <code>true</code> and <code>false</code>.');",
|
||||
"assert((function() { const state = store.getState(); return typeof state.auth === 'object' && typeof state.auth.authenticated === 'boolean' && typeof state.count === 'number' })(), 'message: The store <code>state</code> should have two keys: <code>count</code>, which holds a number, and <code>auth</code>, which holds an object. The <code>auth</code> object should have a property of <code>authenticated</code>, which holds a boolean.');",
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/ /g,''); return typeof rootReducer === 'function' && noWhiteSpace.includes('Redux.combineReducers') })(), 'message: The <code>rootReducer</code> should be a function that combines the <code>counterReducer</code> and the <code>authReducer</code>.');"
|
||||
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\\s/g,''); return typeof rootReducer === 'function' && noWhiteSpace.includes('Redux.combineReducers') })(), 'message: The <code>rootReducer</code> should be a function that combines the <code>counterReducer</code> and the <code>authReducer</code>.');"
|
||||
],
|
||||
"solutions": [
|
||||
"const INCREMENT = 'INCREMENT';\nconst DECREMENT = 'DECREMENT';\n\nconst counterReducer = (state = 0, action) => {\n switch(action.type) {\n case INCREMENT:\n return state + 1;\n case DECREMENT:\n return state - 1;\n default:\n return state;\n }\n};\n\nconst LOGIN = 'LOGIN';\nconst LOGOUT = 'LOGOUT';\n\nconst authReducer = (state = {authenticated: false}, action) => {\n switch(action.type) {\n case LOGIN:\n return {\n authenticated: true\n }\n case LOGOUT:\n return {\n authenticated: false\n }\n default:\n return state;\n }\n};\n\nconst rootReducer = Redux.combineReducers({\n count: counterReducer,\n auth: authReducer\n});\n\nconst store = Redux.createStore(rootReducer);"
|
||||
@ -651,7 +651,7 @@
|
||||
"assert(receivedData('data').type === RECEIVED_DATA, 'message: The <code>receivedData</code> action creator should return an object of type equal to the value of <code>RECEIVED_DATA</code>.');",
|
||||
"assert(typeof asyncDataReducer === 'function', 'message: <code>asyncDataReducer</code> should be a function.');",
|
||||
"assert((function() { const initialState = store.getState(); store.dispatch(requestingData()); const reqState = store.getState(); return initialState.fetching === false && reqState.fetching === true })(), 'message: Dispatching the requestingData action creator should update the store <code>state</code> property of fetching to <code>true</code>.');",
|
||||
"assert((function() { const noWhiteSpace = handleAsync.toString().replace(/ /g,''); return noWhiteSpace.includes('dispatch(requestingData())') === true && noWhiteSpace.includes('dispatch(receivedData(data))') === true })(), 'message: Dispatching <code>handleAsync</code> should dispatch the data request action and then dispatch the received data action after a delay.');"
|
||||
"assert((function() { const noWhiteSpace = handleAsync.toString().replace(/\\s/g,''); return noWhiteSpace.includes('dispatch(requestingData())') === true && noWhiteSpace.includes('dispatch(receivedData(data))') === true })(), 'message: Dispatching <code>handleAsync</code> should dispatch the data request action and then dispatch the received data action after a delay.');"
|
||||
],
|
||||
"solutions": [
|
||||
"const REQUESTING_DATA = 'REQUESTING_DATA'\nconst RECEIVED_DATA = 'RECEIVED_DATA'\n\nconst requestingData = () => { return {type: REQUESTING_DATA} }\nconst receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }\n\nconst handleAsync = () => {\n return function(dispatch) {\n dispatch(requestingData());\n setTimeout(function() {\n let data = {\n users: ['Jeff', 'William', 'Alice']\n }\n dispatch(receivedData(data));\n }, 2500);\n }\n};\n\nconst defaultState = {\n fetching: false,\n users: []\n};\n\nconst asyncDataReducer = (state = defaultState, action) => {\n switch(action.type) {\n case REQUESTING_DATA:\n return {\n fetching: true,\n users: []\n }\n case RECEIVED_DATA:\n return {\n fetching: false,\n users: action.users\n }\n default:\n return state;\n }\n};\n\nconst store = Redux.createStore(\n asyncDataReducer,\n Redux.applyMiddleware(ReduxThunk.default)\n);"
|
||||
|
Reference in New Issue
Block a user