diff --git a/local_moodleappbehat/tests/behat/behat_app.php b/local_moodleappbehat/tests/behat/behat_app.php index 0b09375b5..a5af4a3ca 100644 --- a/local_moodleappbehat/tests/behat/behat_app.php +++ b/local_moodleappbehat/tests/behat/behat_app.php @@ -1012,4 +1012,22 @@ class behat_app extends behat_app_helper { return true; } + /** + * View a specific month in the calendar in the app. + * + * @When /^I open the calendar for "(?P\d+)" "(?P\d+)" in the app$/ + * @param int $month the month selected as a number + * @param int $year the four digit year + */ + public function i_open_the_calendar_for($month, $year) { + $options = json_encode([ + 'params' => [ + 'month' => $month, + 'year' => $year, + ], + ]); + + $this->zone_js("navigator.navigateToSitePath('/calendar/index', $options)"); + } + } diff --git a/src/addons/calendar/pages/edit-event/edit-event.html b/src/addons/calendar/pages/edit-event/edit-event.html index c5b628d9d..23cea6789 100644 --- a/src/addons/calendar/pages/edit-event/edit-event.html +++ b/src/addons/calendar/pages/edit-event/edit-event.html @@ -31,7 +31,7 @@

{{ 'core.date' | translate }}

+ [max]="maxDate" [min]="minDate" [displayTimezone]="displayTimezone"> @@ -156,7 +156,8 @@ + [placeholder]="'addon.calendar.durationuntil' | translate" [displayFormat]="dateFormat" + [displayTimezone]="displayTimezone"> diff --git a/src/addons/calendar/pages/edit-event/edit-event.page.ts b/src/addons/calendar/pages/edit-event/edit-event.page.ts index f5a21a733..e4fb34416 100644 --- a/src/addons/calendar/pages/edit-event/edit-event.page.ts +++ b/src/addons/calendar/pages/edit-event/edit-event.page.ts @@ -46,6 +46,7 @@ import { CoreForms } from '@singletons/form'; import { CoreReminders, CoreRemindersService, CoreRemindersUnits } from '@features/reminders/services/reminders'; import { CoreRemindersSetReminderMenuComponent } from '@features/reminders/components/set-reminder-menu/set-reminder-menu'; import moment from 'moment-timezone'; +import { CoreAppProvider } from '@services/app'; /** * Page that displays a form to create/edit an event. @@ -78,6 +79,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { eventId?: number; maxDate: string; minDate: string; + displayTimezone?: string; // Form variables. form: FormGroup; @@ -109,6 +111,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { // Calculate format to use. ion-datetime doesn't support escaping characters ([]), so we remove them. this.dateFormat = CoreTimeUtils.convertPHPToMoment(Translate.instant('core.strftimedatetimeshort')) .replace(/[[\]]/g, ''); + this.displayTimezone = CoreAppProvider.getForcedTimezone(); this.form = new FormGroup({}); @@ -489,6 +492,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { description: { text: formData.description || '', format: 1, + itemid: 0, // Files not supported yet. }, location: formData.location, duration: formData.duration, diff --git a/src/addons/calendar/services/calendar-sync.ts b/src/addons/calendar/services/calendar-sync.ts index c2a351e87..59ad3e571 100644 --- a/src/addons/calendar/services/calendar-sync.ts +++ b/src/addons/calendar/services/calendar-sync.ts @@ -253,6 +253,7 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider + [disabled]="searchMode && !searchFields!['f_'+field.id+'_z']" [displayFormat]="format" [displayTimezone]="displayTimezone"> diff --git a/src/addons/mod/data/fields/date/component/date.ts b/src/addons/mod/data/fields/date/component/date.ts index 761953f89..91e9c4041 100644 --- a/src/addons/mod/data/fields/date/component/date.ts +++ b/src/addons/mod/data/fields/date/component/date.ts @@ -13,6 +13,7 @@ // limitations under the License. import { Component } from '@angular/core'; +import { CoreAppProvider } from '@services/app'; import { CoreTimeUtils } from '@services/utils/time'; import { Translate } from '@singletons'; import moment, { Moment } from 'moment-timezone'; @@ -31,6 +32,7 @@ export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginBaseC displayDate?: number; maxDate?: string; minDate?: string; + displayTimezone?: string; /** * @inheritdoc @@ -52,6 +54,7 @@ export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginBaseC )); this.maxDate = CoreTimeUtils.getDatetimeDefaultMax(); this.minDate = CoreTimeUtils.getDatetimeDefaultMin(); + this.displayTimezone = CoreAppProvider.getForcedTimezone(); if (this.searchMode) { this.addControl('f_' + this.field.id + '_z'); diff --git a/src/addons/userprofilefield/datetime/component/addon-user-profile-field-datetime.html b/src/addons/userprofilefield/datetime/component/addon-user-profile-field-datetime.html index 77f12bae2..bf48afb57 100644 --- a/src/addons/userprofilefield/datetime/component/addon-user-profile-field-datetime.html +++ b/src/addons/userprofilefield/datetime/component/addon-user-profile-field-datetime.html @@ -12,7 +12,7 @@ {{ field.name }} + [min]="min" [monthNames]="monthNames" [displayTimezone]="displayTimezone"> diff --git a/src/addons/userprofilefield/datetime/component/datetime.ts b/src/addons/userprofilefield/datetime/component/datetime.ts index c26355ce0..eac0d6ec2 100644 --- a/src/addons/userprofilefield/datetime/component/datetime.ts +++ b/src/addons/userprofilefield/datetime/component/datetime.ts @@ -22,6 +22,7 @@ import { CoreUserProfileField } from '@features/user/services/user'; import { Translate } from '@singletons'; import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-profilefield-component'; import { CoreLang } from '@services/lang'; +import { CoreAppProvider } from '@services/app'; /** * Directive to render a datetime user profile field. @@ -37,6 +38,7 @@ export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileField max?: string; valueNumber = 0; monthNames?: string[]; + displayTimezone?: string; /** * Init the data when the field is meant to be displayed without editing. @@ -56,6 +58,7 @@ export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileField super.initForEdit(field); this.monthNames = CoreLang.getMonthNames(); + this.displayTimezone = CoreAppProvider.getForcedTimezone(); // Check if it's only date or it has time too. const hasTime = CoreUtils.isTrueOrOne(field.param3); diff --git a/src/core/services/app.ts b/src/core/services/app.ts index ed55f1e32..4971fe65b 100644 --- a/src/core/services/app.ts +++ b/src/core/services/app.ts @@ -70,6 +70,18 @@ export class CoreAppProvider { return !!navigator.webdriver; } + /** + * Returns the forced timezone to use. Timezone is forced for automated tests. + * + * @return Timezone. Undefined to use the user's timezone. + */ + static getForcedTimezone(): string | undefined { + if (CoreAppProvider.isAutomated()) { + // Use the same timezone forced for LMS in tests. + return 'Australia/Perth'; + } + } + /** * Initialize database. */ diff --git a/src/testing/services/behat-blocking.ts b/src/testing/services/behat-blocking.ts index 92cb315cf..345dba3c9 100644 --- a/src/testing/services/behat-blocking.ts +++ b/src/testing/services/behat-blocking.ts @@ -192,9 +192,25 @@ export class TestingBehatBlockingService { */ protected async checkUIBlocked(): Promise { await CoreUtils.nextTick(); - const blocked = document.querySelector('div.core-loading-container, ion-loading, .click-block-active'); - if (blocked?.offsetParent) { + const blockingElements = Array.from( + document.querySelectorAll('div.core-loading-container, ion-loading, .click-block-active'), + ); + + const isBlocked = blockingElements.some(element => { + if (!element.offsetParent) { + return false; + } + + const slide = element.closest('ion-slide'); + if (slide && !slide.classList.contains('swiper-slide-active')) { + return false; + } + + return true; + }); + + if (isBlocked) { if (!this.waitingBlocked) { this.block('blocked'); this.waitingBlocked = true; diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts index a9d012ad4..878df655b 100644 --- a/src/testing/services/behat-runtime.ts +++ b/src/testing/services/behat-runtime.ts @@ -27,6 +27,7 @@ import { CoreComponentsRegistry } from '@singletons/components-registry'; import { CoreDom } from '@singletons/dom'; import { Injectable } from '@angular/core'; import { CoreSites, CoreSitesProvider } from '@services/sites'; +import { CoreNavigator, CoreNavigatorService } from '@services/navigator'; /** * Behat runtime servive with public API. @@ -56,6 +57,10 @@ export class TestingBehatRuntimeService { return CoreSites.instance; } + get navigator(): CoreNavigatorService { + return CoreNavigator.instance; + } + /** * Init behat functions and set options like skipping onboarding. * @@ -436,7 +441,7 @@ export class TestingBehatRuntimeService { return 'ERROR: No element matches field to set.'; } - const foundValue = 'value' in found ? found.value : found.innerText; + const foundValue = this.getFieldValue(found); if (value !== foundValue) { return `ERROR: Expecting value "${value}", found "${foundValue}" instead.`; } @@ -457,6 +462,24 @@ export class TestingBehatRuntimeService { ); } + /** + * Get the value of a certain field. + * + * @param element Field to get the value. + * @return Value. + */ + protected getFieldValue(element: HTMLElement | HTMLInputElement): string { + if (element.tagName === 'ION-DATETIME') { + // ion-datetime's value is a timestamp in ISO format. Use the text displayed to the user instead. + const dateTimeTextElement = element.shadowRoot?.querySelector('.datetime-text'); + if (dateTimeTextElement) { + return dateTimeTextElement.innerText; + } + } + + return 'value' in element ? element.value : element.innerText; + } + /** * Get an Angular component instance. * diff --git a/src/testing/testing.module.ts b/src/testing/testing.module.ts index bc9171833..479df360d 100644 --- a/src/testing/testing.module.ts +++ b/src/testing/testing.module.ts @@ -28,8 +28,8 @@ function initializeAutomatedTests(window: AutomatedTestsWindow) { window.behat = TestingBehatRuntime.instance; - // Force timezone for automated tests. Use the same timezone forced for LMS in tests. - moment.tz.setDefault('Australia/Perth'); + // Force timezone for automated tests. + moment.tz.setDefault(CoreAppProvider.getForcedTimezone()); } @NgModule({