diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 78e8e395da..ba4e245107 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,2 +1,2 @@
We're getting a lot of duplicate issues and bug reports that just aren't reporting actual bugs.
-So, before you submit your issue, please read the [Help! I've Found a Bug](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Help!-I've-Found-a-Bug) wiki page.
+So, before you submit your issue, please read the [Help I've Found a Bug](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Help-I've-Found-a-Bug) wiki page.
diff --git a/README.md b/README.md
index d62477d7bd..dba5013540 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,8 @@ bower install
# Create a .env file and populate it with the necessary API keys and secrets:
touch .env
+# Install Gulp globally
+npm install -g gulp
```
Edit your .env file with the following API keys accordingly (if you only use email login, only the MONGOHQ_URL, SESSION_SECRET, MANDRILL_USER and MANDRILL_PASSWORD fields are necessary. Keep in mind if you want to use more services you'll have to get your own API keys for those services.
@@ -112,6 +114,11 @@ DEBUG=true
# Start the mongo server
mongod
+# Create your mongo database.
+# Type "mongo" in your terminal to access the mongo shell
+use freecodecamp
+# Exit the mongo shell with control + d
+
# Seed your database with the challenges
node seed/
diff --git a/gulpfile.js b/gulpfile.js
index 8e1e345716..9cfded3db8 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -19,10 +19,12 @@ var Rx = require('rx'),
sync = require('browser-sync'),
inject = require('gulp-inject'),
+
// css
less = require('gulp-less'),
// lint
+ jsonlint = require('gulp-jsonlint'),
eslint = require('gulp-eslint');
@@ -60,6 +62,11 @@ var paths = {
syncWatch: [
'public/**/*.*'
+ ],
+
+ challenges: [
+ 'seed/challenges/*.json',
+ 'seed/under-construction/*.json'
]
};
@@ -163,12 +170,20 @@ gulp.task('sync', ['serve'], function() {
});
});
-gulp.task('lint', function() {
+gulp.task('lint-js', function() {
return gulp.src(['public/js/lib/**/*'])
.pipe(eslint())
.pipe(eslint.format());
});
+gulp.task('lint-json', function() {
+ return gulp.src(paths.challenges)
+ .pipe(jsonlint())
+ .pipe(jsonlint.reporter());
+});
+
+gulp.task('test-challenges', ['lint-json']);
+
gulp.task('less', function() {
return gulp.src('./public/css/*.less')
.pipe(plumber({ errorHandler: errorHandler }))
@@ -182,6 +197,7 @@ gulp.task('build', ['less']);
gulp.task('watch', ['less', 'serve', 'sync'], function() {
gulp.watch('./public/css/*.less', ['less']);
+ gulp.watch(paths.challenges, ['test-challenges']);
});
gulp.task('default', ['less', 'serve', 'sync', 'watch', 'pack-watch']);
diff --git a/package.json b/package.json
index b14ee1e15f..8aa3c12d40 100644
--- a/package.json
+++ b/package.json
@@ -120,6 +120,7 @@
"gulp": "~3.8.8",
"gulp-eslint": "~0.9.0",
"gulp-inject": "~1.0.2",
+ "gulp-jsonlint": "^1.1.0",
"gulp-nodemon": "^2.0.3",
"gulp-notify": "^2.2.0",
"gulp-plumber": "^1.0.1",
diff --git a/seed/challenges/basic-javascript.json b/seed/challenges/basic-javascript.json
index e5d5408fcc..086d04ac64 100644
--- a/seed/challenges/basic-javascript.json
+++ b/seed/challenges/basic-javascript.json
@@ -13,7 +13,8 @@
"// This is a comment.",
"The slash-star-star-slash comment will comment out everything between the /* and the */ characters:",
"/* This is also a comment */",
- "Try creating one of each."
+ "Try creating one of each.",
+ "And one more thing you need to notice. Starting at this waypoint in JavaScript related challenges (except AngularJS, all Ziplines, Git, Node.js and Express.js, MongoDB and Full Stack JavaScript Projects) you can see contents of assert() functions (in some challenges except(), assert.equal() and so on) which are used to test your code. It's part of these challenges that you are able to see the tests that are running against your code."
],
"tests":[
"assert(editor.getValue().match(/(\\/\\/)...../g), 'Create a \\/\\/ style comment that contains at least five letters');",
@@ -606,7 +607,7 @@
"Take the myArray array and shift() the first value off of it."
],
"tests": [
- "assert((function(d){if(d[0] == 23 && d[1][0] == 'dog' && d[1][1] == 3 && d[2] == undefined){return(true);}else{return(false);}})(myArray), 'myArray should only have the first two values left([\"John\", 23])');",
+ "assert((function(d){if(d[0] == 23 && d[1][0] == 'dog' && d[1][1] == 3 && d[2] == undefined){return(true);}else{return(false);}})(myArray), 'myArray should only have the last two values left([23, [\"dog\", 3]])');",
"assert((function(d){if(d === 'John' && typeof(myRemoved) === 'string'){return(true);}else{return(false);}})(myRemoved), 'myRemoved should contain \"John\"');"
],
"challengeSeed": [
@@ -670,8 +671,8 @@
"function functionName (a, b) {",
" return(a + b);",
"}",
- "We can \"call\" our function like this: functionName();, and it will run and return it's return value to us.",
- "Create and call a function called myFunction."
+ "We can \"call\" our function like this: functionName();, and it will run and return its return value to us.",
+ "Create and call a function called myFunction that returns the sum of a and b."
],
"tests":[
"assert((function(){if(typeof(f) !== \"undefined\" && typeof(f) === \"number\" && f === a + b && editor.getValue().match(/return/gi).length >= 1 && editor.getValue().match(/a/gi).length >= 1 && editor.getValue().match(/b/gi).length >= 1 && editor.getValue().match(/\\+/gi).length >= 1){return(true);}else{return(false);}})(), 'Your function should return the value of a + b');"
@@ -684,9 +685,9 @@
" return a - b;",
"};",
"",
- "//Don't modify above this line",
- "//Create a function called myFunction that returns the value of a plus b.",
- " // Only change code below this line.",
+ "// Don't modify above this line",
+ "// Create a function called myFunction that returns the value of a plus b.",
+ "// Only change code below this line.",
"",
"",
"",
@@ -903,7 +904,7 @@
"tests":[
"assert(typeof(myFunction()) === \"number\", 'The result of myFunction should be a number');",
"assert(editor.getValue().match(/Math.random/g), 'You should be using Math.random to create a random number');",
- "assert(!(''+myFunction()).match(/\\./g), 'You should have multiplied the result of Math.random by 10 to make it a number that\\'s greater then zero');",
+ "assert(!(''+myFunction()).match(/\\./g), 'You should have multiplied the result of Math.random by 10 to make it a number that\\'s greater than zero');",
"assert(editor.getValue().match(/Math.floor/g), 'You should use Math.floor to remove the decimal part of the number');"
],
"challengeSeed":[
diff --git a/seed/challenges/bootstrap.json b/seed/challenges/bootstrap.json
index 6710afb129..e7586afa55 100644
--- a/seed/challenges/bootstrap.json
+++ b/seed/challenges/bootstrap.json
@@ -177,7 +177,7 @@
"difficulty": 2.03,
"description": [
"Now that we're using Bootstrap, we can center our heading elements to make them look better. All we need to do is add the class text-center to our h1 and h2 elements.",
- "Remember that you can add several classes to the same element by separating each of them with a space, like this: <h2 class=\"text-red text-center\">your text</h2>."
+ "Remember that you can add several classes to the same element by separating each of them with a space, like this: <h2 class=\"red-text text-center\">your text</h2>."
],
"tests": [
"assert($(\"h2\").hasClass(\"text-center\"), 'Your h2 element should be centered by applying the class text-center')"
@@ -614,7 +614,7 @@
"Note that these buttons still need the btn and btn-block classes."
],
"tests": [
- "assert(new RegExp(\"delete\",\"gi\").test($(\"button\").text()), 'Create a new button element with the text \"delete\".')",
+ "assert(new RegExp(\"Delete\",\"gi\").test($(\"button\").text()), 'Create a new button element with the text \"Delete\".')",
"assert($(\"button.btn-block.btn\").length > 2, 'All of your Bootstrap buttons should have the btn and btn-block classes.')",
"assert($(\"button\").hasClass(\"btn-danger\"), 'Your new button should have the class btn-danger.')",
"assert(editor.match(/<\\/button>/g) && editor.match(/