Skip to content

Commit

Permalink
Merge pull request #4164 from albertgasset/MOBILE-4616
Browse files Browse the repository at this point in the history
MOBILE-4616 behat: Fix flaky tests
  • Loading branch information
crazyserver authored Sep 2, 2024
2 parents dd2ffd0 + a837c9c commit e49f10e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 7 deletions.
19 changes: 15 additions & 4 deletions local_moodleappbehat/tests/behat/behat_app_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -738,25 +738,36 @@ protected function resize_app_window(int $width = 500, int $height = 720) {
* 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 {
Expand Down
12 changes: 12 additions & 0 deletions src/testing/services/behat-blocking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
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
Expand Down
19 changes: 17 additions & 2 deletions src/testing/services/behat-dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}"], ` +
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 7 additions & 1 deletion src/testing/services/behat-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -803,7 +809,7 @@ export type TestingBehatFindOptions = {
};

export type TestingBehatElementLocator = {
text: string;
text: string | string[];
within?: TestingBehatElementLocator;
near?: TestingBehatElementLocator;
selector?: string;
Expand Down

0 comments on commit e49f10e

Please sign in to comment.