feat(client, learn): add helper functions for common validation operations (#38605)
Co-authored-by: Randell Dawson <5313213+RandellDawson@users.noreply.github.com>
This commit is contained in:
parent
aecbc28798
commit
80438cac3e
@ -1,5 +1,6 @@
|
||||
import '@babel/polyfill';
|
||||
import jQuery from 'jquery';
|
||||
import curriculumHelpers from '../utils/curriculum-helpers';
|
||||
|
||||
window.$ = jQuery;
|
||||
|
||||
@ -48,6 +49,7 @@ async function initTestFrame(e = { code: {} }) {
|
||||
// eslint-disable-next-line no-inline-comments
|
||||
const { default: chai } = await import(/* webpackChunkName: "chai" */ 'chai');
|
||||
const assert = chai.assert;
|
||||
const __helpers = curriculumHelpers;
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
let Enzyme;
|
||||
|
@ -2,6 +2,7 @@ import chai from 'chai';
|
||||
import '@babel/polyfill';
|
||||
import __toString from 'lodash/toString';
|
||||
import { format as __format } from '../../utils/format';
|
||||
import curriculumHelpers from '../../utils/curriculum-helpers';
|
||||
|
||||
const __utils = (() => {
|
||||
const MAX_LOGS_SIZE = 64 * 1024;
|
||||
@ -59,6 +60,7 @@ self.onmessage = async e => {
|
||||
const editableContents = (e.data?.code?.editableContents || '').slice();
|
||||
|
||||
const assert = chai.assert;
|
||||
const __helpers = curriculumHelpers;
|
||||
// Fake Deep Equal dependency
|
||||
const DeepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
||||
|
||||
|
45
client/src/utils/__fixtures/curriculum-helpers-css.js
Normal file
45
client/src/utils/__fixtures/curriculum-helpers-css.js
Normal file
@ -0,0 +1,45 @@
|
||||
const cssFullExample = `
|
||||
a {
|
||||
color: green;
|
||||
display: flex;
|
||||
}
|
||||
.aClass {
|
||||
font-size: 32px;
|
||||
/* the property below should not appear in final css string
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
*/
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
}
|
||||
/* Set the background color to blue for screens that are 300px or less */
|
||||
@media screen and (max-width: 300px) {
|
||||
body {
|
||||
background-color: blue;
|
||||
}
|
||||
}`;
|
||||
|
||||
const cssCodeWithCommentsRemoved = `
|
||||
a {
|
||||
color: green;
|
||||
display: flex;
|
||||
}
|
||||
.aClass {
|
||||
font-size: 32px;
|
||||
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 300px) {
|
||||
body {
|
||||
background-color: blue;
|
||||
}
|
||||
}`;
|
||||
|
||||
const testValues = {
|
||||
cssFullExample,
|
||||
cssCodeWithCommentsRemoved
|
||||
};
|
||||
|
||||
export default testValues;
|
30
client/src/utils/__fixtures/curriculum-helpers-html.js
Normal file
30
client/src/utils/__fixtures/curriculum-helpers-html.js
Normal file
@ -0,0 +1,30 @@
|
||||
const htmlFullExample = `
|
||||
<!--
|
||||
multi line html comment
|
||||
-->
|
||||
|
||||
not a comment
|
||||
|
||||
not a commment <!-- single line html comment --> not a comment
|
||||
not a comment
|
||||
<!-- this is my blog: <mynixworld.inf> -->
|
||||
not a comment
|
||||
`;
|
||||
|
||||
const htmlCodeWithCommentsRemoved = `
|
||||
|
||||
|
||||
not a comment
|
||||
|
||||
not a commment not a comment
|
||||
not a comment
|
||||
|
||||
not a comment
|
||||
`;
|
||||
|
||||
const testValues = {
|
||||
htmlFullExample,
|
||||
htmlCodeWithCommentsRemoved
|
||||
};
|
||||
|
||||
export default testValues;
|
44
client/src/utils/__fixtures/curriculum-helpers-javascript.js
Normal file
44
client/src/utils/__fixtures/curriculum-helpers-javascript.js
Normal file
@ -0,0 +1,44 @@
|
||||
const jsCodeWithSingleAndMultLineComments = `
|
||||
function nonMutatingPush(original, newItem) {
|
||||
/* This is a
|
||||
multi-line comment
|
||||
that should be removed. */
|
||||
return original.push(newItem);
|
||||
}
|
||||
var first = [1, 2, 3];
|
||||
// This is a single line comment
|
||||
var second = [4, 5];
|
||||
nonMutatingPush(first, second);`;
|
||||
|
||||
const jsCodeWithSingleAndMultLineCommentsRemoved = `
|
||||
function nonMutatingPush(original, newItem) {
|
||||
|
||||
|
||||
|
||||
return original.push(newItem);
|
||||
}
|
||||
var first = [1, 2, 3];
|
||||
|
||||
var second = [4, 5];
|
||||
nonMutatingPush(first, second);`;
|
||||
|
||||
const jsCodeWithUrl = `
|
||||
function nonMutatingPush(original, newItem) {
|
||||
var url = 'https://freecodecamp.org'; // this comment should vanish
|
||||
return original.push(newItem);
|
||||
}`;
|
||||
|
||||
const jsCodeWithUrlUnchanged = `
|
||||
function nonMutatingPush(original, newItem) {
|
||||
var url = 'https://freecodecamp.org';
|
||||
return original.push(newItem);
|
||||
}`;
|
||||
|
||||
const testValues = {
|
||||
jsCodeWithSingleAndMultLineComments,
|
||||
jsCodeWithSingleAndMultLineCommentsRemoved,
|
||||
jsCodeWithUrl,
|
||||
jsCodeWithUrlUnchanged
|
||||
};
|
||||
|
||||
export default testValues;
|
@ -0,0 +1,16 @@
|
||||
const stringWithWhiteSpaceChars = `
|
||||
This string sentence has various white spaces characters:
|
||||
\t* This line starts with a tab character.
|
||||
\t* This line has several preceding white space characters.`;
|
||||
|
||||
/* eslint-disable max-len */
|
||||
const stringWithWhiteSpaceCharsRemoved =
|
||||
'Thisstringsentencehasvariouswhitespacescharacters:*Thislinestartswithatabcharacter.*Thislinehasseveralprecedingwhitespacecharacters.';
|
||||
/* esline-enable max-len */
|
||||
|
||||
const testValues = {
|
||||
stringWithWhiteSpaceChars,
|
||||
stringWithWhiteSpaceCharsRemoved
|
||||
};
|
||||
|
||||
export default testValues;
|
35
client/src/utils/curriculum-helpers.js
Normal file
35
client/src/utils/curriculum-helpers.js
Normal file
@ -0,0 +1,35 @@
|
||||
import { parse } from '@babel/parser';
|
||||
import generate from '@babel/generator';
|
||||
|
||||
const removeHtmlComments = str => str.replace(/<!--(.|\s)*?-->/g, '');
|
||||
|
||||
const removeCssComments = str => str.replace(/\/\*[\s\S]+?\*\//g, '');
|
||||
|
||||
const removeJSComments = codeStr => {
|
||||
// Note: removes trailing new lines and tailing spaces at end of lines
|
||||
const options = {
|
||||
comments: false,
|
||||
retainLines: true,
|
||||
compact: false,
|
||||
concise: false,
|
||||
minified: false
|
||||
};
|
||||
try {
|
||||
const ast = parse(codeStr);
|
||||
const { code } = generate(ast, options, codeStr);
|
||||
return code;
|
||||
} catch (err) {
|
||||
return codeStr;
|
||||
}
|
||||
};
|
||||
|
||||
const removeWhiteSpace = (str = '') => {
|
||||
return str.replace(/\s/g, '');
|
||||
};
|
||||
|
||||
export default {
|
||||
removeHtmlComments,
|
||||
removeCssComments,
|
||||
removeJSComments,
|
||||
removeWhiteSpace
|
||||
};
|
87
client/src/utils/curriculum-helpers.test.js
Normal file
87
client/src/utils/curriculum-helpers.test.js
Normal file
@ -0,0 +1,87 @@
|
||||
/* global describe it expect */
|
||||
|
||||
import __testHelpers from './curriculum-helpers';
|
||||
import jsTestValues from './__fixtures/curriculum-helpers-javascript';
|
||||
import cssTestValues from './__fixtures/curriculum-helpers-css';
|
||||
import htmlTestValues from './__fixtures/curriculum-helpers-html';
|
||||
/* eslint-disable max-len */
|
||||
import whiteSpaceTestValues from './__fixtures/curriculum-helpers-remove-white-space';
|
||||
/* eslint-enable max-len */
|
||||
|
||||
const {
|
||||
stringWithWhiteSpaceChars,
|
||||
stringWithWhiteSpaceCharsRemoved
|
||||
} = whiteSpaceTestValues;
|
||||
|
||||
const { cssFullExample, cssCodeWithCommentsRemoved } = cssTestValues;
|
||||
|
||||
const { htmlFullExample, htmlCodeWithCommentsRemoved } = htmlTestValues;
|
||||
|
||||
const {
|
||||
jsCodeWithSingleAndMultLineComments,
|
||||
jsCodeWithSingleAndMultLineCommentsRemoved,
|
||||
jsCodeWithUrl,
|
||||
jsCodeWithUrlUnchanged
|
||||
} = jsTestValues;
|
||||
|
||||
describe('removeWhiteSpace', () => {
|
||||
const { removeWhiteSpace } = __testHelpers;
|
||||
it('returns a string', () => {
|
||||
expect(typeof removeWhiteSpace('This should return a string')).toBe(
|
||||
'string'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns a string with no white space characters', () => {
|
||||
expect(removeWhiteSpace(stringWithWhiteSpaceChars)).toBe(
|
||||
stringWithWhiteSpaceCharsRemoved
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeJSComments', () => {
|
||||
const { removeJSComments } = __testHelpers;
|
||||
it('returns a string', () => {
|
||||
expect(typeof removeJSComments('const should = "return a string"')).toBe(
|
||||
'string'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns a string with no single or multi-line comments', () => {
|
||||
expect(removeJSComments(jsCodeWithSingleAndMultLineComments)).toBe(
|
||||
jsCodeWithSingleAndMultLineCommentsRemoved
|
||||
);
|
||||
});
|
||||
|
||||
it('does not remove a url found in JS code', () => {
|
||||
expect(removeJSComments(jsCodeWithUrl)).toBe(jsCodeWithUrlUnchanged);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeCssComments', () => {
|
||||
const { removeCssComments } = __testHelpers;
|
||||
it('returns a string', () => {
|
||||
expect(typeof removeCssComments('.aClass: { color: red; }')).toBe('string');
|
||||
});
|
||||
|
||||
it('returns a CSS string with no single or multi-line comments', () => {
|
||||
expect(removeCssComments(cssFullExample)).toBe(cssCodeWithCommentsRemoved);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeHtmlComments', () => {
|
||||
const { removeHtmlComments } = __testHelpers;
|
||||
it('returns a string', () => {
|
||||
expect(
|
||||
typeof removeHtmlComments(
|
||||
'<h1>hello world</h1><!-- a comment--><h2>h2 element</h2>'
|
||||
)
|
||||
).toBe('string');
|
||||
});
|
||||
|
||||
it('returns an HTML string with no single or multi-line comments', () => {
|
||||
expect(removeHtmlComments(htmlFullExample)).toBe(
|
||||
htmlCodeWithCommentsRemoved
|
||||
);
|
||||
});
|
||||
});
|
@ -23,9 +23,9 @@ For the elements with id of <code>ball1</code> and <code>ball2</code>, add an <c
|
||||
```yml
|
||||
tests:
|
||||
- text: The value of the <code>animation-timing-function</code> property for the element with the id <code>ball1</code> should be linear.
|
||||
testString: const ball1Animation = $('#ball1').css('animation-timing-function').replace(/\s/g, '');assert(ball1Animation == 'linear' || ball1Animation == 'cubic-bezier(0,0,1,1)');
|
||||
testString: const ball1Animation = __helpers.removeWhiteSpace($('#ball1').css('animation-timing-function'));assert(ball1Animation == 'linear' || ball1Animation == 'cubic-bezier(0,0,1,1)');
|
||||
- text: The value of the <code>animation-timing-function</code> property for the element with the id <code>ball2</code> should be ease-out.
|
||||
testString: const ball2Animation = $('#ball2').css('animation-timing-function').replace(/\s/g, ''); assert(ball2Animation == 'ease-out' || ball2Animation == 'cubic-bezier(0,0,0.58,1)');
|
||||
testString: const ball2Animation = __helpers.removeWhiteSpace($('#ball2').css('animation-timing-function')); assert(ball2Animation == 'ease-out' || ball2Animation == 'cubic-bezier(0,0,0.58,1)');
|
||||
|
||||
```
|
||||
|
||||
|
@ -28,7 +28,7 @@ tests:
|
||||
- text: The value of the <code>animation-timing-function</code> property for the element with the id <code>ball1</code> should be the linear-equivalent cubic-bezier function.
|
||||
testString: assert($('#ball1').css('animation-timing-function') == 'cubic-bezier(0.25, 0.25, 0.75, 0.75)');
|
||||
- text: The value of the <code>animation-timing-function</code> property for the element with the id <code>ball2</code> should not change.
|
||||
testString: const ball2Animation = $('#ball2').css('animation-timing-function').replace(/\s/g, ''); assert(ball2Animation == 'ease-out' || ball2Animation == 'cubic-bezier(0,0,0.58,1)');
|
||||
testString: const ball2Animation = __helpers.removeWhiteSpace($('#ball2').css('animation-timing-function')); assert(ball2Animation == 'ease-out' || ball2Animation == 'cubic-bezier(0,0,0.58,1)');
|
||||
|
||||
```
|
||||
|
||||
|
@ -29,7 +29,7 @@ tests:
|
||||
- text: The element with the id <code>red</code> should no longer have the <code>animation-timing-function</code> property of linear.
|
||||
testString: assert($('#red').css('animation-timing-function') !== 'linear');
|
||||
- text: The value of the <code>animation-timing-function</code> property for the element with the id <code>blue</code> should not change.
|
||||
testString: const blueBallAnimation = $('#blue').css('animation-timing-function').replace(/\s/g, ''); assert(blueBallAnimation == 'ease-out' || blueBallAnimation == 'cubic-bezier(0,0,0.58,1)');
|
||||
testString: const blueBallAnimation = __helpers.removeWhiteSpace($('#blue').css('animation-timing-function')); assert(blueBallAnimation == 'ease-out' || blueBallAnimation == 'cubic-bezier(0,0,0.58,1)');
|
||||
|
||||
```
|
||||
|
||||
|
@ -33,7 +33,7 @@ tests:
|
||||
- text: Your <code>blue-box</code> class should give the left of elements <code>40px</code> of <code>margin</code>.
|
||||
testString: assert($(".blue-box").css("margin-left") === "40px");
|
||||
- text: You should use the clockwise notation to set the margin of <code>blue-box</code> class.
|
||||
testString: const removeCssComments = str => str.replace(/\/\*[\s\S]+?\*\//g, '');assert(/\.blue-box\s*{[\s\S]*margin[\s]*:\s*\d+px\s+\d+px\s+\d+px\s+\d+px(;\s*[^}]+\s*}|;?\s*})/.test(removeCssComments($('style').text())));
|
||||
testString: assert(/\.blue-box\s*{[\s\S]*margin[\s]*:\s*\d+px\s+\d+px\s+\d+px\s+\d+px(;\s*[^}]+\s*}|;?\s*})/.test(__helpers.removeCssComments($('style').text())));
|
||||
|
||||
```
|
||||
|
||||
|
@ -32,7 +32,7 @@ tests:
|
||||
- text: Your <code>blue-box</code> class should give the left of elements <code>40px</code> of <code>padding</code>.
|
||||
testString: assert($(".blue-box").css("padding-left") === "40px");
|
||||
- text: You should use the clockwise notation to set the padding of <code>blue-box</code> class.
|
||||
testString: const removeCssComments = str => str.replace(/\/\*[\s\S]+?\*\//g, '');assert(/\.blue-box\s*{[\s\S]*padding[\s]*:\s*\d+px\s+\d+px\s+\d+px\s+\d+px(;\s*[^}]+\s*}|;?\s*})/.test(removeCssComments($('style').text())));
|
||||
testString: assert(/\.blue-box\s*{[\s\S]*padding[\s]*:\s*\d+px\s+\d+px\s+\d+px\s+\d+px(;\s*[^}]+\s*}|;?\s*})/.test(__helpers.removeCssComments($('style').text())));
|
||||
|
||||
```
|
||||
|
||||
|
@ -38,7 +38,7 @@ tests:
|
||||
- text: Your image should have a <code>src</code> attribute that points to the kitten image.
|
||||
testString: assert(/^https:\/\/bit\.ly\/fcc-relaxing-cat$/i.test($("img").attr("src")));
|
||||
- text: Your image element's <code>alt</code> attribute should not be empty.
|
||||
testString: assert($("img").attr("alt") && $("img").attr("alt").length && /<img\S*alt=(['"])(?!\1|>)\S+\1\S*\/?>/.test(code.replace(/\s/g,'')));
|
||||
testString: assert($("img").attr("alt") && $("img").attr("alt").length && /<img\S*alt=(['"])(?!\1|>)\S+\1\S*\/?>/.test(__helpers.removeWhiteSpace(code)));
|
||||
|
||||
```
|
||||
|
||||
|
@ -52,9 +52,9 @@ tests:
|
||||
- text: Your <code>li</code> element should have a closing tag.
|
||||
testString: assert(code.match(/<\/li>/g) && code.match(/<li>/g) && code.match(/<\/li>/g).length === code.match(/<li>/g).length);
|
||||
- text: The <code>li</code> elements in your unordered list should not be empty.
|
||||
testString: $('ul li').each((i, val) => assert(val.textContent.replace(/\s/g, '')));
|
||||
testString: $('ul li').each((i, val) => assert(__helpers.removeWhiteSpace(val.textContent)));
|
||||
- text: The <code>li</code> elements in your ordered list should not be empty.
|
||||
testString: $('ol li').each((i, val) => assert(!!val.textContent.replace(/\s/g, '')));
|
||||
testString: $('ol li').each((i, val) => assert(!!__helpers.removeWhiteSpace(val.textContent)));
|
||||
|
||||
```
|
||||
|
||||
|
@ -33,7 +33,7 @@ Place the area template so that the cell labeled <code>advert</code> becomes an
|
||||
```yml
|
||||
tests:
|
||||
- text: <code>container</code> class should have a <code>grid-template-areas</code> property similar to the preview but has <code>.</code> instead of the <code>advert</code> area.
|
||||
testString: const removeCssComments = str => str.replace(/\/\*[\s\S]+?\*\//g, ''); assert(removeCssComments(code).match(/.container\s*?{[\s\S]*grid-template-areas\s*?:\s*?"\s*?header\s*?header\s*?header\s*?"\s*?"\s*?.\s*?content\s*?content\s*?"\s*?"\s*?footer\s*?footer\s*?footer\s*?"\s*?;[\s\S]*}/gi));
|
||||
testString: assert(__helpers.removeCssComments(code).match(/.container\s*?{[\s\S]*grid-template-areas\s*?:\s*?"\s*?header\s*?header\s*?header\s*?"\s*?"\s*?.\s*?content\s*?content\s*?"\s*?"\s*?footer\s*?footer\s*?footer\s*?"\s*?;[\s\S]*}/gi));
|
||||
|
||||
```
|
||||
|
||||
|
@ -30,7 +30,7 @@ Place an element with the <code>item5</code> class in the <code>footer</code> ar
|
||||
```yml
|
||||
tests:
|
||||
- text: <code>item5</code> class should have a <code>grid-area</code> property that has the value of <code>footer</code>.
|
||||
testString: const removeCssComments = str => str.replace(/\/\*[\s\S]+?\*\//g, '');assert(removeCssComments(code).match(/.item5\s*?{[\s\S]*grid-area\s*?:\s*?footer\s*?;[\s\S]*}/gi));
|
||||
testString: assert(__helpers.removeCssComments(code).match(/.item5\s*?{[\s\S]*grid-area\s*?:\s*?footer\s*?;[\s\S]*}/gi));
|
||||
|
||||
```
|
||||
|
||||
|
@ -33,7 +33,7 @@ Make the item with the class <code>item5</code> consume the last two columns of
|
||||
```yml
|
||||
tests:
|
||||
- text: <code>item5</code> class should have a <code>grid-column</code> property.
|
||||
testString: assert($('style').text().replace(/\s/g, '').match(/\.item5{.*grid-column:.*}/g));
|
||||
testString: assert(__helpers.removeWhiteSpace($('style').text()).match(/\.item5{.*grid-column:.*}/g));
|
||||
- text: <code>item5</code> class should have a <code>grid-column</code> property which results in it consuming the last two columns of the grid.
|
||||
testString: "
|
||||
const colStart = getComputedStyle($('.item5')[0]).gridColumnStart;
|
||||
|
@ -22,7 +22,7 @@ Make the element with the <code>item5</code> class consume the last two rows.
|
||||
```yml
|
||||
tests:
|
||||
- text: <code>item5</code> class should have a <code>grid-row</code> property.
|
||||
testString: assert($('style').text().replace(/\s/g, '').match(/\.item5{.*grid-row:.*}/g));
|
||||
testString: assert(__helpers.removeWhiteSpace($('style').text()).match(/\.item5{.*grid-row:.*}/g));
|
||||
- text: <code>item5</code> class should have a <code>grid-row</code> property which results in it consuming the last two rows of the grid.
|
||||
testString: "
|
||||
const rowStart = getComputedStyle($('.item5')[0]).gridRowStart;
|
||||
|
@ -23,7 +23,7 @@ When the viewport width is <code>400px</code> or more, make the header area occu
|
||||
```yml
|
||||
tests:
|
||||
- text: When the viewport is <code>400px</code> or more, <code>container</code> class should have a <code>grid-template-areas</code> property in which the header and footer areas occupy the top and bottom rows respectively and advert and content occupy the left and right columns of the middle row.
|
||||
testString: const removeCssComments = str => str.replace(/\/\*[\s\S]+?\*\//g, ''); assert(removeCssComments(code).match(/@media\s*?\(\s*?min-width\s*?:\s*?400px\s*?\)[\s\S]*.container\s*?{[\s\S]*grid-template-areas\s*?:\s*?"\s*?header\s*?header\s*?"\s*?"\s*?advert\s*?content\s*?"\s*?"\s*?footer\s*?footer\s*?"\s*?;[\s\S]*}/gi));
|
||||
testString: assert(__helpers.removeCssComments(code).match(/@media\s*?\(\s*?min-width\s*?:\s*?400px\s*?\)[\s\S]*.container\s*?{[\s\S]*grid-template-areas\s*?:\s*?"\s*?header\s*?header\s*?"\s*?"\s*?advert\s*?content\s*?"\s*?"\s*?footer\s*?footer\s*?"\s*?;[\s\S]*}/gi));
|
||||
|
||||
```
|
||||
|
||||
|
@ -38,7 +38,7 @@ tests:
|
||||
- text: <code>copyMachine(["it works"], 3)</code> should return <code>[["it works"], ["it works"], ["it works"]]</code>
|
||||
testString: assert.deepEqual(copyMachine(['it works'], 3), [['it works'], ['it works'], ['it works']]);
|
||||
- text: The <code>copyMachine</code> function should utilize the <code>spread operator</code> with array <code>arr</code>
|
||||
testString: assert(removeJSComments(code).match(/\.\.\.arr/));
|
||||
testString: assert(__helpers.removeJSComments(code).match(/\.\.\.arr/));
|
||||
|
||||
```
|
||||
|
||||
@ -66,15 +66,6 @@ console.log(copyMachine([true, false, true], 2));
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -42,13 +42,13 @@ We've initialized an array `arr`. Use `splice()` to remove elements from `arr`,
|
||||
```yml
|
||||
tests:
|
||||
- text: You should not change the original line of <code>const arr = [2, 4, 5, 1, 7, 5, 2, 1];</code>.
|
||||
testString: assert(code.replace(/\s/g, '').match(/constarr=\[2,4,5,1,7,5,2,1\];?/));
|
||||
testString: assert(__helpers.removeWhiteSpace(code).match(/constarr=\[2,4,5,1,7,5,2,1\];?/));
|
||||
- text: <code>arr</code> should only contain elements that sum to <code>10</code>.
|
||||
testString: assert.strictEqual(arr.reduce((a, b) => a + b), 10);
|
||||
- text: Your code should utilize the <code>splice()</code> method on <code>arr</code>.
|
||||
testString: assert(code.replace(/\s/g, '').match(/arr\.splice\(/));
|
||||
testString: assert(__helpers.removeWhiteSpace(code).match(/arr\.splice\(/));
|
||||
- text: The splice should only remove elements from <code>arr</code> and not add any additional elements to <code>arr</code>.
|
||||
testString: assert(!code.replace(/\s/g, '').match(/arr\.splice\(\d+,\d+,\d+.*\)/g));
|
||||
testString: assert(!__helpers.removeWhiteSpace(code).match(/arr\.splice\(\d+,\d+,\d+.*\)/g));
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -39,7 +39,7 @@ tests:
|
||||
- text: <code>myData</code> should be equal to <code>8</code>.
|
||||
testString: assert(myData === 8);
|
||||
- text: You should be using bracket notation to read the correct value from <code>myArray</code>.
|
||||
testString: assert(/myData=myArray\[2\]\[1\]/.test(code.replace(/\s/g, '')));
|
||||
testString: assert(/myData=myArray\[2\]\[1\]/.test(__helpers.removeWhiteSpace(code)));
|
||||
|
||||
```
|
||||
|
||||
|
@ -37,7 +37,7 @@ tests:
|
||||
- text: You should use a <code>for</code> loop to iterate through <code>myArr</code>.
|
||||
testString: assert(/for\s*\(/g.test(code) && /myArr\s*\[/g.test(code));
|
||||
- text: You should not attempt to directly assign the value 20 to <code>total</code>.
|
||||
testString: assert(!code.replace(/\s/g, '').match(/total[=+-]0*[1-9]+/gm));
|
||||
testString: assert(!__helpers.removeWhiteSpace(code).match(/total[=+-]0*[1-9]+/gm));
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -43,7 +43,7 @@ tests:
|
||||
}
|
||||
assert.throws(declared, ReferenceError);
|
||||
- text: You should add a local <code>myVar</code> variable.
|
||||
testString: assert(/functionmyLocalScope\(\)\{.+(var|let|const)myVar[\s\S]*}/.test(code.replace(/\s/g, '')));
|
||||
testString: assert(/functionmyLocalScope\(\)\{.+(var|let|const)myVar[\s\S]*}/.test(__helpers.removeWhiteSpace(code)));
|
||||
|
||||
|
||||
```
|
||||
|
@ -57,9 +57,9 @@ tests:
|
||||
- text: <code>sum([2, 3, 4, 5], 3)</code> should equal 9.
|
||||
testString: assert.equal(sum([2, 3, 4, 5], 3), 9);
|
||||
- text: Your code should not rely on any kind of loops (<code>for</code> or <code>while</code> or higher order functions such as <code>forEach</code>, <code>map</code>, <code>filter</code>, or <code>reduce</code>.).
|
||||
testString: assert(!removeJSComments(code).match(/for|while|forEach|map|filter|reduce/g));
|
||||
testString: assert(!__helpers.removeJSComments(code).match(/for|while|forEach|map|filter|reduce/g));
|
||||
- text: You should use recursion to solve this problem.
|
||||
testString: assert(removeJSComments(sum.toString()).match(/sum\(.*\)/g).length > 1);
|
||||
testString: assert(__helpers.removeJSComments(sum.toString()).match(/sum\(.*\)/g).length > 1);
|
||||
```
|
||||
|
||||
</section>
|
||||
@ -80,16 +80,6 @@ function sum(arr, n) {
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -33,7 +33,7 @@ tests:
|
||||
- text: The variable <code>difference</code> should be equal to 12.
|
||||
testString: assert(difference === 12);
|
||||
- text: You should only subtract one number from 45.
|
||||
testString: assert(/difference=45-33;?/.test(code.replace(/\s/g, '')));
|
||||
testString: assert(/difference=45-33;?/.test(__helpers.removeWhiteSpace(code)));
|
||||
```
|
||||
|
||||
</section>
|
||||
|
@ -39,7 +39,7 @@ tests:
|
||||
- text: Returned value from <code>addFive</code> should be <code>undefined</code>.
|
||||
testString: assert(addFive() === undefined);
|
||||
- text: Inside the <code>addFive</code> function, you should add <code>5</code> to the <code>sum</code> variable.
|
||||
testString: assert(addFive.toString().replace(/\s/g, '').match(/sum=sum\+5|sum\+=5/));
|
||||
testString: assert(__helpers.removeWhiteSpace(addFive.toString()).match(/sum=sum\+5|sum\+=5/));
|
||||
|
||||
```
|
||||
|
||||
|
@ -52,9 +52,9 @@ tests:
|
||||
- text: <code>countdown(5)</code> should return <code>[5, 4, 3, 2, 1]</code>
|
||||
testString: assert.deepStrictEqual(countdown(5), [5, 4, 3, 2, 1]);
|
||||
- text: Your code should not rely on any kind of loops (<code>for</code>, <code>while</code> or higher order functions such as <code>forEach</code>, <code>map</code>, <code>filter</code>, and <code>reduce</code>).
|
||||
testString: assert(!removeJSComments(code).match(/for|while|forEach|map|filter|reduce/g));
|
||||
testString: assert(!__helpers.removeJSComments(code).match(/for|while|forEach|map|filter|reduce/g));
|
||||
- text: You should use recursion to solve this problem.
|
||||
testString: assert(removeJSComments(countdown.toString()).match(/countdown\s*\(.+\)/));
|
||||
testString: assert(__helpers.removeJSComments(countdown.toString()).match(/countdown\s*\(.+\)/));
|
||||
```
|
||||
|
||||
</section>
|
||||
@ -76,15 +76,6 @@ function countdown(n){
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -25,9 +25,9 @@ tests:
|
||||
- text: Your function should return an array.
|
||||
testString: assert(Array.isArray(rangeOfNumbers(5, 10)));
|
||||
- text: Your code should not use any loop syntax (<code>for</code> or <code>while</code> or higher order functions such as <code>forEach</code>, <code>map</code>, <code>filter</code>, or <code>reduce</code>).
|
||||
testString: assert(!removeJSComments(code).match(/for|while|forEach|map|filter|reduce/g));
|
||||
testString: assert(!__helpers.removeJSComments(code).match(/for|while|forEach|map|filter|reduce/g));
|
||||
- text: <code>rangeOfNumbers</code> should use recursion (call itself) to solve this challenge.
|
||||
testString: assert(removeJSComments(rangeOfNumbers.toString()).match(/rangeOfNumbers\s*\(.+\)/));
|
||||
testString: assert(__helpers.removeJSComments(rangeOfNumbers.toString()).match(/rangeOfNumbers\s*\(.+\)/));
|
||||
- text: <code>rangeOfNumbers(1, 5)</code> should return <code>[1, 2, 3, 4, 5]</code>.
|
||||
testString: assert.deepStrictEqual(rangeOfNumbers(1, 5), [1, 2, 3, 4, 5]);
|
||||
- text: <code>rangeOfNumbers(6, 9)</code> should return <code>[6, 7, 8, 9]</code>.
|
||||
@ -51,15 +51,6 @@ function rangeOfNumbers(startNum, endNum) {
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -28,9 +28,9 @@ First, use <code>console.log</code> to log the <code>output</code> variable. The
|
||||
```yml
|
||||
tests:
|
||||
- text: You should use <code>console.clear()</code> to clear the browser console.
|
||||
testString: const removeJSComments = code.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, ''); const noSpaces = removeJSComments.replace(/\s/g, ''); assert(noSpaces.match(/console.clear\(\)/));
|
||||
testString: assert(__helpers.removeWhiteSpace(__helpers.removeJSComments(code)).match(/console.clear\(\)/));
|
||||
- text: You should use <code>console.log()</code> to print the <code>output</code> variable.
|
||||
testString: const noSpaces = code.replace(/\s/g, ''); assert(noSpaces.match(/console\.log\(output\)/));
|
||||
testString: assert(__helpers.removeWhiteSpace(code).match(/console\.log\(output\)/));
|
||||
|
||||
```
|
||||
|
||||
@ -53,8 +53,6 @@ let output = "Get this to log once in the freeCodeCamp console and twice in the
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -33,9 +33,10 @@ Make the promise handle success and failure. If <code>responseFromServer</code>
|
||||
```yml
|
||||
tests:
|
||||
- text: <code>resolve</code> should be called with the expected string when the <code>if</code> condition is <code>true</code>.
|
||||
testString: assert(removeJSComments(code).match(/if\s*\(\s*responseFromServer\s*\)\s*{\s*resolve\s*\(\s*('|"|`)We got the data\1\s*\)(\s*|\s*;\s*)}/g));
|
||||
testString: assert(__helpers.removeJSComments(code).match(/if\s*\(\s*responseFromServer\s*\)\s*{\s*resolve\s*\(\s*('|"|`)We got the data\1\s*\)(\s*|\s*;\s*)}/g));
|
||||
- text: <code>reject</code> should be called with the expected string when the <code>if</code> condition is <code>false</code>.
|
||||
testString: assert(removeJSComments(code).match(/}\s*else\s*{\s*reject\s*\(\s*('|"|`)Data not received\1\s*\)(\s*|\s*;\s*)}/g));
|
||||
testString: assert(__helpers.removeJSComments(code).match(/}\s*else\s*{\s*reject\s*\(\s*('|"|`)Data not received\1\s*\)(\s*|\s*;\s*)}/g));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
@ -59,14 +60,6 @@ const makeServerRequest = new Promise((resolve, reject) => {
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -29,11 +29,11 @@ Add the <code>then</code> method to your promise. Use <code>result</code> as the
|
||||
```yml
|
||||
tests:
|
||||
- text: You should call the <code>then</code> method on the promise.
|
||||
testString: assert(codeWithoutSpaces.match(/(makeServerRequest|\))\.then\(/g));
|
||||
testString: assert(__helpers.removeWhiteSpace(code).match(/(makeServerRequest|\))\.then\(/g));
|
||||
- text: Your <code>then</code> method should have a callback function with <code>result</code> as its parameter.
|
||||
testString: assert(resultIsParameter);
|
||||
- text: You should log <code>result</code> to the console.
|
||||
testString: assert(resultIsParameter && codeWithoutSpaces.match(/\.then\(.*?result.*?console.log\(result\).*?\)/));
|
||||
testString: assert(resultIsParameter && __helpers.removeWhiteSpace(code).match(/\.then\(.*?result.*?console.log\(result\).*?\)/));
|
||||
```
|
||||
|
||||
</section>
|
||||
@ -61,8 +61,7 @@ const makeServerRequest = new Promise((resolve, reject) => {
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const codeWithoutSpaces = code.replace(/\s/g, '');
|
||||
const resultIsParameter = /\.then\((function\(result\){|result|\(result\)=>)/.test(codeWithoutSpaces);
|
||||
const resultIsParameter = /\.then\((function\(result\){|result|\(result\)=>)/.test(__helpers.removeWhiteSpace(code));
|
||||
```
|
||||
|
||||
</div>
|
||||
|
@ -31,11 +31,11 @@ Add the <code>catch</code> method to your promise. Use <code>error</code> as the
|
||||
```yml
|
||||
tests:
|
||||
- text: You should call the <code>catch</code> method on the promise.
|
||||
testString: assert(codeWithoutSpaces.match(/(makeServerRequest|\))\.catch\(/g));
|
||||
testString: assert(__helpers.removeWhiteSpace(code).match(/(makeServerRequest|\))\.catch\(/g));
|
||||
- text: Your <code>catch</code> method should have a callback function with <code>error</code> as its parameter.
|
||||
testString: assert(errorIsParameter);
|
||||
- text: You should log <code>error</code> to the console.
|
||||
testString: assert(errorIsParameter && codeWithoutSpaces.match(/\.catch\(.*?error.*?console.log\(error\).*?\)/));
|
||||
testString: assert(errorIsParameter && __helpers.removeWhiteSpace(code).match(/\.catch\(.*?error.*?console.log\(error\).*?\)/));
|
||||
```
|
||||
|
||||
</section>
|
||||
@ -67,8 +67,7 @@ makeServerRequest.then(result => {
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const codeWithoutSpaces = code.replace(/\s/g, '');
|
||||
const errorIsParameter = /\.catch\((function\(error\){|error|\(error\)=>)/.test(codeWithoutSpaces);
|
||||
const errorIsParameter = /\.catch\((function\(error\){|error|\(error\)=>)/.test(__helpers.removeWhiteSpace(code));
|
||||
```
|
||||
|
||||
</div>
|
||||
|
@ -41,11 +41,11 @@ Replace the two assignments with an equivalent destructuring assignment. It shou
|
||||
```yml
|
||||
tests:
|
||||
- text: You should remove the ES5 assignment syntax.
|
||||
testString: assert(!removeJSComments(code).match(/today\s*=\s*HIGH_TEMPERATURES\.(today|tomorrow)/g))
|
||||
testString: assert(!__helpers.removeJSComments(code).match(/today\s*=\s*HIGH_TEMPERATURES\.(today|tomorrow)/g))
|
||||
- text: You should use destructuring to create the <code>today</code> variable.
|
||||
testString: assert(removeJSComments(code).match(/(var|let|const)\s*{\s*(today[^}]*|[^,]*,\s*today)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g));
|
||||
testString: assert(__helpers.removeJSComments(code).match(/(var|let|const)\s*{\s*(today[^}]*|[^,]*,\s*today)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g));
|
||||
- text: You should use destructuring to create the <code>tomorrow</code> variable.
|
||||
testString: assert(removeJSComments(code).match(/(var|let|const)\s*{\s*(tomorrow[^}]*|[^,]*,\s*tomorrow)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g));
|
||||
testString: assert(__helpers.removeJSComments(code).match(/(var|let|const)\s*{\s*(tomorrow[^}]*|[^,]*,\s*tomorrow)\s*}\s*=\s*HIGH_TEMPERATURES(;|\s+|\/\/)/g));
|
||||
- text: <code>today</code> should be equal to <code>77</code> and <code>tomorrow</code> should be equal to <code>80</code>.
|
||||
testString: assert(today === 77 && tomorrow === 80);
|
||||
|
||||
@ -74,15 +74,6 @@ const tomorrow = HIGH_TEMPERATURES.tomorrow;
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -43,7 +43,7 @@ tests:
|
||||
- text: <code>half(stats)</code> should be <code>28.015</code>
|
||||
testString: assert(half(stats) === 28.015);
|
||||
- text: Destructuring should be used.
|
||||
testString: assert(code.replace(/\s/g, '').match(/half=\({\w+,\w+}\)/));
|
||||
testString: assert(__helpers.removeWhiteSpace(code).match(/half=\({\w+,\w+}\)/));
|
||||
- text: Destructured parameter should be used.
|
||||
testString: assert(!code.match(/stats\.max|stats\.min/));
|
||||
|
||||
|
@ -37,7 +37,7 @@ tests:
|
||||
- text: <code>Array.slice()</code> should not be used.
|
||||
testString: getUserInput => assert(!getUserInput('index').match(/slice/g));
|
||||
- text: Destructuring on <code>list</code> should be used.
|
||||
testString: assert(code.replace(/\s/g, '').match(/\[(([_$a-z]\w*)?,){1,}\.\.\.arr\]=list/i));
|
||||
testString: assert(__helpers.removeWhiteSpace(code).match(/\[(([_$a-z]\w*)?,){1,}\.\.\.arr\]=list/i));
|
||||
|
||||
```
|
||||
|
||||
|
@ -40,7 +40,7 @@ tests:
|
||||
- text: The result of <code>sum()</code> should be 0
|
||||
testString: assert(sum() === 0);
|
||||
- text: The <code>sum</code> function should use the <code>...</code> rest parameter on the <code>args</code> parameter.
|
||||
testString: assert(code.replace(/\s/g,'').match(/sum=\(\.\.\.args\)=>/));
|
||||
testString: assert(__helpers.removeWhiteSpace(code).match(/sum=\(\.\.\.args\)=>/));
|
||||
|
||||
```
|
||||
|
||||
|
@ -42,7 +42,7 @@ Refactor the function <code>setGear</code> inside the object <code>bicycle</code
|
||||
```yml
|
||||
tests:
|
||||
- text: Traditional function expression should not be used.
|
||||
testString: getUserInput => assert(!removeJSComments(code).match(/function/));
|
||||
testString: getUserInput => assert(!__helpers.removeJSComments(code).match(/function/));
|
||||
- text: <code>setGear</code> should be a declarative function.
|
||||
testString: assert(typeof bicycle.setGear === 'function' && code.match(/setGear\s*\(.+\)\s*\{/));
|
||||
- text: <code>bicycle.setGear(48)</code> should change the <code>gear</code> value to 48.
|
||||
@ -72,15 +72,6 @@ console.log(bicycle.gear);
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -24,9 +24,9 @@ tests:
|
||||
- text: <code>squareList</code> should be a <code>function</code>.
|
||||
testString: assert.typeOf(squareList, 'function'), '<code>squareList</code> should be a <code>function</code>';
|
||||
- text: for or while loops or forEach should not be used.
|
||||
testString: assert(!removeJSComments(code).match(/for|while|forEach/g));
|
||||
testString: assert(!__helpers.removeJSComments(code).match(/for|while|forEach/g));
|
||||
- text: <code>map</code>, <code>filter</code>, or <code>reduce</code> should be used.
|
||||
testString: assert(removeJSComments(code).match(/\.(map|filter|reduce)\s*\(/g));
|
||||
testString: assert(__helpers.removeJSComments(code).match(/\.(map|filter|reduce)\s*\(/g));
|
||||
- text: The function should return an <code>array</code>.
|
||||
testString: assert(Array.isArray(squareList([4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2])));
|
||||
- text: <code>squareList([4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2])</code> should return <code>[16, 1764, 36]</code>.
|
||||
@ -55,14 +55,6 @@ console.log(squaredIntegers);
|
||||
|
||||
</div>
|
||||
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -41,7 +41,7 @@ tests:
|
||||
- text: The <code>watchList</code> variable should not change.
|
||||
testString: assert(watchList[0].Title === "Inception" && watchList[4].Director == "James Cameron");
|
||||
- text: Your code should not use a <code>for</code> loop.
|
||||
testString: assert(!removeJSComments(code).match(/for\s*?\([\s\S]*?\)/));
|
||||
testString: assert(!__helpers.removeJSComments(code).match(/for\s*?\([\s\S]*?\)/));
|
||||
- text: Your code should use the <code>map</code> method.
|
||||
testString: assert(code.match(/\.map/g));
|
||||
- text: <code>ratings</code> should equal <code>[{"title":"Inception","rating":"8.8"},{"title":"Interstellar","rating":"8.6"},{"title":"The Dark Knight","rating":"9.0"},{"title":"Batman Begins","rating":"8.3"},{"title":"Avatar","rating":"7.9"}]</code>.
|
||||
@ -185,15 +185,6 @@ console.log(JSON.stringify(ratings));
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -26,7 +26,7 @@ tests:
|
||||
- text: The <code>DisplayMessages</code> component should render an empty <code>div</code> element.
|
||||
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); return mockedComponent.find('div').text() === '' })());
|
||||
- text: The <code>DisplayMessages</code> constructor should be called properly with <code>super</code>, passing in <code>props</code>.
|
||||
testString: getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\s/g,''); return noWhiteSpace.includes('constructor(props)') && noWhiteSpace.includes('super(props'); })());
|
||||
testString: getUserInput => assert((function() { const noWhiteSpace = __helpers.removeWhiteSpace(getUserInput('index')); return noWhiteSpace.includes('constructor(props)') && noWhiteSpace.includes('super(props'); })());
|
||||
- text: 'The <code>DisplayMessages</code> component should have an initial state equal to <code>{input: "", messages: []}</code>.'
|
||||
testString: "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; })());"
|
||||
|
||||
|
@ -33,7 +33,7 @@ tests:
|
||||
- text: The <code>AppWrapper</code> should render.
|
||||
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').length === 1; })());
|
||||
- text: The <code>Provider</code> wrapper component should have a prop of <code>store</code> passed to it, equal to the Redux store.
|
||||
testString: getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return getUserInput('index').replace(/\s/g,'').includes('<Providerstore={store}>'); })());
|
||||
testString: getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return __helpers.removeWhiteSpace(getUserInput('index')).includes('<Providerstore={store}>'); })());
|
||||
- text: <code>DisplayMessages</code> should render as a child of <code>AppWrapper</code>.
|
||||
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').find('DisplayMessages').length === 1; })());
|
||||
- text: The <code>DisplayMessages</code> component should render an h2, input, button, and <code>ul</code> element.
|
||||
|
@ -44,7 +44,7 @@ tests:
|
||||
- text: The <code>date</code> prop of the <code>CurrentDate</code> should contain a string of text.
|
||||
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); const prop = mockedComponent.children().childAt(1).props().date; return( typeof prop === 'string' && prop.length > 0 ); })());
|
||||
- text: The <code>date</code> prop should be generated by calling <code>Date()</code>
|
||||
testString: assert(/<CurrentDatedate={Date\(\)}\/>/.test(code.replace(/\s/g, '')))
|
||||
testString: assert(/<CurrentDatedate={Date\(\)}\/>/.test(__helpers.removeWhiteSpace(code)))
|
||||
- text: The <code>CurrentDate</code> component should render the value from the <code>date</code> prop in the <code>p</code> tag.
|
||||
testString: let date = "dummy date"; assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CurrentDate, {date})); return mockedComponent.find('p').html().includes(date); })());
|
||||
|
||||
|
@ -28,9 +28,9 @@ tests:
|
||||
- text: The <code>Camper</code> component should render.
|
||||
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('Camper').length === 1; })());
|
||||
- text: The <code>Camper</code> component should include default props which assign the string <code>CamperBot</code> to the key <code>name</code>.
|
||||
testString: assert(/Camper.defaultProps={name:(['"`])CamperBot\1,?}/.test(code.replace(/\s/g, '')));
|
||||
testString: assert(/Camper.defaultProps={name:(['"`])CamperBot\1,?}/.test(__helpers.removeWhiteSpace(code)));
|
||||
- text: The <code>Camper</code> component should include prop types which require the <code>name</code> prop to be of type <code>string</code>.
|
||||
testString: assert(/Camper.propTypes={name:PropTypes.string.isRequired,?}/.test(code.replace(/\s/g, '')));
|
||||
testString: assert(/Camper.propTypes={name:PropTypes.string.isRequired,?}/.test(__helpers.removeWhiteSpace(code)));
|
||||
- text: The <code>Camper</code> component should contain a <code>p</code> element with only the text from the <code>name</code> prop.
|
||||
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('p').text() === mockedComponent.find('Camper').props().name; })());
|
||||
|
||||
|
@ -33,7 +33,7 @@ tests:
|
||||
- text: The <code>Items</code> component should render.
|
||||
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find('Items').length === 1; })());
|
||||
- text: The <code>Items</code> component should include a <code>propTypes</code> check that requires <code>quantity</code> to be a <code>number</code>.
|
||||
testString: getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/ /g, ''); return noWhiteSpace.includes('quantity:PropTypes.number.isRequired') && noWhiteSpace.includes('Items.propTypes='); })());
|
||||
testString: getUserInput => assert((function() { const noWhiteSpace = __helpers.removeWhiteSpace(getUserInput('index')); return noWhiteSpace.includes('quantity:PropTypes.number.isRequired') && noWhiteSpace.includes('Items.propTypes='); })());
|
||||
|
||||
```
|
||||
|
||||
|
@ -77,7 +77,7 @@ tests:
|
||||
assert(!firstValue && secondValue && !thirdValue);
|
||||
})();"
|
||||
- text: An anonymous function should be passed to <code>setState</code>.
|
||||
testString: const paramRegex = '[a-zA-Z$_]\\w*(,[a-zA-Z$_]\\w*)?'; const noSpaces = code.replace(/\s/g, ''); assert(new RegExp('this\\.setState\\((function\\(' + paramRegex + '\\){|([a-zA-Z$_]\\w*|\\(' + paramRegex + '\\))=>)').test(noSpaces));
|
||||
testString: const paramRegex = '[a-zA-Z$_]\\w*(,[a-zA-Z$_]\\w*)?'; assert(new RegExp('this\\.setState\\((function\\(' + paramRegex + '\\){|([a-zA-Z$_]\\w*|\\(' + paramRegex + '\\))=>)').test(__helpers.removeWhiteSpace(code)));
|
||||
- text: <code>this</code> should not be used inside <code>setState</code>
|
||||
testString: assert(!/this\.setState\([^}]*this/.test(code));
|
||||
```
|
||||
|
@ -23,7 +23,7 @@ Render this component to the DOM using <code>ReactDOM.render()</code>. There is
|
||||
```yml
|
||||
tests:
|
||||
- text: There should be a React component called <code>MyComponent</code>.
|
||||
testString: getUserInput => assert(getUserInput('index').replace(/\s/g, '').includes('classMyComponentextendsReact.Component{'));
|
||||
testString: getUserInput => assert(__helpers.removeWhiteSpace(getUserInput('index')).includes('classMyComponentextendsReact.Component{'));
|
||||
- text: <code>MyComponent</code> should contain an <code>h1</code> tag with text <code>My First React Component!</code> Case and punctuation matter.
|
||||
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('h1').text() === 'My First React Component!'; })());
|
||||
- text: <code>MyComponent</code> should render to the DOM.
|
||||
|
@ -39,7 +39,7 @@ tests:
|
||||
- text: '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.'
|
||||
testString: "assert((function() { const state = store.getState(); return typeof state.auth === 'object' && typeof state.auth.authenticated === 'boolean' && typeof state.count === 'number' })());"
|
||||
- text: The <code>rootReducer</code> should be a function that combines the <code>counterReducer</code> and the <code>authReducer</code>.
|
||||
testString: getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\s/g,''); return typeof rootReducer === 'function' && noWhiteSpace.includes('Redux.combineReducers') })());
|
||||
testString: getUserInput => assert((function() { const noWhiteSpace = __helpers.removeWhiteSpace(getUserInput('index')); return typeof rootReducer === 'function' && noWhiteSpace.includes('Redux.combineReducers') })());
|
||||
|
||||
```
|
||||
|
||||
|
@ -35,9 +35,9 @@ tests:
|
||||
- text: The <code>authReducer</code> function should handle multiple action types with a switch statement.
|
||||
testString: getUserInput => assert((function() { return typeof authReducer === 'function' && getUserInput('index').toString().includes('switch') && getUserInput('index').toString().includes('case') && getUserInput('index').toString().includes('default') })());
|
||||
- text: <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>.
|
||||
testString: const noWhiteSpace = code.replace(/\s/g, ''); assert(/constLOGIN=(['"`])LOGIN\1/.test(noWhiteSpace) && /constLOGOUT=(['"`])LOGOUT\1/.test(noWhiteSpace));
|
||||
testString: const noWhiteSpace = __helpers.removeWhiteSpace(code); assert(/constLOGIN=(['"`])LOGIN\1/.test(noWhiteSpace) && /constLOGOUT=(['"`])LOGOUT\1/.test(noWhiteSpace));
|
||||
- text: The action creators and the reducer should reference the <code>LOGIN</code> and <code>LOGOUT</code> constants.
|
||||
testString: 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') })());
|
||||
testString: getUserInput => assert((function() { const noWhiteSpace = __helpers.removeWhiteSpace(getUserInput('index').toString()); return noWhiteSpace.includes('caseLOGIN:') && noWhiteSpace.includes('caseLOGOUT:') && noWhiteSpace.includes('type:LOGIN') && noWhiteSpace.includes('type:LOGOUT') })());
|
||||
|
||||
```
|
||||
|
||||
|
@ -33,7 +33,7 @@ tests:
|
||||
- text: Dispatching the requestingData action creator should update the store <code>state</code> property of fetching to <code>true</code>.
|
||||
testString: assert((function() { const initialState = store.getState(); store.dispatch(requestingData()); const reqState = store.getState(); return initialState.fetching === false && reqState.fetching === true })());
|
||||
- text: Dispatching <code>handleAsync</code> should dispatch the data request action and then dispatch the received data action after a delay.
|
||||
testString: assert((function() { const noWhiteSpace = handleAsync.toString().replace(/\s/g,''); return noWhiteSpace.includes('dispatch(requestingData())') === true && noWhiteSpace.includes('dispatch(receivedData(data))') === true })());
|
||||
testString: assert((function() { const noWhiteSpace = __helpers.removeWhiteSpace(handleAsync.toString()); return noWhiteSpace.includes('dispatch(requestingData())') === true && noWhiteSpace.includes('dispatch(receivedData(data))') === true })());
|
||||
|
||||
```
|
||||
|
||||
|
@ -41,7 +41,7 @@ tests:
|
||||
- text: <code>substringDivisibility()</code> should return [ 1430952867, 1460357289, 1406357289, 4130952867, 4160357289, 4106357289 ].
|
||||
testString: assert.sameMembers(substringDivisibility(), [ 1430952867, 1460357289, 1406357289, 4130952867, 4160357289, 4106357289 ]);
|
||||
- text: You should not copy and return the array.
|
||||
testString: assert(!removeJSComments(code).match(/(1430952867)|(1460357289)|(1406357289)|(4130952867)|(4160357289)|(4106357289)/))
|
||||
testString: assert(!__helpers.removeJSComments(code).match(/(1430952867)|(1460357289)|(1406357289)|(4130952867)|(4160357289)|(4106357289)/))
|
||||
|
||||
```
|
||||
|
||||
@ -63,15 +63,6 @@ substringDivisibility();
|
||||
|
||||
</div>
|
||||
|
||||
### After Test
|
||||
<div id='js-teardown'>
|
||||
|
||||
```js
|
||||
const removeJSComments = str => str.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
@ -77,7 +77,7 @@ function isValid(iban) {
|
||||
MC:27, MR:27, SM:27, AL:28, AZ:28, CY:28, DO:28, GT:28,
|
||||
HU:28, LB:28, PL:28, BR:29, PS:29, KW:30, MU:30, MT:31
|
||||
}
|
||||
iban = iban.replace(/\s/g, '')
|
||||
iban = __helpers.removeWhiteSpace(iban)
|
||||
if (!iban.match(/^[\dA-Z]+$/)) return false
|
||||
var len = iban.length
|
||||
if (len != ibanLen[iban.substr(0,2)]) return false
|
||||
|
@ -66,7 +66,7 @@ function solve(input) {
|
||||
function solve(input) {
|
||||
var orig = {};
|
||||
input.forEach(function(e) {
|
||||
orig[e.replace(/\s/g, '').toLowerCase()] = e;
|
||||
orig[__helpers.removeWhiteSpace(e).toLowerCase()] = e;
|
||||
});
|
||||
|
||||
input = Object.keys(orig);
|
||||
|
Loading…
x
Reference in New Issue
Block a user