diff --git a/local_moodleappbehat/tests/behat/behat_app.php b/local_moodleappbehat/tests/behat/behat_app.php index 8e6dc9588..4d1d84cef 100644 --- a/local_moodleappbehat/tests/behat/behat_app.php +++ b/local_moodleappbehat/tests/behat/behat_app.php @@ -736,6 +736,42 @@ class behat_app extends behat_app_helper { } } + /** + * Checks a field matches a certain value in the app. + * + * Currently this only works for input fields which must be identified using a partial or + * exact match on the placeholder text. + * + * @Given /^the field "((?:[^"]|\\")+)" matches value "((?:[^"]|\\")*)" in the app$/ + * @param string $field Text identifying field + * @param string $value Value for field + * @throws DriverException If the field isn't found + * @throws ExpectationException If the field value is different to the expected value + */ + public function the_field_matches_value_in_the_app(string $field, string $value) { + $field = addslashes_js($field); + $value = addslashes_js($value); + + $this->spin(function() use ($field, $value) { + $result = $this->runtime_js("fieldMatches('$field', '$value')"); + + if ($result !== 'OK') { + if (str_contains($result, 'No element matches')) { + throw new DriverException('Error field matches value - ' . $result); + } else { + throw new ExpectationException( + 'Error field matches value - ' . $result, + $this->getSession()->getDriver() + ); + } + } + + return true; + }); + + $this->wait_for_pending_js(); + } + /** * Checks that the current header stripe in the app contains the expected text. * @@ -912,4 +948,17 @@ class behat_app extends behat_app_helper { } } + /** + * Open a browser tab with a certain URL. + * + * @Then /^I open a browser tab with url "(?P[^"]+)"$/ + * @param string $url URL + */ + public function i_open_a_browser_tab_with_url(string $url) { + $this->execute_script("window.open('$url', '_system');"); + + $windowNames = $this->getSession()->getWindowNames(); + $this->getSession()->switchToWindow($windowNames[1]); + } + } diff --git a/src/core/features/login/pages/credentials/credentials.html b/src/core/features/login/pages/credentials/credentials.html index 94e021f17..5ffbb5515 100644 --- a/src/core/features/login/pages/credentials/credentials.html +++ b/src/core/features/login/pages/credentials/credentials.html @@ -80,7 +80,7 @@ - + diff --git a/src/core/features/login/pages/email-signup/email-signup.html b/src/core/features/login/pages/email-signup/email-signup.html index 6037c7519..fa5eed501 100644 --- a/src/core/features/login/pages/email-signup/email-signup.html +++ b/src/core/features/login/pages/email-signup/email-signup.html @@ -146,7 +146,7 @@ {{ 'core.user.' + nameField | translate }} - diff --git a/src/core/features/login/tests/behat/signup.feature b/src/core/features/login/tests/behat/signup.feature new file mode 100755 index 000000000..68e991ff7 --- /dev/null +++ b/src/core/features/login/tests/behat/signup.feature @@ -0,0 +1,180 @@ +@auth @core_auth @app @javascript +Feature: Test signup in app + I need basic signup functionality to work + + Background: + Given the following config values are set as admin: + | registerauth | email | + | auth_instructions | These are the authentication instructions. | + | passwordpolicy | 0 | + + Scenario: View auth instructions even if signup is disabled + Given the following config values are set as admin: + | registerauth | | + When I launch the app + And I set the field "Your site" to "$WWWROOT" in the app + And I press "Connect to your site" in the app + Then I should find "Is this your first time here?" in the app + And I should find "These are the authentication instructions." in the app + But I should not find "Create new account" in the app + + Scenario: Basic signup + When I launch the app + + And I set the field "Your site" to "$WWWROOT" in the app + And I press "Connect to your site" in the app + Then I should find "Is this your first time here?" in the app + And I should find "These are the authentication instructions." in the app + + When I press "Create new account" in the app + Then I should find "New account" in the app + And I should find "Acceptance test site" in the app + But I should not find "These are the authentication instructions." in the app + + When I press "Instructions" in the app + Then I should find "These are the authentication instructions." in the app + + When I press "Close" in the app + And I press "Create my new account" in the app + Then I should find "Username required" in the app + And I should find "Password required" in the app + And I should find "Missing email address" in the app + And I should find "Missing given name" in the app + And I should find "Missing surname" in the app + + When I set the following fields to these values in the app: + | Username | u1 | + | Password | pu1 | + | Email address | u1@u1.com | + | Email (again) | u2@u1.com | + | First name | User | + | Surname | Test | + | City/town | Barcelona | + | Country | Spain | + Then I should find "Emails do not match" in the app + + When I set the field "Email (again)" to "u1@u1.com" in the app + And I press "Create my new account" in the app + Then I should find "An email should have been sent to your address" in the app + + # Login with the user to confirm the information is correct. + When I press "OK" in the app + And I set the following fields to these values in the app: + | Username | u1 | + | Password | pu1 | + And I press "Log in" near "Forgotten your username or password?" in the app + Then I should find "You need to confirm your account" in the app + + When I open a browser tab with url "$WWWROOT" + And I confirm email for "u1" + And I close the browser tab opened by the app + And I press "Close" in the app + And I press "Log in" near "Forgotten your username or password?" in the app + Then I should find "Acceptance test site" in the app + But I should not find "You need to confirm your account" in the app + + When I press the user menu button in the app + And I press "User Test" in the app + Then I should find "Barcelona, Spain" in the app + And I should find "u1@u1.com" in the app + + Scenario: Check password policy in signup + Given the following config values are set as admin: + | passwordpolicy | 1 | + | minpasswordlength | 8 | + | minpassworddigits | 1 | + | minpasswordlower | 1 | + | minpasswordupper | 1 | + | minpasswordnonalphanum | 1 | + When I launch the app + And I set the field "Your site" to "$WWWROOT" in the app + And I press "Connect to your site" in the app + And I press "Create new account" in the app + Then I should find "The password must have at least 8 characters" in the app + And I set the following fields to these values in the app: + | Username | u1 | + | Password | pu1 | + | Email address | u1@u1.com | + | Email (again) | u1@u1.com | + | First name | User | + | Surname | Test | + | City/town | Barcelona | + | Country | Spain | + And I press "Create my new account" in the app + Then I should find "Error" in the app + And I should find "Passwords must be at least 8 characters long" in the app + And I should find "Passwords must have at least 1 upper case letter(s)" in the app + And I should find "The password must have at least 1 special character(s)" in the app + But I should not find "An email should have been sent to your address" in the app + + When I press "OK" in the app + And I set the field "Password" to "Password1$" in the app + And I press "Create my new account" in the app + Then I should find "An email should have been sent to your address" in the app + + Scenario: Signup with custom profile fields + # Use default options Yes/No for menu field because it's not possible to add new lines. See MDL-75788. + Given the following "custom profile fields" exist: + | datatype | shortname | name | required | signup | defaultdata | + | menu | team | Are you a developer? | 1 | 1 | Yes | + And the following "custom profile fields" exist: + | datatype | shortname | name | required | signup | param1 | param2 | param3 | defaultdata | + | text | food | Favourite food | 1 | 1 | | | | Pasta | + | checkbox | vegetarian | Are you vegetarian? | 0 | 1 | | | | | + | datetime | birthday | Birthday | 1 | 1 | 1900 | 2040 | 0 | | + | datetime | time | Date and time | 0 | 1 | 1900 | 2040 | 1 | | + | textarea | description | Describe yourself | 0 | 1 | | | | Sample text | + | text | beverage | Favourite beverage | 0 | 0 | | | | | + + When I launch the app + And I set the field "Your site" to "$WWWROOT" in the app + And I press "Connect to your site" in the app + And I press "Create new account" in the app + Then I should find "Are you a developer?" in the app + And the field "Are you a developer?" matches value "Yes" in the app + And I should find "Favourite food" in the app + And the field "Favourite food" matches value "Pasta" in the app + And I should find "Birthday" in the app + And I should find "Date and time" in the app + And I should find "Describe yourself" in the app + And the field "Describe yourself" matches value "Sample text" in the app + But I should not find "Favourite beverage" in the app + + When I set the following fields to these values in the app: + | Username | u1 | + | Password | pu1 | + | Email address | u1@u1.com | + | Email (again) | u1@u1.com | + | First name | User | + | Surname | Test | + | City/town | Barcelona | + | Country | Spain | + And I press "Create my new account" in the app + Then I should find "Required" in the app + + When I set the field "Are you a developer?" to "No" in the app + And I set the field "Favourite food" to "Sushi" in the app + And I press "Are you vegetarian?" in the app + And I set the field "Birthday" to "1990-01-01" in the app + And I set the field "Date and time" to "2010-01-01 11:45" in the app + And I set the field "Describe yourself" to "This is my description." in the app + And I press "Create my new account" in the app + Then I should find "An email should have been sent to your address" in the app + + # Login with the user to confirm the information is correct. + When I open a browser tab with url "$WWWROOT" + And I confirm email for "u1" + And I close the browser tab opened by the app + And I press "OK" in the app + And I set the following fields to these values in the app: + | Username | u1 | + | Password | pu1 | + And I press "Log in" near "Forgotten your username or password?" in the app + And I press the user menu button in the app + And I press "User Test" in the app + Then I should find "No" near "Are you a developer?" in the app + And I should find "Sushi" in the app + And I should find "Yes" near "Are you vegetarian?" in the app + And I should find "1 January 1990" in the app + And I should find "1 January 2010, 11:45 AM" in the app + And I should find "This is my description" in the app diff --git a/src/testing/services/behat-dom.ts b/src/testing/services/behat-dom.ts index c856d44a0..f8bc231d6 100644 --- a/src/testing/services/behat-dom.ts +++ b/src/testing/services/behat-dom.ts @@ -351,7 +351,7 @@ export class TestingBehatDomUtilsService { findElementBasedOnText( locator: TestingBehatElementLocator, options: TestingBehatFindOptions, - ): HTMLElement { + ): HTMLElement | undefined { return this.findElementsBasedOnText(locator, options)[0]; } diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts index 6161c0fd3..cd491d22f 100644 --- a/src/testing/services/behat-runtime.ts +++ b/src/testing/services/behat-runtime.ts @@ -312,6 +312,10 @@ export class TestingBehatRuntimeService { try { const element = TestingBehatDomUtils.findElementBasedOnText(locator, { onlyClickable: false, containerName: '' }); + if (!element) { + return 'ERROR: No element matches locator to find.'; + } + return TestingBehatDomUtils.isElementSelected(element, document.body) ? 'YES' : 'NO'; } catch (error) { return 'ERROR: ' + error.message; @@ -403,10 +407,7 @@ export class TestingBehatRuntimeService { async setField(field: string, value: string): Promise { this.log('Action - Set field ' + field + ' to: ' + value); - const found: HTMLElement | HTMLInputElement = TestingBehatDomUtils.findElementBasedOnText( - { text: field, selector: 'input, textarea, [contenteditable="true"], ion-select' }, - { onlyClickable: false, containerName: '' }, - ); + const found = this.findField(field); if (!found) { return 'ERROR: No element matches field to set.'; @@ -417,6 +418,45 @@ export class TestingBehatRuntimeService { return 'OK'; } + /** + * Sets the text of a field to the specified value. + * + * This currently matches fields only based on the placeholder attribute. + * + * @param field Field name + * @param value New value + * @return OK or ERROR: followed by message + */ + async fieldMatches(field: string, value: string): Promise { + this.log('Action - Field ' + field + ' matches value: ' + value); + + const found = this.findField(field); + + if (!found) { + return 'ERROR: No element matches field to set.'; + } + + const foundValue = 'value' in found ? found.value : found.innerText; + if (value !== foundValue) { + return `ERROR: Expecting value "${value}", found "${foundValue}" instead.`; + } + + return 'OK'; + } + + /** + * Find a field. + * + * @param field Field name. + * @return Field element. + */ + protected findField(field: string): HTMLElement | HTMLInputElement | undefined { + return TestingBehatDomUtils.findElementBasedOnText( + { text: field, selector: 'input, textarea, [contenteditable="true"], ion-select, ion-datetime' }, + { onlyClickable: false, containerName: '' }, + ); + } + /** * Get an Angular component instance. *