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

feat: e2e test for actions #1831

Merged
merged 14 commits into from
Jan 23, 2024
Merged

feat: e2e test for actions #1831

merged 14 commits into from
Jan 23, 2024

Conversation

pandeymangg
Copy link
Contributor

What does this PR do?

Fixes # (issue)

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change adds a new database migration
  • This change requires a documentation update

How should this be tested?

  • Test A
  • Test B

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read How we Code at Formbricks
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand bits
  • Ran pnpm build
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues
  • First PR at Formbricks? Please sign the CLA! Without it we wont be able to merge it 🙏

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Formbricks Docs if changes were necessary

Copy link
Contributor

github-actions bot commented Dec 27, 2023

Thank you for following the naming conventions for pull request titles! 🙏

Copy link

vercel bot commented Dec 27, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Ignored Deployments
Name Status Preview Comments Updated (UTC)
formbricks-cloud ⬜️ Ignored (Inspect) Visit Preview Jan 23, 2024 6:38am
formbricks-com ⬜️ Ignored (Inspect) Visit Preview Jan 23, 2024 6:38am

Copy link
Contributor

apps/web/playwright/action.spec.ts

  There is a lot of code duplication in the test functions `createNoCodeActionByCSSSelector`, `createNoCodeActionByPageURL`, and `createNoCodeActionByInnerText`. These functions perform similar actions with slight variations. 

  To improve readability and maintainability, consider refactoring these functions into a single function that accepts the necessary parameters to handle the variations. This will make the code DRY (Don't Repeat Yourself), easier to read, and easier to maintain.

Create Issue
See the diff
Checkout the fix

    const createNoCodeAction = async (
      page: Page,
      email: string,
      password: string,
      name: string,
      description: string,
      actionType: string,
      actionValue: string
    ) => {
      await login(page, email, password);

      await page.getByRole("link", { name: "Actions & Attributes" }).click();
      await page.getByRole("button", { name: "Add Action" }).click();

      await expect(page.getByLabel("What did your user do?")).toBeVisible();
      await page.getByLabel("What did your user do?").fill(name);

      await expect(page.getByLabel("Description")).toBeVisible();
      await page.getByLabel("Description").fill(description);

      await expect(page.locator(`#${actionType}`)).toBeVisible();
      await page.locator(`#${actionType}`).click();

      await expect(page.locator(`[name='noCodeConfig.${actionType}.value']`)).toBeVisible();
      await page.locator(`[name='noCodeConfig.${actionType}.value']`).fill(actionValue);
      await page.getByRole("button", { name: "Track Action", exact: true }).click();
    };
git fetch origin && git checkout -b ReviewBot/Refac-t62eb8d origin/ReviewBot/Refac-t62eb8d
  There are several strings that are repeated multiple times throughout the code, such as "What did your user do?", "Description", "Track Action", etc. 

  To improve readability and maintainability, consider defining these strings as constants at the top of your file and then use these constants throughout your code. This way, if you need to change the string in the future, you only need to change it in one place.

Create Issue
See the diff
Checkout the fix

    const WHAT_DID_YOUR_USER_DO = "What did your user do?";
    const DESCRIPTION = "Description";
    const TRACK_ACTION = "Track Action";
    // ... rest of your code
git fetch origin && git checkout -b ReviewBot/Use-c-wkp6ixa origin/ReviewBot/Use-c-wkp6ixa

Comment on lines 6 to 124
await page.getByLabel("What did your user do?").fill(name);

await expect(page.getByLabel("Description")).toBeVisible();
await page.getByLabel("Description").fill(description);

// User toggles the CSS Selector action type

await expect(page.locator("#CssSelector")).toBeVisible();
await page.locator("#CssSelector").click();

// User fills the CSS Selector to track
await expect(page.locator("[name='noCodeConfig.cssSelector.value']")).toBeVisible();
await page.locator("[name='noCodeConfig.cssSelector.value']").fill(selector);
await page.getByRole("button", { name: "Track Action", exact: true }).click();
};

