diff --git a/lib/behat/form_field/behat_form_editor.php b/lib/behat/form_field/behat_form_editor.php index acc00513254..89ab42bd542 100644 --- a/lib/behat/form_field/behat_form_editor.php +++ b/lib/behat/form_field/behat_form_editor.php @@ -93,7 +93,60 @@ class behat_form_editor extends behat_form_textarea { * @return bool The provided value matches the field value? */ public function matches($expectedvalue) { - // A text editor may silently wrap the content in p tags (or not). Neither is an error. - return $this->text_matches($expectedvalue) || $this->text_matches('
' . $expectedvalue . '
'); + // Fetch the actual value to save fetching it multiple times. + $actualvalue = $this->get_value(); + + if ($this->text_matches($expectedvalue, $actualvalue)) { + // The text is an exact match already. + return true; + } + + if ($this->text_matches("{$expectedvalue}
", $actualvalue)) { + // A text editor may silently wrap the content in p tags. + return true; + } + + // Standardise both the expected value and the actual field value. + // We are likely dealing with HTML content, given this is an editor. + $expectedvalue = $this->standardise_html($expectedvalue); + $actualvalue = $this->standardise_html($actualvalue); + + // Note: We don't need to worry about the floats here that we care about in text_matches. + // That condition isn't relevant to the content of an editor. + if ($expectedvalue === $actualvalue) { + return true; + } + + return false; + } + + /** + * Standardises the HTML content for comparison. + * + * @param string $html The HTML content to standardise + * @return string The standardised HTML content + */ + protected function standardise_html(string $html): string { + $document = new DOMDocument(); + $errorstate = libxml_use_internal_errors(true); + + // Format the whitespace nicely. + $document->preserveWhiteSpace = false; + $document->formatOutput = true; + + // Wrap the content in a DIV element so that it is not parsed weirdly. + // Note: We must remove newlines too because DOMDocument does not do so, despite preserveWhiteSpace being false. + // Unfortunately this is slightly limited in that it will also remove newlines from content and similar.
+ $document->loadHTML(str_replace("\n", "", "{$html}"), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
+ $document->normalizeDocument();
+ libxml_clear_errors();
+ libxml_use_internal_errors($errorstate);
+
+ // Save the content of the 'div' element, removing the and tags at the start and end.
+ return trim(substr(
+ $document->saveHTML($document->getElementsByTagName('div')->item(0)),
+ 5,
+ -6
+ ));
}
}
diff --git a/lib/behat/form_field/behat_form_field.php b/lib/behat/form_field/behat_form_field.php
index c834b7bdb35..5f58d2aab1a 100644
--- a/lib/behat/form_field/behat_form_field.php
+++ b/lib/behat/form_field/behat_form_field.php
@@ -244,18 +244,21 @@ class behat_form_field implements behat_session_interface {
* Checks if the provided text matches the field value.
*
* @param string $expectedvalue
+ * @param string|null $actualvalue The actual value. If not specified, this will be fetched from $this->get_value().
* @return bool
*/
- protected function text_matches($expectedvalue) {
+ protected function text_matches($expectedvalue, ?string $actualvalue = null): bool {
+ $actualvalue = $actualvalue ?? $this->get_value();
+
// Non strict string comparison.
- if (trim($expectedvalue) == trim($this->get_value())) {
+ if (trim($expectedvalue) == trim($actualvalue)) {
return true;
}
// Do one more matching attempt for floats that are valid with current decsep in use
// (let's continue non strict comparing them as strings, but once unformatted).
$expectedfloat = unformat_float(trim($expectedvalue), true);
- $actualfloat = unformat_float(trim($this->get_value()), true);
+ $actualfloat = unformat_float(trim($actualvalue), true);
// If they aren't null or false, then we are good to be compared (basically is_numeric()).
$goodfloats = !is_null($expectedfloat) && ($expectedfloat !== false) &&
!is_null($actualfloat) && ($actualfloat !== false);
diff --git a/lib/tests/behat/behat_general.php b/lib/tests/behat/behat_general.php
index 18103b8d9ac..b2184d10ec4 100644
--- a/lib/tests/behat/behat_general.php
+++ b/lib/tests/behat/behat_general.php
@@ -1776,7 +1776,17 @@ EOF;
* @param string $keys The key, or list of keys, to type
*/
public function i_type(string $keys): void {
- behat_base::type_keys($this->getSession(), str_split($keys));
+ // Certain keys, such as the newline character, must be converted to the appropriate character code.
+ // Without this, keys will behave differently depending on the browser.
+ $keylist = array_map(function($key): string {
+ switch ($key) {
+ case '\n':
+ behat_keys::ENTER;
+ default:
+ return $key;
+ }
+ }, str_split($keys));
+ behat_base::type_keys($this->getSession(), $keylist);
}
/**