From 63c503c9f7f7f7ae5c3a5bc6e68dfa94ee40fb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Carden=CC=83a?= <35935591+luisecm@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:26:32 -0600 Subject: [PATCH] chore(ci): attempt to run parallel tests for mobile and desktop viewports --- .github/workflows/playwright-matrix.yml | 137 +++++++++++++++++++ playwright.config.ts | 29 +++- playwright/PageObjects/MainPage.ts | 16 ++- playwright/specs/07-settings-profile.spec.ts | 35 ++++- 4 files changed, 205 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/playwright-matrix.yml diff --git a/.github/workflows/playwright-matrix.yml b/.github/workflows/playwright-matrix.yml new file mode 100644 index 00000000..328f7f47 --- /dev/null +++ b/.github/workflows/playwright-matrix.yml @@ -0,0 +1,137 @@ +name: Playwright Tests + +on: + pull_request: + paths-ignore: + - ".github/workflows/**" + workflow_dispatch: + +jobs: + test: + runs-on: macos-14 + strategy: + matrix: + project: [desktop-chrome, mobile-chrome, mobile-safari] + steps: + - name: Checkout Uplink Web directory + uses: actions/checkout@v4 + with: + repository: Satellite-im/UplinkWeb + + - name: Checkout Automated Tests directory + uses: actions/checkout@v4 + with: + path: automated-tests + + - name: Setup Node.js for Uplink Web + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies for Uplink Web + run: npm install + + - name: Install dependencies for Testing Repo + working-directory: automated-tests + run: npm install + + - name: Install Playwright Browsers + working-directory: automated-tests + run: npx playwright install --with-deps + + - name: Run server for Uplink Web + run: npm run dev & + + - name: Run Playwright tests for Desktop + if: matrix.project == 'desktop-chrome' + working-directory: automated-tests + run: | + PLAYWRIGHT_JSON_OUTPUT_NAME=report.json npx playwright test --project=${{ matrix.project }} + + - name: Run Playwright tests for Mobile Chrome and Safari (Single Test File) + if: matrix.project == 'mobile-chrome' || matrix.project == 'mobile-safari' + working-directory: automated-tests + run: | + PLAYWRIGHT_JSON_OUTPUT_NAME=report.json npx playwright test ./automated-tests/playwright/specs/07-settings-profile.spec.ts --project=${{ matrix.project }} + + - name: Upload Playwright report + uses: actions/upload-artifact@v4 + with: + name: playwright-report-${{ matrix.project }} + path: automated-tests/playwright-report/ + + - name: Upload Allure results + uses: actions/upload-artifact@v4 + with: + name: allure-results-${{ matrix.project }} + path: automated-tests/allure-results/ + + - name: Add label if any of build jobs failed + if: failure() + uses: buildsville/add-remove-label@v2.0.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + labels: | + Failed Automated Test + type: add + + merge-reports: + runs-on: ubuntu-latest + needs: test + steps: + - name: Download Playwright reports + uses: actions/download-artifact@v4 + with: + name: playwright-report-* + path: ./playwright-reports/ + + - name: Download Allure results + uses: actions/download-artifact@v4 + with: + name: allure-results-* + path: ./allure-results/ + + - name: Generate Allure report + run: | + npx allure generate ./allure-results --clean -o allure-report + + - name: Generate Playwright HTML report + run: | + npx playwright show-report ./playwright-reports + + - name: Upload Allure report to GitHub Pages + uses: peaceiris/actions-gh-pages@v4 + with: + deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} + publish_branch: gh-pages + publish_dir: allure-report + + - name: Comment PR with Test Results Summary + if: github.event_name == 'pull_request' + uses: mshick/add-pr-comment@v2 + with: + message: | + Playwright test execution is complete! + - Playwright report: [here](https://github.io/playwright-report) + - Allure report: [here](https://your-gh-pages-url) + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + finalize-label: + needs: [test, merge-reports] + runs-on: ubuntu-latest + permissions: + checks: write + pull-requests: write + contents: write + issues: read + + steps: + - name: Remove label if all tests succeeded + if: success() + uses: buildsville/add-remove-label@v2.0.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + labels: | + Failed Automated Test + type: remove diff --git a/playwright.config.ts b/playwright.config.ts index d13d97e9..5a3ee9dd 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -46,15 +46,30 @@ export default defineConfig({ /* Configure projects for major browsers */ projects: [ { - name: "Automated Tests on Chrome Desktop", - use: { ...devices["Desktop Chrome"] }, + name: "desktop-chrome", + use: { + browserName: "chromium", + viewport: { width: 1280, height: 720 }, // Desktop viewport + }, }, - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, + // Mobile Chrome (Pixel 5) + { + name: "mobile-chrome", + use: { + browserName: "chromium", + ...devices["Pixel 5"], // Use predefined mobile device + }, + }, + + // iPhone 12 (Safari) + { + name: "mobile-safari", + use: { + browserName: "webkit", + ...devices["iPhone 12"], // Use predefined iPhone 12 device + }, + }, // { // name: 'Mobile Safari', // use: { ...devices['iPhone 12'] }, diff --git a/playwright/PageObjects/MainPage.ts b/playwright/PageObjects/MainPage.ts index cdbf23d5..0bfc171c 100644 --- a/playwright/PageObjects/MainPage.ts +++ b/playwright/PageObjects/MainPage.ts @@ -2,6 +2,7 @@ import { expect, type Locator, type Page } from "@playwright/test"; export default class MainPage { readonly buttonChat: Locator; + readonly buttonDismissInstallAlert: Locator; readonly buttonFiles: Locator; readonly buttonFriends: Locator; readonly buttonHideSidebar: Locator; @@ -23,6 +24,7 @@ export default class MainPage { readonly favoriteProfilePicture: Locator; readonly favoriteProfileStatusIndicator: Locator; readonly favoritesLabel: Locator; + readonly installAlert: Locator; readonly inputSidebarSearch: Locator; readonly navigationBar: Locator; readonly sidebar: Locator; @@ -35,13 +37,17 @@ export default class MainPage { constructor(public readonly page: Page) { this.buttonChat = this.page.getByTestId("button-Chat"); + this.buttonDismissInstallAlert = this.page + .locator("#install-banner") + .getByRole("button") + .first(); this.buttonFiles = this.page.getByTestId("button-Files"); this.buttonFriends = this.page.getByTestId("button-Friends"); this.buttonHideSidebar = this.page.getByTestId("button-hide-sidebar"); this.buttonSettings = this.page.getByTestId("button-Settings"); this.buttonShowSidebar = this.page - .getByTestId("button-show-sidebar") - .first(); + .getByTestId("topbar") + .getByTestId("button-show-sidebar"); this.buttonSidebarChats = this.page.getByTestId("button-sidebar-chats"); this.buttonSidebarFiles = this.page.getByTestId("button-sidebar-files"); this.buttonWallet = this.page.getByTestId("button-Wallet"); @@ -66,6 +72,7 @@ export default class MainPage { this.favoriteProfileStatusIndicator = this.favoriteProfilePicture.getByTestId("status-indicator"); this.favoritesLabel = this.page.getByTestId("label-favorites"); + this.installAlert = this.page.locator("#install-banner"); this.inputSidebarSearch = this.page.getByTestId("input-sidebar-search"); this.navigationBar = this.page.getByTestId(".navigation"); this.sidebar = this.page.getByTestId("sidebar"); @@ -113,6 +120,11 @@ export default class MainPage { await this.toastNotificationButton.click(); } + async dismissDownloadAlert() { + await this.buttonDismissInstallAlert.click(); + await this.installAlert.waitFor({ state: "detached" }); + } + async expectElementToHaveClass(selector: string, className: string) { const element = this.page.locator(selector); const hasClass = await element.evaluate( diff --git a/playwright/specs/07-settings-profile.spec.ts b/playwright/specs/07-settings-profile.spec.ts index eb952df7..a4abc19e 100644 --- a/playwright/specs/07-settings-profile.spec.ts +++ b/playwright/specs/07-settings-profile.spec.ts @@ -6,11 +6,18 @@ test.describe("Settings Profile Tests", () => { const username = "test123"; const status = "fixed status"; - test.beforeEach(async ({ singleUserContext }) => { + test.beforeEach(async ({ singleUserContext }, testoptions) => { const page = singleUserContext.page; const chatsMainPage = new ChatsMainPage(page); + await chatsMainPage.dismissDownloadAlert(); await chatsMainPage.goToSettings(); await page.waitForURL("/settings/profile"); + const viewport = testoptions.project.name; + + // Hide sidebar if viewport is Mobile Chrome + if (viewport === "Mobile Chrome") { + await chatsMainPage.buttonHideSidebar.click(); + } }); test("I1 - Banner Picture - Tooltip displayed", async ({ @@ -163,10 +170,11 @@ test.describe("Settings Profile Tests", () => { test("I9, I10 - User should be able to change username and see toast notification of change", async ({ singleUserContext, - }) => { + }, testoptions) => { const page = singleUserContext.page; const settingsProfile = new SettingsProfile(page); const chatsMainPage = new ChatsMainPage(page); + const viewport = testoptions.project.name; // User types into username and change value const newUsername = "newUsername"; @@ -200,10 +208,20 @@ test.describe("Settings Profile Tests", () => { newUsername, ); + // Show sidebar if viewport is Mobile Chrome + if (viewport === "Mobile Chrome") { + await settingsProfile.buttonShowSidebar.click(); + } + // User goes to another page and returns to settings profile, username is still changed await settingsProfile.goToFriends(); await page.waitForURL("/friends"); await chatsMainPage.goToSettings(); + + // Hide sidebar if viewport is Mobile Chrome + if (viewport === "Mobile Chrome") { + await settingsProfile.buttonHideSidebar.click(); + } await expect(settingsProfile.inputSettingsProfileUsername).toHaveValue( newUsername, ); @@ -293,10 +311,11 @@ test.describe("Settings Profile Tests", () => { test("I15, I16 - User should be able to change Status Message and see toast notification for update", async ({ singleUserContext, - }) => { + }, testoptions) => { const page = singleUserContext.page; const settingsProfile = new SettingsProfile(page); const chatsMainPage = new ChatsMainPage(page); + const viewport = testoptions.project.name; // User types into username and change value const newStatus = "this is my new status"; @@ -330,10 +349,20 @@ test.describe("Settings Profile Tests", () => { newStatus, ); + // Show sidebar if viewport is Mobile Chrome + if (viewport === "Mobile Chrome") { + await settingsProfile.buttonShowSidebar.click(); + } + // User goes to another page and returns to settings profile, username is still changed await settingsProfile.goToFriends(); await page.waitForURL("/friends"); await chatsMainPage.goToSettings(); + + // Hide sidebar if viewport is Mobile Chrome + if (viewport === "Mobile Chrome") { + await settingsProfile.buttonHideSidebar.click(); + } await expect(settingsProfile.inputSettingsProfileStatus).toHaveValue( newStatus, );