mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-21 10:08:34 -06:00
Compare commits
1 Commits
cursor/cus
...
cursor/web
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64c640b181 |
@@ -1,12 +1,5 @@
|
||||
import { Viewport } from "next";
|
||||
import { LinkSurveyLayout } from "@/modules/survey/link/layout";
|
||||
import { LinkSurveyLayout, viewport } from "@/modules/survey/link/layout";
|
||||
|
||||
export const viewport: Viewport = {
|
||||
width: "device-width",
|
||||
initialScale: 1.0,
|
||||
maximumScale: 1.0,
|
||||
userScalable: false,
|
||||
viewportFit: "contain",
|
||||
};
|
||||
export { viewport };
|
||||
|
||||
export default LinkSurveyLayout;
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
import { Viewport } from "next";
|
||||
|
||||
export const viewport: Viewport = {
|
||||
width: "device-width",
|
||||
initialScale: 1.0,
|
||||
maximumScale: 1.0,
|
||||
userScalable: false,
|
||||
viewportFit: "contain",
|
||||
};
|
||||
|
||||
export const LinkSurveyLayout = ({ children }) => {
|
||||
return <div className="h-dvh">{children}</div>;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,52 @@ import { FILE_PICK_EVENT } from "@/lib/constants";
|
||||
import { getI18nLanguage } from "@/lib/i18n-utils";
|
||||
import { addCustomThemeToDom, addStylesToDom, setStyleNonce } from "@/lib/styles";
|
||||
|
||||
// Polyfill for webkit messageHandlers to prevent errors in browsers that don't fully support it
|
||||
// (e.g., Instagram's iOS in-app browser). This prevents TypeError when accessing unregistered handlers.
|
||||
if (typeof window !== "undefined") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- WebKit types are not standard
|
||||
const win = window as any;
|
||||
|
||||
// Create a Proxy that safely handles access to potentially undefined message handlers
|
||||
const createMessageHandlersProxy = (originalHandlers: any = {}) => {
|
||||
return new Proxy(originalHandlers, {
|
||||
get(target, prop) {
|
||||
const handler = target[prop as keyof typeof target];
|
||||
|
||||
// If the handler doesn't exist, return a safe mock object with a no-op postMessage
|
||||
if (!handler) {
|
||||
return {
|
||||
postMessage: () => {
|
||||
// Silently ignore - the message handler is not registered in this environment
|
||||
console.debug(`WebKit message handler "${String(prop)}" is not available in this environment`);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return handler;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// Handle three scenarios:
|
||||
// 1. window.webkit doesn't exist at all (Instagram iOS browser)
|
||||
// 2. window.webkit exists but messageHandlers doesn't
|
||||
// 3. Both exist but handlers might be missing
|
||||
if (!win.webkit) {
|
||||
// Scenario 1: Create the entire webkit object with proxied messageHandlers
|
||||
win.webkit = {
|
||||
messageHandlers: createMessageHandlersProxy(),
|
||||
};
|
||||
} else if (!win.webkit.messageHandlers) {
|
||||
// Scenario 2: webkit exists but messageHandlers doesn't
|
||||
win.webkit.messageHandlers = createMessageHandlersProxy();
|
||||
} else {
|
||||
// Scenario 3: Both exist, wrap existing messageHandlers with proxy
|
||||
const originalMessageHandlers = win.webkit.messageHandlers;
|
||||
win.webkit.messageHandlers = createMessageHandlersProxy(originalMessageHandlers);
|
||||
}
|
||||
}
|
||||
|
||||
export const renderSurveyInline = (props: SurveyContainerProps) => {
|
||||
const inlineProps: SurveyContainerProps = {
|
||||
...props,
|
||||
|
||||
250
packages/surveys/src/lib/webkit-polyfill.test.ts
Normal file
250
packages/surveys/src/lib/webkit-polyfill.test.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe("WebKit messageHandlers polyfill", () => {
|
||||
let originalWebkit: any;
|
||||
let consoleDebugSpy: any;
|
||||
|
||||
beforeEach(() => {
|
||||
// Save the original webkit object if it exists
|
||||
originalWebkit = (window as any).webkit;
|
||||
consoleDebugSpy = vi.spyOn(console, "debug").mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Restore the original webkit object
|
||||
if (originalWebkit) {
|
||||
(window as any).webkit = originalWebkit;
|
||||
} else {
|
||||
delete (window as any).webkit;
|
||||
}
|
||||
consoleDebugSpy.mockRestore();
|
||||
});
|
||||
|
||||
// Helper function to apply the polyfill logic (same as in index.ts)
|
||||
const applyPolyfill = () => {
|
||||
const win = window as any;
|
||||
|
||||
const createMessageHandlersProxy = (originalHandlers: any = {}) => {
|
||||
return new Proxy(originalHandlers, {
|
||||
get(target, prop) {
|
||||
const handler = target[prop as keyof typeof target];
|
||||
|
||||
if (!handler) {
|
||||
return {
|
||||
postMessage: () => {
|
||||
console.debug(
|
||||
`WebKit message handler "${String(prop)}" is not available in this environment`
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return handler;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (!win.webkit) {
|
||||
win.webkit = {
|
||||
messageHandlers: createMessageHandlersProxy(),
|
||||
};
|
||||
} else if (!win.webkit.messageHandlers) {
|
||||
win.webkit.messageHandlers = createMessageHandlersProxy();
|
||||
} else {
|
||||
const originalMessageHandlers = win.webkit.messageHandlers;
|
||||
win.webkit.messageHandlers = createMessageHandlersProxy(originalMessageHandlers);
|
||||
}
|
||||
};
|
||||
|
||||
describe("Scenario 1: window.webkit does not exist (Instagram iOS browser)", () => {
|
||||
it("should create window.webkit with proxied messageHandlers", () => {
|
||||
// Setup: Remove webkit completely
|
||||
delete (window as any).webkit;
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test: webkit should now exist
|
||||
expect((window as any).webkit).toBeDefined();
|
||||
expect((window as any).webkit.messageHandlers).toBeDefined();
|
||||
});
|
||||
|
||||
it("should not throw when accessing undefined messageHandlers", () => {
|
||||
// Setup
|
||||
delete (window as any).webkit;
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test: Accessing an undefined handler should not throw
|
||||
expect(() => {
|
||||
(window as any).webkit.messageHandlers.undefinedHandler.postMessage("test");
|
||||
}).not.toThrow();
|
||||
|
||||
// Verify console.debug was called
|
||||
expect(consoleDebugSpy).toHaveBeenCalledWith(
|
||||
'WebKit message handler "undefinedHandler" is not available in this environment'
|
||||
);
|
||||
});
|
||||
|
||||
it("should handle multiple undefined handlers without throwing", () => {
|
||||
// Setup
|
||||
delete (window as any).webkit;
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test: Multiple undefined handlers should not throw
|
||||
expect(() => {
|
||||
(window as any).webkit.messageHandlers.handler1.postMessage("test1");
|
||||
(window as any).webkit.messageHandlers.handler2.postMessage("test2");
|
||||
(window as any).webkit.messageHandlers.handler3.postMessage("test3");
|
||||
}).not.toThrow();
|
||||
|
||||
expect(consoleDebugSpy).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Scenario 2: window.webkit exists but messageHandlers does not", () => {
|
||||
it("should add proxied messageHandlers to existing webkit", () => {
|
||||
// Setup: Create webkit without messageHandlers
|
||||
(window as any).webkit = {};
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test: messageHandlers should now exist
|
||||
expect((window as any).webkit.messageHandlers).toBeDefined();
|
||||
});
|
||||
|
||||
it("should not throw when accessing undefined handlers", () => {
|
||||
// Setup
|
||||
(window as any).webkit = {};
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test
|
||||
expect(() => {
|
||||
(window as any).webkit.messageHandlers.someHandler.postMessage("test");
|
||||
}).not.toThrow();
|
||||
|
||||
expect(consoleDebugSpy).toHaveBeenCalledWith(
|
||||
'WebKit message handler "someHandler" is not available in this environment'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Scenario 3: Both webkit and messageHandlers exist", () => {
|
||||
it("should preserve existing handlers while proxying new ones", () => {
|
||||
// Setup: Create a webkit object with a real handler
|
||||
const mockPostMessage = vi.fn();
|
||||
(window as any).webkit = {
|
||||
messageHandlers: {
|
||||
existingHandler: {
|
||||
postMessage: mockPostMessage,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test: Existing handler should still work
|
||||
(window as any).webkit.messageHandlers.existingHandler.postMessage("test message");
|
||||
expect(mockPostMessage).toHaveBeenCalledWith("test message");
|
||||
|
||||
// Test: Undefined handler should not throw
|
||||
expect(() => {
|
||||
(window as any).webkit.messageHandlers.undefinedHandler.postMessage("test");
|
||||
}).not.toThrow();
|
||||
|
||||
expect(consoleDebugSpy).toHaveBeenCalledWith(
|
||||
'WebKit message handler "undefinedHandler" is not available in this environment'
|
||||
);
|
||||
});
|
||||
|
||||
it("should work with multiple existing handlers", () => {
|
||||
// Setup
|
||||
const mockPostMessage1 = vi.fn();
|
||||
const mockPostMessage2 = vi.fn();
|
||||
(window as any).webkit = {
|
||||
messageHandlers: {
|
||||
handler1: {
|
||||
postMessage: mockPostMessage1,
|
||||
},
|
||||
handler2: {
|
||||
postMessage: mockPostMessage2,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test: All existing handlers should work
|
||||
(window as any).webkit.messageHandlers.handler1.postMessage("msg1");
|
||||
(window as any).webkit.messageHandlers.handler2.postMessage("msg2");
|
||||
|
||||
expect(mockPostMessage1).toHaveBeenCalledWith("msg1");
|
||||
expect(mockPostMessage2).toHaveBeenCalledWith("msg2");
|
||||
|
||||
// Test: Undefined handlers should not throw
|
||||
expect(() => {
|
||||
(window as any).webkit.messageHandlers.handler3.postMessage("msg3");
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Edge cases", () => {
|
||||
it("should handle messageHandlers with empty object", () => {
|
||||
// Setup
|
||||
(window as any).webkit = {
|
||||
messageHandlers: {},
|
||||
};
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test
|
||||
expect(() => {
|
||||
(window as any).webkit.messageHandlers.anyHandler.postMessage("test");
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it("should handle messageHandlers with null prototype", () => {
|
||||
// Setup
|
||||
(window as any).webkit = {
|
||||
messageHandlers: Object.create(null),
|
||||
};
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test
|
||||
expect(() => {
|
||||
(window as any).webkit.messageHandlers.handler.postMessage("test");
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it("should not interfere with handler methods other than postMessage", () => {
|
||||
// Setup
|
||||
const customMethod = vi.fn();
|
||||
(window as any).webkit = {
|
||||
messageHandlers: {
|
||||
customHandler: {
|
||||
postMessage: vi.fn(),
|
||||
customMethod,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Apply polyfill
|
||||
applyPolyfill();
|
||||
|
||||
// Test: Custom methods should still be accessible
|
||||
(window as any).webkit.messageHandlers.customHandler.customMethod("test");
|
||||
expect(customMethod).toHaveBeenCalledWith("test");
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user