Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[E2E] [QA] Optimizing playwright setup and playwright.config.ts files #4741

Merged
merged 10 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/sixty-colts-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"saleor-dashboard": minor
---

# Optimizing playwright setup and playwright.config.ts files

-Adding a conditioning to auth.setup.ts file to use existing auth json file if it's applicable
-Added some optimizations to playwright config file
-Cleaned up gh action for playwright tests (removed Cypress references)
-Updating gh workflow for PR automation with extra test sharding
-General cleanup of redundant code
14 changes: 11 additions & 3 deletions .github/actions/run-pw-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ inputs:
MAILPITURL:
description: "mailpit uri"
required: true
URL_TO_RUN:
URL_TO_RUN:
description: "Url which will be passed to testmo where can be found artifacts of the run"
required: false
PW_WORKERS:
description: "Playwright workers"
required: true
PW_RETRIES:
description: "Playwright retries"
required: true
Comment on lines +28 to +33
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is required, other jobs, which are using this action can fail: run-test-cron and run-test-manual.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karola312 fixed


runs:
using: "composite"
Expand All @@ -50,8 +56,10 @@ runs:
E2E_USER_PASSWORD: ${{ inputs.E2E_USER_PASSWORD }}
E2E_PERMISSIONS_USERS_PASSWORD: ${{ inputs.E2E_PERMISSIONS_USERS_PASSWORD }}
SHARD_NUMBER: ${{ inputs.SHARD }}
MAILPITURL: ${{ inputs.MAILPITURL }}
URL_TO_RUN: ${{ inputs.URL_TO_RUN }}
MAILPITURL: ${{ inputs.MAILPITURL }}
URL_TO_RUN: ${{ inputs.URL_TO_RUN }}
WORKERS: ${{ inputs.PW_WORKERS }}
RETRIES: ${{ inputs.PW_RETRIES }}
run: npm run qa:pw-e2e -- --shard "$SHARD_NUMBER"

- name: Upload blob report to GitHub Actions Artifacts
Expand Down
15 changes: 9 additions & 6 deletions .github/workflows/pr-automation.yml
yellowee marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,14 @@ jobs:
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
env: ${{ needs.initialize-cloud.outputs.POOL_NAME }}


run-tests:
runs-on: ubuntu-22.04
needs: [initialize-cloud, deploy-dashboard]
strategy:
fail-fast: false
matrix:
shard: [1/2, 2/2]
shard: [1/4, 2/4, 3/4, 4/4]
steps:
- uses: actions/checkout@v4

Expand All @@ -134,10 +135,12 @@ jobs:
SHARD: ${{ matrix.shard }}
BASE_URL: ${{ needs.initialize-cloud.outputs.BASE_URL }}
API_URL: ${{ needs.initialize-cloud.outputs.API_URL }}
E2E_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }}
E2E_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }}
E2E_PERMISSIONS_USERS_PASSWORD: ${{ secrets.CYPRESS_PERMISSIONS_USERS_PASSWORD }}
MAILPITURL: ${{ secrets.CYPRESS_MAILPITURL }}
E2E_USER_NAME: ${{ secrets.E2E_USER_NAME }}
E2E_USER_PASSWORD: ${{ secrets.E2E_USER_PASSWORD }}
E2E_PERMISSIONS_USERS_PASSWORD: ${{ secrets.E2E_PERMISSIONS_USERS_PASSWORD }}
MAILPITURL: ${{ secrets.MAILPITURL }}
szczecha marked this conversation as resolved.
Show resolved Hide resolved
PW_WORKERS: ${{ vars.PW_WORKERS }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PW_WORKERS: ${{ vars.PW_WORKERS }}
E2E_WORKERS: ${{ vars.PW_WORKERS }}

Maybe we can avoid hardcoding PW as env var name 🤔 so we won't have the same problem as with cypress

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrzejewsky can you take a look? You suggested using PW_WORKERS ;)

yellowee marked this conversation as resolved.
Show resolved Hide resolved
PW_RETRIES: ${{ vars.PW_RETRIES }}

merge-reports:
if: "!cancelled()"
Expand All @@ -147,4 +150,4 @@ jobs:
- uses: actions/checkout@v4

