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 @@
-
+
{{ 'core.login.firsttime' | translate }}
@@ -93,7 +93,7 @@
-
+
{{ 'core.login.startsignup' | translate }}
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.
*