<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Poltawski</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Poltawski"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Poltawski"/>
	<updated>2026-08-07T14:51:37Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Coding_style&amp;diff=52786</id>
		<title>Coding style</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Coding_style&amp;diff=52786"/>
		<updated>2017-07-31T09:37:10Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* If / else */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
===Scope===&lt;br /&gt;
&lt;br /&gt;
This document describes &#039;&#039;&#039;style&#039;&#039;&#039; guidelines for developers working on or with Moodle code.  It talks purely about the mechanics of code layout and the choices we have made for Moodle.&lt;br /&gt;
&lt;br /&gt;
For details about using the Moodle API to get things done, see the [[Coding|coding guidelines]].&lt;br /&gt;
&lt;br /&gt;
===Goals===&lt;br /&gt;
&lt;br /&gt;
Consistent coding style is important in any development project, and particularly when many developers are involved.  A standard style helps to ensure that the code is easier to read and understand, which helps overall quality.&lt;br /&gt;
&lt;br /&gt;
Abstract goals we strive for:&lt;br /&gt;
&lt;br /&gt;
* simplicity&lt;br /&gt;
* readability&lt;br /&gt;
* tool friendliness, such as use of method signatures, constants, and patterns that support IDE tools and auto-completion of method, class, and constant names.&lt;br /&gt;
&lt;br /&gt;
When considering the goals above, each situation requires an examination of the circumstances and balancing of various trade-offs.&lt;br /&gt;
&lt;br /&gt;
Note that much of the existing Moodle code may not follow all of these guidelines - we continue to upgrade this code when we see it.&lt;br /&gt;
&lt;br /&gt;
===Useful tools===&lt;br /&gt;
&lt;br /&gt;
There are a couple of different tools available to help you in writing code that conforms to this guide.&lt;br /&gt;
&lt;br /&gt;
; Code checker (integrates with [https://github.com/moodlehq/moodle-local_codechecker/blob/master/README.md#ide-integration eclipse/phpstorm]): http://moodle.org/plugins/view.php?plugin=local_codechecker&lt;br /&gt;
; Marina Glancy&#039;s Moodle PHPdoc checker : https://github.com/marinaglancy/moodle-local_moodlecheck&lt;br /&gt;
&lt;br /&gt;
It is worth using both tools to check the code you are writing as they both perform slightly different checks.&lt;br /&gt;
If you can get your code to pass both then you are well on the way to making friends with those who will be reviewing your work.&lt;br /&gt;
&lt;br /&gt;
==File Formatting==&lt;br /&gt;
&lt;br /&gt;
===PHP tags===&lt;br /&gt;
&lt;br /&gt;
Always use &amp;quot;long&amp;quot; php tags.  However, to avoid whitespace problems, DO NOT include the closing tag at the very end of the file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
require(&#039;config.php&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Indentation===&lt;br /&gt;
&lt;br /&gt;
Use an indent of &#039;&#039;&#039;4 spaces&#039;&#039;&#039; with no tab characters. Editors should be configured to treat tabs as spaces in order to prevent injection of new tab characters into the source code.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t indent the main script level:&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
require(&#039;config.php&#039;);&lt;br /&gt;
$a = required_param(&#039;a&#039;, PARAM_INT);&lt;br /&gt;
if ($a &amp;gt; 10) {&lt;br /&gt;
    call_some_error($a);&lt;br /&gt;
} else {&lt;br /&gt;
    do_something_with($a);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
    require(&#039;config.php&#039;);&lt;br /&gt;
    $a = required_param(&#039;a&#039;, PARAM_INT);&lt;br /&gt;
    if ($a &amp;gt; 10) {&lt;br /&gt;
        call_some_error($a);&lt;br /&gt;
    } else {&lt;br /&gt;
        do_something_with($a);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SQL queries use special indentation, see [[SQL coding style]].&lt;br /&gt;
&lt;br /&gt;
===Maximum Line Length===&lt;br /&gt;
&lt;br /&gt;
The key issue is readability.&lt;br /&gt;
&lt;br /&gt;
Aim for 132 characters if it is convenient,  it is not recommended to use more than 180 characters.&lt;br /&gt;
&lt;br /&gt;
The exception are string files in the &amp;lt;tt&amp;gt;/lang&amp;lt;/tt&amp;gt; directory where lines &amp;lt;tt&amp;gt;$string[&#039;id&#039;] = &#039;value&#039;;&amp;lt;/tt&amp;gt; should have the value defined as a single string of any length, wrapped by quotes (no concatenation operators, no heredoc and no newdoc syntax). This helps to parse and process these string files without including them as a PHP code.&lt;br /&gt;
&lt;br /&gt;
====Wrapping lines====&lt;br /&gt;
&lt;br /&gt;
When wrapping a line, indent the follow-on line by 8 spaces rather than 4. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (a_long_condition() &amp;amp;&amp;amp;&lt;br /&gt;
        a_nother_long_condition()) {&lt;br /&gt;
    do_something();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Using eight spaces makes it easier to spot the difference between wrapped lines and indented blocks.&lt;br /&gt;
&lt;br /&gt;
The example above is only an illustration; it is best practice to avoid wrapping lines in control structures. See below.&lt;br /&gt;
&lt;br /&gt;
====Wrapping Arrays====&lt;br /&gt;
&lt;br /&gt;
Associative arrays are a exception to the rule about 8-space indent for follow-on lines. The correct layout is:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$plugininfo[&#039;preferences&#039;][$plugin] = array(&lt;br /&gt;
    &#039;id&#039;     =&amp;gt; $plugin, &lt;br /&gt;
    &#039;link&#039;   =&amp;gt; $pref_url, &lt;br /&gt;
    &#039;string&#039; =&amp;gt; $modulenamestr&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Lining up the =&amp;gt;s is optional. Small arrays can be done on one line.&lt;br /&gt;
&lt;br /&gt;
====Wrapping function declarations====&lt;br /&gt;
If you have many parameters, indent them in line with the first parameter:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function graded_users_iterator($course, $grade_items = null, $groupid = 0,&lt;br /&gt;
                                      $sortfield1 = &#039;lastname&#039;, $sortorder1 = &#039;ASC&#039;,&lt;br /&gt;
                                      $sortfield2 = &#039;firstname&#039;, $sortorder2 = &#039;ASC&#039;) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Wrapping Control Structures====&lt;br /&gt;
If you have too many conditions in one control structure, try setting some variables before the start of the structure to improve readability.&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$coursecategory = ($element[&#039;object&#039;]-&amp;gt;is_course_item() or $element[&#039;object&#039;]-&amp;gt;is_category_item());&lt;br /&gt;
$scalevalue = in_array($element[&#039;object&#039;]-&amp;gt;gradetype, array(GRADE_TYPE_SCALE, GRADE_TYPE_VALUE));&lt;br /&gt;
&lt;br /&gt;
if ($coursecategory and $scalevalue) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (($element[&#039;object&#039;]-&amp;gt;is_course_item() or $element[&#039;object&#039;]-&amp;gt;is_category_item())&lt;br /&gt;
    and ($element[&#039;object&#039;]-&amp;gt;gradetype == GRADE_TYPE_SCALE&lt;br /&gt;
    or $element[&#039;object&#039;]-&amp;gt;gradetype == GRADE_TYPE_VALUE)) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Line Termination===&lt;br /&gt;
&lt;br /&gt;
Use standard &#039;&#039;&#039;Unix&#039;&#039;&#039; text format. Lines must end only with a linefeed (LF). Linefeeds are represented as ordinal 10, or hexadecimal 0x0A.&lt;br /&gt;
&lt;br /&gt;
Do not use carriage returns (CR) like old &#039;&#039;Macintosh&#039;&#039; computers (0x0D).&lt;br /&gt;
&lt;br /&gt;
Do not use the carriage return/linefeed combination (CRLF) as &#039;&#039;Windows&#039;&#039; computers (0x0D, 0x0A).&lt;br /&gt;
&lt;br /&gt;
Lines should not contain trailing spaces. In order to facilitate this convention, most editors can be configured to strip trailing spaces, such as upon a save operation. However, if you are editing an existing Moodle file and are planning to submit your changes for integration, please switch off that feature so that whitespace changes do not pollute the patch (other developers will have trouble viewing what you&#039;ve done if every other line has been edited for whitespace).&lt;br /&gt;
&lt;br /&gt;
==Naming Conventions==&lt;br /&gt;
&lt;br /&gt;
===Filenames===&lt;br /&gt;
&lt;br /&gt;
Filenames should :&lt;br /&gt;
* be whole english words&lt;br /&gt;
* be as short as possible&lt;br /&gt;
* use lowercase letters only &lt;br /&gt;
* end in .php, .html, .js, .css or .xml&lt;br /&gt;
&lt;br /&gt;
===Classes===&lt;br /&gt;
&lt;br /&gt;
Class names should always be lower-case English words, separated by underscores:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class some_custom_class {&lt;br /&gt;
    function class_method() {&lt;br /&gt;
        echo &#039;foo&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Always use () when creating new instances even if constructor does not need any parameters.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$instance = new some_custom_class();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you want an plain object of no particular class, for example when you are preparing some data to insert into the database with $DB-&amp;gt;insert_record, you should use the PHP standard class &#039;&#039;&#039;stdClass&#039;&#039;&#039;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$row = new stdClass();&lt;br /&gt;
$row-&amp;gt;id    = $id;&lt;br /&gt;
$row-&amp;gt;field = &#039;something&#039;;&lt;br /&gt;
$DB-&amp;gt;insert_record(&#039;table&#039;, $row);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Before Moodle 2.0, we used to define a class &#039;&#039;&#039;object&#039;&#039;&#039; extending stdClass, and use new object(); This has now been deprecated. Please use stdClass instead.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Functions and Methods===&lt;br /&gt;
&lt;br /&gt;
Function names should be simple English lowercase words, and start with the [[Frankenstyle]] prefix and plugin name to avoid conflicts between plugins. Words should be separated by underscores. &lt;br /&gt;
&lt;br /&gt;
Verbosity is encouraged: function names should be as illustrative as is practical to enhance understanding.&lt;br /&gt;
&lt;br /&gt;
Note there is no space between the function name and the following (brackets). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function block_course_overview_get_overviews(array $courses) {&lt;br /&gt;
&lt;br /&gt;
    // Actual function code goes here.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is an exception for [[Activity modules|activity modules]] that still use only plugin name as the prefix for legacy reasons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function forum_set_display_mode($mode = 0) {&lt;br /&gt;
    global $USER, $CFG;&lt;br /&gt;
         &lt;br /&gt;
    // Actual function code goes here.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Function Parameters====&lt;br /&gt;
&lt;br /&gt;
Parameters are always simple lowercase English words (sometimes more than one, like $initialvalue), and should always have sensible defaults if possible. &lt;br /&gt;
&lt;br /&gt;
Use &amp;quot;null&amp;quot; as the default value instead of &amp;quot;false&amp;quot; for situations like this where a default value isn&#039;t needed.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function foo($required, $optional = null)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However, if an optional parameter is boolean, and its logical default value should be true, or false, then using true or false is acceptable.&lt;br /&gt;
&lt;br /&gt;
===Variables===&lt;br /&gt;
&lt;br /&gt;
Variable names should always be easy-to-read, meaningful lower-case English words. If you really need more than one word then run them together, but keep them short as possible. Use &#039;&#039;&#039;plural&#039;&#039;&#039; names for arrays of objects. Use &#039;&#039;&#039;positive&#039;&#039;&#039; variables names always (allow, enable not prevent, disable).&lt;br /&gt;
&lt;br /&gt;
 GOOD: $quiz&lt;br /&gt;
 GOOD: $errorstring&lt;br /&gt;
 GOOD: $assignments (for an array of objects)&lt;br /&gt;
 GOOD: $i (but only in little loops)&lt;br /&gt;
 GOOD: $allowfilelocking = false&lt;br /&gt;
&lt;br /&gt;
 BAD: $Quiz&lt;br /&gt;
 BAD: $camelCase&lt;br /&gt;
 BAD: $aReallyLongVariableNameWithoutAGoodReason&lt;br /&gt;
 BAD: $error_string&lt;br /&gt;
 BAD: $preventfilelocking = true&lt;br /&gt;
&lt;br /&gt;
Core global variables in Moodle are identified using uppercase variables (ie $CFG, $SESSION, $USER, $COURSE, $SITE, $PAGE, $DB and $THEME).  Don&#039;t create any more!&lt;br /&gt;
&lt;br /&gt;
===Constants===&lt;br /&gt;
&lt;br /&gt;
Constants should always be in upper case, and always start with [[Frankenstyle]] prefix and plugin name (in case of activities the module name only for legacy reasons). They should have words separated by underscores. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
define(&#039;BLOCK_COURSE_OVERVIEW_SHOWCATEGORIES_NONE&#039;, &#039;0&#039;);&lt;br /&gt;
define(&#039;FORUM_MODE_FLATOLDEST&#039;, 1);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Booleans and the null value===&lt;br /&gt;
&lt;br /&gt;
Use lower case for &#039;&#039;&#039;true&#039;&#039;&#039;, &#039;&#039;&#039;false&#039;&#039;&#039; and &#039;&#039;&#039;null&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Namespaces ===&lt;br /&gt;
&lt;br /&gt;
Namespaces are not required for any new code and there is no requirement to move non-namespaced classes to namespaces. If&lt;br /&gt;
namespaces are used - they must conform to these rules.&lt;br /&gt;
&lt;br /&gt;
Classes belonging to a namespace must be created in a classes directory inside a plugin (e.g. mod/forum/classes), or for core code,&lt;br /&gt;
in lib/classes or subsystemdir/classes.&lt;br /&gt;
&lt;br /&gt;
The classname and filename for all namespaced classes must conform to the&lt;br /&gt;
[[Automatic class loading|automatic class loading]] rules.&lt;br /&gt;
&lt;br /&gt;
Use at most one namespace declaration per file.&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;? // This is a file mod/porridge/classes/local/equipment/spoon.php&lt;br /&gt;
&lt;br /&gt;
namespace mod_porridge\local\equipment;&lt;br /&gt;
&lt;br /&gt;
class spoon {&lt;br /&gt;
    // Your code here.&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// End of file.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace mod_porridge\local\equipment;&lt;br /&gt;
&lt;br /&gt;
class spoon {&lt;br /&gt;
    // Your code here.&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
namespace mod_porridge\local\procedures; // We are changing the namespace here, do not do it.&lt;br /&gt;
&lt;br /&gt;
class eat {&lt;br /&gt;
    // Another code here.&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// End of file.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The namespace declaration may be preceded with a doc block.&lt;br /&gt;
&lt;br /&gt;
The [[Coding style#Classes|class naming]] rules also apply to the names for each level of namespace.&lt;br /&gt;
&lt;br /&gt;
The namespace declaration must be the first non-comment line in the file, followed by one blank line, followed by the (optional)&lt;br /&gt;
&amp;quot;use&amp;quot; statements, one per line, followed by one blank line.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;use&amp;quot; statements should be used to avoid repetition of long namespaces in the code.&lt;br /&gt;
&lt;br /&gt;
Do not import an entire namespace with a &amp;quot;use&amp;quot; statement, import individual classes only.&lt;br /&gt;
&lt;br /&gt;
Do not use named imports (&amp;quot;use XXX as YYY;&amp;quot;) unless it is absolutely required to resolve a conflict.&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
use mod_porridge\local\equipment\spoon; // One class per line.&lt;br /&gt;
use mod_porridge\local\equipment\bowl; // One class per line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
use mod_porridge\local\equipment\spoon, mod_porridge\local\equipment\bowl; // Multiple classes per line.&lt;br /&gt;
use mod_porridge\local; // Importing an entire namespace.&lt;br /&gt;
use core; // Importing an entire namespace.&lt;br /&gt;
use mod_breakfast; // Importing an entire namespace.&lt;br /&gt;
use mod_porridge\local\equipment\spoon as silverspoon; // Named import with no good reason.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Never use the __NAMESPACE__ magic constant.&lt;br /&gt;
&lt;br /&gt;
Never use the &amp;quot;namespace&amp;quot; keyword anywhere but the namespace declaration.&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$obj = new namespace\Another();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do not use bracketed &amp;quot;namespace&amp;quot; blocks.&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace {&lt;br /&gt;
    // Global scope.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Namespaces MUST only be used for classes existing in a subfolder of &amp;quot;classes&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For new classes - the maximum level of detail should be used when deciding the namespace.&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace xxxx\yyyy; // xxxx is the component, yyyy is the api.&lt;br /&gt;
&lt;br /&gt;
class zzzz {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Never use a leading backslash (\) in &amp;quot;namespace&amp;quot; and &amp;quot;use&amp;quot; statements.&lt;br /&gt;
&lt;br /&gt;
Global functions called from namespaced code should never use a leading&lt;br /&gt;
backslash (\). Classes from outside the current scope use the leading backslash&lt;br /&gt;
or are imported by the &amp;quot;use&amp;quot; keyword. See&lt;br /&gt;
[http://www.php.net/manual/en/language.namespaces.fallback.php PHP manual] for&lt;br /&gt;
details.&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace mod_breakfast\local;&lt;br /&gt;
&lt;br /&gt;
use moodle_url;&lt;br /&gt;
&lt;br /&gt;
echo get_string(&#039;goodmorning&#039;, &#039;mod_breakfast&#039;); // No leading backslash for global functions.&lt;br /&gt;
$url = new moodle_url(...); // Leading backslash not needed here because we imported it into our namespace via &amp;quot;use&amp;quot;.&lt;br /&gt;
$tasks = \core\task\manager::get_all_scheduled_tasks(); // Leading slash needed here.&lt;br /&gt;
$a = new \stdClass(); // Leading slash needed here.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \mod_breakfast; // The leading backslash should not be here.&lt;br /&gt;
&lt;br /&gt;
use \core\task\manager; // The leading backslash should not be here.&lt;br /&gt;
&lt;br /&gt;
\get_string(&#039;xxxx&#039;, &#039;yyyy&#039;); // The leading backslash should not be here.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Parts of a namespace ====&lt;br /&gt;
&lt;br /&gt;
Given the following fully qualified name of a class:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;\&amp;lt;level1&amp;gt;\&amp;lt;level2&amp;gt;\&amp;lt;level3&amp;gt;\...\&amp;lt;classname&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
There are clear rules for what is allowable at each level of namespace. Only the first level is mandatory. Nested namespaces are used when the class implements some core API or when the plugin maintainer want to organise classes to separate namespaces within the plugin - see rules regarding the level2 for details.&lt;br /&gt;
&lt;br /&gt;
==== Rules for level1 ====&lt;br /&gt;
&lt;br /&gt;
The first level MUST BE EITHER:&lt;br /&gt;
* a full component name (e.g. &amp;quot;\mod_forum&amp;quot;). All classes using namespaces in a plugin MUST be contained in&lt;br /&gt;
this level 1 namespace.&lt;br /&gt;
or&lt;br /&gt;
* &amp;quot;\core&amp;quot; for all core apis&lt;br /&gt;
&lt;br /&gt;
==== Rules for level2 ====&lt;br /&gt;
&lt;br /&gt;
The second level, when used, MUST BE EITHER:&lt;br /&gt;
* The short name of a core API (must be defined on https://docs.moodle.org/dev/API). The classes in this namespace must either implement or use the API in some way.&lt;br /&gt;
or&lt;br /&gt;
* &amp;quot;\local&amp;quot; for any other classes in a component, if the maintainer wants to organise them further (note that for most components, it&#039;s probably enough to have all their own classes in the root level1 namespace only).&lt;br /&gt;
&lt;br /&gt;
==== Rules for level3 ====&lt;br /&gt;
&lt;br /&gt;
There are no rules limiting what can be used as a level 3 namespace. This is where a plugin or addon can make extensive use of&lt;br /&gt;
namespaces with no chance of conflict with any other plugin or api, now and forever onwards.&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace mod_breakfast;                // Plugin&#039;s own namespace when not using nested namespaces (typical)&lt;br /&gt;
namespace mod_breakfast\local;          // Plugin&#039;s own namespace when using nested namespaces&lt;br /&gt;
namespace mod_breakfast\local\utils;    // Plugin&#039;s own namespace when using nested namespaces with further organisation&lt;br /&gt;
namespace mod_breakfast\event;          // Plugin&#039;s namespace to implement core API&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace mymodule;                     // Violates the level1 rules - invalid component name&lt;br /&gt;
namespace mod_breakfast\myutilities;    // Violates the level2 rules - invalid core API name&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Strings ==&lt;br /&gt;
&lt;br /&gt;
Since string performance is not an issue in current versions of PHP, the main criteria for strings is readability. &lt;br /&gt;
&lt;br /&gt;
===Single quotes===&lt;br /&gt;
&lt;br /&gt;
Always use single quotes when a string is literal, or contains a lot of double quotes (like HTML):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$a = &#039;Example string&#039;; &lt;br /&gt;
echo &#039;&amp;lt;span class=&amp;quot;&#039;.s($class).&#039;&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&#039;; &lt;br /&gt;
$html = &#039;&amp;lt;a href=&amp;quot;http://something&amp;quot; title=&amp;quot;something&amp;quot;&amp;gt;Link&amp;lt;/a&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Double quotes===&lt;br /&gt;
&lt;br /&gt;
These are a lot less useful in Moodle. Use double quotes when you need to include plain variables or a lot of single quotes. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo &amp;quot;&amp;lt;span&amp;gt;$string&amp;lt;/span&amp;gt;&amp;quot;; &lt;br /&gt;
$statement = &amp;quot;You aren&#039;t serious!&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Complex SQL queries should be always enclosed in double quotes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$sql = &amp;quot;SELECT e.*, ue.userid&lt;br /&gt;
          FROM {user_enrolments} ue&lt;br /&gt;
          JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = &#039;self&#039; AND e.customint2 &amp;gt; 0)&lt;br /&gt;
          JOIN {user} u ON u.id = ue.userid&lt;br /&gt;
         WHERE :now - u.lastaccess &amp;gt; e.customint2&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Variable substitution===&lt;br /&gt;
&lt;br /&gt;
Variable substitution can use either of these forms:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$greeting = &amp;quot;Hello $name, welcome back!&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
$greeting = &amp;quot;Hello {$name}, welcome back!&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===String concatenation===&lt;br /&gt;
&lt;br /&gt;
Strings must be concatenated using the &amp;quot;.&amp;quot; operator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$longstring = $several.$short.&#039;strings&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the lines are long, break the statement into multiple lines to improve readability.  In these cases, put the &amp;quot;dot&amp;quot; at the end of each line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string = &#039;This is a very long and stupid string because &#039;.$editorname.&lt;br /&gt;
          &amp;quot; couldn&#039;t think of a better example at the time.&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The dot operator may be used without any space to either side (as shown in the above examples), or with spaces on each side; whichever the developer prefers.&lt;br /&gt;
&lt;br /&gt;
===Language strings===&lt;br /&gt;
&lt;br /&gt;
====Capitals====&lt;br /&gt;
&lt;br /&gt;
Language strings should &amp;quot;Always look like this&amp;quot; and &amp;quot;Never Like This Example&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Capitals should only be used when:&lt;br /&gt;
# starting a sentence, or&lt;br /&gt;
# starting a proper name, like Moodle.&lt;br /&gt;
&lt;br /&gt;
====Structure====&lt;br /&gt;
&lt;br /&gt;
Strings should not be designed for UI concatenation, as it may cause problems in other languages.   Each string should stand alone.&lt;br /&gt;
&lt;br /&gt;
BAD:   &lt;br /&gt;
 $string[&#039;overduehandling&#039;] = &#039;When time expires&#039;;&lt;br /&gt;
 $string[&#039;overduehandlingautosubmit&#039;] = &#039;the attempt is submitted automatically&#039;;&lt;br /&gt;
 $string[&#039;overduehandlinggraceperiod&#039;] = &#039;there is a grace period in which to submit the attempt, but not answer more questions&#039;;&lt;br /&gt;
 $string[&#039;overduehandlingautoabandon&#039;] = &#039;that is it. The attempt must be submitted before time expires, or it is not counted&#039;;&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
 $string[&#039;overduehandling&#039;] = &#039;Time expiry behaviour&#039;;&lt;br /&gt;
 $string[&#039;overduehandlingautosubmit&#039;] = &#039;Unfinished attempts will be auto-submitted immediately&#039;;&lt;br /&gt;
 $string[&#039;overduehandlinggraceperiod&#039;] = &#039;Unfinished attempts have a short grace period to be submitted for grading&#039;;&lt;br /&gt;
 $string[&#039;overduehandlingautoabandon&#039;] = &#039;Unfinished attempts are immediately discarded&#039;;&lt;br /&gt;
&lt;br /&gt;
==Arrays==&lt;br /&gt;
&lt;br /&gt;
===Numerically indexed arrays===&lt;br /&gt;
&lt;br /&gt;
When declaring indexed arrays with the array function, a trailing space must be added after each comma delimiter to improve readability:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$myarray = array(1, 2, 3, &#039;Stuff&#039;, &#039;Here&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Multi-line indexed arrays are fine, but pad each successive lines as above with an 8-space indent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$myarray = array(&lt;br /&gt;
        1, 2, 3, &#039;Stuff&#039;, &#039;Here&#039;,&lt;br /&gt;
        $a, $b, $c, 56.44, $d, 500);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Associative arrays===&lt;br /&gt;
&lt;br /&gt;
Use multiple lines if this helps readability. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$myarray = array(&lt;br /&gt;
    &#039;firstkey&#039; =&amp;gt; &#039;firstvalue&#039;,&lt;br /&gt;
    &#039;secondkey&#039; =&amp;gt; &#039;secondvalue&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Classes==&lt;br /&gt;
&lt;br /&gt;
=== Class declarations ===&lt;br /&gt;
&lt;br /&gt;
* Classes must be named according to Moodle&#039;s naming conventions.&lt;br /&gt;
* The brace should always be written on the line beside the class name.&lt;br /&gt;
* Every class must have a documentation block that conforms to the PHPDocumentor standard.&lt;br /&gt;
* All code in a class must be indented with 4 spaces.&lt;br /&gt;
* Placing additional code in class files is permitted but discouraged. In such files, two blank lines must separate the class from any additional PHP code in the class file.&lt;br /&gt;
&lt;br /&gt;
: An example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Documentation Block Here&lt;br /&gt;
 */&lt;br /&gt;
class sample_class {&lt;br /&gt;
    // All contents of class&lt;br /&gt;
    // must be indented 4 spaces.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Class member variables===&lt;br /&gt;
&lt;br /&gt;
Member variables must be named according to Moodle&#039;s variable naming conventions.&lt;br /&gt;
&lt;br /&gt;
Any variables declared in a class must be listed at the top of the class, above the declaration of any methods.&lt;br /&gt;
&lt;br /&gt;
The var construct is not permitted. Member variables always declare their visibility by using one of the &#039;&#039;&#039;private&#039;&#039;&#039;, &#039;&#039;&#039;protected&#039;&#039;&#039;, or &#039;&#039;&#039;public&#039;&#039;&#039; modifiers. Giving access to member variables directly by declaring them as public is permitted but discouraged in favor of accessor methods (set/get).&lt;br /&gt;
&lt;br /&gt;
==Functions and methods==&lt;br /&gt;
===Function and method declaration===&lt;br /&gt;
&lt;br /&gt;
Functions must be named according to the Moodle function naming conventions.&lt;br /&gt;
&lt;br /&gt;
Methods inside classes must always declare their visibility by using one of the private, protected, or public modifiers.&lt;br /&gt;
&lt;br /&gt;
As with classes, the brace should always be written on same line as the function name. &lt;br /&gt;
&lt;br /&gt;
Don&#039;t leave spaces between the function name and the opening parenthesis for the arguments.&lt;br /&gt;
&lt;br /&gt;
The return value must not be enclosed in parentheses. This can hinder readability, in additional to breaking code if a method is later changed to return by reference. &lt;br /&gt;
&lt;br /&gt;
Return should only be one data type. It is discouraged to have multiple return types&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Documentation Block Here&lt;br /&gt;
 */&lt;br /&gt;
class sample_class {&lt;br /&gt;
    &lt;br /&gt;
    /**&lt;br /&gt;
     * Documentation Block Here&lt;br /&gt;
     */&lt;br /&gt;
    public function sample_function() {&lt;br /&gt;
        // All contents of function&lt;br /&gt;
        // must be indented four spaces.&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Function and method usage===&lt;br /&gt;
&lt;br /&gt;
Function arguments should be separated by a single trailing space after the comma delimiter. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
three_arguments(1, 2, 3);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Magic methods===&lt;br /&gt;
Magic methods are heavily discouraged, justification will be required when used. Note: lazyness will not be a valid argument.  &lt;br /&gt;
&lt;br /&gt;
(See MDL-52634 for discussion of rationale)&lt;br /&gt;
&lt;br /&gt;
==Control statements==&lt;br /&gt;
&lt;br /&gt;
In general, use white space liberally between lines and so on, to add clarity.&lt;br /&gt;
&lt;br /&gt;
===If / else===&lt;br /&gt;
&lt;br /&gt;
Put a space before and after the control statement in brackets, and separate the operators by spaces within the brackets.  Use inner brackets to improve logical grouping if it helps. &lt;br /&gt;
&lt;br /&gt;
Indent with four spaces. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Don&#039;t use elseif!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Always use braces (even if the block is one line and PHP doesn&#039;t require it). The opening brace of a block is always placed on the same line as its corresponding statement or declaration. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($x == $y) {&lt;br /&gt;
    $a = $b;&lt;br /&gt;
} else if ($x == $z) {&lt;br /&gt;
    $a = $c;&lt;br /&gt;
} else {&lt;br /&gt;
    $a = $d;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Switch===&lt;br /&gt;
&lt;br /&gt;
Put a space before and after the control statement in brackets, and separate the operators by spaces within the brackets.  Use inner brackets to improve logical grouping if it helps. &lt;br /&gt;
&lt;br /&gt;
Always indent with four spaces.  Content under each case statement should be indented a further four spaces.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
switch ($something) {&lt;br /&gt;
    case 1:&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
    case 2:&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
    default:&lt;br /&gt;
        break;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Foreach===&lt;br /&gt;
&lt;br /&gt;
As above, uses spaces like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
foreach ($objects as $key =&amp;gt; $thing) {&lt;br /&gt;
    process($thing);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Ternary Operator===&lt;br /&gt;
&lt;br /&gt;
The ternary operator is only permitted to be used for &#039;&#039;&#039;short&#039;&#039;&#039;, &#039;&#039;&#039;simple to understand&#039;&#039;&#039; statements. If the statement can&#039;t be understood in one sentance, use an if statement instead.&lt;br /&gt;
&lt;br /&gt;
Whitespace must be used around the operators to make it clear where the operation is taking place.&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$username = isset($user-&amp;gt;username) ? $user-&amp;gt;username : &#039;&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$toload = (empty($CFG-&amp;gt;navshowallcourses))?self::LOAD_ROOT_CATEGORIES:self::LOAD_ALL_CATEGORIES;&lt;br /&gt;
$coefstring = ($coefstring==&#039;&#039; or $coefstring==&#039;aggregationcoefextrasum&#039;) ? &#039;aggregationcoefextrasum&#039; : &#039;aggregationcoef&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Require / include==&lt;br /&gt;
&lt;br /&gt;
Each file that is accessed via browser should start by including the main config.php file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require(__DIR__ . &#039;/../../config.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any other include/require should use a path starting with &amp;lt;tt&amp;gt;_DIR_&amp;lt;/tt&amp;gt; or an absolute path starting with &amp;lt;tt&amp;gt;$CFG-&amp;gt;dirroot&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;$CFG-&amp;gt;libdir&amp;lt;/tt&amp;gt;. Relative includes starting with &amp;quot;../&amp;quot; can [http://uk.php.net/manual/en/function.include.php sometimes behave strangely under PHP], so should not be used. Our [[CLI scripts]] must not use relative config.php paths starting with &amp;quot;../&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
For library files in normal usage, require_once should be used (this is different from config.php which should always use &#039;require&#039; as above). Examples:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(_DIR_ . &#039;/locallib.php&#039;);&lt;br /&gt;
require_once($CFG-&amp;gt;libdir . &#039;/filelib.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Includes should generally only be done at the top of files or inside functions/methods that need them. Using include/require in the middle of a file in global scope very hard to audit the security of the code.&lt;br /&gt;
&lt;br /&gt;
All other scripts with the exception of imported 3rd party libraries should use following code at the very top to prevent direct execution which might reveal error messages on misconfigured production servers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Documentation and comments==&lt;br /&gt;
&lt;br /&gt;
Code documentation explains the code flow and the purpose of functions and variables.  Use it whenever practical.&lt;br /&gt;
&lt;br /&gt;
===PHPDoc===&lt;br /&gt;
&lt;br /&gt;
Moodle stays as close as possible to &amp;quot;standard&amp;quot; [http://www.phpdoc.org/ PHPDoc format] to document our files, classes and functions.  This helps IDEs (like Netbeans or Eclipse) work properly for Moodle developers, and also allows us to generate web documentation automatically.&lt;br /&gt;
&lt;br /&gt;
PHPDoc has a number of tags that can be used in different places (files, classes and functions).  We have some particular rules for using them in Moodle that you must follow:&lt;br /&gt;
&lt;br /&gt;
====Types====&lt;br /&gt;
&lt;br /&gt;
Some of the tags below (@param, @return...) do require the specification of a valid php type and a description. All these are allowed:&lt;br /&gt;
&lt;br /&gt;
* PHP primitive types: int, bool, string...&lt;br /&gt;
* PHP complex types: array, stdClass (not Array, object).&lt;br /&gt;
* PHP classes:full or relative (to current namespace) class names.&lt;br /&gt;
* true, false, null (always lowercase).&lt;br /&gt;
* static: for methods returning a new instance of the child/caller class.&lt;br /&gt;
* self: for methods returning a new instance of the parent/called class.&lt;br /&gt;
* $this: for methods returning the current instance of the class.&lt;br /&gt;
* void: for methods with a explicit empty &amp;quot;return&amp;quot; statement.&lt;br /&gt;
&lt;br /&gt;
Also, there are some basic rules about how to use those types:&lt;br /&gt;
* We use [http://php.net/manual/en/language.types.type-juggling.php short type names] (bool instead of boolean, int instead of integer).&lt;br /&gt;
* When multiple occurrences of a given &amp;quot;type&amp;quot; are used, it&#039;s highly recommended to document them as type[] instead of the simpler and less informative &amp;quot;array&amp;quot; alternative.&lt;br /&gt;
* When multiple different types are possible, they must be separated by a vertical bar (pipe).&lt;br /&gt;
* All primitives and keywords must be lowercase. The case of the complex types and classes must match the original.&lt;br /&gt;
&lt;br /&gt;
====Tags====&lt;br /&gt;
&lt;br /&gt;
===== @copyright =====&lt;br /&gt;
&lt;br /&gt;
These include the year and copyright holder (creator) of the original file.  Do not change these in existing files!&lt;br /&gt;
&lt;br /&gt;
  @copyright 2008 Kim Bloggs&lt;br /&gt;
&lt;br /&gt;
===== @license =====&lt;br /&gt;
&lt;br /&gt;
These must be GPL v3+ and use this format: &lt;br /&gt;
&lt;br /&gt;
  @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
&lt;br /&gt;
===== @param =====&lt;br /&gt;
&lt;br /&gt;
Don&#039;t put hyphens or anything fancy after the variable name, just a space.&lt;br /&gt;
&lt;br /&gt;
  @param [[#Types|type]] $name Description.&lt;br /&gt;
&lt;br /&gt;
===== @return =====&lt;br /&gt;
&lt;br /&gt;
The @return tag is mandatory if the function has a return statement, but can be left out if it does not have one.&lt;br /&gt;
&lt;br /&gt;
The description portion is optional, it can be left out if the function is simple and already describes what is returned.&lt;br /&gt;
&lt;br /&gt;
  @return [[#Types|type]] Description.&lt;br /&gt;
&lt;br /&gt;
===== @var =====&lt;br /&gt;
&lt;br /&gt;
The @var tag is used to document class properties.&lt;br /&gt;
&lt;br /&gt;
  @var [[#Types|type]] Description.&lt;br /&gt;
&lt;br /&gt;
Exceptionally, when none of the available [[#Types|types]] define the returned value, inline @var phpdocs (within the body of the methods) providing type hinting are allowed to the returned type. Don&#039;t abuse!&lt;br /&gt;
&lt;br /&gt;
===== @uses =====&lt;br /&gt;
&lt;br /&gt;
If a function uses die or exit, please add this tag to the docblock to help developers know this function could terminate the page:&lt;br /&gt;
&lt;br /&gt;
  @uses exit&lt;br /&gt;
&lt;br /&gt;
===== @access =====&lt;br /&gt;
&lt;br /&gt;
The access can be used to specify access control for an element&lt;br /&gt;
&lt;br /&gt;
# Should only be used when the method definition does not already specify access control.&lt;br /&gt;
# In the case of functions, specifying public access is redundant and so should be avoided.&lt;br /&gt;
&lt;br /&gt;
  @access private&lt;br /&gt;
&lt;br /&gt;
===== @package =====&lt;br /&gt;
&lt;br /&gt;
The package tag should always be used to label php files with the correct [[Frankenstyle]] component name.  Full rules are explained on that page, but in summary:&lt;br /&gt;
&lt;br /&gt;
# If the file is part of any component plugin, then use the plugin component name (eg &#039;&#039;&#039;mod_quiz&#039;&#039;&#039; or &#039;&#039;&#039;gradereport_xls&#039;&#039;&#039;)&lt;br /&gt;
# If the file is part of a core subsystem then it will be core_xxxx where xxxx is the name defined in get_core_subsystems().  (eg &#039;&#039;&#039;core_enrol&#039;&#039;&#039; or &#039;&#039;&#039;core_group&#039;&#039;&#039;)&lt;br /&gt;
# If the file is one of the select few files in core that are not part of a subsystem (such as lib/moodlelib.php) then it just as a package of &#039;&#039;&#039;core&#039;&#039;&#039;.&lt;br /&gt;
# Each file can only be part of ONE package.&lt;br /&gt;
&lt;br /&gt;
(We do not have standards for @subpackage at all.  You can use within your @package how you like.)&lt;br /&gt;
&lt;br /&gt;
  @package gradereport_xls&lt;br /&gt;
&lt;br /&gt;
===== @category =====&lt;br /&gt;
&lt;br /&gt;
We use @category only to highlight the public classes, functions or files that are part of one of our [[Core APIs]], or that provide good example implementations of a Core API.  The value must be one of the ones on the [[Core APIs]] page.  &lt;br /&gt;
&lt;br /&gt;
  @category preferences &lt;br /&gt;
&lt;br /&gt;
===== @since =====&lt;br /&gt;
&lt;br /&gt;
When adding a new classes or function to the Moodle core libraries (or adding a new method to an existing class), use a @since tag to document which version of Moodle it was added in. For example:&lt;br /&gt;
 &lt;br /&gt;
  @since Moodle 2.1&lt;br /&gt;
&lt;br /&gt;
===== @see =====&lt;br /&gt;
&lt;br /&gt;
If you want to refer the user to another related element (include, page, class, function, define, method, variable) then you can use @see.&lt;br /&gt;
 &lt;br /&gt;
  @see some_other_function()&lt;br /&gt;
&lt;br /&gt;
===== @link =====&lt;br /&gt;
&lt;br /&gt;
If you want to refer the user to an external URL, use @link.&lt;br /&gt;
&lt;br /&gt;
  @link https://docs.moodle.org/dev/Core_APIs&lt;br /&gt;
&lt;br /&gt;
===== inline @link =====&lt;br /&gt;
&lt;br /&gt;
Occasionally you might want to refer to something else inline within your text, say in a function description.  For these cases you can use an inline @link (with an element name OR a URL) and it looks like this:&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
    * This function uses {@link get_string()} to obtain the currency names...&lt;br /&gt;
    * .....&lt;br /&gt;
&lt;br /&gt;
===== @deprecated (and @todo) =====&lt;br /&gt;
&lt;br /&gt;
When deprecating an old API, use a @deprecated tag to document which version of Moodle it was deprecated in, and add @todo and @see if possible.  Make sure to mention relevant MDL issues.  For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * ...&lt;br /&gt;
 * @deprecated since Moodle 2.0 MDL-12345 - please do not use this function any more.   &lt;br /&gt;
 * @todo MDL-22334 This will be deleted in Moodle 2.2.&lt;br /&gt;
 * @see class_name::new_function()&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If it is important that developers update their code, consider also adding a debugging(&#039;...&#039;, DEBUG_DEVELOPER); call to repeat the deprecated message. If the old function can no longer be supported at all, you may have to throw a coding_exception. There are examples of the various options in lib/deprecatedlib.php.&lt;br /&gt;
&lt;br /&gt;
===== @throws =====&lt;br /&gt;
&lt;br /&gt;
This tag is valid and can be used optionally to indicate the method or function will throw and exception. This is to help developers know they may have to handle the exceptions from such functions.&lt;br /&gt;
&lt;br /&gt;
===== Other specific tags =====&lt;br /&gt;
&lt;br /&gt;
There are some tags that are only allowed within some contexts and not globally. More precisely:&lt;br /&gt;
&lt;br /&gt;
* @Given, @When, @Then, within the [[Acceptance testing#Adding steps definitions|behat steps definitions]].&lt;br /&gt;
* @dataProvider (and some more coming, see MDLSITE-2824), within [[Writing PHPUnit tests#Generators|unit tests]].&lt;br /&gt;
&lt;br /&gt;
===Files===&lt;br /&gt;
&lt;br /&gt;
All files that contain PHP code should contain, without any blank line after the php open tag, a full GPL copyright statement at the top, plus a SEPARATE docblock right under it containing a:&lt;br /&gt;
&lt;br /&gt;
# short one-line description of the file&lt;br /&gt;
# longer description of the file&lt;br /&gt;
# @package tag (required)&lt;br /&gt;
# @category tag (only when everything in the file is related to one of the [[Core APIs]])&lt;br /&gt;
# @copyright (required)&lt;br /&gt;
# @license (required)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This is a one-line short description of the file.&lt;br /&gt;
 *&lt;br /&gt;
 * You can have a rather longer description of the file as well,&lt;br /&gt;
 * if you like, and it can span multiple lines.&lt;br /&gt;
 *&lt;br /&gt;
 * @package    mod_mymodule&lt;br /&gt;
 * @category   backup&lt;br /&gt;
 * @copyright  2008 Kim Bloggs&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Classes===&lt;br /&gt;
&lt;br /&gt;
All classes must have a complete docblock like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Short description for class.&lt;br /&gt;
 *&lt;br /&gt;
 * Long description for class (if any)...&lt;br /&gt;
 *&lt;br /&gt;
 * @package    mod_mymodule&lt;br /&gt;
 * @copyright  2008 Kim Bloggs&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(NOTE that classes that are fundamental to core APIs will also need a @category tag)&lt;br /&gt;
&lt;br /&gt;
The exception are files containing only one class and nothing else. In that case the class is covered by the file docblock and adding an explicit class docblock is optional.&lt;br /&gt;
&lt;br /&gt;
===Properties===&lt;br /&gt;
&lt;br /&gt;
All properties should have a docblock with the following minimum information:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class example {&lt;br /&gt;
    /** @var string This variable does something */&lt;br /&gt;
    protected $something;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class example {&lt;br /&gt;
    /** &lt;br /&gt;
     * This variable does something and has a very long description which can&lt;br /&gt;
     * wrap on multiple lines&lt;br /&gt;
     * @var string &lt;br /&gt;
     */&lt;br /&gt;
    protected $something;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Even if there are several properties all sharing something in common, do not use [https://en.wikipedia.org/wiki/PHPDoc#DocBlock_Templates DocBlock templates]. Instead, document every property explicitly as in the following example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class zebra {&lt;br /&gt;
    /** @var int The number of white stripes */&lt;br /&gt;
    protected $whitestripes = 0;&lt;br /&gt;
&lt;br /&gt;
    /** @var int The number of black stripes */&lt;br /&gt;
    protected $blackstripes = 0;&lt;br /&gt;
&lt;br /&gt;
    /** @var int The number of red stripes */&lt;br /&gt;
    protected $redstripes = 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Constants===&lt;br /&gt;
&lt;br /&gt;
Class constants should be documented in the following way:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class sam {&lt;br /&gt;
   /**&lt;br /&gt;
    * This is used when Sam is in a good mood.&lt;br /&gt;
    */&lt;br /&gt;
   const MOOD_GOOD = 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Functions===&lt;br /&gt;
&lt;br /&gt;
All functions and methods should have a complete docblock like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * The description should be first, with asterisks laid out exactly&lt;br /&gt;
 * like this example. If you want to refer to a another function,&lt;br /&gt;
 * use @see as below.   If it&#039;s useful to link to Moodle&lt;br /&gt;
 * documentation on the web, you can use a @link below or also &lt;br /&gt;
 * inline like this {@link https://docs.moodle.org/dev/something}&lt;br /&gt;
 * Then, add descriptions for each parameter and the return value as follows.&lt;br /&gt;
 *&lt;br /&gt;
 * @see clean_param()&lt;br /&gt;
 * @param int   $postid The PHP type is followed by the variable name&lt;br /&gt;
 * @param array $scale The PHP type is followed by the variable name&lt;br /&gt;
 * @param array $ratings The PHP type is followed by the variable name&lt;br /&gt;
 * @return bool A status indicating success or failure&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You must include a description even if it appears to be obvious from the @param and/or @return lines.&lt;br /&gt;
&lt;br /&gt;
An exception is made for overridden methods which make no change to the meaning of the parent method and maintain the same arguments/return values. In this case you should omit the comment completely. Use of the @inheritdoc or @see tags is explicitly forbidden as a replacement for any complete docblock.&lt;br /&gt;
&lt;br /&gt;
===Defines===&lt;br /&gt;
&lt;br /&gt;
All defines should be documented in the following way:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * PARAM_INT - integers only, use when expecting only numbers.&lt;br /&gt;
 */&lt;br /&gt;
define(&#039;PARAM_INT&#039;, &#039;int&#039;);&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * PARAM_ALPHANUM - expected numbers and letters only.&lt;br /&gt;
 */&lt;br /&gt;
define(&#039;PARAM_ALPHANUM&#039;, &#039;alphanum&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Inline comments===&lt;br /&gt;
&lt;br /&gt;
Inline comments must use the &amp;quot;// &amp;quot; (2 slashes + whitespace) style, laid out neatly so that it fits among the code and lines up with it. The first line of the comment must begin with a capital letter (or a digit, or &#039;...&#039;) and the comment must end with a proper punctuation character. Permitted final characters are &#039;.&#039;, &#039;?&#039; or &#039;!&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function forum_get_ratings_mean($postid, $scale, $ratings = null) {&lt;br /&gt;
    if (!$ratings) {&lt;br /&gt;
&lt;br /&gt;
        $ratings = array();     // Initialize the empty array.&lt;br /&gt;
&lt;br /&gt;
        $rates = $DB-&amp;gt;get_records(&#039;forum_ratings&#039;, array(&#039;post&#039; =&amp;gt; $postid));&lt;br /&gt;
&lt;br /&gt;
        // ... then process each rating in&lt;br /&gt;
        // turn.&lt;br /&gt;
        foreach ($rates as $rate) {&lt;br /&gt;
            do_something_with($rate);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Do we need to tidy up?&lt;br /&gt;
        if (!empty($rates))&lt;br /&gt;
            // 42 more things happen here!&lt;br /&gt;
            finsh_up();&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
GOOD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Comment explaining this piece of code.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
BAD:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/*  Comment explaining this piece of code. */&lt;br /&gt;
# Comment explaining this piece of code. &lt;br /&gt;
// comment explaining this piece of code (without capital letter and punctuation)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your comment is due to some MDL issue, please feel free to include the correct MDL-12345 in your comment.  This makes it easier to track down decisions and discussions about things.&lt;br /&gt;
&lt;br /&gt;
====Using TODO====&lt;br /&gt;
&lt;br /&gt;
This is especially important if you know an issue still exists in that code that should be dealt with later.  Use a TODO along with a MDL code to mark this.  For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// TODO MDL-12345 This works but is a bit of a hack and should be revised in future.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you have a big task that is nearly done, apart a few TODOs, and you really want to mark the big task as finished, then you should file new tracker tasks for each TODO and change the TODOs comments to point at the new issue numbers.&lt;br /&gt;
&lt;br /&gt;
(The script .../lib/simpletest/todochecker.php in Moodle 2.0 will check this. Requires an admin login. This is a new requirement, see MDL-19772)&lt;br /&gt;
&lt;br /&gt;
===CVS keywords===&lt;br /&gt;
&lt;br /&gt;
We have stopped using CVS keywords such as $Id$ in Moodle 2.0 completely.&lt;br /&gt;
&lt;br /&gt;
==Exceptions==&lt;br /&gt;
&lt;br /&gt;
Use exceptions to report errors, especially in library code.&lt;br /&gt;
&lt;br /&gt;
Throwing an exception has almost exactly the same effect as calling print_error, but it is more flexible. For example, the caller can choose to catch the exception and handle it in some way. It also makes it easier to write unit tests.&lt;br /&gt;
&lt;br /&gt;
Any exception that is not caught will trigger an appropriate call to print_error, to report the problem to the user.&lt;br /&gt;
&lt;br /&gt;
Do not abuse exceptions for normal code flow. Exceptions should only be used in erroneous situations.&lt;br /&gt;
&lt;br /&gt;
===Exception classes===&lt;br /&gt;
&lt;br /&gt;
We have a set of custom exception classes. The base class is moodle_exception. You will see that the arguments you pass to new moodle_exception(...) are very similar to the ones you would pass to print_error. There are more specific subclasses for particular types of error.&lt;br /&gt;
&lt;br /&gt;
To get the full list of exception types, search for the regular expression &#039;class +\w+_exception +extends&#039; or ask your IDE to list all the subclasses of moodle_exception.&lt;br /&gt;
&lt;br /&gt;
Where appropriate, you should create new subclasses of moodle_exception for use in your code.&lt;br /&gt;
&lt;br /&gt;
A few notable exception types:&lt;br /&gt;
; moodle_exception : base class for exceptions in Moodle. Use this when a more specific type is not appropriate.&lt;br /&gt;
; coding_exception : thrown when the problem seems to be caused by a developer&#039;s mistake. Often thrown by core code that interacts with plugins. If you throw an exception of this type, try to make the error message helpful to the plugin author, so they know how to fix their code.&lt;br /&gt;
; dml_exception (and subclasses) : thrown when a database query fails.&lt;br /&gt;
; file_exception : thrown by the File API.&lt;br /&gt;
&lt;br /&gt;
==Dangerous functions and constructs==&lt;br /&gt;
PHP includes multiple questionable features that are highly discouraged because they are very often source of serious security problems.&lt;br /&gt;
&lt;br /&gt;
# do not use &#039;&#039;eval()&#039;&#039; function - language packs are exception (to be solved in future).&lt;br /&gt;
# do not use &#039;&#039;preg_replace()&#039;&#039; with /e modifier - use callbacks in order to prevent unintended PHP execution.&lt;br /&gt;
# do not use backticks for shell command execution.&lt;br /&gt;
# do not use &#039;&#039;goto&#039;&#039;, neither the operator neither labels - use other programming techniques to control the execution flow.&lt;br /&gt;
&lt;br /&gt;
==Policy about coding-style only fixes==&lt;br /&gt;
&lt;br /&gt;
Way before this coding-style guide was defined and agreed, a lot of code had been written already. Obviously such code does not follow the coding-style at all. While &#039;&#039;&#039;we enforce conformance for all the new code&#039;&#039;&#039;, we are not paranoid about the status of all the previous one.&lt;br /&gt;
&lt;br /&gt;
In any case, in order to normalize the (progressive, non-critical) transition, a policy issue (MDL-43233) was created and agreed about. And these are the rules to apply to coding-style only changes:&lt;br /&gt;
&lt;br /&gt;
# Related coding-style changes (same lines, a variable within a method/function, adjacent comments...) within a real issue are allowed.&lt;br /&gt;
# Unrelated coding-style changes (other methods, blocks of code, comments...) within a real issue are only accepted for master and in a separate commit.&lt;br /&gt;
# Coding-style only issues are only accepted for master along the first 2 months of every cycle.&lt;br /&gt;
&lt;br /&gt;
== Git commits ==&lt;br /&gt;
&lt;br /&gt;
Constructing a clear and informative commit is an important aspect of the craft of creating open source code and the history of commits is a vital part of the communication between developers. Time should be spent on crafting commits appropriately and using the git tools to achieve it.&lt;br /&gt;
&lt;br /&gt;
Git commits should:&lt;br /&gt;
&lt;br /&gt;
* Tell a perfect, cleaned up version of the history. As if the code was written perfectly first time.&lt;br /&gt;
* Include the MDL-xxxx issue number associated with the change&lt;br /&gt;
* Include CODE AREA when appropriate. (Code area, is just a short name for the area of Moodle that this change affects. It can be a component name if that makes sense, but does not have to be. Remember that your audience here is humans not computers, so if a shortened version of a component name is more readable and distinctive, use that instead.)&lt;br /&gt;
* Be formatted as:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MDL-xxxx CODE AREA: short summary (72 chars soft limit)&lt;br /&gt;
&lt;br /&gt;
Blank line on line 2, followed by an unlimited length detailed explanation&lt;br /&gt;
following if necessary. This section might include the motivation for the change&lt;br /&gt;
and contrast it with the previous behaviour.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Git commits should not:&lt;br /&gt;
* Include changes from bugs found and fixed before integration&lt;br /&gt;
* Include many separate revisions to the same lines of code for a single issue&lt;br /&gt;
* Arbitrarily split when part of a atomic set of logical changes&lt;br /&gt;
&lt;br /&gt;
For more guidance, see [[Commit cheat sheet]]&lt;br /&gt;
&lt;br /&gt;
==Credits==&lt;br /&gt;
&lt;br /&gt;
This document was drawn from the following sources:&lt;br /&gt;
&lt;br /&gt;
# The original [https://docs.moodle.org/en/index.php?title=Development:Coding&amp;amp;oldid=53799 Coding guidelines] page&lt;br /&gt;
# The [http://framework.zend.com/manual/en/coding-standard.html Zend guidelines] and &lt;br /&gt;
# Feedback from all core Moodle developers&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Javascript/Coding_Style|Javascript Coding Style]]&lt;br /&gt;
* [[CSS_Coding_Style|CSS Coding Style]]&lt;br /&gt;
* [[SQL coding style]]&lt;br /&gt;
* [[Coding]]&lt;br /&gt;
* [[CodeSniffer]]&lt;br /&gt;
* [http://moodle.org/plugins/view.php?plugin=local_codechecker Code Checker plugin]&lt;br /&gt;
* [[Accessibility#Moodle-related_accessibility_coding_guidelines|Accessibility coding guidelines]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Coding style]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript/Coding_Style&amp;diff=52586</id>
		<title>Javascript/Coding Style</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript/Coding_Style&amp;diff=52586"/>
		<updated>2017-06-12T14:21:25Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: MDL-57139: Promises guidance&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Moodle JavaScript coding style&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
This document outlines the exceptions to the general Moodle [[Coding_style|Coding style]] which apply to JavaScript. &lt;br /&gt;
&lt;br /&gt;
Unless otherwise specified, developers should follow the general coding style for advice on coding style. &lt;br /&gt;
&lt;br /&gt;
=== Goals ===&lt;br /&gt;
&lt;br /&gt;
Consistent coding style is important in any development project, and&lt;br /&gt;
particularly when many developers are involved. A standard style helps to&lt;br /&gt;
ensure that the code is easier to read and understand, which helps overall&lt;br /&gt;
quality.&lt;br /&gt;
&lt;br /&gt;
Abstract goals we strive for:&lt;br /&gt;
&lt;br /&gt;
* simplicity&lt;br /&gt;
* readability&lt;br /&gt;
* tool friendliness&lt;br /&gt;
&lt;br /&gt;
== Naming conventions ==&lt;br /&gt;
&lt;br /&gt;
=== Variable and function naming ===&lt;br /&gt;
&lt;br /&gt;
Contrary to the standard Moodle coding style, camelCase should be used to name variables and functions in JavaScript.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var currentY,&lt;br /&gt;
    courseCategory,&lt;br /&gt;
    lastValue,&lt;br /&gt;
    lastBackgroundColor;&lt;br /&gt;
&lt;br /&gt;
function doSomething() {&lt;br /&gt;
    // Do stuff here.&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function doSomethingElse() {&lt;br /&gt;
    // Do stuff here.&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var someFunction = function() {&lt;br /&gt;
    // Do stuff here.&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var current_y,&lt;br /&gt;
    currenty,&lt;br /&gt;
    course_category,&lt;br /&gt;
    coursecategory,&lt;br /&gt;
    last_value,&lt;br /&gt;
    lastvalue,&lt;br /&gt;
    last_background_color,&lt;br /&gt;
    lastbackgroundcolor;&lt;br /&gt;
&lt;br /&gt;
function dosomething() {&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function do_something_else() {&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var somefunction = function() {&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var some_other_function = function() {&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var somevalue = null;&lt;br /&gt;
&lt;br /&gt;
if (someTest) {&lt;br /&gt;
    somevalue = function() {&lt;br /&gt;
        return (something &amp;amp;&amp;amp; complicated || somethingelse);&lt;br /&gt;
    };&lt;br /&gt;
} else {&lt;br /&gt;
    somevalue = &#039;basicvalue&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Class naming ===&lt;br /&gt;
&lt;br /&gt;
Classes should be named using CamelCase starting with an uppercase&lt;br /&gt;
letter.&lt;br /&gt;
&lt;br /&gt;
This helps to clearly separate variables, and standard functions from those&lt;br /&gt;
used to create a new instance.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// The instantiator:&lt;br /&gt;
function Pantry() {&lt;br /&gt;
    // Setup code goes here.&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Making use of it:&lt;br /&gt;
var myPantry = new Pantry();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// And another:&lt;br /&gt;
function PantryShelf() {&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var myPantryShelf = new PantryShelf();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// There is no distinction here between a normal function, and one used to&lt;br /&gt;
// create a new object:&lt;br /&gt;
function pantry() {&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// This results in an unclear object creation:&lt;br /&gt;
var myPantry = new pantry();&lt;br /&gt;
&lt;br /&gt;
// This one is also incorrect, despite using camelCase:&lt;br /&gt;
function pantryShelf() {&lt;br /&gt;
}&lt;br /&gt;
var myPantryShelf = new pantryShelf();&lt;br /&gt;
&lt;br /&gt;
// This one is also incorrect:&lt;br /&gt;
function pantry_shelf() {&lt;br /&gt;
}&lt;br /&gt;
var myPantryShelf = new pantry_shelf();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
Variables intended to be constants should use the same naming style of ALL UPPERCASE.&lt;br /&gt;
&lt;br /&gt;
Constants are recommended for use in the following scenarios:&lt;br /&gt;
* CSS: An object containing any CSS classes you may wish to use with Nodes; and&lt;br /&gt;
* SELECTORS: An object containing query selectors for selecting Nodes.&lt;br /&gt;
&lt;br /&gt;
Generally, the keys under this object should also be capitalised.&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var CSS = {&lt;br /&gt;
        MYCLASS: &#039;myclass&#039;,&lt;br /&gt;
        YOURCLASS: &#039;yourclass&#039;&lt;br /&gt;
    },&lt;br /&gt;
    SELECTORS = {&lt;br /&gt;
        MYNODES: &#039;div.example .myclass&#039;,&lt;br /&gt;
        YOURNODES: &#039;div.example .yourclass&#039;&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
function anExampleFunction() {&lt;br /&gt;
    theNode = Y.one(SELECTORS.MYNODES)&lt;br /&gt;
        .addClass(CSS.YOURCLASS)&lt;br /&gt;
        .removeClass(CSS.MYCLASS);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
All variables must:&lt;br /&gt;
* be declared before they are used and using the &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; keyword;&lt;br /&gt;
* be declared once, and only once, for the scope in which they are used;&lt;br /&gt;
* only be declared if they are to be used; and&lt;br /&gt;
* use sensible naming, following the naming convention.&lt;br /&gt;
&lt;br /&gt;
=== Method call wrapping ===&lt;br /&gt;
&lt;br /&gt;
When wrapping a long line which consists of a chained series of functions,&lt;br /&gt;
break the line at the end of each function, and continue the next chain on&lt;br /&gt;
a new line.&lt;br /&gt;
&lt;br /&gt;
The line should be indented by  spaces.&lt;br /&gt;
&lt;br /&gt;
The start of each line should contain the concatanation character, and the&lt;br /&gt;
final line should contain a trailing semicolon.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var childNode = Y.Node.create(&#039;&amp;lt;div /&amp;gt;&#039;)&lt;br /&gt;
        .addClass(CSS.SOMECLASS)&lt;br /&gt;
        .setAttribute(&#039;someAttribute&#039;, &#039;someValue&#039;)&lt;br /&gt;
        .appendTo(parentNode);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// All on one line:&lt;br /&gt;
var childNode = Y.Node.create(&#039;&amp;lt;div /&amp;gt;&#039;).addClass(CSS.SOMECLASS).setAttribute(&#039;someAttribute&#039;, &#039;someValue&#039;).appendTo(parentNode);&lt;br /&gt;
&lt;br /&gt;
// A mix of separation and line concatanation:&lt;br /&gt;
var childNode = Y.Node.create(&#039;&amp;lt;div /&amp;gt;&#039;).addClass(CSS.SOMECLASS)&lt;br /&gt;
        .setAttribute(&#039;someAttribute&#039;, &#039;someValue&#039;).appendTo(parentNode);&lt;br /&gt;
&lt;br /&gt;
// The concatanation character is at the end of the line:&lt;br /&gt;
var childNode = Y.Node.create(&#039;&amp;lt;div /&amp;gt;&#039;).&lt;br /&gt;
        addClass(CSS.SOMECLASS).&lt;br /&gt;
        setAttribute(&#039;someAttribute&#039;, &#039;someValue&#039;).&lt;br /&gt;
        appendTo(parentNode);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Whitespace ==&lt;br /&gt;
&lt;br /&gt;
=== Operators ===&lt;br /&gt;
&lt;br /&gt;
There should be a space at either side of &#039;&#039;&#039;all&#039;&#039;&#039; binary operators to help improve&lt;br /&gt;
legibility of code. This includes:&lt;br /&gt;
* =&lt;br /&gt;
* &amp;amp;&amp;amp;&lt;br /&gt;
* ||&lt;br /&gt;
* ===&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* /&lt;br /&gt;
* *&lt;br /&gt;
&lt;br /&gt;
There should be no space around unary operators. This includes:&lt;br /&gt;
* !&lt;br /&gt;
* ++&lt;br /&gt;
* --&lt;br /&gt;
&lt;br /&gt;
There should be no space around the function operator (.)&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Valid binary operators:&lt;br /&gt;
var a = 1,&lt;br /&gt;
    b = (a &amp;amp;&amp;amp; 1),&lt;br /&gt;
    c = (b || 1),&lt;br /&gt;
    d = (b === c),&lt;br /&gt;
    e = Y.Node.create(&#039;&amp;lt;div&amp;gt;Some Content&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
// No space around the . operator when it&#039;s not a continuation:&lt;br /&gt;
e.someFunctionCall();&lt;br /&gt;
&lt;br /&gt;
// Whitespace is allowed for a function operator when it is a continuation starting on a new line:&lt;br /&gt;
e.someFunction()&lt;br /&gt;
    .someOtherFunction()&lt;br /&gt;
    .someFinalFunction();&lt;br /&gt;
&lt;br /&gt;
// Unary operators should not be separated by whitespace:&lt;br /&gt;
a = a++;&lt;br /&gt;
b = b--;&lt;br /&gt;
c = (!e.someResult());&lt;br /&gt;
&lt;br /&gt;
// An example bringing most of these together:&lt;br /&gt;
var index,&lt;br /&gt;
    loopTest = 0;&lt;br /&gt;
for (index = 0; (!loopTest &amp;lt;= (a / b * (c + d - e.getValue()))); index++) {&lt;br /&gt;
    loopTest = index * 12;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var a=1,&lt;br /&gt;
    b= (a&amp;amp;&amp;amp;1),&lt;br /&gt;
    c =(b||1),&lt;br /&gt;
    d = (b===c);&lt;br /&gt;
&lt;br /&gt;
a = a ++;&lt;br /&gt;
b =b++;&lt;br /&gt;
c= c++;&lt;br /&gt;
d = d++ ;&lt;br /&gt;
&lt;br /&gt;
var e = Y . Node . create(&#039;&amp;lt;div&amp;gt;Some content&amp;lt;/div&amp;gt;&#039;);&lt;br /&gt;
&lt;br /&gt;
for ( index = 0;index&amp;lt;a; index ++ ) {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Assignment ===&lt;br /&gt;
In the case of object property assignment, there should be a space after&lt;br /&gt;
the colon, but not before.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var anObject = {&lt;br /&gt;
        someKey: &#039;someValue&#039;,&lt;br /&gt;
        anotherKey: Y.one(SELECTORS.FOO)&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var anObject = {&lt;br /&gt;
        // Incorrect because a space is present both before and after the assignation character:&lt;br /&gt;
        someKey : &#039;someValue&#039;,&lt;br /&gt;
&lt;br /&gt;
        // Incorrect because there is no whitespace either side of the assignation character:&lt;br /&gt;
        anotherKey:Y.one(SELECTORS.FOO)&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Documentation and comments ==&lt;br /&gt;
&lt;br /&gt;
Modules should be documented using the standard YUI guidance: http://yui.github.io/yuidoc/syntax/index.html.&lt;br /&gt;
&lt;br /&gt;
=== General notes ===&lt;br /&gt;
&lt;br /&gt;
* Unless otherwise specified, comments should conform to the general style guidelines;&lt;br /&gt;
* all comments must start with leading whitespace before the first word on each line; and&lt;br /&gt;
* all indentation must be in addition to any existing leading whitespace on the line.&lt;br /&gt;
&lt;br /&gt;
=== Official documentation ===&lt;br /&gt;
&lt;br /&gt;
All JavaScript documentation must:&lt;br /&gt;
* use the correct docblock format;&lt;br /&gt;
* use the correct JavaScript types where relevant (note, Int is not a valid type in JavaScript);&lt;br /&gt;
* use all appropriate tags;&lt;br /&gt;
* produce valid documentation using the YUIDoc toolset;&lt;br /&gt;
* have a linebreak between the description and the list of tags.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
YUIDoc will only generate documentation for docblocks starting with /**.&lt;br /&gt;
&lt;br /&gt;
YUIDoc will try to generate documentation for *all* docblocks starting /**.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This docblock describes a YUI module.&lt;br /&gt;
 *&lt;br /&gt;
 * @module moodle-mod_food-marmite&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This docblock describes the marmite class within the&lt;br /&gt;
 * moodle-mod_food-marmite module.&lt;br /&gt;
 *&lt;br /&gt;
 * @class Marmite&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This is an example docblock comment. It describes a function called&lt;br /&gt;
 * marmite.&lt;br /&gt;
 *&lt;br /&gt;
 * It adds a number of jars of marmite to the cupboard.&lt;br /&gt;
 *&lt;br /&gt;
 * @method addMarmite&lt;br /&gt;
 * @param {Number} [jarCount=1] The number of jars of marmite to add to the&lt;br /&gt;
 * cupboard. This parameter is optional and defaults to 1.&lt;br /&gt;
 * @chainable&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This docblock describes the property weight, in grams.&lt;br /&gt;
 *&lt;br /&gt;
 * @property weight&lt;br /&gt;
 * @type {Number}&lt;br /&gt;
 * @default &#039;500&#039;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This docblock describes an attribute.&lt;br /&gt;
 *&lt;br /&gt;
 * @attribute weight&lt;br /&gt;
 * @type {Number}&lt;br /&gt;
 * @default &#039;500&#039;&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This is an invalid comment block. It wouldn&#039;t be picked up by yuidoc as&lt;br /&gt;
 * the comment style is incorrect.&lt;br /&gt;
 *&lt;br /&gt;
 * @method foo&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// This is also an invalid comment block and wouldn&#039;t be picked up by&lt;br /&gt;
// YUIDoc.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
* Although this style would be picked up by YUIDoc, it is hard to read.&lt;br /&gt;
*&lt;br /&gt;
* @method foo&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 *Although this style would be picked up by YUIDoc, it is also hard to read.&lt;br /&gt;
 *&lt;br /&gt;
 *@method foo&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This docblock is mostly valid but does not include a linebreak between&lt;br /&gt;
 * the description, and the tags.&lt;br /&gt;
 * @method foo&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== General comments ===&lt;br /&gt;
&lt;br /&gt;
All shorter comments, for example those explaining the subsequent few lines of code should use the // style of comments.&lt;br /&gt;
&lt;br /&gt;
Comments not intended for official documentation must *not* use the Docblock style of commenting as YUIDoc will attempt to include the comment in official documentation.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// This is a valid set of comments for one line.&lt;br /&gt;
&lt;br /&gt;
// And this is a valid longer comment to describe the subsequent few lines&lt;br /&gt;
// in as much detail as required. It can consist of multiple sentences, as&lt;br /&gt;
// long as each new line starts with the correct comment style.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
/* This is an invalid comment style for short comments. */&lt;br /&gt;
&lt;br /&gt;
//This is also an invalid style as there is no leading whitespace after the&lt;br /&gt;
//comment indicator.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This is an invalid multi-line comment. Multi-line comments should not&lt;br /&gt;
 * use the docblock style comments unless they are a valid and fully&lt;br /&gt;
 * formatted docblock.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * This is an also invalid multi-line comment. Although it is not a full&lt;br /&gt;
 * docblock style, it does not start with the // style of comment&lt;br /&gt;
 * indicator.&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Promises ==&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Single promise chain:&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// Need the result of two promises at once:&lt;br /&gt;
$.when(Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;), renderPromise())&lt;br /&gt;
.then(function(title, html) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title).then(function(pixhtml) {&lt;br /&gt;
        actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
        return;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
   return;&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Coding_style|Coding Style]]&lt;br /&gt;
* [[CSS_Coding_Style|CSS Coding Style]]&lt;br /&gt;
* [[Coding]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52585</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52585"/>
		<updated>2017-06-12T14:21:06Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: MDL-57139&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Single promise chain:&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// Need the result of two promises at once:&lt;br /&gt;
$.when(Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;), renderPromise())&lt;br /&gt;
.then(function(title, html) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title).then(function(pixhtml) {&lt;br /&gt;
        actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
        return;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
   return;&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52584</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52584"/>
		<updated>2017-06-12T14:19:22Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Correct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Single promise chain:&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// Need the result of two promises at once:&lt;br /&gt;
$.when(Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;), renderPromise())&lt;br /&gt;
.then(function(title, html) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title).then(function(pixhtml) {&lt;br /&gt;
        actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
        return;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
   return;&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52583</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52583"/>
		<updated>2017-06-12T14:19:00Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Incorrect */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Single promise chain:&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// Result of two promises:&lt;br /&gt;
$.when(Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;), renderPromise())&lt;br /&gt;
.then(function(title, html) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title).then(function(pixhtml) {&lt;br /&gt;
        actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
        return;&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
   return;&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52582</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52582"/>
		<updated>2017-06-12T14:17:57Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Correct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Single promise chain:&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// Result of two promises:&lt;br /&gt;
$.when(Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;), renderPromise())&lt;br /&gt;
.then(function(title, html) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
   return;&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52581</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52581"/>
		<updated>2017-06-12T14:17:23Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Correct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_string(&#039;title&#039;)&lt;br /&gt;
.then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    actionitem.find(&#039;.icon&#039;).replaceWith(pixhtml);&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$.when(Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;), renderPromise())&lt;br /&gt;
.then(function(title, html) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
   return;&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52580</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52580"/>
		<updated>2017-06-12T14:13:24Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Correct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
$.when(Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;), renderPromise())&lt;br /&gt;
.then(function(title, html) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
   return;&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52579</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52579"/>
		<updated>2017-06-12T14:09:10Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Correct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
   return;&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52578</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52578"/>
		<updated>2017-06-12T14:07:12Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Incorrect */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notification.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52577</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52577"/>
		<updated>2017-06-12T14:06:37Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Chain rather than nest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Avoid mixing callbacks and promises ===&lt;br /&gt;
Avoid mixing callbacks and promises. Design code to embrace promise-y patterns for asynchronous code to make maximum use of promises.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input) {&lt;br /&gt;
     return renderPromise();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input).then(function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}).catch(Notification.exception);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function doWork(input, successHandler, errorHandler) {&lt;br /&gt;
     renderPromise().then(function (html) {&lt;br /&gt;
         successHandler(html)&lt;br /&gt;
    }).catch(errorHandler);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
doWork(input, function () {&lt;br /&gt;
   $(&#039;#selector&#039;).html(html);&lt;br /&gt;
}, function (error){&lt;br /&gt;
  Notificatin.exception(error);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52576</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52576"/>
		<updated>2017-06-12T13:53:01Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Do not nest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Chain rather than nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52575</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52575"/>
		<updated>2017-06-12T13:52:39Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Do not nest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow and error handling. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be chained rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52574</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52574"/>
		<updated>2017-06-12T13:49:10Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Do not nest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
Promises as are a construct which help prevent the &amp;lt;i&amp;gt;pyramid of doom&amp;lt;/i&amp;gt; and regain linear control flow. They should not be nested.&lt;br /&gt;
&lt;br /&gt;
* Promises should be composed rather than nested. &lt;br /&gt;
* $.when() should be used to deal with the result of multiple promises&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52573</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52573"/>
		<updated>2017-06-12T13:42:08Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Incorrect */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
Promises should be composed rather than nested. &lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
        self._popup = new Dialogue(title, html);&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52572</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52572"/>
		<updated>2017-06-12T13:41:26Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Do not nest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
Promises should be composed rather than nested. &lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
		self._popup = new Dialogue(title, html);&lt;br /&gt;
	});&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52571</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52571"/>
		<updated>2017-06-12T13:39:04Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Correct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
The great advantage of promises is keeping async code linear rather than nested in &amp;lt;i&amp;gt;callback hell&amp;lt;/i&amp;gt; and handling errors in one place, by nesting promises these advantages are lost.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
		self._popup = new Dialogue(title, html);&lt;br /&gt;
	});&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52570</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52570"/>
		<updated>2017-06-12T13:38:45Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Correct */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Good:&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
The great advantage of promises is keeping async code linear rather than nested in &amp;lt;i&amp;gt;callback hell&amp;lt;/i&amp;gt; and handling errors in one place, by nesting promises these advantages are lost.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
    return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
    self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
		self._popup = new Dialogue(title, html);&lt;br /&gt;
	});&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52569</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52569"/>
		<updated>2017-06-12T13:38:31Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Incorrect */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Good:&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
        $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    });&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
The great advantage of promises is keeping async code linear rather than nested in &amp;lt;i&amp;gt;callback hell&amp;lt;/i&amp;gt; and handling errors in one place, by nesting promises these advantages are lost.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
	self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
		self._popup = new Dialogue(title, html);&lt;br /&gt;
	});&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52568</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52568"/>
		<updated>2017-06-12T13:37:38Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Good:&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
		$(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
	});&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
The great advantage of promises is keeping async code linear rather than nested in &amp;lt;i&amp;gt;callback hell&amp;lt;/i&amp;gt; and handling errors in one place, by nesting promises these advantages are lost.&lt;br /&gt;
&lt;br /&gt;
==== Correct ====&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
	self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Incorrect ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
		self._popup = new Dialogue(title, html);&lt;br /&gt;
	});&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52567</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52567"/>
		<updated>2017-06-12T13:35:56Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Promises */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). To encourage promise usage to be more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
When writing promises they must:&lt;br /&gt;
* return another promise, or&lt;br /&gt;
* return a synchronous value (or undefined), or &lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&lt;br /&gt;
Good:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Good:&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    return templates.renderPix(image, &#039;core&#039;, title);&lt;br /&gt;
}).then(function(pixhtml) {&lt;br /&gt;
    $(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
    return;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Bad:&lt;br /&gt;
str.get_strings(stringRequests).then(function(title) {&lt;br /&gt;
    templates.renderPix(image, &#039;core&#039;, title).function(pixhtml) {&lt;br /&gt;
		$(&#039;#selector&#039;).html(pixhtml);&lt;br /&gt;
	});&lt;br /&gt;
}).then(function() {&lt;br /&gt;
    // Wrong because renderPix() has not guaranted to be resolved here.&lt;br /&gt;
    makeUIVisible();&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
The great advantage of promises is keeping async code linear rather than nested in &amp;lt;i&amp;gt;callback hell&amp;lt;/i&amp;gt; and handling errors in one place, by nesting promises these advantages are lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// GOOD:&lt;br /&gt;
renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;);&lt;br /&gt;
}).then(function(title) {&lt;br /&gt;
	self._popup = new Dialogue(title, html);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// BAD:&lt;br /&gt;
return renderPromise().then(function (html) {&lt;br /&gt;
	return Str.get_string(&#039;competencypicker&#039;, &#039;tool_lp&#039;).then(function(title) {&lt;br /&gt;
		self._popup = new Dialogue(title, html);&lt;br /&gt;
	});&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52550</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52550"/>
		<updated>2017-06-01T10:14:52Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Promises */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). In order to make best use of promises in Moodle more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
=== Summary ===&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
What can we do here? There are three things:&lt;br /&gt;
* return another promise&lt;br /&gt;
* return a synchronous value (or undefined)&lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Always return or throw  ===&lt;br /&gt;
&lt;br /&gt;
Always return in promises. Seee https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html #5&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Do not nest ===&lt;br /&gt;
&lt;br /&gt;
The great advantage of promises is keeping async code linear rather than nested in &amp;lt;i&amp;gt;callback hell&amp;lt;/i&amp;gt; and handling errors in one place, by nesting promises these advantages are lost.&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52549</id>
		<title>User talk:Poltawski/Javascript promises</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_talk:Poltawski/Javascript_promises&amp;diff=52549"/>
		<updated>2017-06-01T09:59:36Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: Created page with &amp;quot; == Promises ==   Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operat...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Promises ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Promises are used extensively in modern Moodle Javascript APIs to handle asynchronous situations. It is unfortunately common to misunderstand how they operate and introduce bugs which only expose themselves in asynchronous edge cases (see article [https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html we have a problem with promises]). In order to make use of promises in Moodle more understandable, consistent and avoid edge case bugs, we have adopted best practices suggested by Nolan Lawson and verified by [https://github.com/xjamundx/eslint-plugin-promise eslint-plugin-promise].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
What can we do here? There are three things:&lt;br /&gt;
* return another promise&lt;br /&gt;
* return a synchronous value (or undefined)&lt;br /&gt;
* throw a synchronous error&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52548</id>
		<title>NPM</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52548"/>
		<updated>2017-06-01T09:04:45Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Switching NPM versions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress|forumurl=https://tracker.moodle.org/browse/MDL-52250}}&lt;br /&gt;
NPM is a package manager for JavaScript. It is used by Moodle developers to install a number of cli tools, primarily those related with [[Grunt]].&lt;br /&gt;
&lt;br /&gt;
== npm dependency management ==&lt;br /&gt;
Tools installed by npm include things like our css/js compressors, post-processors and integrity checks. As differences in output from these tools would cause different results for different developers working on the same code, we need to ensure installed packages are the same.&lt;br /&gt;
&lt;br /&gt;
=== npm shrinkwrap ===&lt;br /&gt;
We use a npm-shrinkwrap.json to ensure that all versions of packages are consistent for developers when they run `npm install`. See https://docs.npmjs.com/files/package-locks for further details on this mechanism. Note: The npm package lock mechanics changed significantly in NPM version 5.&lt;br /&gt;
&lt;br /&gt;
=== Updating npm dependencies ===&lt;br /&gt;
Periodically we will update our npm dependencies, the process for doing this is:&lt;br /&gt;
&lt;br /&gt;
# Ensure you use npm &amp;gt;= 5 - node version 8 (see MDL-59094 for details of why we require this version)&lt;br /&gt;
# Run &amp;lt;pre&amp;gt;npm install packages-name@version&amp;lt;/pre&amp;gt; (e.g. &amp;lt;pre&amp;gt;npm install eslint@3.8.0&amp;lt;/pre&amp;gt;)&lt;br /&gt;
# Verify that both the package.json and npm-shrinkwrap.json have been updated&lt;br /&gt;
# Commit to source control&lt;br /&gt;
&lt;br /&gt;
=== NPM versions ===&lt;br /&gt;
&lt;br /&gt;
In general, you will get the best results when using the latest stable NPM version for install node dependencies with Moodle.&lt;br /&gt;
&lt;br /&gt;
==== Switching NPM versions ====&lt;br /&gt;
We have discovered upstream npm bugs  (MDL-59103) when upgrading NPM version with a previously installed node_modules directory. It is recommended to clear the node_modules directory and re-running `npm install` when changing npm version to avoid these problems.&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52547</id>
		<title>NPM</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52547"/>
		<updated>2017-06-01T09:04:18Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress|forumurl=https://tracker.moodle.org/browse/MDL-52250}}&lt;br /&gt;
NPM is a package manager for JavaScript. It is used by Moodle developers to install a number of cli tools, primarily those related with [[Grunt]].&lt;br /&gt;
&lt;br /&gt;
== npm dependency management ==&lt;br /&gt;
Tools installed by npm include things like our css/js compressors, post-processors and integrity checks. As differences in output from these tools would cause different results for different developers working on the same code, we need to ensure installed packages are the same.&lt;br /&gt;
&lt;br /&gt;
=== npm shrinkwrap ===&lt;br /&gt;
We use a npm-shrinkwrap.json to ensure that all versions of packages are consistent for developers when they run `npm install`. See https://docs.npmjs.com/files/package-locks for further details on this mechanism. Note: The npm package lock mechanics changed significantly in NPM version 5.&lt;br /&gt;
&lt;br /&gt;
=== Updating npm dependencies ===&lt;br /&gt;
Periodically we will update our npm dependencies, the process for doing this is:&lt;br /&gt;
&lt;br /&gt;
# Ensure you use npm &amp;gt;= 5 - node version 8 (see MDL-59094 for details of why we require this version)&lt;br /&gt;
# Run &amp;lt;pre&amp;gt;npm install packages-name@version&amp;lt;/pre&amp;gt; (e.g. &amp;lt;pre&amp;gt;npm install eslint@3.8.0&amp;lt;/pre&amp;gt;)&lt;br /&gt;
# Verify that both the package.json and npm-shrinkwrap.json have been updated&lt;br /&gt;
# Commit to source control&lt;br /&gt;
&lt;br /&gt;
=== NPM versions ===&lt;br /&gt;
&lt;br /&gt;
In general, you will get the best results when using the latest stable NPM version for install node dependencies with Moodle.&lt;br /&gt;
&lt;br /&gt;
==== Switching NPM versions ====&lt;br /&gt;
We have discovered upstream npm bugs  (MDL-59103) when upgrading NPM version with a previously installed node_modules directory. It is recommended to clear the node_modules directory and re-installing when changing npm version to avoid these problems.&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52546</id>
		<title>NPM</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52546"/>
		<updated>2017-06-01T08:56:50Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* npm shrinkwrap */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress|forumurl=https://tracker.moodle.org/browse/MDL-52250}}&lt;br /&gt;
NPM is a package manager for JavaScript. It is used by Moodle developers to install a number of cli tools, primarily those related with [[Grunt]].&lt;br /&gt;
&lt;br /&gt;
== npm dependency management ==&lt;br /&gt;
Tools installed by npm include things like our css/js compressors, post-processors and integrity checks. As differences in output from these tools would cause different results for different developers working on the same code, we need to ensure installed packages are the same.&lt;br /&gt;
&lt;br /&gt;
=== npm shrinkwrap ===&lt;br /&gt;
We use a npm-shrinkwrap.json to ensure that all versions of packages are consistent for developers when they run `npm install`. See https://docs.npmjs.com/files/package-locks for further details on this mechanism. Note: The npm package lock mechanics changed significantly in NPM version 5.&lt;br /&gt;
&lt;br /&gt;
=== Updating npm dependencies ===&lt;br /&gt;
Periodically we will update our npm dependencies, the process for doing this is:&lt;br /&gt;
&lt;br /&gt;
# Ensure you use npm &amp;gt;= 5 - node version 8 (see MDL-59094 for details of why we require this version)&lt;br /&gt;
# Run &amp;lt;pre&amp;gt;npm install packages-name@version&amp;lt;/pre&amp;gt; (e.g. &amp;lt;pre&amp;gt;npm install eslint@3.8.0&amp;lt;/pre&amp;gt;)&lt;br /&gt;
# Verify that both the package.json and npm-shrinkwrap.json have been updated&lt;br /&gt;
# Commit to source control&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52545</id>
		<title>NPM</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52545"/>
		<updated>2017-06-01T08:56:38Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* npm shrinkwrap */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress|forumurl=https://tracker.moodle.org/browse/MDL-52250}}&lt;br /&gt;
NPM is a package manager for JavaScript. It is used by Moodle developers to install a number of cli tools, primarily those related with [[Grunt]].&lt;br /&gt;
&lt;br /&gt;
== npm dependency management ==&lt;br /&gt;
Tools installed by npm include things like our css/js compressors, post-processors and integrity checks. As differences in output from these tools would cause different results for different developers working on the same code, we need to ensure installed packages are the same.&lt;br /&gt;
&lt;br /&gt;
=== npm shrinkwrap ===&lt;br /&gt;
We use a npm-shrinkwrap.json to ensure that all versions of packages are consistent for developers when they run &amp;lt;pre&amp;gt;npm install&amp;lt;/pre&amp;gt;. See https://docs.npmjs.com/files/package-locks for further details on this mechanism. Note: The npm package lock mechanics changed significantly in NPM version 5.&lt;br /&gt;
&lt;br /&gt;
=== Updating npm dependencies ===&lt;br /&gt;
Periodically we will update our npm dependencies, the process for doing this is:&lt;br /&gt;
&lt;br /&gt;
# Ensure you use npm &amp;gt;= 5 - node version 8 (see MDL-59094 for details of why we require this version)&lt;br /&gt;
# Run &amp;lt;pre&amp;gt;npm install packages-name@version&amp;lt;/pre&amp;gt; (e.g. &amp;lt;pre&amp;gt;npm install eslint@3.8.0&amp;lt;/pre&amp;gt;)&lt;br /&gt;
# Verify that both the package.json and npm-shrinkwrap.json have been updated&lt;br /&gt;
# Commit to source control&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52544</id>
		<title>NPM</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52544"/>
		<updated>2017-06-01T08:56:23Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* npm shrinkwrap */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress|forumurl=https://tracker.moodle.org/browse/MDL-52250}}&lt;br /&gt;
NPM is a package manager for JavaScript. It is used by Moodle developers to install a number of cli tools, primarily those related with [[Grunt]].&lt;br /&gt;
&lt;br /&gt;
== npm dependency management ==&lt;br /&gt;
Tools installed by npm include things like our css/js compressors, post-processors and integrity checks. As differences in output from these tools would cause different results for different developers working on the same code, we need to ensure installed packages are the same.&lt;br /&gt;
&lt;br /&gt;
=== npm shrinkwrap ===&lt;br /&gt;
We use a npm-shrinkwrap.json to ensure that all versions of packages are consistent for developers when they run &amp;lt;code&amp;gt;npm install&amp;lt;/code&amp;gt;. See https://docs.npmjs.com/files/package-locks for further details on this mechanism. Note: The npm package lock mechanics changed significantly in NPM version 5.&lt;br /&gt;
&lt;br /&gt;
=== Updating npm dependencies ===&lt;br /&gt;
Periodically we will update our npm dependencies, the process for doing this is:&lt;br /&gt;
&lt;br /&gt;
# Ensure you use npm &amp;gt;= 5 - node version 8 (see MDL-59094 for details of why we require this version)&lt;br /&gt;
# Run &amp;lt;pre&amp;gt;npm install packages-name@version&amp;lt;/pre&amp;gt; (e.g. &amp;lt;pre&amp;gt;npm install eslint@3.8.0&amp;lt;/pre&amp;gt;)&lt;br /&gt;
# Verify that both the package.json and npm-shrinkwrap.json have been updated&lt;br /&gt;
# Commit to source control&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52541</id>
		<title>NPM</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NPM&amp;diff=52541"/>
		<updated>2017-05-31T09:23:44Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: Updated npm section for npm version 5 changes (much simpler)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress|forumurl=https://tracker.moodle.org/browse/MDL-52250}}&lt;br /&gt;
NPM is a package manager for JavaScript. It is used by Moodle developers to install a number of cli tools, primarily those related with [[Grunt]].&lt;br /&gt;
&lt;br /&gt;
== npm dependency management ==&lt;br /&gt;
Tools installed by npm include things like our css/js compressors, post-processors and integrity checks. As differences in output from these tools would cause different results for different developers working on the same code, we need to ensure installed packages are the same.&lt;br /&gt;
&lt;br /&gt;
=== npm shrinkwrap ===&lt;br /&gt;
We use [https://docs.npmjs.com/cli/shrinkwrap npm shrinkwrap] to ensure that all versions of packages are consistent for developers when they run &amp;lt;code&amp;gt;npm install&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Updating npm dependencies ===&lt;br /&gt;
Periodically we will update our npm dependencies, the process for doing this is:&lt;br /&gt;
&lt;br /&gt;
# Ensure you use npm &amp;gt;= 5 - node version 8 (see MDL-59094 for details of why we require this version)&lt;br /&gt;
# Run &amp;lt;pre&amp;gt;npm install packages-name@version&amp;lt;/pre&amp;gt; (e.g. &amp;lt;pre&amp;gt;npm install eslint@3.8.0&amp;lt;/pre&amp;gt;)&lt;br /&gt;
# Verify that both the package.json and npm-shrinkwrap.json have been updated&lt;br /&gt;
# Commit to source control&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Integration_Review&amp;diff=52310</id>
		<title>Integration Review</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Integration_Review&amp;diff=52310"/>
		<updated>2017-05-09T08:43:18Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* During continuous integration/Freeze/QA period */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Purpose==&lt;br /&gt;
&lt;br /&gt;
The purpose of the integration review is to:&lt;br /&gt;
* Ensure consistent quality across the codebase&lt;br /&gt;
* Ensure that pedagogical aims of Moodle are at the forefront of any change&lt;br /&gt;
* Take into consideration the holistic view of moodle, looking at the impact beyond where the original developer was focused&lt;br /&gt;
* Provide guidance and feedback to developers, helping them learn and improve &lt;br /&gt;
* Consider &#039;&#039;&#039;other perspectives&#039;&#039;&#039; of other users perhaps not considered by original developers e.g.&lt;br /&gt;
** Teachers&lt;br /&gt;
** Students&lt;br /&gt;
** Administrators&lt;br /&gt;
**Third-party developers&lt;br /&gt;
&lt;br /&gt;
==Integration Review Process==&lt;br /&gt;
&lt;br /&gt;
# Run automated pre-checks against the continuous integration server. (In future this can be automated and also moved into a publicly accessible domain.)&lt;br /&gt;
# Final code review, much like the peer review, except that this is the final check. To include&lt;br /&gt;
## Takes place in-situ (integrated) to examine the impact to other integrated issues&lt;br /&gt;
## Checking against the coding guidelines - syntax/whitespace&lt;br /&gt;
## Moodleisms - using the built-in API functions where appropriate&lt;br /&gt;
## Cross-DB compatibility &lt;br /&gt;
## Security&lt;br /&gt;
# Check purpose - the patch needs to fix the issue reported.&lt;br /&gt;
# Verify target branches are appropriated. They must match 100% the rules defined for [[#Backporting|backporting issues]].&lt;br /&gt;
# Ensure backwards compatibility is maintained. As a starting point backwards compatibility must always be maintained. Where backwards compatibility is affected it should be:&lt;br /&gt;
## Well discussed with evidence of justification&lt;br /&gt;
## Documented and communicated to the community &lt;br /&gt;
# Verify that components are correct and check the right people have been involved (e.g. component maintainers)&lt;br /&gt;
# For fundamental changes, check that a thread has been started in an appropriate forum, and other Moodlers, given enough time to comment.&lt;br /&gt;
# Tests - must be written to guide tester to verify the fix is working.&lt;br /&gt;
## Unit test - very much preferred if applicable&lt;br /&gt;
## at end of Wednesday, ensure testing is going to complete as expected. else take other actions (speak to test manager)&lt;br /&gt;
# Performance - we have to look at maintaining optimum code here, as far as simple patches that can affect performance. (simple optimisations)&lt;br /&gt;
# Scalability - if master only - we&#039;re looking far future, stable branches may not be lucky to get such improvements.&lt;br /&gt;
# git authorship is correct vs committer + credits due are mentioned + email addresses&lt;br /&gt;
# Documentation / PHP Doc / readability&lt;br /&gt;
# [[Tracker_issue_labels]] which might need adding. Particularly:&lt;br /&gt;
## docs_required / dev_docs_required / release_notes: About which type of documentation is required for the issue.&lt;br /&gt;
## ui_change / api_change: About the implications of the change.&lt;br /&gt;
## unit_test_required / acceptance_test_required / qa_test_required: About the need to cover the issue with some test.&lt;br /&gt;
# Fixed Version after integration - is the versions that the issue is patched for. (A rule here: mention master if its the only branched fixed. If not, don&#039;t mention master)&lt;br /&gt;
# Update the workflow counters&lt;br /&gt;
## If an issue is in need of a second review +1 to errors column in integration workflow counters&lt;br /&gt;
&lt;br /&gt;
== Integration Principles ==&lt;br /&gt;
&lt;br /&gt;
Integration (non-technical but philosophical) principles (4-5 words determining if something has to be integrated/backported or no):&lt;br /&gt;
&lt;br /&gt;
# safety: if something does not look safe, stable, it won&#039;t land. Be conservative.&lt;br /&gt;
# security: all security issues, if not breaking principle (1) will be integrated/backported to all security-supported versions.&lt;br /&gt;
# community: Anything not useful for the community (or against it) won&#039;t be integrated/backported. We can measure the community as 10%HQ, 10%Partners, 10%Core developers, 20%Admins, 20%Teachers, 30%Students - not exact science, just one approximation, you know). Question yourself how the change will affect those groups and ensure positives are bigger always (only affected groups count). All community issues, if not breaking principles (1) and (2) will be integrated.&lt;br /&gt;
# typology:  bug fixes will be always integrated/backported to all the supported braches if none of the principles (1), (2) and (3) are violated. Also, partially-unsupported branches can receive some if they are important enough. Improvements and new features go, exclusively, to master only, that&#039;s the main reason for short release periods. We *must* not make exceptions to this.&lt;br /&gt;
# priority: issues will be &amp;quot;ordered down&amp;quot; by priority down (where priority is a [https://tracker.moodle.org/issues/?filter=14000 mix of various factors], dynamic). And will be integrated in that order. If something has to be delayed, better if it is low priority. Once again, nothing here can break any of the previous principles.&lt;br /&gt;
# tests: unit tests and acceptance tests will backported as far as possible without breaking (1) and (2). New features required to implement tests will be backported if the API is 100% backwards compatible. &lt;br /&gt;
If all the principles are fulfilled, the answer for &amp;quot;should I integrate this?&amp;quot; is, &amp;quot;yes, please!&amp;quot;&lt;br /&gt;
(apart from technical findings, of course, that can lead to the issue being not integrated/reopened at last, these principles are 100% philosophical)&lt;br /&gt;
&lt;br /&gt;
==Schedule==&lt;br /&gt;
===In normal periods ===&lt;br /&gt;
The integrators adhere to the following schedule:&lt;br /&gt;
&lt;br /&gt;
* Sunday 22:00 UTC: Issues waiting for integration brought into current integration.&lt;br /&gt;
* Monday: Integration&lt;br /&gt;
* Tuesday:  Integration&lt;br /&gt;
* Wednesday: [[Testing of integrated issues#The testing process|Testing]]. Integrators duties during this time are to monitor, facilitate and &#039;problem solve&#039; the testing process.&lt;br /&gt;
* Thursday: Testing should be completed by 07:00 UTC, at which time remaining testing failures will be reverted and reopened. The release process follows.&lt;br /&gt;
* Friday: Should be kept free from integration. Integration systems are maintained during this time.&lt;br /&gt;
&lt;br /&gt;
=== During continuous integration/Freeze/QA period ===&lt;br /&gt;
During the continuous integration period the integration team are continuously focused on producing regular builds of master to facilitate QA and fast fixes to issues identified.&lt;br /&gt;
&lt;br /&gt;
* Throughout:&lt;br /&gt;
** Issues are picked on a one by one basis, prioritising [https://docs.moodle.org/dev/QA_testing#Resetting_tests QA blockers] and master regressions (MUST FIX) issues.&lt;br /&gt;
** Any non bug fix issues are given the &#039;&#039;integration_held&#039;&#039; label and are explicitly not picked for integration. Still, anybody is able to add a reasoned &#039;&#039;unhold_requested&#039;&#039; label to those issues in order to get them unblocked by the development managers. Note this does not guarantee the issue to land before release, but just gives it a chance to be integrated like any other issue.&lt;br /&gt;
** Our goal is to achieve &#039;releaseability&#039; throughout, so we stop integrating to ensure a release happens&lt;br /&gt;
&lt;br /&gt;
So, basically, once the QA cycle begins (4 weeks before release) and until release, we do organize work as follows:&lt;br /&gt;
* Continuous officially begins. Everybody is on integration. Until end of on-sync period.&lt;br /&gt;
* Monday: Integration and [[Testing of integrated issues#Differences in test process during continuous integration periods|testing]] happens.&lt;br /&gt;
* Tuesday: Integration happens until 12:00 (UTC+8), [[Testing of integrated issues#Differences in test process during continuous integration periods|afterwards we try to achieve 100% &#039;Test Passed&#039;]] and stop integrating any untested changes until a master release is produced.&lt;br /&gt;
* Wednesday: [Assuming a master release has been rolled] Integration and testing continues&lt;br /&gt;
* Thursday: Integration and testing continues&lt;br /&gt;
* Friday: Integration happens until 12:00 (UTC+8), afterwards we try to achieve 100% &#039;Test Passed&#039; and stop integrating any untested changes until a master release is produced.&lt;br /&gt;
&lt;br /&gt;
Note: along this period we always release as many stable weeklies as master rolls (on-demand, beta, rc) happen (see MDLSITE-3470). Note that those tags are not simply tags but they come with some important implications, aiming to stability, safety and clarity. Integrators will try to remain loyal to them, be warned:&lt;br /&gt;
&lt;br /&gt;
* Once beta is released... new features or improvements &amp;quot;unrelated&amp;quot; with the release will be really harder to be accepted. A +4 from developer managers (normally +3 is enough) will be needed to proceed with the issue. Integrators vote will be, always, -1.&lt;br /&gt;
* Once rc are released... new features or improvements &amp;quot;unrelated&amp;quot; with the release are forbidden. No unhold voting, no managers. Simply forbidden.&lt;br /&gt;
* Last week before release, only &amp;quot;related&amp;quot; issues will be picked for integration. Everything else (bug fixes included) are kept out if unrelated, at very least until after release. No distractions.&lt;br /&gt;
Definition: &amp;quot;related&amp;quot;: said to be a followup of required to release, planned OR security issue.&lt;br /&gt;
&lt;br /&gt;
=== On-sync period ===&lt;br /&gt;
Immediately after a major release and for a short period (right now, 3 weeks, matching HQ sprint duration), the integration team is under the named on-sync period.&lt;br /&gt;
&lt;br /&gt;
At all effects, it&#039;s a normal period (see above), and weeklies are produced for supported stable branches and also for master. But with one important rule/goal:&lt;br /&gt;
&lt;br /&gt;
* We must keep the latest stable branch and master 100% on-sync, specifically about versions and upgrade steps.&lt;br /&gt;
&lt;br /&gt;
This simple, but important constraint, is there to facilitate the integration of impeding bugs, needing urgent resolution, and by keeping them the same, we guarantee that any stable or master fix will apply without problems to both branches. Of course, in order to achieve the rule, these must be also observed along the period:&lt;br /&gt;
&lt;br /&gt;
* We continuously perform diffs between the latest stable and master, controlling that we are on-sync. Any non-authorised difference is cleaned (rewritten).&lt;br /&gt;
* Both improvements and new features (and, in general, everything leading to divergence) are held until the on-sync period ends.&lt;br /&gt;
&lt;br /&gt;
Last, but not less important, a second goal for this on-sync period is:&lt;br /&gt;
&lt;br /&gt;
* The environmental requirements &#039;&#039;&#039;for next major version&#039;&#039;&#039; [[Release process#3_weeks_after|must be agreed and resolved so they can land to master]] early in the process, remaining defined and stable over the next, 6 months of, development cycle.&lt;br /&gt;
&lt;br /&gt;
== Backporting ==&lt;br /&gt;
&lt;br /&gt;
Whilst we&#039;d all like all Moodle users to be using our latest and greatest code, there is a balance to strike between improving our software and maintaining stability (both in terms of regressions, but also training and documentation materials). Large amounts of change on the stable branches make the lives difficult for institutions to manage upgrades between point releases.&lt;br /&gt;
&lt;br /&gt;
==== General policy ====&lt;br /&gt;
Our general policy is as follows:&lt;br /&gt;
&lt;br /&gt;
* Bug fixes will be backported to all (and only to) supported stable branches. &lt;br /&gt;
** When fixing a bug, please provide a fix for all supported stable branches. &lt;br /&gt;
** If a fix doesn&#039;t make sense to be backported to every branch, please make it clear in the issue.&lt;br /&gt;
* Improvements or new features will only land in master.&lt;br /&gt;
&lt;br /&gt;
==== Process for requesting a non bug-fix backport ====&lt;br /&gt;
Improvements or new features can be requested to be backported to the stable branches. We urge developers to consider this request carefully. In recent years, Moodle has moved to a short and predicatable time based release schedule and we use a very effective distributed source control system. Both of these process changes should ensure that a change not being backported to the stable branches is not as problematic as it may have used to be. &lt;br /&gt;
&lt;br /&gt;
Should you feel that a new feature or improvement needs backporting, please follow this process:&lt;br /&gt;
&lt;br /&gt;
# File a new issue.&lt;br /&gt;
# Set the issue title using our backport template guide.  (i.e. &amp;quot;Fix forum alignment (backport of MDL-99999)&amp;quot;) - see [https://docs.moodle.org/dev/Tracker_guide#Tracker_fields Tracker_guide]&lt;br /&gt;
# Link the original issue&lt;br /&gt;
# You should include clear rationale for the request to backport&lt;br /&gt;
&lt;br /&gt;
The integration team will process backport requests, with the following guidelines:&lt;br /&gt;
# The integration team will together consider each request individually considering the needs of the community (influenced by forum posts, moodle partners, nagging developers etc).&lt;br /&gt;
# Backports will happen not earlier than 3 weeks and not later than 2 months after the issue has landed in master.&lt;br /&gt;
# Rationale will be given for rejection&lt;br /&gt;
&lt;br /&gt;
If the backport request is approved, please follow the usual development process to submit the feature or improvement on earlier branches.&lt;br /&gt;
&lt;br /&gt;
==== Polite note about bug classification ====&lt;br /&gt;
Many issues can be appropiately classified as borderline bugfix/improvements. We politely request that developers do not try and &#039;game the system&#039; by clasifying their improvements as bugs intentionally. If your fix is in a grey area, please state your case for it being a bug fix clearly. The integration team will use their discretion where necessary.&lt;br /&gt;
&lt;br /&gt;
==== Backport fixes to unsupported branches ====&lt;br /&gt;
* Given the [[#General policy|general policy]] above, only supported stable branches are candidates normally.&lt;br /&gt;
* Also security and dataloss issues are accepted to be fixed into security-only supported branches.&lt;br /&gt;
* Apart from the previous, backport to unsupported branches only will happen when the issue is a &#039;&#039;&#039;direct regression caused by a bug fix&#039;&#039;&#039; introduced by the latest releases. This applies to both security-only and out-of-support branches. A new weekly release will be performed including the fix.&lt;br /&gt;
&lt;br /&gt;
== Fixing issues identified during integration review/ testing ==&lt;br /&gt;
&lt;br /&gt;
When a branch has been merged by an integrator, it is important that you do not modify the existing history of your branch (e.g. by amending or squashing your commits) and instead add new commits on top. If you modify the history of your branch, it makes it extremely difficult for the integrator to merge your changes (and see the differences).&lt;br /&gt;
&lt;br /&gt;
As a general rule, this means that if your issue has entered the &#039;in integration review&#039; stage of the development process, please only add new commits on top of your existing commits. There are circumstances when your issue will be &#039;in integration review&#039; but not merged (and thus possible to squash changes) but if in any doubt, please add new commits and ask the integrator to squash your changes for you.&lt;br /&gt;
&lt;br /&gt;
== Commit squashing ==&lt;br /&gt;
&lt;br /&gt;
The Integration team will sometimes recommend squashing commits when things do not look natural (and may offer to do this for you), especially when there are &amp;quot;fix-commits&amp;quot; in the history happening before integration. But [https://moodle.org/local/chatlogs/index.php?conversationid=13987#c489485 our policy] is &amp;quot;if you want your history of commits to look like bad, it&#039;s your history&amp;quot;. You will not be forced to squash your changes. You should pay close attention to https://docs.moodle.org/dev/Coding_style#Git_commits and intend to  &amp;quot;Tell a perfect, cleaned up version of the history. As if the code was written perfectly first time.&amp;quot;.&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52236</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52236"/>
		<updated>2017-05-04T08:25:25Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* And I follow &amp;quot;Course 1&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
UI changes in the new dashboard mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
=== And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt; Summary &amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot;&amp;lt;br&amp;gt;And I navigate to &amp;quot;Site blogs&amp;quot; node in &amp;quot;Site pages&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
| And I navigate to course participants&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;Current course &amp;gt; C1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course participants &lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to course participants&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt; Why did this change? &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52235</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52235"/>
		<updated>2017-05-04T08:25:10Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
UI changes in the new dashboard mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
=== And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt; Summary &amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot;&amp;lt;br&amp;gt;And I navigate to &amp;quot;Site blogs&amp;quot; node in &amp;quot;Site pages&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
| And I navigate to course participants&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;Current course &amp;gt; C1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course participants &lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to course participants&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt; Why did this change? &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52234</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52234"/>
		<updated>2017-05-04T08:24:28Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
UI changes in the new dashboard mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
=== And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt; Summary &amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot;&amp;lt;br&amp;gt;And I navigate to &amp;quot;Site blogs&amp;quot; node in &amp;quot;Site pages&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
| And I navigate to course participants&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Examples &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;Current course &amp;gt; C1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course participants &lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to course participants&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Why did this change? &amp;lt;/b&amp;gt;&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52233</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52233"/>
		<updated>2017-05-04T08:23:50Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* And I follow &amp;quot;Course 1&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
UI changes in the new dashboard mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Examples&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
=== And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt; Summary &amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot;&amp;lt;br&amp;gt;And I navigate to &amp;quot;Site blogs&amp;quot; node in &amp;quot;Site pages&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
| And I navigate to course participants&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Examples &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;Current course &amp;gt; C1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course participants &lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to course participants&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Why did this change? &amp;lt;/b&amp;gt;&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52232</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52232"/>
		<updated>2017-05-04T08:17:28Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Examples&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
UI changes in the new dashboard mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Examples&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
=== And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt; Summary &amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot;&amp;lt;br&amp;gt;And I navigate to &amp;quot;Site blogs&amp;quot; node in &amp;quot;Site pages&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
| And I navigate to course participants&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Examples &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;Current course &amp;gt; C1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course participants &lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to course participants&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; Why did this change? &amp;lt;/b&amp;gt;&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52231</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52231"/>
		<updated>2017-05-04T08:12:13Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Moodle 3.2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI changes in the new dashboard mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
=== And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot;&amp;lt;br&amp;gt;And I navigate to &amp;quot;Site blogs&amp;quot; node in &amp;quot;Site pages&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
| And I navigate to course participants&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;Current course &amp;gt; C1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course participants &lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to course participants&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52230</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52230"/>
		<updated>2017-05-04T08:07:38Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI changes in the new dashboard mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52229</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52229"/>
		<updated>2017-05-04T08:07:02Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: Undo revision 52228 by Poltawski (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52228</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52228"/>
		<updated>2017-05-04T08:06:39Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Compatibility changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Browsers&amp;diff=52227</id>
		<title>Acceptance testing/Browsers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Browsers&amp;diff=52227"/>
		<updated>2017-05-04T08:02:30Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page complements [[Acceptance testing]] providing info about how to run the acceptance tests suite in different browsers.&lt;br /&gt;
&lt;br /&gt;
== Drivers ==&lt;br /&gt;
&lt;br /&gt;
There are Selenium drivers (http://docs.seleniumhq.org/projects/webdriver/) to run acceptance tests in different browsers:&lt;br /&gt;
&lt;br /&gt;
* Firefox - https://code.google.com/p/selenium/wiki/FirefoxDriver&lt;br /&gt;
* Chrome - https://code.google.com/p/selenium/wiki/ChromeDriver&lt;br /&gt;
* Safari - https://code.google.com/p/selenium/wiki/SafariDriver&lt;br /&gt;
* Internet Explorer - https://code.google.com/p/selenium/wiki/InternetExplorerDriver&lt;br /&gt;
* Microsoft Edge - https://www.microsoft.com/en-us/download/details.aspx?id=48212&lt;br /&gt;
* PhantomJS (Webkit) - http://phantomjs.org/&lt;br /&gt;
* IPhone - https://code.google.com/p/selenium/wiki/IPhoneDriver&lt;br /&gt;
&lt;br /&gt;
Each driver should be downloaded and Selenium .jar should be started specifying the path to the driver; depending on the driver there could be other requirements. &lt;br /&gt;
&lt;br /&gt;
=== PhantomJS ===&lt;br /&gt;
&lt;br /&gt;
PhantomJS is different as it is a headless browser as it is quite faster than other drivers, it doesn&#039;t need a GUI to run and can execute JS, it doesn&#039;t even need to be used through Selenium (you can do it though, but it&#039;s not officially supported) and you can do it&lt;br /&gt;
&lt;br /&gt;
* Download PhantomJS: http://phantomjs.org/download.html&lt;br /&gt;
* /path/to/your/phantomjs/bin/phantomjs --webdriver=4444&lt;br /&gt;
&lt;br /&gt;
Note that 4444 is the default port used by Selenium so you must specify another one if you want to run them together and specify the port in $CFG-&amp;gt;behat_config.&lt;br /&gt;
&lt;br /&gt;
=== Examples ===&lt;br /&gt;
&lt;br /&gt;
  # Selenium in Linux (firefox by default + chrome)&lt;br /&gt;
  java -jar /opt/selenium-server-standalone.jar -Dwebdriver.chrome.driver=/opt/chromedriver&lt;br /&gt;
&lt;br /&gt;
  # Selenium in OSx (firefox &amp;amp; safari by default + chrome)&lt;br /&gt;
  java -jar /Users/moodle/Downloads/selenium-server-standalone.jar -Dwebdriver.chrome.driver=/Users/moodle/Downloads/chromedriver&lt;br /&gt;
&lt;br /&gt;
  # Selenium in Windows (started using git bash) (firefox by default + chrome + internet explorer)&lt;br /&gt;
  java -jar /c/seleniumdrivers/selenium-server-standalone.jar -Dwebdriver.chrome.driver=/c/seleniumdrivers/chromedriver.exe -Dwebdriver.ie.driver=/c/seleniumdrivers/IEDriverServer.exe&lt;br /&gt;
&lt;br /&gt;
  # PhantomJS&lt;br /&gt;
  /path/to/your/phantomjs/bin/phantomjs --webdriver=4444&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
Not all the drivers can execute all of Moodle&#039;s step definitions; we tagged the step definitions that are using features not supported by all browsers and also limitations that some browsers have; refer to the following table to know which browsers can run which tags:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
|File uploads (@_file_upload)&lt;br /&gt;
|Browser dialogs (@_alert)&lt;br /&gt;
|Switch window (@_switch_window)&lt;br /&gt;
|Switch frame (@_switch_iframe)&lt;br /&gt;
|Bug in phantomjs (@_bug_phantomjs)&lt;br /&gt;
|-&lt;br /&gt;
|Firefox&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Chrome&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Internet Explorer&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;No&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Safari&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;No&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;No&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PhantomJS&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;No&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;No&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:#0f0&amp;quot;&amp;gt;Yes&amp;lt;/span&amp;gt;&lt;br /&gt;
|&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;No&amp;lt;/span&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Working combinations of OS+Browser+selenium ==&lt;br /&gt;
As OS, Browsers and Selenium keeps updating, some combination of OS+Browser+Selenium will not work on specific moodle version.&lt;br /&gt;
&lt;br /&gt;
We try to support the latest version of these combinations but they are not always BC and hence may not work with older releases. Please refer to [[Acceptance testing/Browsers/Working combinations of OS+Browser+selenium]] to ensure you have correct combination of them to run acceptance test.&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Running_acceptance_test&amp;diff=52226</id>
		<title>Running acceptance test</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Running_acceptance_test&amp;diff=52226"/>
		<updated>2017-05-04T08:02:13Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Tests are failing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Prerequisite ==&lt;br /&gt;
Before initializing acceptance test environment for running behat, you should ensure:&lt;br /&gt;
# [[Acceptance_testing#Requirements Meet min. system requirements for running tests]]&lt;br /&gt;
# [[Acceptance_testing#Installation Have set min. config variable in config.php for behat]]&lt;br /&gt;
# [[Acceptance_testing#Installation Downloaded composer dependencies]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
Acceptance tests (also known as behat), use [http://www.seleniumhq.org/download/ Selenium server] and can be run as:&lt;br /&gt;
# &#039;&#039;&#039;Single run:&#039;&#039;&#039; In single run, only one behat run is executed. So all features are executed in this single run.&lt;br /&gt;
# &#039;&#039;&#039;Parallel runs:&#039;&#039;&#039; (Since Moodle 3.0) Parallel runs allow dev&#039;s to execute multiple behat runs together. This was introduced to get acceptance tests results faster. To achieve this:&lt;br /&gt;
#* Features are divided between multiple behat runs&lt;br /&gt;
#* Symlinks behatrun{x} (x being the run process number), are created pointing to moodle directory, so site for run 1 is accessible via https://localhost/moodle/behatrun1&lt;br /&gt;
#* Process number is included as suffix to $CFG-&amp;gt;behat_prefix.&lt;br /&gt;
#* Process number is suffixed to $CFG-&amp;gt;behat_dataroot.&lt;br /&gt;
&lt;br /&gt;
== Step 1: Initialise acceptance test environment ==&lt;br /&gt;
Before running acceptance tests, environment needs to be initialised for acceptance testing.&lt;br /&gt;
&lt;br /&gt;
=== Single run ===&lt;br /&gt;
For initialising acceptance tests for single run, above command is sufficient.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/init.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parallel runs ===&lt;br /&gt;
For initialising acceptance tests for parallel runs, you can use one of the following options&lt;br /&gt;
# &#039;&#039;&#039;-j or --parallel&#039;&#039;&#039; (required) Number of parallel behat run to initialise&lt;br /&gt;
# &#039;&#039;&#039;-m or --maxruns&#039;&#039;&#039;  (optional) Max parallel site which should be initialised at one time. If your system is slow, then you can initialise sites in chucks.&lt;br /&gt;
# &#039;&#039;&#039;--fromrun&#039;&#039;&#039; (optional) Initialise site to run specified run from. Used for running acceptance tests on different vms&lt;br /&gt;
# &#039;&#039;&#039;--torun&#039;&#039;&#039; (optional) Initialise site to run specified run till. Used for running acceptance tests on different vms&lt;br /&gt;
# &#039;&#039;&#039;-o or --optimize-runs&#039;&#039;&#039; (optional) This option will split features with specified tags in all parallel runs, so they are executed first when parallel run gets executed.&lt;br /&gt;
# &#039;&#039;&#039;-a or --add-core-features-to-theme&#039;&#039;&#039; (optional) Since Moodle 3.2. Use this option to add all core features to specified theme&#039;s (comma separated list of themes)&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Below command will initialise moodle to run 2 parallel tests.&lt;br /&gt;
php admin/tool/behat/cli/init.php --parallel=2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Step 2: Running acceptance test environment ==&lt;br /&gt;
=== Single run ===&lt;br /&gt;
Run either of the following commands. For more options &#039;&#039;&#039;vendor/bin/behat --help&#039;&#039;&#039; or http://docs.behat.org/guides/6.cli.html&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
vendor/bin/behat --config /path/to/your/CFG_behat_dataroot/behatrun/behat/behat.yml&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/run.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parallel runs ===&lt;br /&gt;
For running parallel runs, use following command&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/run.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Following optional options are available for custom run:&lt;br /&gt;
# &#039;&#039;&#039;--feature&#039;&#039;&#039; Only execute specified feature file (Absolute path of feature file).&lt;br /&gt;
# &#039;&#039;&#039;--suite&#039;&#039;&#039; Features for specified theme will be executed.&lt;br /&gt;
# &#039;&#039;&#039;--replace&#039;&#039;&#039; Replace args string with run process number, useful for output and reruns.&lt;br /&gt;
# &#039;&#039;&#039;--fromrun&#039;&#039;&#039; Execute run starting from (Used for parallel runs on different vms)&lt;br /&gt;
# &#039;&#039;&#039;--torun&#039;&#039;&#039; Execute run till (Used for parallel runs on different vms)&lt;br /&gt;
# &#039;&#039;&#039;-a or --add-core-features-to-theme&#039;&#039;&#039; (optional) Since Moodle 3.2. Use this option to add all core features to specified theme&#039;s (comma separated list)&lt;br /&gt;
# Behat options can be passed for filtering features/scenarios:&lt;br /&gt;
#* In case you don&#039;t want to run Javascript tests, use the Behat tags option to skip them, &#039;&#039;&#039;--tags=&amp;quot;~@javascript&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* In case you want to run specific scenario, use the Behat name option to run it, &#039;&#039;&#039;--name=&amp;quot;Filter user accounts by role and cohort&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* In case you want to run specific feature file, use the Behat feature option to run it, &#039;&#039;&#039;--feature=&amp;quot;/PATH/TO/MOODLE/admin/tests/behat/filter_users.feature&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Common options for running tests ===&lt;br /&gt;
==== Tests filters ====&lt;br /&gt;
With the &#039;&#039;&#039;--tags&#039;&#039;&#039; or the &#039;&#039;&#039;-name&#039;&#039;&#039; Behat options you can filter which tests are going to run or which ones are going to be skipped. There are a few tags that you might be interested in:&lt;br /&gt;
* &#039;&#039;&#039;@javascript&#039;&#039;&#039;: All the tests that runs in a browser using Javascript; they require Selenium to be running, otherwise an exception will be thrown.&lt;br /&gt;
* &#039;&#039;&#039;@_file_upload&#039;&#039;&#039;: All the tests that involves file uploading or any OS feature that is not 100% part of the browser. They should only be executed when Selenium is running in the same machine where the tests are running.&lt;br /&gt;
* &#039;&#039;&#039;@_alert&#039;&#039;&#039;: All the tests that involves Javascript dialogs (alerts, confirms...) are using a feature that is OS-dependant and out of the browser scope, so they should be tag appropriately as not all browsers manage them properly.&lt;br /&gt;
* &#039;&#039;&#039;@_switch_window&#039;&#039;&#039;: All the tests that are using the &#039;&#039;&#039;I switch to &amp;quot;NAME&amp;quot; window&#039;&#039;&#039; step should be tagged as not all browsers manage them properly.&lt;br /&gt;
* &#039;&#039;&#039;@_switch_iframe&#039;&#039;&#039;: All the tests that are using the &#039;&#039;&#039;I switch to &amp;quot;NAME&amp;quot; window&#039;&#039;&#039; steps should be tagged as it is an advanced feature and some browsers may have problems dealing with them&lt;br /&gt;
* &#039;&#039;&#039;@_cross_browser&#039;&#039;&#039;: All the tests that should run against multiple combinations of browsers + OS in a regular basis. The features that are sensitive to different combinations of OS and browsers should be tagges as @_cross_browser.&lt;br /&gt;
* &#039;&#039;&#039;@componentname&#039;&#039;&#039;: Moodle features uses the [https://docs.moodle.org/dev/Frankenstyle Frankenstyle] component name to tag the features according to the Moodle subsystem they belong to.&lt;br /&gt;
&lt;br /&gt;
==== Output formats ====&lt;br /&gt;
Since Moodle 3.1 option for output is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
--format=pretty --out=/path/to/pretty.txt --format=moodle_progress --out=std&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Before Moodle 3.1 option for output was:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
--format=&#039;moodle_progress,pretty&#039; --out=&#039;,/path/to/pretty.txt&#039;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Following output formats are supported:&lt;br /&gt;
# &#039;&#039;&#039;progress&#039;&#039;&#039;: Prints one character per step.&lt;br /&gt;
# &#039;&#039;&#039;pretty&#039;&#039;&#039;: Prints the feature as is.&lt;br /&gt;
# &#039;&#039;&#039;junit&#039;&#039;&#039;: Outputs the failures in JUnit compatible files.&lt;br /&gt;
# &#039;&#039;&#039;moodle_progress&#039;&#039;&#039;: Prints Moodle branch information and dots for each step.&lt;br /&gt;
# &#039;&#039;&#039;moodle_list&#039;&#039;&#039;: List all scenarios.&lt;br /&gt;
# &#039;&#039;&#039;moodle_stepcount&#039;&#039;&#039;: List all features with total steps in each feature file. Used for parallel run.&lt;br /&gt;
# &#039;&#039;&#039;moodle_screenshot&#039;&#039;&#039;: (since Moodle 3.1) Take screenshot and core dump of each step. With following options you can dump either or both.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;image&amp;quot;}&#039;**: will dump image only&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html&amp;quot;}&#039;**: will dump html only.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html,image&amp;quot;}&#039;**: will dump both.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html&amp;quot;, &amp;quot;dir_permissions&amp;quot;: &amp;quot;0777&amp;quot;}&#039;**&lt;br /&gt;
If you want to see the failures immediately (rather than waiting ~3 hours for all the tests to finish) then either use the -v option to output a bit more information, or change the output format using --format. Format &#039;pretty&#039; (&#039;&#039;&#039;-f pretty&#039;&#039;&#039;) is sufficient for most cases, as it outputs each step outcomes in the command line making easier to see the progress.&lt;br /&gt;
&lt;br /&gt;
== Advance usage ==&lt;br /&gt;
=== Rerun failed scenarios ===&lt;br /&gt;
With slow systems or parallel run you might see some random failures, to rerun only failed scenarios (to eliminate random failures), use --rerun option&lt;br /&gt;
# &#039;&#039;&#039;Single run:&#039;&#039;&#039; --run=&amp;quot;absolute_path_to_empty_file&amp;quot; (Behat will record failed scenarios in this file, and when run again only failed scenarios will be run)&lt;br /&gt;
# &#039;&#039;&#039;Parallel run:&#039;&#039;&#039; --rerun=&amp;quot;absolute_path_to_empty_file_{runprocess}.txt --replace=&amp;quot;{runprocess}&amp;quot; ({runprocess} will be replaced with the process number for recording fails in the specific run process).&lt;br /&gt;
&#039;&#039;&#039;Since Moodle 3.1 --rerun option don&#039;t accept any value, as it is handled internally by behat&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Running behat with specified theme (Since Moodle 3.2) ===&lt;br /&gt;
You can run behat with any theme installed. To execute behat with specified theme use &#039;&#039;&#039;--suite={THEME_NAME}&#039;&#039;&#039; option, while running behat. By default the features in theme behat folder will be executed for the suite. But if you want to run all core features with the specific theme then initialise acceptance test with -a option. For example, &#039;&#039;&#039;-a {THEME_NAME}&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Override behat core context for theme suite ====&lt;br /&gt;
To override behat step definitions so as to run behat with specified theme, you should create a contexts within &#039;&#039;&#039;/theme/{MYTHEME}/tests/behat/&#039;&#039;&#039; with prefix behat_theme_{MYTHEME}_ and suffixed with the context being overridden. For example, if you want to override behat_mod_forum context, then you should create a class /theme/{MYTHEME}/tests/behat/mod_forum/behat_theme_{MYTHEME}_behat_mod_forum.php&lt;br /&gt;
&lt;br /&gt;
==== Blacklist behat context or features to run in theme suite ====&lt;br /&gt;
To blacklist contexts/ features to be executed by theme suite you should create a /theme/{MYTHEME}/tests/behat/blacklist.json file with following format. Following will not use step_definitions from  behat_grade and behat_navigation while running theme suite. Also, scenarios in auth/tests/behat/login.feature and grade/tests/behat/grade_hidden_items.feature won&#039;t be executed with theme suite.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;contexts&amp;quot;: [&lt;br /&gt;
    &amp;quot;behat_grade&amp;quot;,&lt;br /&gt;
    &amp;quot;behat_navigation&amp;quot;,&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;features&amp;quot;: [&lt;br /&gt;
    &amp;quot;auth/tests/behat/login.feature&amp;quot;,&lt;br /&gt;
    &amp;quot;grade/tests/behat/grade_hidden_items.feature&amp;quot;,&lt;br /&gt;
   ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Override core behat selectors ====&lt;br /&gt;
To override behat selectors in specific theme, you should create a class behat_theme_{MYTHEME}_behat_selectors in /theme/{MYTHEME}/tests/behat/behat_theme_{MYTHEME}_behat_selectors.php extending behat_selectors.&lt;br /&gt;
&lt;br /&gt;
=== Use php built in web server ===&lt;br /&gt;
You can use php built-in-web server for executing behat runs. To do so:&lt;br /&gt;
# Open a command line interface and &#039;&#039;&#039;cd /to/your/moodle/dirroot&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;php -S localhost:8000&#039;&#039;&#039; (This is the test site URL that moodle uses by default, if you want to use another one you can override it in config.php with $CFG-&amp;gt;behat_wwwroot attribute; more info in https://docs.moodle.org/dev/Acceptance_testing#Advanced_usage or config-dist.php)&lt;br /&gt;
# Update $CFG-&amp;gt;behat_wwwroot = localhost:8000; in config.php&lt;br /&gt;
&lt;br /&gt;
=== Define custom options for parallel runs ===&lt;br /&gt;
You can set following custom config options for parallel runs via $CFG-&amp;gt;behat_parallel_run. It&#039;s an array of options where 1st array is for 1st run and so on.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
       array (&lt;br /&gt;
           &#039;dbtype&#039; =&amp;gt; &#039;mysqli&#039;,&lt;br /&gt;
           &#039;dblibrary&#039; =&amp;gt; &#039;native&#039;,&lt;br /&gt;
           &#039;dbhost&#039; =&amp;gt; &#039;localhost&#039;,&lt;br /&gt;
           &#039;dbname&#039; =&amp;gt; &#039;moodletest&#039;,&lt;br /&gt;
           &#039;dbuser&#039; =&amp;gt; &#039;moodle&#039;,&lt;br /&gt;
           &#039;dbpass&#039; =&amp;gt; &#039;moodle&#039;,&lt;br /&gt;
           &#039;behat_prefix&#039; =&amp;gt; &#039;mdl_&#039;,&lt;br /&gt;
           &#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4444/wd/hub&#039;,&lt;br /&gt;
           &#039;behat_wwwroot&#039; =&amp;gt; &#039;http://127.0.0.1/moodle&#039;,&lt;br /&gt;
           &#039;behat_dataroot&#039; =&amp;gt; &#039;/home/example/bht_moodledata&#039;&lt;br /&gt;
       )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To set different selenium servers for parallel runs, you can use following. NOTE: Running parallel (headless) runs on different selenium servers avoid random focus failures.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    $CFG-&amp;gt;behat_parallel_run = array (&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4444/wd/hub&#039;),&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4445/wd/hub&#039;),&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4446/wd/hub&#039;),&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running acceptance tests with different browser ===&lt;br /&gt;
By default behat will run with Firefox browser through Selenium. By adding the following code to your config.php you can change the selected browser that is run when behat is invoked.  You will need to run php admin/tool/behat/cli/init.php for changes to take effect. Then use --profile=&#039;chrome&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;behat_profiles = array(&lt;br /&gt;
   &#039;chrome&#039; =&amp;gt; array(&lt;br /&gt;
       &#039;browser&#039; =&amp;gt; &#039;chrome&#039;,&lt;br /&gt;
       &#039;tags&#039; =&amp;gt; &#039;@javascript&#039;,&lt;br /&gt;
   )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Acceptance_testing/Browsers|More info about alternative browsers]]&lt;br /&gt;
&lt;br /&gt;
=== Start multiple selenium servers ===&lt;br /&gt;
From command line Start selenium servers at different ports (say 4444, 4445, 4446 for 3 parallel runs)&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4444 &amp;amp;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4445 &amp;amp;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4446&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using Docker to start selenium server ===&lt;br /&gt;
==== What is Docker ====&lt;br /&gt;
Docker is a app container,  it&#039;s a kind of virtual machine, but only for one app, service,  so you can download&lt;br /&gt;
a docker image and run a selenium server without worry in how to configure selenium in your machine, one for chrome, others for firefox, you either don&#039;t need to install the browsers in your machine&lt;br /&gt;
To install docker follow this link; https://docs.docker.com/engine/installation/&lt;br /&gt;
&lt;br /&gt;
==== Selenium docker images ====&lt;br /&gt;
There is many docker images available,  for many browser, the complete list is in https://hub.docker.com/u/selenium/&lt;br /&gt;
for moodle you can use standalone version.&lt;br /&gt;
You can download  specific selenium version too,  for example,  for firefox,  moodle recommend selenium 2.53.1, see: [https://docs.moodle.org/dev/Acceptance_testing/Browsers/Working_combinations_of_OS%2BBrowser%2Bselenium What version do I need?]&lt;br /&gt;
&lt;br /&gt;
so  the command will be:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
docker run -d -p4444:4444 selenium/standalone-firefox:2.53.1-beryllium&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
to see all available version click in tags.   For firefox you can find at: https://hub.docker.com/r/selenium/standalone-firefox/tags/&lt;br /&gt;
&lt;br /&gt;
==== Change config.php file ====&lt;br /&gt;
In config.php file you must change the $CFG-&amp;gt;behat_wwwroot=   to your network card (NIC) ip address,  you can&#039;t use &lt;br /&gt;
localhost , 127.0.0.1, ...  or selenium docker server  will fail&lt;br /&gt;
&lt;br /&gt;
== NOTE ==&lt;br /&gt;
# Start the Selenium server (in case you want to run tests that involves Javascript)&lt;br /&gt;
#* (See http://www.installationpage.com/selenium/how-to-run-selenium-headless-firefox-in-ubuntu/ for running &#039;headless&#039; Firefox and xvfm in a server environment)&lt;br /&gt;
#* Open another command line interface and &#039;&#039;&#039;java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Trouble shooting ===&lt;br /&gt;
=== New step definitions or features are not executed === &lt;br /&gt;
If you are adding new tests or steps definitions update the tests list&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/util.php --enable&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039; For parallel runs, all options for initialising parallel runs are valid &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Tests are failing ===&lt;br /&gt;
If you followed all the steps and you receive an unknown weird error probably your system&#039;s Firefox version is not compatible with the Selenium version you are running.  Please refer Working combinations to ensure you have correct [[Acceptance_testing/Browsers#Working_combinations_of_OS.2BBrowser.2Bselenium]] of them to run acceptance test.&lt;br /&gt;
&lt;br /&gt;
=== Disable acceptance test environment ===&lt;br /&gt;
if you want to prevent access to test environment&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/util.php --disable&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that if you have the HTTP_PROXY environment variable set, which you may have had to do to run composer, then you also need to set NO_PROXY=localhost.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== External links ==&lt;br /&gt;
* Vagrant profile with Moodle and Behat preconfigured: https://github.com/mackensen/moodle-hat&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Running_acceptance_test&amp;diff=52225</id>
		<title>Running acceptance test</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Running_acceptance_test&amp;diff=52225"/>
		<updated>2017-05-04T08:01:33Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Prerequisite ==&lt;br /&gt;
Before initializing acceptance test environment for running behat, you should ensure:&lt;br /&gt;
# [[Acceptance_testing#Requirements Meet min. system requirements for running tests]]&lt;br /&gt;
# [[Acceptance_testing#Installation Have set min. config variable in config.php for behat]]&lt;br /&gt;
# [[Acceptance_testing#Installation Downloaded composer dependencies]]&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
Acceptance tests (also known as behat), use [http://www.seleniumhq.org/download/ Selenium server] and can be run as:&lt;br /&gt;
# &#039;&#039;&#039;Single run:&#039;&#039;&#039; In single run, only one behat run is executed. So all features are executed in this single run.&lt;br /&gt;
# &#039;&#039;&#039;Parallel runs:&#039;&#039;&#039; (Since Moodle 3.0) Parallel runs allow dev&#039;s to execute multiple behat runs together. This was introduced to get acceptance tests results faster. To achieve this:&lt;br /&gt;
#* Features are divided between multiple behat runs&lt;br /&gt;
#* Symlinks behatrun{x} (x being the run process number), are created pointing to moodle directory, so site for run 1 is accessible via https://localhost/moodle/behatrun1&lt;br /&gt;
#* Process number is included as suffix to $CFG-&amp;gt;behat_prefix.&lt;br /&gt;
#* Process number is suffixed to $CFG-&amp;gt;behat_dataroot.&lt;br /&gt;
&lt;br /&gt;
== Step 1: Initialise acceptance test environment ==&lt;br /&gt;
Before running acceptance tests, environment needs to be initialised for acceptance testing.&lt;br /&gt;
&lt;br /&gt;
=== Single run ===&lt;br /&gt;
For initialising acceptance tests for single run, above command is sufficient.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/init.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parallel runs ===&lt;br /&gt;
For initialising acceptance tests for parallel runs, you can use one of the following options&lt;br /&gt;
# &#039;&#039;&#039;-j or --parallel&#039;&#039;&#039; (required) Number of parallel behat run to initialise&lt;br /&gt;
# &#039;&#039;&#039;-m or --maxruns&#039;&#039;&#039;  (optional) Max parallel site which should be initialised at one time. If your system is slow, then you can initialise sites in chucks.&lt;br /&gt;
# &#039;&#039;&#039;--fromrun&#039;&#039;&#039; (optional) Initialise site to run specified run from. Used for running acceptance tests on different vms&lt;br /&gt;
# &#039;&#039;&#039;--torun&#039;&#039;&#039; (optional) Initialise site to run specified run till. Used for running acceptance tests on different vms&lt;br /&gt;
# &#039;&#039;&#039;-o or --optimize-runs&#039;&#039;&#039; (optional) This option will split features with specified tags in all parallel runs, so they are executed first when parallel run gets executed.&lt;br /&gt;
# &#039;&#039;&#039;-a or --add-core-features-to-theme&#039;&#039;&#039; (optional) Since Moodle 3.2. Use this option to add all core features to specified theme&#039;s (comma separated list of themes)&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Below command will initialise moodle to run 2 parallel tests.&lt;br /&gt;
php admin/tool/behat/cli/init.php --parallel=2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Step 2: Running acceptance test environment ==&lt;br /&gt;
=== Single run ===&lt;br /&gt;
Run either of the following commands. For more options &#039;&#039;&#039;vendor/bin/behat --help&#039;&#039;&#039; or http://docs.behat.org/guides/6.cli.html&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
vendor/bin/behat --config /path/to/your/CFG_behat_dataroot/behatrun/behat/behat.yml&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/run.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Parallel runs ===&lt;br /&gt;
For running parallel runs, use following command&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/run.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Following optional options are available for custom run:&lt;br /&gt;
# &#039;&#039;&#039;--feature&#039;&#039;&#039; Only execute specified feature file (Absolute path of feature file).&lt;br /&gt;
# &#039;&#039;&#039;--suite&#039;&#039;&#039; Features for specified theme will be executed.&lt;br /&gt;
# &#039;&#039;&#039;--replace&#039;&#039;&#039; Replace args string with run process number, useful for output and reruns.&lt;br /&gt;
# &#039;&#039;&#039;--fromrun&#039;&#039;&#039; Execute run starting from (Used for parallel runs on different vms)&lt;br /&gt;
# &#039;&#039;&#039;--torun&#039;&#039;&#039; Execute run till (Used for parallel runs on different vms)&lt;br /&gt;
# &#039;&#039;&#039;-a or --add-core-features-to-theme&#039;&#039;&#039; (optional) Since Moodle 3.2. Use this option to add all core features to specified theme&#039;s (comma separated list)&lt;br /&gt;
# Behat options can be passed for filtering features/scenarios:&lt;br /&gt;
#* In case you don&#039;t want to run Javascript tests, use the Behat tags option to skip them, &#039;&#039;&#039;--tags=&amp;quot;~@javascript&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* In case you want to run specific scenario, use the Behat name option to run it, &#039;&#039;&#039;--name=&amp;quot;Filter user accounts by role and cohort&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
#* In case you want to run specific feature file, use the Behat feature option to run it, &#039;&#039;&#039;--feature=&amp;quot;/PATH/TO/MOODLE/admin/tests/behat/filter_users.feature&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Common options for running tests ===&lt;br /&gt;
==== Tests filters ====&lt;br /&gt;
With the &#039;&#039;&#039;--tags&#039;&#039;&#039; or the &#039;&#039;&#039;-name&#039;&#039;&#039; Behat options you can filter which tests are going to run or which ones are going to be skipped. There are a few tags that you might be interested in:&lt;br /&gt;
* &#039;&#039;&#039;@javascript&#039;&#039;&#039;: All the tests that runs in a browser using Javascript; they require Selenium to be running, otherwise an exception will be thrown.&lt;br /&gt;
* &#039;&#039;&#039;@_file_upload&#039;&#039;&#039;: All the tests that involves file uploading or any OS feature that is not 100% part of the browser. They should only be executed when Selenium is running in the same machine where the tests are running.&lt;br /&gt;
* &#039;&#039;&#039;@_alert&#039;&#039;&#039;: All the tests that involves Javascript dialogs (alerts, confirms...) are using a feature that is OS-dependant and out of the browser scope, so they should be tag appropriately as not all browsers manage them properly.&lt;br /&gt;
* &#039;&#039;&#039;@_switch_window&#039;&#039;&#039;: All the tests that are using the &#039;&#039;&#039;I switch to &amp;quot;NAME&amp;quot; window&#039;&#039;&#039; step should be tagged as not all browsers manage them properly.&lt;br /&gt;
* &#039;&#039;&#039;@_switch_iframe&#039;&#039;&#039;: All the tests that are using the &#039;&#039;&#039;I switch to &amp;quot;NAME&amp;quot; window&#039;&#039;&#039; steps should be tagged as it is an advanced feature and some browsers may have problems dealing with them&lt;br /&gt;
* &#039;&#039;&#039;@_cross_browser&#039;&#039;&#039;: All the tests that should run against multiple combinations of browsers + OS in a regular basis. The features that are sensitive to different combinations of OS and browsers should be tagges as @_cross_browser.&lt;br /&gt;
* &#039;&#039;&#039;@componentname&#039;&#039;&#039;: Moodle features uses the [https://docs.moodle.org/dev/Frankenstyle Frankenstyle] component name to tag the features according to the Moodle subsystem they belong to.&lt;br /&gt;
&lt;br /&gt;
==== Output formats ====&lt;br /&gt;
Since Moodle 3.1 option for output is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
--format=pretty --out=/path/to/pretty.txt --format=moodle_progress --out=std&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Before Moodle 3.1 option for output was:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
--format=&#039;moodle_progress,pretty&#039; --out=&#039;,/path/to/pretty.txt&#039;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Following output formats are supported:&lt;br /&gt;
# &#039;&#039;&#039;progress&#039;&#039;&#039;: Prints one character per step.&lt;br /&gt;
# &#039;&#039;&#039;pretty&#039;&#039;&#039;: Prints the feature as is.&lt;br /&gt;
# &#039;&#039;&#039;junit&#039;&#039;&#039;: Outputs the failures in JUnit compatible files.&lt;br /&gt;
# &#039;&#039;&#039;moodle_progress&#039;&#039;&#039;: Prints Moodle branch information and dots for each step.&lt;br /&gt;
# &#039;&#039;&#039;moodle_list&#039;&#039;&#039;: List all scenarios.&lt;br /&gt;
# &#039;&#039;&#039;moodle_stepcount&#039;&#039;&#039;: List all features with total steps in each feature file. Used for parallel run.&lt;br /&gt;
# &#039;&#039;&#039;moodle_screenshot&#039;&#039;&#039;: (since Moodle 3.1) Take screenshot and core dump of each step. With following options you can dump either or both.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;image&amp;quot;}&#039;**: will dump image only&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html&amp;quot;}&#039;**: will dump html only.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html,image&amp;quot;}&#039;**: will dump both.&lt;br /&gt;
## --format-settings &#039;{&amp;quot;formats&amp;quot;: &amp;quot;html&amp;quot;, &amp;quot;dir_permissions&amp;quot;: &amp;quot;0777&amp;quot;}&#039;**&lt;br /&gt;
If you want to see the failures immediately (rather than waiting ~3 hours for all the tests to finish) then either use the -v option to output a bit more information, or change the output format using --format. Format &#039;pretty&#039; (&#039;&#039;&#039;-f pretty&#039;&#039;&#039;) is sufficient for most cases, as it outputs each step outcomes in the command line making easier to see the progress.&lt;br /&gt;
&lt;br /&gt;
== Advance usage ==&lt;br /&gt;
=== Rerun failed scenarios ===&lt;br /&gt;
With slow systems or parallel run you might see some random failures, to rerun only failed scenarios (to eliminate random failures), use --rerun option&lt;br /&gt;
# &#039;&#039;&#039;Single run:&#039;&#039;&#039; --run=&amp;quot;absolute_path_to_empty_file&amp;quot; (Behat will record failed scenarios in this file, and when run again only failed scenarios will be run)&lt;br /&gt;
# &#039;&#039;&#039;Parallel run:&#039;&#039;&#039; --rerun=&amp;quot;absolute_path_to_empty_file_{runprocess}.txt --replace=&amp;quot;{runprocess}&amp;quot; ({runprocess} will be replaced with the process number for recording fails in the specific run process).&lt;br /&gt;
&#039;&#039;&#039;Since Moodle 3.1 --rerun option don&#039;t accept any value, as it is handled internally by behat&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Running behat with specified theme (Since Moodle 3.2) ===&lt;br /&gt;
You can run behat with any theme installed. To execute behat with specified theme use &#039;&#039;&#039;--suite={THEME_NAME}&#039;&#039;&#039; option, while running behat. By default the features in theme behat folder will be executed for the suite. But if you want to run all core features with the specific theme then initialise acceptance test with -a option. For example, &#039;&#039;&#039;-a {THEME_NAME}&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Override behat core context for theme suite ====&lt;br /&gt;
To override behat step definitions so as to run behat with specified theme, you should create a contexts within &#039;&#039;&#039;/theme/{MYTHEME}/tests/behat/&#039;&#039;&#039; with prefix behat_theme_{MYTHEME}_ and suffixed with the context being overridden. For example, if you want to override behat_mod_forum context, then you should create a class /theme/{MYTHEME}/tests/behat/mod_forum/behat_theme_{MYTHEME}_behat_mod_forum.php&lt;br /&gt;
&lt;br /&gt;
==== Blacklist behat context or features to run in theme suite ====&lt;br /&gt;
To blacklist contexts/ features to be executed by theme suite you should create a /theme/{MYTHEME}/tests/behat/blacklist.json file with following format. Following will not use step_definitions from  behat_grade and behat_navigation while running theme suite. Also, scenarios in auth/tests/behat/login.feature and grade/tests/behat/grade_hidden_items.feature won&#039;t be executed with theme suite.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;contexts&amp;quot;: [&lt;br /&gt;
    &amp;quot;behat_grade&amp;quot;,&lt;br /&gt;
    &amp;quot;behat_navigation&amp;quot;,&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;features&amp;quot;: [&lt;br /&gt;
    &amp;quot;auth/tests/behat/login.feature&amp;quot;,&lt;br /&gt;
    &amp;quot;grade/tests/behat/grade_hidden_items.feature&amp;quot;,&lt;br /&gt;
   ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Override core behat selectors ====&lt;br /&gt;
To override behat selectors in specific theme, you should create a class behat_theme_{MYTHEME}_behat_selectors in /theme/{MYTHEME}/tests/behat/behat_theme_{MYTHEME}_behat_selectors.php extending behat_selectors.&lt;br /&gt;
&lt;br /&gt;
=== Use php built in web server ===&lt;br /&gt;
You can use php built-in-web server for executing behat runs. To do so:&lt;br /&gt;
# Open a command line interface and &#039;&#039;&#039;cd /to/your/moodle/dirroot&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;php -S localhost:8000&#039;&#039;&#039; (This is the test site URL that moodle uses by default, if you want to use another one you can override it in config.php with $CFG-&amp;gt;behat_wwwroot attribute; more info in https://docs.moodle.org/dev/Acceptance_testing#Advanced_usage or config-dist.php)&lt;br /&gt;
# Update $CFG-&amp;gt;behat_wwwroot = localhost:8000; in config.php&lt;br /&gt;
&lt;br /&gt;
=== Define custom options for parallel runs ===&lt;br /&gt;
You can set following custom config options for parallel runs via $CFG-&amp;gt;behat_parallel_run. It&#039;s an array of options where 1st array is for 1st run and so on.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
       array (&lt;br /&gt;
           &#039;dbtype&#039; =&amp;gt; &#039;mysqli&#039;,&lt;br /&gt;
           &#039;dblibrary&#039; =&amp;gt; &#039;native&#039;,&lt;br /&gt;
           &#039;dbhost&#039; =&amp;gt; &#039;localhost&#039;,&lt;br /&gt;
           &#039;dbname&#039; =&amp;gt; &#039;moodletest&#039;,&lt;br /&gt;
           &#039;dbuser&#039; =&amp;gt; &#039;moodle&#039;,&lt;br /&gt;
           &#039;dbpass&#039; =&amp;gt; &#039;moodle&#039;,&lt;br /&gt;
           &#039;behat_prefix&#039; =&amp;gt; &#039;mdl_&#039;,&lt;br /&gt;
           &#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4444/wd/hub&#039;,&lt;br /&gt;
           &#039;behat_wwwroot&#039; =&amp;gt; &#039;http://127.0.0.1/moodle&#039;,&lt;br /&gt;
           &#039;behat_dataroot&#039; =&amp;gt; &#039;/home/example/bht_moodledata&#039;&lt;br /&gt;
       )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To set different selenium servers for parallel runs, you can use following. NOTE: Running parallel (headless) runs on different selenium servers avoid random focus failures.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    $CFG-&amp;gt;behat_parallel_run = array (&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4444/wd/hub&#039;),&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4445/wd/hub&#039;),&lt;br /&gt;
        array (&#039;wd_host&#039; =&amp;gt; &#039;http://127.0.0.1:4446/wd/hub&#039;),&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running acceptance tests with different browser ===&lt;br /&gt;
By default behat will run with Firefox browser through Selenium. By adding the following code to your config.php you can change the selected browser that is run when behat is invoked.  You will need to run php admin/tool/behat/cli/init.php for changes to take effect. Then use --profile=&#039;chrome&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;behat_profiles = array(&lt;br /&gt;
   &#039;chrome&#039; =&amp;gt; array(&lt;br /&gt;
       &#039;browser&#039; =&amp;gt; &#039;chrome&#039;,&lt;br /&gt;
       &#039;tags&#039; =&amp;gt; &#039;@javascript&#039;,&lt;br /&gt;
   )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
[[Acceptance_testing/Browsers|More info about alternative browsers]]&lt;br /&gt;
&lt;br /&gt;
=== Start multiple selenium servers ===&lt;br /&gt;
From command line Start selenium servers at different ports (say 4444, 4445, 4446 for 3 parallel runs)&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4444 &amp;amp;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4445 &amp;amp;&lt;br /&gt;
java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar -port 4446&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using Docker to start selenium server ===&lt;br /&gt;
==== What is Docker ====&lt;br /&gt;
Docker is a app container,  it&#039;s a kind of virtual machine, but only for one app, service,  so you can download&lt;br /&gt;
a docker image and run a selenium server without worry in how to configure selenium in your machine, one for chrome, others for firefox, you either don&#039;t need to install the browsers in your machine&lt;br /&gt;
To install docker follow this link; https://docs.docker.com/engine/installation/&lt;br /&gt;
&lt;br /&gt;
==== Selenium docker images ====&lt;br /&gt;
There is many docker images available,  for many browser, the complete list is in https://hub.docker.com/u/selenium/&lt;br /&gt;
for moodle you can use standalone version.&lt;br /&gt;
You can download  specific selenium version too,  for example,  for firefox,  moodle recommend selenium 2.53.1, see: [https://docs.moodle.org/dev/Acceptance_testing/Browsers/Working_combinations_of_OS%2BBrowser%2Bselenium What version do I need?]&lt;br /&gt;
&lt;br /&gt;
so  the command will be:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
docker run -d -p4444:4444 selenium/standalone-firefox:2.53.1-beryllium&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
to see all available version click in tags.   For firefox you can find at: https://hub.docker.com/r/selenium/standalone-firefox/tags/&lt;br /&gt;
&lt;br /&gt;
==== Change config.php file ====&lt;br /&gt;
In config.php file you must change the $CFG-&amp;gt;behat_wwwroot=   to your network card (NIC) ip address,  you can&#039;t use &lt;br /&gt;
localhost , 127.0.0.1, ...  or selenium docker server  will fail&lt;br /&gt;
&lt;br /&gt;
== NOTE ==&lt;br /&gt;
# Start the Selenium server (in case you want to run tests that involves Javascript)&lt;br /&gt;
#* (See http://www.installationpage.com/selenium/how-to-run-selenium-headless-firefox-in-ubuntu/ for running &#039;headless&#039; Firefox and xvfm in a server environment)&lt;br /&gt;
#* Open another command line interface and &#039;&#039;&#039;java -jar /path/to/your/selenium/server/selenium-server-standalone-2.NN.N.jar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Trouble shooting ===&lt;br /&gt;
=== New step definitions or features are not executed === &lt;br /&gt;
If you are adding new tests or steps definitions update the tests list&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/util.php --enable&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039; For parallel runs, all options for initialising parallel runs are valid &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Tests are failing ===&lt;br /&gt;
If you followed all the steps and you receive an unknown weird error probably your system&#039;s Firefox version is not compatible with the Selenium version you are running.  Please refer Working combinations to ensure you have correct [[Acceptance_testing/Browsers/Working_combinations_of_OS%2BBrowser%2Bselenium combination]] of them to run acceptance test.&lt;br /&gt;
&lt;br /&gt;
=== Disable acceptance test environment ===&lt;br /&gt;
if you want to prevent access to test environment&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
php admin/tool/behat/cli/util.php --disable&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that if you have the HTTP_PROXY environment variable set, which you may have had to do to run composer, then you also need to set NO_PROXY=localhost.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== External links ==&lt;br /&gt;
* Vagrant profile with Moodle and Behat preconfigured: https://github.com/mackensen/moodle-hat&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52224</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52224"/>
		<updated>2017-05-04T08:01:18Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52223</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52223"/>
		<updated>2017-05-04T08:00:32Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52222</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52222"/>
		<updated>2017-05-04T07:59:38Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: Undo revision 52221 by Poltawski (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52221</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52221"/>
		<updated>2017-05-04T07:59:16Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
= Moodle 3.3 =&lt;br /&gt;
&lt;br /&gt;
== And I follow &amp;quot;Course 1&amp;quot; ==&lt;br /&gt;
=== Summary ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Examples ===&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=== Why did this change? ===&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
= Moodle 3.2 =&lt;br /&gt;
== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ==&lt;br /&gt;
=== Summary ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Examples ===&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Why did this change? ===&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
= Moodle 3.1 =&lt;br /&gt;
== Behat migration from 2.5 to 3.x ==&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
*Running_acceptance_test&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52220</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52220"/>
		<updated>2017-05-04T07:57:37Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Behat migration from 2.5 to 3.x */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52219</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52219"/>
		<updated>2017-05-04T07:57:08Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Moodle 3.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details.&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52218</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52218"/>
		<updated>2017-05-04T07:54:26Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Moodle 3.2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52217</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=52217"/>
		<updated>2017-05-04T07:54:12Z</updated>

		<summary type="html">&lt;p&gt;Poltawski: /* Why did this change? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
==== Summary ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Examples ====&lt;br /&gt;
&amp;lt;b&amp;gt;Before:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;After:&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why did this change? ====&lt;br /&gt;
UI Changes mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
&lt;br /&gt;
== Moodle 3.1 ==&lt;/div&gt;</summary>
		<author><name>Poltawski</name></author>
	</entry>
</feed>