- name: Merge playwright reports
uses: ./.github/actions/merge-pw-reports
uses: ./.github/actions/merge-pw-reports
16 changes: 9 additions & 7 deletions .github/workflows/run-test-cron.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ jobs:
SHARD: ${{ matrix.shard }}
BASE_URL: ${{ needs.initialize-cloud.outputs.BASE_URL }}
API_URL: ${{ needs.initialize-cloud.outputs.API_URL }}
E2E_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }}
E2E_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }}
E2E_PERMISSIONS_USERS_PASSWORD: ${{ secrets.CYPRESS_PERMISSIONS_USERS_PASSWORD }}
MAILPITURL: ${{ secrets.CYPRESS_MAILPITURL }}
E2E_USER_NAME: ${{ secrets.E2E_USER_NAME }}
E2E_USER_PASSWORD: ${{ secrets.E2E_USER_PASSWORD }}
E2E_PERMISSIONS_USERS_PASSWORD: ${{ secrets.E2E_PERMISSIONS_USERS_PASSWORD }}
MAILPITURL: ${{ secrets.MAILPITURL }}
PW_WORKERS: ${{ vars.PW_WORKERS }}
PW_RETRIES: ${{ vars.PW_RETRIES }}
URL_TO_RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

- name: submit-results-to-testmo
Expand All @@ -97,7 +99,7 @@ jobs:

- name: Merge playwright reports
uses: ./.github/actions/merge-pw-reports

- name: complete testmo report
uses: ./.github/actions/testmo/testmo-finish
with:
Expand All @@ -122,6 +124,6 @@ jobs:
--slack_webhook_url "$slack_webhook_url" \
--environment "$environment" \
--url_to_action "$url_to_action" \
--ref_name "$ref_name"
--ref_name "$ref_name"


16 changes: 9 additions & 7 deletions .github/workflows/run-test-manual.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v4
with:
sparse-checkout: ./.github/actions

- name: Set variables mode
id: set_variables_mode
shell: bash
Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:
testmoToken: ${{ secrets.TESTMO_TOKEN }}
testmoRunName: "Playwright run ${{github.ref_name}}"
id: init-testmo

run-tests:
runs-on: ubuntu-22.04
needs: ["initialize-cloud", "create-run-on-testmo"]
Expand All @@ -81,10 +81,12 @@ jobs:
SHARD: ${{ matrix.shard }}
BASE_URL: ${{ needs.initialize-cloud.outputs.BASE_URL }}
API_URL: ${{ needs.initialize-cloud.outputs.API_URL }}
E2E_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }}
E2E_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }}
E2E_PERMISSIONS_USERS_PASSWORD: ${{ secrets.CYPRESS_PERMISSIONS_USERS_PASSWORD }}
MAILPITURL: ${{ secrets.CYPRESS_MAILPITURL }}
E2E_USER_NAME: ${{ secrets.E2E_USER_NAME }}
E2E_USER_PASSWORD: ${{ secrets.E2E_USER_PASSWORD }}
E2E_PERMISSIONS_USERS_PASSWORD: ${{ secrets.E2E_PERMISSIONS_USERS_PASSWORD }}
MAILPITURL: ${{ secrets.MAILPITURL }}
PW_WORKERS: ${{ vars.PW_WORKERS }}
PW_RETRIES: ${{ vars.PW_RETRIES }}
URL_TO_RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

- name: submit-results-to-testmo
Expand Down Expand Up @@ -129,4 +131,4 @@ jobs:
--slack_webhook_url "$slack_webhook_url" \
--environment "$environment" \
--url_to_action "$url_to_action" \
--ref_name "$ref_name"
--ref_name "$ref_name"
41 changes: 18 additions & 23 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import dotenv from "dotenv";

import { defineConfig, devices } from "@playwright/test";

dotenv.config();

