From 3107b975cf3cefbbde5ecd2818e7bd016e36b084 Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 21 Aug 2024 11:01:40 +0100 Subject: [PATCH 01/16] create test for workspace --- apps/frontend/package.json | 1 + apps/frontend/playwright.config.ts | 9 ++-- apps/frontend/tests/auth.setup.ts | 51 +++++++++++-------- apps/frontend/tests/utils/constants.ts | 6 +++ .../tests/workspace/create-workspace.spec.ts | 49 ++++++++++++++++-- 5 files changed, 85 insertions(+), 31 deletions(-) diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 93317f01..8317d54b 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -60,6 +60,7 @@ "zustand": "^4.4.5" }, "devDependencies": { + "@faker-js/faker": "^8.4.1", "@graphql-codegen/cli": "^3.3.1", "@graphql-codegen/client-preset": "^4.1.0", "@graphql-codegen/typescript": "^3.0.4", diff --git a/apps/frontend/playwright.config.ts b/apps/frontend/playwright.config.ts index dfe125f6..09c06649 100644 --- a/apps/frontend/playwright.config.ts +++ b/apps/frontend/playwright.config.ts @@ -1,4 +1,5 @@ import { defineConfig, devices } from "@playwright/test"; +import { ONBOARDED_USER_FILE } from "./tests/utils/constants"; /** * Read environment variables from file. @@ -19,7 +20,7 @@ export default defineConfig({ /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, + workers: process.env.CI ? 2 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ @@ -37,19 +38,19 @@ export default defineConfig({ { name: "chromium", - use: { ...devices["Desktop Chrome"] }, + use: { ...devices["Desktop Chrome"], storageState: ONBOARDED_USER_FILE }, dependencies: ["setup"], }, { name: "firefox", - use: { ...devices["Desktop Firefox"] }, + use: { ...devices["Desktop Firefox"], storageState: ONBOARDED_USER_FILE }, dependencies: ["setup"], }, { name: "webkit", - use: { ...devices["Desktop Safari"] }, + use: { ...devices["Desktop Safari"], storageState: ONBOARDED_USER_FILE }, dependencies: ["setup"], }, diff --git a/apps/frontend/tests/auth.setup.ts b/apps/frontend/tests/auth.setup.ts index 514e91dc..dba45f08 100644 --- a/apps/frontend/tests/auth.setup.ts +++ b/apps/frontend/tests/auth.setup.ts @@ -1,12 +1,9 @@ +import { faker } from "@faker-js/faker"; import { expect, Page, test as setup } from "@playwright/test"; -import { NEW_USER_FILE, NON_ONBOARDED_USER_FILE, ONBOARDED_USER_FILE } from "./utils/constants"; +import { NEW_USER_FILE, NON_ONBOARDED_USER_FILE, ONBOARDED_USER_FILE, ROUTES } from "./utils/constants"; const e2eTestToken = "e2e_test_token"; -const createWorkspaceUrl = "/create-workspace"; -const onboardingUrl = /\/[\w-]+\/projects\/[\w-]+\/get-started/; -const surveyListUrl = /\/onboarded\/projects\/[\w-]+\/surveys/; - async function authenticateUser(page: Page, email: string, stateFile: string) { await page.goto("/"); await page.getByPlaceholder("Enter your email").fill(email); @@ -15,7 +12,13 @@ async function authenticateUser(page: Page, email: string, stateFile: string) { await page.getByRole("button", { name: /enter code manually/i }).click(); await page.fill('input[name="code"]', e2eTestToken); await page.getByRole("button", { name: /continue/i }).click(); - + await page.waitForURL((url) => { + return ( + ROUTES.ONBOARDING_URL.test(url.pathname) || + url.pathname === ROUTES.CREATE_WORKSPACE_URL || + ROUTES.SURVEY_LIST_URL.test(url.pathname) + ); + }); await page.context().storageState({ path: stateFile }); } @@ -33,25 +36,29 @@ setup("authenticate as onboarded user", async ({ page }) => { // Wait for the navigation to complete to one of the expected URLs await page.waitForURL((url) => { return ( - onboardingUrl.test(url.pathname) || url.pathname === createWorkspaceUrl || surveyListUrl.test(url.pathname) + ROUTES.ONBOARDING_URL.test(url.pathname) || + url.pathname === ROUTES.CREATE_WORKSPACE_URL || + ROUTES.SURVEY_LIST_URL.test(url.pathname) ); }); const currentUrl = page.url(); - if (currentUrl.includes(createWorkspaceUrl)) { - await expect(page).toHaveURL(createWorkspaceUrl); + if (currentUrl.includes(ROUTES.CREATE_WORKSPACE_URL)) { + await expect(page).toHaveURL(ROUTES.CREATE_WORKSPACE_URL); await expect(page.locator("h3")).toContainText("Create a new workspace"); await page.locator('[name="workspaceName"]').fill("onboarded"); await page.locator('[name="workspaceUrl"]').fill("onboarded"); await page.getByRole("button", { name: /Create Workspace/i }).click(); - await page.waitForURL(onboardingUrl); - await expect(page).toHaveURL(onboardingUrl); + await page.waitForURL(ROUTES.ONBOARDING_URL); + await expect(page).toHaveURL(ROUTES.ONBOARDING_URL); await handleOnboardingSteps(page); - } else if (surveyListUrl.test(currentUrl)) { - await expect(page).toHaveURL(surveyListUrl); + } else if (ROUTES.SURVEY_LIST_URL.test(currentUrl)) { + console.log("survey list"); + await expect(page).toHaveURL(ROUTES.SURVEY_LIST_URL); + await expect(page.locator("h1").nth(0)).toContainText(/Create your first survey/i); } else { throw new Error(`Unexpected URL: ${currentUrl}`); } @@ -61,24 +68,24 @@ setup("authenticate as non onboarded user", async ({ page }) => { await authenticateUser(page, "test2@example.com", NON_ONBOARDED_USER_FILE); await page.waitForURL((url) => { - return onboardingUrl.test(url.pathname) || url.pathname === createWorkspaceUrl; + return ROUTES.ONBOARDING_URL.test(url.pathname) || url.pathname === ROUTES.CREATE_WORKSPACE_URL; }); const currentUrl = page.url(); - if (currentUrl.includes(createWorkspaceUrl)) { - await expect(page).toHaveURL(createWorkspaceUrl); + if (currentUrl.includes(ROUTES.CREATE_WORKSPACE_URL)) { + await expect(page).toHaveURL(ROUTES.CREATE_WORKSPACE_URL); await expect(page.locator("h3")).toContainText("Create a new workspace"); - await page.locator('[name="workspaceName"]').fill("test2"); - await page.locator('[name="workspaceUrl"]').fill("test2"); + await page.locator('[name="workspaceName"]').fill(faker.word.words(2)); + await page.locator('[name="workspaceUrl"]').fill(`${faker.word.words(1)}-${faker.word.words(1)}`); await page.getByRole("button", { name: /Create Workspace/i }).click(); - await page.waitForURL(onboardingUrl); - await expect(page).toHaveURL(onboardingUrl); + await page.waitForURL(ROUTES.ONBOARDING_URL); + await expect(page).toHaveURL(ROUTES.ONBOARDING_URL); await expect(page.locator("h1").nth(0)).toContainText("Getting started"); - } else if (onboardingUrl.test(currentUrl)) { - await expect(page).toHaveURL(onboardingUrl); + } else if (ROUTES.ONBOARDING_URL.test(currentUrl)) { + await expect(page).toHaveURL(ROUTES.ONBOARDING_URL); await expect(page.locator("h1").nth(0)).toContainText("Getting started"); } else { throw new Error(`Unexpected URL: ${currentUrl}`); diff --git a/apps/frontend/tests/utils/constants.ts b/apps/frontend/tests/utils/constants.ts index 90731adc..baf85ed8 100644 --- a/apps/frontend/tests/utils/constants.ts +++ b/apps/frontend/tests/utils/constants.ts @@ -1,3 +1,9 @@ export const NEW_USER_FILE = "playwright/.auth/newUser.json"; export const ONBOARDED_USER_FILE = "playwright/.auth/onboardedUser.json"; export const NON_ONBOARDED_USER_FILE = "playwright/.auth/nonOnboardedUser.json"; + +export const ROUTES = { + CREATE_WORKSPACE_URL: "/create-workspace", + ONBOARDING_URL: /\/[\w-]+\/projects\/[\w-]+\/get-started/, + SURVEY_LIST_URL: /\/[\w-]+\/projects\/[\w-]+\/surveys/, +}; diff --git a/apps/frontend/tests/workspace/create-workspace.spec.ts b/apps/frontend/tests/workspace/create-workspace.spec.ts index 0a70ffb2..883c6492 100644 --- a/apps/frontend/tests/workspace/create-workspace.spec.ts +++ b/apps/frontend/tests/workspace/create-workspace.spec.ts @@ -1,10 +1,49 @@ -import { test } from "@playwright/test"; -import { ONBOARDED_USER_FILE } from "../utils/constants"; +import { faker } from "@faker-js/faker"; +import { expect, test } from "@playwright/test"; +import { ROUTES } from "../utils/constants"; + +const word1 = faker.word.words(1); +const word2 = faker.word.words(1); +const workspaceUrl = `${word1}-${word2}`; test.describe("Create workspace", () => { - test.use({ storageState: ONBOARDED_USER_FILE }); + test.beforeEach(async ({ page }) => { + await page.goto(ROUTES.CREATE_WORKSPACE_URL); + await page.waitForSelector("h3"); + await expect(page.locator("h3")).toContainText("Create a new workspace"); + }); + // test.use({ storageState: NON_ONBOARDED_USER_FILE }); + + test("should allow user to create a new workspace", async ({ page }) => { + await page.locator('[name="workspaceName"]').fill(faker.word.words(2)); + // await page.locator('[name="workspaceUrl"]').fill(faker.word.words(2)); + await page.getByRole("button", { name: /Create Workspace/i }).click(); + + await page.waitForURL((url) => { + return ROUTES.SURVEY_LIST_URL.test(url.pathname); + }); + + await expect(page.locator("h1").nth(0)).toContainText(/Create your first survey/i); + }); + + test("should allow specifying workspace URL", async ({ page }) => { + await page.locator('[name="workspaceName"]').fill(faker.word.words(2)); + await page.locator('[name="workspaceUrl"]').fill(workspaceUrl); + + await page.getByRole("button", { name: /Create Workspace/i }).click(); + + await page.waitForURL((url) => { + return ROUTES.SURVEY_LIST_URL.test(url.pathname); + }); + + await expect(page.locator("h1").nth(0)).toContainText(/Create your first survey/i); + }); + + test("should not allow repeating workspace URL", async ({ page }) => { + await page.locator('[name="workspaceName"]').fill(faker.word.words(2)); + await page.locator('[name="workspaceUrl"]').fill(workspaceUrl); + await page.getByRole("button", { name: /Create Workspace/i }).click(); - test("should allow new user to create a new workspace", async ({ page }) => { - await page.goto("/create-workspace"); + await expect(page.locator(".tremor-TextInput-errorMessage")).toBeVisible(); }); }); From fc0e9c01aced4bb278b483e29cf09b3d7b22f1a6 Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 21 Aug 2024 14:26:30 +0100 Subject: [PATCH 02/16] update workspace test --- apps/frontend/playwright.config.ts | 2 +- apps/frontend/tests/workspace/create-workspace.spec.ts | 8 +++----- yarn.lock | 5 +++++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/frontend/playwright.config.ts b/apps/frontend/playwright.config.ts index 09c06649..fb183422 100644 --- a/apps/frontend/playwright.config.ts +++ b/apps/frontend/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 2 : undefined, + workers: undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ diff --git a/apps/frontend/tests/workspace/create-workspace.spec.ts b/apps/frontend/tests/workspace/create-workspace.spec.ts index 883c6492..dd3638df 100644 --- a/apps/frontend/tests/workspace/create-workspace.spec.ts +++ b/apps/frontend/tests/workspace/create-workspace.spec.ts @@ -12,11 +12,9 @@ test.describe("Create workspace", () => { await page.waitForSelector("h3"); await expect(page.locator("h3")).toContainText("Create a new workspace"); }); - // test.use({ storageState: NON_ONBOARDED_USER_FILE }); test("should allow user to create a new workspace", async ({ page }) => { await page.locator('[name="workspaceName"]').fill(faker.word.words(2)); - // await page.locator('[name="workspaceUrl"]').fill(faker.word.words(2)); await page.getByRole("button", { name: /Create Workspace/i }).click(); await page.waitForURL((url) => { @@ -26,7 +24,7 @@ test.describe("Create workspace", () => { await expect(page.locator("h1").nth(0)).toContainText(/Create your first survey/i); }); - test("should allow specifying workspace URL", async ({ page }) => { + test("should not allow repeating workspace URL", async ({ page }) => { await page.locator('[name="workspaceName"]').fill(faker.word.words(2)); await page.locator('[name="workspaceUrl"]').fill(workspaceUrl); @@ -37,9 +35,9 @@ test.describe("Create workspace", () => { }); await expect(page.locator("h1").nth(0)).toContainText(/Create your first survey/i); - }); - test("should not allow repeating workspace URL", async ({ page }) => { + await page.goto(ROUTES.CREATE_WORKSPACE_URL); + await page.waitForSelector("h3"); await page.locator('[name="workspaceName"]').fill(faker.word.words(2)); await page.locator('[name="workspaceUrl"]').fill(workspaceUrl); await page.getByRole("button", { name: /Create Workspace/i }).click(); diff --git a/yarn.lock b/yarn.lock index 1f387ce7..74932664 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1732,6 +1732,11 @@ dependencies: "@f/map-obj" "^1.2.2" +"@faker-js/faker@^8.4.1": + version "8.4.1" + resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.4.1.tgz#5d5e8aee8fce48f5e189bf730ebd1f758f491451" + integrity sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg== + "@floating-ui/core@^1.0.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" From 353c326d4b340fad0123223d9874c9a64249ba51 Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 21 Aug 2024 14:44:00 +0100 Subject: [PATCH 03/16] update create workspace test --- apps/frontend/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/playwright.config.ts b/apps/frontend/playwright.config.ts index fb183422..97f1c330 100644 --- a/apps/frontend/playwright.config.ts +++ b/apps/frontend/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: undefined, + workers: "100%", /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ From 82864ab5891275f5b37953cfa59dec49b2ae72a4 Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 21 Aug 2024 15:01:16 +0100 Subject: [PATCH 04/16] update workspace test --- apps/frontend/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/playwright.config.ts b/apps/frontend/playwright.config.ts index 97f1c330..242df480 100644 --- a/apps/frontend/playwright.config.ts +++ b/apps/frontend/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: "100%", + workers: process.env.CI ? "100%" : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ From 06b57cb1fccc2804012133f4590a318bc6d7b57b Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 21 Aug 2024 15:26:14 +0100 Subject: [PATCH 05/16] update auth layout --- .github/workflows/playwright.yml | 2 -- apps/frontend/src/layout/AuthLayout.tsx | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 8b9dd2ad..a214e3f5 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -32,8 +32,6 @@ jobs: - name: Build dashboard run: yarn build:dashboard - env: - VITE_SERVER_BASE_URL: http://localhost:8000 - name: Start Backend Server run: docker compose -f ./docker-compose-test.yml up -d diff --git a/apps/frontend/src/layout/AuthLayout.tsx b/apps/frontend/src/layout/AuthLayout.tsx index e7ebd192..f54e23aa 100644 --- a/apps/frontend/src/layout/AuthLayout.tsx +++ b/apps/frontend/src/layout/AuthLayout.tsx @@ -6,7 +6,7 @@ import Profile2 from "../assets/images/loginScreen/profile-2.png"; import Profile3 from "../assets/images/loginScreen/profile-3.png"; import Logo from "../assets/images/logo.png"; -const clientId = import.meta.env.VITE_GOOGLE_CLIENT_ID; +const clientId = import.meta.env.VITE_GOOGLE_CLIENT_ID ?? ""; export function AuthLayout() { return ( From ea3f194e046d49d56b01c500b3a7c5b5d9c1912f Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 21 Aug 2024 15:35:36 +0100 Subject: [PATCH 06/16] update config --- apps/frontend/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/playwright.config.ts b/apps/frontend/playwright.config.ts index 242df480..eee11751 100644 --- a/apps/frontend/playwright.config.ts +++ b/apps/frontend/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? "100%" : undefined, + workers: process.env.CI ? "75%" : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ From a2c647049439592319991f9a799594473d5b837a Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 21 Aug 2024 15:56:54 +0100 Subject: [PATCH 07/16] update action --- .github/workflows/playwright.yml | 6 ++++++ apps/frontend/playwright.config.ts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index a214e3f5..6f878150 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -32,6 +32,12 @@ jobs: - name: Build dashboard run: yarn build:dashboard + env: + VITE_GOOGLE_CLIENT_ID: ${{ secrets.VITE_GOOGLE_CLIENT_ID }} + VITE_SERVER_BASE_URL: ${{ secrets.VITE_SERVER_BASE_URL }} + VITE_LINK_SURVEY_HOST: ${{ secrets.VITE_LINK_SURVEY_HOST }} + VITE_PUBLIC_POSTHOG_KEY: ${{ secrets.VITE_PUBLIC_POSTHOG_KEY }} + VITE_PUBLIC_POSTHOG_HOST: ${{ secrets.VITE_PUBLIC_POSTHOG_HOST }} - name: Start Backend Server run: docker compose -f ./docker-compose-test.yml up -d diff --git a/apps/frontend/playwright.config.ts b/apps/frontend/playwright.config.ts index eee11751..242df480 100644 --- a/apps/frontend/playwright.config.ts +++ b/apps/frontend/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? "75%" : undefined, + workers: process.env.CI ? "100%" : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ From 18b82d538c27ab907888e485f62633708864b32a Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 21 Aug 2024 16:15:49 +0100 Subject: [PATCH 08/16] update config --- apps/frontend/playwright.config.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/frontend/playwright.config.ts b/apps/frontend/playwright.config.ts index 242df480..a1c0f2ec 100644 --- a/apps/frontend/playwright.config.ts +++ b/apps/frontend/playwright.config.ts @@ -19,8 +19,6 @@ export default defineConfig({ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? "100%" : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "html", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ From ab233583c10e20fcaf5298cafdbf23a49d852270 Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 11 Sep 2024 19:31:28 +0100 Subject: [PATCH 09/16] update auth provider --- apps/frontend/src/modules/auth/AuthProvider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/modules/auth/AuthProvider.tsx b/apps/frontend/src/modules/auth/AuthProvider.tsx index 320da3fc..a1a42c23 100644 --- a/apps/frontend/src/modules/auth/AuthProvider.tsx +++ b/apps/frontend/src/modules/auth/AuthProvider.tsx @@ -291,7 +291,7 @@ export const AuthProvider = ({ children, apollo, purgePersistedCache }: AuthProv const workspace = useMemo(() => { const slug = orgSlug ?? user?.organization?.slug; - return organizations.find((organization) => organization?.slug === slug) ?? null; + return organizations.find((organization) => organization?.slug?.toLowerCase() === slug?.toLowerCase()) ?? null; }, [orgSlug, user?.organization?.slug, organizations]); const projects = useMemo(() => { @@ -313,7 +313,7 @@ export const AuthProvider = ({ children, apollo, purgePersistedCache }: AuthProv const slug = projectSlug ?? user?.project?.slug; - return projects?.find((project) => project?.slug === slug) ?? null; + return projects?.find((project) => project?.slug?.toLowerCase() === slug?.toLowerCase()) ?? null; }, [user, orgSlug, projectSlug, projects, workspace]); const handleUserUpdate = useCallback( From 084bf18f107f38e5cda04c495664bb8c907e5449 Mon Sep 17 00:00:00 2001 From: Afeez G Lawal Date: Wed, 11 Sep 2024 19:48:36 +0100 Subject: [PATCH 10/16] update auth provider --- apps/frontend/src/modules/auth/AuthProvider.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/modules/auth/AuthProvider.tsx b/apps/frontend/src/modules/auth/AuthProvider.tsx index a1a42c23..82ff5adf 100644 --- a/apps/frontend/src/modules/auth/AuthProvider.tsx +++ b/apps/frontend/src/modules/auth/AuthProvider.tsx @@ -354,7 +354,10 @@ export const AuthProvider = ({ children, apollo, purgePersistedCache }: AuthProv switchProject(project.id); } - if (orgSlug !== organization?.slug || projectSlug !== project.slug) { + if ( + orgSlug?.toLowerCase() !== organization?.slug.toLowerCase() || + projectSlug?.toLowerCase() !== project.slug.toLowerCase() + ) { redirect({ ...(user ?? {}), ...updatedUser, From d6e6c2cee317cfd69b0dd916be399f6b44c9ef75 Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 18 Sep 2024 16:30:56 +0100 Subject: [PATCH 11/16] update workspace test --- .../tests/workspace/create-workspace.spec.ts | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/apps/frontend/tests/workspace/create-workspace.spec.ts b/apps/frontend/tests/workspace/create-workspace.spec.ts index dd3638df..63b050ad 100644 --- a/apps/frontend/tests/workspace/create-workspace.spec.ts +++ b/apps/frontend/tests/workspace/create-workspace.spec.ts @@ -1,6 +1,8 @@ import { faker } from "@faker-js/faker"; +import fs from "fs"; + import { expect, test } from "@playwright/test"; -import { ROUTES } from "../utils/constants"; +import { ROUTES, userDetailsFile } from "../utils/constants"; const word1 = faker.word.words(1); const word2 = faker.word.words(1); @@ -8,7 +10,7 @@ const workspaceUrl = `${word1}-${word2}`; test.describe("Create workspace", () => { test.beforeEach(async ({ page }) => { - await page.goto(ROUTES.CREATE_WORKSPACE_URL); + await page.goto(ROUTES.WORKSPACE.CREATE); await page.waitForSelector("h3"); await expect(page.locator("h3")).toContainText("Create a new workspace"); }); @@ -18,9 +20,17 @@ test.describe("Create workspace", () => { await page.getByRole("button", { name: /Create Workspace/i }).click(); await page.waitForURL((url) => { - return ROUTES.SURVEY_LIST_URL.test(url.pathname); + return ROUTES.PATTERNS.SURVEY_LIST_URL.test(url.pathname); }); + const url = new URL(page.url()); + + const workspaceSlug = url.pathname.split("/")[1]; + const projectSlug = url.pathname.split("/")[3]; + const details = { workspaceSlug, projectSlug }; + + fs.writeFileSync(userDetailsFile, JSON.stringify(details), "utf-8"); + await expect(page.locator("h1").nth(0)).toContainText(/Create your first survey/i); }); @@ -31,17 +41,26 @@ test.describe("Create workspace", () => { await page.getByRole("button", { name: /Create Workspace/i }).click(); await page.waitForURL((url) => { - return ROUTES.SURVEY_LIST_URL.test(url.pathname); + return ROUTES.PATTERNS.SURVEY_LIST_URL.test(url.pathname); }); + const url = new URL(page.url()); + + const workspaceSlug = url.pathname.split("/")[1]; + const projectSlug = url.pathname.split("/")[3]; + const details = { workspaceSlug, projectSlug }; + + fs.writeFileSync(userDetailsFile, JSON.stringify(details), "utf-8"); + await expect(page.locator("h1").nth(0)).toContainText(/Create your first survey/i); - await page.goto(ROUTES.CREATE_WORKSPACE_URL); + await page.goto(ROUTES.WORKSPACE.CREATE); await page.waitForSelector("h3"); await page.locator('[name="workspaceName"]').fill(faker.word.words(2)); await page.locator('[name="workspaceUrl"]').fill(workspaceUrl); await page.getByRole("button", { name: /Create Workspace/i }).click(); + await page.locator(".tremor-TextInput-errorMessage").waitFor({ state: "attached" }); await expect(page.locator(".tremor-TextInput-errorMessage")).toBeVisible(); }); }); From d6967f36b83c8573981c4e93f075c4a9c9bb0796 Mon Sep 17 00:00:00 2001 From: afolasope Date: Mon, 23 Sep 2024 16:09:59 +0100 Subject: [PATCH 12/16] redirect user after updating workspace --- .../components/settings/Workspace/General.tsx | 16 +++++++++++++++- .../src/modules/workspace/hooks/useWorkspace.tsx | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx index 494495b4..573f9720 100644 --- a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx +++ b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx @@ -1,7 +1,10 @@ +import { useProject } from "@/modules/projects/hooks/useProject"; import { useWorkspace } from "@/modules/workspace/hooks/useWorkspace"; +import { ROUTES } from "@/routes"; import { Button, TextInput } from "@/ui"; import { toast } from "@/utils/toast"; import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; type WorkspaceData = { workspaceName: string | undefined; @@ -9,7 +12,9 @@ type WorkspaceData = { }; export const General = () => { + const navigate = useNavigate(); const { workspace, updateWorkspace } = useWorkspace(); + const { project } = useProject(); const { register, @@ -28,13 +33,22 @@ export const General = () => { return; } - await updateWorkspace( + const response = await updateWorkspace( { name: formInfo.workspaceName, slug: formInfo.workspaceUrl, }, false, ); + + if (response?.data?.organizationUpdate) { + navigate( + `${ROUTES.WORKSPACE_SETTINGS}` + .replace(":orgSlug", response.data.organizationUpdate.organization?.slug!) + .replace(":projectSlug", project?.slug!), + ); + } + toast.success(`Your organization name has been updated`); }; return ( diff --git a/apps/frontend/src/modules/workspace/hooks/useWorkspace.tsx b/apps/frontend/src/modules/workspace/hooks/useWorkspace.tsx index fcc1beae..f9c09ef3 100644 --- a/apps/frontend/src/modules/workspace/hooks/useWorkspace.tsx +++ b/apps/frontend/src/modules/workspace/hooks/useWorkspace.tsx @@ -88,6 +88,7 @@ export const useWorkspace = () => { if (response.data?.organizationUpdate?.organization) { updateUserCache(response.data?.organizationUpdate?.organization); } + return response; } catch (error) { console.error(error); } From 82cba379055f21251d78769d8d45692d2558e12d Mon Sep 17 00:00:00 2001 From: afolasope Date: Mon, 23 Sep 2024 16:44:59 +0100 Subject: [PATCH 13/16] redirect user after workspace update --- .../workspace/components/settings/Workspace/General.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx index 573f9720..aabbe491 100644 --- a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx +++ b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx @@ -41,11 +41,11 @@ export const General = () => { false, ); - if (response?.data?.organizationUpdate) { + if (response?.data?.organizationUpdate?.organization?.slug && project?.slug) { navigate( `${ROUTES.WORKSPACE_SETTINGS}` - .replace(":orgSlug", response.data.organizationUpdate.organization?.slug!) - .replace(":projectSlug", project?.slug!), + .replace(":orgSlug", response.data.organizationUpdate.organization?.slug) + .replace(":projectSlug", project?.slug), ); } From 1d97f5532efc650a7a6292bcf832caa495fe6839 Mon Sep 17 00:00:00 2001 From: afolasope Date: Mon, 23 Sep 2024 17:04:10 +0100 Subject: [PATCH 14/16] redirect user after updating workspace --- .../workspace/components/settings/Workspace/General.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx index aabbe491..cb919d96 100644 --- a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx +++ b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx @@ -47,9 +47,10 @@ export const General = () => { .replace(":orgSlug", response.data.organizationUpdate.organization?.slug) .replace(":projectSlug", project?.slug), ); + toast.success(`Your organization name has been updated`); + } else { + toast.success(`Your organization failed to update, please try again later`); } - - toast.success(`Your organization name has been updated`); }; return (
From fd6a46e42c0f9d238c652e688963c7a72137643c Mon Sep 17 00:00:00 2001 From: Afeez G Lawal Date: Mon, 23 Sep 2024 17:16:27 +0100 Subject: [PATCH 15/16] update toast --- .../modules/workspace/components/settings/Workspace/General.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx index cb919d96..a83d88b8 100644 --- a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx +++ b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx @@ -49,7 +49,7 @@ export const General = () => { ); toast.success(`Your organization name has been updated`); } else { - toast.success(`Your organization failed to update, please try again later`); + toast.error(`Your organization failed to update, please try again later`); } }; return ( From 78c0b4a8e5833481d70a9b647d3e1eb92c969a32 Mon Sep 17 00:00:00 2001 From: afolasope Date: Wed, 25 Sep 2024 12:31:38 +0100 Subject: [PATCH 16/16] update workspace test --- apps/frontend/src/layout/partials/Navbar.tsx | 1 + .../src/layout/partials/UserProfile.tsx | 1 + .../components/invite/WorkspaceInvite.tsx | 12 ++- .../components/settings/Workspace/General.tsx | 23 +++-- apps/frontend/tests/auth.setup.ts | 16 ++- apps/frontend/tests/auth/auth.setup.ts | 99 ------------------- apps/frontend/tests/utils/constants.ts | 9 ++ apps/frontend/tests/utils/helper.ts | 4 +- .../tests/workspace/manage-workspace.spec.ts | 32 ++++++ .../tests/workspace/update-workspace.spec.ts | 67 +++++++++++++ 10 files changed, 145 insertions(+), 119 deletions(-) delete mode 100644 apps/frontend/tests/auth/auth.setup.ts create mode 100644 apps/frontend/tests/workspace/update-workspace.spec.ts diff --git a/apps/frontend/src/layout/partials/Navbar.tsx b/apps/frontend/src/layout/partials/Navbar.tsx index e68e8b29..a92084b7 100644 --- a/apps/frontend/src/layout/partials/Navbar.tsx +++ b/apps/frontend/src/layout/partials/Navbar.tsx @@ -248,6 +248,7 @@ export const Navbar = () => { onClick={() => { setOpenOrganizationInviteModal(true); }} + data-testid="invite-team-btn" > diff --git a/apps/frontend/src/layout/partials/UserProfile.tsx b/apps/frontend/src/layout/partials/UserProfile.tsx index 01a3fd0d..e7691016 100644 --- a/apps/frontend/src/layout/partials/UserProfile.tsx +++ b/apps/frontend/src/layout/partials/UserProfile.tsx @@ -147,6 +147,7 @@ export const UserProfile = () => { navigate( diff --git a/apps/frontend/src/modules/workspace/components/invite/WorkspaceInvite.tsx b/apps/frontend/src/modules/workspace/components/invite/WorkspaceInvite.tsx index 4a3a15ca..efcb69e7 100644 --- a/apps/frontend/src/modules/workspace/components/invite/WorkspaceInvite.tsx +++ b/apps/frontend/src/modules/workspace/components/invite/WorkspaceInvite.tsx @@ -1,5 +1,5 @@ import { Link, LucideMail, RefreshCcwIcon } from "lucide-react"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { OrganizationErrorCode, OrganizationInvite, OrganizationInviteCreate, User } from "@/generated/graphql"; import { useAuth } from "@/modules/auth/hooks/useAuth"; @@ -36,6 +36,10 @@ export const WorkspaceInvite = ({ open, onOpenChange }: Props) => { } }; + useEffect(() => { + handleLinkInvite(); + }, [onOpenChange]); + const handleEmailInvite = async (e: React.FormEvent) => { e.preventDefault(); if (!inviteEmail) { @@ -169,7 +173,7 @@ export const WorkspaceInvite = ({ open, onOpenChange }: Props) => { ) : ( -
+

Invite link will provide a unique URL that allows anyone to join your organization.

@@ -185,6 +189,7 @@ export const WorkspaceInvite = ({ open, onOpenChange }: Props) => { size="sm" disabled={loading} onClick={handleInviteLinkRefresh} + data-testid="refresh-invite-link" icon={ { } /> } + data-testid="invite-link" />
diff --git a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx index a83d88b8..954bfff3 100644 --- a/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx +++ b/apps/frontend/src/modules/workspace/components/settings/Workspace/General.tsx @@ -1,7 +1,7 @@ import { useProject } from "@/modules/projects/hooks/useProject"; import { useWorkspace } from "@/modules/workspace/hooks/useWorkspace"; import { ROUTES } from "@/routes"; -import { Button, TextInput } from "@/ui"; +import { Button, GlobalSpinner, TextInput } from "@/ui"; import { toast } from "@/utils/toast"; import { useForm } from "react-hook-form"; import { useNavigate } from "react-router-dom"; @@ -12,9 +12,9 @@ type WorkspaceData = { }; export const General = () => { - const navigate = useNavigate(); - const { workspace, updateWorkspace } = useWorkspace(); const { project } = useProject(); + const { workspace, updateWorkspace, loading } = useWorkspace(); + const navigate = useNavigate(); const { register, @@ -40,18 +40,19 @@ export const General = () => { }, false, ); - - if (response?.data?.organizationUpdate?.organization?.slug && project?.slug) { + if (response?.data?.organizationUpdate) { navigate( `${ROUTES.WORKSPACE_SETTINGS}` - .replace(":orgSlug", response.data.organizationUpdate.organization?.slug) - .replace(":projectSlug", project?.slug), + .replace(":orgSlug", response?.data?.organizationUpdate?.organization?.slug!) + .replace(":projectSlug", project?.slug!), ); - toast.success(`Your organization name has been updated`); - } else { - toast.error(`Your organization failed to update, please try again later`); } + toast.success(`Your organization name has been updated`); }; + + if (loading) { + return ; + } return (
@@ -75,6 +76,7 @@ export const General = () => { defaultValue={workspace?.name} error={!!errors.workspaceName?.message} errorMessage={errors.workspaceName?.message} + data-testid="workspace-name" /> { })} error={!!errors.workspaceUrl?.message} errorMessage={errors.workspaceUrl?.message} + data-testid="workspace-url" />