MOBILE-4110 behat: Clean up services
parent
b0ccc7bf34
commit
c8b16035fe
|
@ -46,6 +46,12 @@
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/testing/testing.module.ts",
|
||||||
|
"with": "src/testing/testing.module.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
"optimization": {
|
"optimization": {
|
||||||
"scripts": false,
|
"scripts": false,
|
||||||
"styles": true
|
"styles": true
|
||||||
|
|
|
@ -96,9 +96,8 @@ class behat_app extends behat_app_helper {
|
||||||
public function i_wait_the_app_to_restart() {
|
public function i_wait_the_app_to_restart() {
|
||||||
// Wait window to reload.
|
// Wait window to reload.
|
||||||
$this->spin(function() {
|
$this->spin(function() {
|
||||||
$result = $this->js("return !window.behat;");
|
if ($this->js('window.behat.hasInitialized()')) {
|
||||||
|
// Behat runtime shouldn't be initialized after reload.
|
||||||
if (!$result) {
|
|
||||||
throw new DriverException('Window is not reloading properly.');
|
throw new DriverException('Window is not reloading properly.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -318,7 +318,7 @@ class behat_app_helper extends behat_base {
|
||||||
$initOptions->skipOnBoarding = $options['skiponboarding'] ?? true;
|
$initOptions->skipOnBoarding = $options['skiponboarding'] ?? true;
|
||||||
$initOptions->configOverrides = $this->appconfig;
|
$initOptions->configOverrides = $this->appconfig;
|
||||||
|
|
||||||
$this->js('window.behatInit(' . json_encode($initOptions) . ');');
|
$this->js('window.behat.init(' . json_encode($initOptions) . ');');
|
||||||
} catch (Exception $error) {
|
} catch (Exception $error) {
|
||||||
throw new DriverException('Moodle App not running or not running on Automated mode.');
|
throw new DriverException('Moodle App not running or not running on Automated mode.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { IonRouterOutlet } from '@ionic/angular';
|
import { IonRouterOutlet } from '@ionic/angular';
|
||||||
import { BackButtonEvent, ScrollDetail } from '@ionic/core';
|
import { BackButtonEvent, ScrollDetail } from '@ionic/core';
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import { CoreLoginHelper } from '@features/login/services/login-helper';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { NgZone, SplashScreen, Translate } from '@singletons';
|
import { NgZone, SplashScreen, Translate } from '@singletons';
|
||||||
import { CoreNetwork } from '@services/network';
|
import { CoreNetwork } from '@services/network';
|
||||||
import { CoreApp, CoreAppProvider } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSubscriptions } from '@singletons/subscriptions';
|
import { CoreSubscriptions } from '@singletons/subscriptions';
|
||||||
|
@ -38,10 +38,6 @@ import { CorePlatform } from '@services/platform';
|
||||||
const MOODLE_VERSION_PREFIX = 'version-';
|
const MOODLE_VERSION_PREFIX = 'version-';
|
||||||
const MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
|
const MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
|
||||||
|
|
||||||
type AutomatedTestsWindow = Window & {
|
|
||||||
changeDetector?: ChangeDetectorRef;
|
|
||||||
};
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: 'app.component.html',
|
templateUrl: 'app.component.html',
|
||||||
|
@ -54,12 +50,6 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||||
protected lastUrls: Record<string, number> = {};
|
protected lastUrls: Record<string, number> = {};
|
||||||
protected lastInAppUrl?: string;
|
protected lastInAppUrl?: string;
|
||||||
|
|
||||||
constructor(changeDetector: ChangeDetectorRef) {
|
|
||||||
if (CoreAppProvider.isAutomated()) {
|
|
||||||
(window as AutomatedTestsWindow).changeDetector = changeDetector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Component being initialized.
|
||||||
*
|
*
|
||||||
|
|
|
@ -32,7 +32,7 @@ import { JitCompilerFactory } from '@angular/platform-browser-dynamic';
|
||||||
import { CoreCronDelegate } from '@services/cron';
|
import { CoreCronDelegate } from '@services/cron';
|
||||||
import { CoreSiteInfoCronHandler } from '@services/handlers/site-info-cron';
|
import { CoreSiteInfoCronHandler } from '@services/handlers/site-info-cron';
|
||||||
import { moodleTransitionAnimation } from '@classes/page-transition';
|
import { moodleTransitionAnimation } from '@classes/page-transition';
|
||||||
import { BehatTestingModule } from '@/testing/behat-testing.module';
|
import { TestingModule } from '@/testing/testing.module';
|
||||||
|
|
||||||
// For translate loader. AoT requires an exported function for factories.
|
// For translate loader. AoT requires an exported function for factories.
|
||||||
export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
|
export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
|
||||||
|
@ -60,7 +60,7 @@ export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
CoreModule,
|
CoreModule,
|
||||||
AddonsModule,
|
AddonsModule,
|
||||||
BehatTestingModule,
|
TestingModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
|
||||||
import { CoreAppProvider } from '@services/app';
|
|
||||||
import { TestingBehatBlockingService } from './services/behat-blocking';
|
|
||||||
import { BehatTestsWindow, TestingBehatRuntime } from './services/behat-runtime';
|
|
||||||
|
|
||||||
function initializeBehatTestsWindow(window: BehatTestsWindow) {
|
|
||||||
// Make functions publicly available for Behat to call.
|
|
||||||
window.behatInit = TestingBehatRuntime.init;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
providers:
|
|
||||||
CoreAppProvider.isAutomated()
|
|
||||||
? [
|
|
||||||
{ provide: APP_INITIALIZER, multi: true, useValue: () => initializeBehatTestsWindow(window) },
|
|
||||||
TestingBehatBlockingService,
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
})
|
|
||||||
export class BehatTestingModule {}
|
|
|
@ -12,9 +12,10 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
import { CorePromisedValue } from '@classes/promised-value';
|
import { CorePromisedValue } from '@classes/promised-value';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { NgZone } from '@singletons';
|
import { makeSingleton, NgZone } from '@singletons';
|
||||||
import { TestingBehatElementLocator, TestingBehatFindOptions } from './behat-runtime';
|
import { TestingBehatElementLocator, TestingBehatFindOptions } from './behat-runtime';
|
||||||
|
|
||||||
// Containers that block containers behind them.
|
// Containers that block containers behind them.
|
||||||
|
@ -23,7 +24,8 @@ const blockingContainers = ['ION-ALERT', 'ION-POPOVER', 'ION-ACTION-SHEET', 'COR
|
||||||
/**
|
/**
|
||||||
* Behat Dom Utils helper functions.
|
* Behat Dom Utils helper functions.
|
||||||
*/
|
*/
|
||||||
export class TestingBehatDomUtils {
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class TestingBehatDomUtilsService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if an element is visible.
|
* Check if an element is visible.
|
||||||
|
@ -32,7 +34,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param container Container.
|
* @param container Container.
|
||||||
* @return Whether the element is visible or not.
|
* @return Whether the element is visible or not.
|
||||||
*/
|
*/
|
||||||
static isElementVisible(element: HTMLElement, container: HTMLElement): boolean {
|
isElementVisible(element: HTMLElement, container: HTMLElement): boolean {
|
||||||
if (element.getAttribute('aria-hidden') === 'true' || getComputedStyle(element).display === 'none') {
|
if (element.getAttribute('aria-hidden') === 'true' || getComputedStyle(element).display === 'none') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +58,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param container Container.
|
* @param container Container.
|
||||||
* @return Whether the element is selected or not.
|
* @return Whether the element is selected or not.
|
||||||
*/
|
*/
|
||||||
static isElementSelected(element: HTMLElement, container: HTMLElement): boolean {
|
isElementSelected(element: HTMLElement, container: HTMLElement): boolean {
|
||||||
const ariaCurrent = element.getAttribute('aria-current');
|
const ariaCurrent = element.getAttribute('aria-current');
|
||||||
if (
|
if (
|
||||||
(ariaCurrent && ariaCurrent !== 'false') ||
|
(ariaCurrent && ariaCurrent !== 'false') ||
|
||||||
|
@ -82,7 +84,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param options Search options.
|
* @param options Search options.
|
||||||
* @return Elements containing the given text with exact boolean.
|
* @return Elements containing the given text with exact boolean.
|
||||||
*/
|
*/
|
||||||
protected static findElementsBasedOnTextWithinWithExact(
|
protected findElementsBasedOnTextWithinWithExact(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
text: string,
|
text: string,
|
||||||
options: TestingBehatFindOptions,
|
options: TestingBehatFindOptions,
|
||||||
|
@ -187,7 +189,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param text Text to check.
|
* @param text Text to check.
|
||||||
* @return If text matches any of the label attributes.
|
* @return If text matches any of the label attributes.
|
||||||
*/
|
*/
|
||||||
protected static checkElementLabel(element: HTMLElement, text: string): boolean {
|
protected checkElementLabel(element: HTMLElement, text: string): boolean {
|
||||||
return element.title === text ||
|
return element.title === text ||
|
||||||
element.getAttribute('alt') === text ||
|
element.getAttribute('alt') === text ||
|
||||||
element.getAttribute('aria-label') === text ||
|
element.getAttribute('aria-label') === text ||
|
||||||
|
@ -202,7 +204,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param options Search options.
|
* @param options Search options.
|
||||||
* @return Elements containing the given text.
|
* @return Elements containing the given text.
|
||||||
*/
|
*/
|
||||||
protected static findElementsBasedOnTextWithin(
|
protected findElementsBasedOnTextWithin(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
text: string,
|
text: string,
|
||||||
options: TestingBehatFindOptions,
|
options: TestingBehatFindOptions,
|
||||||
|
@ -223,7 +225,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param elements Elements list.
|
* @param elements Elements list.
|
||||||
* @return Top ancestors.
|
* @return Top ancestors.
|
||||||
*/
|
*/
|
||||||
protected static getTopAncestors(elements: HTMLElement[]): HTMLElement[] {
|
protected getTopAncestors(elements: HTMLElement[]): HTMLElement[] {
|
||||||
const uniqueElements = new Set(elements);
|
const uniqueElements = new Set(elements);
|
||||||
|
|
||||||
for (const element of uniqueElements) {
|
for (const element of uniqueElements) {
|
||||||
|
@ -247,7 +249,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param element Element.
|
* @param element Element.
|
||||||
* @return Parent element.
|
* @return Parent element.
|
||||||
*/
|
*/
|
||||||
protected static getParentElement(element: HTMLElement): HTMLElement | null {
|
protected getParentElement(element: HTMLElement): HTMLElement | null {
|
||||||
return element.parentElement ||
|
return element.parentElement ||
|
||||||
(element.getRootNode() && (element.getRootNode() as ShadowRoot).host as HTMLElement) ||
|
(element.getRootNode() && (element.getRootNode() as ShadowRoot).host as HTMLElement) ||
|
||||||
null;
|
null;
|
||||||
|
@ -261,7 +263,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param container Topmost container to search within.
|
* @param container Topmost container to search within.
|
||||||
* @return Closest matching element.
|
* @return Closest matching element.
|
||||||
*/
|
*/
|
||||||
protected static getClosestMatching(element: HTMLElement, selector: string, container: HTMLElement | null): HTMLElement | null {
|
protected getClosestMatching(element: HTMLElement, selector: string, container: HTMLElement | null): HTMLElement | null {
|
||||||
if (element.matches(selector)) {
|
if (element.matches(selector)) {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
@ -279,7 +281,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param containerName Whether to search inside the a container name.
|
* @param containerName Whether to search inside the a container name.
|
||||||
* @return Found top container elements.
|
* @return Found top container elements.
|
||||||
*/
|
*/
|
||||||
protected static getCurrentTopContainerElements(containerName: string): HTMLElement[] {
|
protected getCurrentTopContainerElements(containerName: string): HTMLElement[] {
|
||||||
const topContainers: HTMLElement[] = [];
|
const topContainers: HTMLElement[] = [];
|
||||||
let containers = Array.from(document.querySelectorAll<HTMLElement>([
|
let containers = Array.from(document.querySelectorAll<HTMLElement>([
|
||||||
'ion-alert.hydrated',
|
'ion-alert.hydrated',
|
||||||
|
@ -345,7 +347,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param options Search options.
|
* @param options Search options.
|
||||||
* @return First found element.
|
* @return First found element.
|
||||||
*/
|
*/
|
||||||
static findElementBasedOnText(
|
findElementBasedOnText(
|
||||||
locator: TestingBehatElementLocator,
|
locator: TestingBehatElementLocator,
|
||||||
options: TestingBehatFindOptions,
|
options: TestingBehatFindOptions,
|
||||||
): HTMLElement {
|
): HTMLElement {
|
||||||
|
@ -359,7 +361,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param options Search options.
|
* @param options Search options.
|
||||||
* @return Found elements
|
* @return Found elements
|
||||||
*/
|
*/
|
||||||
protected static findElementsBasedOnText(
|
protected findElementsBasedOnText(
|
||||||
locator: TestingBehatElementLocator,
|
locator: TestingBehatElementLocator,
|
||||||
options: TestingBehatFindOptions,
|
options: TestingBehatFindOptions,
|
||||||
): HTMLElement[] {
|
): HTMLElement[] {
|
||||||
|
@ -384,7 +386,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param options Search options.
|
* @param options Search options.
|
||||||
* @return Found elements
|
* @return Found elements
|
||||||
*/
|
*/
|
||||||
protected static findElementsBasedOnTextInContainer(
|
protected findElementsBasedOnTextInContainer(
|
||||||
locator: TestingBehatElementLocator,
|
locator: TestingBehatElementLocator,
|
||||||
topContainer: HTMLElement,
|
topContainer: HTMLElement,
|
||||||
options: TestingBehatFindOptions,
|
options: TestingBehatFindOptions,
|
||||||
|
@ -465,7 +467,7 @@ export class TestingBehatDomUtils {
|
||||||
*
|
*
|
||||||
* @param element Element.
|
* @param element Element.
|
||||||
*/
|
*/
|
||||||
protected static async ensureElementVisible(element: HTMLElement): Promise<DOMRect> {
|
protected async ensureElementVisible(element: HTMLElement): Promise<DOMRect> {
|
||||||
const initialRect = element.getBoundingClientRect();
|
const initialRect = element.getBoundingClientRect();
|
||||||
|
|
||||||
element.scrollIntoView(false);
|
element.scrollIntoView(false);
|
||||||
|
@ -494,7 +496,7 @@ export class TestingBehatDomUtils {
|
||||||
*
|
*
|
||||||
* @param element Element to press.
|
* @param element Element to press.
|
||||||
*/
|
*/
|
||||||
static async pressElement(element: HTMLElement): Promise<void> {
|
async pressElement(element: HTMLElement): Promise<void> {
|
||||||
await NgZone.run(async () => {
|
await NgZone.run(async () => {
|
||||||
const promise = new CorePromisedValue<void>();
|
const promise = new CorePromisedValue<void>();
|
||||||
|
|
||||||
|
@ -539,7 +541,7 @@ export class TestingBehatDomUtils {
|
||||||
* @param element HTML to set.
|
* @param element HTML to set.
|
||||||
* @param value Value to be set.
|
* @param value Value to be set.
|
||||||
*/
|
*/
|
||||||
static async setElementValue(element: HTMLInputElement | HTMLElement, value: string): Promise<void> {
|
async setElementValue(element: HTMLInputElement | HTMLElement, value: string): Promise<void> {
|
||||||
await NgZone.run(async () => {
|
await NgZone.run(async () => {
|
||||||
const promise = new CorePromisedValue<void>();
|
const promise = new CorePromisedValue<void>();
|
||||||
|
|
||||||
|
@ -604,6 +606,8 @@ export class TestingBehatDomUtils {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const TestingBehatDomUtils = makeSingleton(TestingBehatDomUtilsService);
|
||||||
|
|
||||||
type ElementsWithExact = {
|
type ElementsWithExact = {
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
exact: boolean;
|
exact: boolean;
|
||||||
|
|
|
@ -18,8 +18,8 @@ import { CoreCustomURLSchemes } from '@services/urlschemes';
|
||||||
import { CoreLoginHelperProvider } from '@features/login/services/login-helper';
|
import { CoreLoginHelperProvider } from '@features/login/services/login-helper';
|
||||||
import { CoreConfig } from '@services/config';
|
import { CoreConfig } from '@services/config';
|
||||||
import { EnvironmentConfig } from '@/types/config';
|
import { EnvironmentConfig } from '@/types/config';
|
||||||
import { NgZone } from '@singletons';
|
import { makeSingleton, NgZone } from '@singletons';
|
||||||
import { CoreNetwork } from '@services/network';
|
import { CoreNetwork, CoreNetworkService } from '@services/network';
|
||||||
import {
|
import {
|
||||||
CorePushNotifications,
|
CorePushNotifications,
|
||||||
CorePushNotificationsNotificationBasicData,
|
CorePushNotificationsNotificationBasicData,
|
||||||
|
@ -30,45 +30,34 @@ import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||||
import { CoreDom } from '@singletons/dom';
|
import { CoreDom } from '@singletons/dom';
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
import { CoreCoursesDashboardPage } from '@features/courses/pages/dashboard/dashboard';
|
import { CoreCoursesDashboardPage } from '@features/courses/pages/dashboard/dashboard';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Behat runtime servive with public API.
|
* Behat runtime servive with public API.
|
||||||
*/
|
*/
|
||||||
export class TestingBehatRuntime {
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class TestingBehatRuntimeService {
|
||||||
|
|
||||||
|
protected initialized = false;
|
||||||
|
|
||||||
|
get network(): CoreNetworkService {
|
||||||
|
return CoreNetwork.instance;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init behat functions and set options like skipping onboarding.
|
* Init behat functions and set options like skipping onboarding.
|
||||||
*
|
*
|
||||||
* @param options Options to set on the app.
|
* @param options Options to set on the app.
|
||||||
*/
|
*/
|
||||||
static init(options?: TestingBehatInitOptions): void {
|
init(options: TestingBehatInitOptions = {}): void {
|
||||||
TestingBehatBlocking.init();
|
if (this.initialized) {
|
||||||
|
|
||||||
(window as BehatTestsWindow).behat = {
|
|
||||||
closePopup: TestsBehatRuntime.closePopup,
|
|
||||||
find: TestsBehatRuntime.find,
|
|
||||||
getAngularInstance: TestsBehatRuntime.getAngularInstance,
|
|
||||||
getHeader: TestsBehatRuntime.getHeader,
|
|
||||||
isSelected: TestsBehatRuntime.isSelected,
|
|
||||||
loadMoreItems: TestsBehatRuntime.loadMoreItems,
|
|
||||||
log: TestsBehatRuntime.log,
|
|
||||||
press: TestsBehatRuntime.press,
|
|
||||||
pressStandard: TestsBehatRuntime.pressStandard,
|
|
||||||
pullToRefresh: TestsBehatRuntime.pullToRefresh,
|
|
||||||
scrollTo: TestsBehatRuntime.scrollTo,
|
|
||||||
setField: TestsBehatRuntime.setField,
|
|
||||||
handleCustomURL: TestsBehatRuntime.handleCustomURL,
|
|
||||||
notificationClicked: TestsBehatRuntime.notificationClicked,
|
|
||||||
forceSyncExecution: TestsBehatRuntime.forceSyncExecution,
|
|
||||||
waitLoadingToFinish: TestsBehatRuntime.waitLoadingToFinish,
|
|
||||||
network: CoreNetwork.instance,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!options) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.skipOnBoarding === true) {
|
this.initialized = true;
|
||||||
|
TestingBehatBlocking.init();
|
||||||
|
|
||||||
|
if (options.skipOnBoarding) {
|
||||||
CoreConfig.set(CoreLoginHelperProvider.ONBOARDING_DONE, 1);
|
CoreConfig.set(CoreLoginHelperProvider.ONBOARDING_DONE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,13 +68,22 @@ export class TestingBehatRuntime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the service has been initialized or not.
|
||||||
|
*
|
||||||
|
* @returns Whether the service has been initialized or not.
|
||||||
|
*/
|
||||||
|
hasInitialized(): boolean {
|
||||||
|
return this.initialized;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a custom URL.
|
* Handles a custom URL.
|
||||||
*
|
*
|
||||||
* @param url Url to open.
|
* @param url Url to open.
|
||||||
* @return OK if successful, or ERROR: followed by message.
|
* @return OK if successful, or ERROR: followed by message.
|
||||||
*/
|
*/
|
||||||
static async handleCustomURL(url: string): Promise<string> {
|
async handleCustomURL(url: string): Promise<string> {
|
||||||
try {
|
try {
|
||||||
await NgZone.run(async () => {
|
await NgZone.run(async () => {
|
||||||
await CoreCustomURLSchemes.handleCustomURL(url);
|
await CoreCustomURLSchemes.handleCustomURL(url);
|
||||||
|
@ -103,7 +101,7 @@ export class TestingBehatRuntime {
|
||||||
* @param data Notification data.
|
* @param data Notification data.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
static async notificationClicked(data: CorePushNotificationsNotificationBasicData): Promise<void> {
|
async notificationClicked(data: CorePushNotificationsNotificationBasicData): Promise<void> {
|
||||||
const blockKey = TestingBehatBlocking.block();
|
const blockKey = TestingBehatBlocking.block();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -121,7 +119,7 @@ export class TestingBehatRuntime {
|
||||||
*
|
*
|
||||||
* @return Promise resolved if all handlers are executed successfully, rejected otherwise.
|
* @return Promise resolved if all handlers are executed successfully, rejected otherwise.
|
||||||
*/
|
*/
|
||||||
static async forceSyncExecution(): Promise<void> {
|
async forceSyncExecution(): Promise<void> {
|
||||||
await NgZone.run(async () => {
|
await NgZone.run(async () => {
|
||||||
await CoreCronDelegate.forceSyncExecution();
|
await CoreCronDelegate.forceSyncExecution();
|
||||||
});
|
});
|
||||||
|
@ -132,7 +130,7 @@ export class TestingBehatRuntime {
|
||||||
*
|
*
|
||||||
* @return Promise resolved when all components have been rendered.
|
* @return Promise resolved when all components have been rendered.
|
||||||
*/
|
*/
|
||||||
static async waitLoadingToFinish(): Promise<void> {
|
async waitLoadingToFinish(): Promise<void> {
|
||||||
await NgZone.run(async () => {
|
await NgZone.run(async () => {
|
||||||
const elements = Array.from(document.body.querySelectorAll<HTMLElement>('core-loading'))
|
const elements = Array.from(document.body.querySelectorAll<HTMLElement>('core-loading'))
|
||||||
.filter((element) => CoreDom.isElementVisible(element));
|
.filter((element) => CoreDom.isElementVisible(element));
|
||||||
|
@ -148,7 +146,7 @@ export class TestingBehatRuntime {
|
||||||
* @param button Type of button to press.
|
* @param button Type of button to press.
|
||||||
* @return OK if successful, or ERROR: followed by message.
|
* @return OK if successful, or ERROR: followed by message.
|
||||||
*/
|
*/
|
||||||
static async pressStandard(button: string): Promise<string> {
|
async pressStandard(button: string): Promise<string> {
|
||||||
this.log('Action - Click standard button: ' + button);
|
this.log('Action - Click standard button: ' + button);
|
||||||
|
|
||||||
// Find button
|
// Find button
|
||||||
|
@ -194,7 +192,7 @@ export class TestingBehatRuntime {
|
||||||
*
|
*
|
||||||
* @return OK if successful, or ERROR: followed by message
|
* @return OK if successful, or ERROR: followed by message
|
||||||
*/
|
*/
|
||||||
static closePopup(): string {
|
closePopup(): string {
|
||||||
this.log('Action - Close popup');
|
this.log('Action - Close popup');
|
||||||
|
|
||||||
let backdrops = Array.from(document.querySelectorAll('ion-backdrop'));
|
let backdrops = Array.from(document.querySelectorAll('ion-backdrop'));
|
||||||
|
@ -222,7 +220,7 @@ export class TestingBehatRuntime {
|
||||||
* @param options Search options.
|
* @param options Search options.
|
||||||
* @return OK if successful, or ERROR: followed by message
|
* @return OK if successful, or ERROR: followed by message
|
||||||
*/
|
*/
|
||||||
static find(locator: TestingBehatElementLocator, options: Partial<TestingBehatFindOptions> = {}): string {
|
find(locator: TestingBehatElementLocator, options: Partial<TestingBehatFindOptions> = {}): string {
|
||||||
this.log('Action - Find', { locator, ...options });
|
this.log('Action - Find', { locator, ...options });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -250,7 +248,7 @@ export class TestingBehatRuntime {
|
||||||
* @param locator Element locator.
|
* @param locator Element locator.
|
||||||
* @return OK if successful, or ERROR: followed by message
|
* @return OK if successful, or ERROR: followed by message
|
||||||
*/
|
*/
|
||||||
static scrollTo(locator: TestingBehatElementLocator): string {
|
scrollTo(locator: TestingBehatElementLocator): string {
|
||||||
this.log('Action - scrollTo', { locator });
|
this.log('Action - scrollTo', { locator });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -277,7 +275,7 @@ export class TestingBehatRuntime {
|
||||||
*
|
*
|
||||||
* @return OK if successful, or ERROR: followed by message
|
* @return OK if successful, or ERROR: followed by message
|
||||||
*/
|
*/
|
||||||
static async loadMoreItems(): Promise<string> {
|
async loadMoreItems(): Promise<string> {
|
||||||
this.log('Action - loadMoreItems');
|
this.log('Action - loadMoreItems');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -324,7 +322,7 @@ export class TestingBehatRuntime {
|
||||||
* @param locator Element locator.
|
* @param locator Element locator.
|
||||||
* @return YES or NO if successful, or ERROR: followed by message
|
* @return YES or NO if successful, or ERROR: followed by message
|
||||||
*/
|
*/
|
||||||
static isSelected(locator: TestingBehatElementLocator): string {
|
isSelected(locator: TestingBehatElementLocator): string {
|
||||||
this.log('Action - Is Selected', locator);
|
this.log('Action - Is Selected', locator);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -342,7 +340,7 @@ export class TestingBehatRuntime {
|
||||||
* @param locator Element locator.
|
* @param locator Element locator.
|
||||||
* @return OK if successful, or ERROR: followed by message
|
* @return OK if successful, or ERROR: followed by message
|
||||||
*/
|
*/
|
||||||
static async press(locator: TestingBehatElementLocator): Promise<string> {
|
async press(locator: TestingBehatElementLocator): Promise<string> {
|
||||||
this.log('Action - Press', locator);
|
this.log('Action - Press', locator);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -365,7 +363,7 @@ export class TestingBehatRuntime {
|
||||||
*
|
*
|
||||||
* @return OK if successful, or ERROR: followed by message
|
* @return OK if successful, or ERROR: followed by message
|
||||||
*/
|
*/
|
||||||
static async pullToRefresh(): Promise<string> {
|
async pullToRefresh(): Promise<string> {
|
||||||
this.log('Action - pullToRefresh');
|
this.log('Action - pullToRefresh');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -398,7 +396,7 @@ export class TestingBehatRuntime {
|
||||||
*
|
*
|
||||||
* @return OK: followed by header text if successful, or ERROR: followed by message.
|
* @return OK: followed by header text if successful, or ERROR: followed by message.
|
||||||
*/
|
*/
|
||||||
static getHeader(): string {
|
getHeader(): string {
|
||||||
this.log('Action - Get header');
|
this.log('Action - Get header');
|
||||||
|
|
||||||
let titles = Array.from(document.querySelectorAll<HTMLElement>('.ion-page:not(.ion-page-hidden) > ion-header h1'));
|
let titles = Array.from(document.querySelectorAll<HTMLElement>('.ion-page:not(.ion-page-hidden) > ion-header h1'));
|
||||||
|
@ -424,7 +422,7 @@ export class TestingBehatRuntime {
|
||||||
* @param value New value
|
* @param value New value
|
||||||
* @return OK or ERROR: followed by message
|
* @return OK or ERROR: followed by message
|
||||||
*/
|
*/
|
||||||
static async setField(field: string, value: string): Promise<string> {
|
async setField(field: string, value: string): Promise<string> {
|
||||||
this.log('Action - Set field ' + field + ' to: ' + value);
|
this.log('Action - Set field ' + field + ' to: ' + value);
|
||||||
|
|
||||||
const found: HTMLElement | HTMLInputElement = TestingBehatDomUtils.findElementBasedOnText(
|
const found: HTMLElement | HTMLInputElement = TestingBehatDomUtils.findElementBasedOnText(
|
||||||
|
@ -448,7 +446,7 @@ export class TestingBehatRuntime {
|
||||||
* @param className Constructor class name
|
* @param className Constructor class name
|
||||||
* @return Component instance
|
* @return Component instance
|
||||||
*/
|
*/
|
||||||
static getAngularInstance<T = unknown>(selector: string, className: string): T | null {
|
getAngularInstance<T = unknown>(selector: string, className: string): T | null {
|
||||||
this.log('Action - Get Angular instance ' + selector + ', ' + className);
|
this.log('Action - Get Angular instance ' + selector + ', ' + className);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -465,7 +463,7 @@ export class TestingBehatRuntime {
|
||||||
* Logs information from this Behat runtime JavaScript, including the time and the 'BEHAT'
|
* Logs information from this Behat runtime JavaScript, including the time and the 'BEHAT'
|
||||||
* keyword so we can easily filter for it if needed.
|
* keyword so we can easily filter for it if needed.
|
||||||
*/
|
*/
|
||||||
static log(...args: unknown[]): void {
|
log(...args: unknown[]): void {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const nowFormatted = String(now.getHours()).padStart(2, '0') + ':' +
|
const nowFormatted = String(now.getHours()).padStart(2, '0') + ':' +
|
||||||
String(now.getMinutes()).padStart(2, '0') + ':' +
|
String(now.getMinutes()).padStart(2, '0') + ':' +
|
||||||
|
@ -477,14 +475,14 @@ export class TestingBehatRuntime {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const TestingBehatRuntime = makeSingleton(TestingBehatRuntimeService);
|
||||||
|
|
||||||
export type BehatTestsWindow = Window & {
|
export type BehatTestsWindow = Window & {
|
||||||
M?: { // eslint-disable-line @typescript-eslint/naming-convention
|
M?: { // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
util?: {
|
util?: {
|
||||||
pending_js?: string[]; // eslint-disable-line @typescript-eslint/naming-convention
|
pending_js?: string[]; // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
behatInit?: () => void;
|
|
||||||
behat?: unknown;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TestingBehatFindOptions = {
|
export type TestingBehatFindOptions = {
|
||||||
|
|
|
@ -18,4 +18,4 @@ import { NgModule } from '@angular/core';
|
||||||
* Stub used in production to avoid including testing code in production bundles.
|
* Stub used in production to avoid including testing code in production bundles.
|
||||||
*/
|
*/
|
||||||
@NgModule({})
|
@NgModule({})
|
||||||
export class BehatTestingModule {}
|
export class TestingModule {}
|
|
@ -12,21 +12,25 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||||
import { CoreAppProvider } from '@services/app';
|
import { CoreAppProvider } from '@services/app';
|
||||||
import { CoreDB, CoreDbProvider } from '@services/db';
|
import { TestingBehatRuntime, TestingBehatRuntimeService } from './services/behat-runtime';
|
||||||
|
|
||||||
type AutomatedTestsWindow = Window & {
|
type AutomatedTestsWindow = Window & {
|
||||||
dbProvider?: CoreDbProvider;
|
behat?: TestingBehatRuntimeService;
|
||||||
};
|
};
|
||||||
|
|
||||||
function initializeAutomatedTestsWindow(window: AutomatedTestsWindow) {
|
function initializeAutomatedTestsWindow(window: AutomatedTestsWindow) {
|
||||||
window.dbProvider = CoreDB.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function(): void {
|
|
||||||
if (!CoreAppProvider.isAutomated()) {
|
if (!CoreAppProvider.isAutomated()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeAutomatedTestsWindow(window);
|
window.behat = TestingBehatRuntime.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
providers: [
|
||||||
|
{ provide: APP_INITIALIZER, multi: true, useValue: () => initializeAutomatedTestsWindow(window) },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class TestingModule {}
|
Loading…
Reference in New Issue