const env = process.env;
const DEFAULT_RETRIES = '1';
const DEFAULT_WORKERS = '2';
export default defineConfig({
testDir: "playwright/tests",
fullyParallel: true,
forbidOnly: !!process.env.CI,
// TODO hardcoded values should be extracted to ENVs
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 2 : 2,
reporter: process.env.CI
forbidOnly: !!env.CI,
retries: parseInt(env.RETRIES || DEFAULT_RETRIES),
workers: parseInt(env.WORKERS || DEFAULT_WORKERS),
reporter: process.env.CI
? [
["blob"],
["github"],
Expand All @@ -29,30 +29,25 @@ export default defineConfig({
],
]
: [["html"], ["list"]],
timeout: 60000,
expect: { timeout: 10000 },
// webServer: {
// command: "npm run dev",
// url: "http://localhost:9000/",
// reuseExistingServer: !process.env.CI,
// },
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
maxFailures: 5,
timeout: env.CI ? 45000 : 60000,
use: {
baseURL: process.env.BASE_URL,
trace: "on-first-retry",
baseURL: env.BASE_URL || '',
trace: env.CI ? "on-all-retries" : "on",
screenshot: "only-on-failure",
testIdAttribute: "data-test-id",
video: process.env.CI ? "retain-on-failure" : "off",
video: env.CI ? "retain-on-failure" : "off",
headless: true,
},

/* Configure projects for major browsers */
projects: [
{ name: "setup", testMatch: /.*\.setup\.ts/ },

{
// if new project added make sure to add dependency as below
dependencies: ["setup"],
name: "setup",
testMatch: /.*\.setup\.ts/
},
{
name: "chromium",
dependencies: ["setup"],
use: { ...devices["Desktop Chrome"] },
},
],
Expand Down
7 changes: 6 additions & 1 deletion playwright/pages/basePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@
"No error banner should be visible",
).not.toBeVisible();
}
async waitForNetworkIdle(action: () => Promise<void>) {
const responsePromise = this.page.waitForResponse('**/graphql/');
await action();
await responsePromise;
}
async resizeWindow(w: number, h: number) {
await this.page.setViewportSize({width: w, height: h,});
}
Expand Down Expand Up @@ -254,7 +259,7 @@
.locator("tr")
.filter({ hasText: expectedText })
.first()
.waitFor({ state: "attached" });
.waitFor({ state: "attached", timeout: 10000 });

Check failure on line 262 in playwright/pages/basePage.ts

View workflow job for this annotation

GitHub Actions / run-tests (2/4)

[chromium] › giftCards.spec.ts:49:5 › TC: SALEOR_106 Issue gift card with specific customer and expiry date @e2e @gift

1) [chromium] › giftCards.spec.ts:49:5 › TC: SALEOR_106 Issue gift card with specific customer and expiry date @e2e @gift Error: locator.waitFor: Timeout 10000ms exceeded. Call log: - waiting for locator('[data-testid="data-grid-canvas"]').locator('tr').filter({ hasText: 'Code' }).first() at ../pages/basePage.ts:262 260 | .filter({ hasText: expectedText }) 261 | .first() > 262 | .waitFor({ state: "attached", timeout: 10000 }); | ^ 263 | const gridRowsWithText = await this.gridCanvas 264 | .locator("tr") 265 | .filter({ hasText: expectedText }) at GiftCardsPage.getNumberOfGridRowsWithText (/home/runner/work/saleor-dashboard/saleor-dashboard/playwright/pages/basePage.ts:262:8) at /home/runner/work/saleor-dashboard/saleor-dashboard/playwright/tests/giftCards.spec.ts:51:25

Check failure on line 262 in playwright/pages/basePage.ts

View workflow job for this annotation

GitHub Actions / run-tests (2/4)

[chromium] › giftCards.spec.ts:117:5 › TC: SALEOR_111 Bulk delete gift cards @e2e @gift

2) [chromium] › giftCards.spec.ts:117:5 › TC: SALEOR_111 Bulk delete gift cards @e2e @gift ─────── Error: locator.waitFor: Timeout 10000ms exceeded. Call log: - waiting for locator('[data-testid="data-grid-canvas"]').locator('tr').filter({ hasText: 'Code' }).first() at ../pages/basePage.ts:262 260 | .filter({ hasText: expectedText }) 261 | .first() > 262 | .waitFor({ state: "attached", timeout: 10000 }); | ^ 263 | const gridRowsWithText = await this.gridCanvas 264 | .locator("tr") 265 | .filter({ hasText: expectedText }) at GiftCardsPage.getNumberOfGridRowsWithText (/home/runner/work/saleor-dashboard/saleor-dashboard/playwright/pages/basePage.ts:262:8) at /home/runner/work/saleor-dashboard/saleor-dashboard/playwright/tests/giftCards.spec.ts:119:25
const gridRowsWithText = await this.gridCanvas
.locator("tr")
.filter({ hasText: expectedText })
Expand Down
11 changes: 4 additions & 7 deletions playwright/pages/dialogs/productCreateDialog.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { BasePage } from "@pages/basePage";
import type { Page } from "@playwright/test";
import {expect} from "@playwright/test";

