Skip to content

Commit

Permalink
chore: standardize testkit package with lint, config, plugins (#2601)
Browse files Browse the repository at this point in the history
  • Loading branch information
YossiSaadi authored Nov 21, 2024
1 parent ddd22e0 commit 798497f
Show file tree
Hide file tree
Showing 27 changed files with 251 additions and 144 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ jobs:
SINCE_FLAG: ${{ steps.determine-since-flag.outputs.since_flag }}
run: yarn lerna run ${{ matrix.command }} $SINCE_FLAG

tests_e2e:
name: Run end-to-end tests
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -56,12 +55,12 @@ jobs:
- uses: ./.github/actions/download-builds
- name: Install playwright browsers
run: npx playwright install --with-deps
- name: Run tests
- name: Run e2e tests
run: yarn lerna run test:e2e $SINCE_FLAG --scope "@vibe/testkit"
- uses: actions/upload-artifact@v4
if: ${{ always() }}
with:
name: test-results
path: |
packages/testkit/reports
packages/testkit/test-results
packages/testkit/test-results
59 changes: 59 additions & 0 deletions packages/testkit/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const defaultPlugins = ["prettier"];
const defaultExtends = ["eslint:recommended", "plugin:prettier/recommended"];
const defaultRules = {
"prettier/prettier": "error"
};

const commonJsPlugins = defaultPlugins;
const commonJsExtends = defaultExtends;
const commonJsRules = {
...defaultRules,
"no-unused-vars": ["error", { argsIgnorePattern: "^_" }]
};

const commonTsPlugins = [...defaultPlugins, "@typescript-eslint"];
const commonTsExtends = [...defaultExtends, "plugin:@typescript-eslint/recommended"];
const commonTsRules = {
...defaultRules,
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
"@typescript-eslint/no-explicit-any": "warn"
};

module.exports = {
ignorePatterns: ["node_modules", "dist"],
parserOptions: {
sourceType: "module"
},
env: {
es2021: true,
node: true
},
overrides: [
{
files: ["**/*.js"],
extends: commonJsExtends,
plugins: commonJsPlugins,
rules: commonJsRules
},
{
files: ["**/*.ts"],
parser: "@typescript-eslint/parser",
plugins: commonTsPlugins,
extends: commonTsExtends,
rules: commonTsRules
},
{
files: ["./__tests__/*.test.js"],
plugins: [...commonJsPlugins, "playwright"],
extends: [...commonJsExtends, "plugin:playwright/recommended"],
rules: commonJsRules
},
{
files: ["./__tests__/*.test.ts"],
parser: "@typescript-eslint/parser",
plugins: [...commonTsPlugins, "playwright"],
extends: [...commonTsExtends, "plugin:playwright/recommended"],
rules: commonTsRules
}
]
};
43 changes: 24 additions & 19 deletions packages/testkit/BaseElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { test, Page, Locator } from "@playwright/test";
* Class representing a base element for Playwright tests.
*/
export class BaseElement {
page : Page;
locator : Locator;
elementReportName: String
page: Page;
locator: Locator;
elementReportName: string;
/**
* Create a BaseElement.
* @param {Object} page - The Playwright page object.
* @param {Object} locator - The locator for the element.
* @param {string} elementReportName - The name for reporting purposes.
*/
constructor(page: Page, locator: Locator, elementReportName: String) {
constructor(page: Page, locator: Locator, elementReportName: string) {
this.page = page;
this.locator = locator;
this.elementReportName = elementReportName;
Expand All @@ -31,11 +31,12 @@ export class BaseElement {
* Wait for the list elements to stabilize (i.e., the count of items remains constant for a specified duration).
* @returns {Promise<void>}
*/
async waitForElementsGroup(locator: Locator, elementReportName: String): Promise<void> {
async waitForElementsGroup(locator: Locator, elementReportName: string): Promise<void> {
await test.step(`Wait for ${elementReportName} items to stabilize`, async () => {
let previousCount = 0;
let stableCountTime = 0;
const stabilizationTimeMs = 500;
// eslint-disable-next-line no-constant-condition
while (true) {
const currentCount = await this.locator.locator(locator).count();

Expand All @@ -58,12 +59,12 @@ export class BaseElement {
* @returns {Promise<boolean>} - Returns true if the element is enabled, otherwise false.
*/
async isEnabled(): Promise<boolean> {
let isEnabled: boolean = false;
await test.step(`Return if ${this.elementReportName} is enabled`, async () => {
isEnabled = await this.locator.isEnabled();
return isEnabled;
});
let isEnabled = false;
await test.step(`Return if ${this.elementReportName} is enabled`, async () => {
isEnabled = await this.locator.isEnabled();
return isEnabled;
});
return isEnabled;
}

/**
Expand All @@ -75,15 +76,19 @@ export class BaseElement {
await this.locator.scrollIntoViewIfNeeded();
});
}
async getAttributeValue(attributeName: string, options: any = { timeout: 10000, pollInterval: 500 }) : Promise <string | null> {
async getAttributeValue(
attributeName: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
options: any = { timeout: 10000, pollInterval: 500 }
): Promise<string | null> {
let attributeValue = null;

await test.step(`Get attribute ${attributeName} of ${this.elementReportName}`, async () => {
const startTime = Date.now();

while (Date.now() - startTime < options.timeout) {
attributeValue = await this.locator.getAttribute(attributeName);

if (attributeValue !== null) {
break;
}
Expand All @@ -98,8 +103,8 @@ export class BaseElement {
return attributeValue;
}

async getText() : Promise<string|undefined> {
let text: string|undefined;
async getText(): Promise<string | undefined> {
let text: string | undefined;
await test.step(`Get text of ${this.elementReportName}`, async () => {
text = await this.locator.innerText();
return text;
Expand All @@ -113,14 +118,14 @@ export class BaseElement {
});
}

async waitForAbsence() : Promise<void>{
async waitForAbsence(): Promise<void> {
await test.step(`Wait for ${this.elementReportName} to be absent`, async () => {
await this.waitFor({ state: "detached" });
});
}

async count() : Promise<number>{
let count: number=0;
async count(): Promise<number> {
let count = 0;
await test.step(`Count elements matching ${this.elementReportName}`, async () => {
count = await this.locator.count();
});
Expand Down
41 changes: 0 additions & 41 deletions packages/testkit/__TESTS__/button.spec.js

This file was deleted.

24 changes: 0 additions & 24 deletions packages/testkit/__TESTS__/checkbox.spec.js

This file was deleted.

43 changes: 43 additions & 0 deletions packages/testkit/__tests__/button.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { test, expect } from "@playwright/test";
import { Button } from "../buttons/Button";
import { buttonStory } from "./utils/url-helper";

test("should fire a click event and log to console", async ({ page }) => {
// Navigate to the Storybook page with the component
await page.goto(buttonStory, { timeout: 100000 });
// Locate the iframe where the button is rendered
const frame = page.frameLocator("[id='storybook-preview-iframe']");
const button = new Button(page, frame.locator('button[data-testid="button"]'), "Button");

//TODO - find a better way to wait for the storybook to load
while ((await button.locator.isVisible()) === false) {
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(30000);
await page.reload();
// eslint-disable-next-line playwright/no-conditional-in-test
if ((await button.locator.isVisible()) === true) {
break;
}
}
// Add a listener to capture console logs
let consoleMessage = "";
page.on("console", async msg => {
const values = await Promise.all(msg.args().map(arg => arg.jsonValue()));
consoleMessage = values.join(" ");
});

// Attach a click event listener that logs a message to the console
await button.locator.evaluate(buttonElement => {
buttonElement.addEventListener("click", () => {
console.log("Button clicked"); // Log to console when clicked
});
});
// Click the button
await button.click();

// eslint-disable-next-line playwright/no-wait-for-timeout -- Wait a bit to ensure the console log is captured
await page.waitForTimeout(500);

// Verify the console log contains the expected message
expect(consoleMessage).toContain("Button clicked");
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { test, expect } from "@playwright/test";
import { ButtonGroup } from "../buttons/ButtonGroup";
import { buttonGroupStory } from "./utils/url-helper";


test.describe("ButtonGroup Class with Storybook", () => {
let buttonGroup;

Expand All @@ -15,10 +14,11 @@ test.describe("ButtonGroup Class with Storybook", () => {

// Locate the button group inside the iframe
const buttonGroupLocator = frame.locator('div[data-testid="button-group"]');
while (await buttonGroupLocator.isVisible() === false) {
while ((await buttonGroupLocator.isVisible()) === false) {
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(30000);
await page.reload();
if (await buttonGroupLocator.isVisible() === true) {
if ((await buttonGroupLocator.isVisible()) === true) {
break;
}
}
Expand Down Expand Up @@ -60,7 +60,7 @@ test.describe("ButtonGroup Class with Storybook", () => {
// Click the button
await buttonGroup.click("Beta");

// Wait a bit to ensure the console log is captured
// eslint-disable-next-line playwright/no-wait-for-timeout -- Wait a bit to ensure the console log is captured
await page.waitForTimeout(500);

// Verify the console message contains the expected log
Expand Down
28 changes: 28 additions & 0 deletions packages/testkit/__tests__/checkbox.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { test, expect } from "@playwright/test";
import { Checkbox } from "../inputs/Checkbox";
import { checkboxStory } from "./utils/url-helper";

test.describe("menuButton Class with Storybook", () => {
let checkbox;

test.beforeEach(async ({ page }) => {
await page.goto(checkboxStory);
const frame = page.frameLocator("[id='storybook-preview-iframe']");
const checkboxLocator = frame.locator('[data-testid="checkbox-checkbox"]');
checkbox = new Checkbox(page, checkboxLocator, "Test checkbox button");
});

// eslint-disable-next-line no-unused-vars
test("set checkbox", async ({ page }) => {
// eslint-disable-next-line playwright/no-conditional-in-test
if (await checkbox.isChecked()) {
await checkbox.setChecked(false);
// eslint-disable-next-line playwright/prefer-web-first-assertions, playwright/no-conditional-expect
expect(await checkbox.isChecked()).toBe(false);
} else {
await checkbox.setChecked(true);
// eslint-disable-next-line playwright/prefer-web-first-assertions, playwright/no-conditional-expect
expect(await checkbox.isChecked()).toBe(true);
}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ test.describe("dropdown Class with Storybook", () => {
});

test.fixme("set dropdown value", async ({ page }) => {
// extended wait for interaction test to finish
// eslint-disable-next-line playwright/no-wait-for-timeout -- extended wait for interaction test to finish
await page.waitForTimeout(10000);
await DropDown.inputField.setText("");
await DropDown.selectItem("2");
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(500);
expect(await DropDown.getText()).toContain("2");
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ test.describe("menuButton Class with Storybook", () => {
menuButton = new MenuButton(page, menubuttonLocator, "Test menu button");
});

test("should open and close menu", async ({page}) => {
test("should open and close menu", async ({ page }) => {
await menuButton.openMenu();
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(500);
expect(await menuButton.isExpanded()).toBe(true);
await menuButton.closeMenu();
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(500);
expect(await menuButton.isExpanded()).toBe(false);
});
Expand Down
Loading

0 comments on commit 798497f

Please sign in to comment.