const createNoCodeActionByPageURL = async (
page: Page,
email: string,
password: string,
name: string,
description: string,
matcher: {
label: string;
value: string;
},
testURL: string
) => {
// await signUpAndLogin(page, name, email, password);
await login(page, email, password);
// await skipOnboarding(page);

await page.getByRole("link", { name: "Actions & Attributes" }).click();

// Add Action button
await page.getByRole("button", { name: "Add Action" }).click();

// User fills the action name and description
await expect(page.getByLabel("What did your user do?")).toBeVisible();
await page.getByLabel("What did your user do?").fill(name);

await expect(page.getByLabel("Description")).toBeVisible();
await page.getByLabel("Description").fill(description);

// User toggles the Page URL action type

await expect(page.locator("#PageURL")).toBeVisible();
await page.locator("#PageURL").click();

// User opens the dropdown and selects the URL match type
await expect(page.locator("[name='noCodeConfig.[pageUrl].rule']")).toBeVisible();
await page.locator("[name='noCodeConfig.[pageUrl].rule']").selectOption({ label: matcher.label });

// User fills the Page URL to track
await page.locator("[name='noCodeConfig.[pageUrl].value']").fill(matcher.value);

// User fills the Test URL to track
await page.locator("[name='noCodeConfig.[pageUrl].testUrl']").fill(testURL);

// User clicks the Test Match button
await page.getByRole("button", { name: "Test Match", exact: true }).click();

// User clicks the Track Action button
await page.getByRole("button", { name: "Track Action", exact: true }).click();
};

