diff --git a/src/addons/mod/scorm/pages/player/player.html b/src/addons/mod/scorm/pages/player/player.html index 85093fb51..a4e33155b 100644 --- a/src/addons/mod/scorm/pages/player/player.html +++ b/src/addons/mod/scorm/pages/player/player.html @@ -21,7 +21,7 @@ - diff --git a/src/addons/mod/scorm/pages/player/player.ts b/src/addons/mod/scorm/pages/player/player.ts index aaa42569a..f98f6547e 100644 --- a/src/addons/mod/scorm/pages/player/player.ts +++ b/src/addons/mod/scorm/pages/player/player.ts @@ -426,6 +426,11 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { // eslint-disable-next-line @typescript-eslint/no-explicit-any ( window).API = this.dataModel; } else { + // Changing SCO. First unload the existing SCO to make sure the callback to send the data has been called. + this.src = ''; + + await CoreUtils.nextTick(); + // Load the SCO in the existing model. this.dataModel.loadSco(sco.id); } @@ -436,7 +441,7 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { this.calculateNavigationItems(sco.id); // Load the SCO source. - this.loadScoSrc(sco); + this.src = await AddonModScorm.getScoSrc(this.scorm, sco); if (sco.scormtype == 'asset') { // Mark the asset as completed. @@ -446,25 +451,6 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { this.logEvent(sco.id); } - /** - * Load SCO src. - * - * @param sco SCO to load. - * @returns Promise resolved when done. - */ - protected async loadScoSrc(sco: AddonModScormScoWithData): Promise { - const src = await AddonModScorm.getScoSrc(this.scorm, sco); - - if (src == this.src) { - // Re-loading same page. Set it to empty and then re-set the src in the next digest so it detects it has changed. - this.src = ''; - - await CoreUtils.nextTick(); - } - - this.src = src; - } - /** * Given an SCO, mark it as completed. * diff --git a/src/addons/mod/scorm/tests/behat/basic_usage.feature b/src/addons/mod/scorm/tests/behat/basic_usage.feature new file mode 100755 index 000000000..c0fb7ef12 --- /dev/null +++ b/src/addons/mod/scorm/tests/behat/basic_usage.feature @@ -0,0 +1,169 @@ +@mod @mod_scorm @app @javascript @_switch_iframe +Feature: Test basic usage of SCORM activity in app + In order to play a SCORM while using the mobile app + As a student + I need basic SCORM functionality to work + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | teacher | teacher1@example.com | + | student1 | Student | student | student1@example.com | + And the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + + Scenario: Resume progress when re-entering SCORM + Given the following "activities" exist: + | activity | name | intro | course | idnumber | packagefilepath | + | scorm | Basic SCORM | SCORM description | C1 | scorm | mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip | + And I entered the course "Course 1" as "student1" in the app + When I press "Basic SCORM" in the app + And I press "Enter" in the app + And I press "Disable fullscreen" in the app + Then I should find "2 / 11" in the app + And I switch to "scorm_object" iframe + And I should see "Play of the game" + + When I switch to the main frame + And I press "Next" in the app + And I press "Next" in the app + Then I should find "4 / 11" in the app + And I switch to "scorm_object" iframe + And I should see "Scoring" + + When I switch to the main frame + And I press the back button in the app + And I wait loading to finish in the app + Then I should find "1" within "Number of attempts you have made" "ion-item" in the app + And I should find "3" within "Grade reported" "ion-item" in the app + + When I press "Enter" in the app + And I press "Disable fullscreen" in the app + Then I should find "5 / 11" in the app + And I switch to "scorm_object" iframe + And I should see "Other Scoring Systems" + + Scenario: TOC displays the right status and opens the right SCO + Given the following "activities" exist: + | activity | name | intro | course | idnumber | displaycoursestructure | packagefilepath | + | scorm | Basic SCORM | SCORM description | C1 | scorm | 1 | mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip | + And I entered the course "Course 1" as "student1" in the app + When I press "Basic SCORM" in the app + Then I should find "Not attempted" within "How to Play" "ion-item" in the app + And I should find "Not attempted" within "Par?" "ion-item" in the app + And I should find "Not attempted" within "Keeping Score" "ion-item" in the app + And I should find "Not attempted" within "Other Scoring Systems" "ion-item" in the app + And I should find "Not attempted" within "The Rules of Golf" "ion-item" in the app + And I should find "Not attempted" within "Playing Golf Quiz" "ion-item" in the app + And I should find "Not attempted" within "How to Have Fun Playing Golf" "ion-item" in the app + And I should find "Not attempted" within "How to Make Friends Playing Golf" "ion-item" in the app + And I should find "Not attempted" within "Having Fun Quiz" "ion-item" in the app + + When I press "Enter" in the app + And I press "Disable fullscreen" in the app + And I press "TOC" in the app + Then I should find "Not attempted" within "How to Play" "ion-item" in the app + And I should find "Not attempted" within "Par?" "ion-item" in the app + And I should find "Not attempted" within "Keeping Score" "ion-item" in the app + And I should find "Not attempted" within "Other Scoring Systems" "ion-item" in the app + And I should find "Not attempted" within "The Rules of Golf" "ion-item" in the app + And I should find "Not attempted" within "Playing Golf Quiz" "ion-item" in the app + And I should find "Not attempted" within "How to Have Fun Playing Golf" "ion-item" in the app + And I should find "Not attempted" within "How to Make Friends Playing Golf" "ion-item" in the app + And I should find "Not attempted" within "Having Fun Quiz" "ion-item" in the app + + When I press "Close" in the app + And I press "Next" in the app + And I press "TOC" in the app + Then I should find "Completed" within "How to Play" "ion-item" in the app + And I should find "Not attempted" within "Par?" "ion-item" in the app + + When I press "The Rules of Golf" in the app + Then I should find "6 / 11" in the app + And I switch to "scorm_object" iframe + And I should see "The Rules of Golf" + + When I switch to the main frame + And I press "TOC" in the app + Then I should find "Completed" within "How to Play" "ion-item" in the app + And I should find "Completed" within "Par?" "ion-item" in the app + And I should find "Not attempted" within "Keeping Score" "ion-item" in the app + And I should find "Not attempted" within "Other Scoring Systems" "ion-item" in the app + And I should find "Not attempted" within "The Rules of Golf" "ion-item" in the app + And I should find "Not attempted" within "Playing Golf Quiz" "ion-item" in the app + And I should find "Not attempted" within "How to Have Fun Playing Golf" "ion-item" in the app + And I should find "Not attempted" within "How to Make Friends Playing Golf" "ion-item" in the app + And I should find "Not attempted" within "Having Fun Quiz" "ion-item" in the app + + When I press "Close" in the app + And I press the back button in the app + And I wait loading to finish in the app + Then I should find "Completed" within "How to Play" "ion-item" in the app + And I should find "Completed" within "Par?" "ion-item" in the app + And I should find "Not attempted" within "Keeping Score" "ion-item" in the app + And I should find "Not attempted" within "Other Scoring Systems" "ion-item" in the app + And I should find "Completed" within "The Rules of Golf" "ion-item" in the app + And I should find "Not attempted" within "Playing Golf Quiz" "ion-item" in the app + And I should find "Not attempted" within "How to Have Fun Playing Golf" "ion-item" in the app + And I should find "Not attempted" within "How to Make Friends Playing Golf" "ion-item" in the app + And I should find "Not attempted" within "Having Fun Quiz" "ion-item" in the app + + When I press "How to Have Fun Playing Golf" in the app + Then I should find "9 / 11" in the app + And I switch to "scorm_object" iframe + And I should see "How to Have Fun Golfing" + + Scenario: Preview SCORM + Given the following "activities" exist: + | activity | name | intro | course | idnumber | packagefilepath | + | scorm | Basic SCORM | SCORM description | C1 | scorm | mod/scorm/tests/packages/RuntimeMinimumCalls_SCORM12-mini.zip | + And I entered the course "Course 1" as "teacher1" in the app + When I press "Basic SCORM" in the app + Then I should find "0" within "Number of attempts you have made" "ion-item" in the app + + When I press "Preview" in the app + And I press "Disable fullscreen" in the app + And I press "TOC" in the app + Then I should find "Preview mode" in the app + + When I press "Close" in the app + And I press "Next" in the app + And I press "Next" in the app + And I press "Next" in the app + And I press "Next" in the app + And I press "Next" in the app + And I press "Next" in the app + And I press "Next" in the app + And I press "Next" in the app + Then I should find "11 / 11" in the app + + When I press the back button in the app + And I wait loading to finish in the app + Then I should find "1" within "Number of attempts you have made" "ion-item" in the app + And I should find "9" within "Grade reported" "ion-item" in the app + + # Check that Preview doesn't start a new attempt. + When I press "Start a new attempt" in the app + And I press "Preview" in the app + And I press "Disable fullscreen" in the app + And I press "TOC" in the app + Then I should find "Complete" within "How to Play" "ion-item" in the app + And I should find "Complete" within "Having Fun Quiz" "ion-item" in the app + + When I press "Close" in the app + And I press the back button in the app + And I wait loading to finish in the app + Then I should find "1" within "Number of attempts you have made" "ion-item" in the app + + Scenario: Unsupported SCORM + Given the following "activities" exist: + | activity | name | course | idnumber | packagefilepath | + | scorm | SCORM 1.2 | C1 | scorm2 | mod/scorm/tests/packages/RuntimeBasicCalls_SCORM20043rdEdition.zip | + And I entered the course "Course 1" as "student1" in the app + When I press "SCORM 1.2" in the app + Then I should find "Sorry, the application only supports SCORM 1.2." in the app diff --git a/src/core/components/iframe/core-iframe.html b/src/core/components/iframe/core-iframe.html index 51a88f9ff..6c7a0fa1d 100644 --- a/src/core/components/iframe/core-iframe.html +++ b/src/core/components/iframe/core-iframe.html @@ -11,7 +11,7 @@ - diff --git a/src/core/components/iframe/iframe.ts b/src/core/components/iframe/iframe.ts index bcccf96ac..6a21b9b69 100644 --- a/src/core/components/iframe/iframe.ts +++ b/src/core/components/iframe/iframe.ts @@ -42,6 +42,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { @ViewChild('iframe') iframe?: ElementRef; @Input() src?: string; + @Input() id: string | null = null; @Input() iframeWidth?: string; @Input() iframeHeight?: string; @Input() allowFullscreen?: boolean | string; @@ -160,10 +161,10 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { return; } - let url = changes.src.currentValue; + let url = this.src; - if (!CoreUrlUtils.isLocalFileUrl(url)) { - url = CoreUrlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue; + if (url && !CoreUrlUtils.isLocalFileUrl(url)) { + url = CoreUrlUtils.getYoutubeEmbedUrl(url) || url; this.displayHelp = CoreIframeUtils.shouldDisplayHelpForUrl(url); const currentSite = CoreSites.getCurrentSite(); @@ -181,7 +182,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { await CoreIframeUtils.fixIframeCookies(url); } - this.safeUrl = DomSanitizer.bypassSecurityTrustResourceUrl(CoreFile.convertFileSrc(url)); + this.safeUrl = DomSanitizer.bypassSecurityTrustResourceUrl(url ? CoreFile.convertFileSrc(url) : ''); // Now that the URL has been set, initialize the iframe. Wait for the iframe to the added to the DOM. setTimeout(() => { diff --git a/src/testing/services/behat-blocking.ts b/src/testing/services/behat-blocking.ts index 68498ed3a..8ae1d02be 100644 --- a/src/testing/services/behat-blocking.ts +++ b/src/testing/services/behat-blocking.ts @@ -236,15 +236,27 @@ export class TestingBehatBlockingService { NgZone.run(() => { const index = requestIndex++; const key = 'httprequest-' + index; + const isAsync = args[2] !== false; try { - // Add to the list of pending requests. + // Add to the list of pending requests. TestingBehatBlocking.block(key); // Detect when it finishes and remove it from the list. - this.addEventListener('loadend', () => { - TestingBehatBlocking.unblock(key); - }); + if (isAsync) { + this.addEventListener('loadend', () => { + TestingBehatBlocking.unblock(key); + }); + } else { + const realSend = this.send; + this.send = (...args) => { + try { + return realSend.apply(this, args); + } finally { + TestingBehatBlocking.unblock(key); + } + }; + } return realOpen.apply(this, args); } catch (error) {