diff --git a/e2e-tests/.gitignore b/e2e-tests/.gitignore index 0d29725c0..405b844c5 100644 --- a/e2e-tests/.gitignore +++ b/e2e-tests/.gitignore @@ -3,4 +3,4 @@ cypress/screenshots/ cypress/videos/ cypress/reports/ cucumber-messages.ndjson - +**/target diff --git a/e2e-tests/playwright/Dockerfile b/e2e-tests/playwright/Dockerfile deleted file mode 100644 index c0dfbde47..000000000 --- a/e2e-tests/playwright/Dockerfile +++ /dev/null @@ -1,42 +0,0 @@ -############################################################################### -# Dockerfile to create a ready-to-use Playwright Docker image for end-to-end -# testing. -# -# To avoid hardcoded versoning of Playwright, this Dockerfile is a custom -# version of the ready-to-use Dockerfile privided by Playwright developement -# (https://github.com/microsoft/playwright/blob/main/utils/docker/Dockerfile.focal) -# -# Here the latest stable versions of the browsers Chromium, Firefox, and Webkit -# (Safari) are installed, icluding all dependencies based on Ubuntu specified by -# Playwright developement. -############################################################################### - -FROM ubuntu:focal - -# set a timezone for the Playwright browser dependency installation -ARG TZ=Europe/Berlin - -ARG DOCKER_WORKDIR=/tests/ -WORKDIR $DOCKER_WORKDIR - -# package manager preparation -RUN apt-get -qq update && apt-get install -qq -y curl gpg > /dev/null -# for Node.js -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - -# for Yarn -RUN curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ - echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list - -# install node v16 and Yarn -RUN apt-get -qq update && apt-get install -qq -y nodejs yarn - -COPY tests/package.json tests/yarn.lock $DOCKER_WORKDIR - -# install Playwright with all dependencies -# for the browsers chromium, firefox, and webkit -RUN yarn install && yarn playwright install --with-deps - -# clean up -RUN rm -rf /var/lib/apt/lists/* && apt-get -qq clean - -COPY tests/ $DOCKER_WORKDIR diff --git a/e2e-tests/playwright/README.md b/e2e-tests/playwright/README.md deleted file mode 100644 index a3a2b34bb..000000000 --- a/e2e-tests/playwright/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Gradido End-to-End Testing with [Playwright](https://playwright.dev/) (CI-ready via Docker) - - -A sample setup to show-case Playwright (using Typescript) as an end-to-end testing tool for Gradido runniing in a Docker container. -Here we have a simple UI-based happy path login test running against the DEV system. - -## Precondition -Since dependencies and configurations for Github Actions integration is not set up yet, please run in root directory - -```bash -docker-compose up -``` - -to boot up the DEV system, before running the test. - -## Execute the test - -```bash -# build a Docker image from the Dockerfile -docker build -t gradido_e2e-tests-playwright . - -# run the Docker container and execute the given tests -docker run -it --network=host gradido_e2e-tests-playwright yarn playwright-e2e-tests -``` diff --git a/e2e-tests/playwright/java/Readme.md b/e2e-tests/playwright/java/Readme.md new file mode 100644 index 000000000..68aebae3d --- /dev/null +++ b/e2e-tests/playwright/java/Readme.md @@ -0,0 +1,12 @@ +# gradido-e2e-tests-playwright with java + +Experimental End-to-end tests with Playwright and Java + +## Prerequisites + +- Java 17 +- Maven +- Playwright +- Gradle +- Git + diff --git a/e2e-tests/playwright/java/pom.xml b/e2e-tests/playwright/java/pom.xml new file mode 100644 index 000000000..4e8b82d8c --- /dev/null +++ b/e2e-tests/playwright/java/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + net.gradido + gradido-e2e-tests-playwright + 0.0.1 + Gradido Playwright End-to-End Tests in Java + + UTF-8 + 17 + 17 + + + + com.microsoft.playwright + playwright + 1.52.0 + + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + + 17 + 17 + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M9 + + + **/*Test*.java + + + + + + \ No newline at end of file diff --git a/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/base/BaseTest.java b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/base/BaseTest.java new file mode 100644 index 000000000..b3449e5b0 --- /dev/null +++ b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/base/BaseTest.java @@ -0,0 +1,68 @@ +package net.gradido.e2e.base; + +import com.microsoft.playwright.Browser; +import com.microsoft.playwright.BrowserContext; +import com.microsoft.playwright.Playwright; +import com.microsoft.playwright.Page; +import com.microsoft.playwright.Tracing; +import org.junit.jupiter.api.*; +import java.nio.file.Path; +import java.nio.file.Paths; + +// Subclasses will inherit PER_CLASS behavior. +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class BaseTest { + protected Playwright playwright; + protected Browser browser; + + @BeforeAll + void setUpAll() { + playwright = Playwright.create(); + browser = playwright.chromium().launch(); + } + + @AfterAll + void tearDownAll() { + playwright.close(); + } + + // New instance for each test method. + protected BrowserContext context; + protected Page page; + protected Path currentTracePath; + + @BeforeEach + void setUp(TestInfo testInfo) { + context = browser.newContext( + new Browser.NewContextOptions().setBaseURL("http://localhost:3000") + ); + context.route("**/*", route -> { + String url = route.request().url(); + + // we skip fontawesome and googleapis requests, we don't need them for functions test, but they cost time + if (url.contains("use.fontawesome.com") || url.contains("fonts.googleapis.com")) { + route.abort(); + return; + } + route.resume(); + }); + + // Start tracing before creating + String testName = testInfo.getDisplayName().replaceAll("[^a-zA-Z0-9]", ""); + currentTracePath = Paths.get("target/traces/" + testName + ".zip"); + context.tracing().start(new Tracing.StartOptions() + .setScreenshots(true) + .setSnapshots(true) + .setSources(true)); + page = context.newPage(); + } + + @AfterEach + void tearDown() { + // Stop tracing and export it into a zip archive. + context.tracing().stop(new Tracing.StopOptions().setPath(currentTracePath)); + + page.close(); + context.close(); + } +} \ No newline at end of file diff --git a/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/components/Toasts.java b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/components/Toasts.java new file mode 100644 index 000000000..6e95e95ef --- /dev/null +++ b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/components/Toasts.java @@ -0,0 +1,29 @@ +package net.gradido.e2e.components; + +import com.microsoft.playwright.Locator; +import com.microsoft.playwright.Page; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class Toasts { + private final Page page; + + public final Locator toastSlot; + public final Locator toastTypeError; + public final Locator toastTitle; + public final Locator toastMessage; + + public Toasts(Page page) { + this.page = page; + toastSlot = page.locator("#__BVID__toaster-container"); + toastTypeError = toastSlot.locator(".toast.text-bg-danger"); + toastTitle = toastTypeError.locator(".gdd-toaster-title"); + toastMessage = toastTypeError.locator(".gdd-toaster-body"); + } + + public void assertErrorToastVisible() { + toastTypeError.waitFor(); // auf Fehler-Toast warten + assertTrue(toastTitle.isVisible()); + assertTrue(toastMessage.isVisible()); + } +} diff --git a/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/pages/LoginPage.java b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/pages/LoginPage.java new file mode 100644 index 000000000..091c346bf --- /dev/null +++ b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/pages/LoginPage.java @@ -0,0 +1,28 @@ +package net.gradido.e2e.pages; + +import com.microsoft.playwright.Locator; +import com.microsoft.playwright.Page; +import com.microsoft.playwright.Response; + +public class LoginPage { + private final Page page; + + private final Locator emailInput; + private final Locator passwordInput; + private final Locator submitButton; + + public LoginPage(Page page) { + this.page = page; + emailInput = page.locator("input[name='email']"); + passwordInput = page.locator("input[name='password']"); + submitButton = page.locator("button[type='submit']"); + } + + public void login(String email, String password) { + emailInput.fill(email); + passwordInput.fill(password); + Response response = page.waitForResponse("**/graphql", () -> { + submitButton.click(); + }); + } +} \ No newline at end of file diff --git a/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/tests/DashboardTests.java b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/tests/DashboardTests.java new file mode 100644 index 000000000..e69de29bb diff --git a/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/tests/InvalidLoginTest.java b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/tests/InvalidLoginTest.java new file mode 100644 index 000000000..b8168aaec --- /dev/null +++ b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/tests/InvalidLoginTest.java @@ -0,0 +1,26 @@ +package net.gradido.e2e.tests; + +import net.gradido.e2e.base.BaseTest; +import net.gradido.e2e.pages.LoginPage; +import net.gradido.e2e.components.Toasts; +import org.junit.jupiter.api.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class InvalidLoginTest extends BaseTest { + private LoginPage loginPage; + + @BeforeEach + void initPageObjects() { + loginPage = new LoginPage(page); + } + + @Test + void invalidUserSeesError() { + page.navigate("http://localhost:3000/login"); + loginPage.login("peter@lustig.de", "wrongpass"); + Toasts toast = new Toasts(page); + toast.assertErrorToastVisible(); + } +} \ No newline at end of file diff --git a/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/tests/ValidLoginTest.java b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/tests/ValidLoginTest.java new file mode 100644 index 000000000..92f0e82fc --- /dev/null +++ b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/tests/ValidLoginTest.java @@ -0,0 +1,28 @@ +package net.gradido.e2e.tests; + +import net.gradido.e2e.base.BaseTest; +import net.gradido.e2e.pages.LoginPage; +import net.gradido.e2e.components.Toasts; + +import org.junit.jupiter.api.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ValidLoginTest extends BaseTest { + private LoginPage loginPage; + + @BeforeEach + void initPageObjects() { + loginPage = new LoginPage(page); + } + + @Test + void validUserCanLogin() { + page.navigate("http://localhost:3000/login"); + loginPage.login("peter@lustig.de", "Aa12345_"); + page.waitForURL("http://localhost:3000/overview"); + assertTrue(page.url().contains("/overview")); + } +} + diff --git a/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/utils/TestUtil.java b/e2e-tests/playwright/java/src/test/java/net/gradido/e2e/utils/TestUtil.java new file mode 100644 index 000000000..e69de29bb diff --git a/e2e-tests/playwright/java/src/test/resources/junit-platform.properties b/e2e-tests/playwright/java/src/test/resources/junit-platform.properties new file mode 100644 index 000000000..4570caf06 --- /dev/null +++ b/e2e-tests/playwright/java/src/test/resources/junit-platform.properties @@ -0,0 +1,5 @@ +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = same_thread +junit.jupiter.execution.parallel.mode.classes.default = concurrent +junit.jupiter.execution.parallel.config.strategy=dynamic +junit.jupiter.execution.parallel.config.dynamic.factor=0.5 \ No newline at end of file diff --git a/e2e-tests/playwright/tests/global-setup.ts b/e2e-tests/playwright/tests/global-setup.ts deleted file mode 100644 index 1581a9aea..000000000 --- a/e2e-tests/playwright/tests/global-setup.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { FullConfig } from '@playwright/test'; - -async function globalSetup(config: FullConfig) { - process.env.EMAIL = 'bibi@bloxberg.de'; - process.env.PASSWORD = 'Aa12345_'; - process.env.GMS_ACTIVE = false; - process.env.HUMHUB_ACTIVE = false; -} - -export default globalSetup; diff --git a/e2e-tests/playwright/tests/gradido_login.spec.ts b/e2e-tests/playwright/tests/gradido_login.spec.ts deleted file mode 100644 index 0853780d1..000000000 --- a/e2e-tests/playwright/tests/gradido_login.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { test, expect } from '@playwright/test'; -import { LoginPage } from './models/login_page'; -import { WelcomePage } from './models/welcome_page'; - - -test('Gradido login test (happy path)', async ({ page }) => { - const { EMAIL, PASSWORD } = process.env; - const loginPage = new LoginPage(page); - await loginPage.goto(); - await loginPage.enterEmail(EMAIL); - await loginPage.enterPassword(PASSWORD); - await loginPage.submitLogin(); - // assertions - await expect(page).toHaveURL('./overview'); -}); diff --git a/e2e-tests/playwright/tests/models/login_page.ts b/e2e-tests/playwright/tests/models/login_page.ts deleted file mode 100644 index 50abb4933..000000000 --- a/e2e-tests/playwright/tests/models/login_page.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { expect, test, Locator, Page } from '@playwright/test'; - -export class LoginPage { - readonly page: Page; - readonly url: string; - readonly emailInput: Locator; - readonly passwordInput: Locator; - readonly submitBtn: Locator; - - constructor(page: Page) { - this.page = page; - this.url = './login'; - this.emailInput = page.locator('id=Email-input-field'); - this.passwordInput = page.locator('id=Password-input-field'); - this.submitBtn = page.locator('text=Login'); - } - - async goto() { - await this.page.goto(this.url); - } - - async enterEmail(email: string) { - await this.emailInput.fill(email); - } - - async enterPassword(password: string) { - await this.passwordInput.fill(password); - } - - async submitLogin() { - await this.submitBtn.click(); - } -} diff --git a/e2e-tests/playwright/tests/models/welcome_page.ts b/e2e-tests/playwright/tests/models/welcome_page.ts deleted file mode 100644 index 81d73a771..000000000 --- a/e2e-tests/playwright/tests/models/welcome_page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { expect, Locator, Page } from '@playwright/test'; - -export class WelcomePage { - readonly page: Page; - readonly url: string; - readonly profileLink: Locator; - - constructor(page: Page){ - this.page = page; - this.url = './overview'; - this.profileLink = page.locator('href=/profile'); - } -} diff --git a/e2e-tests/playwright/tests/playwright.config.ts b/e2e-tests/playwright/tests/playwright.config.ts deleted file mode 100644 index 13ea41d89..000000000 --- a/e2e-tests/playwright/tests/playwright.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { PlaywrightTestConfig } from '@playwright/test'; - -const config: PlaywrightTestConfig = { - globalSetup: require.resolve('./global-setup'), - ignoreHTTPSErrors: true, - locale: 'de-DE', - reporter: process.env.CI ? 'github' : 'list', - retries: 1, - screenshot: 'only-on-failure', - testDir: '.', - timeout: 30000, - trace: 'on-first-retry', - video: 'never', - viewport: { width: 1280, height: 720 }, - use: { - baseURL: process.env.URL || 'http://127.0.0.1:3000', - browserName: 'webkit', - - }, -}; -export default config;