mirror of
https://github.com/pa11y/pa11y-dashboard.git
synced 2025-09-25 14:51:28 +00:00
Compare commits
35 Commits
1.0.0-beta
...
1.1.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2ebb54f545 | ||
![]() |
d57ae45b4f | ||
![]() |
ea330548b1 | ||
![]() |
ae5b214834 | ||
![]() |
b5735b7f05 | ||
![]() |
a47fb38d7f | ||
![]() |
da0e98eab1 | ||
![]() |
623a52e112 | ||
![]() |
9d72e50b4e | ||
![]() |
3535b9b11c | ||
![]() |
8f636173a0 | ||
![]() |
ec9f82aa6f | ||
![]() |
34a7c351c9 | ||
![]() |
c13af05422 | ||
![]() |
a853d329c0 | ||
![]() |
3237e87f4a | ||
![]() |
22958bdf1b | ||
![]() |
44726558f1 | ||
![]() |
15ae109eac | ||
![]() |
a609f0cd62 | ||
![]() |
1dcac7be72 | ||
![]() |
9b67e8298b | ||
![]() |
b996f2694b | ||
![]() |
7a1160b257 | ||
![]() |
98bd9ed208 | ||
![]() |
55d44685e9 | ||
![]() |
85b70c5679 | ||
![]() |
9b1079eea3 | ||
![]() |
15bbc2e774 | ||
![]() |
66fb1e68af | ||
![]() |
2ccb7784e0 | ||
![]() |
802634d0ad | ||
![]() |
d016ebfdce | ||
![]() |
c249a542bf | ||
![]() |
6b6ce57e48 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@
|
|||||||
# Config files
|
# Config files
|
||||||
config/development.json
|
config/development.json
|
||||||
config/production.json
|
config/production.json
|
||||||
|
config/test.json
|
||||||
|
|
||||||
# Generated npm files
|
# Generated npm files
|
||||||
node_modules
|
node_modules
|
||||||
|
24
.travis.yml
Normal file
24
.travis.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
# Language/versions
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.10"
|
||||||
|
|
||||||
|
# Services setup
|
||||||
|
services:
|
||||||
|
- mongodb
|
||||||
|
|
||||||
|
# Build script
|
||||||
|
before_script:
|
||||||
|
- npm install -g grunt-cli
|
||||||
|
- cp config/test.sample.json config/test.json
|
||||||
|
- grunt start-test &
|
||||||
|
- sleep 5 # give server time to start
|
||||||
|
script: 'grunt ci'
|
||||||
|
|
||||||
|
# Notifications
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
- j.robinson@nature.com
|
||||||
|
- perry.harlock@nature.com
|
||||||
|
- rowan.manning@nature.com
|
25
Gruntfile.js
25
Gruntfile.js
@@ -34,6 +34,15 @@ module.exports = function (grunt) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mochaTest: {
|
||||||
|
functional: {
|
||||||
|
src: ['test/functional/**/*.js'],
|
||||||
|
options: {
|
||||||
|
reporter: 'spec'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
nodemon: {
|
nodemon: {
|
||||||
development: {
|
development: {
|
||||||
options: {
|
options: {
|
||||||
@@ -43,6 +52,15 @@ module.exports = function (grunt) {
|
|||||||
NODE_ENV: 'development'
|
NODE_ENV: 'development'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
options: {
|
||||||
|
cwd: __dirname,
|
||||||
|
file: 'index.js',
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -84,12 +102,15 @@ module.exports = function (grunt) {
|
|||||||
grunt.loadNpmTasks('grunt-contrib-less');
|
grunt.loadNpmTasks('grunt-contrib-less');
|
||||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||||
|
grunt.loadNpmTasks('grunt-mocha-test');
|
||||||
grunt.loadNpmTasks('grunt-nodemon');
|
grunt.loadNpmTasks('grunt-nodemon');
|
||||||
|
|
||||||
grunt.registerTask('lint', ['jshint']);
|
grunt.registerTask('lint', ['jshint']);
|
||||||
|
grunt.registerTask('test', ['mochaTest']);
|
||||||
grunt.registerTask('compile', ['less', 'uglify']);
|
grunt.registerTask('compile', ['less', 'uglify']);
|
||||||
grunt.registerTask('start', ['nodemon:development']);
|
grunt.registerTask('start', ['nodemon:development']);
|
||||||
grunt.registerTask('default', ['compile', 'lint']);
|
grunt.registerTask('start-test', ['nodemon:test']);
|
||||||
grunt.registerTask('ci', ['compile', 'lint']);
|
grunt.registerTask('default', ['compile', 'lint', 'test']);
|
||||||
|
grunt.registerTask('ci', ['lint', 'test']);
|
||||||
|
|
||||||
};
|
};
|
54
README.md
54
README.md
@@ -1,20 +1,21 @@
|
|||||||
pa11y-dashboard
|
pa11y-dashboard
|
||||||
===============
|
===============
|
||||||
|
|
||||||
pa11y-dashboard is a visual web interface to the [pa11y][pa11y] accessibility reporter.
|
pa11y-dashboard is a web interface to the [pa11y][pa11y] accessibility reporter; allowing you to focus on *fixing* issues rather than hunting them down.
|
||||||
|
|
||||||
**Current Version:** *1.0.0-beta.3*
|
**Current Version:** *1.1.0*
|
||||||
|
**Build Status:** [![Build Status][travis-img]][travis]
|
||||||
**Node Version Support:** *0.10*
|
**Node Version Support:** *0.10*
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
-----
|
-----
|
||||||
|
|
||||||
pa11y-dashboard requires [Node.js][node] 0.10+ and [pa11y-webservice][pa11y-webservice] to be installed and running. You'll need to follow the setup guide for pa11y-webservice before setting up pa11y-dashboard.
|
pa11y-dashboard requires [Node.js][node] 0.10+, [PhantomJS][phantom], and [MongoDB][mongo] to be installed. See the [pa11y][pa11y] and [pa11y-webservice][pa11y-webservice] documentation for more information on these dependencies.
|
||||||
|
|
||||||
You'll then need to clone this repo locally and install dependencies with `npm install`.
|
You'll then need to clone this repo locally and install dependencies with `npm install`.
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ Once you have a local clone, you'll need to copy some sample configuration files
|
|||||||
```sh
|
```sh
|
||||||
$ cp config/development.sample.json config/development.json
|
$ cp config/development.sample.json config/development.json
|
||||||
$ cp config/production.sample.json config/production.json
|
$ cp config/production.sample.json config/production.json
|
||||||
|
$ cp config/test.sample.json config/test.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Each of these files defines configurations for a different environment. If you're just running the application locally, then you should be OK with just development configurations. The [available configurations are documented here](#configurations).
|
Each of these files defines configurations for a different environment. If you're just running the application locally, then you should be OK with just development configurations. The [available configurations are documented here](#configurations).
|
||||||
@@ -32,9 +34,10 @@ Now that you've got your application configured, you can run in each mode with t
|
|||||||
```sh
|
```sh
|
||||||
$ NODE_ENV=production node . # Run in production
|
$ NODE_ENV=production node . # Run in production
|
||||||
$ NODE_ENV=development node . # Run in development
|
$ NODE_ENV=development node . # Run in development
|
||||||
|
$ NODE_ENV=test node . # Run in test
|
||||||
```
|
```
|
||||||
|
|
||||||
See [development instructions](#development) for more information about running locally (and restarting automatically when files change).
|
Check the [development instructions](#development) for more information about running locally (and restarting automatically when files change).
|
||||||
|
|
||||||
|
|
||||||
Configurations
|
Configurations
|
||||||
@@ -42,26 +45,43 @@ Configurations
|
|||||||
|
|
||||||
The boot configurations for pa11y-dashboard are as follows. Look at the sample JSON files in the repo for example usage.
|
The boot configurations for pa11y-dashboard are as follows. Look at the sample JSON files in the repo for example usage.
|
||||||
|
|
||||||
### webservice
|
|
||||||
*(string)* The base URL of the [pa11y-webservice][pa11y-webservice] instance you intend on using.
|
|
||||||
|
|
||||||
### port
|
### port
|
||||||
*(number)* The port to run the application on.
|
*(number)* The port to run the application on.
|
||||||
|
|
||||||
|
### noindex
|
||||||
|
*(boolean)* If set to `true` (default), the dashboard will not be indexed by search engines. Set to `false` to allow indexing.
|
||||||
|
|
||||||
|
### readonly
|
||||||
|
*(boolean)* If set to `true`, users will not be able to add, delete or run URLs (defaults to `false`).
|
||||||
|
|
||||||
|
### siteMessage
|
||||||
|
*(string)* A message to display prominently on the site home page. Defaults to `null`.
|
||||||
|
|
||||||
|
### webservice
|
||||||
|
This can either be an object containing [pa11y-webservice configurations][pa11y-webservice-config], or a string which is the base URL of a [pa11y-webservice][pa11y-webservice] instance you are running separately.
|
||||||
|
|
||||||
|
|
||||||
Development
|
Development
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
To develop pa11y-dashboard, you'll need to clone the repo and get set up as outlined in the [setup guide](#setup). You'll also need [Grunt][grunt] to be installed globally in order to run tests, you can do this with `npm install -g grunt-cli`.
|
To develop pa11y-dashboard, you'll need to clone the repo and get set up as outlined in the [setup guide](#setup). You'll also need [Grunt][grunt] to be installed globally in order to run tests, you can do this with `npm install -g grunt-cli`.
|
||||||
|
|
||||||
|
Once you've done this, you'll need to start the application in test mode with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ grunt start-test
|
||||||
|
```
|
||||||
|
|
||||||
Now you'll be able to run the following commands:
|
Now you'll be able to run the following commands:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ grunt # Run the lint and test tasks together
|
$ grunt # Run the lint and test tasks together
|
||||||
$ grunt lint # Run JSHint with the correct config
|
$ grunt lint # Run JSHint with the correct config
|
||||||
$ grunt compile # Compile front-end assets
|
$ grunt compile # Compile front-end assets
|
||||||
$ grunt start # Run app in development mode, restarting if files change
|
$ grunt start # Run app in development mode, restarting if files change
|
||||||
$ grunt watch # Watch for file changes and compile assets
|
$ grunt start-test # Run app in test mode, restarting if files change
|
||||||
|
$ grunt test # Run functional tests
|
||||||
|
$ grunt watch # Watch for file changes and compile assets
|
||||||
```
|
```
|
||||||
|
|
||||||
Code with lint errors or failing tests will not be accepted, please use the build tools outlined above.
|
Code with lint errors or failing tests will not be accepted, please use the build tools outlined above.
|
||||||
@@ -79,7 +99,11 @@ pa11y-dashboard is licensed under the [GNU General Public License 3.0][gpl].
|
|||||||
|
|
||||||
[gpl]: http://www.gnu.org/licenses/gpl-3.0.html
|
[gpl]: http://www.gnu.org/licenses/gpl-3.0.html
|
||||||
[grunt]: http://gruntjs.com/
|
[grunt]: http://gruntjs.com/
|
||||||
|
[mongo]: http://www.mongodb.org/
|
||||||
[node]: http://nodejs.org/
|
[node]: http://nodejs.org/
|
||||||
[pa11y]: https://github.com/nature/pa11y
|
[pa11y]: https://github.com/nature/pa11y
|
||||||
[pa11y-webservice]: https://github.com/nature/pa11y-webservice
|
[pa11y-webservice]: https://github.com/nature/pa11y-webservice
|
||||||
[supervisor]: https://github.com/isaacs/node-supervisor
|
[pa11y-webservice-config]: https://github.com/nature/pa11y-webservice#configurations
|
||||||
|
[phantom]: http://phantomjs.org/
|
||||||
|
[travis]: https://travis-ci.org/nature/pa11y-dashboard
|
||||||
|
[travis-img]: https://travis-ci.org/nature/pa11y-dashboard.png?branch=master
|
||||||
|
33
app.js
33
app.js
@@ -11,12 +11,18 @@ module.exports = initApp;
|
|||||||
|
|
||||||
// Initialise the application
|
// Initialise the application
|
||||||
function initApp (config, callback) {
|
function initApp (config, callback) {
|
||||||
|
config = defaultConfig(config);
|
||||||
|
|
||||||
|
var webserviceUrl = config.webservice;
|
||||||
|
if (typeof webserviceUrl == 'object') {
|
||||||
|
webserviceUrl = 'http://' + webserviceUrl.host + ':' + webserviceUrl.port + '/';
|
||||||
|
}
|
||||||
|
|
||||||
var app = new EventEmitter();
|
var app = new EventEmitter();
|
||||||
app.address = null;
|
app.address = null;
|
||||||
app.express = express();
|
app.express = express();
|
||||||
app.server = http.createServer(app.express);
|
app.server = http.createServer(app.express);
|
||||||
app.webservice = createClient(config.webservice);
|
app.webservice = createClient(webserviceUrl);
|
||||||
|
|
||||||
// Compression
|
// Compression
|
||||||
app.express.use(express.compress());
|
app.express.use(express.compress());
|
||||||
@@ -51,8 +57,12 @@ function initApp (config, callback) {
|
|||||||
year: (new Date()).getFullYear(),
|
year: (new Date()).getFullYear(),
|
||||||
version: pkg.version,
|
version: pkg.version,
|
||||||
repo: pkg.homepage,
|
repo: pkg.homepage,
|
||||||
bugtracker: pkg.bugs
|
bugtracker: pkg.bugs,
|
||||||
|
noindex: config.noindex,
|
||||||
|
readonly: config.readonly,
|
||||||
|
siteMessage: config.siteMessage
|
||||||
});
|
});
|
||||||
|
|
||||||
app.express.use(function (req, res, next) {
|
app.express.use(function (req, res, next) {
|
||||||
res.locals.isHomePage = (req.path === '/');
|
res.locals.isHomePage = (req.path === '/');
|
||||||
res.locals.host = req.host;
|
res.locals.host = req.host;
|
||||||
@@ -61,12 +71,14 @@ function initApp (config, callback) {
|
|||||||
|
|
||||||
// Load routes
|
// Load routes
|
||||||
require('./route/index')(app);
|
require('./route/index')(app);
|
||||||
require('./route/new')(app);
|
|
||||||
require('./route/task/index')(app);
|
require('./route/task/index')(app);
|
||||||
require('./route/task/delete')(app);
|
|
||||||
require('./route/task/run')(app);
|
|
||||||
require('./route/result/index')(app);
|
require('./route/result/index')(app);
|
||||||
require('./route/result/download')(app);
|
require('./route/result/download')(app);
|
||||||
|
if (!config.readonly) {
|
||||||
|
require('./route/new')(app);
|
||||||
|
require('./route/task/delete')(app);
|
||||||
|
require('./route/task/run')(app);
|
||||||
|
}
|
||||||
|
|
||||||
// Error handling
|
// Error handling
|
||||||
app.express.get('*', function (req, res) {
|
app.express.get('*', function (req, res) {
|
||||||
@@ -93,3 +105,14 @@ function initApp (config, callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get default configurations
|
||||||
|
function defaultConfig (config) {
|
||||||
|
if (typeof config.noindex !== 'boolean') {
|
||||||
|
config.noindex = true;
|
||||||
|
}
|
||||||
|
if (typeof config.readonly !== 'boolean') {
|
||||||
|
config.readonly = false;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
"webservice": "http://localhost:3000/",
|
"port": 4000,
|
||||||
"port": 4000
|
"noindex": true,
|
||||||
|
"readonly": false,
|
||||||
|
|
||||||
|
"webservice": {
|
||||||
|
"database": "mongodb://localhost/pa11y-webservice-dev",
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
"cron": "0 30 0 * * *"
|
||||||
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
"webservice": "http://localhost:3000/",
|
"port": 4000,
|
||||||
"port": 4000
|
"noindex": true,
|
||||||
|
"readonly": false,
|
||||||
|
|
||||||
|
"webservice": {
|
||||||
|
"database": "mongodb://localhost/pa11y-webservice",
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
"cron": "0 30 0 * * *"
|
||||||
|
}
|
||||||
}
|
}
|
12
config/test.sample.json
Normal file
12
config/test.sample.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"port": 4000,
|
||||||
|
"noindex": true,
|
||||||
|
"readonly": false,
|
||||||
|
|
||||||
|
"webservice": {
|
||||||
|
"database": "mongodb://localhost/pa11y-webservice-test",
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 3000,
|
||||||
|
"cron": "0 30 0 * * *"
|
||||||
|
}
|
||||||
|
}
|
10
index.js
10
index.js
@@ -18,4 +18,14 @@ require('./app')(config, function (err, app) {
|
|||||||
console.error(chalk.grey(stack.join('\n')));
|
console.error(chalk.grey(stack.join('\n')));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Start the webservice if required
|
||||||
|
if (typeof config.webservice === 'object') {
|
||||||
|
require('pa11y-webservice')(config.webservice, function (err, webservice) {
|
||||||
|
console.log('');
|
||||||
|
console.log(chalk.underline.cyan('pa11y-webservice started'));
|
||||||
|
console.log(chalk.grey('mode: %s'), process.env.NODE_ENV);
|
||||||
|
console.log(chalk.grey('uri: %s'), webservice.server.info.uri);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
11
package.json
11
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pa11y-dashboard",
|
"name": "pa11y-dashboard",
|
||||||
"version": "1.0.0-beta.3",
|
"version": "1.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
||||||
"description": "pa11y-dashboard is a visual web interface to the pa11y accessibility reporter",
|
"description": "pa11y-dashboard is a visual web interface to the pa11y accessibility reporter",
|
||||||
@@ -25,7 +25,8 @@
|
|||||||
"express": "~3.4",
|
"express": "~3.4",
|
||||||
"express-hbs": "~0.2",
|
"express-hbs": "~0.2",
|
||||||
"moment": "~2.2",
|
"moment": "~2.2",
|
||||||
"pa11y-webservice-client-node": "git+ssh://git@github.com:nature/pa11y-webservice-client-node.git#1.0.0-beta.7",
|
"pa11y-webservice": "~1.1",
|
||||||
|
"pa11y-webservice-client-node": "~1.0",
|
||||||
"underscore": "~1.5"
|
"underscore": "~1.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -35,7 +36,11 @@
|
|||||||
"grunt-contrib-less": "~0.8",
|
"grunt-contrib-less": "~0.8",
|
||||||
"grunt-contrib-uglify": "~0.2",
|
"grunt-contrib-uglify": "~0.2",
|
||||||
"grunt-contrib-watch": "~0.5",
|
"grunt-contrib-watch": "~0.5",
|
||||||
"grunt-nodemon": "~0.1"
|
"grunt-mocha-test": "~0.7",
|
||||||
|
"grunt-nodemon": "~0.1",
|
||||||
|
"jsdom": "~0.8",
|
||||||
|
"proclaim": "~2.0",
|
||||||
|
"request": "~2.27"
|
||||||
},
|
},
|
||||||
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
2
public/css/site.min.css
vendored
2
public/css/site.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -132,9 +132,9 @@ $(document).ready(function(){
|
|||||||
|
|
||||||
function getData() {
|
function getData() {
|
||||||
return [
|
return [
|
||||||
{ color: 'rgb(231, 76, 60)', label: 'Errors', data: data.error },
|
{ color: 'rgb(216, 61, 45)', label: 'Errors', data: data.error },
|
||||||
{ color: 'rgb(243, 156, 18)', label: 'Warnings', data: data.warning },
|
{ color: 'rgb(168, 103, 0)', label: 'Warnings', data: data.warning },
|
||||||
{ color: 'rgb(52, 152, 219)', label: 'Notices', data: data.notice }
|
{ color: 'rgb(23, 123, 190)', label: 'Notices', data: data.notice }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,12 +167,20 @@ $(document).ready(function(){
|
|||||||
|
|
||||||
$.each(datasets, function(key, val) {
|
$.each(datasets, function(key, val) {
|
||||||
var lowerCaseValue = (val.label.substring(0, val.label.length - 1)).toLowerCase();
|
var lowerCaseValue = (val.label.substring(0, val.label.length - 1)).toLowerCase();
|
||||||
choiceContainer.append('<li class="text-center '+
|
choiceContainer.append(
|
||||||
lowerCaseValue +'"><label for="id' + key +
|
'<li class="text-center ' + lowerCaseValue + '">' +
|
||||||
'"><input type="checkbox" name="' + key +
|
'<div class="series-checkbox-container">' +
|
||||||
'" checked="checked" id="id' + key +
|
'<input type="checkbox"' +
|
||||||
'"/><span class="stat-type">' + val.label +
|
'name="' + key + '" ' +
|
||||||
'</span></label></li>');
|
'checked="checked" ' +
|
||||||
|
'id="id' + key + '"' +
|
||||||
|
'/>' +
|
||||||
|
'<label for="id' + key + '">' +
|
||||||
|
'<span class="stat-type">' + val.label + '</span>' +
|
||||||
|
'</label>' +
|
||||||
|
'</div>' +
|
||||||
|
'</li>'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
choiceContainer.find('input').click(plotAccordingToChoices);
|
choiceContainer.find('input').click(plotAccordingToChoices);
|
||||||
|
2
public/js/site.min.js
vendored
2
public/js/site.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -32,7 +32,6 @@
|
|||||||
.date {
|
.date {
|
||||||
margin-top:10px;
|
margin-top:10px;
|
||||||
float:right;
|
float:right;
|
||||||
font-size:;
|
|
||||||
}
|
}
|
||||||
.other-tasks {
|
.other-tasks {
|
||||||
.sr-only();
|
.sr-only();
|
||||||
@@ -65,6 +64,11 @@
|
|||||||
margin-top:0;
|
margin-top:0;
|
||||||
margin-bottom:25px;
|
margin-bottom:25px;
|
||||||
}
|
}
|
||||||
|
.readonly-mode .date {
|
||||||
|
margin-top:0;
|
||||||
|
margin-bottom:5px;
|
||||||
|
float:none;
|
||||||
|
}
|
||||||
.graph-spacer {
|
.graph-spacer {
|
||||||
padding-bottom:20px;
|
padding-bottom:20px;
|
||||||
margin-bottom:15px;
|
margin-bottom:15px;
|
||||||
@@ -131,6 +135,15 @@
|
|||||||
.series-checkboxes li {
|
.series-checkboxes li {
|
||||||
font-size:floor(@font-size-base * 0.8); // ~12px;
|
font-size:floor(@font-size-base * 0.8); // ~12px;
|
||||||
}
|
}
|
||||||
|
.task-header .h3 {
|
||||||
|
float:none !important;
|
||||||
|
text-align:center;
|
||||||
|
margin-bottom:15px !important;
|
||||||
|
padding:10px;
|
||||||
|
}
|
||||||
|
.task-header h1 {
|
||||||
|
margin-bottom:3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media (max-width:360px) {
|
@media (max-width:360px) {
|
||||||
.delete-button {
|
.delete-button {
|
||||||
|
@@ -96,6 +96,19 @@
|
|||||||
.delete-button:hover {
|
.delete-button:hover {
|
||||||
color:lighten(@brand-danger, 8%);
|
color:lighten(@brand-danger, 8%);
|
||||||
}
|
}
|
||||||
|
.footer a, .breadcrumb a {
|
||||||
|
text-decoration:underline;
|
||||||
|
}
|
||||||
|
.breadcrumb a {
|
||||||
|
&:hover, &:active, &:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.site-message {
|
||||||
|
.glyphicon {
|
||||||
|
margin-right:6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Type */
|
/* Type */
|
||||||
.h1 {
|
.h1 {
|
||||||
@@ -219,6 +232,10 @@
|
|||||||
.task-header {
|
.task-header {
|
||||||
margin-bottom:30px;
|
margin-bottom:30px;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom:6px;
|
||||||
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
word-wrap:break-word;
|
word-wrap:break-word;
|
||||||
}
|
}
|
||||||
@@ -226,6 +243,9 @@
|
|||||||
.date {
|
.date {
|
||||||
margin-top:5px;
|
margin-top:5px;
|
||||||
}
|
}
|
||||||
|
.readonly-mode .date {
|
||||||
|
margin-top:40px;
|
||||||
|
}
|
||||||
.tasks-list {
|
.tasks-list {
|
||||||
padding:15px;
|
padding:15px;
|
||||||
margin-bottom:30px;
|
margin-bottom:30px;
|
||||||
@@ -334,12 +354,20 @@ ul.date-links {
|
|||||||
border-radius: @border-radius-base;
|
border-radius: @border-radius-base;
|
||||||
|
|
||||||
label {
|
label {
|
||||||
padding:2px 4px;
|
|
||||||
margin-bottom:0;
|
margin-bottom:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.series-checkbox-container {
|
||||||
|
padding:2px 4px 3px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin:5px auto 3px auto;
|
||||||
|
}
|
||||||
|
|
||||||
input, label {
|
input, label {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
display:block;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
|
@@ -13,16 +13,16 @@
|
|||||||
@gray-dark: #616D6E;
|
@gray-dark: #616D6E;
|
||||||
@gray: #6C7878;
|
@gray: #6C7878;
|
||||||
@gray-light: #7C8C8D;
|
@gray-light: #7C8C8D;
|
||||||
@gray-lighter: #ecf0f1;
|
@gray-lighter: #eaeff1;
|
||||||
|
|
||||||
// Brand colors
|
// Brand colors
|
||||||
// -------------------------
|
// -------------------------
|
||||||
|
|
||||||
@brand-primary: #2C3E50;
|
@brand-primary: #2C3E50;
|
||||||
@brand-success: #00A18C;
|
@brand-success: #00806F;
|
||||||
@brand-warning: #F39C12;
|
@brand-warning: #A86700;
|
||||||
@brand-danger: #E74C3C;
|
@brand-danger: #D83D2D;
|
||||||
@brand-info: #3498DB;
|
@brand-info: #177BBE;
|
||||||
|
|
||||||
// Scaffolding
|
// Scaffolding
|
||||||
// -------------------------
|
// -------------------------
|
||||||
@@ -551,7 +551,7 @@
|
|||||||
// Breadcrumbs
|
// Breadcrumbs
|
||||||
// -------------------------
|
// -------------------------
|
||||||
@breadcrumb-bg: lighten(@gray-lighter, 4%);
|
@breadcrumb-bg: lighten(@gray-lighter, 4%);
|
||||||
@breadcrumb-color: lighten(@gray-dark, 3%);
|
@breadcrumb-color: @gray-dark;
|
||||||
@breadcrumb-active-color: @breadcrumb-color;
|
@breadcrumb-active-color: @breadcrumb-color;
|
||||||
|
|
||||||
|
|
||||||
|
51
test/functional/helper/navigate.js
Normal file
51
test/functional/helper/navigate.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var jsdom = require('jsdom');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
|
module.exports = createNavigator;
|
||||||
|
|
||||||
|
// Create a navigate function
|
||||||
|
function createNavigator (baseUrl, store) {
|
||||||
|
return function (opts, callback) {
|
||||||
|
|
||||||
|
store.body = null;
|
||||||
|
store.dom = null;
|
||||||
|
store.request = null;
|
||||||
|
store.response = null;
|
||||||
|
store.status = null;
|
||||||
|
store.window = null;
|
||||||
|
|
||||||
|
request({
|
||||||
|
url: baseUrl + opts.endpoint,
|
||||||
|
method: opts.method || 'GET',
|
||||||
|
body: opts.body,
|
||||||
|
json: true,
|
||||||
|
qs: opts.query,
|
||||||
|
followAllRedirects: true
|
||||||
|
}, function (err, res, body) {
|
||||||
|
|
||||||
|
store.body = body;
|
||||||
|
store.request = res.request;
|
||||||
|
store.response = res;
|
||||||
|
store.status = res.statusCode;
|
||||||
|
|
||||||
|
if (opts.nonDom) {
|
||||||
|
store.window = null;
|
||||||
|
store.dom = null;
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
jsdom.env(
|
||||||
|
store.body,
|
||||||
|
function (err, window) {
|
||||||
|
store.window = window;
|
||||||
|
store.dom = window.document;
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
14
test/functional/helper/webservice.js
Normal file
14
test/functional/helper/webservice.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var createClient = require('pa11y-webservice-client-node');
|
||||||
|
|
||||||
|
module.exports = createWebserviceClient;
|
||||||
|
|
||||||
|
// Create a webservice client
|
||||||
|
function createWebserviceClient (config) {
|
||||||
|
var webserviceUrl = config.webservice;
|
||||||
|
if (typeof webserviceUrl == 'object') {
|
||||||
|
webserviceUrl = 'http://' + webserviceUrl.host + ':' + webserviceUrl.port + '/';
|
||||||
|
}
|
||||||
|
return createClient(webserviceUrl);
|
||||||
|
}
|
65
test/functional/route/index.js
Normal file
65
test/functional/route/index.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/* global beforeEach, describe, it */
|
||||||
|
/* jshint maxlen: false, maxstatements: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('proclaim');
|
||||||
|
|
||||||
|
describe('GET /', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/'
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display an "Add new URL" button', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=add-task]');
|
||||||
|
assert.strictEqual(elem.length, 1);
|
||||||
|
assert.strictEqual(elem[0].getAttribute('href'), '/new');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display all of the expected tasks', function () {
|
||||||
|
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
|
||||||
|
assert.strictEqual(tasks.length, 3);
|
||||||
|
assert.match(tasks[0].textContent, /npg home\s+\(wcag2aa\)/i);
|
||||||
|
assert.match(tasks[1].textContent, /npg home\s+\(wcag2aaa\)/i);
|
||||||
|
assert.match(tasks[2].textContent, /nature news\s+\(section508\)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have links to each task', function () {
|
||||||
|
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
|
||||||
|
assert.strictEqual(tasks[0].querySelectorAll('[href="/abc000000000000000000001"]').length, 1);
|
||||||
|
assert.strictEqual(tasks[1].querySelectorAll('[href="/abc000000000000000000002"]').length, 1);
|
||||||
|
assert.strictEqual(tasks[2].querySelectorAll('[href="/abc000000000000000000003"]').length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a delete button for each task', function () {
|
||||||
|
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
|
||||||
|
assert.strictEqual(tasks[0].querySelectorAll('[href="/abc000000000000000000001/delete"]').length, 1);
|
||||||
|
assert.strictEqual(tasks[1].querySelectorAll('[href="/abc000000000000000000002/delete"]').length, 1);
|
||||||
|
assert.strictEqual(tasks[2].querySelectorAll('[href="/abc000000000000000000003/delete"]').length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display the task result counts if the task has been run', function () {
|
||||||
|
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
|
||||||
|
assert.match(tasks[0].textContent, /1\s*errors/i);
|
||||||
|
assert.match(tasks[0].textContent, /2\s*warnings/i);
|
||||||
|
assert.match(tasks[0].textContent, /3\s*notices/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a message indicating that there are no results if the task has not been run', function () {
|
||||||
|
var tasks = this.last.dom.querySelectorAll('[data-test=task]');
|
||||||
|
assert.match(tasks[2].textContent, /no results/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display an alert message', function () {
|
||||||
|
assert.strictEqual(this.last.dom.querySelectorAll('[data-test=alert]').length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
136
test/functional/route/new.js
Normal file
136
test/functional/route/new.js
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/* global beforeEach, describe, it */
|
||||||
|
/* jshint maxlen: false, maxstatements: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('proclaim');
|
||||||
|
|
||||||
|
describe('GET /new', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/new'
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display an error message', function () {
|
||||||
|
assert.strictEqual(this.last.dom.querySelectorAll('[data-test=error]').length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have an "Add new URL" form', function () {
|
||||||
|
var form = this.last.dom.querySelectorAll('[data-test=new-url-form]')[0];
|
||||||
|
assert.isDefined(form);
|
||||||
|
assert.strictEqual(form.getAttribute('action'), '/new');
|
||||||
|
assert.strictEqual(form.getAttribute('method'), 'post');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('"Add New URL" form', function () {
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
this.form = this.last.dom.querySelectorAll('[data-test=new-url-form]')[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a "name" field', function () {
|
||||||
|
var field = this.form.querySelectorAll('input[name=name]')[0];
|
||||||
|
assert.isDefined(field);
|
||||||
|
assert.strictEqual(field.getAttribute('type'), 'text');
|
||||||
|
assert.strictEqual(field.getAttribute('value'), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a "url" field', function () {
|
||||||
|
var field = this.form.querySelectorAll('input[name=url]')[0];
|
||||||
|
assert.isDefined(field);
|
||||||
|
assert.strictEqual(field.getAttribute('type'), 'url');
|
||||||
|
assert.strictEqual(field.getAttribute('value'), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a "standard" field', function () {
|
||||||
|
var field = this.form.querySelectorAll('select[name=standard]')[0];
|
||||||
|
assert.isDefined(field);
|
||||||
|
assert.strictEqual(field.querySelectorAll('option').length, 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have "ignore" fields', function () {
|
||||||
|
var fields = this.form.querySelectorAll('input[name="ignore[]"]');
|
||||||
|
assert.isDefined(fields);
|
||||||
|
assert.notStrictEqual(fields.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /new', function () {
|
||||||
|
|
||||||
|
describe('with invalid query', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'POST',
|
||||||
|
endpoint: '/new',
|
||||||
|
body: {
|
||||||
|
name: '',
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display an error message', function () {
|
||||||
|
assert.strictEqual(this.last.dom.querySelectorAll('[data-test=error]').length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with valid query', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'POST',
|
||||||
|
endpoint: '/new',
|
||||||
|
body: {
|
||||||
|
name: 'Example',
|
||||||
|
url: 'http://example.com/',
|
||||||
|
standard: 'WCAG2AA'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the task', function (done) {
|
||||||
|
this.webservice.tasks.get({}, function (err, tasks) {
|
||||||
|
assert.strictEqual(tasks.length, 4);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect me to the new URL page', function () {
|
||||||
|
assert.match(this.last.request.uri.pathname, /^\/[a-z0-9]{24}$/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display an error message', function () {
|
||||||
|
assert.strictEqual(this.last.dom.querySelectorAll('[data-test=error]').length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a success message', function () {
|
||||||
|
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
|
||||||
|
assert.isDefined(alert);
|
||||||
|
assert.match(alert.textContent, /url has been added/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
53
test/functional/route/result/download.js
Normal file
53
test/functional/route/result/download.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/* global beforeEach, describe, it */
|
||||||
|
/* jshint maxlen: false, maxstatements: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('proclaim');
|
||||||
|
|
||||||
|
describe('GET /<task-id>/<result-id>.csv', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/abc000000000000000000001/def000000000000000000001.csv',
|
||||||
|
nonDom: true
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should output CSV results', function () {
|
||||||
|
assert.match(this.last.body, /^"code", "message", "type"/);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET /<task-id>/<result-id>.json', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/abc000000000000000000001/def000000000000000000001.json',
|
||||||
|
nonDom: true
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should output JSON results', function () {
|
||||||
|
var json = this.last.body;
|
||||||
|
assert.strictEqual(json.task.name, 'NPG Home');
|
||||||
|
assert.strictEqual(json.task.url, 'nature.com');
|
||||||
|
assert.strictEqual(json.count.error, 1);
|
||||||
|
assert.strictEqual(json.count.warning, 2);
|
||||||
|
assert.strictEqual(json.count.notice, 3);
|
||||||
|
assert.isArray(json.results);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
55
test/functional/route/result/index.js
Normal file
55
test/functional/route/result/index.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/* global beforeEach, describe, it */
|
||||||
|
/* jshint maxlen: false, maxstatements: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('proclaim');
|
||||||
|
|
||||||
|
describe('GET /<task-id>/<result-id>', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/abc000000000000000000001/def000000000000000000001'
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a "Download CSV" button', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=download-csv]');
|
||||||
|
assert.strictEqual(elem.length, 1);
|
||||||
|
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000001/def000000000000000000001.csv');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a "Download JSON" button', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=download-json]');
|
||||||
|
assert.strictEqual(elem.length, 1);
|
||||||
|
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000001/def000000000000000000001.json');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a link back to the task', function () {
|
||||||
|
assert.isDefined(this.last.dom.querySelectorAll('[href="/abc000000000000000000001"]')[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display errors', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=task-errors]')[0];
|
||||||
|
assert.isDefined(elem);
|
||||||
|
assert.match(elem.textContent, /errors \( 1 \)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display warnings', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=task-warnings]')[0];
|
||||||
|
assert.isDefined(elem);
|
||||||
|
assert.match(elem.textContent, /warnings \( 2 \)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display notices', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=task-notices]')[0];
|
||||||
|
assert.isDefined(elem);
|
||||||
|
assert.match(elem.textContent, /notices \( 3 \)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
61
test/functional/route/task/delete.js
Normal file
61
test/functional/route/task/delete.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/* global beforeEach, describe, it */
|
||||||
|
/* jshint maxlen: false, maxstatements: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('proclaim');
|
||||||
|
|
||||||
|
describe('GET /<task-id>/delete', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/abc000000000000000000001/delete'
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a "Delete URL" form', function () {
|
||||||
|
var form = this.last.dom.querySelectorAll('[data-test=delete-url-form]')[0];
|
||||||
|
assert.isDefined(form);
|
||||||
|
assert.strictEqual(form.getAttribute('action'), '/abc000000000000000000001/delete');
|
||||||
|
assert.strictEqual(form.getAttribute('method'), 'post');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST /<task-id>/delete', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'POST',
|
||||||
|
endpoint: '/abc000000000000000000001/delete'
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the task', function (done) {
|
||||||
|
this.webservice.task('abc000000000000000000001').get({}, function (err) {
|
||||||
|
assert.strictEqual(err.message, 'Error 404');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect me to the home page', function () {
|
||||||
|
assert.strictEqual(this.last.request.uri.pathname, '/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a success message', function () {
|
||||||
|
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
|
||||||
|
assert.isDefined(alert);
|
||||||
|
assert.match(alert.textContent, /been deleted/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
94
test/functional/route/task/index.js
Normal file
94
test/functional/route/task/index.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/* global beforeEach, describe, it */
|
||||||
|
/* jshint maxlen: false, maxstatements: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('proclaim');
|
||||||
|
|
||||||
|
describe('GET /<task-id>', function () {
|
||||||
|
|
||||||
|
describe('when task has results', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/abc000000000000000000001'
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a "Run" button', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=run-task]');
|
||||||
|
assert.strictEqual(elem.length, 1);
|
||||||
|
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000001/run');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a "Download CSV" button for the latest result', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=download-csv]');
|
||||||
|
assert.strictEqual(elem.length, 1);
|
||||||
|
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000001/def000000000000000000001.csv');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a "Download JSON" button for the latest result', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=download-json]');
|
||||||
|
assert.strictEqual(elem.length, 1);
|
||||||
|
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000001/def000000000000000000001.json');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display links to all results', function () {
|
||||||
|
assert.isDefined(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/def000000000000000000001"]')[0]);
|
||||||
|
assert.isDefined(this.last.dom.querySelectorAll('[href="/abc000000000000000000001/def000000000000000000003"]')[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display errors', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=task-errors]')[0];
|
||||||
|
assert.isDefined(elem);
|
||||||
|
assert.match(elem.textContent, /errors \( 1 \)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display warnings', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=task-warnings]')[0];
|
||||||
|
assert.isDefined(elem);
|
||||||
|
assert.match(elem.textContent, /warnings \( 2 \)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display notices', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=task-notices]')[0];
|
||||||
|
assert.isDefined(elem);
|
||||||
|
assert.match(elem.textContent, /notices \( 3 \)/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when task has no results', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/abc000000000000000000003'
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a "Run" button', function () {
|
||||||
|
var elem = this.last.dom.querySelectorAll('[data-test=run-task]');
|
||||||
|
assert.strictEqual(elem.length, 1);
|
||||||
|
assert.strictEqual(elem[0].getAttribute('href'), '/abc000000000000000000003/run');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a message indicating that there are no results', function () {
|
||||||
|
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
|
||||||
|
assert.isDefined(alert);
|
||||||
|
assert.match(alert.textContent, /there are no results to show/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
31
test/functional/route/task/run.js
Normal file
31
test/functional/route/task/run.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/* global beforeEach, describe, it */
|
||||||
|
/* jshint maxlen: false, maxstatements: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('proclaim');
|
||||||
|
|
||||||
|
describe('GET /<task-id>/run', function () {
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
var req = {
|
||||||
|
method: 'GET',
|
||||||
|
endpoint: '/abc000000000000000000001/run'
|
||||||
|
};
|
||||||
|
this.navigate(req, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a 200 status', function () {
|
||||||
|
assert.strictEqual(this.last.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect me to the task page', function () {
|
||||||
|
assert.strictEqual(this.last.request.uri.pathname, '/abc000000000000000000001');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a success message', function () {
|
||||||
|
var alert = this.last.dom.querySelectorAll('[data-test=alert]')[0];
|
||||||
|
assert.isDefined(alert);
|
||||||
|
assert.match(alert.textContent, /new results are being generated/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
36
test/functional/setup.js
Normal file
36
test/functional/setup.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/* global afterEach, before */
|
||||||
|
/* jshint maxlen: false, maxstatements: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var config = require('../../config/test.json');
|
||||||
|
var createNavigator = require('./helper/navigate');
|
||||||
|
var createWebserviceClient = require('./helper/webservice');
|
||||||
|
var loadFixtures = require('pa11y-webservice/data/fixture/load');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
|
// Run before all tests
|
||||||
|
before(function (done) {
|
||||||
|
this.baseUrl = 'http://localhost:' + config.port;
|
||||||
|
this.last = {};
|
||||||
|
this.navigate = createNavigator(this.baseUrl, this.last);
|
||||||
|
this.webservice = createWebserviceClient(config);
|
||||||
|
assertTestAppIsRunning(this.baseUrl, function () {
|
||||||
|
loadFixtures('test', config.webservice, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run after each test
|
||||||
|
afterEach(function (done) {
|
||||||
|
loadFixtures('test', config.webservice, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the test application is running, and exit if not
|
||||||
|
function assertTestAppIsRunning (url, done) {
|
||||||
|
request(url, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error: Test app not started; run with `grunt start-test`');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
@@ -1,7 +1,16 @@
|
|||||||
{{#content "title"}}pa11y-dashboard{{/content}}
|
{{#content "title"}}pa11y-dashboard{{/content}}
|
||||||
|
|
||||||
|
{{#if siteMessage}}
|
||||||
|
<div class="col-md-12 clearfix" data-test="alert">
|
||||||
|
<div class="alert alert-info site-message">
|
||||||
|
<h3 class="crunch-top"><span class="pull-left glyphicon glyphicon-exclamation-sign"></span> Important</h3>
|
||||||
|
<p class="h5">{{siteMessage}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#deleted}}
|
{{#deleted}}
|
||||||
<div class="col-md-12 clearfix">
|
<div class="col-md-12 clearfix" data-test="alert">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
|
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
|
||||||
<strong>Bye Bye URL</strong>
|
<strong>Bye Bye URL</strong>
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
<title>{{block "title"}}</title>
|
<title>{{block "title"}}</title>
|
||||||
<meta name="description" content="{{block "description"}}"/>
|
<meta name="description" content="{{block "description"}}"/>
|
||||||
|
|
||||||
|
{{#if noindex}}<meta name="robots" content="noindex"/>{{/if}}
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="favicon.png" />
|
<link rel="icon" type="image/png" href="favicon.png" />
|
||||||
|
|
||||||
<!-- For mobile devices. -->
|
<!-- For mobile devices. -->
|
||||||
@@ -30,7 +32,11 @@
|
|||||||
{{> breadcrumb}}
|
{{> breadcrumb}}
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
{{#if readonly}}
|
||||||
|
<div class="row readonly-mode">
|
||||||
|
{{else}}
|
||||||
|
<div class="row">
|
||||||
|
{{/if}}
|
||||||
<section>
|
<section>
|
||||||
<div class="section" role="main">
|
<div class="section" role="main">
|
||||||
{{{body}}}
|
{{{body}}}
|
||||||
|
@@ -3,14 +3,14 @@
|
|||||||
Add a new URL
|
Add a new URL
|
||||||
{{/content}}
|
{{/content}}
|
||||||
|
|
||||||
<form role="form" class="col-md-12" action="/new" method="post">
|
<form role="form" class="col-md-12" action="/new" method="post" data-test="new-url-form">
|
||||||
|
|
||||||
<div class="legend">
|
<div class="legend">
|
||||||
<h1 class="h2 crunch-top">Add a new URL</h1>
|
<h1 class="h2 crunch-top">Add a new URL</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#error}}
|
{{#error}}
|
||||||
<div class="col-md-12 clearfix">
|
<div class="col-md-12 clearfix" data-test="error">
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
<strong>Oh my gosh!</strong>
|
<strong>Oh my gosh!</strong>
|
||||||
<p>{{.}}</p>
|
<p>{{.}}</p>
|
||||||
@@ -58,8 +58,8 @@
|
|||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
{{#rules}}
|
{{#rules}}
|
||||||
<li>
|
<li>
|
||||||
<label title="{{description}}" data-role="rules-tooltip" class="checkbox">
|
<input class="pull-left" id="{{name}}" type="checkbox" name="ignore[]" value="{{name}}" {{#ignored}}checked{{/ignored}}/>
|
||||||
<input type="checkbox" name="ignore[]" value="{{name}}" {{#ignored}}checked{{/ignored}}/>
|
<label for="{{name}}" title="{{description}}" data-role="rules-tooltip" class="checkbox">
|
||||||
{{name}}
|
{{name}}
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
@@ -8,10 +8,10 @@
|
|||||||
<li class="active">Add URL</li>
|
<li class="active">Add URL</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if isTaskPage}}
|
{{#if isTaskPage}}
|
||||||
<li class="active">{{simplify-url task.url}}</li>
|
<li class="active">{{task.name}}</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if isResultPage}}
|
{{#if isResultPage}}
|
||||||
<li><a href="{{task.href}}">{{simplify-url task.url}}</a></li>
|
<li><a href="{{task.href}}">{{task.name}}</a></li>
|
||||||
<li class="active">Results for {{date-format mainResult.date format="DD MMM YYYY"}}</li>
|
<li class="active">Results for {{date-format mainResult.date format="DD MMM YYYY"}}</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</ol>
|
</ol>
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<div class="footer" role="contentinfo">
|
<div class="footer" role="contentinfo">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<p>© {{year}} Nature Publishing Group.<br/>pa11y dashboard is licensed under the GNU General Public License 3.0.<br/>Version {{version}}</p>
|
<small>© {{year}} Nature Publishing Group.<br/>pa11y dashboard is licensed under the GNU General Public License 3.0.<br/>Version {{version}}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5 clearfix">
|
<div class="col-md-5 clearfix">
|
||||||
<ul class="crunch-bottom floated-list nav">
|
<ul class="crunch-bottom floated-list nav">
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="h3 crunch well-med well pull-right"><span class="glyphicon glyphicon-calendar"></span> {{date-format mainResult.date format="DD MMM YYYY"}}</div>
|
<div class="h3 crunch well-med well pull-right"><span class="glyphicon glyphicon-calendar"></span> {{date-format mainResult.date format="DD MMM YYYY"}}</div>
|
||||||
<h1 class="h2 crunch-top">{{task.name}}</h1>
|
<h1 class="h2 crunch-top">{{task.name}}</h1>
|
||||||
<p class="h4">{{simplify-url task.url}}<span class="h5"> - ({{task.standard}})</span></p>
|
<p class="h4">{{simplify-url task.url}}<span class="h5"> ({{task.standard}})</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -12,10 +12,14 @@
|
|||||||
<div class="action-buttons col-md-12 col-sm-6 clearfix">
|
<div class="action-buttons col-md-12 col-sm-6 clearfix">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 col-sm-6 col-xs-12">
|
<div class="col-md-12 col-sm-6 col-xs-12">
|
||||||
<a href="{{mainResult.hrefCsv}}" class="btn-full-width btn btn-default">Download CSV <span class="glyphicon glyphicon-download"></span></a>
|
<a href="{{mainResult.hrefCsv}}" class="btn-full-width btn btn-default" data-test="download-csv">
|
||||||
|
Download CSV <span class="glyphicon glyphicon-download"></span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12 col-sm-6 col-xs-12">
|
<div class="col-md-12 col-sm-6 col-xs-12">
|
||||||
<a href="{{mainResult.hrefJson}}" class="btn-full-width btn btn-default">Download JSON <span class="glyphicon glyphicon-download"></span></a>
|
<a href="{{mainResult.hrefJson}}" class="btn-full-width btn btn-default" data-test="download-json">
|
||||||
|
Download JSON <span class="glyphicon glyphicon-download"></span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,7 +41,7 @@
|
|||||||
|
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
{{#if mainResult.count.error}}
|
{{#if mainResult.count.error}}
|
||||||
<div class="heading label-danger showing first" id="errors">
|
<div class="heading label-danger showing first" id="errors" data-test="task-errors">
|
||||||
<span data-role="expander" class="pull-right expander"> - </span>
|
<span data-role="expander" class="pull-right expander"> - </span>
|
||||||
Errors ( {{mainResult.count.error}} )
|
Errors ( {{mainResult.count.error}} )
|
||||||
</div>
|
</div>
|
||||||
@@ -58,7 +62,7 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if mainResult.count.warning}}
|
{{#if mainResult.count.warning}}
|
||||||
<div class="heading label-warning" id="warnings">
|
<div class="heading label-warning" id="warnings" data-test="task-warnings">
|
||||||
<span data-role="expander" class="pull-right expander"> + </span>
|
<span data-role="expander" class="pull-right expander"> + </span>
|
||||||
Warnings ( {{mainResult.count.warning}} )
|
Warnings ( {{mainResult.count.warning}} )
|
||||||
</div>
|
</div>
|
||||||
@@ -79,7 +83,7 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if mainResult.count.notice}}
|
{{#if mainResult.count.notice}}
|
||||||
<div class="heading label-info" id="notices">
|
<div class="heading label-info" id="notices" data-test="task-notices">
|
||||||
<span data-role="expander" class="pull-right expander"> + </span>
|
<span data-role="expander" class="pull-right expander"> + </span>
|
||||||
Notices ( {{mainResult.count.notice}} )
|
Notices ( {{mainResult.count.notice}} )
|
||||||
</div>
|
</div>
|
||||||
|
@@ -3,10 +3,14 @@
|
|||||||
<div class="row clearfix">
|
<div class="row clearfix">
|
||||||
<div class="col-md-9 col-sm-9">
|
<div class="col-md-9 col-sm-9">
|
||||||
<h1 class="h2 crunch-top">{{task.name}}</h1>
|
<h1 class="h2 crunch-top">{{task.name}}</h1>
|
||||||
<p class="h4">{{simplify-url task.url}}<span class="h5"> - ({{task.standard}})</span></p>
|
<p class="h4">{{simplify-url task.url}}<span class="h5"> ({{task.standard}})</span></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 col-sm-3 text-right run-details">
|
<div class="col-md-3 col-sm-3 text-right run-details">
|
||||||
<a href="{{task.hrefRun}}" class="btn btn-success">Run <span class="glyphicon glyphicon-play"></span></a>
|
{{#unless readonly}}
|
||||||
|
<a href="{{task.hrefRun}}" class="btn btn-success" data-test="run-task">
|
||||||
|
Run <span class="glyphicon glyphicon-play"></span>
|
||||||
|
</a>
|
||||||
|
{{/unless}}
|
||||||
{{#if mainResult}}
|
{{#if mainResult}}
|
||||||
<div class="date">Last run : {{date-format mainResult.date format="DD MMM YYYY"}}</div>
|
<div class="date">Last run : {{date-format mainResult.date format="DD MMM YYYY"}}</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@@ -1,13 +1,21 @@
|
|||||||
|
|
||||||
<ul class="list-unstyled clearfix crunch-bottom">
|
<ul class="list-unstyled clearfix crunch-bottom">
|
||||||
<li class="col-md-4 col-sm-6 task-card add-task">
|
<li class="col-md-4 col-sm-6 task-card add-task">
|
||||||
<a class="well task-card-link crunch-bottom" data-role="add-task" href="/new">
|
{{#if readonly}}
|
||||||
<p class="h3 crunch">Add new URL</p>
|
{{! TODO PERRY: make this look disabled }}
|
||||||
<p class="supersize-me crunch">+</p>
|
<span class="well task-card-link crunch-bottom">
|
||||||
</a>
|
<p class="h3 crunch">Add new URL</p>
|
||||||
|
<p class="supersize-me crunch">+</p>
|
||||||
|
</span>
|
||||||
|
{{else}}
|
||||||
|
<a class="well task-card-link crunch-bottom" data-role="add-task" href="/new" data-test="add-task">
|
||||||
|
<p class="h3 crunch">Add new URL</p>
|
||||||
|
<p class="supersize-me crunch">+</p>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
</li>
|
</li>
|
||||||
{{#tasks}}
|
{{#each tasks}}
|
||||||
<li class="col-md-4 col-sm-6 task-card">
|
<li class="col-md-4 col-sm-6 task-card" data-test="task">
|
||||||
<a class="well task-card-link crunch-bottom" title="Details for URL {{simplify-url url}}" href="{{href}}">
|
<a class="well task-card-link crunch-bottom" title="Details for URL {{simplify-url url}}" href="{{href}}">
|
||||||
<p class="h3">{{name}}</p>
|
<p class="h3">{{name}}</p>
|
||||||
<p class="h5">({{standard}})</p>
|
<p class="h5">({{standard}})</p>
|
||||||
@@ -24,7 +32,9 @@
|
|||||||
<p class="no-results">No results</p>
|
<p class="no-results">No results</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</a>
|
</a>
|
||||||
<a title="Delete this URL" class="delete-button" href="{{hrefDelete}}"><span class="sr-only">Delete </span><span class="glyphicon glyphicon-remove"></span></a>
|
{{#unless ../readonly}}
|
||||||
|
<a title="Delete this URL" class="delete-button" href="{{hrefDelete}}"><span class="sr-only">Delete </span><span class="glyphicon glyphicon-remove"></span></a>
|
||||||
|
{{/unless}}
|
||||||
</li>
|
</li>
|
||||||
{{/tasks}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
{{#content "title"}}
|
{{#content "title"}}
|
||||||
{{task.url}} ({{task.standard}}) {{date-format mainResult.date format="DD MMM YYYY"}}
|
{{task.name}} - {{simplify-url task.url}} ({{task.standard}}) - {{date-format mainResult.date format="DD MMM YYYY"}}
|
||||||
{{/content}}
|
{{/content}}
|
||||||
|
|
||||||
{{> result-header}}
|
{{> result-header}}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
Delete {{task.url}} ({{task.standard}})
|
Delete {{task.url}} ({{task.standard}})
|
||||||
{{/content}}
|
{{/content}}
|
||||||
|
|
||||||
<form class="col-md-12" action="{{task.hrefDelete}}" method="post">
|
<form class="col-md-12" action="{{task.hrefDelete}}" method="post" data-test="delete-url-form">
|
||||||
<div class="legend">
|
<div class="legend">
|
||||||
<legend>Delete URL ({{simplify-url task.url}})</legend>
|
<legend>Delete URL ({{simplify-url task.url}})</legend>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
{{#content "title"}}
|
{{#content "title"}}
|
||||||
{{task.url}} ({{task.standard}})
|
{{task.name}} - {{simplify-url task.url}} ({{task.standard}})
|
||||||
{{/content}}
|
{{/content}}
|
||||||
|
|
||||||
{{#added}}
|
{{#added}}
|
||||||
<div class="col-md-12 clearfix">
|
<div class="col-md-12 clearfix" data-test="alert">
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
|
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
|
||||||
<strong>Whoop whoop!</strong>
|
<strong>Whoop whoop!</strong>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
{{/added}}
|
{{/added}}
|
||||||
|
|
||||||
{{#running}}
|
{{#running}}
|
||||||
<div class="col-md-12 clearfix">
|
<div class="col-md-12 clearfix" data-test="alert">
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
|
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
|
||||||
<strong>New results incoming!</strong>
|
<strong>New results incoming!</strong>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
{{#if mainResult}}
|
{{#if mainResult}}
|
||||||
{{> result}}
|
{{> result}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="col-md-12">
|
<div class="col-md-12" data-test="alert">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
<h4>There are no results to show</h4>
|
<h4>There are no results to show</h4>
|
||||||
<p>pa11y has not been run against this URL yet so there are no results to show.</p>
|
<p>pa11y has not been run against this URL yet so there are no results to show.</p>
|
||||||
|
Reference in New Issue
Block a user