export class ProductCreateDialog {
readonly page: Page;
export class ProductCreateDialog extends BasePage{

constructor(
page: Page,
Expand All @@ -16,12 +15,10 @@ export class ProductCreateDialog {
readonly confirmButton = page.getByTestId("submit"),
readonly tooltipResult = page.getByRole("tooltip"),
) {
this.page = page;
super(page);
}
async selectProductTypeWithVariants(productType: string = "Beer") {
const responsePromise = this.page.waitForResponse('**/graphql/');
await this.dialogProductTypeInput.fill(productType);
await responsePromise;
await this.waitForNetworkIdle(() => this.dialogProductTypeInput.fill(productType));
await this.promptedOptions.filter({hasText:productType}).click();
}
async clickConfirmButton() {
Expand Down
10 changes: 8 additions & 2 deletions playwright/tests/auth.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,26 @@ const authenticateAndSaveState = async (request: APIRequestContext, email: strin
});
fs.writeFileSync(filePath, JSON.stringify(loginJsonInfo, null, 2));
};
const authSetup = async ( request: APIRequestContext,email: string, password: string, fileName: string) => {

const authSetup = async (request: APIRequestContext, email: string, password: string, fileName: string) => {
const tempDir = path.join(__dirname, '../.auth');
if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir, { recursive: true });
}
const tempFilePath = path.join(tempDir, fileName);
await authenticateAndSaveState(request, email, password, tempFilePath);

if (!fs.existsSync(tempFilePath)) {
await authenticateAndSaveState(request, email, password, tempFilePath);
}
};

setup("Authenticate as admin via API", async ({ request }) => {
await authSetup(request, process.env.E2E_USER_NAME!, process.env.E2E_USER_PASSWORD!, 'admin.json');
});

const user: UserPermissionType = USER_PERMISSION;
const password: string = process.env.E2E_PERMISSIONS_USERS_PASSWORD!;

for (const permission of permissions) {
setup(`Authenticate as ${permission} user via API`, async ({ request }) => {
await authSetup(request, user[permission], password, `${permission}.json`);
Expand Down
9 changes: 3 additions & 6 deletions playwright/tests/giftCards.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ test("TC: SALEOR_105 Issue gift card @e2e @gift", async () => {
state: "hidden",
timeout: 30000,
});
await giftCardsPage.gotoGiftCardsListView();
await giftCardsPage.waitForNetworkIdle(() => giftCardsPage.gotoGiftCardsListView());
await giftCardsPage.waitForDOMToFullyLoad();
const actualNumberOfRows = await giftCardsPage.getNumberOfGridRowsWithText(
"Code",
Expand Down Expand Up @@ -65,10 +65,7 @@ test("TC: SALEOR_106 Issue gift card with specific customer and expiry date @e2e
state: "hidden",
timeout: 30000,
});

await giftCardsPage.waitForGrid();

await giftCardsPage.gotoGiftCardsListView();
await giftCardsPage.waitForNetworkIdle(() => giftCardsPage.gotoGiftCardsListView());
await giftCardsPage.waitForDOMToFullyLoad();
const actualNumberOfRows = await giftCardsPage.getNumberOfGridRowsWithText(
"Code",
Expand Down Expand Up @@ -129,7 +126,7 @@ test("TC: SALEOR_111 Bulk delete gift cards @e2e @gift", async () => {
await giftCardsPage.deleteDialog.clickConfirmDeletionCheckbox();
await giftCardsPage.deleteDialog.clickDeleteButton();
await giftCardsPage.dialog.waitFor({ state: "hidden" });
await giftCardsPage.gotoGiftCardsListView();
await giftCardsPage.waitForNetworkIdle(() => giftCardsPage.gotoGiftCardsListView());
await giftCardsPage.waitForDOMToFullyLoad();
const actualNumberOfRows = await giftCardsPage.getNumberOfGridRowsWithText(
"Code",
Expand Down
Loading