diff --git a/apps/web/playwright/onboarding.spec.ts b/apps/web/playwright/onboarding.spec.ts index daa71e2311..a26a0fa686 100644 --- a/apps/web/playwright/onboarding.spec.ts +++ b/apps/web/playwright/onboarding.spec.ts @@ -1,6 +1,7 @@ -import { teams, users } from "./utils/mock"; +import { expect, test } from "@playwright/test"; + import { signUpAndLogin } from "./utils/helper"; -import { test, expect } from "@playwright/test"; +import { teams, users } from "./utils/mock"; const { role, productName, useCase } = teams.onboarding[0]; @@ -22,7 +23,7 @@ test.describe("Onboarding Flow Test", async () => { await expect(page.getByPlaceholder("e.g. Formbricks")).toBeVisible(); await page.getByPlaceholder("e.g. Formbricks").fill(productName); - await page.locator(".h-6").click(); + await page.locator("#color-picker").click(); await page.getByLabel("Hue").click(); await page.locator("div").filter({ hasText: "Create your team's product." }).nth(1).click(); diff --git a/apps/web/playwright/signup.spec.ts b/apps/web/playwright/signup.spec.ts index 193b1a5aec..bbc8bced17 100644 --- a/apps/web/playwright/signup.spec.ts +++ b/apps/web/playwright/signup.spec.ts @@ -1,5 +1,6 @@ +import { expect, test } from "@playwright/test"; + import { users } from "./utils/mock"; -import { test, expect } from "@playwright/test"; const { name, email, password } = users.signup[0]; diff --git a/apps/web/playwright/survey.spec.ts b/apps/web/playwright/survey.spec.ts new file mode 100644 index 0000000000..67a81b9d63 --- /dev/null +++ b/apps/web/playwright/survey.spec.ts @@ -0,0 +1,258 @@ +import { surveys, users } from "@/playwright/utils/mock"; +import { expect, test } from "@playwright/test"; +import path from "path"; + +import { signUpAndLogin, skipOnboarding } from "./utils/helper"; + +test.describe("Survey Create & Submit Response", async () => { + test.describe.configure({ mode: "serial" }); + let url: string | null; + const { name, email, password } = users.survey[0]; + let addQuestion = "Add QuestionAdd a new question to your survey"; + + test("Create Survey", async ({ page }) => { + await signUpAndLogin(page, name, email, password); + await skipOnboarding(page); + + await page.getByRole("heading", { name: "Start from Scratch" }).click(); + + // Welcome Card + await expect(page.locator("#welcome-toggle")).toBeVisible(); + await page.getByText("Welcome Card").click(); + await page.locator("#welcome-toggle").check(); + await page.getByLabel("Headline").fill(surveys.createAndSubmit.welcomeCard.headline); + await page + .locator("form") + .getByText("Thanks for providing your") + .fill(surveys.createAndSubmit.welcomeCard.description); + await page.getByText("Welcome CardEnabled").click(); + + // Open Text Question + await page.getByRole("button", { name: "1 What would you like to know" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.openTextQuestion.question); + await page.getByLabel("Description").fill(surveys.createAndSubmit.openTextQuestion.description); + await page.getByLabel("Placeholder").fill(surveys.createAndSubmit.openTextQuestion.placeholder); + await page.getByRole("button", { name: surveys.createAndSubmit.openTextQuestion.question }).click(); + + // Single Select Question + await page + .locator("div") + .filter({ hasText: new RegExp(`^${addQuestion}$`) }) + .nth(1) + .click(); + await page.getByRole("button", { name: "Single-Select" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.singleSelectQuestion.question); + await page.getByLabel("Description").fill(surveys.createAndSubmit.singleSelectQuestion.description); + await page.getByPlaceholder("Option 1").fill(surveys.createAndSubmit.singleSelectQuestion.options[0]); + await page.getByPlaceholder("Option 2").fill(surveys.createAndSubmit.singleSelectQuestion.options[1]); + await page.getByRole("button", { name: 'Add "Other"', exact: true }).click(); + + // Multi Select Question + await page + .locator("div") + .filter({ hasText: new RegExp(`^${addQuestion}$`) }) + .nth(1) + .click(); + await page.getByRole("button", { name: "Multi-Select" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.multiSelectQuestion.question); + await page.getByRole("button", { name: "Add Description", exact: true }).click(); + await page.getByLabel("Description").fill(surveys.createAndSubmit.multiSelectQuestion.description); + await page.getByPlaceholder("Option 1").fill(surveys.createAndSubmit.multiSelectQuestion.options[0]); + await page.getByPlaceholder("Option 2").fill(surveys.createAndSubmit.multiSelectQuestion.options[1]); + await page.getByPlaceholder("Option 3").fill(surveys.createAndSubmit.multiSelectQuestion.options[2]); + + // Rating Question + await page + .locator("div") + .filter({ hasText: new RegExp(`^${addQuestion}$`) }) + .nth(1) + .click(); + await page.getByRole("button", { name: "Rating" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.ratingQuestion.question); + await page.getByLabel("Scale").fill(surveys.createAndSubmit.ratingQuestion.description); + await page.getByPlaceholder("Not good").fill(surveys.createAndSubmit.ratingQuestion.lowLabel); + await page.getByPlaceholder("Very satisfied").fill(surveys.createAndSubmit.ratingQuestion.highLabel); + + // NPS Question + await page + .locator("div") + .filter({ hasText: new RegExp(`^${addQuestion}$`) }) + .nth(1) + .click(); + await page.getByRole("button", { name: "Net Promoter Score (NPS)" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.npsQuestion.question); + await page.getByLabel("Lower label").fill(surveys.createAndSubmit.npsQuestion.lowLabel); + await page + .locator("div") + .filter({ hasText: /^Upper label$/ }) + .locator("#subheader") + .fill(surveys.createAndSubmit.npsQuestion.highLabel); + + // CTA Question + await page + .locator("div") + .filter({ hasText: new RegExp(`^${addQuestion}$`) }) + .nth(1) + .click(); + await page.getByRole("button", { name: "Call-to-Action" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.ctaQuestion.question); + await page.getByPlaceholder("Finish").fill(surveys.createAndSubmit.ctaQuestion.buttonLabel); + + // Consent Question + await page + .locator("div") + .filter({ hasText: new RegExp(`^${addQuestion}$`) }) + .nth(1) + .click(); + await page.getByRole("button", { name: "Consent" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.consentQuestion.question); + await page + .getByPlaceholder("I agree to the terms and") + .fill(surveys.createAndSubmit.consentQuestion.checkboxLabel); + + // Picture Select Question + await page + .locator("div") + .filter({ hasText: new RegExp(`^${addQuestion}$`) }) + .nth(1) + .click(); + await page.getByRole("button", { name: "Picture Selection" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.pictureSelectQuestion.question); + await page.getByLabel("Description").fill(surveys.createAndSubmit.pictureSelectQuestion.description); + + // File Upload Question + await page + .locator("div") + .filter({ hasText: new RegExp(`^${addQuestion}$`) }) + .nth(1) + .click(); + await page.getByRole("button", { name: "File Upload" }).click(); + await page.getByLabel("Question").fill(surveys.createAndSubmit.fileUploadQuestion.question); + + // Thank You Card + await page + .locator("div") + .filter({ hasText: /^Thank You CardShown$/ }) + .nth(1) + .click(); + await page.getByLabel("Headline").fill(surveys.createAndSubmit.thankYouCard.headline); + await page.getByLabel("Description").fill(surveys.createAndSubmit.thankYouCard.description); + + // Save & Publish Survey + await page.getByRole("button", { name: "Continue to Settings" }).click(); + await page.getByRole("button", { name: "Publish" }).click(); + + // Get URL + await page.waitForURL(/\/environments\/[^/]+\/surveys\/[^/]+\/summary$/); + url = await page + .locator("div") + .filter({ hasText: /^http:\/\/localhost:3000\/s\/[A-Za-z0-9]+$/ }) + .innerText(); + }); + + test("Submit Survey Response", async ({ page }) => { + await page.goto(url!); + await page.waitForURL(/\/s\/[A-Za-z0-9]+$/); + + // Welcome Card + await expect(page.getByText(surveys.createAndSubmit.welcomeCard.headline)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.welcomeCard.description)).toBeVisible(); + await page.getByRole("button", { name: "Next" }).click(); + + // Open Text Question + await expect(page.getByText(surveys.createAndSubmit.openTextQuestion.question)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.openTextQuestion.description)).toBeVisible(); + await expect(page.getByPlaceholder(surveys.createAndSubmit.openTextQuestion.placeholder)).toBeVisible(); + await page + .getByPlaceholder(surveys.createAndSubmit.openTextQuestion.placeholder) + .fill("This is my Open Text answer"); + await page.getByRole("button", { name: "Next" }).click(); + + // Single Select Question + await expect(page.getByText(surveys.createAndSubmit.singleSelectQuestion.question)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.singleSelectQuestion.description)).toBeVisible(); + for (let i = 0; i < surveys.createAndSubmit.singleSelectQuestion.options.length; i++) { + await expect(page.getByText(surveys.createAndSubmit.singleSelectQuestion.options[i])).toBeVisible(); + } + await expect(page.getByText("Other")).toBeVisible(); + await expect(page.getByRole("button", { name: "Next" })).toBeVisible(); + await expect(page.getByRole("button", { name: "Back" })).toBeVisible(); + await page.getByText(surveys.createAndSubmit.singleSelectQuestion.options[0]).click(); + await page.getByRole("button", { name: "Next" }).click(); + + // Multi Select Question + await expect(page.getByText(surveys.createAndSubmit.multiSelectQuestion.question)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.multiSelectQuestion.description)).toBeVisible(); + for (let i = 0; i < surveys.createAndSubmit.multiSelectQuestion.options.length; i++) { + await expect(page.getByText(surveys.createAndSubmit.multiSelectQuestion.options[i])).toBeVisible(); + } + await expect(page.getByRole("button", { name: "Next" })).toBeVisible(); + await expect(page.getByRole("button", { name: "Back" })).toBeVisible(); + await page.getByText(surveys.createAndSubmit.multiSelectQuestion.options[0]).click(); + await page.getByText(surveys.createAndSubmit.multiSelectQuestion.options[1]).click(); + await page.getByRole("button", { name: "Next" }).click(); + + // Rating Question + await expect(page.getByText(surveys.createAndSubmit.ratingQuestion.question)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.ratingQuestion.description)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.ratingQuestion.lowLabel)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.ratingQuestion.highLabel)).toBeVisible(); + expect(await page.getByRole("group", { name: "Choices" }).locator("label").count()).toBe(5); + await expect(page.getByRole("button", { name: "Next" })).not.toBeVisible(); + await expect(page.getByRole("button", { name: "Back" })).toBeVisible(); + await page.getByLabel("").nth(3).click(); + + // NPS Question + await expect(page.getByText(surveys.createAndSubmit.npsQuestion.question)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.npsQuestion.lowLabel)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.npsQuestion.highLabel)).toBeVisible(); + await expect(page.getByRole("button", { name: "Next" })).not.toBeVisible(); + await expect(page.getByRole("button", { name: "Back" })).toBeVisible(); + + for (let i = 0; i < 11; i++) { + await expect(page.getByText(`${i}`, { exact: true })).toBeVisible(); + } + await page.getByText("8").click(); + + // CTA Question + await expect(page.getByText(surveys.createAndSubmit.ctaQuestion.question)).toBeVisible(); + await expect( + page.getByRole("button", { name: surveys.createAndSubmit.ctaQuestion.buttonLabel }) + ).toBeVisible(); + await page.getByRole("button", { name: surveys.createAndSubmit.ctaQuestion.buttonLabel }).click(); + + // Consent Question + await expect(page.getByText(surveys.createAndSubmit.consentQuestion.question)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.consentQuestion.checkboxLabel)).toBeVisible(); + await expect(page.getByRole("button", { name: "Next" })).toBeVisible(); + await expect(page.getByRole("button", { name: "Back" })).toBeVisible(); + await page.getByText(surveys.createAndSubmit.consentQuestion.checkboxLabel).check(); + await page.getByRole("button", { name: "Next" }).click(); + + // Picture Select Question + await expect(page.getByText(surveys.createAndSubmit.pictureSelectQuestion.question)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.pictureSelectQuestion.description)).toBeVisible(); + await expect(page.getByRole("button", { name: "Next" })).toBeVisible(); + await expect(page.getByRole("button", { name: "Back" })).toBeVisible(); + await expect(page.getByRole("img", { name: "puppy-1-small.jpg" })).toBeVisible(); + await expect(page.getByRole("img", { name: "puppy-2-small.jpg" })).toBeVisible(); + await page.getByRole("img", { name: "puppy-1-small.jpg" }).click(); + await page.getByRole("button", { name: "Next" }).click(); + + // File Upload Question + await expect(page.getByText(surveys.createAndSubmit.fileUploadQuestion.question)).toBeVisible(); + await expect(page.getByRole("button", { name: "Finish" })).toBeVisible(); + await expect(page.getByRole("button", { name: "Back" })).toBeVisible(); + await expect( + page.locator("label").filter({ hasText: "Click or drag to upload files." }).locator("div").nth(0) + ).toBeVisible(); + await page.locator("input[type=file]").setInputFiles(path.join(__dirname, "survey.spec.ts")); + await page.getByText("Uploading...").waitFor({ state: "hidden" }); + + await page.getByRole("button", { name: "Finish" }).click(); + + // Thank You Card + await expect(page.getByText(surveys.createAndSubmit.thankYouCard.headline)).toBeVisible(); + await expect(page.getByText(surveys.createAndSubmit.thankYouCard.description)).toBeVisible(); + }); +}); diff --git a/apps/web/playwright/utils/helper.ts b/apps/web/playwright/utils/helper.ts index 1a6a3559f4..e0513ca17f 100644 --- a/apps/web/playwright/utils/helper.ts +++ b/apps/web/playwright/utils/helper.ts @@ -1,3 +1,4 @@ +import { expect } from "@playwright/test"; import { Page } from "playwright"; export const signUpAndLogin = async ( @@ -22,3 +23,22 @@ export const signUpAndLogin = async ( await page.getByPlaceholder("*******").fill(password); await page.getByRole("button", { name: "Login with Email" }).click(); }; + +export const login = async (page: Page, email: string, password: string): Promise => { + await page.goto("/auth/login"); + await page.getByRole("button", { name: "Login with Email" }).click(); + await page.getByPlaceholder("work@email.com").fill(email); + await page.getByPlaceholder("*******").click(); + await page.getByPlaceholder("*******").fill(password); + await page.getByRole("button", { name: "Login with Email" }).click(); +}; + +export const skipOnboarding = async (page: Page): Promise => { + await page.waitForURL("/onboarding"); + await expect(page).toHaveURL("/onboarding"); + await page.getByRole("button", { name: "I'll do it later" }).click(); + await page.getByRole("button", { name: "I'll do it later" }).click(); + await page.waitForURL(/\/environments\/[^/]+\/surveys/); + await expect(page).toHaveURL(/\/environments\/[^/]+\/surveys/); + await expect(page.getByText("My Product")).toBeVisible(); +}; diff --git a/apps/web/playwright/utils/mock.ts b/apps/web/playwright/utils/mock.ts index 4d4596bb9f..e022141eca 100644 --- a/apps/web/playwright/utils/mock.ts +++ b/apps/web/playwright/utils/mock.ts @@ -18,6 +18,13 @@ export const users = { password: "231Xh7D&dM8u75EjIYV", }, ], + survey: [ + { + name: "Survey User 1", + email: "survey1@formbricks.com", + password: "Y1I*EpURUSb32j5XijP", + }, + ], }; export const teams = { @@ -29,3 +36,57 @@ export const teams = { }, ], }; + +export const surveys = { + createAndSubmit: { + welcomeCard: { + headline: "Welcome to My Testing Survey Welcome Card!", + description: "This is the description of my Welcome Card!", + }, + openTextQuestion: { + question: "This is my Open Text Question", + description: "This is my Open Text Description", + placeholder: "This is my Placeholder", + }, + singleSelectQuestion: { + question: "This is my Single Select Question", + description: "This is my Single Select Description", + options: ["Option 1", "Option 2"], + }, + multiSelectQuestion: { + question: "This is my Multi Select Question", + description: "This is Multi Select Description", + options: ["Option 1", "Option 2", "Option 3"], + }, + ratingQuestion: { + question: "This is my Rating Question", + description: "This is Rating Description", + lowLabel: "My Lower Label", + highLabel: "My Upper Label", + }, + npsQuestion: { + question: "This is my NPS Question", + lowLabel: "My Lower Label", + highLabel: "My Upper Label", + }, + ctaQuestion: { + question: "This is my CTA Question", + buttonLabel: "My Button Label", + }, + consentQuestion: { + question: "This is my Consent Question", + checkboxLabel: "My Checkbox Label", + }, + pictureSelectQuestion: { + question: "This is my Picture Select Question", + description: "This is Picture Select Description", + }, + fileUploadQuestion: { + question: "This is my File Upload Question", + }, + thankYouCard: { + headline: "This is my Thank You Card Headline!", + description: "This is my Thank you Card Description!", + }, + }, +}; diff --git a/packages/ui/ColorPicker/index.tsx b/packages/ui/ColorPicker/index.tsx index 46f223359d..1cf362f28d 100644 --- a/packages/ui/ColorPicker/index.tsx +++ b/packages/ui/ColorPicker/index.tsx @@ -36,6 +36,7 @@ export const PopoverPicker = ({ color, onChange }: { color: string; onChange: (v return (
toggle(!isOpen)}