const createNoCodeActionByInnerText = async (
page: Page,
email: string,
password: string,
name: string,
description: string,
innerText: string
) => {
// await signUpAndLogin(page, name, email, password);
await login(page, email, password);
// await skipOnboarding(page);

await page.getByRole("link", { name: "Actions & Attributes" }).click();

// Add Action button
await page.getByRole("button", { name: "Add Action" }).click();

// User fills the action name and description
await expect(page.getByLabel("What did your user do?")).toBeVisible();
await page.getByLabel("What did your user do?").fill(name);

await expect(page.getByLabel("Description")).toBeVisible();
await page.getByLabel("Description").fill(description);

// User toggles the Inner Text action type

await expect(page.locator("#InnerText")).toBeVisible();
await page.locator("#InnerText").click();

// User fills the Inner Text to track
await expect(page.locator("[name='noCodeConfig.innerHtml.value']")).toBeVisible();
await page.locator("[name='noCodeConfig.innerHtml.value']").fill(innerText);
await page.getByRole("button", { name: "Track Action", exact: true }).click();
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Refactor the test functions to reduce code duplication and improve readability. The functions createNoCodeActionByCSSSelector, createNoCodeActionByPageURL, and createNoCodeActionByInnerText have been refactored into a single function createNoCodeAction that accepts the necessary parameters to handle the variations.

Suggested change
const createNoCodeActionByCSSSelector = async (
page: Page,
email: string,
password: string,
name: string,
description: string,
selector: string
) => {
// await signUpAndLogin(page, name, email, password);
await login(page, email, password);
// await skipOnboarding(page);
await page.getByRole("link", { name: "Actions & Attributes" }).click();
// Add Action button
await page.getByRole("button", { name: "Add Action" }).click();
// User fills the action name and description
await expect(page.getByLabel("What did your user do?")).toBeVisible();
await page.getByLabel("What did your user do?").fill(name);
await expect(page.getByLabel("Description")).toBeVisible();
await page.getByLabel("Description").fill(description);
// User toggles the CSS Selector action type
await expect(page.locator("#CssSelector")).toBeVisible();
await page.locator("#CssSelector").click();
// User fills the CSS Selector to track
await expect(page.locator("[name='noCodeConfig.cssSelector.value']")).toBeVisible();
await page.locator("[name='noCodeConfig.cssSelector.value']").fill(selector);
await page.getByRole("button", { name: "Track Action", exact: true }).click();
};
const createNoCodeActionByPageURL = async (
page: Page,
email: string,
password: string,
name: string,
description: string,
matcher: {
label: string;
value: string;
},
testURL: string
) => {
// await signUpAndLogin(page, name, email, password);
await login(page, email, password);
// await skipOnboarding(page);
await page.getByRole("link", { name: "Actions & Attributes" }).click();
// Add Action button
await page.getByRole("button", { name: "Add Action" }).click();
// User fills the action name and description
await expect(page.getByLabel("What did your user do?")).toBeVisible();
await page.getByLabel("What did your user do?").fill(name);
await expect(page.getByLabel("Description")).toBeVisible();
await page.getByLabel("Description").fill(description);
// User toggles the Page URL action type
await expect(page.locator("#PageURL")).toBeVisible();
await page.locator("#PageURL").click();
// User opens the dropdown and selects the URL match type
await expect(page.locator("[name='noCodeConfig.[pageUrl].rule']")).toBeVisible();
await page.locator("[name='noCodeConfig.[pageUrl].rule']").selectOption({ label: matcher.label });
// User fills the Page URL to track
await page.locator("[name='noCodeConfig.[pageUrl].value']").fill(matcher.value);
// User fills the Test URL to track
await page.locator("[name='noCodeConfig.[pageUrl].testUrl']").fill(testURL);
// User clicks the Test Match button
await page.getByRole("button", { name: "Test Match", exact: true }).click();
// User clicks the Track Action button
await page.getByRole("button", { name: "Track Action", exact: true }).click();
};
const createNoCodeActionByInnerText = async (
page: Page,
email: string,
password: string,
name: string,
description: string,
innerText: string
) => {
// await signUpAndLogin(page, name, email, password);
await login(page, email, password);
// await skipOnboarding(page);
await page.getByRole("link", { name: "Actions & Attributes" }).click();
// Add Action button
await page.getByRole("button", { name: "Add Action" }).click();
// User fills the action name and description
await expect(page.getByLabel("What did your user do?")).toBeVisible();
await page.getByLabel("What did your user do?").fill(name);
await expect(page.getByLabel("Description")).toBeVisible();
await page.getByLabel("Description").fill(description);
// User toggles the Inner Text action type
await expect(page.locator("#InnerText")).toBeVisible();
await page.locator("#InnerText").click();
// User fills the Inner Text to track
await expect(page.locator("[name='noCodeConfig.innerHtml.value']")).toBeVisible();
await page.locator("[name='noCodeConfig.innerHtml.value']").fill(innerText);
await page.getByRole("button", { name: "Track Action", exact: true }).click();
};
const createNoCodeAction = async (
page: Page,
email: string,
password: string,
name: string,
description: string,
actionType: string,
actionValue: string
) => {
await login(page, email, password);
await page.getByRole("link", { name: "Actions & Attributes" }).click();
await page.getByRole("button", { name: "Add Action" }).click();
await expect(page.getByLabel("What did your user do?")).toBeVisible();
await page.getByLabel("What did your user do?").fill(name);
await expect(page.getByLabel("Description")).toBeVisible();
await page.getByLabel("Description").fill(description);
await expect(page.locator(`#${actionType}`)).toBeVisible();
await page.locator(`#${actionType}`).click();
await expect(page.locator(`[name='noCodeConfig.${actionType}.value']`)).toBeVisible();
await page.locator(`[name='noCodeConfig.${actionType}.value']`).fill(actionValue);
await page.getByRole("button", { name: "Track Action", exact: true }).click();
};

@@ -0,0 +1,320 @@
import { actions, users } from "@/playwright/utils/mock";
Copy link
Contributor

Choose a reason for hiding this comment

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

Defining the repeated strings as constants at the top of the file to improve readability and maintainability.

Suggested change
import { actions, users } from "@/playwright/utils/mock";
const WHAT_DID_YOUR_USER_DO = 'What did your user do?';
const DESCRIPTION = 'Description';
const TRACK_ACTION = 'Track Action';
const ADD_ACTION = 'Add Action';
const SAVE_CHANGES = 'Save changes';
const SETTINGS = 'Settings';
const TEST_MATCH = 'Test Match';
const CODE = 'Code';
const ACTIONS_AND_ATTRIBUTES = 'Actions & Attributes';
const DELETE = 'Delete';

Copy link
Member

@mattinannt mattinannt left a comment

Choose a reason for hiding this comment

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

@pandeymangg thanks a lot for adding the tests 😊🚀
We are great on track to test the most important frontend parts of the Formbricks app 💪

@mattinannt mattinannt added this pull request to the merge queue Jan 8, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 8, 2024
@mattinannt mattinannt added this pull request to the merge queue Jan 15, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 15, 2024
Copy link
Member

@mattinannt mattinannt left a comment

Choose a reason for hiding this comment

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

@pandeymangg Thanks a lot for creating the additional tests 😊💪Looks great!
Now that we fixed the e2e pipeline, we can merge this :-) 🚀

@mattinannt mattinannt added this pull request to the merge queue Jan 22, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 22, 2024
@mattinannt mattinannt added this pull request to the merge queue Jan 22, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 22, 2024
@pandeymangg pandeymangg added this pull request to the merge queue Jan 23, 2024
Merged via the queue into main with commit f1535d3 Jan 23, 2024
12 checks passed
@pandeymangg pandeymangg deleted the feat/actions-e2e branch January 23, 2024 06:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants