Add Metric to Imperial certification project
This commit is contained in:
parent
e18a30816b
commit
c121d6a025
22 changed files with 3957 additions and 0 deletions
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"optOut": false,
|
||||
"lastUpdateCheck": 1660315504033
|
||||
}
|
2
7-quality-assurance/1-metric-imp-converter/.gitattributes
vendored
Normal file
2
7-quality-assurance/1-metric-imp-converter/.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Tell Linguist to exclude HTML files to help Replit language detection.
|
||||
*.html linguist-vendored
|
2
7-quality-assurance/1-metric-imp-converter/.gitignore
vendored
Normal file
2
7-quality-assurance/1-metric-imp-converter/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.env
|
||||
node_modules
|
|
@ -0,0 +1 @@
|
|||
.replit
|
59
7-quality-assurance/1-metric-imp-converter/.replit
Normal file
59
7-quality-assurance/1-metric-imp-converter/.replit
Normal file
|
@ -0,0 +1,59 @@
|
|||
run = "npm start"
|
||||
entrypoint = "server.js"
|
||||
|
||||
[packager]
|
||||
language = "nodejs"
|
||||
|
||||
[packager.features]
|
||||
packageSearch = true
|
||||
guessImports = true
|
||||
enabledForHosting = false
|
||||
|
||||
[env]
|
||||
XDG_CONFIG_HOME = "/home/runner/.config"
|
||||
PATH = "/home/runner/$REPL_SLUG/.config/npm/node_global/bin:/home/runner/$REPL_SLUG/node_modules/.bin"
|
||||
npm_config_prefix = "/home/runner/$REPL_SLUG/.config/npm/node_global"
|
||||
|
||||
[nix]
|
||||
channel = "stable-22_05"
|
||||
|
||||
[debugger]
|
||||
support = true
|
||||
|
||||
[debugger.interactive]
|
||||
transport = "localhost:0"
|
||||
startCommand = ["dap-node"]
|
||||
|
||||
[debugger.interactive.initializeMessage]
|
||||
command = "initialize"
|
||||
type = "request"
|
||||
|
||||
[debugger.interactive.initializeMessage.arguments]
|
||||
clientID = "replit"
|
||||
clientName = "replit.com"
|
||||
columnsStartAt1 = true
|
||||
linesStartAt1 = true
|
||||
locale = "en-us"
|
||||
pathFormat = "path"
|
||||
supportsInvalidatedEvent = true
|
||||
supportsProgressReporting = true
|
||||
supportsRunInTerminalRequest = true
|
||||
supportsVariablePaging = true
|
||||
supportsVariableType = true
|
||||
|
||||
[debugger.interactive.launchMessage]
|
||||
command = "launch"
|
||||
type = "request"
|
||||
|
||||
[debugger.interactive.launchMessage.arguments]
|
||||
console = "externalTerminal"
|
||||
cwd = "."
|
||||
pauseForSourceMap = false
|
||||
program = "./index.js"
|
||||
request = "launch"
|
||||
sourceMaps = true
|
||||
stopOnEntry = false
|
||||
type = "pwa-node"
|
||||
|
||||
[unitTest]
|
||||
language = "nodejs"
|
|
@ -0,0 +1 @@
|
|||
{"version":2,"languages":{"nodejs-npm":{"specfileHash":"b7193edd675f0fb97b8a16efc52d4e3c","lockfileHash":"db9ba5b054f4c040b4dc349779638bf2","guessedImports":["mocha","chai","cors","express","body-parser","dotenv"],"guessedImportsHash":"ebd5497271a4dced5969e250381705e0"}}}
|
3
7-quality-assurance/1-metric-imp-converter/README.md
Normal file
3
7-quality-assurance/1-metric-imp-converter/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Metric-Imperial Converter
|
||||
|
||||
This is the boilerplate for the Metric-Imperial Converter project. Instructions for building your project can be found at https://www.freecodecamp.org/learn/quality-assurance/quality-assurance-projects/metric-imperial-converter
|
139
7-quality-assurance/1-metric-imp-converter/assertion-analyser.js
Normal file
139
7-quality-assurance/1-metric-imp-converter/assertion-analyser.js
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* DO NOT EDIT THIS FILE
|
||||
* For FCC testing purposes!
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
function objParser(str, init) {
|
||||
// finds objects, arrays, strings, and function arguments
|
||||
// between parens, because they may contain ','
|
||||
let openSym = ['[', '{', '"', "'", '('];
|
||||
let closeSym = [']', '}', '"', "'", ')'];
|
||||
let type;
|
||||
let i;
|
||||
for(i = (init || 0); i < str.length; i++ ) {
|
||||
type = openSym.indexOf(str[i]);
|
||||
if( type !== -1) break;
|
||||
}
|
||||
if (type === -1) return null;
|
||||
let open = openSym[type];
|
||||
let close = closeSym[type];
|
||||
let count = 1;
|
||||
let k;
|
||||
for(k = i+1; k < str.length; k++) {
|
||||
if(open === '"' || open === "'") {
|
||||
if(str[k] === close) count--;
|
||||
if(str[k] === '\\') k++;
|
||||
} else {
|
||||
if(str[k] === open) count++;
|
||||
if(str[k] === close) count--;
|
||||
}
|
||||
if(count === 0) break;
|
||||
}
|
||||
if(count !== 0) return null;
|
||||
let obj = str.slice(i, k+1);
|
||||
return {
|
||||
start : i,
|
||||
end: k,
|
||||
obj: obj
|
||||
};
|
||||
}
|
||||
|
||||
function replacer(str) {
|
||||
// replace objects with a symbol ( __#n)
|
||||
let obj;
|
||||
let cnt = 0;
|
||||
let data = [];
|
||||
while(obj = objParser(str)) {
|
||||
data[cnt] = obj.obj;
|
||||
str = str.substring(0, obj.start) + '__#' + cnt++ + str.substring(obj.end+1)
|
||||
}
|
||||
return {
|
||||
str : str,
|
||||
dictionary : data
|
||||
}
|
||||
}
|
||||
|
||||
function splitter(str) {
|
||||
// split on commas, then restore the objects
|
||||
let strObj = replacer(str);
|
||||
let args = strObj.str.split(',');
|
||||
args = args.map(function(a){
|
||||
let m = a.match(/__#(\d+)/);
|
||||
while (m) {
|
||||
a = a.replace(/__#(\d+)/, strObj.dictionary[m[1]]);
|
||||
m = a.match(/__#(\d+)/);
|
||||
}
|
||||
return a.trim();
|
||||
})
|
||||
return args;
|
||||
}
|
||||
|
||||
function assertionAnalyser(body) {
|
||||
|
||||
// already filtered in the test runner
|
||||
// // remove comments
|
||||
// body = body.replace(/\/\/.*\n|\/\*.*\*\//g, '');
|
||||
// // get test function body
|
||||
// body = body.match(/\{\s*([\s\S]*)\}\s*$/)[1];
|
||||
|
||||
if(!body) return "invalid assertion";
|
||||
// replace assertions bodies, so that they cannot
|
||||
// contain the word 'assertion'
|
||||
|
||||
let cleanedBody = body.match(/(?:browser\s*\.\s*)?assert\s*\.\s*\w*\([\s\S]*\)/)
|
||||
if(cleanedBody && Array.isArray(cleanedBody)) {
|
||||
body = cleanedBody[0];
|
||||
} else {
|
||||
// No assertions present
|
||||
return [];
|
||||
}
|
||||
let s = replacer(body);
|
||||
// split on 'assertion'
|
||||
let splittedAssertions = s.str.split('assert');
|
||||
let assertions = splittedAssertions.slice(1);
|
||||
// match the METHODS
|
||||
|
||||
let assertionBodies = [];
|
||||
let methods = assertions.map(function(a, i){
|
||||
let m = a.match(/^\s*\.\s*(\w+)__#(\d+)/);
|
||||
assertionBodies.push(parseInt(m[2]));
|
||||
let pre = splittedAssertions[i].match(/browser\s*\.\s*/) ? 'browser.' : '';
|
||||
return pre + m[1];
|
||||
});
|
||||
if(methods.some(function(m){ return !m })) return "invalid assertion";
|
||||
// remove parens from the assertions bodies
|
||||
let bodies = assertionBodies.map(function(b){
|
||||
return s.dictionary[b].slice(1,-1).trim();
|
||||
});
|
||||
assertions = methods.map(function(m, i) {
|
||||
return {
|
||||
method: m,
|
||||
args: splitter(bodies[i]) //replace objects, split on ',' ,then restore objects
|
||||
}
|
||||
})
|
||||
return assertions;
|
||||
}
|
||||
|
||||
module.exports = assertionAnalyser;
|
|
@ -0,0 +1,91 @@
|
|||
function ConvertHandler() {
|
||||
|
||||
this.getNum = function(input) {
|
||||
let result = [];
|
||||
if (/^(km|mi|gal|L|lbs|kg)$/.test(input)){return 1}
|
||||
const tempResult = input.match(/(?!.*\/.*\/)(^\d+)([.]\d+)?(\/\d+([.]\d)?)?/)
|
||||
if (!tempResult){return 'invalid number'}
|
||||
result = tempResult[0]
|
||||
if (result.includes('/')) {
|
||||
let temp = result.split('/')
|
||||
|
||||
if (temp.length !== 2)
|
||||
return 'invalid number'
|
||||
|
||||
result = parseFloat(temp[0]) / parseFloat(temp[1])
|
||||
}
|
||||
return parseFloat(result);
|
||||
};
|
||||
|
||||
this.getUnit = function(input) {
|
||||
let result;
|
||||
result = input.match(/(km|mi|gal|L|lbs|kg)$/i)
|
||||
if (!result) {return 'invalid unit'}
|
||||
if (result[0].toLowerCase() === 'l'){return 'L'}
|
||||
|
||||
return result[0].toLowerCase();
|
||||
};
|
||||
|
||||
this.getReturnUnit = function(initUnit) {
|
||||
switch(initUnit){
|
||||
case 'gal':
|
||||
return 'L'
|
||||
case 'L':
|
||||
return 'gal'
|
||||
case 'mi':
|
||||
return 'km'
|
||||
case 'km':
|
||||
return 'mi'
|
||||
case 'lbs':
|
||||
return 'kg'
|
||||
case 'kg':
|
||||
return 'lbs'
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.spellOutUnit = function(unit) {
|
||||
switch(unit){
|
||||
case 'gal':
|
||||
return 'gallons'
|
||||
case 'L':
|
||||
return 'liters'
|
||||
case 'mi':
|
||||
return 'miles'
|
||||
case 'km':
|
||||
return 'kilometers'
|
||||
case 'lbs':
|
||||
return 'pounds'
|
||||
case 'kg':
|
||||
return 'kilograms'
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.convert = function(initNum, initUnit) {
|
||||
const galToL = 3.78541;
|
||||
const lbsToKg = 0.453592;
|
||||
const miToKm = 1.60934;
|
||||
switch (initUnit) {
|
||||
case 'gal':
|
||||
return (galToL * initNum)
|
||||
case 'lbs':
|
||||
return lbsToKg * initNum
|
||||
case 'mi':
|
||||
return miToKm * initNum
|
||||
case 'L':
|
||||
return initNum / galToL
|
||||
case 'kg':
|
||||
return initNum / lbsToKg
|
||||
case 'km':
|
||||
return initNum / miToKm
|
||||
}
|
||||
};
|
||||
|
||||
this.getString = function(initNum, initUnit, returnNum, returnUnit) {
|
||||
return (initNum + ' ' + this.spellOutUnit(initUnit) + ' converts to ' + Number(returnNum).toFixed(5) + ' ' + this.spellOutUnit(returnUnit))
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
module.exports = ConvertHandler;
|
3123
7-quality-assurance/1-metric-imp-converter/package-lock.json
generated
Normal file
3123
7-quality-assurance/1-metric-imp-converter/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
29
7-quality-assurance/1-metric-imp-converter/package.json
Normal file
29
7-quality-assurance/1-metric-imp-converter/package.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "fcc-imperial-metric-converter-boilerplate",
|
||||
"version": "1.0.0",
|
||||
"description": "Metric / Imperial Unit Converter",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"test": "mocha ./tests/ --ui tdd"
|
||||
},
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai-http": "^4.3.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"mocha": "^8.1.3"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/freeCodeCamp/boilerplate-project-metricimpconverter"
|
||||
},
|
||||
"keywords": [
|
||||
"node",
|
||||
"freeCodeCamp",
|
||||
"express"
|
||||
],
|
||||
"license": "MIT"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
code {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
section, header {
|
||||
margin: 50px;
|
||||
}
|
8
7-quality-assurance/1-metric-imp-converter/replit.nix
Normal file
8
7-quality-assurance/1-metric-imp-converter/replit.nix
Normal file
|
@ -0,0 +1,8 @@
|
|||
{ pkgs }: {
|
||||
deps = [
|
||||
pkgs.nodejs-16_x
|
||||
pkgs.nodePackages.typescript-language-server
|
||||
pkgs.yarn
|
||||
pkgs.replitPackages.jest
|
||||
];
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/_mocha","time":"2022-11-02T14:18:01Z"}
|
||||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/esparse","time":"2022-11-02T14:18:01Z"}
|
||||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/esvalidate","time":"2022-11-02T14:18:01Z"}
|
||||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/flat","time":"2022-11-02T14:18:01Z"}
|
||||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/he","time":"2022-11-02T14:18:01Z"}
|
||||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/js-yaml","time":"2022-11-02T14:18:01Z"}
|
||||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/mime","time":"2022-11-02T14:18:01Z"}
|
||||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/mocha","time":"2022-11-02T14:18:01Z"}
|
||||
{"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/node-which","time":"2022-11-02T14:18:01Z"}
|
21
7-quality-assurance/1-metric-imp-converter/routes/api.js
Normal file
21
7-quality-assurance/1-metric-imp-converter/routes/api.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
'use strict';
|
||||
const ConvertHandler = require('../controllers/convertHandler.js');
|
||||
|
||||
|
||||
module.exports = function (app) {
|
||||
|
||||
const convertHandler = new ConvertHandler();
|
||||
app.get('/api/convert', (req, res) => {
|
||||
let error
|
||||
const input = req.query.input
|
||||
const initNum = convertHandler.getNum(input)
|
||||
const initUnit = convertHandler.getUnit(input)
|
||||
if (initNum === 'invalid number') {error = 'invalid number'}
|
||||
if (initUnit === 'invalid unit') {if (!error){ error = 'invalid unit'} else {error = 'invalid number and unit'}}
|
||||
if (error){res.json(error)}
|
||||
const returnNum = parseFloat(convertHandler.convert(initNum, initUnit).toFixed(5))
|
||||
const returnUnit = convertHandler.getReturnUnit(initUnit)
|
||||
const string = convertHandler.getString(initNum, initUnit, returnNum, returnUnit)
|
||||
res.json({ initNum, initUnit, returnNum, returnUnit, string })
|
||||
})
|
||||
};
|
102
7-quality-assurance/1-metric-imp-converter/routes/fcctesting.js
Normal file
102
7-quality-assurance/1-metric-imp-converter/routes/fcctesting.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* DO NOT EDIT THIS FILE
|
||||
* For FCC testing purposes!
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const cors = require('cors');
|
||||
const fs = require('fs');
|
||||
const runner = require('../test-runner');
|
||||
|
||||
module.exports = function (app) {
|
||||
|
||||
app.route('/_api/server.js')
|
||||
.get(function(req, res, next) {
|
||||
console.log('requested');
|
||||
fs.readFile(__dirname + '/server.js', function(err, data) {
|
||||
if(err) return next(err);
|
||||
res.send(data.toString());
|
||||
});
|
||||
});
|
||||
app.route('/_api/routes/api.js')
|
||||
.get(function(req, res, next) {
|
||||
console.log('requested');
|
||||
fs.readFile(__dirname + '/routes/api.js', function(err, data) {
|
||||
if(err) return next(err);
|
||||
res.type('txt').send(data.toString());
|
||||
});
|
||||
});
|
||||
app.route('/_api/controllers/convertHandler.js')
|
||||
.get(function(req, res, next) {
|
||||
console.log('requested');
|
||||
fs.readFile(__dirname + '/controllers/convertHandler.js', function(err, data) {
|
||||
if(err) return next(err);
|
||||
res.type('txt').send(data.toString());
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/_api/get-tests', cors(), function(req, res, next){
|
||||
console.log('requested');
|
||||
if(process.env.NODE_ENV === 'test') return next();
|
||||
res.json({status: 'unavailable'});
|
||||
},
|
||||
function(req, res, next){
|
||||
if(!runner.report) return next();
|
||||
res.json(testFilter(runner.report, req.query.type, req.query.n));
|
||||
},
|
||||
function(req, res){
|
||||
runner.on('done', function(report){
|
||||
process.nextTick(() => res.json(testFilter(runner.report, req.query.type, req.query.n)));
|
||||
});
|
||||
});
|
||||
app.get('/_api/app-info', function(req, res) {
|
||||
let hs = Object.keys(res._headers)
|
||||
.filter(h => !h.match(/^access-control-\w+/));
|
||||
let hObj = {};
|
||||
hs.forEach(h => {hObj[h] = res._headers[h]});
|
||||
delete res._headers['strict-transport-security'];
|
||||
res.json({headers: hObj});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
function testFilter(tests, type, n) {
|
||||
let out;
|
||||
switch (type) {
|
||||
case 'unit' :
|
||||
out = tests.filter(t => t.context.match('Unit Tests'));
|
||||
break;
|
||||
case 'functional':
|
||||
out = tests.filter(t => t.context.match('Functional Tests') && !t.title.match('#example'));
|
||||
break;
|
||||
default:
|
||||
out = tests;
|
||||
}
|
||||
if(n !== undefined) {
|
||||
return out[n] || out;
|
||||
}
|
||||
return out;
|
||||
}
|
2
7-quality-assurance/1-metric-imp-converter/sample.env
Normal file
2
7-quality-assurance/1-metric-imp-converter/sample.env
Normal file
|
@ -0,0 +1,2 @@
|
|||
PORT=
|
||||
# NODE_ENV=test
|
59
7-quality-assurance/1-metric-imp-converter/server.js
Normal file
59
7-quality-assurance/1-metric-imp-converter/server.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
'use strict';
|
||||
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const expect = require('chai').expect;
|
||||
const cors = require('cors');
|
||||
require('dotenv').config();
|
||||
|
||||
const apiRoutes = require('./routes/api.js');
|
||||
const fccTestingRoutes = require('./routes/fcctesting.js');
|
||||
const runner = require('./test-runner');
|
||||
|
||||
let app = express();
|
||||
|
||||
app.use('/public', express.static(process.cwd() + '/public'));
|
||||
|
||||
app.use(cors({origin: '*'})); //For FCC testing purposes only
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
//Index page (static HTML)
|
||||
app.route('/')
|
||||
.get(function (req, res) {
|
||||
res.sendFile(process.cwd() + '/views/index.html');
|
||||
});
|
||||
|
||||
//For FCC testing purposes
|
||||
fccTestingRoutes(app);
|
||||
|
||||
//Routing for API
|
||||
apiRoutes(app);
|
||||
|
||||
//404 Not Found Middleware
|
||||
app.use(function(req, res, next) {
|
||||
res.status(404)
|
||||
.type('text')
|
||||
.send('Not Found');
|
||||
});
|
||||
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
//Start our server and tests!
|
||||
app.listen(port, function () {
|
||||
console.log("Listening on port " + port);
|
||||
if(process.env.NODE_ENV==='test') {
|
||||
console.log('Running Tests...');
|
||||
setTimeout(function () {
|
||||
try {
|
||||
runner.run();
|
||||
} catch(e) {
|
||||
console.log('Tests are not valid:');
|
||||
console.error(e);
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = app; //for testing
|
106
7-quality-assurance/1-metric-imp-converter/test-runner.js
Normal file
106
7-quality-assurance/1-metric-imp-converter/test-runner.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* DO NOT EDIT THIS FILE
|
||||
* For FCC testing purposes!
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const analyser = require('./assertion-analyser');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
||||
const Mocha = require('mocha'),
|
||||
fs = require('fs'),
|
||||
path = require('path');
|
||||
|
||||
let mocha = new Mocha();
|
||||
let testDir = './tests'
|
||||
|
||||
|
||||
// Add each .js file to the mocha instance
|
||||
fs.readdirSync(testDir).filter(function(file){
|
||||
// Only keep the .js files
|
||||
return file.substr(-3) === '.js';
|
||||
|
||||
}).forEach(function(file){
|
||||
mocha.addFile(
|
||||
path.join(testDir, file)
|
||||
);
|
||||
});
|
||||
|
||||
let emitter = new EventEmitter();
|
||||
emitter.run = function() {
|
||||
|
||||
let tests = [];
|
||||
let context = "";
|
||||
let separator = ' -> ';
|
||||
// Run the tests.
|
||||
try {
|
||||
let runner = mocha.ui('tdd').run()
|
||||
.on('test end', function(test) {
|
||||
// remove comments
|
||||
let body = test.body.replace(/\/\/.*\n|\/\*.*\*\//g, '');
|
||||
// collapse spaces
|
||||
body = body.replace(/\s+/g,' ');
|
||||
let obj = {
|
||||
title: test.title,
|
||||
context: context.slice(0, -separator.length),
|
||||
state: test.state,
|
||||
// body: body,
|
||||
assertions: analyser(body)
|
||||
};
|
||||
tests.push(obj);
|
||||
})
|
||||
.on('end', function() {
|
||||
emitter.report = tests;
|
||||
emitter.emit('done', tests)
|
||||
})
|
||||
.on('suite', function(s) {
|
||||
context += (s.title + separator);
|
||||
|
||||
})
|
||||
.on('suite end', function(s) {
|
||||
context = context.slice(0, -(s.title.length + separator.length))
|
||||
})
|
||||
} catch(e) {
|
||||
throw(e);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = emitter;
|
||||
|
||||
/*
|
||||
* Mocha.runner Events:
|
||||
* can be used to build a better custom report
|
||||
*
|
||||
* - `start` execution started
|
||||
* - `end` execution complete
|
||||
* - `suite` (suite) test suite execution started
|
||||
* - `suite end` (suite) all tests (and sub-suites) have finished
|
||||
* - `test` (test) test execution started
|
||||
* - `test end` (test) test completed
|
||||
* - `hook` (hook) hook execution started
|
||||
* - `hook end` (hook) hook complete
|
||||
* - `pass` (test) test passed
|
||||
* - `fail` (test, err) test failed
|
||||
* - `pending` (test) test pending
|
||||
*/
|
|
@ -0,0 +1,75 @@
|
|||
const chai = require('chai');
|
||||
let assert = chai.assert;
|
||||
const ConvertHandler = require('../controllers/convertHandler.js');
|
||||
|
||||
let convertHandler = new ConvertHandler();
|
||||
|
||||
suite('Unit Tests',() => {
|
||||
|
||||
test('convertHandler should correctly read a whole number input.', () => {
|
||||
assert.equal(convertHandler.getNum('5kg'), '5')
|
||||
assert.equal(convertHandler.getNum('3mi'), '3')
|
||||
})
|
||||
test('convertHandler should correctly read a decimal number input.', () => {
|
||||
assert.equal(convertHandler.getNum('5.5km'), '5.5')
|
||||
assert.equal(convertHandler.getNum('7.3mi'), '7.3')
|
||||
})
|
||||
test('convertHandler should correctly read a fractional input.', () => {
|
||||
assert.equal(convertHandler.getNum('3/4lbs'), '0.75')
|
||||
})
|
||||
test('convertHandler should correctly read a fractional input with a decimal', () => {
|
||||
assert.equal(convertHandler.getNum('1.5/3kg'), '0.5')
|
||||
})
|
||||
test('convertHandler should correctly return an error on a double-fraction (i.e. 3/2/3).', () => {
|
||||
assert.equal(convertHandler.getNum('3/2/3mi'), 'invalid number')
|
||||
})
|
||||
test('convertHandler should correctly default to a numerical input of 1 when no numerical input is provided.', () => {
|
||||
assert.equal(convertHandler.getNum('kg'), '1')
|
||||
})
|
||||
test('convertHandler should correctly read each valid input unit.', () => {
|
||||
assert.equal(convertHandler.getUnit('1gal'), 'gal')
|
||||
assert.equal(convertHandler.getUnit('2L'), 'L')
|
||||
assert.equal(convertHandler.getUnit('3/4l'), 'L')
|
||||
assert.equal(convertHandler.getUnit('5.7mi'), 'mi')
|
||||
assert.equal(convertHandler.getUnit('9/3km'), 'km')
|
||||
assert.equal(convertHandler.getUnit('3000lbs'), 'lbs')
|
||||
assert.equal(convertHandler.getUnit('2kg'), 'kg')
|
||||
})
|
||||
test('convertHandler should correctly return an error for an invalid input unit.', () => {
|
||||
assert.equal(convertHandler.getUnit('football fields'), 'invalid unit')
|
||||
})
|
||||
test('convertHandler should return the correct return unit for each valid input unit.', () => {
|
||||
assert.equal(convertHandler.getReturnUnit('gal'), 'L')
|
||||
assert.equal(convertHandler.getReturnUnit('L'), 'gal')
|
||||
assert.equal(convertHandler.getReturnUnit('mi'), 'km')
|
||||
assert.equal(convertHandler.getReturnUnit('km'), 'mi')
|
||||
assert.equal(convertHandler.getReturnUnit('lbs'), 'kg')
|
||||
assert.equal(convertHandler.getReturnUnit('kg'), 'lbs')
|
||||
})
|
||||
test('convertHandler should correctly return the spelled-out string unit for each valid input unit.', () => {
|
||||
assert.equal(convertHandler.spellOutUnit('gal'), 'gallons')
|
||||
assert.equal(convertHandler.spellOutUnit('L'), 'liters')
|
||||
assert.equal(convertHandler.spellOutUnit('mi'), 'miles')
|
||||
assert.equal(convertHandler.spellOutUnit('km'), 'kilometers')
|
||||
assert.equal(convertHandler.spellOutUnit('lbs'), 'pounds')
|
||||
assert.equal(convertHandler.spellOutUnit('kg'), 'kilograms')
|
||||
})
|
||||
test('convertHandler should correctly convert gal to L', () => {
|
||||
assert.approximately(convertHandler.convert(1, 'gal'), 3.78, 0.1)
|
||||
})
|
||||
test('convertHandler should correctly convert L to gal.', () => {
|
||||
assert.approximately(convertHandler.convert(1, 'L'), 0.26, 0.1)
|
||||
})
|
||||
test('convertHandler should correctly convert mi to km.', () => {
|
||||
assert.approximately(convertHandler.convert(1, 'mi'), 1.60, 0.1)
|
||||
})
|
||||
test('convertHandler should correctly convert km to mi.', () => {
|
||||
assert.approximately(convertHandler.convert(1, 'km'), 0.62, 0.1)
|
||||
})
|
||||
test('convertHandler should correctly convert lbs to kg.', () => {
|
||||
assert.approximately(convertHandler.convert(1, 'lbs'), 0.45, 0.1)
|
||||
})
|
||||
test('convertHandler should correctly convert kg to lbs.', () => {
|
||||
assert.approximately(convertHandler.convert(1, 'kg'), 2.2, 0.1)
|
||||
})
|
||||
});
|
|
@ -0,0 +1,55 @@
|
|||
const chaiHttp = require('chai-http');
|
||||
const chai = require('chai');
|
||||
let assert = chai.assert;
|
||||
const server = require('../server');
|
||||
|
||||
chai.use(chaiHttp);
|
||||
|
||||
suite('Functional Tests', function() {
|
||||
test('Convert a valid input such as 10L: GET request to /api/convert.', () => {
|
||||
chai
|
||||
.request(server)
|
||||
.get('/api/convert')
|
||||
.query({ input: '10L' })
|
||||
.end((err, res) => {
|
||||
assert.equal(res.body.initNum, 10)
|
||||
assert.equal(res.body.initUnit, 'L')
|
||||
})
|
||||
})
|
||||
test('Convert an invalid input such as 32g: GET request to /api/convert.', () => {
|
||||
chai
|
||||
.request(server)
|
||||
.get('/api/convert')
|
||||
.query({ input: '32g' })
|
||||
.end((err, res) => {
|
||||
assert.equal(res.body, 'invalid unit')
|
||||
})
|
||||
})
|
||||
test('Convert an invalid number such as 3/7.2/4kg: GET request to /api/convert', () => {
|
||||
chai
|
||||
.request(server)
|
||||
.get('/api/convert')
|
||||
.query({ input: '3/7.2/4kg' })
|
||||
.end((err, res) => {
|
||||
assert.equal(res.body, 'invalid number')
|
||||
})
|
||||
})
|
||||
test('Convert an invalid number AND unit such as 3/7.2/4kilomegagram: GET request to /api/convert.', () => {
|
||||
chai
|
||||
.request(server)
|
||||
.get('/api/convert')
|
||||
.query({ input: '3/7.2/4kilomegagram' })
|
||||
.end((err, res) => {
|
||||
assert.equal(res.body, 'invalid number and unit')
|
||||
})
|
||||
})
|
||||
test('Convert with no number such as kg: GET request to /api/convert.', () => {
|
||||
chai
|
||||
.request(server)
|
||||
.get('/api/convert')
|
||||
.query({ input: 'kg' })
|
||||
.end((err, res) => {
|
||||
assert.equal(res.body.initNum, 1)
|
||||
})
|
||||
})
|
||||
});
|
59
7-quality-assurance/1-metric-imp-converter/views/index.html
vendored
Normal file
59
7-quality-assurance/1-metric-imp-converter/views/index.html
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Metric/Imperial Converter</title>
|
||||
<meta name="description" content="An example of the Free Code Camp Metric/Imperial Converter Project">
|
||||
<link id="favicon" rel="icon" href="https://cdn.freecodecamp.org/universal/favicons/favicon-32x32.png" type="image/x-icon">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="./public/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Metric/Imperial Converter</h1>
|
||||
</header>
|
||||
<hr style='margin: 50px'>
|
||||
<section>
|
||||
<h3>Example usage</h3>
|
||||
<code>/api/convert?input=4gal</code><br>
|
||||
<code>/api/convert?input=1/2km</code><br>
|
||||
<code>/api/convert?input=5.4/3lbs</code><br>
|
||||
<code>/api/convert?input=kg</code><br>
|
||||
<h3>Example return</h3>
|
||||
<code>{ initNum: 3.1, initUnit: 'mi', returnNum: 4.98895, returnUnit: 'km', string: '3.1 miles converts to 4.98895 kilometers' }</code>
|
||||
</section>
|
||||
<hr style='margin: 50px'>
|
||||
<section>
|
||||
<div id='testui' >
|
||||
<h3 style="text-align: left">Front-End</h3>
|
||||
<form id="convertForm" class="border">
|
||||
<input type="text" id="convertField" name="input" placeholder="3.1mi" style="width: 200px">
|
||||
<input id="convert" type="submit" value='Convert!'>
|
||||
</form>
|
||||
<p id='result'></p>
|
||||
<code id='jsonResult'></code>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Your web-app is https, so your scripts need to be too -->
|
||||
<script src="https://code.jquery.com/jquery-2.2.1.min.js"
|
||||
integrity="sha256-gvQgAFzTH6trSrAWoH1iPo9Xc96QxSZ3feW6kem+O00="
|
||||
crossorigin="anonymous"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$('#convertForm').submit(function(event) {
|
||||
event.preventDefault();
|
||||
$.ajax({
|
||||
url: '/api/convert',
|
||||
type: 'get',
|
||||
data: $('#convertForm').serialize(),
|
||||
success: function(data) {
|
||||
$('#result').text(data.string || data);
|
||||
$('#jsonResult').text(JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Reference in a new issue