feat(learn): Add tests for refactored American/British Translator (#39822)
* feat(learn): Add tests for refactored American/British Translator * Move to Markdown formatting Co-authored-by: Shaun Hamilton <51722130+Sky020@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Tom <20648924+moT01@users.noreply.github.com> * Update curriculum/challenges/english/06-quality-assurance/quality-assurance-projects/american-british-translator.md Co-authored-by: Tom <20648924+moT01@users.noreply.github.com> * Update american-british-translator.md With contributions from @mot01 * Apply suggestions from code review Co-authored-by: Randell Dawson <5313213+RandellDawson@users.noreply.github.com> Co-authored-by: Shaun Hamilton <51722130+Sky020@users.noreply.github.com> Co-authored-by: Tom <20648924+moT01@users.noreply.github.com> Co-authored-by: Randell Dawson <5313213+RandellDawson@users.noreply.github.com>
This commit is contained in:
@ -6,16 +6,25 @@ challengeType: 4
|
|||||||
|
|
||||||
## Description
|
## Description
|
||||||
<section id='description'>
|
<section id='description'>
|
||||||
Build a full stack JavaScript app that is functionally similar to this: <a href="https://american-british-translator.freecodecamp.rocks/" target="_blank">https://american-british-translator.freecodecamp.rocks/</a>.
|
Build a full stack JavaScript app that is functionally similar to this: <a href='https://american-british-translator.freecodecamp.rocks/' target='_blank'>https://american-british-translator.freecodecamp.rocks/</a>. Working on this project will involve you writing your code using one of the following methods:
|
||||||
|
|
||||||
Working on this project will involve you writing your code on Repl.it on our starter project. After completing this project you can copy your public Repl.it URL (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.
|
- Clone <a href='https://github.com/freeCodeCamp/boilerplate-project-american-british-english-translator/' target='_blank'>this GitHub repo</a> and complete your project locally.
|
||||||
|
- Use <a href='https://repl.it/github/freeCodeCamp/boilerplate-project-american-british-english-translator' target='_blank'>our repl.it starter project</a> to complete your project.
|
||||||
|
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
|
||||||
|
|
||||||
Start this project on Repl.it using <a href="https://repl.it/github/freeCodeCamp/boilerplate-project-american-british-english-translator">this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-american-british-english-translator/'>this repository</a> on GitHub! If you use Repl.it, remember to save the link to your project somewhere safe!
|
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
## Instructions
|
## Instructions
|
||||||
<section id='instructions'>
|
<section id='instructions'>
|
||||||
|
|
||||||
|
- All logic can go into `/components/translator.js`
|
||||||
|
- Complete the `/api/translate` route in `/routes/api.js`
|
||||||
|
- Create all of the unit/functional tests in `tests/1_unit-tests.js` and `tests/2_functional-tests.js`
|
||||||
|
- See the JavaScript files in `/components` for the different spelling and terms your application should translate
|
||||||
|
- To run the tests on Repl.it, set `NODE_ENV` to `test` without quotes in the `.env` file
|
||||||
|
- To run the tests in the console, use the command `npm run test`. To open the Repl.it console, press Ctrl+Shift+P (Cmd if on a Mac) and type "open shell"
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
@ -28,28 +37,225 @@ tests:
|
|||||||
getUserInput => {
|
getUserInput => {
|
||||||
assert(!/.*\/american-british-translator\.freecodecamp\.rocks/.test(getUserInput('url')));
|
assert(!/.*\/american-british-translator\.freecodecamp\.rocks/.test(getUserInput('url')));
|
||||||
}
|
}
|
||||||
- text: I can enter a simple sentence into the text area and select whether to translate to British or American English from the dropdown menu.
|
|
||||||
testString: ''
|
- text: You can <code>POST</code> to <code>/api/translate</code> with a body containing <code>text</code> with the text to translate and <code>locale</code> with either <code>american-to-british</code> or <code>british-to-american</code>. The returned object should contain the submitted <code>text</code> and <code>translation</code> with the translated text.
|
||||||
- text: When the "Translate" button is pressed, append the translated sentence to the <code>translated-sentence</code> <code>div</code>. See the JavaScript files in <code>/public</code> for the different spelling and terms your application should translate.
|
testString: "async getUserInput => {
|
||||||
testString: ''
|
try {
|
||||||
- text: |
|
const text = 'Mangoes are my favorite fruit.';
|
||||||
Your application should handle the way time is written in American and British English. For example, ten thirty is written as "10.30" in British English and "10:30" in American English.
|
const locale = 'american-to-british';
|
||||||
testString: ''
|
const output = {
|
||||||
- text: Your application should also handle the way titles/honorifics are abbreviated in American and British English. For example, Doctor Wright is abbreviated as "Dr Wright" in British English and "Dr. Wright" in American English. See <code>/public/american-to-british-titles.js</code> for the different titles your application should handle.
|
text: 'Mangoes are my favorite fruit.',
|
||||||
testString: ''
|
translation: 'Mangoes are my <span class=\"highlight\">favourite</span> fruit.'
|
||||||
- text: Wrap any translated spelling or terms with <code><span class="highlight">...</span></code> tags so they appear in green.
|
};
|
||||||
testString: ''
|
let data = await fetch(getUserInput('url') + '/api/translate', {
|
||||||
- text: If the sentence in the text area has no spelling or terms that should be translated, append the message "Everything looks good to me!" to the <code>translated-sentence</code> <code>div</code>.
|
method: 'POST',
|
||||||
testString: ''
|
headers: {
|
||||||
- text: |
|
'Content-Type': 'application/json'
|
||||||
If there is no text in the text area, append the message "Error: No text to translate." to the <code>error-msg</code> <code>div</code> so the text appears in red.
|
},
|
||||||
testString: ''
|
body: JSON.stringify({text, locale})
|
||||||
- text: I can press the "Clear Input" button to remove all text from the text area and the <code>translated-sentence</code> <code>div</code>.
|
});
|
||||||
testString: ''
|
let parsed = await data.json();
|
||||||
- text: All 20 unit tests are complete and passing. See <code>/tests/1_unit-tests.js</code> for the sentences you should write tests for.
|
assert.isObject(parsed);
|
||||||
testString: ''
|
assert.property(parsed, 'text');
|
||||||
- text: All 4 functional tests are complete and passing. See <code>/tests/2_functional-tests.js</code> for the functionality you should write tests for.
|
assert.property(parsed, 'translation');
|
||||||
testString: ''
|
assert.deepEqual(parsed, output);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: The <code>/api/translate</code> route should handle the way time is written in American and British English. For example, ten thirty is written as "10.30" in British English and "10:30" in American English.
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const text = 'Lunch is at 12:15 today.';
|
||||||
|
const locale = 'american-to-british';
|
||||||
|
const output = {
|
||||||
|
text: text,
|
||||||
|
translation: 'Lunch is at <span class=\"highlight\">12.15</span> today.'
|
||||||
|
};
|
||||||
|
let data = await fetch(getUserInput('url') + '/api/translate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({text, locale})
|
||||||
|
});
|
||||||
|
let parsed = await data.json();
|
||||||
|
assert.isObject(parsed);
|
||||||
|
assert.property(parsed, 'text');
|
||||||
|
assert.property(parsed, 'translation');
|
||||||
|
assert.deepEqual(parsed, output);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: The <code>/api/translate</code> route should also handle the way titles/honorifics are abbreviated in American and British English. For example, Doctor Wright is abbreviated as "Dr Wright" in British English and "Dr. Wright" in American English. See <code>/public/american-to-british-titles.js</code> for the different titles your application should handle.
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const text = 'Dr. Grosh will see you now.';
|
||||||
|
const locale = 'american-to-british';
|
||||||
|
const output = {
|
||||||
|
text: text,
|
||||||
|
translation: '<span class=\"highlight\">Dr</span> Grosh will see you now.'
|
||||||
|
};
|
||||||
|
let data = await fetch(getUserInput('url') + '/api/translate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({text, locale})
|
||||||
|
});
|
||||||
|
let parsed = await data.json();
|
||||||
|
assert.isObject(parsed);
|
||||||
|
assert.property(parsed, 'text');
|
||||||
|
assert.property(parsed, 'translation');
|
||||||
|
assert.deepEqual(parsed, output);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: Wrap any translated spelling or terms with <code><span class="highlight">...</span></code> tags so they appear in green.
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const text = 'Mangoes are my favorite fruit.';
|
||||||
|
const locale = 'american-to-british';
|
||||||
|
const output = {
|
||||||
|
text: 'Mangoes are my favorite fruit.',
|
||||||
|
translation: 'Mangoes are my <span class=\"highlight\">favourite</span> fruit.'
|
||||||
|
};
|
||||||
|
let data = await fetch(getUserInput('url') + '/api/translate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({text, locale})
|
||||||
|
});
|
||||||
|
let parsed = await data.json();
|
||||||
|
assert.isObject(parsed);
|
||||||
|
assert.property(parsed, 'text');
|
||||||
|
assert.property(parsed, 'translation');
|
||||||
|
assert.deepEqual(parsed, output);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: If one or more of the required fields is missing, return <code>{ error: 'Required field(s) missing' }</code>.
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const locale = 'american-to-british';
|
||||||
|
let data = await fetch(getUserInput('url') + '/api/translate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({locale})
|
||||||
|
});
|
||||||
|
let parsed = await data.json();
|
||||||
|
assert.isObject(parsed);
|
||||||
|
assert.property(parsed, 'error');
|
||||||
|
assert.equal(parsed.error, 'Required field(s) missing');
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: If <code>text</code> is empty, return <code>{ error: 'No text to translate' }</code>
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const locale = 'american-to-british';
|
||||||
|
let data = await fetch(getUserInput('url') + '/api/translate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({text: '', locale})
|
||||||
|
});
|
||||||
|
let parsed = await data.json();
|
||||||
|
assert.isObject(parsed);
|
||||||
|
assert.property(parsed, 'error');
|
||||||
|
assert.equal(parsed.error, 'No text to translate');
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: If <code>locale</code> does not match one of the two specified locales, return <code>{ error: 'Invalid value for locale field' }</code>.
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const text = 'Ceci n\\'est pas une pipe';
|
||||||
|
const locale = 'french-to-american';
|
||||||
|
let data = await fetch(getUserInput('url') + '/api/translate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({text, locale})
|
||||||
|
});
|
||||||
|
let parsed = await data.json();
|
||||||
|
assert.isObject(parsed);
|
||||||
|
assert.property(parsed, 'error');
|
||||||
|
assert.equal(parsed.error, 'Invalid value for locale field');
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: If <code>text</code> requires no translation, return <code>"Everything looks good to me!"</code> for the <code>translation</code> value.
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const locale = 'british-to-american';
|
||||||
|
const output = {
|
||||||
|
text: 'SaintPeter and nhcarrigan give their regards!',
|
||||||
|
translation: 'Everything looks good to me!'
|
||||||
|
};
|
||||||
|
let data = await fetch(getUserInput('url') + '/api/translate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ text: output.text, locale})
|
||||||
|
});
|
||||||
|
let parsed = await data.json();
|
||||||
|
assert.isObject(parsed);
|
||||||
|
assert.isObject(parsed);
|
||||||
|
assert.property(parsed, 'text');
|
||||||
|
assert.property(parsed, 'translation');
|
||||||
|
assert.deepEqual(parsed, output);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: All 24 unit tests are complete and passing. See `/tests/1_unit-tests.js` for the expected behavior you should write tests for.
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const getTests = await $.get(getUserInput('url') + '/_api/get-tests' );
|
||||||
|
assert.isArray(getTests);
|
||||||
|
const unitTests = getTests.filter((test) => {
|
||||||
|
return !!test.context.match(/Unit Tests ->/ig);
|
||||||
|
});
|
||||||
|
assert.isAtLeast(unitTests.length, 24, 'At least 24 tests passed');
|
||||||
|
unitTests.forEach(test => {
|
||||||
|
assert.equal(test.state, 'passed', 'Tests in Passed State');
|
||||||
|
assert.isAtLeast(test.assertions.length, 1, 'At least one assertion per test');
|
||||||
|
});
|
||||||
|
} catch(err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
- text: All 6 functional tests are complete and passing. See `/tests/2_functional-tests.js` for the functionality you should write tests for.
|
||||||
|
testString: "async getUserInput => {
|
||||||
|
try {
|
||||||
|
const getTests = await $.get(getUserInput('url') + '/_api/get-tests' );
|
||||||
|
assert.isArray(getTests);
|
||||||
|
const functTests = getTests.filter((test) => {
|
||||||
|
return !!test.context.match(/Functional Tests ->/ig);
|
||||||
|
});
|
||||||
|
assert.isAtLeast(functTests.length, 6, 'At least 6 tests passed');
|
||||||
|
functTests.forEach(test => {
|
||||||
|
assert.equal(test.state, 'passed', 'Tests in Passed State');
|
||||||
|
assert.isAtLeast(test.assertions.length, 1, 'At least one assertion per test');
|
||||||
|
});
|
||||||
|
} catch(err) {
|
||||||
|
throw new Error(err.responseText || err.message);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
Reference in New Issue
Block a user