diff --git a/packages/js/README.md b/packages/js/README.md index c4a4f8a..effeb27 100644 --- a/packages/js/README.md +++ b/packages/js/README.md @@ -25,12 +25,14 @@ import formbricks from "@formbricks/js"; if (typeof window !== "undefined") { formbricks.setup({ - environmentId: "your-environment-id", + workspaceId: "your-workspace-id", appUrl: "https://app.formbricks.com", }); } ``` -Replace your-environment-id with your actual environment ID. You can find your environment ID in the **Setup Checklist** in the Formbricks settings. If you want to use the user identification feature, please check out [our docs for details](https://formbricks.com/docs/app-surveys/user-identification). +Replace your-workspace-id with your actual workspace ID. You can find your workspace ID in the **Setup Checklist** in the Formbricks settings. If you want to use the user identification feature, please check out [our docs for details](https://formbricks.com/docs/app-surveys/user-identification). + +> `environmentId` is still accepted for backward compatibility but is deprecated and will be removed in a future version. Prefer `workspaceId`. For more detailed guides for different frameworks, check out our [Framework Guides](https://formbricks.com/docs/getting-started/framework-guides). diff --git a/packages/js/src/index.test.ts b/packages/js/src/index.test.ts index 01cdeb6..15e01db 100644 --- a/packages/js/src/index.test.ts +++ b/packages/js/src/index.test.ts @@ -24,7 +24,18 @@ describe("formbricks", () => { expect(typeof formbricks).toBe("object"); }); - test("should delegate setup to setup()", async () => { + test("should delegate setup to setup() (workspaceId)", async () => { + const setupArgs = { + workspaceId: "ws123", + appUrl: "https://app.formbricks.com", + }; + + await formbricks.setup(setupArgs); + + expect(mockSetup).toHaveBeenCalledWith(setupArgs); + }); + + test("should delegate setup to setup() (environmentId backward compat)", async () => { const setupArgs = { environmentId: "env123", appUrl: "https://app.formbricks.com", @@ -212,6 +223,7 @@ describe("type safety", () => { test("should maintain type safety for known methods", () => { const testTypeSafety = () => { + void formbricks.setup({ workspaceId: "ws", appUrl: "url" }); void formbricks.setup({ environmentId: "env", appUrl: "url" }); void formbricks.track("event"); void formbricks.setEmail("email"); diff --git a/packages/js/src/lib/load-formbricks.test.ts b/packages/js/src/lib/load-formbricks.test.ts index 3565c75..6b72aa4 100644 --- a/packages/js/src/lib/load-formbricks.test.ts +++ b/packages/js/src/lib/load-formbricks.test.ts @@ -1,7 +1,8 @@ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; +import type { TSetupConfig } from "../types/formbricks"; // We need to import the module after each reset -let setup: (config: { appUrl: string; environmentId: string }) => Promise; +let setup: (config: TSetupConfig) => Promise; let callMethod: (method: string, ...args: unknown[]) => Promise; // Mock the globalThis formbricks object @@ -191,7 +192,7 @@ describe("load-formbricks", () => { ); }); - test("should log error when environmentId is missing", async () => { + test("should log error when both workspaceId and environmentId are missing", async () => { const consoleSpy = createConsoleErrorSpy(); await setup({ @@ -200,10 +201,83 @@ describe("load-formbricks", () => { }); expect(consoleSpy).toHaveBeenCalledWith( - "🧱 Formbricks - Error: environmentId is required", + "🧱 Formbricks - Error: workspaceId or environmentId is required", ); }); + test("should handle setup call with workspaceId", async () => { + const setupArgs = { + appUrl: "https://app.formbricks.com", + workspaceId: "ws123", + }; + + const mockAppendChild = vi + .spyOn(document.head, "appendChild") + .mockImplementation(createSuccessfulScriptMock()); + + await setup(setupArgs); + + expect(mockAppendChild).toHaveBeenCalledWith( + expect.objectContaining({ + src: `${setupArgs.appUrl}/js/formbricks.umd.cjs`, + type: "text/javascript", + async: true, + }), + ); + expect(mockFormbricks.setup).toHaveBeenCalledWith(setupArgs); + }); + + test("should warn about deprecation when only environmentId is provided", async () => { + const consoleWarnSpy = createConsoleWarnSpy(); + + vi.spyOn(document.head, "appendChild").mockImplementation( + createSuccessfulScriptMock(), + ); + + await setup({ + appUrl: "https://app.formbricks.com", + environmentId: "env123", + }); + + expect(consoleWarnSpy).toHaveBeenCalledWith( + "🧱 Formbricks - Warning: environmentId is deprecated and will be removed in a future version. Please use workspaceId instead.", + ); + }); + + test("should not warn about deprecation when workspaceId is provided", async () => { + const consoleWarnSpy = createConsoleWarnSpy(); + + vi.spyOn(document.head, "appendChild").mockImplementation( + createSuccessfulScriptMock(), + ); + + await setup({ + appUrl: "https://app.formbricks.com", + workspaceId: "ws123", + environmentId: "env123", + }); + + expect(consoleWarnSpy).not.toHaveBeenCalledWith( + expect.stringContaining("environmentId is deprecated"), + ); + }); + + test("should pass both workspaceId and environmentId through when both provided", async () => { + const setupArgs = { + appUrl: "https://app.formbricks.com", + workspaceId: "ws123", + environmentId: "env123", + }; + + vi.spyOn(document.head, "appendChild").mockImplementation( + createSuccessfulScriptMock(), + ); + + await setup(setupArgs); + + expect(mockFormbricks.setup).toHaveBeenCalledWith(setupArgs); + }); + test("should not load script again if formbricks is already available", async () => { const setupArgs = { appUrl: "https://app.formbricks.com", diff --git a/packages/js/src/lib/load-formbricks.ts b/packages/js/src/lib/load-formbricks.ts index b18e410..9ae5b4f 100644 --- a/packages/js/src/lib/load-formbricks.ts +++ b/packages/js/src/lib/load-formbricks.ts @@ -1,4 +1,4 @@ -import type { TFormbricks } from "../types/formbricks"; +import type { TFormbricks, TSetupConfig } from "../types/formbricks"; type Result = { ok: true; data: T } | { ok: false; error: E }; @@ -76,30 +76,37 @@ const loadFormbricksSDK = async (appUrl: string): Promise> => { return loadPromise; }; -const validateSetupArgs = ( - config: unknown, -): { appUrl: string; environmentId: string } | null => { - const { appUrl, environmentId } = config as { - appUrl: string; - environmentId: string; - }; +const validateSetupArgs = (config: TSetupConfig): TSetupConfig | null => { + const { appUrl, environmentId, workspaceId } = config; if (!appUrl) { console.error("🧱 Formbricks - Error: appUrl is required"); return null; } - if (!environmentId) { - console.error("🧱 Formbricks - Error: environmentId is required"); + if (!workspaceId && !environmentId) { + console.error( + "🧱 Formbricks - Error: workspaceId or environmentId is required", + ); return null; } + if (environmentId && !workspaceId) { + console.warn( + "🧱 Formbricks - Warning: environmentId is deprecated and will be removed in a future version. Please use workspaceId instead.", + ); + } + // Removing trailing slash const appUrlWithoutTrailingSlash = appUrl.endsWith("/") ? appUrl.slice(0, -1) : appUrl; - return { appUrl: appUrlWithoutTrailingSlash, environmentId }; + return { + appUrl: appUrlWithoutTrailingSlash, + ...(workspaceId ? { workspaceId } : {}), + ...(environmentId ? { environmentId } : {}), + }; }; const processQueue = (): void => { @@ -126,10 +133,7 @@ const processQueue = (): void => { } }; -export const setup = async (config: { - appUrl: string; - environmentId: string; -}): Promise => { +export const setup = async (config: TSetupConfig): Promise => { if (isInitializing) { console.warn( "🧱 Formbricks - Warning: Formbricks is already initializing.", diff --git a/packages/js/src/types/formbricks.ts b/packages/js/src/types/formbricks.ts index cc3f0ad..bede833 100644 --- a/packages/js/src/types/formbricks.ts +++ b/packages/js/src/types/formbricks.ts @@ -3,10 +3,7 @@ export interface TFormbricks { * @description Initializes the Formbricks SDK. * @param setupConfig - The configuration for the Formbricks SDK. */ - setup: (setupConfig: { - environmentId: string; - appUrl: string; - }) => Promise; + setup: (setupConfig: TSetupConfig) => Promise; /** * @description Sets the email of the user. @@ -67,3 +64,12 @@ export interface TFormbricks { */ registerRouteChange: () => Promise; } + +export type TSetupConfig = { + workspaceId?: string; + /** + * @deprecated use workspaceId instead, environmentId will be removed in a future version + */ + environmentId?: string; + appUrl: string; +};