Skip to content

Commit 99a490e

Browse files
authored
feat: formbricks v5 changes (#50)
* feat: adds workspace support * fixes coderabbit feedback * fixes feedback
1 parent ec4b03c commit 99a490e

5 files changed

Lines changed: 139 additions & 25 deletions

File tree

packages/js/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ import formbricks from "@formbricks/js";
2525

2626
if (typeof window !== "undefined") {
2727
formbricks.setup({
28-
environmentId: "your-environment-id",
28+
workspaceId: "your-workspace-id",
2929
appUrl: "https://app.formbricks.com",
3030
});
3131
}
3232
```
3333

34-
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).
34+
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).
35+
36+
> `environmentId` is still accepted for backward compatibility but is deprecated and will be removed in a future version. Prefer `workspaceId`.
3537
3638
For more detailed guides for different frameworks, check out our [Framework Guides](https://formbricks.com/docs/getting-started/framework-guides).

packages/js/src/index.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,18 @@ describe("formbricks", () => {
2424
expect(typeof formbricks).toBe("object");
2525
});
2626

27-
test("should delegate setup to setup()", async () => {
27+
test("should delegate setup to setup() (workspaceId)", async () => {
28+
const setupArgs = {
29+
workspaceId: "ws123",
30+
appUrl: "https://app.formbricks.com",
31+
};
32+
33+
await formbricks.setup(setupArgs);
34+
35+
expect(mockSetup).toHaveBeenCalledWith(setupArgs);
36+
});
37+
38+
test("should delegate setup to setup() (environmentId backward compat)", async () => {
2839
const setupArgs = {
2940
environmentId: "env123",
3041
appUrl: "https://app.formbricks.com",
@@ -212,6 +223,7 @@ describe("type safety", () => {
212223

213224
test("should maintain type safety for known methods", () => {
214225
const testTypeSafety = () => {
226+
void formbricks.setup({ workspaceId: "ws", appUrl: "url" });
215227
void formbricks.setup({ environmentId: "env", appUrl: "url" });
216228
void formbricks.track("event");
217229
void formbricks.setEmail("email");

packages/js/src/lib/load-formbricks.test.ts

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
2+
import type { TSetupConfig } from "../types/formbricks";
23

34
// We need to import the module after each reset
4-
let setup: (config: { appUrl: string; environmentId: string }) => Promise<void>;
5+
let setup: (config: TSetupConfig) => Promise<void>;
56
let callMethod: (method: string, ...args: unknown[]) => Promise<void>;
67

78
// Mock the globalThis formbricks object
@@ -191,7 +192,7 @@ describe("load-formbricks", () => {
191192
);
192193
});
193194

194-
test("should log error when environmentId is missing", async () => {
195+
test("should log error when both workspaceId and environmentId are missing", async () => {
195196
const consoleSpy = createConsoleErrorSpy();
196197

197198
await setup({
@@ -200,10 +201,83 @@ describe("load-formbricks", () => {
200201
});
201202

202203
expect(consoleSpy).toHaveBeenCalledWith(
203-
"🧱 Formbricks - Error: environmentId is required",
204+
"🧱 Formbricks - Error: workspaceId or environmentId is required",
204205
);
205206
});
206207

208+
test("should handle setup call with workspaceId", async () => {
209+
const setupArgs = {
210+
appUrl: "https://app.formbricks.com",
211+
workspaceId: "ws123",
212+
};
213+
214+
const mockAppendChild = vi
215+
.spyOn(document.head, "appendChild")
216+
.mockImplementation(createSuccessfulScriptMock());
217+
218+
await setup(setupArgs);
219+
220+
expect(mockAppendChild).toHaveBeenCalledWith(
221+
expect.objectContaining({
222+
src: `${setupArgs.appUrl}/js/formbricks.umd.cjs`,
223+
type: "text/javascript",
224+
async: true,
225+
}),
226+
);
227+
expect(mockFormbricks.setup).toHaveBeenCalledWith(setupArgs);
228+
});
229+
230+
test("should warn about deprecation when only environmentId is provided", async () => {
231+
const consoleWarnSpy = createConsoleWarnSpy();
232+
233+
vi.spyOn(document.head, "appendChild").mockImplementation(
234+
createSuccessfulScriptMock(),
235+
);
236+
237+
await setup({
238+
appUrl: "https://app.formbricks.com",
239+
environmentId: "env123",
240+
});
241+
242+
expect(consoleWarnSpy).toHaveBeenCalledWith(
243+
"🧱 Formbricks - Warning: environmentId is deprecated and will be removed in a future version. Please use workspaceId instead.",
244+
);
245+
});
246+
247+
test("should not warn about deprecation when workspaceId is provided", async () => {
248+
const consoleWarnSpy = createConsoleWarnSpy();
249+
250+
vi.spyOn(document.head, "appendChild").mockImplementation(
251+
createSuccessfulScriptMock(),
252+
);
253+
254+
await setup({
255+
appUrl: "https://app.formbricks.com",
256+
workspaceId: "ws123",
257+
environmentId: "env123",
258+
});
259+
260+
expect(consoleWarnSpy).not.toHaveBeenCalledWith(
261+
expect.stringContaining("environmentId is deprecated"),
262+
);
263+
});
264+
265+
test("should pass both workspaceId and environmentId through when both provided", async () => {
266+
const setupArgs = {
267+
appUrl: "https://app.formbricks.com",
268+
workspaceId: "ws123",
269+
environmentId: "env123",
270+
};
271+
272+
vi.spyOn(document.head, "appendChild").mockImplementation(
273+
createSuccessfulScriptMock(),
274+
);
275+
276+
await setup(setupArgs);
277+
278+
expect(mockFormbricks.setup).toHaveBeenCalledWith(setupArgs);
279+
});
280+
207281
test("should not load script again if formbricks is already available", async () => {
208282
const setupArgs = {
209283
appUrl: "https://app.formbricks.com",

packages/js/src/lib/load-formbricks.ts

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { TFormbricks } from "../types/formbricks";
1+
import type { TFormbricks, TSetupConfig } from "../types/formbricks";
22

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

@@ -76,30 +76,44 @@ const loadFormbricksSDK = async (appUrl: string): Promise<Result<void>> => {
7676
return loadPromise;
7777
};
7878

79-
const validateSetupArgs = (
80-
config: unknown,
81-
): { appUrl: string; environmentId: string } | null => {
82-
const { appUrl, environmentId } = config as {
83-
appUrl: string;
84-
environmentId: string;
85-
};
79+
const validateSetupArgs = (config: TSetupConfig): TSetupConfig | null => {
80+
const { appUrl, environmentId, workspaceId } = config;
8681

8782
if (!appUrl) {
8883
console.error("🧱 Formbricks - Error: appUrl is required");
8984
return null;
9085
}
9186

92-
if (!environmentId) {
93-
console.error("🧱 Formbricks - Error: environmentId is required");
87+
if (!workspaceId && !environmentId) {
88+
console.error(
89+
"🧱 Formbricks - Error: workspaceId or environmentId is required",
90+
);
9491
return null;
9592
}
9693

94+
if (environmentId && !workspaceId) {
95+
console.warn(
96+
"🧱 Formbricks - Warning: environmentId is deprecated and will be removed in a future version. Please use workspaceId instead.",
97+
);
98+
}
99+
97100
// Removing trailing slash
98101
const appUrlWithoutTrailingSlash = appUrl.endsWith("/")
99102
? appUrl.slice(0, -1)
100103
: appUrl;
101104

102-
return { appUrl: appUrlWithoutTrailingSlash, environmentId };
105+
if (workspaceId) {
106+
return {
107+
appUrl: appUrlWithoutTrailingSlash,
108+
workspaceId,
109+
...(environmentId ? { environmentId } : {}),
110+
};
111+
}
112+
113+
return {
114+
appUrl: appUrlWithoutTrailingSlash,
115+
environmentId: environmentId as string,
116+
};
103117
};
104118

105119
const processQueue = (): void => {
@@ -126,10 +140,7 @@ const processQueue = (): void => {
126140
}
127141
};
128142

129-
export const setup = async (config: {
130-
appUrl: string;
131-
environmentId: string;
132-
}): Promise<void> => {
143+
export const setup = async (config: TSetupConfig): Promise<void> => {
133144
if (isInitializing) {
134145
console.warn(
135146
"🧱 Formbricks - Warning: Formbricks is already initializing.",

packages/js/src/types/formbricks.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ export interface TFormbricks {
33
* @description Initializes the Formbricks SDK.
44
* @param setupConfig - The configuration for the Formbricks SDK.
55
*/
6-
setup: (setupConfig: {
7-
environmentId: string;
8-
appUrl: string;
9-
}) => Promise<void>;
6+
setup: (setupConfig: TSetupConfig) => Promise<void>;
107

118
/**
129
* @description Sets the email of the user.
@@ -67,3 +64,21 @@ export interface TFormbricks {
6764
*/
6865
registerRouteChange: () => Promise<void>;
6966
}
67+
68+
export type TSetupConfig =
69+
| {
70+
workspaceId: string;
71+
/**
72+
* @deprecated use workspaceId instead, environmentId will be removed in a future version
73+
*/
74+
environmentId?: string;
75+
appUrl: string;
76+
}
77+
| {
78+
workspaceId?: string;
79+
/**
80+
* @deprecated use workspaceId instead, environmentId will be removed in a future version
81+
*/
82+
environmentId: string;
83+
appUrl: string;
84+
};

0 commit comments

Comments
 (0)