Merge branch 'master' into 2109-Typo-im-Dialog

This commit is contained in:
Alexander Friedland 2022-09-29 14:36:36 +02:00 committed by GitHub
commit aea4057df1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 132 additions and 23 deletions

View File

@ -1,24 +1,73 @@
# Gradido End-to-End Testing with [Cypress](https://www.cypress.io/) (CI-ready via Docker) # Gradido End-to-End Testing with [Cypress](https://www.cypress.io/) (CI-ready via Docker)
A setup to show-case Cypress as an end-to-end testing tool for Gradido running in a Docker container.
The tests are organized in feature files written in Gherkin syntax.
## Features under test
So far these features are initially tested
- [User authentication](https://github.com/gradido/gradido/blob/master/e2e-tests/cypress/tests/cypress/e2e/User.Authentication.feature)
- [User profile - change password](https://github.com/gradido/gradido/blob/master/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword.feature)
- [User registration]((https://github.com/gradido/gradido/blob/master/e2e-tests/cypress/tests/cypress/e2e/User.Registration.feature)) (WIP)
A sample setup to show-case Cypress as an end-to-end testing tool for Gradido running in a Docker container.
Here we have a simple UI-based happy path login test running against the DEV system.
## Precondition ## Precondition
Since dependencies and configurations for Github Actions integration is not set up yet, please run in root directory
Before running the tests, change to the repo's root directory (gradido).
### Boot up the system under test
```bash ```bash
docker-compose up docker-compose up
``` ```
to boot up the DEV system, before running the test. ### Seed the database
The database has to be seeded upfront to every test run.
```bash
# change to the backend directory
cd /path/to/gradido/gradido/backend
# install all dependencies
yarn
# seed the database (everytime before running the tests)
yarn seed
```
## Execute the test ## Execute the test
This setup will be integrated in the Gradido Github Actions to automatically support the CI/CD process.
For now the test setup can only be used locally in two modes.
### Run Cypress directly from the code
```bash ```bash
# change to the tests directory
cd /path/to/gradido/e2e-tests/cypress/tests
# install all dependencies
yarn install
# a) run the tests on command line
yarn cypress run
# b) open the Cypress GUI to run the tests in interactive mode
yarn cypress open
```
### Run Cyprss from a separate Docker container
```bash
# change to the cypress directory
cd /path/to/gradido/e2e-tests/cypress/
# build a Docker image from the Dockerfile # build a Docker image from the Dockerfile
docker build -t gradido_e2e-tests-cypress . docker build -t gradido_e2e-tests-cypress .
# run the Docker container and execute the given tests # run the Docker image and execute the given tests
docker run -it --network=host gradido_e2e-tests-cypress yarn run cypress-e2e-tests docker run -it --network=host gradido_e2e-tests-cypress yarn cypress-e2e
``` ```

View File

@ -32,6 +32,7 @@ export default defineConfig({
excludeSpecPattern: "*.js", excludeSpecPattern: "*.js",
baseUrl: "http://localhost:3000", baseUrl: "http://localhost:3000",
chromeWebSecurity: false, chromeWebSecurity: false,
defaultCommandTimeout: 10000,
supportFile: "cypress/support/index.ts", supportFile: "cypress/support/index.ts",
viewportHeight: 720, viewportHeight: 720,
viewportWidth: 1280, viewportWidth: 1280,

View File

@ -0,0 +1,13 @@
Feature: User registration
As a user
I want to register to create an account
@skip
Scenario: Register successfully
Given the browser navigates to page "/register"
When the user fills name and email "Regina" "Register" "regina@register.com"
And the user agrees to the privacy policy
And the user submits the registration form
Then the user can use a provided activation link
And the user can set a password "Aa12345_"
And the user can login with the credentials "regina@register.com" "Aa12345_"

View File

@ -2,8 +2,8 @@
export class LoginPage { export class LoginPage {
// selectors // selectors
emailInput = "#Email-input-field"; emailInput = "input[type=email]";
passwordInput = "#Password-input-field"; passwordInput = "input[type=password]";
submitBtn = "[type=submit]"; submitBtn = "[type=submit]";
emailHint = "#vee_Email"; emailHint = "#vee_Email";
passwordHint = "#vee_Password"; passwordHint = "#vee_Password";

View File

@ -4,8 +4,8 @@ export class ProfilePage {
// selectors // selectors
openChangePassword = "[data-test=open-password-change-form]"; openChangePassword = "[data-test=open-password-change-form]";
oldPasswordInput = "#password-input-field"; oldPasswordInput = "#password-input-field";
newPasswordInput = "#New-password-input-field"; newPasswordInput = "#new-password-input-field";
newPasswordRepeatInput = "#Repeat-new-password-input-field"; newPasswordRepeatInput = "#repeat-new-password-input-field";
submitNewPasswordBtn = "[data-test=submit-new-password-btn]"; submitNewPasswordBtn = "[data-test=submit-new-password-btn]";
goto() { goto() {
@ -19,12 +19,12 @@ export class ProfilePage {
} }
enterNewPassword(password: string) { enterNewPassword(password: string) {
cy.get(this.newPasswordInput).clear().type(password); cy.get(this.newPasswordInput).find("input").clear().type(password);
return this; return this;
} }
enterRepeatPassword(password: string) { enterRepeatPassword(password: string) {
cy.get(this.newPasswordRepeatInput).clear().type(password); cy.get(this.newPasswordRepeatInput).find("input").clear().type(password);
return this; return this;
} }

View File

@ -0,0 +1,42 @@
/// <reference types="cypress" />
export class RegistrationPage {
// selectors
firstnameInput = "#registerFirstname";
lastnameInput = "#registerLastname";
emailInput = "#Email-input-field";
checkbox = "#registerCheckbox";
submitBtn = "[type=submit]";
RegistrationThanxHeadline = ".test-message-headline";
RegistrationThanxText = ".test-message-subtitle";
goto() {
cy.visit("/register");
return this;
}
enterFirstname(firstname: string) {
cy.get(this.firstnameInput).clear().type(firstname);
return this;
}
enterLastname(lastname: string) {
cy.get(this.lastnameInput).clear().type(lastname);
return this;
}
enterEmail(email: string) {
cy.get(this.emailInput).clear().type(email);
return this;
}
checkPrivacyCheckbox() {
cy.get(this.checkbox).click({ force: true });
}
submitRegistrationPage() {
cy.get(this.submitBtn).should("be.enabled");
cy.get(this.submitBtn).click();
}
}

View File

@ -2,6 +2,9 @@
export class Toasts { export class Toasts {
// selectors // selectors
toastSlot = ".b-toaster-slot";
toastTypeSuccess = ".b-toast-success";
toastTypeError = ".b-toast-danger";
toastTitle = ".gdd-toaster-title"; toastTitle = ".gdd-toaster-title";
toastMessage = ".gdd-toaster-body"; toastMessage = ".gdd-toaster-body";
} }

View File

@ -25,11 +25,11 @@ Then("the user is logged in with username {string}", (username: string) => {
Then("the user cannot login", () => { Then("the user cannot login", () => {
const toast = new Toasts(); const toast = new Toasts();
cy.get(toast.toastTitle).should("contain.text", "Error!"); cy.get(toast.toastSlot).within(() => {
cy.get(toast.toastMessage).should( cy.get(toast.toastTypeError);
"contain.text", cy.get(toast.toastTitle).should("be.visible");
"No user with this credentials." cy.get(toast.toastMessage).should("be.visible");
); });
}); });
// //

View File

@ -24,9 +24,9 @@ And("the user submits the password form", () => {
When("the user is presented a {string} message", (type: string) => { When("the user is presented a {string} message", (type: string) => {
const toast = new Toasts(); const toast = new Toasts();
cy.get(toast.toastTitle).should("contain.text", "Success"); cy.get(toast.toastSlot).within(() => {
cy.get(toast.toastMessage).should( cy.get(toast.toastTypeSuccess);
"contain.text", cy.get(toast.toastTitle).should("be.visible");
"Your password has been changed." cy.get(toast.toastMessage).should("be.visible");
); });
}); });

View File

@ -14,7 +14,7 @@
} }
}, },
"scripts": { "scripts": {
"cypress": "cypress run", "cypress-e2e": "cypress run",
"lint": "eslint --max-warnings=0 --ext .js,.ts ." "lint": "eslint --max-warnings=0 --ext .js,.ts ."
}, },
"dependencies": { "dependencies": {

View File

@ -29,6 +29,7 @@
required: true, required: true,
samePassword: value.password, samePassword: value.password,
}" }"
id="repeat-new-password-input-field"
:label="register ? $t('form.passwordRepeat') : $t('form.password_new_repeat')" :label="register ? $t('form.passwordRepeat') : $t('form.password_new_repeat')"
:immediate="true" :immediate="true"
:name="createId(register ? $t('form.passwordRepeat') : $t('form.password_new_repeat'))" :name="createId(register ? $t('form.passwordRepeat') : $t('form.password_new_repeat'))"