mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-24 03:21:20 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b50605058 |
@@ -42,22 +42,27 @@ const setup = async (setupConfig: TConfigInput): Promise<void> => {
|
|||||||
|
|
||||||
const setUserId = async (userId: string): Promise<void> => {
|
const setUserId = async (userId: string): Promise<void> => {
|
||||||
await queue.add(User.setUserId, CommandType.UserAction, true, userId);
|
await queue.add(User.setUserId, CommandType.UserAction, true, userId);
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setEmail = async (email: string): Promise<void> => {
|
const setEmail = async (email: string): Promise<void> => {
|
||||||
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { email });
|
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { email });
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setAttribute = async (key: string, value: string): Promise<void> => {
|
const setAttribute = async (key: string, value: string): Promise<void> => {
|
||||||
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { [key]: value });
|
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { [key]: value });
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setAttributes = async (attributes: Record<string, string>): Promise<void> => {
|
const setAttributes = async (attributes: Record<string, string>): Promise<void> => {
|
||||||
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, attributes);
|
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, attributes);
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setLanguage = async (language: string): Promise<void> => {
|
const setLanguage = async (language: string): Promise<void> => {
|
||||||
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { language });
|
await queue.add(Attribute.setAttributes, CommandType.UserAction, true, { language });
|
||||||
|
await queue.wait();
|
||||||
};
|
};
|
||||||
|
|
||||||
const logout = async (): Promise<void> => {
|
const logout = async (): Promise<void> => {
|
||||||
|
|||||||
@@ -1,12 +1,25 @@
|
|||||||
|
import { Logger } from "@/lib/common/logger";
|
||||||
import { UpdateQueue } from "@/lib/user/update-queue";
|
import { UpdateQueue } from "@/lib/user/update-queue";
|
||||||
import { type NetworkError, type Result, okVoid } from "@/types/error";
|
import { type NetworkError, type Result, err, okVoid } from "@/types/error";
|
||||||
|
|
||||||
export const setAttributes = async (
|
export const setAttributes = async (
|
||||||
attributes: Record<string, string>
|
attributes: Record<string, string>
|
||||||
// eslint-disable-next-line @typescript-eslint/require-await -- we want to use promises here
|
|
||||||
): Promise<Result<void, NetworkError>> => {
|
): Promise<Result<void, NetworkError>> => {
|
||||||
|
const logger = Logger.getInstance();
|
||||||
const updateQueue = UpdateQueue.getInstance();
|
const updateQueue = UpdateQueue.getInstance();
|
||||||
updateQueue.updateAttributes(attributes);
|
updateQueue.updateAttributes(attributes);
|
||||||
void updateQueue.processUpdates();
|
try {
|
||||||
return okVoid();
|
await updateQueue.processUpdates();
|
||||||
|
return okVoid();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(
|
||||||
|
`Failed to process attribute updates: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||||
|
);
|
||||||
|
return err({
|
||||||
|
code: "network_error",
|
||||||
|
message: "Failed to sync attributes",
|
||||||
|
responseMessage: error instanceof Error ? error.message : "Unknown error",
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,16 @@ vi.mock("@/lib/user/update-queue", () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Mock the Logger
|
||||||
|
vi.mock("@/lib/common/logger", () => ({
|
||||||
|
Logger: {
|
||||||
|
getInstance: vi.fn(() => ({
|
||||||
|
error: vi.fn(),
|
||||||
|
debug: vi.fn(),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
describe("User Attributes", () => {
|
describe("User Attributes", () => {
|
||||||
const mockUpdateQueue = {
|
const mockUpdateQueue = {
|
||||||
updateAttributes: vi.fn(),
|
updateAttributes: vi.fn(),
|
||||||
@@ -32,6 +42,8 @@ describe("User Attributes", () => {
|
|||||||
|
|
||||||
describe("setAttributes", () => {
|
describe("setAttributes", () => {
|
||||||
test("successfully updates attributes and triggers processing", async () => {
|
test("successfully updates attributes and triggers processing", async () => {
|
||||||
|
mockUpdateQueue.processUpdates.mockResolvedValue(undefined);
|
||||||
|
|
||||||
const result = await setAttributes(mockAttributes);
|
const result = await setAttributes(mockAttributes);
|
||||||
|
|
||||||
// Verify UpdateQueue methods were called correctly
|
// Verify UpdateQueue methods were called correctly
|
||||||
@@ -43,6 +55,8 @@ describe("User Attributes", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("processes multiple attribute updates", async () => {
|
test("processes multiple attribute updates", async () => {
|
||||||
|
mockUpdateQueue.processUpdates.mockResolvedValue(undefined);
|
||||||
|
|
||||||
const firstAttributes = { name: mockAttributes.name };
|
const firstAttributes = { name: mockAttributes.name };
|
||||||
const secondAttributes = { email: mockAttributes.email };
|
const secondAttributes = { email: mockAttributes.email };
|
||||||
|
|
||||||
@@ -55,22 +69,35 @@ describe("User Attributes", () => {
|
|||||||
expect(mockUpdateQueue.processUpdates).toHaveBeenCalledTimes(2);
|
expect(mockUpdateQueue.processUpdates).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("processes updates asynchronously", async () => {
|
test("waits for processUpdates to complete", async () => {
|
||||||
const attributes = { name: mockAttributes.name };
|
const attributes = { name: mockAttributes.name };
|
||||||
|
let processUpdatesResolved = false;
|
||||||
|
|
||||||
// Mock processUpdates to be async
|
// Mock processUpdates to be async and set a flag when resolved
|
||||||
mockUpdateQueue.processUpdates.mockImplementation(
|
mockUpdateQueue.processUpdates.mockImplementation(
|
||||||
() =>
|
() =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
setTimeout(resolve, 100);
|
setTimeout(() => {
|
||||||
|
processUpdatesResolved = true;
|
||||||
|
resolve(undefined);
|
||||||
|
}, 100);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await setAttributes(attributes);
|
const resultPromise = setAttributes(attributes);
|
||||||
|
|
||||||
expect(result.ok).toBe(true);
|
// Verify processUpdates was called
|
||||||
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
||||||
// The function returns before processUpdates completes due to void operator
|
|
||||||
|
// Verify the function hasn't resolved yet
|
||||||
|
expect(processUpdatesResolved).toBe(false);
|
||||||
|
|
||||||
|
// Wait for setAttributes to complete
|
||||||
|
const result = await resultPromise;
|
||||||
|
|
||||||
|
// Verify it completed after processUpdates
|
||||||
|
expect(processUpdatesResolved).toBe(true);
|
||||||
|
expect(result.ok).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ describe("user.ts", () => {
|
|||||||
|
|
||||||
const mockUpdateQueue = {
|
const mockUpdateQueue = {
|
||||||
updateUserId: vi.fn(),
|
updateUserId: vi.fn(),
|
||||||
processUpdates: vi.fn(),
|
processUpdates: vi.fn().mockResolvedValue(undefined),
|
||||||
};
|
};
|
||||||
|
|
||||||
getInstanceConfigMock.mockReturnValue(mockConfig as unknown as Config);
|
getInstanceConfigMock.mockReturnValue(mockConfig as unknown as Config);
|
||||||
@@ -113,6 +113,42 @@ describe("user.ts", () => {
|
|||||||
expect(mockUpdateQueue.updateUserId).toHaveBeenCalledWith(mockUserId);
|
expect(mockUpdateQueue.updateUserId).toHaveBeenCalledWith(mockUserId);
|
||||||
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("returns error if processUpdates fails", async () => {
|
||||||
|
const mockConfig = {
|
||||||
|
get: vi.fn().mockReturnValue({
|
||||||
|
user: {
|
||||||
|
data: {
|
||||||
|
userId: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockLogger = {
|
||||||
|
debug: vi.fn(),
|
||||||
|
error: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockUpdateQueue = {
|
||||||
|
updateUserId: vi.fn(),
|
||||||
|
processUpdates: vi.fn().mockRejectedValue(new Error("Network error")),
|
||||||
|
};
|
||||||
|
|
||||||
|
getInstanceConfigMock.mockReturnValue(mockConfig as unknown as Config);
|
||||||
|
getInstanceLoggerMock.mockReturnValue(mockLogger as unknown as Logger);
|
||||||
|
getInstanceUpdateQueueMock.mockReturnValue(mockUpdateQueue as unknown as UpdateQueue);
|
||||||
|
const result = await setUserId(mockUserId);
|
||||||
|
|
||||||
|
expect(result.ok).toBe(false);
|
||||||
|
if (!result.ok) {
|
||||||
|
expect(result.error.code).toBe("network_error");
|
||||||
|
expect(result.error.status).toBe(500);
|
||||||
|
}
|
||||||
|
expect(mockUpdateQueue.updateUserId).toHaveBeenCalledWith(mockUserId);
|
||||||
|
expect(mockUpdateQueue.processUpdates).toHaveBeenCalled();
|
||||||
|
expect(mockLogger.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("logout", () => {
|
describe("logout", () => {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { tearDown } from "@/lib/common/setup";
|
|||||||
import { UpdateQueue } from "@/lib/user/update-queue";
|
import { UpdateQueue } from "@/lib/user/update-queue";
|
||||||
import { type ApiErrorResponse, type Result, err, okVoid } from "@/types/error";
|
import { type ApiErrorResponse, type Result, err, okVoid } from "@/types/error";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/require-await -- we want to use promises here
|
|
||||||
export const setUserId = async (userId: string): Promise<Result<void, ApiErrorResponse>> => {
|
export const setUserId = async (userId: string): Promise<Result<void, ApiErrorResponse>> => {
|
||||||
const appConfig = Config.getInstance();
|
const appConfig = Config.getInstance();
|
||||||
const logger = Logger.getInstance();
|
const logger = Logger.getInstance();
|
||||||
@@ -27,8 +26,20 @@ export const setUserId = async (userId: string): Promise<Result<void, ApiErrorRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateQueue.updateUserId(userId);
|
updateQueue.updateUserId(userId);
|
||||||
void updateQueue.processUpdates();
|
try {
|
||||||
return okVoid();
|
await updateQueue.processUpdates();
|
||||||
|
return okVoid();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(
|
||||||
|
`Failed to process userId update: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||||
|
);
|
||||||
|
return err({
|
||||||
|
code: "network_error",
|
||||||
|
message: "Failed to sync userId",
|
||||||
|
responseMessage: error instanceof Error ? error.message : "Unknown error",
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const logout = (): Result<void> => {
|
export const logout = (): Result<void> => {
|
||||||
|
|||||||
Reference in New Issue
Block a user