From 1815059e285848116cba2205282089dbf868cbb5 Mon Sep 17 00:00:00 2001 From: Albert Gasset Date: Fri, 30 Aug 2024 11:26:28 +0200 Subject: [PATCH 1/2] MOBILE-4616 behat: Block Behat for at least 500ms after a press --- src/testing/services/behat-blocking.ts | 12 ++++++++++++ src/testing/services/behat-runtime.ts | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/src/testing/services/behat-blocking.ts b/src/testing/services/behat-blocking.ts index b58407b0d..b56159ea4 100644 --- a/src/testing/services/behat-blocking.ts +++ b/src/testing/services/behat-blocking.ts @@ -139,6 +139,18 @@ export class TestingBehatBlockingService { this.unblock(key); } + /** + * Adds a pending key to the array, and remove it after some time. + * + * @param milliseconds Number of milliseconds to wait before the key is removed. + * @returns Promise resolved after the time has passed. + */ + async wait(milliseconds: number): Promise { + const key = this.block(); + await CoreWait.wait(milliseconds); + this.unblock(key); + } + /** * It would be really beautiful if you could detect CSS transitions and animations, that would * cover almost everything, but sadly there is no way to do this because the transitionstart diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts index c030715a6..d3c612236 100644 --- a/src/testing/services/behat-runtime.ts +++ b/src/testing/services/behat-runtime.ts @@ -219,6 +219,9 @@ export class TestingBehatRuntimeService { // Click button await TestingBehatDomUtils.pressElement(foundButton); + // Block Behat for at least 500ms, WS calls or DOM changes might not begin immediately. + TestingBehatBlocking.wait(500); + return 'OK'; } @@ -446,6 +449,9 @@ export class TestingBehatRuntimeService { await TestingBehatDomUtils.pressElement(found); + // Block Behat for at least 500ms, WS calls or DOM changes might not begin immediately. + TestingBehatBlocking.wait(500); + return 'OK'; } catch (error) { return 'ERROR: ' + error.message; From a837c9c5514b75d4ef9754948babd6db848e11fd Mon Sep 17 00:00:00 2001 From: Albert Gasset Date: Fri, 30 Aug 2024 14:13:27 +0200 Subject: [PATCH 2/2] 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;