diff --git a/.jshintignore b/.eslintignore similarity index 59% rename from .jshintignore rename to .eslintignore index 0fd4831..3a241f4 100644 --- a/.jshintignore +++ b/.eslintignore @@ -1,3 +1,2 @@ coverage -node_modules public/js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..1f67508 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('pa11y-lint-config/eslint/es6'); diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index 36dce16..0000000 --- a/.jscsrc +++ /dev/null @@ -1,94 +0,0 @@ -{ - "disallowEmptyBlocks": true, - "disallowImplicitTypeConversion": [ - "binary", - "boolean", - "numeric", - "string" - ], - "disallowKeywordsOnNewLine": [ - "catch", - "else" - ], - "disallowMixedSpacesAndTabs": true, - "disallowMultipleSpaces": true, - "disallowMultipleVarDecl": true, - "disallowNewlineBeforeBlockStatements": true, - "disallowParenthesesAroundArrowParam": true, - "disallowQuotedKeysInObjects": true, - "disallowSpaceAfterObjectKeys": { - "allExcept": [ - "method" - ] - }, - "disallowSpaceAfterPrefixUnaryOperators": true, - "disallowSpaceBeforeComma": true, - "disallowSpaceBeforeSemicolon": true, - "disallowSpacesInCallExpression": true, - "disallowSpacesInFunction": { - "beforeOpeningRoundBrace": true - }, - "disallowSpacesInsideArrayBrackets": true, - "disallowSpacesInsideBrackets": true, - "disallowSpacesInsideObjectBrackets": true, - "disallowSpacesInsideParentheses": true, - "disallowSpacesInsideTemplateStringPlaceholders": true, - "disallowTrailingComma": true, - "disallowTrailingWhitespace": true, - "disallowVar": true, - "disallowYodaConditions": true, - - "maximumLineLength": 100, - - "requireArrowFunctions": true, - "requireBlocksOnNewline": true, - "requireCamelCaseOrUpperCaseIdentifiers": true, - "requireCapitalizedConstructors": true, - "requireCommaBeforeLineBreak": true, - "requireCurlyBraces": true, - "requireDotNotation": true, - "requireFunctionDeclarations": true, - "requireLineBreakAfterVariableAssignment": true, - "requireLineFeedAtFileEnd": true, - "requireObjectKeysOnNewLine": true, - "requireParenthesesAroundIIFE": true, - "requireSemicolons": true, - "requireSpaceAfterBinaryOperators": true, - "requireSpaceAfterKeywords": [ - "if", - "else", - "for", - "while", - "do", - "switch", - "try", - "catch" - ], - "requireSpaceAfterLineComment": { - "allExcept": [ - "=" - ] - }, - "requireSpaceBeforeBinaryOperators": true, - "requireSpaceBeforeBlockStatements": true, - "requireSpaceBeforeObjectValues": true, - "requireSpaceBetweenArguments": true, - "requireSpacesInConditionalExpression": true, - "requireSpacesInForStatement": true, - "requireSpacesInFunction": { - "beforeOpeningCurlyBrace": true - }, - "requireTemplateStrings": true, - - "validateIndentation": "\t", - "validateLineBreaks": "LF", - "validateNewlineAfterArrayElements": true, - "validateParameterSeparator": ", ", - "validateQuoteMarks": "'", - - "excludeFiles": [ - "coverage", - "node_modules", - "public/js" - ] -} diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 4379be2..0000000 --- a/.jshintrc +++ /dev/null @@ -1,26 +0,0 @@ -{ - "curly": true, - "eqeqeq": true, - "esversion": 6, - "forin": true, - "globals": { - "after": true, - "afterEach": true, - "before": true, - "beforeEach": true, - "describe": true, - "it": true - }, - "latedef": "nofunc", - "maxcomplexity": 6, - "maxdepth": 2, - "maxparams": 4, - "noarg": true, - "node": true, - "nonew": true, - "nonstandard": true, - "shadow": false, - "strict": true, - "undef": true, - "unused": true -} diff --git a/Makefile b/Makefile index ae277b1..1f4331e 100644 --- a/Makefile +++ b/Makefile @@ -1,47 +1,27 @@ +include Makefile.node -# Color helpers -C_CYAN=\x1b[34;01m -C_RESET=\x1b[0m +# We need to run integration tests recursively +export INTEGRATION_FLAGS := --recursive -# Group targets -all: deps lint test -ci: lint test -# Install dependencies -deps: - @echo "$(C_CYAN)> installing dependencies$(C_RESET)" - @npm install +# Verify tasks +# ------------ -# Lint JavaScript -lint: jshint jscs +# Lint alias for backwards compatibility +lint: verify -# Run JSHint -jshint: - @echo "$(C_CYAN)> linting javascript$(C_RESET)" - @./node_modules/.bin/jshint . -# Run JavaScript Code Style -jscs: - @echo "$(C_CYAN)> checking javascript code style$(C_RESET)" - @./node_modules/.bin/jscs . - -# Run all tests -test: test-integration - -# Run integration tests -test-integration: - @echo "$(C_CYAN)> running integration tests$(C_RESET)" - @./node_modules/.bin/mocha ./test/integration --reporter spec --recursive --timeout 5000 --slow 50 +# Client-side asset tasks +# ----------------------- # Compile LESS less: - @echo "$(C_CYAN)> compiling less$(C_RESET)" - @./node_modules/.bin/lessc -x ./public/less/main.less ./public/css/site.min.css + @lessc -x ./public/less/main.less ./public/css/site.min.css + @$(TASK_DONE) # Compile client-side JavaScript uglify: - @echo "$(C_CYAN)> compiling client-side JavaScript$(C_RESET)" - @./node_modules/.bin/uglifyjs \ + @uglifyjs \ public/js/vendor/jquery/jquery.min.js \ public/js/vendor/bootstrap/js/alert.js \ public/js/vendor/bootstrap/js/dropdown.js \ @@ -55,5 +35,4 @@ uglify: public/js/vendor/flot/jquery.flot.resize.js \ public/js/site.js \ -o ./public/js/site.min.js - -.PHONY: test + @$(TASK_DONE) diff --git a/Makefile.node b/Makefile.node new file mode 100644 index 0000000..c82b55d --- /dev/null +++ b/Makefile.node @@ -0,0 +1,125 @@ +# +# Node.js Makefile +# ================ +# +# Do not update this file manually – it's maintained separately on GitHub: +# https://github.com/rowanmanning/makefiles/blob/master/Makefile.node +# +# To update to the latest version, run `make update-makefile`. +# + + +# Meta tasks +# ---------- + +.PHONY: test + + +# Useful variables +# ---------------- + +NPM_BIN = ./node_modules/.bin +export PATH := $(NPM_BIN):$(PATH) +export EXPECTED_COVERAGE := 90 +export INTEGRATION_TIMEOUT := 5000 +export INTEGRATION_SLOW := 4000 + + +# Output helpers +# -------------- + +TASK_DONE = echo "✓ $@ done" + + +# Group tasks +# ----------- + +all: install ci +ci: verify test + + +# Install tasks +# ------------- + +clean: + @git clean -fxd + @$(TASK_DONE) + +install: node_modules + @$(TASK_DONE) + +node_modules: package.json + @npm prune --production=false + @npm install + @$(TASK_DONE) + + +# Verify tasks +# ------------ + +verify: verify-javascript verify-dust verify-spaces + @$(TASK_DONE) + +verify-javascript: verify-eslint verify-jshint verify-jscs + @$(TASK_DONE) + +verify-dust: + @if [ -e .dustmiterc* ]; then dustmite --path ./view && $(TASK_DONE); fi + +verify-eslint: + @if [ -e .eslintrc* ]; then eslint . && $(TASK_DONE); fi + +verify-jshint: + @if [ -e .jshintrc* ]; then jshint . && $(TASK_DONE); fi + +verify-jscs: + @if [ -e .jscsrc* ]; then jscs . && $(TASK_DONE); fi + +verify-spaces: + @if [ -e .editorconfig* ] && [ -x $(NPM_BIN)/lintspaces ]; then \ + git ls-files | xargs lintspaces -e .editorconfig && $(TASK_DONE); \ + fi + +verify-coverage: + @if [ -d coverage ]; then \ + if [ -x $(NPM_BIN)/nyc ]; then \ + nyc check-coverage --lines $(EXPECTED_COVERAGE) --functions $(EXPECTED_COVERAGE) --branches $(EXPECTED_COVERAGE) && $(TASK_DONE); \ + else \ + if [ -x $(NPM_BIN)/istanbul ]; then \ + istanbul check-coverage --statement $(EXPECTED_COVERAGE) --branch $(EXPECTED_COVERAGE) --function $(EXPECTED_COVERAGE) && $(TASK_DONE); \ + fi \ + fi \ + fi + +# Test tasks +# ---------- + +test: test-unit-coverage verify-coverage test-integration + @$(TASK_DONE) + +test-unit: + @if [ -d test/unit ]; then mocha test/unit --recursive && $(TASK_DONE); fi + +test-unit-coverage: + @if [ -d test/unit ]; then \ + if [ -x $(NPM_BIN)/nyc ]; then \ + nyc --reporter=text --reporter=html $(NPM_BIN)/_mocha test/unit --recursive && $(TASK_DONE); \ + else \ + if [ -x $(NPM_BIN)/istanbul ]; then \ + istanbul cover $(NPM_BIN)/_mocha -- test/unit --recursive && $(TASK_DONE); \ + else \ + make test-unit; \ + fi \ + fi \ + fi + +test-integration: + @if [ -d test/integration ]; then mocha test/integration --timeout $(INTEGRATION_TIMEOUT) --slow $(INTEGRATION_SLOW) $(INTEGRATION_FLAGS) && $(TASK_DONE); fi + + +# Tooling tasks +# ------------- + +update-makefile: + @curl -s https://raw.githubusercontent.com/rowanmanning/makefiles/master/Makefile.node > Makefile.node + @$(TASK_DONE) diff --git a/README.md b/README.md index 8818a48..2984751 100644 --- a/README.md +++ b/README.md @@ -87,24 +87,20 @@ Contributing There are many ways to contribute to Pa11y Dashboard, we cover these in the [contributing guide](CONTRIBUTING.md) for this repo. -If you're ready to contribute some code, you'll need to clone the repo and get set up as outlined in the [setup guide](#setup). - -You'll need to start the application in test mode with: +If you're ready to contribute some code, you'll need to clone the repo and get set up as outlined in the [setup guide](#setup). You'll then need to start the application in test mode with: ```sh NODE_ENV=test node index.js ``` -Now you'll be able to run the following commands: +You'll now be able to run the following commands: ```sh -make # Run the lint and test tasks together -make lint # Run linters with the correct config -make test # Run integration tests +make verify # Verify all of the code (ESLint) +make test # Run all tests +make test-integration # Run the integration tests ``` -Code with lint errors or failing tests will not be accepted, please use the build tools outlined above. - To compile the client-side JavaScript and CSS, you'll need the following commands. Compiled code is committed to the repository. ```sh diff --git a/app.js b/app.js index 31a3965..1cecea0 100644 --- a/app.js +++ b/app.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const bodyParser = require('body-parser'); @@ -84,9 +83,9 @@ function initApp(config, callback) { settings: {} }; - app.express.use((req, res, next) => { - res.locals.isHomePage = (req.path === '/'); - res.locals.host = req.hostname; + app.express.use((request, response, next) => { + response.locals.isHomePage = (request.path === '/'); + response.locals.host = request.hostname; next(); }); @@ -105,27 +104,27 @@ function initApp(config, callback) { } // Error handling - app.express.get('*', (req, res) => { - res.status(404); - res.render('404'); + app.express.get('*', (request, response) => { + response.status(404); + response.render('404'); }); - app.express.use((err, req, res, next) => { - /* jshint unused: false */ - if (err.code === 'ECONNREFUSED') { - err = new Error('Could not connect to Pa11y Webservice'); + app.express.use((error, request, response, next) => { + /* eslint no-unused-vars: 'off' */ + if (error.code === 'ECONNREFUSED') { + error = new Error('Could not connect to Pa11y Webservice'); } - app.emit('route-error', err); + app.emit('route-error', error); if (process.env.NODE_ENV !== 'production') { - res.locals.error = err; + response.locals.error = error; } - res.status(500); - res.render('500'); + response.status(500); + response.render('500'); }); - app.server.listen(config.port, err => { + app.server.listen(config.port, error => { const address = app.server.address(); app.address = `http://${address.address}:${address.port}`; - callback(err, app); + callback(error, app); }); } diff --git a/config.js b/config.js index ffd84ca..a67d5cd 100644 --- a/config.js +++ b/config.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const fs = require('fs'); diff --git a/data/.eslintrc.js b/data/.eslintrc.js new file mode 100644 index 0000000..a3d4df7 --- /dev/null +++ b/data/.eslintrc.js @@ -0,0 +1,8 @@ +'use strict'; + +// Clone the main config +var config = module.exports = JSON.parse(JSON.stringify(require('../.eslintrc'))); + +// Disable max line length/statements +config.rules['max-len'] = 'off'; +config.rules['max-statements'] = 'off'; diff --git a/index.js b/index.js index 8b00f03..e12008f 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const chalk = require('chalk'); @@ -23,15 +22,19 @@ process.on('SIGINT', () => { process.exit(); }); -require('./app')(config, (err, app) => { +require('./app')(config, (error, app) => { + if (error) { + console.error(error.stack); + process.exit(1); + } console.log(''); console.log(chalk.underline.magenta('Pa11y Dashboard started')); console.log(chalk.grey('mode: %s'), process.env.NODE_ENV); console.log(chalk.grey('uri: %s'), app.address); - app.on('route-error', err => { - const stack = (err.stack ? err.stack.split('\n') : [err.message]); + app.on('route-error', error => { + const stack = (error.stack ? error.stack.split('\n') : [error.message]); const msg = chalk.red(stack.shift()); console.error(''); console.error(msg); @@ -40,7 +43,12 @@ require('./app')(config, (err, app) => { // Start the webservice if required if (typeof config.webservice === 'object') { - require('pa11y-webservice')(config.webservice, (err, webservice) => { + require('pa11y-webservice')(config.webservice, (error, webservice) => { + if (error) { + console.error(error.stack); + process.exit(1); + } + console.log(''); console.log(chalk.underline.cyan('Pa11y Webservice started')); console.log(chalk.grey('mode: %s'), process.env.NODE_ENV); diff --git a/package.json b/package.json index d977bfa..b53dcab 100644 --- a/package.json +++ b/package.json @@ -38,10 +38,10 @@ "devDependencies": { "bower": "~1.7", "cheerio": "~0.20", - "jscs": "^2", - "jshint": "^2", + "eslint": "^3.18.0", "less": "~2.7", "mocha": "^2", + "pa11y-lint-config": "^1.0.0", "proclaim": "^3", "request": "^2.74", "uglify-js": "~2.6" diff --git a/route/index.js b/route/index.js index dfd031e..2aa46b5 100644 --- a/route/index.js +++ b/route/index.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const presentTask = require('../view/presenter/task'); @@ -21,14 +20,14 @@ module.exports = route; // Route definition function route(app) { - app.express.get('/', (req, res, next) => { - app.webservice.tasks.get({lastres: true}, (err, tasks) => { - if (err) { - return next(err); + app.express.get('/', (request, response, next) => { + app.webservice.tasks.get({lastres: true}, (error, tasks) => { + if (error) { + return next(error); } - res.render('index', { + response.render('index', { tasks: tasks.map(presentTask), - deleted: (typeof req.query.deleted !== 'undefined'), + deleted: (typeof request.query.deleted !== 'undefined'), isHomePage: true }); }); diff --git a/route/new.js b/route/new.js index 91bf15b..feebce3 100644 --- a/route/new.js +++ b/route/new.js @@ -12,9 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - -/*jshint maxcomplexity:10*/ - 'use strict'; const getStandards = require('../data/standards'); @@ -25,24 +22,24 @@ module.exports = route; // Route definition function route(app) { - app.express.get('/new', (req, res) => { + app.express.get('/new', (request, response) => { const standards = getStandards().map(standard => { if (standard.title === 'WCAG2AA') { standard.selected = true; } return standard; }); - res.render('new', { + response.render('new', { standards: standards, isNewTaskPage: true }); }); - app.express.post('/new', (req, res) => { + app.express.post('/new', (request, response) => { let parsedActions; - if (req.body.actions) { - parsedActions = req.body.actions.split(/[\r\n]+/) + if (request.body.actions) { + parsedActions = request.body.actions.split(/[\r\n]+/) .map(action => { return action.trim(); }) @@ -52,26 +49,26 @@ function route(app) { } let parsedHeaders; - if (req.body.headers) { - parsedHeaders = httpHeaders(req.body.headers, true); + if (request.body.headers) { + parsedHeaders = httpHeaders(request.body.headers, true); } const newTask = { - name: req.body.name, - url: req.body.url, - standard: req.body.standard, - ignore: req.body.ignore || [], - timeout: req.body.timeout || undefined, - wait: req.body.wait || undefined, + name: request.body.name, + url: request.body.url, + standard: request.body.standard, + ignore: request.body.ignore || [], + timeout: request.body.timeout || undefined, + wait: request.body.wait || undefined, actions: parsedActions, - username: req.body.username || undefined, - password: req.body.password || undefined, + username: request.body.username || undefined, + password: request.body.password || undefined, headers: parsedHeaders, - hideElements: req.body.hideElements || undefined + hideElements: request.body.hideElements || undefined }; - app.webservice.tasks.create(newTask, (err, task) => { - if (err) { + app.webservice.tasks.create(newTask, (error, task) => { + if (error) { const standards = getStandards().map(standard => { if (standard.title === newTask.standard) { standard.selected = true; @@ -84,15 +81,15 @@ function route(app) { }); return standard; }); - newTask.actions = req.body.actions; - newTask.headers = req.body.headers; - return res.render('new', { - error: err, + newTask.actions = request.body.actions; + newTask.headers = request.body.headers; + return response.render('new', { + error: error, standards: standards, task: newTask }); } - res.redirect(`/${task.id}?added`); + response.redirect(`/${task.id}?added`); }); }); diff --git a/route/result/download.js b/route/result/download.js index e232ae3..6b71aff 100644 --- a/route/result/download.js +++ b/route/result/download.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const moment = require('moment'); @@ -22,20 +21,20 @@ module.exports = route; // Route definition function route(app) { - function getTaskAndResult(req, res, next) { - app.webservice.task(req.params.id).get({}, (err, task) => { - if (err) { + function getTaskAndResult(request, response, next) { + app.webservice.task(request.params.id).get({}, (error, task) => { + if (error) { return next('route'); } app.webservice - .task(req.params.id) - .result(req.params.rid) - .get({full: true}, (err, result) => { - if (err) { + .task(request.params.id) + .result(request.params.rid) + .get({full: true}, (error, result) => { + if (error) { return next('route'); } - res.locals.task = task; - res.locals.result = result; + response.locals.task = task; + response.locals.result = result; next(); }); }); @@ -48,7 +47,7 @@ function route(app) { task.url .replace(/^https?:\/\//i, '') .replace(/\/$/, '') - .replace(/[^a-z0-9\.\-\_]+/gi, '-'), + .replace(/[^a-z0-9.\-_]+/gi, '-'), '--', task.standard.toLowerCase(), '--', @@ -58,9 +57,9 @@ function route(app) { ].join(''); } - app.express.get('/:id/:rid.csv', getTaskAndResult, (req, res) => { - const task = res.locals.task; - const result = res.locals.result; + app.express.get('/:id/:rid.csv', getTaskAndResult, (request, response) => { + const task = response.locals.task; + const result = response.locals.result; const rows = ['"code","message","type","context","selector"']; result.results.forEach(msg => { rows.push([ @@ -71,18 +70,18 @@ function route(app) { JSON.stringify(msg.selector) ].join(',')); }); - res.attachment(getDownloadFileName(task, result, 'csv')); - res.send(rows.join('\n')); + response.attachment(getDownloadFileName(task, result, 'csv')); + response.send(rows.join('\n')); }); - app.express.get('/:id/:rid.json', getTaskAndResult, (req, res) => { - const task = res.locals.task; - const result = res.locals.result; - res.attachment(getDownloadFileName(task, result, 'json')); + app.express.get('/:id/:rid.json', getTaskAndResult, (request, response) => { + const task = response.locals.task; + const result = response.locals.result; + response.attachment(getDownloadFileName(task, result, 'json')); delete task.id; delete result.id; result.task = task; - res.send(result); + response.send(result); }); } diff --git a/route/result/index.js b/route/result/index.js index 296fb61..a200c32 100644 --- a/route/result/index.js +++ b/route/result/index.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const presentTask = require('../../view/presenter/task'); @@ -23,19 +22,19 @@ module.exports = route; // Route definition function route(app) { - app.express.get('/:id/:rid', (req, res, next) => { - app.webservice.task(req.params.id).get({}, (err, task) => { - if (err) { + app.express.get('/:id/:rid', (request, response, next) => { + app.webservice.task(request.params.id).get({}, (error, task) => { + if (error) { return next(); } app.webservice - .task(req.params.id) - .result(req.params.rid) - .get({full: true}, (err, result) => { - if (err) { + .task(request.params.id) + .result(request.params.rid) + .get({full: true}, (error, result) => { + if (error) { return next(); } - res.render('result', { + response.render('result', { task: presentTask(task), mainResult: presentResult(result), isResultPage: true diff --git a/route/task/delete.js b/route/task/delete.js index b7aebc3..6d9d946 100644 --- a/route/task/delete.js +++ b/route/task/delete.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const presentTask = require('../../view/presenter/task'); @@ -22,24 +21,24 @@ module.exports = route; // Route definition function route(app) { - app.express.get('/:id/delete', (req, res, next) => { - app.webservice.task(req.params.id).get({}, (err, task) => { - if (err) { + app.express.get('/:id/delete', (request, response, next) => { + app.webservice.task(request.params.id).get({}, (error, task) => { + if (error) { return next(); } - res.render('task/delete', { + response.render('task/delete', { task: presentTask(task), isTaskSubPage: true }); }); }); - app.express.post('/:id/delete', (req, res, next) => { - app.webservice.task(req.params.id).remove(err => { - if (err) { + app.express.post('/:id/delete', (request, response, next) => { + app.webservice.task(request.params.id).remove(error => { + if (error) { return next(); } - res.redirect('/?deleted'); + response.redirect('/?deleted'); }); }); diff --git a/route/task/edit.js b/route/task/edit.js index bae572b..3be4277 100644 --- a/route/task/edit.js +++ b/route/task/edit.js @@ -12,9 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - -/*jshint maxcomplexity:12*/ - 'use strict'; const presentTask = require('../../view/presenter/task'); @@ -26,9 +23,9 @@ module.exports = route; // Route definition function route(app) { - app.express.get('/:id/edit', (req, res, next) => { - app.webservice.task(req.params.id).get({}, (err, task) => { - if (err) { + app.express.get('/:id/edit', (request, response, next) => { + app.webservice.task(request.params.id).get({}, (error, task) => { + if (error) { return next(); } const standards = getStandards().map(standard => { @@ -44,8 +41,8 @@ function route(app) { return standard; }); task.actions = (task.actions ? task.actions.join('\n') : ''); - res.render('task/edit', { - edited: (typeof req.query.edited !== 'undefined'), + response.render('task/edit', { + edited: (typeof request.query.edited !== 'undefined'), standards: standards, task: presentTask(task), isTaskSubPage: true @@ -53,18 +50,18 @@ function route(app) { }); }); - app.express.post('/:id/edit', (req, res, next) => { - app.webservice.task(req.params.id).get({}, (err, task) => { - if (err) { + app.express.post('/:id/edit', (request, response, next) => { + app.webservice.task(request.params.id).get({}, (error, task) => { + if (error) { return next(); } - const originalActions = req.body.actions; - const originalHeaders = req.body.headers; - req.body.ignore = req.body.ignore || []; - req.body.timeout = req.body.timeout || undefined; - req.body.wait = req.body.wait || undefined; - if (req.body.actions) { - req.body.actions = req.body.actions.split(/[\r\n]+/) + const originalActions = request.body.actions; + const originalHeaders = request.body.headers; + request.body.ignore = request.body.ignore || []; + request.body.timeout = request.body.timeout || undefined; + request.body.wait = request.body.wait || undefined; + if (request.body.actions) { + request.body.actions = request.body.actions.split(/[\r\n]+/) .map(action => { return action.trim(); }) @@ -72,24 +69,24 @@ function route(app) { return Boolean(action); }); } - if (!req.body.actions) { - req.body.actions = []; + if (!request.body.actions) { + request.body.actions = []; } - req.body.username = req.body.username || undefined; - req.body.password = req.body.password || undefined; - req.body.hideElements = req.body.hideElements || undefined; - req.body.headers = httpHeaders(req.body.headers || '', true); - app.webservice.task(req.params.id).edit(req.body, err => { - if (err) { - task.name = req.body.name; - task.ignore = req.body.ignore; - task.timeout = req.body.timeout; - task.wait = req.body.wait; + request.body.username = request.body.username || undefined; + request.body.password = request.body.password || undefined; + request.body.hideElements = request.body.hideElements || undefined; + request.body.headers = httpHeaders(request.body.headers || '', true); + app.webservice.task(request.params.id).edit(request.body, error => { + if (error) { + task.name = request.body.name; + task.ignore = request.body.ignore; + task.timeout = request.body.timeout; + task.wait = request.body.wait; task.actions = originalActions; - task.username = req.body.username; - task.password = req.body.password; + task.username = request.body.username; + task.password = request.body.password; task.headers = originalHeaders; - task.hideElements = req.body.hideElements; + task.hideElements = request.body.hideElements; const standards = getStandards().map(standard => { if (standard.title === task.standard) { standard.selected = true; @@ -102,14 +99,14 @@ function route(app) { }); return standard; }); - return res.render('task/edit', { - error: err, + return response.render('task/edit', { + error: error, standards: standards, task: task, isTaskSubPage: true }); } - res.redirect(`/${req.params.id}/edit?edited`); + response.redirect(`/${request.params.id}/edit?edited`); }); }); }); diff --git a/route/task/ignore.js b/route/task/ignore.js index 18b8c8b..2bf4073 100644 --- a/route/task/ignore.js +++ b/route/task/ignore.js @@ -5,20 +5,20 @@ module.exports = route; // Route definition function route(app) { - app.express.post('/:id/ignore', (req, res, next) => { - app.webservice.task(req.params.id).get({}, (err, task) => { - if (err) { + app.express.post('/:id/ignore', (request, response, next) => { + app.webservice.task(request.params.id).get({}, (error, task) => { + if (error) { return next(); } const edit = { name: task.name, ignore: task.ignore }; - if (typeof req.body.rule === 'string') { - edit.ignore.push(req.body.rule); + if (typeof request.body.rule === 'string') { + edit.ignore.push(request.body.rule); } - app.webservice.task(req.params.id).edit(edit, () => { - res.redirect(`/${req.params.id}?rule-ignored`); + app.webservice.task(request.params.id).edit(edit, () => { + response.redirect(`/${request.params.id}?rule-ignored`); }); }); }); diff --git a/route/task/index.js b/route/task/index.js index 234e3e1..5c76128 100644 --- a/route/task/index.js +++ b/route/task/index.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const presentTask = require('../../view/presenter/task'); @@ -24,24 +23,24 @@ module.exports = route; // Route definition function route(app) { - app.express.get('/:id', (req, res, next) => { - app.webservice.task(req.params.id).get({lastres: true}, (err, task) => { - if (err) { + app.express.get('/:id', (request, response, next) => { + app.webservice.task(request.params.id).get({lastres: true}, (error, task) => { + if (error) { return next(); } - app.webservice.task(req.params.id).results({}, (err, results) => { - if (err) { - return next(err); + app.webservice.task(request.params.id).results({}, (error, results) => { + if (error) { + return next(error); } const presentedResults = presentResultList(results.map(presentResult)); - res.render('task', { + response.render('task', { task: presentTask(task), results: presentedResults, mainResult: task.lastResult || null, - added: (typeof req.query.added !== 'undefined'), - running: (typeof req.query.running !== 'undefined'), - ruleIgnored: (typeof req.query['rule-ignored'] !== 'undefined'), - ruleUnignored: (typeof req.query['rule-unignored'] !== 'undefined'), + added: (typeof request.query.added !== 'undefined'), + running: (typeof request.query.running !== 'undefined'), + ruleIgnored: (typeof request.query['rule-ignored'] !== 'undefined'), + ruleUnignored: (typeof request.query['rule-unignored'] !== 'undefined'), hasOneResult: (presentedResults.length < 2), isTaskPage: true }); diff --git a/route/task/run.js b/route/task/run.js index b5f85cb..9cb0102 100644 --- a/route/task/run.js +++ b/route/task/run.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; module.exports = route; @@ -20,12 +19,12 @@ module.exports = route; // Route definition function route(app) { - app.express.get('/:id/run', (req, res, next) => { - app.webservice.task(req.params.id).run(err => { - if (err) { + app.express.get('/:id/run', (request, response, next) => { + app.webservice.task(request.params.id).run(error => { + if (error) { return next(); } - res.redirect(`/${req.params.id}?running`); + response.redirect(`/${request.params.id}?running`); }); }); diff --git a/route/task/unignore.js b/route/task/unignore.js index 412d9e3..6c9e98e 100644 --- a/route/task/unignore.js +++ b/route/task/unignore.js @@ -5,21 +5,21 @@ module.exports = route; // Route definition function route(app) { - app.express.post('/:id/unignore', (req, res, next) => { - app.webservice.task(req.params.id).get({}, (err, task) => { - if (err) { + app.express.post('/:id/unignore', (request, response, next) => { + app.webservice.task(request.params.id).get({}, (error, task) => { + if (error) { return next(); } const edit = { name: task.name, ignore: task.ignore }; - const indexOfRule = edit.ignore.indexOf(req.body.rule); - if (typeof req.body.rule === 'string' && indexOfRule !== -1) { + const indexOfRule = edit.ignore.indexOf(request.body.rule); + if (typeof request.body.rule === 'string' && indexOfRule !== -1) { edit.ignore.splice(indexOfRule, 1); } - app.webservice.task(req.params.id).edit(edit, () => { - res.redirect(`/${req.params.id}?rule-unignored`); + app.webservice.task(request.params.id).edit(edit, () => { + response.redirect(`/${request.params.id}?rule-unignored`); }); }); }); diff --git a/test/.eslintrc.js b/test/.eslintrc.js new file mode 100644 index 0000000..1d1bc36 --- /dev/null +++ b/test/.eslintrc.js @@ -0,0 +1,15 @@ +'use strict'; + +// Clone the main config +var config = module.exports = JSON.parse(JSON.stringify(require('../.eslintrc'))); + +// We use `this` all over the integration tests +config.rules['no-invalid-this'] = 'off'; + +// Because of our use of `this`, arrow functions +// aren't really gonna work in the integration tests +config.rules['prefer-arrow-callback'] = 'off'; + +// Disable max line length/statements +config.rules['max-len'] = 'off'; +config.rules['max-statements'] = 'off'; diff --git a/test/integration/helper/navigate.js b/test/integration/helper/navigate.js index 456a8ec..9294684 100644 --- a/test/integration/helper/navigate.js +++ b/test/integration/helper/navigate.js @@ -38,12 +38,15 @@ function createNavigator(baseUrl, store) { json: opts.json || false, qs: opts.query, followAllRedirects: true - }, function(err, res, body) { + }, function(error, response, body) { + if (error) { + return callback(error); + } store.body = body; - store.request = res.request; - store.response = res; - store.status = res.statusCode; + store.request = response.request; + store.response = response; + store.status = response.statusCode; if (opts.nonDom) { store.dom = null; diff --git a/test/integration/route/index.js b/test/integration/route/index.js index 18a259b..5ea162c 100644 --- a/test/integration/route/index.js +++ b/test/integration/route/index.js @@ -21,11 +21,11 @@ const assert = require('proclaim'); describe.only('GET /', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { diff --git a/test/integration/route/new.js b/test/integration/route/new.js index b86a30f..e1efba5 100644 --- a/test/integration/route/new.js +++ b/test/integration/route/new.js @@ -21,11 +21,11 @@ const assert = require('proclaim'); describe('GET /new', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/new' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -122,7 +122,7 @@ describe('POST /new', function() { describe('with invalid query', function() { beforeEach(function(done) { - const req = { + const request = { method: 'POST', endpoint: '/new', form: { @@ -130,7 +130,7 @@ describe('POST /new', function() { url: '' } }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -146,7 +146,7 @@ describe('POST /new', function() { describe('with valid query', function() { beforeEach(function(done) { - const req = { + const request = { method: 'POST', endpoint: '/new', form: { @@ -155,7 +155,7 @@ describe('POST /new', function() { standard: 'WCAG2AA' } }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -163,9 +163,9 @@ describe('POST /new', function() { }); it('should create the task', function(done) { - this.webservice.tasks.get({}, function(err, tasks) { + this.webservice.tasks.get({}, function(error, tasks) { assert.strictEqual(tasks.length, 4); - done(); + done(error); }); }); diff --git a/test/integration/route/result/download.js b/test/integration/route/result/download.js index be22d6c..dd1a3c7 100644 --- a/test/integration/route/result/download.js +++ b/test/integration/route/result/download.js @@ -21,12 +21,12 @@ const assert = require('proclaim'); describe('GET //.csv', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/abc000000000000000000001/def000000000000000000001.csv', nonDom: true }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -42,13 +42,13 @@ describe('GET //.csv', function() { describe('GET //.json', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/abc000000000000000000001/def000000000000000000001.json', nonDom: true, json: true }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { diff --git a/test/integration/route/result/index.js b/test/integration/route/result/index.js index 3c759a8..7ebafaa 100644 --- a/test/integration/route/result/index.js +++ b/test/integration/route/result/index.js @@ -21,11 +21,11 @@ const assert = require('proclaim'); describe('GET //', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/abc000000000000000000001/def000000000000000000001' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { diff --git a/test/integration/route/task/delete.js b/test/integration/route/task/delete.js index 6298d9e..8b5c257 100644 --- a/test/integration/route/task/delete.js +++ b/test/integration/route/task/delete.js @@ -21,11 +21,11 @@ const assert = require('proclaim'); describe('GET //delete', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/abc000000000000000000001/delete' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -48,11 +48,11 @@ describe('GET //delete', function() { describe('POST //delete', function() { beforeEach(function(done) { - const req = { + const request = { method: 'POST', endpoint: '/abc000000000000000000001/delete' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -60,8 +60,8 @@ describe('POST //delete', function() { }); it('should delete the task', function(done) { - this.webservice.task('abc000000000000000000001').get({}, function(err) { - assert.strictEqual(err.message, 'Error 404'); + this.webservice.task('abc000000000000000000001').get({}, function(error) { + assert.strictEqual(error.message, 'Error 404'); done(); }); }); diff --git a/test/integration/route/task/edit.js b/test/integration/route/task/edit.js index c684035..2eb89e7 100644 --- a/test/integration/route/task/edit.js +++ b/test/integration/route/task/edit.js @@ -21,11 +21,11 @@ const assert = require('proclaim'); describe('GET //edit', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/abc000000000000000000001/edit' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -121,7 +121,7 @@ describe('GET //edit', function() { describe('POST //edit', function() { beforeEach(function(done) { - const req = { + const request = { method: 'POST', endpoint: '/abc000000000000000000001/edit', form: { @@ -131,7 +131,7 @@ describe('POST //edit', function() { ignore: ['bar', 'baz'] } }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -139,12 +139,12 @@ describe('POST //edit', function() { }); it('should edit the task', function(done) { - this.webservice.task('abc000000000000000000001').get({}, function(err, task) { + this.webservice.task('abc000000000000000000001').get({}, function(error, task) { assert.strictEqual(task.name, 'foo'); assert.strictEqual(task.username, 'newuser'); assert.strictEqual(task.password, 'secure'); assert.deepEqual(task.ignore, ['bar', 'baz']); - done(); + done(error); }); }); diff --git a/test/integration/route/task/index.js b/test/integration/route/task/index.js index e69eb08..124821d 100644 --- a/test/integration/route/task/index.js +++ b/test/integration/route/task/index.js @@ -23,11 +23,11 @@ describe('GET /', function() { describe('when task has results', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/abc000000000000000000001' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { @@ -82,11 +82,11 @@ describe('GET /', function() { describe('when task has no results', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/abc000000000000000000003' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { diff --git a/test/integration/route/task/run.js b/test/integration/route/task/run.js index 5059183..8659669 100644 --- a/test/integration/route/task/run.js +++ b/test/integration/route/task/run.js @@ -21,11 +21,11 @@ const assert = require('proclaim'); describe('GET //run', function() { beforeEach(function(done) { - const req = { + const request = { method: 'GET', endpoint: '/abc000000000000000000001/run' }; - this.navigate(req, done); + this.navigate(request, done); }); it('should send a 200 status', function() { diff --git a/test/integration/setup.js b/test/integration/setup.js index 5abfd63..103af94 100644 --- a/test/integration/setup.js +++ b/test/integration/setup.js @@ -40,8 +40,8 @@ afterEach(function(done) { // Check that the test application is running, and exit if not function assertTestAppIsRunning(url, done) { - request(url, err => { - if (err) { + request(url, error => { + if (error) { console.error('Error: Test app not started; run with `NODE_ENV=test node index.js`'); process.exit(1); } diff --git a/view/helper/date.js b/view/helper/date.js index a542422..49aea72 100644 --- a/view/helper/date.js +++ b/view/helper/date.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const moment = require('moment'); diff --git a/view/helper/url.js b/view/helper/url.js index b823b1e..986d2b0 100644 --- a/view/helper/url.js +++ b/view/helper/url.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; module.exports = helper; diff --git a/view/presenter/ignore.js b/view/presenter/ignore.js index 72f2a16..f5da38d 100644 --- a/view/presenter/ignore.js +++ b/view/presenter/ignore.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const standardsArray = require('../../data/standards')(); diff --git a/view/presenter/result-list.js b/view/presenter/result-list.js index 10b340b..3126065 100644 --- a/view/presenter/result-list.js +++ b/view/presenter/result-list.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const _ = require('underscore'); diff --git a/view/presenter/result.js b/view/presenter/result.js index a342805..6b53f5c 100644 --- a/view/presenter/result.js +++ b/view/presenter/result.js @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - 'use strict'; const _ = require('underscore'); diff --git a/view/presenter/task.js b/view/presenter/task.js index d2b34dc..6462b53 100644 --- a/view/presenter/task.js +++ b/view/presenter/task.js @@ -12,8 +12,6 @@ // // You should have received a copy of the GNU General Public License // along with Pa11y Dashboard. If not, see . - -// jscs:disable requireCamelCaseOrUpperCaseIdentifiers 'use strict'; const presentIgnoreRules = require('./ignore');