From a837c9c5514b75d4ef9754948babd6db848e11fd Mon Sep 17 00:00:00 2001 From: Albert Gasset Date: Fri, 30 Aug 2024 14:13:27 +0200 Subject: [PATCH] MOBILE-4616 behat: Fix flaky tests using relative dates Allow a difference of one minute for the base time used to calculate the timestamps of relative dates. This change prevents test errors caused by delays between setting the data with relative dates and the rules that match those dates. --- .../tests/behat/behat_app_helper.php | 19 +++++++++++++++---- src/testing/services/behat-dom.ts | 19 +++++++++++++++++-- src/testing/services/behat-runtime.ts | 2 +- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/local_moodleappbehat/tests/behat/behat_app_helper.php b/local_moodleappbehat/tests/behat/behat_app_helper.php index 45dc62741..7427a8937 100644 --- a/local_moodleappbehat/tests/behat/behat_app_helper.php +++ b/local_moodleappbehat/tests/behat/behat_app_helper.php @@ -738,25 +738,36 @@ EOF; * This function is similar to the arg_time_to_string transformation, but it allows the time to be a sub-text of the string. * * @param string $text - * @return string Transformed text. + * @return string|string[] Transformed text. */ - protected function transform_time_to_string(string $text): string { + protected function transform_time_to_string(string $text): string|array { if (!preg_match('/##(.*)##/', $text, $matches)) { // No time found, return the original text. return $text; } $timepassed = explode('##', $matches[1]); + $basetime = time(); // If not a valid time string, then just return what was passed. - if ((($timestamp = strtotime($timepassed[0])) === false)) { + if ((($timestamp = strtotime($timepassed[0], $basetime)) === false)) { return $text; } $count = count($timepassed); if ($count === 2) { // If timestamp with specified strftime format, then return formatted date string. - return str_replace($matches[0], userdate($timestamp, $timepassed[1]), $text); + $result = [str_replace($matches[0], userdate($timestamp, $timepassed[1]), $text)]; + + // If it's a relative date, allow a difference of 1 minute for the base time used to calculate the timestampt. + if ($timestamp !== strtotime($timepassed[0], 0)) { + $timestamp = strtotime($timepassed[0], $basetime - 60); + $result[] = str_replace($matches[0], userdate($timestamp, $timepassed[1]), $text); + } + + $result = array_unique($result); + + return count($result) == 1 ? $result[0] : $result; } else if ($count === 1) { return str_replace($matches[0], $timestamp, $text); } else { diff --git a/src/testing/services/behat-dom.ts b/src/testing/services/behat-dom.ts index d053e331e..94fa3e803 100644 --- a/src/testing/services/behat-dom.ts +++ b/src/testing/services/behat-dom.ts @@ -124,9 +124,13 @@ export class TestingBehatDomUtilsService { */ protected findElementsBasedOnTextWithinWithExact( container: HTMLElement, - text: string, + text: string | string[], options: TestingBehatFindOptions, ): ElementsWithExact[] { + if (Array.isArray(text)) { + return text.map((text) => this.findElementsBasedOnTextWithinWithExact(container, text, options)).flat(); + } + // Escape double quotes to prevent breaking the query selector. const escapedText = text.replace(/"/g, '\\"'); const attributesSelector = `[aria-label*="${escapedText}"], a[title*="${escapedText}"], ` + @@ -266,7 +270,7 @@ export class TestingBehatDomUtilsService { */ protected findElementsBasedOnTextWithin( container: HTMLElement, - text: string, + text: string | string[], options: TestingBehatFindOptions, ): HTMLElement[] { const elements = this.findElementsBasedOnTextWithinWithExact(container, text, options); @@ -495,6 +499,17 @@ export class TestingBehatDomUtilsService { locator: TestingBehatElementLocator, options: TestingBehatFindOptions = {}, ): HTMLElement | undefined { + if (Array.isArray(locator.text)) { + for (const text of locator.text) { + const element = this.findElementBasedOnText({ ...locator, text }); + if (element) { + return element; + } + } + + return undefined; + } + // Remove extra spaces. const treatedText = locator.text.trim().replace(/\s\s+/g, ' '); if (treatedText !== locator.text) { diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts index d3c612236..b5530f8d7 100644 --- a/src/testing/services/behat-runtime.ts +++ b/src/testing/services/behat-runtime.ts @@ -809,7 +809,7 @@ export type TestingBehatFindOptions = { }; export type TestingBehatElementLocator = { - text: string; + text: string | string[]; within?: TestingBehatElementLocator; near?: TestingBehatElementLocator; selector?: string;