MOBILE-4110 behat: Clean up js calls

main
Noel De Martin 2022-06-30 13:48:43 +02:00
parent c8b16035fe
commit 52259b421f
4 changed files with 88 additions and 81 deletions

View File

@ -96,7 +96,7 @@ class behat_app extends behat_app_helper {
public function i_wait_the_app_to_restart() {
// Wait window to reload.
$this->spin(function() {
if ($this->js('window.behat.hasInitialized()')) {
if ($this->runtime_js('hasInitialized()')) {
// Behat runtime shouldn't be initialized after reload.
throw new DriverException('Window is not reloading properly.');
}
@ -114,18 +114,18 @@ class behat_app extends behat_app_helper {
* @Then /^I should( not)? find (".+")( inside the .+)? in the app$/
* @param bool $not Whether assert that the element was not found
* @param string $locator Element locator
* @param string $containerName Container name
* @param string $container Container name
*/
public function i_find_in_the_app(bool $not, string $locator, string $containerName = '') {
public function i_find_in_the_app(bool $not, string $locator, string $container = '') {
$locator = $this->parse_element_locator($locator);
if (!empty($containerName)) {
preg_match('/^ inside the (.+)$/', $containerName, $matches);
$containerName = $matches[1];
if (!empty($container)) {
preg_match('/^ inside the (.+)$/', $container, $matches);
$container = $matches[1];
}
$containerName = json_encode($containerName);
$options = json_encode(['containerName' => $container]);
$this->spin(function() use ($not, $locator, $containerName) {
$result = $this->js("return window.behat.find($locator, { containerName: $containerName });");
$this->spin(function() use ($not, $locator, $options) {
$result = $this->runtime_js("find($locator, $options)");
if ($not && $result === 'OK') {
throw new DriverException('Error, found an element that should not be found');
@ -151,7 +151,7 @@ class behat_app extends behat_app_helper {
$locator = $this->parse_element_locator($locator);
$this->spin(function() use ($locator) {
$result = $this->js("return window.behat.scrollTo($locator);");
$result = $this->runtime_js("scrollTo($locator)");
if ($result !== 'OK') {
throw new DriverException('Error finding element - ' . $result);
@ -174,7 +174,7 @@ class behat_app extends behat_app_helper {
*/
public function i_load_more_items_in_the_app(bool $not = false) {
$this->spin(function() use ($not) {
$result = $this->js('return await window.behat.loadMoreItems();');
$result = $this->runtime_js('loadMoreItems()');
if ($not && $result !== 'ERROR: All items are already loaded.') {
throw new DriverException('It should not have been possible to load more items');
@ -199,7 +199,7 @@ class behat_app extends behat_app_helper {
public function i_swipe_in_the_app(string $direction) {
$method = 'swipe' . ucwords($direction);
$this->js("window.behat.getAngularInstance('ion-content', 'CoreSwipeNavigationDirective').$method()");
$this->runtime_js("getAngularInstance('ion-content', 'CoreSwipeNavigationDirective').$method()");
$this->wait_for_pending_js();
@ -218,7 +218,7 @@ class behat_app extends behat_app_helper {
$locator = $this->parse_element_locator($locator);
$this->spin(function() use ($locator, $not) {
$result = $this->js("return window.behat.isSelected($locator);");
$result = $this->runtime_js("isSelected($locator)");
switch ($result) {
case 'YES':
@ -325,7 +325,7 @@ class behat_app extends behat_app_helper {
$this->login($username);
}
$mycoursesfound = $this->js("return window.behat.find({ text: 'My courses', selector: 'ion-tab-button'});");
$mycoursesfound = $this->runtime_js("find({ text: 'My courses', selector: 'ion-tab-button'})");
if ($mycoursesfound !== 'OK') {
// My courses not present enter from Dashboard.
@ -381,7 +381,7 @@ class behat_app extends behat_app_helper {
*/
public function i_press_the_standard_button_in_the_app(string $button) {
$this->spin(function() use ($button) {
$result = $this->js("return await window.behat.pressStandard('$button');");
$result = $this->runtime_js("pressStandard('$button')");
if ($result !== 'OK') {
throw new DriverException('Error pressing standard button - ' . $result);
@ -419,7 +419,7 @@ class behat_app extends behat_app_helper {
],
]);
$this->js("window.behat.notificationClicked($notification)");
$this->zone_js("pushNotifications.notificationClicked($notification)", true);
$this->wait_for_pending_js();
}
@ -507,7 +507,7 @@ class behat_app extends behat_app_helper {
*/
public function i_close_the_popup_in_the_app() {
$this->spin(function() {
$result = $this->js("return window.behat.closePopup();");
$result = $this->runtime_js('closePopup()');
if ($result !== 'OK') {
throw new DriverException('Error closing popup - ' . $result);
@ -545,7 +545,7 @@ class behat_app extends behat_app_helper {
$locator = $this->parse_element_locator($locator);
$this->spin(function() use ($locator) {
$result = $this->js("return await window.behat.press($locator);");
$result = $this->runtime_js("press($locator)");
if ($result !== 'OK') {
throw new DriverException('Error pressing item - ' . $result);
@ -588,7 +588,7 @@ class behat_app extends behat_app_helper {
$locator = $this->parse_element_locator($locator);
$this->spin(function() use ($not, $locator) {
$result = $this->js("return window.behat.find($locator, { onlyClickable: true });");
$result = $this->runtime_js("find($locator, { onlyClickable: true })");
if ($not && $result === 'OK') {
throw new DriverException('Error, found a clickable element that should not be found');
@ -622,14 +622,14 @@ class behat_app extends behat_app_helper {
$this->spin(function() use ($selectedtext, $selected, $locator) {
// Don't do anything if the item is already in the expected state.
$result = $this->js("return window.behat.isSelected($locator);");
$result = $this->runtime_js("isSelected($locator)");
if ($result === $selected) {
return true;
}
// Press element.
$result = $this->js("return await window.behat.press($locator);");
$result = $this->runtime_js("press($locator)");
if ($result !== 'OK') {
throw new DriverException('Error pressing element - ' . $result);
@ -638,7 +638,7 @@ class behat_app extends behat_app_helper {
// Check that it worked as expected.
$this->wait_for_pending_js();
$result = $this->js("return window.behat.isSelected($locator);");
$result = $this->runtime_js("isSelected($locator)");
switch ($result) {
case 'YES':
@ -672,7 +672,7 @@ class behat_app extends behat_app_helper {
$value = addslashes_js($value);
$this->spin(function() use ($field, $value) {
$result = $this->js("return await window.behat.setField(\"$field\", \"$value\");");
$result = $this->runtime_js("setField('$field', '$value')");
if ($result !== 'OK') {
throw new DriverException('Error setting field - ' . $result);
@ -711,7 +711,7 @@ class behat_app extends behat_app_helper {
*/
public function the_header_should_be_in_the_app(string $text) {
$this->spin(function() use ($text) {
$result = $this->js('return window.behat.getHeader();');
$result = $this->runtime_js('getHeader()');
if (substr($result, 0, 3) !== 'OK:') {
throw new DriverException('Error getting header - ' . $result);
@ -792,7 +792,7 @@ class behat_app extends behat_app_helper {
* @When I run cron tasks in the app
*/
public function i_run_cron_tasks_in_the_app() {
$this->js('await window.behat.forceSyncExecution()');
$this->zone_js('cronDelegate.forceSyncExecution()');
$this->wait_for_pending_js();
}
@ -802,7 +802,7 @@ class behat_app extends behat_app_helper {
* @When I wait loading to finish in the app
*/
public function i_wait_loading_to_finish_in_the_app() {
$this->js('await window.behat.waitLoadingToFinish()');
$this->runtime_js('waitLoadingToFinish()');
$this->wait_for_pending_js();
}
@ -824,7 +824,7 @@ class behat_app extends behat_app_helper {
$this->getSession()->switchToWindow($names[1]);
}
$this->js('window.close();');
$this->js('window.close()');
$this->getSession()->switchToWindow($names[0]);
}
@ -836,7 +836,7 @@ class behat_app extends behat_app_helper {
* @throws DriverException If the navigator.online mode is not available
*/
public function i_switch_offline_mode(string $offline) {
$this->js("window.behat.network.setForceOffline($offline);");
$this->runtime_js("network.setForceOffline($offline)");
}
}

View File

@ -313,12 +313,12 @@ class behat_app_helper extends behat_base {
try {
// Init Behat JavaScript runtime.
$initoptions = json_encode([
'skipOnBoarding' => $options['skiponboarding'] ?? true,
'configOverrides' => $this->appconfig,
]);
$initOptions = new StdClass();
$initOptions->skipOnBoarding = $options['skiponboarding'] ?? true;
$initOptions->configOverrides = $this->appconfig;
$this->js('window.behat.init(' . json_encode($initOptions) . ');');
$this->runtime_js("init($initoptions)");
} catch (Exception $error) {
throw new DriverException('Moodle App not running or not running on Automated mode.');
}
@ -456,7 +456,7 @@ class behat_app_helper extends behat_base {
$res = $this->evaluate_script("Promise.resolve($script)
.then(result => window.$promisevariable = result)
.catch(error => window.$promisevariable = 'Async code rejected: ' + error?.message);");
.catch(error => window.$promisevariable = 'Async code rejected: ' + error?.message)");
do {
if (microtime(true) - $start > $timeout) {
@ -465,15 +465,42 @@ class behat_app_helper extends behat_base {
// 0.1 seconds.
usleep(100000);
} while (!$this->evaluate_script("return '$promisevariable' in window;"));
} while (!$this->evaluate_script("'$promisevariable' in window"));
$result = $this->evaluate_script("return window.$promisevariable;");
$result = $this->evaluate_script("window.$promisevariable");
$this->evaluate_script("delete window.$promisevariable;");
$this->evaluate_script("delete window.$promisevariable");
if (is_string($result) && strrpos($result, 'Async code rejected:') === 0) {
throw new DriverException($result);
}
return $result;
}
/**
* Evaluate and execute methods from the Behat runtime.
*
* @param string $script
* @return mixed Result.
*/
protected function runtime_js(string $script) {
return $this->js("window.behat.$script");
}
/**
* Evaluate and execute methods from the Behat runtime inside the Angular zone.
*
* @param string $script
* @param bool $blocking
* @return mixed Result.
*/
protected function zone_js(string $script, bool $blocking = false) {
$blockingjson = json_encode($blocking);
return $this->runtime_js("runInZone(() => window.behat.$script, $blockingjson)");
}
/**
* Opens a custom URL for automatic login and redirect from the Moodle App (and waits to finish.)
*
@ -548,8 +575,7 @@ class behat_app_helper extends behat_base {
* @param string $successXPath The XPath of the element to lookat after navigation.
*/
protected function handle_url(string $customurl, string $successXPath = '') {
// Instead of using evaluate_async_script, we wait for the path to load.
$result = $this->js("return await window.behat.handleCustomURL('$customurl');");
$result = $this->zone_js("customUrlSchemes.handleCustomURL('$customurl')");
if ($result !== 'OK') {
throw new DriverException('Error handling url - ' . $result);

View File

@ -178,7 +178,7 @@ class performance_measure implements behat_app_listener {
* @return int Current time in milliseconds.
*/
private function now(): int {
return $this->driver->evaluateScript('Date.now();');
return $this->driver->evaluateScript('Date.now()');
}
/**

View File

@ -14,17 +14,14 @@
import { TestingBehatDomUtils } from './behat-dom';
import { TestingBehatBlocking } from './behat-blocking';
import { CoreCustomURLSchemes } from '@services/urlschemes';
import { CoreCustomURLSchemes, CoreCustomURLSchemesProvider } from '@services/urlschemes';
import { CoreLoginHelperProvider } from '@features/login/services/login-helper';
import { CoreConfig } from '@services/config';
import { EnvironmentConfig } from '@/types/config';
import { makeSingleton, NgZone } from '@singletons';
import { CoreNetwork, CoreNetworkService } from '@services/network';
import {
CorePushNotifications,
CorePushNotificationsNotificationBasicData,
} from '@features/pushnotifications/services/pushnotifications';
import { CoreCronDelegate } from '@services/cron';
import { CorePushNotifications, CorePushNotificationsProvider } from '@features/pushnotifications/services/pushnotifications';
import { CoreCronDelegate, CoreCronDelegateService } from '@services/cron';
import { CoreLoadingComponent } from '@components/loading/loading';
import { CoreComponentsRegistry } from '@singletons/components-registry';
import { CoreDom } from '@singletons/dom';
@ -40,10 +37,22 @@ export class TestingBehatRuntimeService {
protected initialized = false;
get cronDelegate(): CoreCronDelegateService {
return CoreCronDelegate.instance;
}
get customUrlSchemes(): CoreCustomURLSchemesProvider {
return CoreCustomURLSchemes.instance;
}
get network(): CoreNetworkService {
return CoreNetwork.instance;
}
get pushNotifications(): CorePushNotificationsProvider {
return CorePushNotifications.instance;
}
/**
* Init behat functions and set options like skipping onboarding.
*
@ -78,53 +87,25 @@ export class TestingBehatRuntimeService {
}
/**
* Handles a custom URL.
* Run an operation inside the angular zone and return result.
*
* @param url Url to open.
* @param operation Operation callback.
* @return OK if successful, or ERROR: followed by message.
*/
async handleCustomURL(url: string): Promise<string> {
async runInZone(operation: () => unknown, blocking: boolean = false): Promise<string> {
const blockKey = blocking && TestingBehatBlocking.block();
try {
await NgZone.run(async () => {
await CoreCustomURLSchemes.handleCustomURL(url);
});
await NgZone.run(operation);
return 'OK';
} catch (error) {
return 'ERROR: ' + error.message;
}
}
/**
* Function called when a push notification is clicked. Redirect the user to the right state.
*
* @param data Notification data.
* @return Promise resolved when done.
*/
async notificationClicked(data: CorePushNotificationsNotificationBasicData): Promise<void> {
const blockKey = TestingBehatBlocking.block();
try {
await NgZone.run(async () => {
await CorePushNotifications.notificationClicked(data);
});
} finally {
TestingBehatBlocking.unblock(blockKey);
blockKey && TestingBehatBlocking.unblock(blockKey);
}
}
/**
* Force execution of synchronization cron tasks without waiting for the scheduled time.
* Please notice that some tasks may not be executed depending on the network connection and sync settings.
*
* @return Promise resolved if all handlers are executed successfully, rejected otherwise.
*/
async forceSyncExecution(): Promise<void> {
await NgZone.run(async () => {
await CoreCronDelegate.forceSyncExecution();
});
}
/**
* Wait all controlled components to be rendered.
*