Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
14 changes: 13 additions & 1 deletion packages/js/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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");
Expand Down
80 changes: 77 additions & 3 deletions packages/js/src/lib/load-formbricks.test.ts
Original file line number Diff line number Diff line change
@@ -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<void>;
let setup: (config: TSetupConfig) => Promise<void>;
let callMethod: (method: string, ...args: unknown[]) => Promise<void>;

// Mock the globalThis formbricks object
Expand Down Expand Up @@ -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({
Expand All @@ -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",
Expand Down
34 changes: 19 additions & 15 deletions packages/js/src/lib/load-formbricks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TFormbricks } from "../types/formbricks";
import type { TFormbricks, TSetupConfig } from "../types/formbricks";

type Result<T, E = Error> = { ok: true; data: T } | { ok: false; error: E };

Expand Down Expand Up @@ -76,30 +76,37 @@
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;

Check warning on line 80 in packages/js/src/lib/load-formbricks.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'environmentId' is deprecated.

See more on https://sonarcloud.io/project/issues?id=formbricks_js&issues=AZ2-J7wJ7cCKCwTggt9s&open=AZ2-J7wJ7cCKCwTggt9s&pullRequest=47

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 => {
Expand All @@ -126,10 +133,7 @@
}
};

export const setup = async (config: {
appUrl: string;
environmentId: string;
}): Promise<void> => {
export const setup = async (config: TSetupConfig): Promise<void> => {
if (isInitializing) {
console.warn(
"🧱 Formbricks - Warning: Formbricks is already initializing.",
Expand Down
14 changes: 10 additions & 4 deletions packages/js/src/types/formbricks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>;
setup: (setupConfig: TSetupConfig) => Promise<void>;

/**
* @description Sets the email of the user.
Expand Down Expand Up @@ -67,3 +64,12 @@ export interface TFormbricks {
*/
registerRouteChange: () => Promise<void>;
}

export type TSetupConfig = {
workspaceId?: string;
/**
* @deprecated use workspaceId instead, environmentId will be removed in a future version
*/
environmentId?: string;
appUrl: string;
};
Loading