diff --git a/config.js b/config.js index 318c1e9..3a7b9a7 100644 --- a/config.js +++ b/config.js @@ -26,7 +26,8 @@ if (fs.existsSync(jsonPath)) { port: Number(env('PORT', jsonConfig.port)), cron: env('CRON', jsonConfig.cron), chromeLaunchConfig: jsonConfig.chromeLaunchConfig || {}, - numWorkers: jsonConfig.numWorkers || 2 + numWorkers: jsonConfig.numWorkers || 2, + runners: jsonConfig.runners || ['htmlcs'] }; } else { module.exports = { @@ -35,7 +36,8 @@ if (fs.existsSync(jsonPath)) { port: Number(env('PORT', '3000')), cron: env('CRON', false), chromeLaunchConfig: {}, - numWorkers: Number(env('NUM_WORKERS', '2')) + numWorkers: Number(env('NUM_WORKERS', '2')), + runners: ['htmlcs'] }; } diff --git a/config/development.sample.json b/config/development.sample.json index a1af1e8..fd98d4d 100644 --- a/config/development.sample.json +++ b/config/development.sample.json @@ -7,5 +7,6 @@ "args": [ "--no-sandbox" ] - } + }, + "runners": ["axe", "htmlcs"] } diff --git a/config/production.sample.json b/config/production.sample.json index 65d1e26..e16f235 100644 --- a/config/production.sample.json +++ b/config/production.sample.json @@ -3,5 +3,6 @@ "host": "0.0.0.0", "port": 3000, "cron": "0 30 0 * * *", - "chromeLaunchConfig": {} + "chromeLaunchConfig": {}, + "runners": [] } diff --git a/config/test.sample.json b/config/test.sample.json index 37b77f6..dc261f2 100644 --- a/config/test.sample.json +++ b/config/test.sample.json @@ -2,5 +2,6 @@ "database": "mongodb://localhost/pa11y-webservice-test", "host": "0.0.0.0", "port": 3000, - "chromeLaunchConfig": {} + "chromeLaunchConfig": {}, + "runners": ["htmlcs"] } diff --git a/index.js b/index.js index 1a3dcca..8a128ec 100644 --- a/index.js +++ b/index.js @@ -40,6 +40,7 @@ app(config, (error, initialisedApp) => { console.log(grey('database: %s'), dbConnectionString); console.log(grey('cron: %s'), config.cron); console.log(grey('workers: %s'), config.numWorkers); + console.log(grey('runners: %s'), config.runners); if (error) { console.error(''); diff --git a/model/task.js b/model/task.js index c697e89..4ff85a4 100644 --- a/model/task.js +++ b/model/task.js @@ -104,7 +104,8 @@ module.exports = function(app, callback) { wait: parseInt(edits.wait, 10), actions: edits.actions, username: edits.username, - password: edits.password + password: edits.password, + runners: edits.runners }; if (edits.ignore) { taskEdits.ignore = edits.ignore; @@ -190,6 +191,7 @@ module.exports = function(app, callback) { actions: task.actions || [], chromeLaunchConfig: app.config.chromeLaunchConfig || {}, headers: task.headers || {}, + runners: task.runners || app.config.runners, log: { debug: model.pa11yLog(task.id), error: model.pa11yLog(task.id), @@ -238,7 +240,8 @@ module.exports = function(app, callback) { wait: (task.wait ? parseInt(task.wait, 10) : 0), standard: task.standard, ignore: task.ignore || [], - actions: task.actions || [] + actions: task.actions || [], + runners: task.runners || app.config.runners }; if (task.annotations) { output.annotations = task.annotations; diff --git a/route/task.js b/route/task.js index 7712dec..69e1581 100644 --- a/route/task.js +++ b/route/task.js @@ -100,6 +100,7 @@ module.exports = function(app) { username: Joi.string().allow(''), password: Joi.string().allow(''), hideElements: Joi.string().allow(''), + runners: Joi.array().items(Joi.string()), headers: [ Joi.string().allow(''), Joi.object().pattern(/.*/, Joi.string().allow('')) diff --git a/route/tasks.js b/route/tasks.js index 4cd4d02..145b746 100644 --- a/route/tasks.js +++ b/route/tasks.js @@ -105,6 +105,7 @@ module.exports = function(app) { ignore: Joi.array(), actions: Joi.array().items(Joi.string()), hideElements: Joi.string().allow(''), + runners: Joi.array().items(Joi.string()), headers: [ Joi.string().allow(''), Joi.object().pattern(/.*/, Joi.string().allow('')) diff --git a/test/integration/create-task.js b/test/integration/create-task.js index f33e31e..f56579f 100644 --- a/test/integration/create-task.js +++ b/test/integration/create-task.js @@ -28,7 +28,8 @@ describe('POST /tasks', function() { url: 'nature.com', timeout: '30000', standard: 'WCAG2AA', - ignore: ['foo', 'bar'] + ignore: ['foo', 'bar'], + runners: ['axe'] }; const request = { @@ -60,12 +61,14 @@ describe('POST /tasks', function() { assert.strictEqual(this.last.body.url, newTask.url); assert.strictEqual(this.last.body.standard, newTask.standard); assert.deepEqual(this.last.body.ignore, newTask.ignore || []); + assert.deepEqual(this.last.body.runners, newTask.runners); }); }); describe('with valid JSON and HTTP basic user authentication', function() { let newTask; + const defaultRunners = ['htmlcs']; beforeEach(function(done) { newTask = { @@ -108,6 +111,7 @@ describe('POST /tasks', function() { assert.strictEqual(this.last.body.password, newTask.password); assert.strictEqual(this.last.body.standard, newTask.standard); assert.deepEqual(this.last.body.ignore, newTask.ignore || []); + assert.deepEqual(this.last.body.runners, defaultRunners); assert.deepEqual(this.last.body.hideElements, newTask.hideElements); }); diff --git a/test/integration/edit-task-by-id.js b/test/integration/edit-task-by-id.js index a72a510..5e6d2f2 100644 --- a/test/integration/edit-task-by-id.js +++ b/test/integration/edit-task-by-id.js @@ -38,6 +38,7 @@ describe('PATCH /tasks/{id}', function() { actions: [ 'click element body' ], + runners: ['run', 'sprint'], comment: 'Just changing some stuff, you know' }; const request = { @@ -88,6 +89,11 @@ describe('PATCH /tasks/{id}', function() { assert.deepEqual(task.actions, taskEdits.actions); }); + it('should update the task\'s associated runners in the database', async function() { + const task = await this.app.model.task.getById('abc000000000000000000001'); + assert.deepEqual(task.runners, taskEdits.runners); + }); + it('should add an annotation for the edit to the task', async function() { const task = await this.app.model.task.getById('abc000000000000000000001'); assert.isArray(task.annotations); @@ -234,6 +240,38 @@ describe('PATCH /tasks/{id}', function() { }); + describe('with invalid runners during edit', function() { + let taskEdits; + + const defaultRunners = ['htmlcs']; + + beforeEach(function(done) { + // Runners need to be strings + taskEdits = { + runners: [ + 1, + 2 + ] + }; + const request = { + method: 'PATCH', + endpoint: 'tasks/abc000000000000000000001', + body: taskEdits + }; + this.navigate(request, done); + }); + + it('should send a 400 status', function() { + assert.strictEqual(this.last.status, 400); + }); + + it('should not update the task in the database and continue to be default', async function() { + const task = await this.app.model.task.getById('abc000000000000000000001'); + assert.notDeepEqual(task.runners, taskEdits.runners); + assert.deepEqual(task.runners, defaultRunners); + }); + }); + describe('with valid but non-existent task ID', function() { beforeEach(function(done) { diff --git a/test/unit/config.test.js b/test/unit/config.test.js index 22ac96e..dad86bd 100644 --- a/test/unit/config.test.js +++ b/test/unit/config.test.js @@ -31,7 +31,8 @@ describe('config', () => { numWorkers: 2, chromeLaunchConfig: { field: 'value' - } + }, + runners: ['htmlcs'] }; before(() => { @@ -67,6 +68,7 @@ describe('config', () => { assert.strictEqual(config.port, mockConfig.port); assert.strictEqual(config.cron, mockConfig.cron); assert.strictEqual(config.numWorkers, mockConfig.numWorkers); + assert.deepEqual(config.runners, mockConfig.runners); assert.deepEqual(config.chromeLaunchConfig, mockConfig.chromeLaunchConfig); }); @@ -93,6 +95,7 @@ describe('config', () => { assert.strictEqual(config.port, 2000); assert.strictEqual(config.cron, mockConfig.cron); assert.strictEqual(config.numWorkers, mockConfig.numWorkers); + assert.deepEqual(config.runners, mockConfig.runners); assert.deepEqual(config.chromeLaunchConfig, mockConfig.chromeLaunchConfig); }); });