2018-10-04 14:37:37 +01:00
---
id: 587d8249367417b2b2512c41
title: Metric-Imperial Converter
challengeType: 4
2019-08-05 09:17:33 -07:00
forumTopicId: 301570
2021-01-13 03:31:00 +01:00
dashedName: metric-imperial-converter
2018-10-04 14:37:37 +01:00
---
2020-11-27 19:02:05 +01:00
# --description--
2020-11-20 12:02:31 -08:00
2020-11-27 19:02:05 +01:00
Build a full stack JavaScript app that is functionally similar to this: < https: / / metric-imperial-converter . freecodecamp . rocks / > . Working on this project will involve you writing your code using one of the following methods:
2021-01-20 20:51:57 -08:00
- Clone [this GitHub repo ](https://github.com/freeCodeCamp/boilerplate-project-metricimpconverter/ ) and complete your project locally.
2021-04-29 06:13:38 -04:00
- Use [our Replit starter project ](https://replit.com/github/freeCodeCamp/boilerplate-project-metricimpconverter ) to complete your project.
2021-01-20 20:51:57 -08:00
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
2020-11-20 12:02:31 -08:00
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.
2020-11-27 19:02:05 +01:00
2021-01-20 20:51:57 -08:00
# --instructions--
- Complete the necessary conversion logic in `/controllers/convertHandler.js`
- Complete the necessary routes in `/routes/api.js`
- Copy the `sample.env` file to `.env` and set the variables appropriately
- To run the tests uncomment `NODE_ENV=test` in your `.env` file
2021-04-29 06:13:38 -04:00
- To run the tests in the console, use the command `npm run test` . To open the Replit console, press Ctrl+Shift+P (Cmd if on a Mac) and type "open shell"
2021-01-20 20:51:57 -08:00
Write the following tests in `tests/1_unit-tests.js` :
- `convertHandler` should correctly read a whole number input.
- `convertHandler` should correctly read a decimal number input.
- `convertHandler` should correctly read a fractional input.
- `convertHandler` should correctly read a fractional input with a decimal.
- `convertHandler` should correctly return an error on a double-fraction (i.e. `3/2/3` ).
- `convertHandler` should correctly default to a numerical input of `1` when no numerical input is provided.
- `convertHandler` should correctly read each valid input unit.
- `convertHandler` should correctly return an error for an invalid input unit.
- `convertHandler` should return the correct return unit for each valid input unit.
- `convertHandler` should correctly return the spelled-out string unit for each valid input unit.
- `convertHandler` should correctly convert `gal` to `L` .
- `convertHandler` should correctly convert `L` to `gal` .
- `convertHandler` should correctly convert `mi` to `km` .
- `convertHandler` should correctly convert `km` to `mi` .
- `convertHandler` should correctly convert `lbs` to `kg` .
- `convertHandler` should correctly convert `kg` to `lbs` .
Write the following tests in `tests/2_functional-tests.js` :
- Convert a valid input such as `10L` : `GET` request to `/api/convert` .
- Convert an invalid input such as `32g` : `GET` request to `/api/convert` .
- Convert an invalid number such as `3/7.2/4kg` : `GET` request to `/api/convert` .
- Convert an invalid number AND unit such as `3/7.2/4kilomegagram` : `GET` request to `/api/convert` .
- Convert with no number such as `kg` : `GET` request to `/api/convert` .
2020-11-27 19:02:05 +01:00
# --hints--
2021-01-20 20:51:57 -08:00
You can provide your own project, not the example URL.
2020-11-27 19:02:05 +01:00
```js
2021-01-20 20:51:57 -08:00
getUserInput => {
2020-11-27 19:02:05 +01:00
assert(
!/.*\/metric-imperial-converter\.freecodecamp\.rocks/.test(
getUserInput('url')
)
);
};
```
2021-01-20 20:51:57 -08:00
You can `GET` `/api/convert` with a single parameter containing an accepted number and unit and have it converted. (Hint: Split the input by looking for the index of the first character which will mark the start of the unit)
2020-11-27 19:02:05 +01:00
```js
2021-03-04 04:14:28 +07:00
2018-10-04 14:37:37 +01:00
```
2021-01-20 20:51:57 -08:00
You can convert `'gal'` to `'L'` and vice versa. (1 gal to 3.78541 L)
2018-10-04 14:37:37 +01:00
2020-11-27 19:02:05 +01:00
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data1 = await $.get(getUserInput('url') + '/api/convert?input=1gal');
assert.equal(data1.returnNum, 3.78541);
assert.equal(data1.returnUnit, 'L');
const data2 = await $.get(getUserInput('url') + '/api/convert?input=10gal');
assert.equal(data2.returnNum, 37.8541);
assert.equal(data2.returnUnit, 'L');
const data3 = await $.get(getUserInput('url') + '/api/convert?input=1l');
assert.equal(data3.returnNum, 0.26417);
assert.equal(data3.returnUnit, 'gal');
const data4 = await $.get(getUserInput('url') + '/api/convert?input=10l');
assert.equal(data4.returnNum, 2.64172);
assert.equal(data4.returnUnit, 'gal');
} catch (xhr) {
throw new Error(xhr.responseText || xhr.message);
}
};
```
2021-01-20 20:51:57 -08:00
You can convert `'lbs'` to `'kg'` and vice versa. (1 lbs to 0.453592 kg)
2018-10-04 14:37:37 +01:00
2020-11-27 19:02:05 +01:00
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data1 = await $.get(getUserInput('url') + '/api/convert?input=1lbs');
assert.equal(data1.returnNum, 0.45359);
assert.equal(data1.returnUnit, 'kg');
const data2 = await $.get(getUserInput('url') + '/api/convert?input=10lbs');
assert.equal(data2.returnNum, 4.53592);
assert.equal(data2.returnUnit, 'kg');
const data3 = await $.get(getUserInput('url') + '/api/convert?input=1kg');
assert.equal(data3.returnNum, 2.20462);
assert.equal(data3.returnUnit, 'lbs');
const data4 = await $.get(getUserInput('url') + '/api/convert?input=10kg');
assert.equal(data4.returnNum, 22.04624);
assert.equal(data4.returnUnit, 'lbs');
} catch (xhr) {
throw new Error(xhr.responseText || xhr.message);
}
};
```
2021-01-20 20:51:57 -08:00
You can convert `'mi'` to `'km'` and vice versa. (1 mi to 1.60934 km)
2020-11-27 19:02:05 +01:00
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data1 = await $.get(getUserInput('url') + '/api/convert?input=1mi');
assert.equal(data1.returnNum, 1.60934);
assert.equal(data1.returnUnit, 'km');
const data2 = await $.get(getUserInput('url') + '/api/convert?input=10mi');
assert.equal(data2.returnNum, 16.0934);
assert.equal(data2.returnUnit, 'km');
const data3 = await $.get(getUserInput('url') + '/api/convert?input=1km');
assert.equal(data3.returnNum, 0.62137);
assert.equal(data3.returnUnit, 'mi');
const data4 = await $.get(getUserInput('url') + '/api/convert?input=10km');
assert.equal(data4.returnNum, 6.21373);
assert.equal(data4.returnUnit, 'mi');
} catch (xhr) {
throw new Error(xhr.responseText || xhr.message);
}
};
```
All incoming units should be accepted in both upper and lower case, but should be returned in both the `initUnit` and `returnUnit` in lower case, except for liter, which should be represented as an uppercase `'L'` .
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data1 = await $.get(getUserInput('url') + '/api/convert?input=1gal');
assert.equal(data1.initUnit, 'gal');
assert.equal(data1.returnUnit, 'L');
const data2 = await $.get(getUserInput('url') + '/api/convert?input=10L');
assert.equal(data2.initUnit, 'L');
assert.equal(data2.returnUnit, 'gal');
const data3 = await $.get(getUserInput('url') + '/api/convert?input=1l');
assert.equal(data3.initUnit, 'L');
assert.equal(data3.returnUnit, 'gal');
const data4 = await $.get(getUserInput('url') + '/api/convert?input=10KM');
assert.equal(data4.initUnit, 'km');
assert.equal(data4.returnUnit, 'mi');
} catch (xhr) {
throw new Error(xhr.responseText || xhr.message);
}
};
```
2021-01-20 20:51:57 -08:00
If the unit of measurement is invalid, returned will be `'invalid unit'` .
2020-11-27 19:02:05 +01:00
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data = await $.get(getUserInput('url') + '/api/convert?input=1min');
assert(data.error === 'invalid unit' || data === 'invalid unit');
} catch (xhr) {
throw new Error(xhr.responseText || xhr.message);
}
};
```
2018-10-04 14:37:37 +01:00
2021-01-20 20:51:57 -08:00
If the number is invalid, returned will be `'invalid number'` .
2020-11-27 19:02:05 +01:00
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data = await $.get(
getUserInput('url') + '/api/convert?input=1//2gal'
);
assert(data.error === 'invalid number' || data === 'invalid number');
} catch (xhr) {
throw new Error(xhr.responseText || xhr.message);
}
};
```
If both the unit and number are invalid, returned will be `'invalid number and unit'` .
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data = await $.get(
getUserInput('url') + '/api/convert?input=1//2min'
);
assert(
data.error === 'invalid number and unit' ||
data === 'invalid number and unit'
);
} catch (xhr) {
throw new Error(xhr.responseText || xhr.message);
}
};
```
2021-01-20 20:51:57 -08:00
You can use fractions, decimals or both in the parameter (ie. 5, 1/2, 2.5/6), but if nothing is provided it will default to 1.
2020-11-27 19:02:05 +01:00
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data1 = await $.get(getUserInput('url') + '/api/convert?input=mi');
assert.approximately(data1.initNum, 1, 0.001);
assert.approximately(data1.returnNum, 1.60934, 0.001);
assert.equal(data1.returnUnit, 'km');
const data2 = await $.get(getUserInput('url') + '/api/convert?input=1/5mi');
assert.approximately(data2.initNum, 1 / 5, 0.1);
assert.approximately(data2.returnNum, 0.32187, 0.001);
assert.equal(data2.returnUnit, 'km');
const data3 = await $.get(
getUserInput('url') + '/api/convert?input=1.5/7km'
);
assert.approximately(data3.initNum, 1.5 / 7, 0.001);
assert.approximately(data3.returnNum, 0.13315, 0.001);
assert.equal(data3.returnUnit, 'mi');
const data4 = await $.get(
getUserInput('url') + '/api/convert?input=3/2.7km'
);
assert.approximately(data4.initNum, 3 / 2.7, 0.001);
assert.approximately(data4.returnNum, 0.69041, 0.001);
assert.equal(data4.returnUnit, 'mi');
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
```
2021-01-20 20:51:57 -08:00
Your return will consist of the `initNum` , `initUnit` , `returnNum` , `returnUnit` , and `string` spelling out units in the format `'{initNum} {initUnitString} converts to {returnNum} {returnUnitString}'` with the result rounded to 5 decimals.
2020-11-27 19:02:05 +01:00
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const data = await $.get(getUserInput('url') + '/api/convert?input=2mi');
assert.equal(data.initNum, 2);
assert.equal(data.initUnit, 'mi');
assert.approximately(data.returnNum, 3.21868, 0.001);
assert.equal(data.returnUnit, 'km', 'returnUnit did not match');
assert.equal(data.string, '2 miles converts to 3.21868 kilometers');
} catch (xhr) {
throw new Error(xhr.responseText || xhr.message);
}
};
```
All 16 unit tests are complete and passing.
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const getTests = await $.get(getUserInput('url') + '/_api/get-tests');
assert.isArray(getTests);
2021-01-20 20:51:57 -08:00
const unitTests = getTests.filter(test => {
return !!test.context.match(/Unit Tests/gi);
2020-11-27 19:02:05 +01:00
});
assert.isAtLeast(unitTests.length, 16, 'At least 16 tests passed');
2021-01-20 20:51:57 -08:00
unitTests.forEach(test => {
2020-11-27 19:02:05 +01:00
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);
}
};
```
All 5 functional tests are complete and passing.
```js
2021-01-20 20:51:57 -08:00
async getUserInput => {
2020-11-27 19:02:05 +01:00
try {
const getTests = await $.get(getUserInput('url') + '/_api/get-tests');
assert.isArray(getTests);
2021-01-20 20:51:57 -08:00
const functTests = getTests.filter(test => {
return !!test.context.match(/Functional Tests/gi);
2020-11-27 19:02:05 +01:00
});
assert.isAtLeast(functTests.length, 5, 'At least 5 tests passed');
2021-01-20 20:51:57 -08:00
functTests.forEach(test => {
2020-11-27 19:02:05 +01:00
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);
}
};
```
# --solutions--
2018-10-04 14:37:37 +01:00
```js
2019-10-14 21:00:42 +05:30
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
2018-10-04 14:37:37 +01:00
```