Merge branch 'MDL-67687-master-2' of git://github.com/andrewnicols/moodle into master

This commit is contained in:
Eloy Lafuente (stronk7) 2020-08-06 00:59:15 +02:00
commit d55f2b787c
11 changed files with 297 additions and 2 deletions

View File

@ -19,6 +19,7 @@ lib/editor/tinymce/plugins/spellchecker/rpc.php
lib/editor/tinymce/tiny_mce/
lib/mlbackend/php/phpml/
lib/adodb/
lib/behat/axe/
lib/bennu/
lib/evalmath/
lib/phpspreadsheet/

View File

@ -20,6 +20,7 @@ lib/editor/tinymce/plugins/spellchecker/rpc.php
lib/editor/tinymce/tiny_mce/
lib/mlbackend/php/phpml/
lib/adodb/
lib/behat/axe/
lib/bennu/
lib/evalmath/
lib/phpspreadsheet/

View File

@ -49,6 +49,7 @@ list($options, $unrecognized) = cli_get_params(
'torun' => 0,
'optimize-runs' => '',
'add-core-features-to-theme' => false,
'axe' => false,
),
array(
'j' => 'parallel',
@ -71,6 +72,7 @@ Options:
-m, --maxruns Max parallel processes to be executed at one time.
--fromrun Execute run starting from (Used for parallel runs on different vms)
--torun Execute run till (Used for parallel runs on different vms)
--axe Include axe accessibility tests
-o, --optimize-runs Split features with specified tags in all parallel runs.
-a, --add-core-features-to-theme Add all core features to specified theme's
@ -102,7 +104,10 @@ if ($options['parallel'] && $options['parallel'] > 1) {
}
} else {
// Only sanitize options for single run.
$cmdoptionsforsinglerun = array('add-core-features-to-theme');
$cmdoptionsforsinglerun = [
'add-core-features-to-theme',
'axe',
];
foreach ($cmdoptionsforsinglerun as $option) {
if (!empty($options[$option])) {

View File

@ -54,6 +54,7 @@ list($options, $unrecognized) = cli_get_params(
'torun' => 0,
'optimize-runs' => '',
'add-core-features-to-theme' => false,
'axe' => false,
),
array(
'h' => 'help',
@ -69,7 +70,7 @@ $help = "
Behat utilities to manage the test environment
Usage:
php util.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--help] [--parallel=value [--maxruns=value]]
php util.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--axe|--help] [--parallel=value [--maxruns=value]]
Options:
--install Installs the test environment for acceptance tests
@ -78,6 +79,7 @@ Options:
--disable Disables test environment
--diag Get behat test environment status code
--updatesteps Update feature step file.
--axe Include axe accessibility tests
-j, --parallel Number of parallel behat run operation
-m, --maxruns Max parallel processes to be executed at one time.

View File

@ -49,6 +49,7 @@ list($options, $unrecognized) = cli_get_params(
'updatesteps' => false,
'optimize-runs' => '',
'add-core-features-to-theme' => false,
'axe' => false,
),
array(
'h' => 'help',
@ -75,6 +76,7 @@ Options:
--disable Disables test environment
--diag Get behat test environment status code
--updatesteps Update feature step file.
--axe Include axe accessibility tests
-o, --optimize-runs Split features with specified tags in all parallel runs.
-a, --add-core-features-to-theme Add all core features to specified theme's
@ -181,6 +183,9 @@ if ($options['install']) {
behat_config_manager::set_behat_run_config_value('behatsiteenabled', 1);
}
// Define whether to run Behat with axe tests.
behat_config_manager::set_behat_run_config_value('axe', $options['axe']);
// Enable test mode.
behat_util::start_test_mode($options['add-core-features-to-theme'], $options['optimize-runs'], $parallel, $run);

View File

@ -54,3 +54,17 @@ Feature: Authentication
| 0 | not see |
| 1 | see |
| 2 | see |
@javascript @accessibility
Scenario: Login page must be accessible
When I am on site homepage
# The following tests are all provided to ensure that the accessibility tests themselves are tested.
# In normal tests only one of the following is required.
Then the page should meet accessibility standards
And the page should meet "wcag131, wcag412" accessibility standards
And the page should meet accessibility standards with "wcag131, wcag412" extra tests
And I follow "Log in"
And the page should meet accessibility standards
And the page should meet "wcag131, wcag412" accessibility standards
And the page should meet accessibility standards with "wcag131, wcag412" extra tests

12
lib/behat/axe/axe.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -491,4 +491,23 @@ class behat_util extends testing_util {
$linecount = count(explode("\n", $formattedmessage));
fwrite(STDOUT, str_repeat(cli_ansi_format("<cursor:down>"), $linecount - 1));
}
/**
* Gets a text-based site version description.
*
* @return string The site info
*/
public static function get_site_info() {
$siteinfo = parent::get_site_info();
$accessibility = empty(behat_config_manager::get_behat_run_config_value('axe')) ? 'No' : 'Yes';
$siteinfo .= <<<EOF
Run optional tests:
- Accessibility: {$accessibility}
EOF;
return $siteinfo;
}
}

View File

@ -105,6 +105,12 @@ function cli_get_params(array $longoptions, array $shortmapping=null) {
if (count($parts) == 1) {
$key = reset($parts);
$value = true;
if (substr($key, 0, 3) === 'no-') {
// Support flipping the boolean value.
$value = !$value;
$key = substr($key, 3);
}
} else {
$key = array_shift($parts);
$value = implode('=', $parts);

View File

@ -0,0 +1,223 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Steps definitions to open and close action menus.
*
* @package core
* @category test
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use Behat\Mink\Exception\{DriverException, ExpectationException};
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
require_once(__DIR__ . '/../../behat/behat_base.php');
/**
* Steps definitions to assist with accessibility testing.
*
* @package core
* @category test
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_accessibility extends behat_base {
/**
* Run the axe-core accessibility tests.
*
* There are standard tags to ensure WCAG 2.1 A, WCAG 2.1 AA, and Section 508 compliance.
* It is also possible to specify any desired optional tags.
*
* The list of available tags can be found at
* https://github.com/dequelabs/axe-core/blob/v3.5.5/doc/rule-descriptions.md.
*
* @Then the page should meet accessibility standards
* @Then the page should meet accessibility standards with :extratags extra tests
* @Then the page should meet :standardtags accessibility standards
* @param string $standardtags Comma-separated list of standard tags to run
* @param string $extratags Comma-separated list of tags to run in addition to the standard tags
*/
public function run_axe_validation_for_tags(string $standardtags = '', string $extratags = ''): void {
$this->run_axe_for_tags(
// Turn the comma-separated string into an array of trimmed values, filtering out empty values.
array_filter(array_map('trim', explode(',', $standardtags))),
array_filter(array_map('trim', explode(',', $extratags)))
);
}
/**
* Run the Axe tests.
*
* See https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md for details of the supported
* tags.
*
* @param array $standardtags The list of standard tags to run
* @param array $extratags The list of tags, in addition to the standard tags, to run
*/
protected function run_axe_for_tags(array $standardtags = [], array $extratags = []): void {
if (!behat_config_manager::get_behat_run_config_value('axe')) {
return;
}
if (!$this->has_tag('accessibility')) {
throw new DriverException(
'Accessibility tests using Axe must have the @accessibility tag on either the scenario or feature.'
);
}
$this->require_javascript();
$axeurl = (new \moodle_url('/lib/behat/axe/axe.min.js'))->out(false);
$axeconfig = $this->get_axe_config_for_tags($standardtags, $extratags);
$runaxe = <<<EOF
(axeurl => {
const runTests = () => {
const axeTag = document.querySelector('script[data-purpose="axe"]');
axeTag.dataset.results = null;
axe.run({$axeconfig})
.then(results => {
axeTag.dataset.results = JSON.stringify({
violations: results.violations,
exception: null,
});
})
.catch(exception => {
axeTag.dataset.results = JSON.stringify({
violations: [],
exception: exception,
});
});
};
if (document.querySelector('script[data-purpose="axe"]')) {
runTests();
} else {
// Inject the axe content.
const axeTag = document.createElement('script');
axeTag.src = axeurl,
axeTag.dataset.purpose = 'axe';
axeTag.onload = () => runTests();
document.head.append(axeTag);
}
})('{$axeurl}');
EOF;
$this->execute_script($runaxe);
$getresults = <<<EOF
return (() => {
const axeTag = document.querySelector('script[data-purpose="axe"]');
return axeTag.dataset.results;
})()
EOF;
for ($i = 0; $i < self::get_extended_timeout() * 10; $i++) {
$results = json_decode($this->evaluate_script($getresults));
if ($results) {
break;
}
}
if (empty($results)) {
throw new \Exception('No data');
}
if ($results->exception !== null) {
throw new ExpectationException($results->exception, $this->session);
}
$violations = $results->violations;
if (!count($violations)) {
return;
}
$violationdata = "Accessibility violations found:\n";
foreach ($violations as $violation) {
$nodedata = '';
foreach ($violation->nodes as $node) {
$failedchecks = [];
foreach (array_merge($node->any, $node->all, $node->none) as $check) {
$failedchecks[$check->id] = $check->message;
}
$nodedata .= sprintf(
" - %s:\n %s\n\n",
implode(', ', $failedchecks),
implode("\n ", $node->target)
);
}
$violationdata .= sprintf(
" %.03d violations of '%s' (severity: %s)\n%s\n",
count($violation->nodes),
$violation->description,
$violation->impact,
$nodedata
);
}
throw new ExpectationException($violationdata, $this->getSession());
}
/**
* Get the configuration to use with Axe.
*
* See https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md for details of the rules.
*
* @param array|null $standardtags The list of standard tags to run
* @param array|null $extratags The list of tags, in addition to the standard tags, to run
* @return string The JSON-encoded configuration.
*/
protected function get_axe_config_for_tags(?array $standardtags = null, ?array $extratags = null): string {
if (empty($standardtags)) {
$standardtags = [
// Meet WCAG 2.1 A requirements.
'wcag2a',
// Meet WCAG 2.1 AA requirements.
'wcag2aa',
// Meet Section 508 requirements.
// See https://www.epa.gov/accessibility/what-section-508 for detail.
'section508',
// Ensure that ARIA attributes are correctly defined.
'cat.aria',
// Requiremetns for sensory and visual cues.
// These largely related to viewport scale and zoom functionality.
'cat.sensory-and-visual-cues',
// Meet WCAG 1.3.4 requirements for orientation.
// See https://www.w3.org/WAI/WCAG21/Understanding/orientation.html for detail.
'wcag134',
];
}
return json_encode([
'runOnly' => [
'type' > 'tag',
'values' => array_merge($standardtags, $extratags),
],
]);
}
}

View File

@ -7,6 +7,13 @@
<version>5.20.16</version>
<licenseversion>2.1+</licenseversion>
</library>
<library>
<location>behat/axe</location>
<name>axe-core</name>
<license>MPL</license>
<version>3.5.5</version>
<licenseversion>2.0</licenseversion>
</library>
<library>
<location>bennu</location>
<name>Bennu</name>