From bcebd06d4ca64ea1cbe40ab3fee9bcad141c43e6 Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Wed, 6 Mar 2024 11:34:56 +0530 Subject: [PATCH 01/10] fix: remove edit button from visual editor --- src/livePreview/editButton/editButton.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/livePreview/editButton/editButton.ts b/src/livePreview/editButton/editButton.ts index 4e185dfb..3da834eb 100644 --- a/src/livePreview/editButton/editButton.ts +++ b/src/livePreview/editButton/editButton.ts @@ -190,17 +190,15 @@ export function shouldRenderEditButton(editButton: IConfigEditButton): boolean { PublicLogger.error(error); } - // case if inside live preview + // case if inside live preview or inside live editor if ( - inIframe() && + inIframe() || editButton.exclude?.find( (exclude) => exclude === "insideLivePreviewPortal" ) ) { return false; - } else if (inIframe()) { - return true; - } + } // case outside live preview if ( From 58265878f214c290bf3cc2289bfb63b034d86ae3 Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Fri, 8 Mar 2024 12:35:29 +0530 Subject: [PATCH 02/10] add: deepSignal package --- package-lock.json | 26 ++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 27 insertions(+) diff --git a/package-lock.json b/package-lock.json index d091a3f1..ecf48149 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@preact/compat": "^17.1.2", "@preact/signals": "^1.2.2", "classnames": "^2.5.1", + "deepsignal": "^1.5.0", "just-camel-case": "^6.2.0", "lodash-es": "^4.17.21", "mustache": "^4.2.0", @@ -5361,6 +5362,31 @@ "node": ">=0.10.0" } }, + "node_modules/deepsignal": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/deepsignal/-/deepsignal-1.5.0.tgz", + "integrity": "sha512-bFywDpBUUWMs576H2dgLFLLFuQ/UWXbzHfKD98MZTfGsl7+twIzvz4ihCNrRrZ/Emz3kqJaNIAp5eBWUEWhnAw==", + "peerDependencies": { + "@preact/signals": "^1.1.4", + "@preact/signals-core": "^1.5.1", + "@preact/signals-react": "^1.3.8 || ^2.0.0", + "preact": "^10.16.0" + }, + "peerDependenciesMeta": { + "@preact/signals": { + "optional": true + }, + "@preact/signals-core": { + "optional": true + }, + "@preact/signals-react": { + "optional": true + }, + "preact": { + "optional": true + } + } + }, "node_modules/default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", diff --git a/package.json b/package.json index 87afeed0..a71d1737 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "@preact/compat": "^17.1.2", "@preact/signals": "^1.2.2", "classnames": "^2.5.1", + "deepsignal": "^1.5.0", "just-camel-case": "^6.2.0", "lodash-es": "^4.17.21", "mustache": "^4.2.0", From 2843bc00e419cee62e3b5ad2b75f59e62fdf4454 Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Fri, 8 Mar 2024 12:37:39 +0530 Subject: [PATCH 03/10] refactor: implement deepSignal into Config object --- src/configManager/config.default.ts | 20 +- src/configManager/configManager.ts | 34 ++-- src/configManager/handleUserConfig.ts | 179 +++++++++++------- src/cslp/cslpdata.ts | 13 +- src/liveEditor/__test__/index.test.ts | 2 +- .../__test__/visualEditorHover.test.ts | 2 +- src/liveEditor/__test__/withoutIframe.test.ts | 2 +- .../__tests__/startEditingButton.test.tsx | 9 +- src/liveEditor/index.ts | 8 +- .../utils/getLiveEditorRedirectionUrl.ts | 4 +- src/liveEditor/utils/isFieldDisabled.ts | 2 +- src/livePreview/__test__/live-preview.test.ts | 2 +- .../eventManager/livePreviewEventManager.ts | 2 +- .../eventManager/postMessageEvent.hooks.ts | 14 +- src/livePreview/live-preview.ts | 24 +-- src/preview/contentstack-live-preview-HOC.ts | 2 +- 16 files changed, 185 insertions(+), 134 deletions(-) diff --git a/src/configManager/config.default.ts b/src/configManager/config.default.ts index 96cbdc2b..cc3e0858 100644 --- a/src/configManager/config.default.ts +++ b/src/configManager/config.default.ts @@ -1,4 +1,4 @@ -import { IConfig, IInitData, ILivePreviewWindowType } from "../types/types"; +import { IClientUrlParams, IConfig, IConfigEditButton, IInitData, ILivePreviewModeConfig, ILivePreviewWindowType, IStackDetails, IStackSdk } from "../types/types"; export function getUserInitData(): IInitData { return { @@ -48,10 +48,10 @@ export function getDefaultConfig(): IConfig { exclude: [], position: "top", includeByQueryParameter: true, - }, + } as IConfigEditButton, - hash: "", - mode: 1, + hash: "" as string, + mode: 1 as ILivePreviewModeConfig, windowType: ILivePreviewWindowType.INDEPENDENT, stackDetails: { @@ -62,29 +62,31 @@ export function getDefaultConfig(): IConfig { locale: "en-us", branch: "main", masterLocale: "en-us", - }, + } as IStackDetails, clientUrlParams: { protocol: "https", host: "app.contentstack.com", port: 443, url: "https://app.contentstack.com:443", - }, + } as IClientUrlParams, stackSdk: { live_preview: {}, headers: { api_key: "", }, environment: "", - }, + } as IStackSdk, runScriptsOnUpdate: false, onChange() { - // this is intentional + return; }, elements: { highlightedElement: null, - }, + } }; + + } diff --git a/src/configManager/configManager.ts b/src/configManager/configManager.ts index 0e255791..32bc1803 100644 --- a/src/configManager/configManager.ts +++ b/src/configManager/configManager.ts @@ -1,29 +1,35 @@ +import { DeepSignal, deepSignal } from "deepsignal"; import { IConfig, IInitData } from "../types/types"; import { getDefaultConfig, getUserInitData } from "./config.default"; import { handleInitData } from "./handleUserConfig"; -import { has as lodashHas, set as lodashSet } from "lodash-es"; +import { has as lodashHas, set as lodashSet, get as lodashGet } from "lodash-es"; class Config { - static config: IConfig = getDefaultConfig(); + + static config: DeepSignal<{ + state: IConfig | {}; + }> = { + state : getDefaultConfig() + }; static replace(userInput: Partial = getUserInitData()): void { - handleInitData(userInput, this.config); + handleInitData(userInput); } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types static set(key: string, value: any): void { if (!lodashHas(this.config, key)) { throw new Error(`Invalid key: ${key}`); - } + } lodashSet(this.config, key, value); } - - static get(): IConfig { - return this.config; + + static get(key: string): DeepSignal> { + return lodashGet(this.config, key); } static reset(): void { - this.config = getDefaultConfig(); + this.set("state", getDefaultConfig()); } } @@ -64,28 +70,30 @@ export function updateConfigFromUrl(): void { export function setConfigFromParams( params: ConstructorParameters[0] = {} ): void { + const urlParams = new URLSearchParams(params); const live_preview = urlParams.get("live_preview"); const content_type_uid = urlParams.get("content_type_uid"); const entry_uid = urlParams.get("entry_uid"); - const stackSdkLivePreview = Config.get().stackSdk.live_preview; + const stackSdkLivePreview = Config.get("state.stackSdk.live_preview") as { [key: string]: any } & Partial;; if (live_preview) { - Config.set("hash", live_preview); + Config.set("state.hash", live_preview); stackSdkLivePreview.hash = live_preview; stackSdkLivePreview.live_preview = live_preview; } if (content_type_uid) { - Config.set("stackDetails.contentTypeUid", content_type_uid); + Config.set("state.stackDetails.contentTypeUid", content_type_uid); stackSdkLivePreview.content_type_uid = content_type_uid; } if (entry_uid) { - Config.set("stackDetails.entryUid", entry_uid); + Config.set("state.stackDetails.entryUid", entry_uid); stackSdkLivePreview.entry_uid = entry_uid; } - Config.set("stackSdk.live_preview", stackSdkLivePreview); + Config.set("state.stackSdk.live_preview", stackSdkLivePreview); + } diff --git a/src/configManager/handleUserConfig.ts b/src/configManager/handleUserConfig.ts index cbea4ceb..0e67f725 100644 --- a/src/configManager/handleUserConfig.ts +++ b/src/configManager/handleUserConfig.ts @@ -1,4 +1,4 @@ -import { shouldRenderEditButton } from "../livePreview/editButton/editButton"; +import { DeepSignal } from "deepsignal"; import { IClientUrlParams, IConfig, @@ -6,77 +6,98 @@ import { ILivePreviewModeConfig, IStackSdk, } from "../types/types"; +import Config from "./configManager"; -const handleClientUrlParams = ( - existingConfig: IConfig, - userConfig: Partial -): void => { - existingConfig.clientUrlParams.host = - userConfig.host ?? existingConfig.clientUrlParams.host; - existingConfig.clientUrlParams.protocol = - userConfig.protocol ?? existingConfig.clientUrlParams.protocol; - existingConfig.clientUrlParams.port = - userConfig.port ?? existingConfig.clientUrlParams.port; +const handleClientUrlParams = (userConfig: Partial): void => { + Config.set( + "state.clientUrlParams.host", + userConfig.host ?? Config.get("state.clientUrlParams.host") + ); + + Config.set( + "state.clientUrlParams.protocol", + userConfig.protocol ?? Config.get("state.clientUrlParams.protocol") + ); + Config.set( + "state.clientUrlParams.port", + userConfig.port ?? Config.get("state.clientUrlParams.port") + ); if (userConfig.protocol !== undefined && userConfig.port === undefined) { switch (userConfig.protocol) { case "http": { - existingConfig.clientUrlParams.port = 80; + Config.set("state.clientUrlParams.port", 80); break; } case "https": { - existingConfig.clientUrlParams.port = 443; + Config.set("state.clientUrlParams.port", 443); break; } } } // build url - let host = existingConfig.clientUrlParams.host; + let host = Config.get("state.clientUrlParams.host") as unknown as string; + let protocol = Config.get( + "state.clientUrlParams.protocol" + ) as unknown as string; + let port = Config.get("state.clientUrlParams.port") as unknown as + | string + | number; if (host.endsWith("/")) { host = host.slice(0, -1); - existingConfig.clientUrlParams.host = host; + Config.set("state.clientUrlParams.host", host); } - existingConfig.clientUrlParams.url = `${existingConfig.clientUrlParams.protocol}://${existingConfig.clientUrlParams.host}:${existingConfig.clientUrlParams.port}`; + Config.set("state.clientUrlParams.url", `${protocol}://${host}:${port}`); }; // TODO: add documentation mentioning that you cannot pass stack sdk in the init data -export const handleInitData = ( - initData: Partial, - config: IConfig -): void => { - const stackSdk: Partial = initData.stackSdk || config.stackSdk; +export const handleInitData = (initData: Partial): void => { + const stackSdk: IStackSdk = + initData.stackSdk || + (Config.get("state.stackSdk") as unknown as IStackSdk); - config.enable = - initData.enable ?? stackSdk.live_preview?.enable ?? config.enable; + Config.set( + "state.enable", + initData.enable ?? + stackSdk.live_preview?.enable ?? + Config.get("state.enable") + ); - config.ssr = - initData.ssr ?? + Config.set( + "state.ssr", stackSdk.live_preview?.ssr ?? - (typeof initData.stackSdk === "object" ? false : true) ?? - true; + (typeof initData.stackSdk === "object" ? false : true) ?? + true + ); - config.runScriptsOnUpdate = + Config.set( + "state.runScriptsOnUpdate", initData.runScriptsOnUpdate ?? - stackSdk.live_preview?.runScriptsOnUpdate ?? - config.runScriptsOnUpdate; + stackSdk.live_preview?.runScriptsOnUpdate ?? + Config.get("state.runScriptsOnUpdate") + ); - config.stackSdk = stackSdk as IStackSdk; + Config.set( + "state.stackSdk", + initData.stackSdk as unknown as DeepSignal + ); - config.cleanCslpOnProduction = + Config.set( + "state.cleanCslpOnProduction", initData.cleanCslpOnProduction ?? - stackSdk.live_preview?.cleanCslpOnProduction ?? - config.cleanCslpOnProduction; - - config.editButton = { - enable: shouldRenderEditButton( - initData.editButton ?? - stackSdk.live_preview?.editButton ?? - config.editButton - ), + stackSdk.live_preview?.cleanCslpOnProduction ?? + Config.get("state.cleanCslpOnProduction") + ); + + Config.set("state.editButton", { + enable: + initData.editButton?.enable ?? + stackSdk.live_preview?.editButton?.enable ?? + Config.get("state.editButton.enable"), // added extra check if exclude data passed by user is array or not exclude: Array.isArray(initData.editButton?.exclude) && @@ -85,35 +106,39 @@ export const handleInitData = ( : Array.isArray(stackSdk.live_preview?.exclude) && stackSdk.live_preview?.exclude ? stackSdk.live_preview?.exclude - : config.editButton.exclude ?? [], + : Config.get("state.editButton.exclude") ?? [], position: initData.editButton?.position ?? stackSdk.live_preview?.position ?? - config.editButton.position ?? + Config.get("state.editButton.position") ?? "top", includeByQueryParameter: initData.editButton?.includeByQueryParameter ?? stackSdk.live_preview?.includeByQueryParameter ?? - config.editButton.includeByQueryParameter ?? + Config.get("state.editButton.includeByQueryParameter") ?? true, - }; + }); + // client URL params handleClientUrlParams( - config, - initData.clientUrlParams ?? - stackSdk.live_preview?.clientUrlParams ?? - config.clientUrlParams + (initData.clientUrlParams as + | Partial> + | undefined) ?? + (stackSdk.live_preview?.clientUrlParams as IClientUrlParams) ?? + (Config.get("state.clientUrlParams") as unknown as IClientUrlParams) ); + // Partial>; || IClientUrlParams || + if (initData.mode) { switch (initData.mode) { case "preview": { - config.mode = ILivePreviewModeConfig.PREVIEW; + Config.set("state.mode", ILivePreviewModeConfig.PREVIEW); break; } case "editor": { - config.mode = ILivePreviewModeConfig.EDITOR; + Config.set("state.mode", ILivePreviewModeConfig.EDITOR); break; } default: { @@ -124,41 +149,55 @@ export const handleInitData = ( } } - config.debug = - initData.debug ?? stackSdk.live_preview?.debug ?? config.debug; + Config.set( + "state.debug", + initData.debug ?? + stackSdk.live_preview?.debug ?? + Config.get("state.debug") + ); - handleStackDetails(initData, stackSdk, config); + handleStackDetails(initData, stackSdk); }; function handleStackDetails( initData: Partial, - stackSdk: Partial, - config: IConfig + stackSdk: Partial ): void { - config.stackDetails.apiKey = + Config.set( + "state.stackDetails.apiKey", initData.stackDetails?.apiKey ?? - stackSdk.headers?.api_key ?? - config.stackDetails.apiKey; + stackSdk.headers?.api_key ?? + Config.get("state.stackDetails.apiKey") + ); - config.stackDetails.environment = + Config.set( + "state.stackDetails.environment", initData.stackDetails?.environment ?? - stackSdk.environment ?? - config.stackDetails.environment; + stackSdk.environment ?? + Config.get("state.stackDetails.environment") + ); - config.stackDetails.branch = + Config.set( + "state.stackDetails.branch", initData.stackDetails?.branch ?? - stackSdk.headers?.branch ?? - config.stackDetails.branch; + stackSdk.headers?.branch ?? + Config.get("state.stackDetails.branch") + ); - config.stackDetails.locale = - initData.stackDetails?.locale ?? config.stackDetails.locale; + Config.set( + "state.stackDetails.locale", + initData.stackDetails?.locale ?? Config.get("state.stackDetails.locale") + ); - if (config.mode >= ILivePreviewModeConfig.EDITOR) { - if (!config.stackDetails.environment) { + if ( + (Config.get("state.mode") as unknown as number) >= + ILivePreviewModeConfig.EDITOR + ) { + if (!Config.get("state.stackDetails.environment")) { throw Error("Live preview SDK: environment is required"); } - if (!config.stackDetails.apiKey) { + if (!Config.get("state.stackDetails.apiKey")) { throw Error("Live preview SDK: api key is required"); } } diff --git a/src/cslp/cslpdata.ts b/src/cslp/cslpdata.ts index 107bc72f..76963a87 100644 --- a/src/cslp/cslpdata.ts +++ b/src/cslp/cslpdata.ts @@ -119,7 +119,10 @@ export function addCslpOutline( highlightedElement: HTMLElement; }) => void ): void { - const config = Config.get(); + + const elements = Config.get("state.elements") as unknown as { + highlightedElement: HTMLElement | null; + }; let trigger = true; const eventTargets = e.composedPath(); @@ -132,15 +135,15 @@ export function addCslpOutline( const cslpTag = element.getAttribute("data-cslp"); if (trigger && cslpTag) { - if (config.elements.highlightedElement) - config.elements.highlightedElement.classList.remove( + if (elements.highlightedElement) + elements.highlightedElement.classList.remove( "cslp-edit-mode" ); element.classList.add("cslp-edit-mode"); - const updatedElements = config.elements; + const updatedElements = elements; updatedElements.highlightedElement = element; - Config.set("elements", updatedElements); + Config.set("state.elements", updatedElements); callback?.({ cslpTag: cslpTag, diff --git a/src/liveEditor/__test__/index.test.ts b/src/liveEditor/__test__/index.test.ts index d8958fa6..430e939f 100644 --- a/src/liveEditor/__test__/index.test.ts +++ b/src/liveEditor/__test__/index.test.ts @@ -45,7 +45,7 @@ describe("Visual editor", () => { "all_fields", getFieldSchemaMap().all_fields ); - Config.set("mode", 2); + Config.set("state.mode", 2); }); afterEach(() => { diff --git a/src/liveEditor/__test__/visualEditorHover.test.ts b/src/liveEditor/__test__/visualEditorHover.test.ts index 3e6d4978..ab117f57 100644 --- a/src/liveEditor/__test__/visualEditorHover.test.ts +++ b/src/liveEditor/__test__/visualEditorHover.test.ts @@ -163,7 +163,7 @@ describe("When an element is hovered in visual editor mode", () => { getFieldSchemaMap().all_fields ); - Config.set("mode", 2); + Config.set("state.mode", 2); }); beforeEach(() => { diff --git a/src/liveEditor/__test__/withoutIframe.test.ts b/src/liveEditor/__test__/withoutIframe.test.ts index cd1f9b92..42de792d 100644 --- a/src/liveEditor/__test__/withoutIframe.test.ts +++ b/src/liveEditor/__test__/withoutIframe.test.ts @@ -17,7 +17,7 @@ global.ResizeObserver = jest.fn().mockImplementation(() => ({ })); describe("When outside the Visual editor, the Visual Editor", () => { beforeAll(() => { - Config.set("mode", 2); + Config.set("state.mode", 2); }); afterAll(() => { Config.reset(); diff --git a/src/liveEditor/components/__tests__/startEditingButton.test.tsx b/src/liveEditor/components/__tests__/startEditingButton.test.tsx index 2f572575..0b434a4d 100644 --- a/src/liveEditor/components/__tests__/startEditingButton.test.tsx +++ b/src/liveEditor/components/__tests__/startEditingButton.test.tsx @@ -3,16 +3,17 @@ import { render, fireEvent } from "@testing-library/preact"; import StartEditingButtonComponent from "../startEditingButton"; import { IConfig } from "../../../types/types"; import { getDefaultConfig } from "../../../configManager/config.default"; +import { DeepSignal } from "deepsignal"; +import Config from "../../../configManager/configManager"; describe("StartEditingButtonComponent", () => { - let config: IConfig; + let config: DeepSignal; let visualEditorContainer: HTMLDivElement; beforeEach(() => { - config = getDefaultConfig(); - config.stackDetails.apiKey = "bltapikey"; - config.stackDetails.environment = "bltenvironment"; + Config.set("state.stackDetails.apiKey", "bltapikey"); + Config.set("state.stackDetails.environment", "bltenvironment"); visualEditorContainer = document.createElement("div"); document.body.appendChild(visualEditorContainer); diff --git a/src/liveEditor/index.ts b/src/liveEditor/index.ts index c7acf0e8..2b043e6e 100644 --- a/src/liveEditor/index.ts +++ b/src/liveEditor/index.ts @@ -77,22 +77,20 @@ export class VisualEditor { ".visual-editor__focused-toolbar" ); - const config = Config.get(); - - if (!config.enable || config.mode < ILivePreviewModeConfig.EDITOR) { + if (!Config.get("state.enable") || Config.get("state.mode") as unknown as number < ILivePreviewModeConfig.EDITOR) { return; } liveEditorPostMessage ?.send("init", { - isSSR: Config.get().ssr, + isSSR: Config.get("state.ssr"), }) .then((data) => { const { windowType = ILivePreviewWindowType.EDITOR, stackDetails, } = data; - Config.set("windowType", windowType); + Config.set("state.windowType", windowType); Config.set( "stackDetails.masterLocale", stackDetails?.masterLocale || "en-us" diff --git a/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts b/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts index 57299f12..48244fc1 100644 --- a/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts +++ b/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts @@ -1,12 +1,14 @@ import Config from "../../configManager/configManager"; import { extractDetailsFromCslp } from "../../cslp"; +import { IClientUrlParams, IStackDetails } from "../../types/types"; /** * Returns the redirection URL for the Live Editor. * @returns {URL} The redirection URL. */ export default function getLiveEditorRedirectionUrl(): URL { - const { stackDetails, clientUrlParams } = Config.get(); + const stackDetails = Config.get("state.stackDetails") as unknown as IStackDetails; + const clientUrlParams = Config.get("state.clientUrlParams") as unknown as IClientUrlParams; const { branch, apiKey, environment, locale } = stackDetails; const { url: appUrl } = clientUrlParams; diff --git a/src/liveEditor/utils/isFieldDisabled.ts b/src/liveEditor/utils/isFieldDisabled.ts index 81aa9a87..527998d6 100644 --- a/src/liveEditor/utils/isFieldDisabled.ts +++ b/src/liveEditor/utils/isFieldDisabled.ts @@ -6,7 +6,7 @@ export const isFieldDisabled = ( fieldSchemaMap: ISchemaFieldMap, eventDetails: VisualEditorCslpEventDetails ): any => { - const masterLocale = Config.get()?.stackDetails?.masterLocale || "en-us"; + const masterLocale = Config.get("state.stackDetails.masterLocale") as unknown as string || "en-us"; const updateRestrictDueToRole = Boolean( fieldSchemaMap?.field_metadata?.updateRestrict ); diff --git a/src/livePreview/__test__/live-preview.test.ts b/src/livePreview/__test__/live-preview.test.ts index 2d67a216..52b2bd40 100644 --- a/src/livePreview/__test__/live-preview.test.ts +++ b/src/livePreview/__test__/live-preview.test.ts @@ -79,7 +79,7 @@ describe("cslp tooltip", () => { document.body.appendChild(descPara); document.body.appendChild(linkPara); - Config.set("windowType", ILivePreviewWindowType.PREVIEW); + Config.set("state.windowType", ILivePreviewWindowType.PREVIEW); }); afterEach(() => { diff --git a/src/livePreview/eventManager/livePreviewEventManager.ts b/src/livePreview/eventManager/livePreviewEventManager.ts index fbd5693a..c832cbfc 100644 --- a/src/livePreview/eventManager/livePreviewEventManager.ts +++ b/src/livePreview/eventManager/livePreviewEventManager.ts @@ -6,7 +6,7 @@ let livePreviewPostMessage: EventManager | undefined; if (typeof window !== "undefined") { livePreviewPostMessage = new EventManager(LIVE_PREVIEW_CHANNEL_ID, { target: window.parent, - debug: false, + debug: true, suppressErrors: true, }); } diff --git a/src/livePreview/eventManager/postMessageEvent.hooks.ts b/src/livePreview/eventManager/postMessageEvent.hooks.ts index 7f607714..21969f1e 100644 --- a/src/livePreview/eventManager/postMessageEvent.hooks.ts +++ b/src/livePreview/eventManager/postMessageEvent.hooks.ts @@ -46,29 +46,27 @@ export function useOnEntryUpdatePostMessageEvent(): void { livePreviewPostMessage?.on( LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE, (event) => { - const config = Config.get(); setConfigFromParams({ live_preview: event.data.hash, }); - if (!config.ssr) { - const config = Config.get(); - config.onChange(); + if (!Config.get("state.ssr")) { + const config = Config.get("state"); + config.onChange!(); } } ); } export function sendInitializeLivePreviewPostMessageEvent(): void { - const config = Config.get(); livePreviewPostMessage ?.send( LIVE_PREVIEW_POST_MESSAGE_EVENTS.INIT, { config: { - shouldReload: config.ssr, + shouldReload: Config.get("state.ssr"), href: window.location.href, sdkVersion: packageJson.version, }, @@ -93,10 +91,10 @@ export function sendInitializeLivePreviewPostMessageEvent(): void { // "init message did not contain contentTypeUid or entryUid." // ); } - Config.set("windowType", windowType); + Config.set("state.windowType", windowType); // set timeout for client side (use to show warning: You are not editing this page) - if (!config.ssr) { + if (!Config.get("state.ssr")) { setInterval(() => { sendCurrentPageUrlPostMessageEvent(); }, 1500); diff --git a/src/livePreview/live-preview.ts b/src/livePreview/live-preview.ts index 6a317504..5d9c5867 100644 --- a/src/livePreview/live-preview.ts +++ b/src/livePreview/live-preview.ts @@ -21,7 +21,6 @@ export default class LivePreview { private subscribers: OnEntryChangeCallbackSubscribers = {}; constructor() { - const config = Config.get(); this.requestDataSync = this.requestDataSync.bind(this); this.subscribeToOnEntryChange = @@ -30,14 +29,14 @@ export default class LivePreview { this.unsubscribeOnEntryChange = this.unsubscribeOnEntryChange.bind(this); - if (config.debug) { + if (Config.get("state.debug")) { PublicLogger.debug( "Contentstack Live Preview Debugging mode: config --", - config + Config.config ); } - if (config.enable) { + if (Config.get("state.enable")) { if ( typeof document !== undefined && document.readyState === "complete" @@ -51,15 +50,16 @@ export default class LivePreview { // TODO: mjrf: Check if we need the second condition here. // We are already handling the functions separately in the live editor. // render the hover outline only when edit button enable + if ( - config.editButton.enable || - config.mode >= ILivePreviewModeConfig.EDITOR + Config.get("state.editButton.enable") || + Config.get("state.mode") as unknown as number >= ILivePreviewModeConfig.EDITOR ) { new LivePreviewEditButton(); } //NOTE - I think we are already handling the link click event here. Let's move it to a function. - if (config.ssr) { + if (Config.get("state.ssr")) { // NOTE: what are we doing here? window.addEventListener("load", (e) => { const allATags = document.querySelectorAll("a"); @@ -87,20 +87,20 @@ export default class LivePreview { } }); } - } else if (config.cleanCslpOnProduction) { + } else if (Config.get("state.cleanCslpOnProduction")) { removeDataCslp(); } } // Request parent for data sync when document loads private requestDataSync() { - const config = Config.get(); - - Config.set("onChange", this.publish); + const config = Config.get("state"); + Config.set("state.onChange", this.publish); + //! TODO: we replaced the handleOnChange() with this. //! I don't think we need this. Confirm and remove it. - config.onChange(); + config.onChange!(); sendInitializeLivePreviewPostMessageEvent(); } diff --git a/src/preview/contentstack-live-preview-HOC.ts b/src/preview/contentstack-live-preview-HOC.ts index bd23b55c..e71c60e3 100644 --- a/src/preview/contentstack-live-preview-HOC.ts +++ b/src/preview/contentstack-live-preview-HOC.ts @@ -67,7 +67,7 @@ class ContentstackLivePreview { if (!ContentstackLivePreview.isInitialized()) { updateConfigFromUrl(); // check if we could extract from the URL } - return Config.get().hash; + return Config.get("state.hash") as unknown as string; } private static isInitialized(): boolean { From 5485bc842f48ce6b8131fd14afcb2bb9839d520e Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Fri, 8 Mar 2024 14:49:20 +0530 Subject: [PATCH 04/10] add: test cases for updated Config object --- .../__test__/configManager.test.ts | 79 ++- .../__test__/handleUserConfig.test.ts | 461 +++++++++--------- src/configManager/config.default.ts | 8 +- src/configManager/handleUserConfig.ts | 9 +- 4 files changed, 302 insertions(+), 255 deletions(-) diff --git a/src/configManager/__test__/configManager.test.ts b/src/configManager/__test__/configManager.test.ts index 6423467d..3777e926 100644 --- a/src/configManager/__test__/configManager.test.ts +++ b/src/configManager/__test__/configManager.test.ts @@ -1,6 +1,42 @@ import Config, { updateConfigFromUrl } from "../configManager"; import { getDefaultConfig } from "../config.default"; +const colours = { + reset: "\x1b[0m", + bright: "\x1b[1m", + dim: "\x1b[2m", + underscore: "\x1b[4m", + blink: "\x1b[5m", + reverse: "\x1b[7m", + hidden: "\x1b[8m", + + fg: { + black: "\x1b[30m", + red: "\x1b[31m", + green: "\x1b[32m", + yellow: "\x1b[33m", + blue: "\x1b[34m", + magenta: "\x1b[35m", + cyan: "\x1b[36m", + white: "\x1b[37m", + gray: "\x1b[90m", + crimson: "\x1b[38m" // Scarlet + }, + bg: { + black: "\x1b[40m", + red: "\x1b[41m", + green: "\x1b[42m", + yellow: "\x1b[43m", + blue: "\x1b[44m", + magenta: "\x1b[45m", + cyan: "\x1b[46m", + white: "\x1b[47m", + gray: "\x1b[100m", + crimson: "\x1b[48m" + } + }; + + describe("Config", () => { beforeEach(() => { Config.reset(); @@ -11,30 +47,27 @@ describe("Config", () => { test("should return default value", () => { const defaultConfig = getDefaultConfig(); - const receivedConfig = Config.get(); + const receivedConfig = Config.get("state"); //@ts-expect-error delete defaultConfig.onChange; - //@ts-expect-error delete receivedConfig.onChange; - expect(Config.get()).toStrictEqual(defaultConfig); + expect(Config.get("state")).toStrictEqual(defaultConfig); }); test("should set and get value", () => { const defaultConfig = getDefaultConfig(); - let receivedConfig = Config.get(); + let receivedConfig = Config.get("state"); // @ts-expect-error delete defaultConfig.onChange; - // @ts-expect-error delete receivedConfig.onChange; expect(receivedConfig).toEqual({ ...defaultConfig, ssr: true }); - Config.set("ssr", false); - receivedConfig = Config.get(); + Config.set("state.ssr", false); + receivedConfig = Config.get("state"); - // @ts-expect-error delete receivedConfig.onChange; expect(receivedConfig).toEqual({ ...defaultConfig, ssr: false }); @@ -48,11 +81,10 @@ describe("Config", () => { test("should replace config", () => { const defaultConfig = getDefaultConfig(); - let receivedConfig = Config.get(); + let receivedConfig = Config.get("state"); // @ts-expect-error delete defaultConfig.onChange; - // @ts-expect-error delete receivedConfig.onChange; expect(receivedConfig).toEqual(defaultConfig); @@ -66,9 +98,8 @@ describe("Config", () => { }, }); - receivedConfig = Config.get(); + receivedConfig = Config.get("state"); - // @ts-expect-error delete receivedConfig.onChange; expect(receivedConfig).toEqual({ @@ -116,26 +147,26 @@ describe("update config from url", () => { }, }); - expect(Config.get().stackDetails.contentTypeUid).toEqual(""); - expect(Config.get().stackDetails.entryUid).toEqual(""); - expect(Config.get().hash).toEqual(""); + expect(Config.get("state.stackDetails.contentTypeUid")).toEqual(""); + expect(Config.get("state.stackDetails.entryUid")).toEqual(""); + expect(Config.get("state.hash")).toEqual(""); updateConfigFromUrl(); - expect(Config.get().stackDetails.contentTypeUid).toEqual("test"); - expect(Config.get().stackDetails.entryUid).toEqual("test"); - expect(Config.get().hash).toEqual("test"); + expect(Config.get("state.stackDetails.contentTypeUid")).toEqual("test"); + expect(Config.get("state.stackDetails.entryUid")).toEqual("test"); + expect(Config.get("state.hash")).toEqual("test"); }); it("should be default config if url params are not available", () => { - expect(Config.get().stackDetails.contentTypeUid).toEqual(""); - expect(Config.get().stackDetails.entryUid).toEqual(""); - expect(Config.get().hash).toEqual(""); + expect(Config.get("state.stackDetails.contentTypeUid")).toEqual(""); + expect(Config.get("state.stackDetails.entryUid")).toEqual(""); + expect(Config.get("state.hash")).toEqual(""); updateConfigFromUrl(); - expect(Config.get().stackDetails.contentTypeUid).toEqual(""); - expect(Config.get().stackDetails.entryUid).toEqual(""); - expect(Config.get().hash).toEqual(""); + expect(Config.get("state.stackDetails.contentTypeUid")).toEqual(""); + expect(Config.get("state.stackDetails.entryUid")).toEqual(""); + expect(Config.get("state.hash")).toEqual(""); }); }); diff --git a/src/configManager/__test__/handleUserConfig.test.ts b/src/configManager/__test__/handleUserConfig.test.ts index de8d9732..2a16e61a 100644 --- a/src/configManager/__test__/handleUserConfig.test.ts +++ b/src/configManager/__test__/handleUserConfig.test.ts @@ -7,6 +7,8 @@ import { ILivePreviewModeConfig, IStackSdk, } from "../../types/types"; +import { DeepSignal } from "deepsignal"; +import Config from "../configManager"; // example Stack object @@ -42,12 +44,16 @@ import { } */ -let config: IConfig; + describe("handleInitData()", () => { beforeEach(() => { - config = getDefaultConfig(); + Config.reset(); }); + afterEach(() => { + Config.reset(); + }) + test("must set data when config is provided", () => { const initData: Partial = { enable: true, @@ -57,7 +63,7 @@ describe("handleInitData()", () => { }, }; - handleInitData(initData, config); + handleInitData(initData); const expectedOutput = { ssr: true, enable: true, @@ -81,6 +87,8 @@ describe("handleInitData()", () => { environment: "", }, }; + + const config = Config.get("state"); expect(config).toMatchObject(expectedOutput); }); @@ -93,8 +101,8 @@ describe("handleInitData()", () => { }, }; - handleInitData(initData, config); - expect(config.ssr).toBe(true); + handleInitData(initData); + expect(Config.get("state.ssr")).toBe(true); }); test("must set SSR: true is stack SDK is not provided", () => { @@ -116,8 +124,8 @@ describe("handleInitData()", () => { }, }; - handleInitData(initData, config); - expect(config.ssr).toBe(false); + handleInitData(initData); + expect(Config.get("state.ssr")).toBe(false); }); describe("live mode", () => { @@ -126,9 +134,10 @@ describe("handleInitData()", () => { enable: true, }; - handleInitData(initData, config); - expect(config.mode).toBe(ILivePreviewModeConfig.PREVIEW); + handleInitData(initData); + expect(Config.get("state.mode")).toBe(ILivePreviewModeConfig.PREVIEW); }); + test("should be set to 2 if user set it to editor", () => { const initData: Partial = { enable: true, @@ -139,18 +148,20 @@ describe("handleInitData()", () => { }, }; - handleInitData(initData, config); - expect(config.mode).toBe(ILivePreviewModeConfig.EDITOR); + handleInitData(initData); + expect(Config.get("state.mode")).toBe(ILivePreviewModeConfig.EDITOR); }); + test("should be set to 1 if user set it to preview", () => { const initData: Partial = { enable: true, mode: "preview", }; - handleInitData(initData, config); - expect(config.mode).toBe(ILivePreviewModeConfig.PREVIEW); + handleInitData(initData); + expect(Config.get("state.mode")).toBe(ILivePreviewModeConfig.PREVIEW); }); + test("should throw an error if user set it to something else", () => { const initData: Partial = { enable: true, @@ -159,226 +170,230 @@ describe("handleInitData()", () => { }; expect(() => { - handleInitData(initData, config); + handleInitData(initData); }).toThrowError( "Live Preview SDK: The mode must be either 'editor' or 'preview'" ); }); }); - describe("stack details set by user", () => { - test("should prioritize api key from user config", () => { - const initData: Partial = { - enable: true, - stackDetails: { - apiKey: "bltuserapikey", - }, - }; - - handleInitData(initData, config); - expect(config.stackDetails.apiKey).toBe("bltuserapikey"); - - config = getDefaultConfig(); - - initData.stackSdk = { - live_preview: {}, - headers: { - api_key: "bltheaderapikey", - }, - environment: "dev", - }; - - handleInitData(initData, config); - expect(config.stackDetails.apiKey).toBe("bltuserapikey"); - }); - - test("should set api key from headers if available", () => { - const initData: Partial = { - enable: true, - - stackSdk: { - live_preview: {}, - headers: { - api_key: "bltheaderapikey", - }, - environment: "dev", - }, - }; - - handleInitData(initData, config); - expect(config.stackDetails.apiKey).toBe("bltheaderapikey"); - }); - - test("should reset api key if it is not passed", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData, config); - expect(config.stackDetails.apiKey).toBe(""); - }); - - test("should throw error if api key is not passed in editor mode", () => { - const initData: Partial = { - enable: true, - stackDetails: { - environment: "dev", - }, - mode: "editor", - }; - - expect(() => { - handleInitData(initData, config); - }).toThrowError("Live preview SDK: api key is required"); - }); - - test("should prioritize environment from user config", () => { - const initData: Partial = { - enable: true, - stackDetails: { - environment: "userenvironment", - }, - }; - - handleInitData(initData, config); - expect(config.stackDetails.environment).toBe("userenvironment"); - - config = getDefaultConfig(); - - initData.stackSdk = { - live_preview: {}, - environment: "sdkenvironment", - headers: { - api_key: "", - }, - }; - - handleInitData(initData, config); - expect(config.stackDetails.environment).toBe("userenvironment"); - }); - - test("should set environment from stack sdk if available", () => { - const initData: Partial = { - enable: true, - stackSdk: { - live_preview: {}, - environment: "sdkenvironment", - headers: { - api_key: "", - }, - }, - }; - - handleInitData(initData, config); - expect(config.stackDetails.environment).toBe("sdkenvironment"); - }); - - test("should reset environment if it is not passed", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData, config); - expect(config.stackDetails.environment).toBe(""); - }); - - test("should throw error if environment is not passed in editor mode", () => { - const initData: Partial = { - enable: true, - stackDetails: { - apiKey: "bltapikey", - }, - mode: "editor", - }; - - expect(() => { - handleInitData(initData, config); - }).toThrowError("Live preview SDK: environment is required"); - }); - - test("should prioritize branch from user config", () => { - const initData: Partial = { - enable: true, - stackDetails: { - branch: "userbranch", - }, - }; - - handleInitData(initData, config); - expect(config.stackDetails.branch).toBe("userbranch"); - - config = getDefaultConfig(); - - initData.stackSdk = { - live_preview: {}, - headers: { - api_key: "bltapikey", - branch: "sdkbranch", - }, - environment: "dev", - }; - - handleInitData(initData, config); - expect(config.stackDetails.branch).toBe("userbranch"); - }); - - test("should set branch from headers if available", () => { - const initData: Partial = { - enable: true, - - stackSdk: { - live_preview: {}, - headers: { - api_key: "sdkbranch", - branch: "sdkbranch", - }, - environment: "dev", - }, - }; - - handleInitData(initData, config); - expect(config.stackDetails.branch).toBe("sdkbranch"); - }); - - test("should reset branch if it is not passed", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData, config); - expect(config.stackDetails.branch).toBe("main"); - }); - - test("should set locale from user config", () => { - const initData: Partial = { - enable: true, - stackDetails: { - locale: "userlocale", - }, - }; - - handleInitData(initData, config); - expect(config.stackDetails.locale).toBe("userlocale"); - }); - - test("should set default locale if it is not passed", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData, config); - expect(config.stackDetails.locale).toBe("en-us"); - }); - }); + // describe("stack details set by user", () => { + // test("should prioritize api key from user config", () => { + // const initData: Partial = { + // enable: true, + // stackDetails: { + // apiKey: "bltuserapikey", + // }, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.apiKey).toBe("bltuserapikey"); + + // config = getDefaultConfig(); + + // initData.stackSdk = { + // live_preview: {}, + // headers: { + // api_key: "bltheaderapikey", + // }, + // environment: "dev", + // }; + + // handleInitData(initData); + // expect(config.stackDetails.apiKey).toBe("bltuserapikey"); + // }); + + // test("should set api key from headers if available", () => { + // const initData: Partial = { + // enable: true, + + // stackSdk: { + // live_preview: {}, + // headers: { + // api_key: "bltheaderapikey", + // }, + // environment: "dev", + // }, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.apiKey).toBe("bltheaderapikey"); + // }); + + // test("should reset api key if it is not passed", () => { + // const initData: Partial = { + // enable: true, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.apiKey).toBe(""); + // }); + + // test("should throw error if api key is not passed in editor mode", () => { + // const initData: Partial = { + // enable: true, + // stackDetails: { + // environment: "dev", + // }, + // mode: "editor", + // }; + + // expect(() => { + // handleInitData(initData); + // }).toThrowError("Live preview SDK: api key is required"); + // }); + + // test("should prioritize environment from user config", () => { + // const initData: Partial = { + // enable: true, + // stackDetails: { + // environment: "userenvironment", + // }, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.environment).toBe("userenvironment"); + + // config = getDefaultConfig(); + + // initData.stackSdk = { + // live_preview: {}, + // environment: "sdkenvironment", + // headers: { + // api_key: "", + // }, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.environment).toBe("userenvironment"); + // }); + + // test("should set environment from stack sdk if available", () => { + // const initData: Partial = { + // enable: true, + // stackSdk: { + // live_preview: {}, + // environment: "sdkenvironment", + // headers: { + // api_key: "", + // }, + // }, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.environment).toBe("sdkenvironment"); + // }); + + // test("should reset environment if it is not passed", () => { + // const initData: Partial = { + // enable: true, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.environment).toBe(""); + // }); + + // test("should throw error if environment is not passed in editor mode", () => { + // const initData: Partial = { + // enable: true, + // stackDetails: { + // apiKey: "bltapikey", + // }, + // mode: "editor", + // }; + + // expect(() => { + // handleInitData(initData); + // }).toThrowError("Live preview SDK: environment is required"); + // }); + + // test("should prioritize branch from user config", () => { + // const initData: Partial = { + // enable: true, + // stackDetails: { + // branch: "userbranch", + // }, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.branch).toBe("userbranch"); + + // config = getDefaultConfig(); + + // initData.stackSdk = { + // live_preview: {}, + // headers: { + // api_key: "bltapikey", + // branch: "sdkbranch", + // }, + // environment: "dev", + // }; + + // handleInitData(initData); + // expect(config.stackDetails.branch).toBe("userbranch"); + // }); + + // test("should set branch from headers if available", () => { + // const initData: Partial = { + // enable: true, + + // stackSdk: { + // live_preview: {}, + // headers: { + // api_key: "sdkbranch", + // branch: "sdkbranch", + // }, + // environment: "dev", + // }, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.branch).toBe("sdkbranch"); + // }); + + // test("should reset branch if it is not passed", () => { + // const initData: Partial = { + // enable: true, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.branch).toBe("main"); + // }); + + // test("should set locale from user config", () => { + // const initData: Partial = { + // enable: true, + // stackDetails: { + // locale: "userlocale", + // }, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.locale).toBe("userlocale"); + // }); + + // test("should set default locale if it is not passed", () => { + // const initData: Partial = { + // enable: true, + // }; + + // handleInitData(initData); + // expect(config.stackDetails.locale).toBe("en-us"); + // }); + // }); }); describe("handleClientUrlParams()", () => { beforeEach(() => { - config = getDefaultConfig(); + Config.reset(); }); + afterEach(() => { + Config.reset(); + }) + test("must modify host and url accordingly", () => { - handleUserConfig.clientUrlParams(config, { + handleUserConfig.clientUrlParams({ host: "example.com/", protocol: "http", }); @@ -389,9 +404,9 @@ describe("handleClientUrlParams()", () => { port: 80, url: "http://example.com:80", }; - expect(config.clientUrlParams).toMatchObject(expectedOutputForHttp); + expect(Config.get("state.clientUrlParams")).toMatchObject(expectedOutputForHttp); - handleUserConfig.clientUrlParams(config, { + handleUserConfig.clientUrlParams({ host: "example.com/", protocol: "https", }); @@ -402,6 +417,6 @@ describe("handleClientUrlParams()", () => { port: 443, url: "https://example.com:443", }; - expect(config.clientUrlParams).toMatchObject(expectedOutputForHttps); + expect(Config.get("state.clientUrlParams")).toMatchObject(expectedOutputForHttps); }); }); diff --git a/src/configManager/config.default.ts b/src/configManager/config.default.ts index cc3e0858..dfdb4f82 100644 --- a/src/configManager/config.default.ts +++ b/src/configManager/config.default.ts @@ -48,7 +48,7 @@ export function getDefaultConfig(): IConfig { exclude: [], position: "top", includeByQueryParameter: true, - } as IConfigEditButton, + }, hash: "" as string, mode: 1 as ILivePreviewModeConfig, @@ -62,21 +62,21 @@ export function getDefaultConfig(): IConfig { locale: "en-us", branch: "main", masterLocale: "en-us", - } as IStackDetails, + }, clientUrlParams: { protocol: "https", host: "app.contentstack.com", port: 443, url: "https://app.contentstack.com:443", - } as IClientUrlParams, + }, stackSdk: { live_preview: {}, headers: { api_key: "", }, environment: "", - } as IStackSdk, + } , runScriptsOnUpdate: false, onChange() { diff --git a/src/configManager/handleUserConfig.ts b/src/configManager/handleUserConfig.ts index 0e67f725..717ad13d 100644 --- a/src/configManager/handleUserConfig.ts +++ b/src/configManager/handleUserConfig.ts @@ -70,8 +70,9 @@ export const handleInitData = (initData: Partial): void => { Config.set( "state.ssr", stackSdk.live_preview?.ssr ?? - (typeof initData.stackSdk === "object" ? false : true) ?? - true + initData.ssr ?? + (typeof initData.stackSdk === "object" ? false : true) ?? + true ); Config.set( @@ -80,10 +81,10 @@ export const handleInitData = (initData: Partial): void => { stackSdk.live_preview?.runScriptsOnUpdate ?? Config.get("state.runScriptsOnUpdate") ); - + Config.set( "state.stackSdk", - initData.stackSdk as unknown as DeepSignal + initData.stackSdk ?? Config.get("state.stackSdk") ); Config.set( From 0f4cb8214c954b93fd2f79c1152052c30f3a1234 Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Fri, 8 Mar 2024 17:02:07 +0530 Subject: [PATCH 05/10] refactor: add state property to Config getter and setter and update associated functions --- .../__test__/configManager.test.ts | 160 +++--- .../__test__/handleUserConfig.test.ts | 477 +++++++++--------- src/configManager/configManager.ts | 25 +- src/configManager/handleUserConfig.ts | 88 ++-- src/cslp/cslpdata.ts | 4 +- src/liveEditor/__test__/index.test.ts | 2 +- .../__test__/visualEditorHover.test.ts | 6 +- src/liveEditor/__test__/withoutIframe.test.ts | 2 +- .../__tests__/startEditingButton.test.tsx | 10 +- src/liveEditor/index.ts | 6 +- .../utils/getLiveEditorRedirectionUrl.ts | 6 +- src/liveEditor/utils/isFieldDisabled.ts | 2 +- src/livePreview/__test__/live-preview.test.ts | 5 +- src/livePreview/editButton/editButton.ts | 45 +- .../eventManager/postMessageEvent.hooks.ts | 10 +- src/livePreview/live-preview.ts | 16 +- src/preview/contentstack-live-preview-HOC.ts | 2 +- 17 files changed, 416 insertions(+), 450 deletions(-) diff --git a/src/configManager/__test__/configManager.test.ts b/src/configManager/__test__/configManager.test.ts index 3777e926..bde168ab 100644 --- a/src/configManager/__test__/configManager.test.ts +++ b/src/configManager/__test__/configManager.test.ts @@ -1,42 +1,6 @@ import Config, { updateConfigFromUrl } from "../configManager"; import { getDefaultConfig } from "../config.default"; -const colours = { - reset: "\x1b[0m", - bright: "\x1b[1m", - dim: "\x1b[2m", - underscore: "\x1b[4m", - blink: "\x1b[5m", - reverse: "\x1b[7m", - hidden: "\x1b[8m", - - fg: { - black: "\x1b[30m", - red: "\x1b[31m", - green: "\x1b[32m", - yellow: "\x1b[33m", - blue: "\x1b[34m", - magenta: "\x1b[35m", - cyan: "\x1b[36m", - white: "\x1b[37m", - gray: "\x1b[90m", - crimson: "\x1b[38m" // Scarlet - }, - bg: { - black: "\x1b[40m", - red: "\x1b[41m", - green: "\x1b[42m", - yellow: "\x1b[43m", - blue: "\x1b[44m", - magenta: "\x1b[45m", - cyan: "\x1b[46m", - white: "\x1b[47m", - gray: "\x1b[100m", - crimson: "\x1b[48m" - } - }; - - describe("Config", () => { beforeEach(() => { Config.reset(); @@ -47,17 +11,17 @@ describe("Config", () => { test("should return default value", () => { const defaultConfig = getDefaultConfig(); - const receivedConfig = Config.get("state"); + const receivedConfig = Config.get(); //@ts-expect-error delete defaultConfig.onChange; delete receivedConfig.onChange; - expect(Config.get("state")).toStrictEqual(defaultConfig); + expect(Config.get()).toStrictEqual(defaultConfig); }); test("should set and get value", () => { const defaultConfig = getDefaultConfig(); - let receivedConfig = Config.get("state"); + let receivedConfig = Config.get(); // @ts-expect-error delete defaultConfig.onChange; @@ -65,8 +29,8 @@ describe("Config", () => { expect(receivedConfig).toEqual({ ...defaultConfig, ssr: true }); - Config.set("state.ssr", false); - receivedConfig = Config.get("state"); + Config.set("ssr", false); + receivedConfig = Config.get(); delete receivedConfig.onChange; @@ -81,7 +45,7 @@ describe("Config", () => { test("should replace config", () => { const defaultConfig = getDefaultConfig(); - let receivedConfig = Config.get("state"); + let receivedConfig = Config.get(); // @ts-expect-error delete defaultConfig.onChange; @@ -98,7 +62,7 @@ describe("Config", () => { }, }); - receivedConfig = Config.get("state"); + receivedConfig = Config.get(); delete receivedConfig.onChange; @@ -115,58 +79,58 @@ describe("Config", () => { }); }); -describe("update config from url", () => { - beforeEach(() => { - Config.reset(); - }); - - afterEach(() => { - Object.defineProperty(window, "location", { - writable: true, - value: { - search: "", - }, - }); - }); - - afterAll(() => { - Config.reset(); - }); - - it("should update config from url if available", () => { - const searchParams = new URLSearchParams(window.location.search); - searchParams.set("content_type_uid", "test"); - searchParams.set("entry_uid", "test"); - searchParams.set("live_preview", "test"); - - // mock window location - Object.defineProperty(window, "location", { - writable: true, - value: { - search: searchParams.toString(), - }, - }); - - expect(Config.get("state.stackDetails.contentTypeUid")).toEqual(""); - expect(Config.get("state.stackDetails.entryUid")).toEqual(""); - expect(Config.get("state.hash")).toEqual(""); - - updateConfigFromUrl(); - - expect(Config.get("state.stackDetails.contentTypeUid")).toEqual("test"); - expect(Config.get("state.stackDetails.entryUid")).toEqual("test"); - expect(Config.get("state.hash")).toEqual("test"); - }); - - it("should be default config if url params are not available", () => { - expect(Config.get("state.stackDetails.contentTypeUid")).toEqual(""); - expect(Config.get("state.stackDetails.entryUid")).toEqual(""); - expect(Config.get("state.hash")).toEqual(""); - - updateConfigFromUrl(); - - expect(Config.get("state.stackDetails.contentTypeUid")).toEqual(""); - expect(Config.get("state.stackDetails.entryUid")).toEqual(""); - expect(Config.get("state.hash")).toEqual(""); - }); -}); +// describe("update config from url", () => { +// beforeEach(() => { +// Config.reset(); +// }); + +// afterEach(() => { +// Object.defineProperty(window, "location", { +// writable: true, +// value: { +// search: "", +// }, +// }); +// }); + +// afterAll(() => { +// Config.reset(); +// }); + +// it("should update config from url if available", () => { +// const searchParams = new URLSearchParams(window.location.search); +// searchParams.set("content_type_uid", "test"); +// searchParams.set("entry_uid", "test"); +// searchParams.set("live_preview", "test"); + +// // mock window location +// Object.defineProperty(window, "location", { +// writable: true, +// value: { +// search: searchParams.toString(), +// }, +// }); + +// expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); +// expect(Config.get("stackDetails.entryUid")).toEqual(""); +// expect(Config.get("hash")).toEqual(""); + +// updateConfigFromUrl(); + +// expect(Config.get("stackDetails.contentTypeUid")).toEqual("test"); +// expect(Config.get("stackDetails.entryUid")).toEqual("test"); +// expect(Config.get("hash")).toEqual("test"); +// }); + +// it("should be default config if url params are not available", () => { +// expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); +// expect(Config.get("stackDetails.entryUid")).toEqual(""); +// expect(Config.get("hash")).toEqual(""); + +// updateConfigFromUrl(); + +// expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); +// expect(Config.get("stackDetails.entryUid")).toEqual(""); +// expect(Config.get("hash")).toEqual(""); +// }); +// }); diff --git a/src/configManager/__test__/handleUserConfig.test.ts b/src/configManager/__test__/handleUserConfig.test.ts index 2a16e61a..0e182850 100644 --- a/src/configManager/__test__/handleUserConfig.test.ts +++ b/src/configManager/__test__/handleUserConfig.test.ts @@ -1,13 +1,8 @@ -import { getDefaultConfig } from "../config.default"; import { handleInitData, handleUserConfig } from "../handleUserConfig"; -import { PublicLogger } from "../../logger/logger"; import { - IConfig, IInitData, ILivePreviewModeConfig, - IStackSdk, } from "../../types/types"; -import { DeepSignal } from "deepsignal"; import Config from "../configManager"; // example Stack object @@ -88,7 +83,7 @@ describe("handleInitData()", () => { }, }; - const config = Config.get("state"); + const config = Config.get(); expect(config).toMatchObject(expectedOutput); }); @@ -102,7 +97,7 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(Config.get("state.ssr")).toBe(true); + expect(Config.get("ssr")).toBe(true); }); test("must set SSR: true is stack SDK is not provided", () => { @@ -125,7 +120,7 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(Config.get("state.ssr")).toBe(false); + expect(Config.get("ssr")).toBe(false); }); describe("live mode", () => { @@ -135,7 +130,7 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(Config.get("state.mode")).toBe(ILivePreviewModeConfig.PREVIEW); + expect(Config.get("mode")).toBe(ILivePreviewModeConfig.PREVIEW); }); test("should be set to 2 if user set it to editor", () => { @@ -149,7 +144,7 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(Config.get("state.mode")).toBe(ILivePreviewModeConfig.EDITOR); + expect(Config.get("mode")).toBe(ILivePreviewModeConfig.EDITOR); }); test("should be set to 1 if user set it to preview", () => { @@ -159,7 +154,7 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(Config.get("state.mode")).toBe(ILivePreviewModeConfig.PREVIEW); + expect(Config.get("mode")).toBe(ILivePreviewModeConfig.PREVIEW); }); test("should throw an error if user set it to something else", () => { @@ -177,246 +172,240 @@ describe("handleInitData()", () => { }); }); - // describe("stack details set by user", () => { - // test("should prioritize api key from user config", () => { - // const initData: Partial = { - // enable: true, - // stackDetails: { - // apiKey: "bltuserapikey", - // }, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.apiKey).toBe("bltuserapikey"); - - // config = getDefaultConfig(); - - // initData.stackSdk = { - // live_preview: {}, - // headers: { - // api_key: "bltheaderapikey", - // }, - // environment: "dev", - // }; - - // handleInitData(initData); - // expect(config.stackDetails.apiKey).toBe("bltuserapikey"); - // }); - - // test("should set api key from headers if available", () => { - // const initData: Partial = { - // enable: true, - - // stackSdk: { - // live_preview: {}, - // headers: { - // api_key: "bltheaderapikey", - // }, - // environment: "dev", - // }, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.apiKey).toBe("bltheaderapikey"); - // }); - - // test("should reset api key if it is not passed", () => { - // const initData: Partial = { - // enable: true, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.apiKey).toBe(""); - // }); - - // test("should throw error if api key is not passed in editor mode", () => { - // const initData: Partial = { - // enable: true, - // stackDetails: { - // environment: "dev", - // }, - // mode: "editor", - // }; - - // expect(() => { - // handleInitData(initData); - // }).toThrowError("Live preview SDK: api key is required"); - // }); - - // test("should prioritize environment from user config", () => { - // const initData: Partial = { - // enable: true, - // stackDetails: { - // environment: "userenvironment", - // }, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.environment).toBe("userenvironment"); - - // config = getDefaultConfig(); - - // initData.stackSdk = { - // live_preview: {}, - // environment: "sdkenvironment", - // headers: { - // api_key: "", - // }, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.environment).toBe("userenvironment"); - // }); - - // test("should set environment from stack sdk if available", () => { - // const initData: Partial = { - // enable: true, - // stackSdk: { - // live_preview: {}, - // environment: "sdkenvironment", - // headers: { - // api_key: "", - // }, - // }, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.environment).toBe("sdkenvironment"); - // }); - - // test("should reset environment if it is not passed", () => { - // const initData: Partial = { - // enable: true, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.environment).toBe(""); - // }); - - // test("should throw error if environment is not passed in editor mode", () => { - // const initData: Partial = { - // enable: true, - // stackDetails: { - // apiKey: "bltapikey", - // }, - // mode: "editor", - // }; - - // expect(() => { - // handleInitData(initData); - // }).toThrowError("Live preview SDK: environment is required"); - // }); - - // test("should prioritize branch from user config", () => { - // const initData: Partial = { - // enable: true, - // stackDetails: { - // branch: "userbranch", - // }, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.branch).toBe("userbranch"); - - // config = getDefaultConfig(); - - // initData.stackSdk = { - // live_preview: {}, - // headers: { - // api_key: "bltapikey", - // branch: "sdkbranch", - // }, - // environment: "dev", - // }; - - // handleInitData(initData); - // expect(config.stackDetails.branch).toBe("userbranch"); - // }); - - // test("should set branch from headers if available", () => { - // const initData: Partial = { - // enable: true, - - // stackSdk: { - // live_preview: {}, - // headers: { - // api_key: "sdkbranch", - // branch: "sdkbranch", - // }, - // environment: "dev", - // }, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.branch).toBe("sdkbranch"); - // }); - - // test("should reset branch if it is not passed", () => { - // const initData: Partial = { - // enable: true, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.branch).toBe("main"); - // }); - - // test("should set locale from user config", () => { - // const initData: Partial = { - // enable: true, - // stackDetails: { - // locale: "userlocale", - // }, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.locale).toBe("userlocale"); - // }); - - // test("should set default locale if it is not passed", () => { - // const initData: Partial = { - // enable: true, - // }; - - // handleInitData(initData); - // expect(config.stackDetails.locale).toBe("en-us"); - // }); - // }); -}); + describe("stack details set by user", () => { + test("should prioritize api key from user config", () => { + const initData: Partial = { + enable: true, + stackDetails: { + apiKey: "bltuserapikey", + }, + }; -describe("handleClientUrlParams()", () => { - beforeEach(() => { - Config.reset(); - }); + handleInitData(initData); + expect(Config.get("stackDetails.apiKey")).toBe("bltuserapikey"); - afterEach(() => { - Config.reset(); - }) + initData.stackSdk = { + live_preview: {}, + headers: { + api_key: "bltheaderapikey", + }, + environment: "dev", + }; - test("must modify host and url accordingly", () => { - handleUserConfig.clientUrlParams({ - host: "example.com/", - protocol: "http", + handleInitData(initData); + expect(Config.get("stackDetails.apiKey")).toBe("bltuserapikey"); }); - const expectedOutputForHttp = { - protocol: "http", - host: "example.com", - port: 80, - url: "http://example.com:80", - }; - expect(Config.get("state.clientUrlParams")).toMatchObject(expectedOutputForHttp); + test("should set api key from headers if available", () => { + const initData: Partial = { + enable: true, + + stackSdk: { + live_preview: {}, + headers: { + api_key: "bltheaderapikey", + }, + environment: "dev", + }, + }; - handleUserConfig.clientUrlParams({ - host: "example.com/", - protocol: "https", + handleInitData(initData); + expect(Config.get("stackDetails.apiKey")).toBe("bltheaderapikey"); }); - const expectedOutputForHttps = { - protocol: "https", - host: "example.com", - port: 443, - url: "https://example.com:443", - }; - expect(Config.get("state.clientUrlParams")).toMatchObject(expectedOutputForHttps); + test("should reset api key if it is not passed", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.apiKey")).toBe(""); + }); + + test("should throw error if api key is not passed in editor mode", () => { + const initData: Partial = { + enable: true, + stackDetails: { + environment: "dev", + }, + mode: "editor", + }; + + expect(() => { + handleInitData(initData); + }).toThrowError("Live preview SDK: api key is required"); + }); + + test("should prioritize environment from user config", () => { + const initData: Partial = { + enable: true, + stackDetails: { + environment: "userenvironment", + }, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.environment")).toBe("userenvironment"); + + initData.stackSdk = { + live_preview: {}, + environment: "sdkenvironment", + headers: { + api_key: "", + }, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.environment")).toBe("userenvironment"); + }); + + test("should set environment from stack sdk if available", () => { + const initData: Partial = { + enable: true, + stackSdk: { + live_preview: {}, + environment: "sdkenvironment", + headers: { + api_key: "", + }, + }, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.environment")).toBe("sdkenvironment"); + }); + + test("should reset environment if it is not passed", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.environment")).toBe(""); + }); + + test("should throw error if environment is not passed in editor mode", () => { + const initData: Partial = { + enable: true, + stackDetails: { + apiKey: "bltapikey", + }, + mode: "editor", + }; + + expect(() => { + handleInitData(initData); + }).toThrowError("Live preview SDK: environment is required"); + }); + + test("should prioritize branch from user config", () => { + const initData: Partial = { + enable: true, + stackDetails: { + branch: "userbranch", + }, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.branch")).toBe("userbranch"); + + initData.stackSdk = { + live_preview: {}, + headers: { + api_key: "bltapikey", + branch: "sdkbranch", + }, + environment: "dev", + }; + + handleInitData(initData); + expect(Config.get("stackDetails.branch")).toBe("userbranch"); + }); + + test("should set branch from headers if available", () => { + const initData: Partial = { + enable: true, + + stackSdk: { + live_preview: {}, + headers: { + api_key: "sdkbranch", + branch: "sdkbranch", + }, + environment: "dev", + }, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.branch")).toBe("sdkbranch"); + }); + + test("should reset branch if it is not passed", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.branch")).toBe("main"); + }); + + test("should set locale from user config", () => { + const initData: Partial = { + enable: true, + stackDetails: { + locale: "userlocale", + }, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.locale")).toBe("userlocale"); + }); + + test("should set default locale if it is not passed", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(Config.get("stackDetails.locale")).toBe("en-us"); + }); }); }); + +// describe("handleClientUrlParams()", () => { +// beforeEach(() => { +// Config.reset(); +// }); + +// afterEach(() => { +// Config.reset(); +// }) + +// test("must modify host and url accordingly", () => { +// handleUserConfig.clientUrlParams({ +// host: "example.com/", +// protocol: "http", +// }); + +// const expectedOutputForHttp = { +// protocol: "http", +// host: "example.com", +// port: 80, +// url: "http://example.com:80", +// }; +// expect(Config.get("clientUrlParams")).toMatchObject(expectedOutputForHttp); + +// handleUserConfig.clientUrlParams({ +// host: "example.com/", +// protocol: "https", +// }); + +// const expectedOutputForHttps = { +// protocol: "https", +// host: "example.com", +// port: 443, +// url: "https://example.com:443", +// }; +// expect(Config.get("clientUrlParams")).toMatchObject(expectedOutputForHttps); +// }); +// }); diff --git a/src/configManager/configManager.ts b/src/configManager/configManager.ts index 32bc1803..9ead5fb9 100644 --- a/src/configManager/configManager.ts +++ b/src/configManager/configManager.ts @@ -16,20 +16,23 @@ class Config { handleInitData(userInput); } - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types static set(key: string, value: any): void { - if (!lodashHas(this.config, key)) { + if (!lodashHas(this.config.state, key)) { throw new Error(`Invalid key: ${key}`); } - lodashSet(this.config, key, value); + lodashSet(this.config.state, key, value); + } - static get(key: string): DeepSignal> { - return lodashGet(this.config, key); + static get(key?: string): DeepSignal> { + if(key === undefined) { + return this.config.state; + } + return lodashGet(this.config.state, key); } static reset(): void { - this.set("state", getDefaultConfig()); + lodashSet(this.config, "state", getDefaultConfig()); } } @@ -76,24 +79,24 @@ export function setConfigFromParams( const content_type_uid = urlParams.get("content_type_uid"); const entry_uid = urlParams.get("entry_uid"); - const stackSdkLivePreview = Config.get("state.stackSdk.live_preview") as { [key: string]: any } & Partial;; + const stackSdkLivePreview = Config.get("stackSdk.live_preview") as { [key: string]: any } & Partial;; if (live_preview) { - Config.set("state.hash", live_preview); + Config.set("hash", live_preview); stackSdkLivePreview.hash = live_preview; stackSdkLivePreview.live_preview = live_preview; } if (content_type_uid) { - Config.set("state.stackDetails.contentTypeUid", content_type_uid); + Config.set("stackDetails.contentTypeUid", content_type_uid); stackSdkLivePreview.content_type_uid = content_type_uid; } if (entry_uid) { - Config.set("state.stackDetails.entryUid", entry_uid); + Config.set("stackDetails.entryUid", entry_uid); stackSdkLivePreview.entry_uid = entry_uid; } - Config.set("state.stackSdk.live_preview", stackSdkLivePreview); + Config.set("stackSdk.live_preview", stackSdkLivePreview); } diff --git a/src/configManager/handleUserConfig.ts b/src/configManager/handleUserConfig.ts index 717ad13d..7c6518ce 100644 --- a/src/configManager/handleUserConfig.ts +++ b/src/configManager/handleUserConfig.ts @@ -10,47 +10,47 @@ import Config from "./configManager"; const handleClientUrlParams = (userConfig: Partial): void => { Config.set( - "state.clientUrlParams.host", - userConfig.host ?? Config.get("state.clientUrlParams.host") + "clientUrlParams.host", + userConfig.host ?? Config.get("clientUrlParams.host") ); Config.set( - "state.clientUrlParams.protocol", - userConfig.protocol ?? Config.get("state.clientUrlParams.protocol") + "clientUrlParams.protocol", + userConfig.protocol ?? Config.get("clientUrlParams.protocol") ); Config.set( - "state.clientUrlParams.port", - userConfig.port ?? Config.get("state.clientUrlParams.port") + "clientUrlParams.port", + userConfig.port ?? Config.get("clientUrlParams.port") ); if (userConfig.protocol !== undefined && userConfig.port === undefined) { switch (userConfig.protocol) { case "http": { - Config.set("state.clientUrlParams.port", 80); + Config.set("clientUrlParams.port", 80); break; } case "https": { - Config.set("state.clientUrlParams.port", 443); + Config.set("clientUrlParams.port", 443); break; } } } // build url - let host = Config.get("state.clientUrlParams.host") as unknown as string; + let host = Config.get("clientUrlParams.host") as unknown as string; let protocol = Config.get( - "state.clientUrlParams.protocol" + "clientUrlParams.protocol" ) as unknown as string; - let port = Config.get("state.clientUrlParams.port") as unknown as + let port = Config.get("clientUrlParams.port") as unknown as | string | number; if (host.endsWith("/")) { host = host.slice(0, -1); - Config.set("state.clientUrlParams.host", host); + Config.set("clientUrlParams.host", host); } - Config.set("state.clientUrlParams.url", `${protocol}://${host}:${port}`); + Config.set("clientUrlParams.url", `${protocol}://${host}:${port}`); }; // TODO: add documentation mentioning that you cannot pass stack sdk in the init data @@ -58,17 +58,17 @@ const handleClientUrlParams = (userConfig: Partial): void => { export const handleInitData = (initData: Partial): void => { const stackSdk: IStackSdk = initData.stackSdk || - (Config.get("state.stackSdk") as unknown as IStackSdk); + (Config.get("stackSdk") as unknown as IStackSdk); Config.set( - "state.enable", + "enable", initData.enable ?? stackSdk.live_preview?.enable ?? - Config.get("state.enable") + Config.get("enable") ); Config.set( - "state.ssr", + "ssr", stackSdk.live_preview?.ssr ?? initData.ssr ?? (typeof initData.stackSdk === "object" ? false : true) ?? @@ -76,29 +76,29 @@ export const handleInitData = (initData: Partial): void => { ); Config.set( - "state.runScriptsOnUpdate", + "runScriptsOnUpdate", initData.runScriptsOnUpdate ?? stackSdk.live_preview?.runScriptsOnUpdate ?? - Config.get("state.runScriptsOnUpdate") + Config.get("runScriptsOnUpdate") ); Config.set( - "state.stackSdk", - initData.stackSdk ?? Config.get("state.stackSdk") + "stackSdk", + initData.stackSdk ?? Config.get("stackSdk") ); Config.set( - "state.cleanCslpOnProduction", + "cleanCslpOnProduction", initData.cleanCslpOnProduction ?? stackSdk.live_preview?.cleanCslpOnProduction ?? - Config.get("state.cleanCslpOnProduction") + Config.get("cleanCslpOnProduction") ); - Config.set("state.editButton", { + Config.set("editButton", { enable: initData.editButton?.enable ?? stackSdk.live_preview?.editButton?.enable ?? - Config.get("state.editButton.enable"), + Config.get("editButton.enable"), // added extra check if exclude data passed by user is array or not exclude: Array.isArray(initData.editButton?.exclude) && @@ -107,17 +107,17 @@ export const handleInitData = (initData: Partial): void => { : Array.isArray(stackSdk.live_preview?.exclude) && stackSdk.live_preview?.exclude ? stackSdk.live_preview?.exclude - : Config.get("state.editButton.exclude") ?? [], + : Config.get("editButton.exclude") ?? [], position: initData.editButton?.position ?? stackSdk.live_preview?.position ?? - Config.get("state.editButton.position") ?? + Config.get("editButton.position") ?? "top", includeByQueryParameter: initData.editButton?.includeByQueryParameter ?? stackSdk.live_preview?.includeByQueryParameter ?? - Config.get("state.editButton.includeByQueryParameter") ?? + Config.get("editButton.includeByQueryParameter") ?? true, }); @@ -127,7 +127,7 @@ export const handleInitData = (initData: Partial): void => { | Partial> | undefined) ?? (stackSdk.live_preview?.clientUrlParams as IClientUrlParams) ?? - (Config.get("state.clientUrlParams") as unknown as IClientUrlParams) + (Config.get("clientUrlParams") as unknown as IClientUrlParams) ); // Partial>; || IClientUrlParams || @@ -135,11 +135,11 @@ export const handleInitData = (initData: Partial): void => { if (initData.mode) { switch (initData.mode) { case "preview": { - Config.set("state.mode", ILivePreviewModeConfig.PREVIEW); + Config.set("mode", ILivePreviewModeConfig.PREVIEW); break; } case "editor": { - Config.set("state.mode", ILivePreviewModeConfig.EDITOR); + Config.set("mode", ILivePreviewModeConfig.EDITOR); break; } default: { @@ -151,10 +151,10 @@ export const handleInitData = (initData: Partial): void => { } Config.set( - "state.debug", + "debug", initData.debug ?? stackSdk.live_preview?.debug ?? - Config.get("state.debug") + Config.get("debug") ); handleStackDetails(initData, stackSdk); @@ -165,40 +165,40 @@ function handleStackDetails( stackSdk: Partial ): void { Config.set( - "state.stackDetails.apiKey", + "stackDetails.apiKey", initData.stackDetails?.apiKey ?? stackSdk.headers?.api_key ?? - Config.get("state.stackDetails.apiKey") + Config.get("stackDetails.apiKey") ); Config.set( - "state.stackDetails.environment", + "stackDetails.environment", initData.stackDetails?.environment ?? stackSdk.environment ?? - Config.get("state.stackDetails.environment") + Config.get("stackDetails.environment") ); Config.set( - "state.stackDetails.branch", + "stackDetails.branch", initData.stackDetails?.branch ?? stackSdk.headers?.branch ?? - Config.get("state.stackDetails.branch") + Config.get("stackDetails.branch") ); Config.set( - "state.stackDetails.locale", - initData.stackDetails?.locale ?? Config.get("state.stackDetails.locale") + "stackDetails.locale", + initData.stackDetails?.locale ?? Config.get("stackDetails.locale") ); if ( - (Config.get("state.mode") as unknown as number) >= + (Config.get("mode") as unknown as number) >= ILivePreviewModeConfig.EDITOR ) { - if (!Config.get("state.stackDetails.environment")) { + if (!Config.get("stackDetails.environment")) { throw Error("Live preview SDK: environment is required"); } - if (!Config.get("state.stackDetails.apiKey")) { + if (!Config.get("stackDetails.apiKey")) { throw Error("Live preview SDK: api key is required"); } } diff --git a/src/cslp/cslpdata.ts b/src/cslp/cslpdata.ts index 76963a87..3f87d640 100644 --- a/src/cslp/cslpdata.ts +++ b/src/cslp/cslpdata.ts @@ -120,7 +120,7 @@ export function addCslpOutline( }) => void ): void { - const elements = Config.get("state.elements") as unknown as { + const elements = Config.get("elements") as unknown as { highlightedElement: HTMLElement | null; }; @@ -143,7 +143,7 @@ export function addCslpOutline( const updatedElements = elements; updatedElements.highlightedElement = element; - Config.set("state.elements", updatedElements); + Config.set("elements", updatedElements); callback?.({ cslpTag: cslpTag, diff --git a/src/liveEditor/__test__/index.test.ts b/src/liveEditor/__test__/index.test.ts index 430e939f..d8958fa6 100644 --- a/src/liveEditor/__test__/index.test.ts +++ b/src/liveEditor/__test__/index.test.ts @@ -45,7 +45,7 @@ describe("Visual editor", () => { "all_fields", getFieldSchemaMap().all_fields ); - Config.set("state.mode", 2); + Config.set("mode", 2); }); afterEach(() => { diff --git a/src/liveEditor/__test__/visualEditorHover.test.ts b/src/liveEditor/__test__/visualEditorHover.test.ts index ab117f57..e2024fdd 100644 --- a/src/liveEditor/__test__/visualEditorHover.test.ts +++ b/src/liveEditor/__test__/visualEditorHover.test.ts @@ -162,11 +162,11 @@ describe("When an element is hovered in visual editor mode", () => { "all_fields", getFieldSchemaMap().all_fields ); - - Config.set("state.mode", 2); }); beforeEach(() => { + Config.reset(); + Config.set("mode", 2); mousemoveEvent = new Event("mousemove", { bubbles: true, cancelable: true, @@ -174,6 +174,7 @@ describe("When an element is hovered in visual editor mode", () => { }); afterEach(() => { + Config.reset(); jest.clearAllMocks(); document.getElementsByTagName("html")[0].innerHTML = ""; }); @@ -216,6 +217,7 @@ describe("When an element is hovered in visual editor mode", () => { }); }); + describe("single line field", () => { let singleLineField: HTMLParagraphElement; let visualEditor: VisualEditor; diff --git a/src/liveEditor/__test__/withoutIframe.test.ts b/src/liveEditor/__test__/withoutIframe.test.ts index 42de792d..cd1f9b92 100644 --- a/src/liveEditor/__test__/withoutIframe.test.ts +++ b/src/liveEditor/__test__/withoutIframe.test.ts @@ -17,7 +17,7 @@ global.ResizeObserver = jest.fn().mockImplementation(() => ({ })); describe("When outside the Visual editor, the Visual Editor", () => { beforeAll(() => { - Config.set("state.mode", 2); + Config.set("mode", 2); }); afterAll(() => { Config.reset(); diff --git a/src/liveEditor/components/__tests__/startEditingButton.test.tsx b/src/liveEditor/components/__tests__/startEditingButton.test.tsx index 0b434a4d..5ce42d2d 100644 --- a/src/liveEditor/components/__tests__/startEditingButton.test.tsx +++ b/src/liveEditor/components/__tests__/startEditingButton.test.tsx @@ -2,24 +2,24 @@ import "@testing-library/jest-dom/extend-expect"; import { render, fireEvent } from "@testing-library/preact"; import StartEditingButtonComponent from "../startEditingButton"; import { IConfig } from "../../../types/types"; -import { getDefaultConfig } from "../../../configManager/config.default"; import { DeepSignal } from "deepsignal"; import Config from "../../../configManager/configManager"; describe("StartEditingButtonComponent", () => { - let config: DeepSignal; let visualEditorContainer: HTMLDivElement; beforeEach(() => { - Config.set("state.stackDetails.apiKey", "bltapikey"); - Config.set("state.stackDetails.environment", "bltenvironment"); + Config.reset(); + Config.set("stackDetails.apiKey", "bltapikey"); + Config.set("stackDetails.environment", "bltenvironment"); visualEditorContainer = document.createElement("div"); document.body.appendChild(visualEditorContainer); }); afterEach(() => { + Config.reset(); jest.clearAllMocks(); document.body.removeChild(visualEditorContainer); }); @@ -42,7 +42,7 @@ describe("StartEditingButtonComponent", () => { fireEvent.click(button); expect(button?.getAttribute("href")).toBe( - "https://app.contentstack.com/live-editor/stack//environment/?branch=main&target-url=http%3A%2F%2Flocalhost%2F&locale=en-us" + "https://app.contentstack.com/live-editor/stack/bltapikey/environment/bltenvironment?branch=main&target-url=http%3A%2F%2Flocalhost%2F&locale=en-us" ); }); }); diff --git a/src/liveEditor/index.ts b/src/liveEditor/index.ts index 2b043e6e..db9203e0 100644 --- a/src/liveEditor/index.ts +++ b/src/liveEditor/index.ts @@ -77,20 +77,20 @@ export class VisualEditor { ".visual-editor__focused-toolbar" ); - if (!Config.get("state.enable") || Config.get("state.mode") as unknown as number < ILivePreviewModeConfig.EDITOR) { + if (!Config.get("enable") || Config.get("mode") as unknown as number < ILivePreviewModeConfig.EDITOR) { return; } liveEditorPostMessage ?.send("init", { - isSSR: Config.get("state.ssr"), + isSSR: Config.get("ssr"), }) .then((data) => { const { windowType = ILivePreviewWindowType.EDITOR, stackDetails, } = data; - Config.set("state.windowType", windowType); + Config.set("windowType", windowType); Config.set( "stackDetails.masterLocale", stackDetails?.masterLocale || "en-us" diff --git a/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts b/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts index 48244fc1..3675fb91 100644 --- a/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts +++ b/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts @@ -7,8 +7,8 @@ import { IClientUrlParams, IStackDetails } from "../../types/types"; * @returns {URL} The redirection URL. */ export default function getLiveEditorRedirectionUrl(): URL { - const stackDetails = Config.get("state.stackDetails") as unknown as IStackDetails; - const clientUrlParams = Config.get("state.clientUrlParams") as unknown as IClientUrlParams; + const stackDetails = Config.get("stackDetails") as unknown as IStackDetails; + const clientUrlParams = Config.get("clientUrlParams") as unknown as IClientUrlParams; const { branch, apiKey, environment, locale } = stackDetails; const { url: appUrl } = clientUrlParams; @@ -36,6 +36,6 @@ export default function getLiveEditorRedirectionUrl(): URL { } else if (locale) { completeURL.searchParams.set("locale", locale); } - + return completeURL; } diff --git a/src/liveEditor/utils/isFieldDisabled.ts b/src/liveEditor/utils/isFieldDisabled.ts index 527998d6..343167f7 100644 --- a/src/liveEditor/utils/isFieldDisabled.ts +++ b/src/liveEditor/utils/isFieldDisabled.ts @@ -6,7 +6,7 @@ export const isFieldDisabled = ( fieldSchemaMap: ISchemaFieldMap, eventDetails: VisualEditorCslpEventDetails ): any => { - const masterLocale = Config.get("state.stackDetails.masterLocale") as unknown as string || "en-us"; + const masterLocale = Config.get("stackDetails.masterLocale") as unknown as string || "en-us"; const updateRestrictDueToRole = Boolean( fieldSchemaMap?.field_metadata?.updateRestrict ); diff --git a/src/livePreview/__test__/live-preview.test.ts b/src/livePreview/__test__/live-preview.test.ts index 52b2bd40..3fb9dc1c 100644 --- a/src/livePreview/__test__/live-preview.test.ts +++ b/src/livePreview/__test__/live-preview.test.ts @@ -53,6 +53,7 @@ global.ResizeObserver = jest.fn().mockImplementation(() => ({ unobserve: jest.fn(), disconnect: jest.fn(), })); + describe("cslp tooltip", () => { beforeEach(() => { Config.reset(); @@ -79,7 +80,7 @@ describe("cslp tooltip", () => { document.body.appendChild(descPara); document.body.appendChild(linkPara); - Config.set("state.windowType", ILivePreviewWindowType.PREVIEW); + Config.set("windowType", ILivePreviewWindowType.PREVIEW); }); afterEach(() => { @@ -300,7 +301,7 @@ describe("debug module", () => { const expectedOutput = getDefaultConfig(); expectedOutput.debug = true; - const actualOutput = outputErrorLog[1]; + const actualOutput = outputErrorLog[1]["state"]; // Not removing them causes serialization problems. // @ts-ignore diff --git a/src/livePreview/editButton/editButton.ts b/src/livePreview/editButton/editButton.ts index 3da834eb..87b74224 100644 --- a/src/livePreview/editButton/editButton.ts +++ b/src/livePreview/editButton/editButton.ts @@ -3,9 +3,11 @@ import Config from "../../configManager/configManager"; import { addCslpOutline, extractDetailsFromCslp } from "../../cslp"; import { PublicLogger } from "../../logger/logger"; import { + IClientUrlParams, IConfigEditButton, IEditButtonPosition, ILivePreviewWindowType, + IStackDetails, } from "../../types/types"; import livePreviewPostMessage from "../eventManager/livePreviewEventManager"; @@ -198,7 +200,7 @@ export function shouldRenderEditButton(editButton: IConfigEditButton): boolean { ) ) { return false; - } + } // case outside live preview if ( @@ -265,11 +267,9 @@ export class LivePreviewEditButton { } private createCslpTooltip(): boolean { - const config = Config.get(); - if ( !document.getElementById("cslp-tooltip") && - config.editButton.enable + Config.get("editButton.enable") ) { const tooltip = document.createElement("button"); this.tooltip = tooltip; @@ -297,8 +297,9 @@ export class LivePreviewEditButton { } private updateTooltipPosition() { - const config = Config.get(); - const { elements } = config; + const elements = Config.get("elements") as { + highlightedElement: HTMLElement | null; + }; if (!elements.highlightedElement || !this.tooltip) return false; @@ -310,7 +311,7 @@ export class LivePreviewEditButton { if (currentRectOfElement && currentRectOfParentOfElement) { const editButtonPosition = getEditButtonPosition( elements.highlightedElement, - config.editButton.position + Config.get("editButton.position") as string ); let upperBoundOfTooltip = editButtonPosition.upperBoundOfTooltip; @@ -362,11 +363,14 @@ export class LivePreviewEditButton { } }; - const config = Config.get(); + const windowType = Config.get( + "windowType" + ) as unknown as ILivePreviewWindowType; + if ( - (config.windowType === ILivePreviewWindowType.PREVIEW || - config.windowType === ILivePreviewWindowType.INDEPENDENT) && - config.editButton.enable + (windowType === ILivePreviewWindowType.PREVIEW || + windowType === ILivePreviewWindowType.INDEPENDENT) && + Config.get("editButton.enable") ) { addCslpOutline(e, updateTooltipPosition); } @@ -420,8 +424,11 @@ export class LivePreviewEditButton { entry_uid: string, preview_field: string ): string { - const config = Config.get(); - if (!config.stackDetails.apiKey) { + + const stackDetails = Config.get("stackDetails") as IStackDetails; + const clientUrlParams = Config.get("clientUrlParams") as IClientUrlParams; + + if (!stackDetails.apiKey) { throw `To use edit tags, you must provide the stack API key. Specify the API key while initializing the Live Preview SDK. ContentstackLivePreview.init({ @@ -433,7 +440,7 @@ export class LivePreviewEditButton { })`; } - if (!config.stackDetails.environment) { + if (!stackDetails.environment) { throw `To use edit tags, you must provide the preview environment. Specify the preview environment while initializing the Live Preview SDK. ContentstackLivePreview.init({ @@ -445,13 +452,13 @@ export class LivePreviewEditButton { })`; } - const protocol = String(config.clientUrlParams.protocol); - const host = String(config.clientUrlParams.host); - const port = String(config.clientUrlParams.port); - const environment = String(config.stackDetails.environment); + const protocol = String(clientUrlParams.protocol); + const host = String(clientUrlParams.host); + const port = String(clientUrlParams.port); + const environment = String(stackDetails.environment); const urlHash = `!/stack/${ - config.stackDetails.apiKey + stackDetails.apiKey }/content-type/${content_type_uid}/${ locale ?? "en-us" }/entry/${entry_uid}/edit`; diff --git a/src/livePreview/eventManager/postMessageEvent.hooks.ts b/src/livePreview/eventManager/postMessageEvent.hooks.ts index 21969f1e..86089f8a 100644 --- a/src/livePreview/eventManager/postMessageEvent.hooks.ts +++ b/src/livePreview/eventManager/postMessageEvent.hooks.ts @@ -51,8 +51,8 @@ export function useOnEntryUpdatePostMessageEvent(): void { live_preview: event.data.hash, }); - if (!Config.get("state.ssr")) { - const config = Config.get("state"); + if (!Config.get("ssr")) { + const config = Config.get(); config.onChange!(); } } @@ -66,7 +66,7 @@ export function sendInitializeLivePreviewPostMessageEvent(): void { LIVE_PREVIEW_POST_MESSAGE_EVENTS.INIT, { config: { - shouldReload: Config.get("state.ssr"), + shouldReload: Config.get("ssr"), href: window.location.href, sdkVersion: packageJson.version, }, @@ -91,10 +91,10 @@ export function sendInitializeLivePreviewPostMessageEvent(): void { // "init message did not contain contentTypeUid or entryUid." // ); } - Config.set("state.windowType", windowType); + Config.set("windowType", windowType); // set timeout for client side (use to show warning: You are not editing this page) - if (!Config.get("state.ssr")) { + if (!Config.get("ssr")) { setInterval(() => { sendCurrentPageUrlPostMessageEvent(); }, 1500); diff --git a/src/livePreview/live-preview.ts b/src/livePreview/live-preview.ts index 5d9c5867..35c1a443 100644 --- a/src/livePreview/live-preview.ts +++ b/src/livePreview/live-preview.ts @@ -29,14 +29,14 @@ export default class LivePreview { this.unsubscribeOnEntryChange = this.unsubscribeOnEntryChange.bind(this); - if (Config.get("state.debug")) { + if (Config.get("debug")) { PublicLogger.debug( "Contentstack Live Preview Debugging mode: config --", Config.config ); } - if (Config.get("state.enable")) { + if (Config.get("enable")) { if ( typeof document !== undefined && document.readyState === "complete" @@ -52,14 +52,14 @@ export default class LivePreview { // render the hover outline only when edit button enable if ( - Config.get("state.editButton.enable") || - Config.get("state.mode") as unknown as number >= ILivePreviewModeConfig.EDITOR + Config.get("editButton.enable") || + Config.get("mode") as unknown as number >= ILivePreviewModeConfig.EDITOR ) { new LivePreviewEditButton(); } //NOTE - I think we are already handling the link click event here. Let's move it to a function. - if (Config.get("state.ssr")) { + if (Config.get("ssr")) { // NOTE: what are we doing here? window.addEventListener("load", (e) => { const allATags = document.querySelectorAll("a"); @@ -87,16 +87,16 @@ export default class LivePreview { } }); } - } else if (Config.get("state.cleanCslpOnProduction")) { + } else if (Config.get("cleanCslpOnProduction")) { removeDataCslp(); } } // Request parent for data sync when document loads private requestDataSync() { - const config = Config.get("state"); + const config = Config.get(); - Config.set("state.onChange", this.publish); + Config.set("onChange", this.publish); //! TODO: we replaced the handleOnChange() with this. //! I don't think we need this. Confirm and remove it. diff --git a/src/preview/contentstack-live-preview-HOC.ts b/src/preview/contentstack-live-preview-HOC.ts index e71c60e3..d4a85f3a 100644 --- a/src/preview/contentstack-live-preview-HOC.ts +++ b/src/preview/contentstack-live-preview-HOC.ts @@ -67,7 +67,7 @@ class ContentstackLivePreview { if (!ContentstackLivePreview.isInitialized()) { updateConfigFromUrl(); // check if we could extract from the URL } - return Config.get("state.hash") as unknown as string; + return Config.get("hash") as unknown as string; } private static isInitialized(): boolean { From bc7fdcde312cff189be9e15d554115dc1c0f67c9 Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Fri, 8 Mar 2024 17:08:43 +0530 Subject: [PATCH 06/10] chore: re-add commented test cases --- .../__test__/configManager.test.ts | 110 +++++++++--------- .../__test__/handleUserConfig.test.ts | 74 ++++++------ 2 files changed, 92 insertions(+), 92 deletions(-) diff --git a/src/configManager/__test__/configManager.test.ts b/src/configManager/__test__/configManager.test.ts index bde168ab..26f2cd27 100644 --- a/src/configManager/__test__/configManager.test.ts +++ b/src/configManager/__test__/configManager.test.ts @@ -79,58 +79,58 @@ describe("Config", () => { }); }); -// describe("update config from url", () => { -// beforeEach(() => { -// Config.reset(); -// }); - -// afterEach(() => { -// Object.defineProperty(window, "location", { -// writable: true, -// value: { -// search: "", -// }, -// }); -// }); - -// afterAll(() => { -// Config.reset(); -// }); - -// it("should update config from url if available", () => { -// const searchParams = new URLSearchParams(window.location.search); -// searchParams.set("content_type_uid", "test"); -// searchParams.set("entry_uid", "test"); -// searchParams.set("live_preview", "test"); - -// // mock window location -// Object.defineProperty(window, "location", { -// writable: true, -// value: { -// search: searchParams.toString(), -// }, -// }); - -// expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); -// expect(Config.get("stackDetails.entryUid")).toEqual(""); -// expect(Config.get("hash")).toEqual(""); - -// updateConfigFromUrl(); - -// expect(Config.get("stackDetails.contentTypeUid")).toEqual("test"); -// expect(Config.get("stackDetails.entryUid")).toEqual("test"); -// expect(Config.get("hash")).toEqual("test"); -// }); - -// it("should be default config if url params are not available", () => { -// expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); -// expect(Config.get("stackDetails.entryUid")).toEqual(""); -// expect(Config.get("hash")).toEqual(""); - -// updateConfigFromUrl(); - -// expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); -// expect(Config.get("stackDetails.entryUid")).toEqual(""); -// expect(Config.get("hash")).toEqual(""); -// }); -// }); +describe("update config from url", () => { + beforeEach(() => { + Config.reset(); + }); + + afterEach(() => { + Object.defineProperty(window, "location", { + writable: true, + value: { + search: "", + }, + }); + }); + + afterAll(() => { + Config.reset(); + }); + + it("should update config from url if available", () => { + const searchParams = new URLSearchParams(window.location.search); + searchParams.set("content_type_uid", "test"); + searchParams.set("entry_uid", "test"); + searchParams.set("live_preview", "test"); + + // mock window location + Object.defineProperty(window, "location", { + writable: true, + value: { + search: searchParams.toString(), + }, + }); + + expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); + expect(Config.get("stackDetails.entryUid")).toEqual(""); + expect(Config.get("hash")).toEqual(""); + + updateConfigFromUrl(); + + expect(Config.get("stackDetails.contentTypeUid")).toEqual("test"); + expect(Config.get("stackDetails.entryUid")).toEqual("test"); + expect(Config.get("hash")).toEqual("test"); + }); + + it("should be default config if url params are not available", () => { + expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); + expect(Config.get("stackDetails.entryUid")).toEqual(""); + expect(Config.get("hash")).toEqual(""); + + updateConfigFromUrl(); + + expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); + expect(Config.get("stackDetails.entryUid")).toEqual(""); + expect(Config.get("hash")).toEqual(""); + }); +}); diff --git a/src/configManager/__test__/handleUserConfig.test.ts b/src/configManager/__test__/handleUserConfig.test.ts index 0e182850..ade689f4 100644 --- a/src/configManager/__test__/handleUserConfig.test.ts +++ b/src/configManager/__test__/handleUserConfig.test.ts @@ -372,40 +372,40 @@ describe("handleInitData()", () => { }); }); -// describe("handleClientUrlParams()", () => { -// beforeEach(() => { -// Config.reset(); -// }); - -// afterEach(() => { -// Config.reset(); -// }) - -// test("must modify host and url accordingly", () => { -// handleUserConfig.clientUrlParams({ -// host: "example.com/", -// protocol: "http", -// }); - -// const expectedOutputForHttp = { -// protocol: "http", -// host: "example.com", -// port: 80, -// url: "http://example.com:80", -// }; -// expect(Config.get("clientUrlParams")).toMatchObject(expectedOutputForHttp); - -// handleUserConfig.clientUrlParams({ -// host: "example.com/", -// protocol: "https", -// }); - -// const expectedOutputForHttps = { -// protocol: "https", -// host: "example.com", -// port: 443, -// url: "https://example.com:443", -// }; -// expect(Config.get("clientUrlParams")).toMatchObject(expectedOutputForHttps); -// }); -// }); +describe("handleClientUrlParams()", () => { + beforeEach(() => { + Config.reset(); + }); + + afterEach(() => { + Config.reset(); + }) + + test("must modify host and url accordingly", () => { + handleUserConfig.clientUrlParams({ + host: "example.com/", + protocol: "http", + }); + + const expectedOutputForHttp = { + protocol: "http", + host: "example.com", + port: 80, + url: "http://example.com:80", + }; + expect(Config.get("clientUrlParams")).toMatchObject(expectedOutputForHttp); + + handleUserConfig.clientUrlParams({ + host: "example.com/", + protocol: "https", + }); + + const expectedOutputForHttps = { + protocol: "https", + host: "example.com", + port: 443, + url: "https://example.com:443", + }; + expect(Config.get("clientUrlParams")).toMatchObject(expectedOutputForHttps); + }); +}); From 378ea8b3010196e591eae29b39c42ba8af04b07d Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Fri, 8 Mar 2024 17:16:59 +0530 Subject: [PATCH 07/10] chore: lint and prettify code --- .../__test__/handleUserConfig.test.ts | 30 +++++++++++-------- src/configManager/config.default.ts | 17 ++++++----- src/configManager/configManager.ts | 24 ++++++++------- src/configManager/handleUserConfig.ts | 30 +++++++------------ src/cslp/cslpdata.ts | 5 +--- .../__test__/visualEditorHover.test.ts | 1 - .../__tests__/multipleFieldToolbar.test.tsx | 7 +---- .../__tests__/startEditingButton.test.tsx | 3 -- src/liveEditor/index.ts | 6 +++- .../utils/getLiveEditorRedirectionUrl.ts | 6 ++-- src/liveEditor/utils/isFieldDisabled.ts | 4 ++- src/livePreview/__test__/live-preview.test.ts | 9 ++---- src/livePreview/editButton/editButton.ts | 5 ++-- .../eventManager/postMessageEvent.hooks.ts | 2 -- src/livePreview/live-preview.ts | 6 ++-- 15 files changed, 73 insertions(+), 82 deletions(-) diff --git a/src/configManager/__test__/handleUserConfig.test.ts b/src/configManager/__test__/handleUserConfig.test.ts index ade689f4..f6fb613b 100644 --- a/src/configManager/__test__/handleUserConfig.test.ts +++ b/src/configManager/__test__/handleUserConfig.test.ts @@ -1,8 +1,5 @@ import { handleInitData, handleUserConfig } from "../handleUserConfig"; -import { - IInitData, - ILivePreviewModeConfig, -} from "../../types/types"; +import { IInitData, ILivePreviewModeConfig } from "../../types/types"; import Config from "../configManager"; // example Stack object @@ -39,7 +36,6 @@ import Config from "../configManager"; } */ - describe("handleInitData()", () => { beforeEach(() => { Config.reset(); @@ -47,7 +43,7 @@ describe("handleInitData()", () => { afterEach(() => { Config.reset(); - }) + }); test("must set data when config is provided", () => { const initData: Partial = { @@ -245,7 +241,9 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(Config.get("stackDetails.environment")).toBe("userenvironment"); + expect(Config.get("stackDetails.environment")).toBe( + "userenvironment" + ); initData.stackSdk = { live_preview: {}, @@ -256,7 +254,9 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(Config.get("stackDetails.environment")).toBe("userenvironment"); + expect(Config.get("stackDetails.environment")).toBe( + "userenvironment" + ); }); test("should set environment from stack sdk if available", () => { @@ -272,7 +272,9 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(Config.get("stackDetails.environment")).toBe("sdkenvironment"); + expect(Config.get("stackDetails.environment")).toBe( + "sdkenvironment" + ); }); test("should reset environment if it is not passed", () => { @@ -379,7 +381,7 @@ describe("handleClientUrlParams()", () => { afterEach(() => { Config.reset(); - }) + }); test("must modify host and url accordingly", () => { handleUserConfig.clientUrlParams({ @@ -393,7 +395,9 @@ describe("handleClientUrlParams()", () => { port: 80, url: "http://example.com:80", }; - expect(Config.get("clientUrlParams")).toMatchObject(expectedOutputForHttp); + expect(Config.get("clientUrlParams")).toMatchObject( + expectedOutputForHttp + ); handleUserConfig.clientUrlParams({ host: "example.com/", @@ -406,6 +410,8 @@ describe("handleClientUrlParams()", () => { port: 443, url: "https://example.com:443", }; - expect(Config.get("clientUrlParams")).toMatchObject(expectedOutputForHttps); + expect(Config.get("clientUrlParams")).toMatchObject( + expectedOutputForHttps + ); }); }); diff --git a/src/configManager/config.default.ts b/src/configManager/config.default.ts index dfdb4f82..4178ed38 100644 --- a/src/configManager/config.default.ts +++ b/src/configManager/config.default.ts @@ -1,4 +1,9 @@ -import { IClientUrlParams, IConfig, IConfigEditButton, IInitData, ILivePreviewModeConfig, ILivePreviewWindowType, IStackDetails, IStackSdk } from "../types/types"; +import { + IConfig, + IInitData, + ILivePreviewModeConfig, + ILivePreviewWindowType, +} from "../types/types"; export function getUserInitData(): IInitData { return { @@ -51,7 +56,7 @@ export function getDefaultConfig(): IConfig { }, hash: "" as string, - mode: 1 as ILivePreviewModeConfig, + mode: 1 as ILivePreviewModeConfig, windowType: ILivePreviewWindowType.INDEPENDENT, stackDetails: { @@ -69,14 +74,14 @@ export function getDefaultConfig(): IConfig { host: "app.contentstack.com", port: 443, url: "https://app.contentstack.com:443", - }, + }, stackSdk: { live_preview: {}, headers: { api_key: "", }, environment: "", - } , + }, runScriptsOnUpdate: false, onChange() { @@ -85,8 +90,6 @@ export function getDefaultConfig(): IConfig { elements: { highlightedElement: null, - } + }, }; - - } diff --git a/src/configManager/configManager.ts b/src/configManager/configManager.ts index 9ead5fb9..01f9843d 100644 --- a/src/configManager/configManager.ts +++ b/src/configManager/configManager.ts @@ -1,15 +1,18 @@ -import { DeepSignal, deepSignal } from "deepsignal"; +import { DeepSignal } from "deepsignal"; import { IConfig, IInitData } from "../types/types"; import { getDefaultConfig, getUserInitData } from "./config.default"; import { handleInitData } from "./handleUserConfig"; -import { has as lodashHas, set as lodashSet, get as lodashGet } from "lodash-es"; +import { + has as lodashHas, + set as lodashSet, + get as lodashGet, +} from "lodash-es"; class Config { - static config: DeepSignal<{ state: IConfig | {}; }> = { - state : getDefaultConfig() + state: getDefaultConfig(), }; static replace(userInput: Partial = getUserInitData()): void { @@ -19,13 +22,12 @@ class Config { static set(key: string, value: any): void { if (!lodashHas(this.config.state, key)) { throw new Error(`Invalid key: ${key}`); - } + } lodashSet(this.config.state, key, value); - } - + static get(key?: string): DeepSignal> { - if(key === undefined) { + if (key === undefined) { return this.config.state; } return lodashGet(this.config.state, key); @@ -73,13 +75,14 @@ export function updateConfigFromUrl(): void { export function setConfigFromParams( params: ConstructorParameters[0] = {} ): void { - const urlParams = new URLSearchParams(params); const live_preview = urlParams.get("live_preview"); const content_type_uid = urlParams.get("content_type_uid"); const entry_uid = urlParams.get("entry_uid"); - const stackSdkLivePreview = Config.get("stackSdk.live_preview") as { [key: string]: any } & Partial;; + const stackSdkLivePreview = Config.get("stackSdk.live_preview") as { + [key: string]: any; + } & Partial; if (live_preview) { Config.set("hash", live_preview); @@ -98,5 +101,4 @@ export function setConfigFromParams( } Config.set("stackSdk.live_preview", stackSdkLivePreview); - } diff --git a/src/configManager/handleUserConfig.ts b/src/configManager/handleUserConfig.ts index 7c6518ce..ff4c65e3 100644 --- a/src/configManager/handleUserConfig.ts +++ b/src/configManager/handleUserConfig.ts @@ -1,7 +1,5 @@ -import { DeepSignal } from "deepsignal"; import { IClientUrlParams, - IConfig, IInitData, ILivePreviewModeConfig, IStackSdk, @@ -38,10 +36,10 @@ const handleClientUrlParams = (userConfig: Partial): void => { // build url let host = Config.get("clientUrlParams.host") as unknown as string; - let protocol = Config.get( + const protocol = Config.get( "clientUrlParams.protocol" ) as unknown as string; - let port = Config.get("clientUrlParams.port") as unknown as + const port = Config.get("clientUrlParams.port") as unknown as | string | number; @@ -57,22 +55,19 @@ const handleClientUrlParams = (userConfig: Partial): void => { export const handleInitData = (initData: Partial): void => { const stackSdk: IStackSdk = - initData.stackSdk || - (Config.get("stackSdk") as unknown as IStackSdk); + initData.stackSdk || (Config.get("stackSdk") as unknown as IStackSdk); Config.set( "enable", - initData.enable ?? - stackSdk.live_preview?.enable ?? - Config.get("enable") + initData.enable ?? stackSdk.live_preview?.enable ?? Config.get("enable") ); Config.set( "ssr", stackSdk.live_preview?.ssr ?? - initData.ssr ?? - (typeof initData.stackSdk === "object" ? false : true) ?? - true + initData.ssr ?? + (typeof initData.stackSdk === "object" ? false : true) ?? + true ); Config.set( @@ -81,11 +76,8 @@ export const handleInitData = (initData: Partial): void => { stackSdk.live_preview?.runScriptsOnUpdate ?? Config.get("runScriptsOnUpdate") ); - - Config.set( - "stackSdk", - initData.stackSdk ?? Config.get("stackSdk") - ); + + Config.set("stackSdk", initData.stackSdk ?? Config.get("stackSdk")); Config.set( "cleanCslpOnProduction", @@ -152,9 +144,7 @@ export const handleInitData = (initData: Partial): void => { Config.set( "debug", - initData.debug ?? - stackSdk.live_preview?.debug ?? - Config.get("debug") + initData.debug ?? stackSdk.live_preview?.debug ?? Config.get("debug") ); handleStackDetails(initData, stackSdk); diff --git a/src/cslp/cslpdata.ts b/src/cslp/cslpdata.ts index 3f87d640..6a503725 100644 --- a/src/cslp/cslpdata.ts +++ b/src/cslp/cslpdata.ts @@ -119,7 +119,6 @@ export function addCslpOutline( highlightedElement: HTMLElement; }) => void ): void { - const elements = Config.get("elements") as unknown as { highlightedElement: HTMLElement | null; }; @@ -136,9 +135,7 @@ export function addCslpOutline( if (trigger && cslpTag) { if (elements.highlightedElement) - elements.highlightedElement.classList.remove( - "cslp-edit-mode" - ); + elements.highlightedElement.classList.remove("cslp-edit-mode"); element.classList.add("cslp-edit-mode"); const updatedElements = elements; diff --git a/src/liveEditor/__test__/visualEditorHover.test.ts b/src/liveEditor/__test__/visualEditorHover.test.ts index e2024fdd..a0cb5e25 100644 --- a/src/liveEditor/__test__/visualEditorHover.test.ts +++ b/src/liveEditor/__test__/visualEditorHover.test.ts @@ -217,7 +217,6 @@ describe("When an element is hovered in visual editor mode", () => { }); }); - describe("single line field", () => { let singleLineField: HTMLParagraphElement; let visualEditor: VisualEditor; diff --git a/src/liveEditor/components/__tests__/multipleFieldToolbar.test.tsx b/src/liveEditor/components/__tests__/multipleFieldToolbar.test.tsx index f6532fa1..39ca31c4 100644 --- a/src/liveEditor/components/__tests__/multipleFieldToolbar.test.tsx +++ b/src/liveEditor/components/__tests__/multipleFieldToolbar.test.tsx @@ -1,10 +1,5 @@ import "@testing-library/jest-dom/extend-expect"; -import { - render, - cleanup, - fireEvent, - getByTestId, -} from "@testing-library/preact"; +import { render, cleanup, fireEvent } from "@testing-library/preact"; import MultipleFieldToolbarComponent from "../multipleFieldToolbar"; import { diff --git a/src/liveEditor/components/__tests__/startEditingButton.test.tsx b/src/liveEditor/components/__tests__/startEditingButton.test.tsx index 5ce42d2d..52c86410 100644 --- a/src/liveEditor/components/__tests__/startEditingButton.test.tsx +++ b/src/liveEditor/components/__tests__/startEditingButton.test.tsx @@ -1,15 +1,12 @@ import "@testing-library/jest-dom/extend-expect"; import { render, fireEvent } from "@testing-library/preact"; import StartEditingButtonComponent from "../startEditingButton"; -import { IConfig } from "../../../types/types"; -import { DeepSignal } from "deepsignal"; import Config from "../../../configManager/configManager"; describe("StartEditingButtonComponent", () => { let visualEditorContainer: HTMLDivElement; beforeEach(() => { - Config.reset(); Config.set("stackDetails.apiKey", "bltapikey"); Config.set("stackDetails.environment", "bltenvironment"); diff --git a/src/liveEditor/index.ts b/src/liveEditor/index.ts index db9203e0..1069afe5 100644 --- a/src/liveEditor/index.ts +++ b/src/liveEditor/index.ts @@ -77,7 +77,11 @@ export class VisualEditor { ".visual-editor__focused-toolbar" ); - if (!Config.get("enable") || Config.get("mode") as unknown as number < ILivePreviewModeConfig.EDITOR) { + if ( + !Config.get("enable") || + (Config.get("mode") as unknown as number) < + ILivePreviewModeConfig.EDITOR + ) { return; } diff --git a/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts b/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts index 3675fb91..018c4ef2 100644 --- a/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts +++ b/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts @@ -8,7 +8,9 @@ import { IClientUrlParams, IStackDetails } from "../../types/types"; */ export default function getLiveEditorRedirectionUrl(): URL { const stackDetails = Config.get("stackDetails") as unknown as IStackDetails; - const clientUrlParams = Config.get("clientUrlParams") as unknown as IClientUrlParams; + const clientUrlParams = Config.get( + "clientUrlParams" + ) as unknown as IClientUrlParams; const { branch, apiKey, environment, locale } = stackDetails; const { url: appUrl } = clientUrlParams; @@ -36,6 +38,6 @@ export default function getLiveEditorRedirectionUrl(): URL { } else if (locale) { completeURL.searchParams.set("locale", locale); } - + return completeURL; } diff --git a/src/liveEditor/utils/isFieldDisabled.ts b/src/liveEditor/utils/isFieldDisabled.ts index 343167f7..c7244f59 100644 --- a/src/liveEditor/utils/isFieldDisabled.ts +++ b/src/liveEditor/utils/isFieldDisabled.ts @@ -6,7 +6,9 @@ export const isFieldDisabled = ( fieldSchemaMap: ISchemaFieldMap, eventDetails: VisualEditorCslpEventDetails ): any => { - const masterLocale = Config.get("stackDetails.masterLocale") as unknown as string || "en-us"; + const masterLocale = + (Config.get("stackDetails.masterLocale") as unknown as string) || + "en-us"; const updateRestrictDueToRole = Boolean( fieldSchemaMap?.field_metadata?.updateRestrict ); diff --git a/src/livePreview/__test__/live-preview.test.ts b/src/livePreview/__test__/live-preview.test.ts index 3fb9dc1c..6d8b0038 100644 --- a/src/livePreview/__test__/live-preview.test.ts +++ b/src/livePreview/__test__/live-preview.test.ts @@ -1,14 +1,9 @@ import crypto from "crypto"; -import { - convertObjectToMinifiedString, - sendPostmessageToWindow, - sleep, -} from "../../__test__/utils"; +import { sendPostmessageToWindow, sleep } from "../../__test__/utils"; import { getDefaultConfig } from "../../configManager/config.default"; import Config from "../../configManager/configManager"; -import * as LiveEditorModule from "../../liveEditor"; import { PublicLogger } from "../../logger/logger"; -import { IInitData, ILivePreviewWindowType } from "../../types/types"; +import { ILivePreviewWindowType } from "../../types/types"; import livePreviewPostMessage from "../eventManager/livePreviewEventManager"; import LivePreview from "../live-preview"; import { LIVE_PREVIEW_POST_MESSAGE_EVENTS } from "../eventManager/livePreviewEventManager.constant"; diff --git a/src/livePreview/editButton/editButton.ts b/src/livePreview/editButton/editButton.ts index 87b74224..6a2c5c3f 100644 --- a/src/livePreview/editButton/editButton.ts +++ b/src/livePreview/editButton/editButton.ts @@ -424,9 +424,10 @@ export class LivePreviewEditButton { entry_uid: string, preview_field: string ): string { - const stackDetails = Config.get("stackDetails") as IStackDetails; - const clientUrlParams = Config.get("clientUrlParams") as IClientUrlParams; + const clientUrlParams = Config.get( + "clientUrlParams" + ) as IClientUrlParams; if (!stackDetails.apiKey) { throw `To use edit tags, you must provide the stack API key. Specify the API key while initializing the Live Preview SDK. diff --git a/src/livePreview/eventManager/postMessageEvent.hooks.ts b/src/livePreview/eventManager/postMessageEvent.hooks.ts index 86089f8a..6a683905 100644 --- a/src/livePreview/eventManager/postMessageEvent.hooks.ts +++ b/src/livePreview/eventManager/postMessageEvent.hooks.ts @@ -46,7 +46,6 @@ export function useOnEntryUpdatePostMessageEvent(): void { livePreviewPostMessage?.on( LIVE_PREVIEW_POST_MESSAGE_EVENTS.ON_CHANGE, (event) => { - setConfigFromParams({ live_preview: event.data.hash, }); @@ -60,7 +59,6 @@ export function useOnEntryUpdatePostMessageEvent(): void { } export function sendInitializeLivePreviewPostMessageEvent(): void { - livePreviewPostMessage ?.send( LIVE_PREVIEW_POST_MESSAGE_EVENTS.INIT, diff --git a/src/livePreview/live-preview.ts b/src/livePreview/live-preview.ts index 35c1a443..fe4e5895 100644 --- a/src/livePreview/live-preview.ts +++ b/src/livePreview/live-preview.ts @@ -21,7 +21,6 @@ export default class LivePreview { private subscribers: OnEntryChangeCallbackSubscribers = {}; constructor() { - this.requestDataSync = this.requestDataSync.bind(this); this.subscribeToOnEntryChange = this.subscribeToOnEntryChange.bind(this); @@ -53,7 +52,8 @@ export default class LivePreview { if ( Config.get("editButton.enable") || - Config.get("mode") as unknown as number >= ILivePreviewModeConfig.EDITOR + (Config.get("mode") as unknown as number) >= + ILivePreviewModeConfig.EDITOR ) { new LivePreviewEditButton(); } @@ -97,7 +97,7 @@ export default class LivePreview { const config = Config.get(); Config.set("onChange", this.publish); - + //! TODO: we replaced the handleOnChange() with this. //! I don't think we need this. Confirm and remove it. config.onChange!(); From 79323ed40f320ac55e53df03f2c07ddec19c0d0b Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Mon, 11 Mar 2024 18:18:08 +0530 Subject: [PATCH 08/10] fix : revert Config.get method to return the entire object and update test cases accordingly --- .../__test__/configManager.test.ts | 54 +- .../__test__/handleUserConfig.test.ts | 694 +++++++++--------- src/configManager/config.default.ts | 11 +- src/configManager/configManager.ts | 27 +- src/configManager/handleUserConfig.ts | 81 +- src/cslp/cslpdata.ts | 8 +- .../__test__/visualEditorHover.test.ts | 6 +- .../__tests__/startEditingButton.test.tsx | 5 +- src/liveEditor/index.ts | 12 +- .../utils/getLiveEditorRedirectionUrl.ts | 6 +- src/liveEditor/utils/isFieldDisabled.ts | 4 +- src/livePreview/editButton/editButton.ts | 22 +- .../eventManager/livePreviewEventManager.ts | 2 +- .../eventManager/postMessageEvent.hooks.ts | 11 +- src/livePreview/live-preview.ts | 19 +- .../contentstack-live-preview-HOC.test.ts | 12 +- src/preview/contentstack-live-preview-HOC.ts | 2 +- 17 files changed, 486 insertions(+), 490 deletions(-) diff --git a/src/configManager/__test__/configManager.test.ts b/src/configManager/__test__/configManager.test.ts index 26f2cd27..ef90b20b 100644 --- a/src/configManager/__test__/configManager.test.ts +++ b/src/configManager/__test__/configManager.test.ts @@ -1,37 +1,46 @@ import Config, { updateConfigFromUrl } from "../configManager"; import { getDefaultConfig } from "../config.default"; +import { DeepSignal } from "deepsignal"; +import { IConfig } from "../../types/types"; describe("Config", () => { + let config: DeepSignal; + beforeEach(() => { Config.reset(); + config = Config.get(); }); + afterAll(() => { Config.reset(); }); test("should return default value", () => { const defaultConfig = getDefaultConfig(); - const receivedConfig = Config.get(); + const receivedConfig = config; - //@ts-expect-error + // @ts-expect-error delete defaultConfig.onChange; + // @ts-expect-error delete receivedConfig.onChange; - expect(Config.get()).toStrictEqual(defaultConfig); + expect(config).toStrictEqual(defaultConfig); }); test("should set and get value", () => { const defaultConfig = getDefaultConfig(); - let receivedConfig = Config.get(); + let receivedConfig = config; // @ts-expect-error delete defaultConfig.onChange; + // @ts-expect-error delete receivedConfig.onChange; expect(receivedConfig).toEqual({ ...defaultConfig, ssr: true }); Config.set("ssr", false); - receivedConfig = Config.get(); + receivedConfig = config; + // @ts-expect-error delete receivedConfig.onChange; expect(receivedConfig).toEqual({ ...defaultConfig, ssr: false }); @@ -45,10 +54,11 @@ describe("Config", () => { test("should replace config", () => { const defaultConfig = getDefaultConfig(); - let receivedConfig = Config.get(); + let receivedConfig = config; // @ts-expect-error delete defaultConfig.onChange; + // @ts-expect-error delete receivedConfig.onChange; expect(receivedConfig).toEqual(defaultConfig); @@ -62,8 +72,9 @@ describe("Config", () => { }, }); - receivedConfig = Config.get(); + receivedConfig = config; + // @ts-expect-error delete receivedConfig.onChange; expect(receivedConfig).toEqual({ @@ -80,8 +91,11 @@ describe("Config", () => { }); describe("update config from url", () => { + let config: DeepSignal; + beforeEach(() => { Config.reset(); + config = Config.get(); }); afterEach(() => { @@ -111,26 +125,28 @@ describe("update config from url", () => { }, }); - expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); - expect(Config.get("stackDetails.entryUid")).toEqual(""); - expect(Config.get("hash")).toEqual(""); + const config = Config.get(); + + expect(config.stackDetails.contentTypeUid).toEqual(""); + expect(config.stackDetails.entryUid).toEqual(""); + expect(config.hash).toEqual(""); updateConfigFromUrl(); - expect(Config.get("stackDetails.contentTypeUid")).toEqual("test"); - expect(Config.get("stackDetails.entryUid")).toEqual("test"); - expect(Config.get("hash")).toEqual("test"); + expect(config.stackDetails.contentTypeUid).toEqual("test"); + expect(config.stackDetails.entryUid).toEqual("test"); + expect(config.hash).toEqual("test"); }); it("should be default config if url params are not available", () => { - expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); - expect(Config.get("stackDetails.entryUid")).toEqual(""); - expect(Config.get("hash")).toEqual(""); + expect(config.stackDetails.contentTypeUid).toEqual(""); + expect(config.stackDetails.entryUid).toEqual(""); + expect(config.hash).toEqual(""); updateConfigFromUrl(); - expect(Config.get("stackDetails.contentTypeUid")).toEqual(""); - expect(Config.get("stackDetails.entryUid")).toEqual(""); - expect(Config.get("hash")).toEqual(""); + expect(config.stackDetails.contentTypeUid).toEqual(""); + expect(config.stackDetails.entryUid).toEqual(""); + expect(config.hash).toEqual(""); }); }); diff --git a/src/configManager/__test__/handleUserConfig.test.ts b/src/configManager/__test__/handleUserConfig.test.ts index f6fb613b..bce9fcd4 100644 --- a/src/configManager/__test__/handleUserConfig.test.ts +++ b/src/configManager/__test__/handleUserConfig.test.ts @@ -1,6 +1,7 @@ import { handleInitData, handleUserConfig } from "../handleUserConfig"; -import { IInitData, ILivePreviewModeConfig } from "../../types/types"; +import { IConfig, IInitData, ILivePreviewModeConfig } from "../../types/types"; import Config from "../configManager"; +import { DeepSignal } from "deepsignal"; // example Stack object @@ -36,350 +37,356 @@ import Config from "../configManager"; } */ -describe("handleInitData()", () => { - beforeEach(() => { - Config.reset(); - }); - - afterEach(() => { - Config.reset(); - }); - - test("must set data when config is provided", () => { - const initData: Partial = { - enable: true, - stackDetails: { - apiKey: "bltanything", - environment: "", - }, - }; - - handleInitData(initData); - const expectedOutput = { - ssr: true, - enable: true, - cleanCslpOnProduction: true, - stackDetails: { - apiKey: "bltanything", - environment: "", - contentTypeUid: "", - entryUid: "", - }, - clientUrlParams: { - protocol: "https", - host: "app.contentstack.com", - port: 443, - url: "https://app.contentstack.com:443", - }, - stackSdk: { - headers: { - api_key: "", - }, - environment: "", - }, - }; - - const config = Config.get(); - expect(config).toMatchObject(expectedOutput); - }); - - test("must set SSR: true is stack SDK is not provided", () => { - const initData: Partial = { - enable: true, - stackDetails: { - apiKey: "bltanything", - environment: "", - }, - }; - - handleInitData(initData); - expect(Config.get("ssr")).toBe(true); - }); - - test("must set SSR: true is stack SDK is not provided", () => { - const initData: Partial = { - enable: true, - stackDetails: { - apiKey: "bltanything", - environment: "", - }, - stackSdk: { - live_preview: { - enable: true, - }, - headers: { - api_key: "bltanything", - }, - environment: "", - cachePolicy: 1, - }, - }; - - handleInitData(initData); - expect(Config.get("ssr")).toBe(false); - }); - - describe("live mode", () => { - test("should be set to 1 by default", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData); - expect(Config.get("mode")).toBe(ILivePreviewModeConfig.PREVIEW); - }); - - test("should be set to 2 if user set it to editor", () => { - const initData: Partial = { - enable: true, - mode: "editor", - stackDetails: { - environment: "main", - apiKey: "bltanything", - }, - }; - - handleInitData(initData); - expect(Config.get("mode")).toBe(ILivePreviewModeConfig.EDITOR); - }); - - test("should be set to 1 if user set it to preview", () => { - const initData: Partial = { - enable: true, - mode: "preview", - }; - - handleInitData(initData); - expect(Config.get("mode")).toBe(ILivePreviewModeConfig.PREVIEW); - }); - - test("should throw an error if user set it to something else", () => { - const initData: Partial = { - enable: true, - // @ts-ignore - mode: "wrong-value", - }; - - expect(() => { - handleInitData(initData); - }).toThrowError( - "Live Preview SDK: The mode must be either 'editor' or 'preview'" - ); - }); - }); - - describe("stack details set by user", () => { - test("should prioritize api key from user config", () => { - const initData: Partial = { - enable: true, - stackDetails: { - apiKey: "bltuserapikey", - }, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.apiKey")).toBe("bltuserapikey"); - - initData.stackSdk = { - live_preview: {}, - headers: { - api_key: "bltheaderapikey", - }, - environment: "dev", - }; - - handleInitData(initData); - expect(Config.get("stackDetails.apiKey")).toBe("bltuserapikey"); - }); - - test("should set api key from headers if available", () => { - const initData: Partial = { - enable: true, - - stackSdk: { - live_preview: {}, - headers: { - api_key: "bltheaderapikey", - }, - environment: "dev", - }, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.apiKey")).toBe("bltheaderapikey"); - }); - - test("should reset api key if it is not passed", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.apiKey")).toBe(""); - }); - - test("should throw error if api key is not passed in editor mode", () => { - const initData: Partial = { - enable: true, - stackDetails: { - environment: "dev", - }, - mode: "editor", - }; - - expect(() => { - handleInitData(initData); - }).toThrowError("Live preview SDK: api key is required"); - }); - - test("should prioritize environment from user config", () => { - const initData: Partial = { - enable: true, - stackDetails: { - environment: "userenvironment", - }, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.environment")).toBe( - "userenvironment" - ); - - initData.stackSdk = { - live_preview: {}, - environment: "sdkenvironment", - headers: { - api_key: "", - }, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.environment")).toBe( - "userenvironment" - ); - }); - - test("should set environment from stack sdk if available", () => { - const initData: Partial = { - enable: true, - stackSdk: { - live_preview: {}, - environment: "sdkenvironment", - headers: { - api_key: "", - }, - }, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.environment")).toBe( - "sdkenvironment" - ); - }); - - test("should reset environment if it is not passed", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.environment")).toBe(""); - }); - - test("should throw error if environment is not passed in editor mode", () => { - const initData: Partial = { - enable: true, - stackDetails: { - apiKey: "bltapikey", - }, - mode: "editor", - }; - - expect(() => { - handleInitData(initData); - }).toThrowError("Live preview SDK: environment is required"); - }); - - test("should prioritize branch from user config", () => { - const initData: Partial = { - enable: true, - stackDetails: { - branch: "userbranch", - }, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.branch")).toBe("userbranch"); - - initData.stackSdk = { - live_preview: {}, - headers: { - api_key: "bltapikey", - branch: "sdkbranch", - }, - environment: "dev", - }; - - handleInitData(initData); - expect(Config.get("stackDetails.branch")).toBe("userbranch"); - }); - - test("should set branch from headers if available", () => { - const initData: Partial = { - enable: true, - - stackSdk: { - live_preview: {}, - headers: { - api_key: "sdkbranch", - branch: "sdkbranch", - }, - environment: "dev", - }, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.branch")).toBe("sdkbranch"); - }); - - test("should reset branch if it is not passed", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.branch")).toBe("main"); - }); - - test("should set locale from user config", () => { - const initData: Partial = { - enable: true, - stackDetails: { - locale: "userlocale", - }, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.locale")).toBe("userlocale"); - }); - - test("should set default locale if it is not passed", () => { - const initData: Partial = { - enable: true, - }; - - handleInitData(initData); - expect(Config.get("stackDetails.locale")).toBe("en-us"); - }); - }); -}); +// describe("handleInitData()", () => { + +// let config : DeepSignal; + +// beforeEach(() => { +// Config.reset(); +// config = Config.get(); +// }); + +// afterAll(() => { +// Config.reset(); +// }); + +// test("must set data when config is provided", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// apiKey: "bltanything", +// environment: "", +// }, +// }; + +// handleInitData(initData); +// const expectedOutput = { +// ssr: true, +// enable: true, +// cleanCslpOnProduction: true, +// stackDetails: { +// apiKey: "bltanything", +// environment: "", +// contentTypeUid: "", +// entryUid: "", +// }, +// clientUrlParams: { +// protocol: "https", +// host: "app.contentstack.com", +// port: 443, +// url: "https://app.contentstack.com:443", +// }, +// stackSdk: { +// headers: { +// api_key: "", +// }, +// environment: "", +// }, +// }; + +// expect(config).toMatchObject(expectedOutput); +// }); + +// test("must set SSR: true is stack SDK is not provided", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// apiKey: "bltanything", +// environment: "", +// }, +// }; + +// handleInitData(initData); +// expect(config.ssr).toBe(true); +// }); + +// test("must set SSR: true is stack SDK is not provided", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// apiKey: "bltanything", +// environment: "", +// }, +// stackSdk: { +// live_preview: { +// enable: true, +// }, +// headers: { +// api_key: "bltanything", +// }, +// environment: "", +// cachePolicy: 1, +// }, +// }; + +// handleInitData(initData); +// expect(config.ssr).toBe(false); +// }); + +// describe("live mode", () => { +// test("should be set to 1 by default", () => { +// const initData: Partial = { +// enable: true, +// }; + +// handleInitData(initData); +// expect(config.mode).toBe(ILivePreviewModeConfig.PREVIEW); +// }); + +// test("should be set to 2 if user set it to editor", () => { +// const initData: Partial = { +// enable: true, +// mode: "editor", +// stackDetails: { +// environment: "main", +// apiKey: "bltanything", +// }, +// }; + +// handleInitData(initData); +// expect(config.mode).toBe(ILivePreviewModeConfig.EDITOR); +// }); + +// test("should be set to 1 if user set it to preview", () => { +// const initData: Partial = { +// enable: true, +// mode: "preview", +// }; + +// handleInitData(initData); +// expect(config.mode).toBe(ILivePreviewModeConfig.PREVIEW); +// }); + +// test("should throw an error if user set it to something else", () => { +// const initData: Partial = { +// enable: true, +// // @ts-ignore +// mode: "wrong-value", +// }; + +// expect(() => { +// handleInitData(initData); +// }).toThrowError( +// "Live Preview SDK: The mode must be either 'editor' or 'preview'" +// ); +// }); +// }); + +// describe("stack details set by user", () => { +// test("should prioritize api key from user config", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// apiKey: "bltuserapikey", +// }, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.apiKey).toBe("bltuserapikey"); + +// initData.stackSdk = { +// live_preview: {}, +// headers: { +// api_key: "bltheaderapikey", +// }, +// environment: "dev", +// }; + +// handleInitData(initData); +// expect(config.stackDetails.apiKey).toBe("bltuserapikey"); +// }); + +// test("should set api key from headers if available", () => { +// const initData: Partial = { +// enable: true, + +// stackSdk: { +// live_preview: {}, +// headers: { +// api_key: "bltheaderapikey", +// }, +// environment: "dev", +// }, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.apiKey).toBe("bltheaderapikey"); +// }); + +// test("should reset api key if it is not passed", () => { +// const initData: Partial = { +// enable: true, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.apiKey).toBe(""); +// }); + +// test("should throw error if api key is not passed in editor mode", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// environment: "dev", +// }, +// mode: "editor", +// }; + +// expect(() => { +// handleInitData(initData); +// }).toThrowError("Live preview SDK: api key is required"); +// }); + +// test("should prioritize environment from user config", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// environment: "userenvironment", +// }, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.environment).toBe( +// "userenvironment" +// ); + +// initData.stackSdk = { +// live_preview: {}, +// environment: "sdkenvironment", +// headers: { +// api_key: "", +// }, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.environment).toBe( +// "userenvironment" +// ); +// }); + +// test("should set environment from stack sdk if available", () => { +// const initData: Partial = { +// enable: true, +// stackSdk: { +// live_preview: {}, +// environment: "sdkenvironment", +// headers: { +// api_key: "", +// }, +// }, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.environment).toBe( +// "sdkenvironment" +// ); +// }); + +// test("should reset environment if it is not passed", () => { +// const initData: Partial = { +// enable: true, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.environment).toBe(""); +// }); + +// test("should throw error if environment is not passed in editor mode", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// apiKey: "bltapikey", +// }, +// mode: "editor", +// }; + +// expect(() => { +// handleInitData(initData); +// }).toThrowError("Live preview SDK: environment is required"); +// }); + +// test("should prioritize branch from user config", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// branch: "userbranch", +// }, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.branch).toBe("userbranch"); + +// initData.stackSdk = { +// live_preview: {}, +// headers: { +// api_key: "bltapikey", +// branch: "sdkbranch", +// }, +// environment: "dev", +// }; + +// handleInitData(initData); +// expect(config.stackDetails.branch).toBe("userbranch"); +// }); + +// test("should set branch from headers if available", () => { +// const initData: Partial = { +// enable: true, + +// stackSdk: { +// live_preview: {}, +// headers: { +// api_key: "sdkbranch", +// branch: "sdkbranch", +// }, +// environment: "dev", +// }, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.branch).toBe("sdkbranch"); +// }); + +// test("should reset branch if it is not passed", () => { +// const initData: Partial = { +// enable: true, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.branch).toBe("main"); +// }); + +// test("should set locale from user config", () => { +// const initData: Partial = { +// enable: true, +// stackDetails: { +// locale: "userlocale", +// }, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.locale).toBe("userlocale"); +// }); + +// test("should set default locale if it is not passed", () => { +// const initData: Partial = { +// enable: true, +// }; + +// handleInitData(initData); +// expect(config.stackDetails.locale).toBe("en-us"); +// }); +// }); +// }); describe("handleClientUrlParams()", () => { + let config: DeepSignal; + beforeEach(() => { Config.reset(); + config = Config.get(); }); - afterEach(() => { + afterAll(() => { Config.reset(); }); @@ -395,9 +402,8 @@ describe("handleClientUrlParams()", () => { port: 80, url: "http://example.com:80", }; - expect(Config.get("clientUrlParams")).toMatchObject( - expectedOutputForHttp - ); + + expect(config.clientUrlParams).toMatchObject(expectedOutputForHttp); handleUserConfig.clientUrlParams({ host: "example.com/", @@ -410,8 +416,6 @@ describe("handleClientUrlParams()", () => { port: 443, url: "https://example.com:443", }; - expect(Config.get("clientUrlParams")).toMatchObject( - expectedOutputForHttps - ); + expect(config.clientUrlParams).toMatchObject(expectedOutputForHttps); }); }); diff --git a/src/configManager/config.default.ts b/src/configManager/config.default.ts index 4178ed38..c9e38c3c 100644 --- a/src/configManager/config.default.ts +++ b/src/configManager/config.default.ts @@ -1,9 +1,4 @@ -import { - IConfig, - IInitData, - ILivePreviewModeConfig, - ILivePreviewWindowType, -} from "../types/types"; +import { IConfig, IInitData, ILivePreviewWindowType } from "../types/types"; export function getUserInitData(): IInitData { return { @@ -55,8 +50,8 @@ export function getDefaultConfig(): IConfig { includeByQueryParameter: true, }, - hash: "" as string, - mode: 1 as ILivePreviewModeConfig, + hash: "", + mode: 1, windowType: ILivePreviewWindowType.INDEPENDENT, stackDetails: { diff --git a/src/configManager/configManager.ts b/src/configManager/configManager.ts index 01f9843d..fdd123bf 100644 --- a/src/configManager/configManager.ts +++ b/src/configManager/configManager.ts @@ -1,18 +1,14 @@ -import { DeepSignal } from "deepsignal"; +import { DeepSignal, deepSignal } from "deepsignal"; import { IConfig, IInitData } from "../types/types"; import { getDefaultConfig, getUserInitData } from "./config.default"; import { handleInitData } from "./handleUserConfig"; -import { - has as lodashHas, - set as lodashSet, - get as lodashGet, -} from "lodash-es"; +import { has as lodashHas, set as lodashSet } from "lodash-es"; class Config { - static config: DeepSignal<{ - state: IConfig | {}; - }> = { - state: getDefaultConfig(), + static config: { + state: DeepSignal; + } = { + state: deepSignal(getDefaultConfig()), }; static replace(userInput: Partial = getUserInitData()): void { @@ -26,11 +22,8 @@ class Config { lodashSet(this.config.state, key, value); } - static get(key?: string): DeepSignal> { - if (key === undefined) { - return this.config.state; - } - return lodashGet(this.config.state, key); + static get(): DeepSignal { + return this.config.state; } static reset(): void { @@ -80,9 +73,7 @@ export function setConfigFromParams( const content_type_uid = urlParams.get("content_type_uid"); const entry_uid = urlParams.get("entry_uid"); - const stackSdkLivePreview = Config.get("stackSdk.live_preview") as { - [key: string]: any; - } & Partial; + const stackSdkLivePreview = Config.get().stackSdk.live_preview; if (live_preview) { Config.set("hash", live_preview); diff --git a/src/configManager/handleUserConfig.ts b/src/configManager/handleUserConfig.ts index ff4c65e3..0af3d13a 100644 --- a/src/configManager/handleUserConfig.ts +++ b/src/configManager/handleUserConfig.ts @@ -7,19 +7,19 @@ import { import Config from "./configManager"; const handleClientUrlParams = (userConfig: Partial): void => { + const config = Config.get(); + const clientUrlParams = config.clientUrlParams; + Config.set( "clientUrlParams.host", - userConfig.host ?? Config.get("clientUrlParams.host") + userConfig.host ?? config.clientUrlParams.host ); Config.set( "clientUrlParams.protocol", - userConfig.protocol ?? Config.get("clientUrlParams.protocol") - ); - Config.set( - "clientUrlParams.port", - userConfig.port ?? Config.get("clientUrlParams.port") + userConfig.protocol ?? clientUrlParams.protocol ); + Config.set("clientUrlParams.port", userConfig.port ?? clientUrlParams.port); if (userConfig.protocol !== undefined && userConfig.port === undefined) { switch (userConfig.protocol) { @@ -34,32 +34,28 @@ const handleClientUrlParams = (userConfig: Partial): void => { } } + let host = config.clientUrlParams.host; + // build url - let host = Config.get("clientUrlParams.host") as unknown as string; - const protocol = Config.get( - "clientUrlParams.protocol" - ) as unknown as string; - const port = Config.get("clientUrlParams.port") as unknown as - | string - | number; - - if (host.endsWith("/")) { + if (typeof host == "string" && host.endsWith("/")) { host = host.slice(0, -1); Config.set("clientUrlParams.host", host); } - Config.set("clientUrlParams.url", `${protocol}://${host}:${port}`); + const url = `${clientUrlParams.protocol}://${config.clientUrlParams.host}:${clientUrlParams.port}`; + + Config.set("clientUrlParams.url", url); }; // TODO: add documentation mentioning that you cannot pass stack sdk in the init data export const handleInitData = (initData: Partial): void => { - const stackSdk: IStackSdk = - initData.stackSdk || (Config.get("stackSdk") as unknown as IStackSdk); + const config = Config.get(); + const stackSdk = initData.stackSdk || config.stackSdk; Config.set( "enable", - initData.enable ?? stackSdk.live_preview?.enable ?? Config.get("enable") + initData.enable ?? stackSdk.live_preview?.enable ?? config.enable ); Config.set( @@ -74,23 +70,23 @@ export const handleInitData = (initData: Partial): void => { "runScriptsOnUpdate", initData.runScriptsOnUpdate ?? stackSdk.live_preview?.runScriptsOnUpdate ?? - Config.get("runScriptsOnUpdate") + config.runScriptsOnUpdate ); - Config.set("stackSdk", initData.stackSdk ?? Config.get("stackSdk")); + Config.set("stackSdk", initData.stackSdk ?? config.stackSdk); Config.set( "cleanCslpOnProduction", initData.cleanCslpOnProduction ?? stackSdk.live_preview?.cleanCslpOnProduction ?? - Config.get("cleanCslpOnProduction") + config.cleanCslpOnProduction ); Config.set("editButton", { enable: initData.editButton?.enable ?? stackSdk.live_preview?.editButton?.enable ?? - Config.get("editButton.enable"), + config.editButton.enable, // added extra check if exclude data passed by user is array or not exclude: Array.isArray(initData.editButton?.exclude) && @@ -99,31 +95,27 @@ export const handleInitData = (initData: Partial): void => { : Array.isArray(stackSdk.live_preview?.exclude) && stackSdk.live_preview?.exclude ? stackSdk.live_preview?.exclude - : Config.get("editButton.exclude") ?? [], + : config.editButton.exclude ?? [], position: initData.editButton?.position ?? stackSdk.live_preview?.position ?? - Config.get("editButton.position") ?? + config.editButton.position ?? "top", includeByQueryParameter: initData.editButton?.includeByQueryParameter ?? stackSdk.live_preview?.includeByQueryParameter ?? - Config.get("editButton.includeByQueryParameter") ?? + config.editButton.includeByQueryParameter ?? true, }); // client URL params handleClientUrlParams( - (initData.clientUrlParams as - | Partial> - | undefined) ?? - (stackSdk.live_preview?.clientUrlParams as IClientUrlParams) ?? - (Config.get("clientUrlParams") as unknown as IClientUrlParams) + initData.clientUrlParams ?? + stackSdk.live_preview?.clientUrlParams ?? + config.clientUrlParams ); - // Partial>; || IClientUrlParams || - if (initData.mode) { switch (initData.mode) { case "preview": { @@ -144,51 +136,50 @@ export const handleInitData = (initData: Partial): void => { Config.set( "debug", - initData.debug ?? stackSdk.live_preview?.debug ?? Config.get("debug") + initData.debug ?? stackSdk.live_preview?.debug ?? config.debug ); - handleStackDetails(initData, stackSdk); + handleStackDetails(initData, stackSdk as IStackSdk); }; function handleStackDetails( initData: Partial, stackSdk: Partial ): void { + const config = Config.get(); + Config.set( "stackDetails.apiKey", initData.stackDetails?.apiKey ?? stackSdk.headers?.api_key ?? - Config.get("stackDetails.apiKey") + config.stackDetails.apiKey ); Config.set( "stackDetails.environment", initData.stackDetails?.environment ?? stackSdk.environment ?? - Config.get("stackDetails.environment") + config.stackDetails.environment ); Config.set( "stackDetails.branch", initData.stackDetails?.branch ?? stackSdk.headers?.branch ?? - Config.get("stackDetails.branch") + config.stackDetails.branch ); Config.set( "stackDetails.locale", - initData.stackDetails?.locale ?? Config.get("stackDetails.locale") + initData.stackDetails?.locale ?? config.stackDetails.locale ); - if ( - (Config.get("mode") as unknown as number) >= - ILivePreviewModeConfig.EDITOR - ) { - if (!Config.get("stackDetails.environment")) { + if (config.mode >= ILivePreviewModeConfig.EDITOR) { + if (!config.stackDetails.environment) { throw Error("Live preview SDK: environment is required"); } - if (!Config.get("stackDetails.apiKey")) { + if (!config.stackDetails.apiKey) { throw Error("Live preview SDK: api key is required"); } } diff --git a/src/cslp/cslpdata.ts b/src/cslp/cslpdata.ts index 6a503725..8859dec2 100644 --- a/src/cslp/cslpdata.ts +++ b/src/cslp/cslpdata.ts @@ -5,6 +5,7 @@ import { CslpDataParentDetails, } from "./types/cslp.types"; import Config from "../configManager/configManager"; +import { DeepSignal } from "deepsignal"; /** * Extracts details from a CSLP value string. @@ -119,9 +120,7 @@ export function addCslpOutline( highlightedElement: HTMLElement; }) => void ): void { - const elements = Config.get("elements") as unknown as { - highlightedElement: HTMLElement | null; - }; + const elements = Config.get().elements; let trigger = true; const eventTargets = e.composedPath(); @@ -139,7 +138,8 @@ export function addCslpOutline( element.classList.add("cslp-edit-mode"); const updatedElements = elements; - updatedElements.highlightedElement = element; + updatedElements.highlightedElement = + element as DeepSignal; Config.set("elements", updatedElements); callback?.({ diff --git a/src/liveEditor/__test__/visualEditorHover.test.ts b/src/liveEditor/__test__/visualEditorHover.test.ts index a0cb5e25..d89a9745 100644 --- a/src/liveEditor/__test__/visualEditorHover.test.ts +++ b/src/liveEditor/__test__/visualEditorHover.test.ts @@ -174,10 +174,14 @@ describe("When an element is hovered in visual editor mode", () => { }); afterEach(() => { - Config.reset(); jest.clearAllMocks(); document.getElementsByTagName("html")[0].innerHTML = ""; }); + + afterAll(() => { + Config.reset(); + }); + describe("title field", () => { let titleField: HTMLParagraphElement; let visualEditor: VisualEditor; diff --git a/src/liveEditor/components/__tests__/startEditingButton.test.tsx b/src/liveEditor/components/__tests__/startEditingButton.test.tsx index 52c86410..77a0f3da 100644 --- a/src/liveEditor/components/__tests__/startEditingButton.test.tsx +++ b/src/liveEditor/components/__tests__/startEditingButton.test.tsx @@ -16,11 +16,14 @@ describe("StartEditingButtonComponent", () => { }); afterEach(() => { - Config.reset(); jest.clearAllMocks(); document.body.removeChild(visualEditorContainer); }); + afterAll(() => { + Config.reset(); + }); + it("renders correctly with EditIcon and Start Editing text", () => { const { getByText, getByTestId } = render( diff --git a/src/liveEditor/index.ts b/src/liveEditor/index.ts index 1069afe5..b4ba2131 100644 --- a/src/liveEditor/index.ts +++ b/src/liveEditor/index.ts @@ -77,17 +77,15 @@ export class VisualEditor { ".visual-editor__focused-toolbar" ); - if ( - !Config.get("enable") || - (Config.get("mode") as unknown as number) < - ILivePreviewModeConfig.EDITOR - ) { + const config = Config.get(); + + if (!config.enable || config.mode < ILivePreviewModeConfig.EDITOR) { return; } liveEditorPostMessage ?.send("init", { - isSSR: Config.get("ssr"), + isSSR: config.ssr, }) .then((data) => { const { @@ -120,7 +118,7 @@ export class VisualEditor { useHistoryPostMessageEvent(); useOnEntryUpdatePostMessageEvent(); }) - .catch((e) => { + .catch(() => { if (!inIframe()) { generateStartEditingButton(this.visualEditorContainer); } diff --git a/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts b/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts index 018c4ef2..57299f12 100644 --- a/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts +++ b/src/liveEditor/utils/getLiveEditorRedirectionUrl.ts @@ -1,16 +1,12 @@ import Config from "../../configManager/configManager"; import { extractDetailsFromCslp } from "../../cslp"; -import { IClientUrlParams, IStackDetails } from "../../types/types"; /** * Returns the redirection URL for the Live Editor. * @returns {URL} The redirection URL. */ export default function getLiveEditorRedirectionUrl(): URL { - const stackDetails = Config.get("stackDetails") as unknown as IStackDetails; - const clientUrlParams = Config.get( - "clientUrlParams" - ) as unknown as IClientUrlParams; + const { stackDetails, clientUrlParams } = Config.get(); const { branch, apiKey, environment, locale } = stackDetails; const { url: appUrl } = clientUrlParams; diff --git a/src/liveEditor/utils/isFieldDisabled.ts b/src/liveEditor/utils/isFieldDisabled.ts index c7244f59..22fe7e0b 100644 --- a/src/liveEditor/utils/isFieldDisabled.ts +++ b/src/liveEditor/utils/isFieldDisabled.ts @@ -6,9 +6,7 @@ export const isFieldDisabled = ( fieldSchemaMap: ISchemaFieldMap, eventDetails: VisualEditorCslpEventDetails ): any => { - const masterLocale = - (Config.get("stackDetails.masterLocale") as unknown as string) || - "en-us"; + const masterLocale = Config.get().stackDetails.masterLocale || "en-us"; const updateRestrictDueToRole = Boolean( fieldSchemaMap?.field_metadata?.updateRestrict ); diff --git a/src/livePreview/editButton/editButton.ts b/src/livePreview/editButton/editButton.ts index 6a2c5c3f..e4ab071c 100644 --- a/src/livePreview/editButton/editButton.ts +++ b/src/livePreview/editButton/editButton.ts @@ -269,7 +269,7 @@ export class LivePreviewEditButton { private createCslpTooltip(): boolean { if ( !document.getElementById("cslp-tooltip") && - Config.get("editButton.enable") + Config.get().editButton.enable ) { const tooltip = document.createElement("button"); this.tooltip = tooltip; @@ -297,9 +297,7 @@ export class LivePreviewEditButton { } private updateTooltipPosition() { - const elements = Config.get("elements") as { - highlightedElement: HTMLElement | null; - }; + const { elements, editButton } = Config.get(); if (!elements.highlightedElement || !this.tooltip) return false; @@ -310,8 +308,8 @@ export class LivePreviewEditButton { if (currentRectOfElement && currentRectOfParentOfElement) { const editButtonPosition = getEditButtonPosition( - elements.highlightedElement, - Config.get("editButton.position") as string + elements.highlightedElement as HTMLElement, + editButton.position as unknown as string ); let upperBoundOfTooltip = editButtonPosition.upperBoundOfTooltip; @@ -350,6 +348,7 @@ export class LivePreviewEditButton { } private addEditStyleOnHover(e: MouseEvent) { + const { windowType, editButton } = Config.get(); const updateTooltipPosition: Parameters["1"] = ({ cslpTag, highlightedElement, @@ -363,14 +362,10 @@ export class LivePreviewEditButton { } }; - const windowType = Config.get( - "windowType" - ) as unknown as ILivePreviewWindowType; - if ( (windowType === ILivePreviewWindowType.PREVIEW || windowType === ILivePreviewWindowType.INDEPENDENT) && - Config.get("editButton.enable") + editButton.enable ) { addCslpOutline(e, updateTooltipPosition); } @@ -424,10 +419,7 @@ export class LivePreviewEditButton { entry_uid: string, preview_field: string ): string { - const stackDetails = Config.get("stackDetails") as IStackDetails; - const clientUrlParams = Config.get( - "clientUrlParams" - ) as IClientUrlParams; + const { stackDetails, clientUrlParams } = Config.get(); if (!stackDetails.apiKey) { throw `To use edit tags, you must provide the stack API key. Specify the API key while initializing the Live Preview SDK. diff --git a/src/livePreview/eventManager/livePreviewEventManager.ts b/src/livePreview/eventManager/livePreviewEventManager.ts index c832cbfc..fbd5693a 100644 --- a/src/livePreview/eventManager/livePreviewEventManager.ts +++ b/src/livePreview/eventManager/livePreviewEventManager.ts @@ -6,7 +6,7 @@ let livePreviewPostMessage: EventManager | undefined; if (typeof window !== "undefined") { livePreviewPostMessage = new EventManager(LIVE_PREVIEW_CHANNEL_ID, { target: window.parent, - debug: true, + debug: false, suppressErrors: true, }); } diff --git a/src/livePreview/eventManager/postMessageEvent.hooks.ts b/src/livePreview/eventManager/postMessageEvent.hooks.ts index 6a683905..a8044ca1 100644 --- a/src/livePreview/eventManager/postMessageEvent.hooks.ts +++ b/src/livePreview/eventManager/postMessageEvent.hooks.ts @@ -49,10 +49,9 @@ export function useOnEntryUpdatePostMessageEvent(): void { setConfigFromParams({ live_preview: event.data.hash, }); - - if (!Config.get("ssr")) { - const config = Config.get(); - config.onChange!(); + const { ssr, onChange } = Config.get(); + if (!ssr) { + onChange!(); } } ); @@ -64,7 +63,7 @@ export function sendInitializeLivePreviewPostMessageEvent(): void { LIVE_PREVIEW_POST_MESSAGE_EVENTS.INIT, { config: { - shouldReload: Config.get("ssr"), + shouldReload: Config.get().ssr, href: window.location.href, sdkVersion: packageJson.version, }, @@ -92,7 +91,7 @@ export function sendInitializeLivePreviewPostMessageEvent(): void { Config.set("windowType", windowType); // set timeout for client side (use to show warning: You are not editing this page) - if (!Config.get("ssr")) { + if (!Config.get().ssr) { setInterval(() => { sendCurrentPageUrlPostMessageEvent(); }, 1500); diff --git a/src/livePreview/live-preview.ts b/src/livePreview/live-preview.ts index fe4e5895..55ce74e6 100644 --- a/src/livePreview/live-preview.ts +++ b/src/livePreview/live-preview.ts @@ -1,6 +1,6 @@ import Config from "../configManager/configManager"; import { PublicLogger } from "../logger/logger"; -import { ILivePreviewModeConfig } from "../types/types"; +import { IConfig, ILivePreviewModeConfig } from "../types/types"; import { addLivePreviewQueryTags } from "../utils"; import { LivePreviewEditButton } from "./editButton/editButton"; import { sendInitializeLivePreviewPostMessageEvent } from "./eventManager/postMessageEvent.hooks"; @@ -28,14 +28,16 @@ export default class LivePreview { this.unsubscribeOnEntryChange = this.unsubscribeOnEntryChange.bind(this); - if (Config.get("debug")) { + const config = Config.get(); + + if (config.debug) { PublicLogger.debug( "Contentstack Live Preview Debugging mode: config --", Config.config ); } - if (Config.get("enable")) { + if (config.enable) { if ( typeof document !== undefined && document.readyState === "complete" @@ -51,15 +53,14 @@ export default class LivePreview { // render the hover outline only when edit button enable if ( - Config.get("editButton.enable") || - (Config.get("mode") as unknown as number) >= - ILivePreviewModeConfig.EDITOR + config.editButton.enable || + config.mode >= ILivePreviewModeConfig.EDITOR ) { new LivePreviewEditButton(); } //NOTE - I think we are already handling the link click event here. Let's move it to a function. - if (Config.get("ssr")) { + if (config.ssr) { // NOTE: what are we doing here? window.addEventListener("load", (e) => { const allATags = document.querySelectorAll("a"); @@ -87,7 +88,7 @@ export default class LivePreview { } }); } - } else if (Config.get("cleanCslpOnProduction")) { + } else if (config.cleanCslpOnProduction) { removeDataCslp(); } } @@ -100,7 +101,7 @@ export default class LivePreview { //! TODO: we replaced the handleOnChange() with this. //! I don't think we need this. Confirm and remove it. - config.onChange!(); + config.onChange(); sendInitializeLivePreviewPostMessageEvent(); } diff --git a/src/preview/__test__/contentstack-live-preview-HOC.test.ts b/src/preview/__test__/contentstack-live-preview-HOC.test.ts index e3dcd3a4..e154a056 100644 --- a/src/preview/__test__/contentstack-live-preview-HOC.test.ts +++ b/src/preview/__test__/contentstack-live-preview-HOC.test.ts @@ -29,6 +29,8 @@ global.ResizeObserver = jest.fn().mockImplementation(() => ({ describe("Live Preview HOC init", () => { beforeEach(() => { + Config.reset(); + livePreviewPostMessage?.on( LIVE_PREVIEW_POST_MESSAGE_EVENTS.INIT, mockLivePreviewInitEventListener @@ -49,9 +51,11 @@ describe("Live Preview HOC init", () => { ContentstackLivePreview.previewConstructors = {}; livePreviewPostMessage?.destroy({ soft: true }); liveEditorPostMessage?.destroy({ soft: true }); + jest.clearAllMocks(); + }); + afterAll(() => { Config.reset(); - jest.clearAllMocks(); }); test("should initialize only the live preview ", async () => { @@ -122,6 +126,8 @@ describe("Live Preview HOC init", () => { describe("Live Preview HOC config", () => { beforeEach(() => { + Config.reset(); + livePreviewPostMessage?.on( LIVE_PREVIEW_POST_MESSAGE_EVENTS.INIT, mockLivePreviewInitEventListener @@ -142,9 +148,11 @@ describe("Live Preview HOC config", () => { ContentstackLivePreview.previewConstructors = {}; livePreviewPostMessage?.destroy({ soft: true }); liveEditorPostMessage?.destroy({ soft: true }); + jest.clearAllMocks(); + }); + afterAll(() => { Config.reset(); - jest.clearAllMocks(); }); test("should set user config", async () => { diff --git a/src/preview/contentstack-live-preview-HOC.ts b/src/preview/contentstack-live-preview-HOC.ts index d4a85f3a..bd23b55c 100644 --- a/src/preview/contentstack-live-preview-HOC.ts +++ b/src/preview/contentstack-live-preview-HOC.ts @@ -67,7 +67,7 @@ class ContentstackLivePreview { if (!ContentstackLivePreview.isInitialized()) { updateConfigFromUrl(); // check if we could extract from the URL } - return Config.get("hash") as unknown as string; + return Config.get().hash; } private static isInitialized(): boolean { From 64ee0a926895f7af3eb3592ac9e33c8d6bfe9184 Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Tue, 12 Mar 2024 10:33:14 +0530 Subject: [PATCH 09/10] chore: remove as unknown and re-added commented test cases --- .../__test__/handleUserConfig.test.ts | 680 +++++++++--------- src/livePreview/editButton/editButton.ts | 5 +- .../eventManager/postMessageEvent.hooks.ts | 2 +- 3 files changed, 345 insertions(+), 342 deletions(-) diff --git a/src/configManager/__test__/handleUserConfig.test.ts b/src/configManager/__test__/handleUserConfig.test.ts index bce9fcd4..6a07156f 100644 --- a/src/configManager/__test__/handleUserConfig.test.ts +++ b/src/configManager/__test__/handleUserConfig.test.ts @@ -37,346 +37,346 @@ import { DeepSignal } from "deepsignal"; } */ -// describe("handleInitData()", () => { - -// let config : DeepSignal; - -// beforeEach(() => { -// Config.reset(); -// config = Config.get(); -// }); - -// afterAll(() => { -// Config.reset(); -// }); - -// test("must set data when config is provided", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// apiKey: "bltanything", -// environment: "", -// }, -// }; - -// handleInitData(initData); -// const expectedOutput = { -// ssr: true, -// enable: true, -// cleanCslpOnProduction: true, -// stackDetails: { -// apiKey: "bltanything", -// environment: "", -// contentTypeUid: "", -// entryUid: "", -// }, -// clientUrlParams: { -// protocol: "https", -// host: "app.contentstack.com", -// port: 443, -// url: "https://app.contentstack.com:443", -// }, -// stackSdk: { -// headers: { -// api_key: "", -// }, -// environment: "", -// }, -// }; - -// expect(config).toMatchObject(expectedOutput); -// }); - -// test("must set SSR: true is stack SDK is not provided", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// apiKey: "bltanything", -// environment: "", -// }, -// }; - -// handleInitData(initData); -// expect(config.ssr).toBe(true); -// }); - -// test("must set SSR: true is stack SDK is not provided", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// apiKey: "bltanything", -// environment: "", -// }, -// stackSdk: { -// live_preview: { -// enable: true, -// }, -// headers: { -// api_key: "bltanything", -// }, -// environment: "", -// cachePolicy: 1, -// }, -// }; - -// handleInitData(initData); -// expect(config.ssr).toBe(false); -// }); - -// describe("live mode", () => { -// test("should be set to 1 by default", () => { -// const initData: Partial = { -// enable: true, -// }; - -// handleInitData(initData); -// expect(config.mode).toBe(ILivePreviewModeConfig.PREVIEW); -// }); - -// test("should be set to 2 if user set it to editor", () => { -// const initData: Partial = { -// enable: true, -// mode: "editor", -// stackDetails: { -// environment: "main", -// apiKey: "bltanything", -// }, -// }; - -// handleInitData(initData); -// expect(config.mode).toBe(ILivePreviewModeConfig.EDITOR); -// }); - -// test("should be set to 1 if user set it to preview", () => { -// const initData: Partial = { -// enable: true, -// mode: "preview", -// }; - -// handleInitData(initData); -// expect(config.mode).toBe(ILivePreviewModeConfig.PREVIEW); -// }); - -// test("should throw an error if user set it to something else", () => { -// const initData: Partial = { -// enable: true, -// // @ts-ignore -// mode: "wrong-value", -// }; - -// expect(() => { -// handleInitData(initData); -// }).toThrowError( -// "Live Preview SDK: The mode must be either 'editor' or 'preview'" -// ); -// }); -// }); - -// describe("stack details set by user", () => { -// test("should prioritize api key from user config", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// apiKey: "bltuserapikey", -// }, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.apiKey).toBe("bltuserapikey"); - -// initData.stackSdk = { -// live_preview: {}, -// headers: { -// api_key: "bltheaderapikey", -// }, -// environment: "dev", -// }; - -// handleInitData(initData); -// expect(config.stackDetails.apiKey).toBe("bltuserapikey"); -// }); - -// test("should set api key from headers if available", () => { -// const initData: Partial = { -// enable: true, - -// stackSdk: { -// live_preview: {}, -// headers: { -// api_key: "bltheaderapikey", -// }, -// environment: "dev", -// }, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.apiKey).toBe("bltheaderapikey"); -// }); - -// test("should reset api key if it is not passed", () => { -// const initData: Partial = { -// enable: true, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.apiKey).toBe(""); -// }); - -// test("should throw error if api key is not passed in editor mode", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// environment: "dev", -// }, -// mode: "editor", -// }; - -// expect(() => { -// handleInitData(initData); -// }).toThrowError("Live preview SDK: api key is required"); -// }); - -// test("should prioritize environment from user config", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// environment: "userenvironment", -// }, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.environment).toBe( -// "userenvironment" -// ); - -// initData.stackSdk = { -// live_preview: {}, -// environment: "sdkenvironment", -// headers: { -// api_key: "", -// }, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.environment).toBe( -// "userenvironment" -// ); -// }); - -// test("should set environment from stack sdk if available", () => { -// const initData: Partial = { -// enable: true, -// stackSdk: { -// live_preview: {}, -// environment: "sdkenvironment", -// headers: { -// api_key: "", -// }, -// }, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.environment).toBe( -// "sdkenvironment" -// ); -// }); - -// test("should reset environment if it is not passed", () => { -// const initData: Partial = { -// enable: true, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.environment).toBe(""); -// }); - -// test("should throw error if environment is not passed in editor mode", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// apiKey: "bltapikey", -// }, -// mode: "editor", -// }; - -// expect(() => { -// handleInitData(initData); -// }).toThrowError("Live preview SDK: environment is required"); -// }); - -// test("should prioritize branch from user config", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// branch: "userbranch", -// }, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.branch).toBe("userbranch"); - -// initData.stackSdk = { -// live_preview: {}, -// headers: { -// api_key: "bltapikey", -// branch: "sdkbranch", -// }, -// environment: "dev", -// }; - -// handleInitData(initData); -// expect(config.stackDetails.branch).toBe("userbranch"); -// }); - -// test("should set branch from headers if available", () => { -// const initData: Partial = { -// enable: true, - -// stackSdk: { -// live_preview: {}, -// headers: { -// api_key: "sdkbranch", -// branch: "sdkbranch", -// }, -// environment: "dev", -// }, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.branch).toBe("sdkbranch"); -// }); - -// test("should reset branch if it is not passed", () => { -// const initData: Partial = { -// enable: true, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.branch).toBe("main"); -// }); - -// test("should set locale from user config", () => { -// const initData: Partial = { -// enable: true, -// stackDetails: { -// locale: "userlocale", -// }, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.locale).toBe("userlocale"); -// }); - -// test("should set default locale if it is not passed", () => { -// const initData: Partial = { -// enable: true, -// }; - -// handleInitData(initData); -// expect(config.stackDetails.locale).toBe("en-us"); -// }); -// }); -// }); +describe("handleInitData()", () => { + + let config : DeepSignal; + + beforeEach(() => { + Config.reset(); + config = Config.get(); + }); + + afterAll(() => { + Config.reset(); + }); + + test("must set data when config is provided", () => { + const initData: Partial = { + enable: true, + stackDetails: { + apiKey: "bltanything", + environment: "", + }, + }; + + handleInitData(initData); + const expectedOutput = { + ssr: true, + enable: true, + cleanCslpOnProduction: true, + stackDetails: { + apiKey: "bltanything", + environment: "", + contentTypeUid: "", + entryUid: "", + }, + clientUrlParams: { + protocol: "https", + host: "app.contentstack.com", + port: 443, + url: "https://app.contentstack.com:443", + }, + stackSdk: { + headers: { + api_key: "", + }, + environment: "", + }, + }; + + expect(config).toMatchObject(expectedOutput); + }); + + test("must set SSR: true is stack SDK is not provided", () => { + const initData: Partial = { + enable: true, + stackDetails: { + apiKey: "bltanything", + environment: "", + }, + }; + + handleInitData(initData); + expect(config.ssr).toBe(true); + }); + + test("must set SSR: true is stack SDK is not provided", () => { + const initData: Partial = { + enable: true, + stackDetails: { + apiKey: "bltanything", + environment: "", + }, + stackSdk: { + live_preview: { + enable: true, + }, + headers: { + api_key: "bltanything", + }, + environment: "", + cachePolicy: 1, + }, + }; + + handleInitData(initData); + expect(config.ssr).toBe(false); + }); + + describe("live mode", () => { + test("should be set to 1 by default", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(config.mode).toBe(ILivePreviewModeConfig.PREVIEW); + }); + + test("should be set to 2 if user set it to editor", () => { + const initData: Partial = { + enable: true, + mode: "editor", + stackDetails: { + environment: "main", + apiKey: "bltanything", + }, + }; + + handleInitData(initData); + expect(config.mode).toBe(ILivePreviewModeConfig.EDITOR); + }); + + test("should be set to 1 if user set it to preview", () => { + const initData: Partial = { + enable: true, + mode: "preview", + }; + + handleInitData(initData); + expect(config.mode).toBe(ILivePreviewModeConfig.PREVIEW); + }); + + test("should throw an error if user set it to something else", () => { + const initData: Partial = { + enable: true, + // @ts-ignore + mode: "wrong-value", + }; + + expect(() => { + handleInitData(initData); + }).toThrowError( + "Live Preview SDK: The mode must be either 'editor' or 'preview'" + ); + }); + }); + + describe("stack details set by user", () => { + test("should prioritize api key from user config", () => { + const initData: Partial = { + enable: true, + stackDetails: { + apiKey: "bltuserapikey", + }, + }; + + handleInitData(initData); + expect(config.stackDetails.apiKey).toBe("bltuserapikey"); + + initData.stackSdk = { + live_preview: {}, + headers: { + api_key: "bltheaderapikey", + }, + environment: "dev", + }; + + handleInitData(initData); + expect(config.stackDetails.apiKey).toBe("bltuserapikey"); + }); + + test("should set api key from headers if available", () => { + const initData: Partial = { + enable: true, + + stackSdk: { + live_preview: {}, + headers: { + api_key: "bltheaderapikey", + }, + environment: "dev", + }, + }; + + handleInitData(initData); + expect(config.stackDetails.apiKey).toBe("bltheaderapikey"); + }); + + test("should reset api key if it is not passed", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(config.stackDetails.apiKey).toBe(""); + }); + + test("should throw error if api key is not passed in editor mode", () => { + const initData: Partial = { + enable: true, + stackDetails: { + environment: "dev", + }, + mode: "editor", + }; + + expect(() => { + handleInitData(initData); + }).toThrowError("Live preview SDK: api key is required"); + }); + + test("should prioritize environment from user config", () => { + const initData: Partial = { + enable: true, + stackDetails: { + environment: "userenvironment", + }, + }; + + handleInitData(initData); + expect(config.stackDetails.environment).toBe( + "userenvironment" + ); + + initData.stackSdk = { + live_preview: {}, + environment: "sdkenvironment", + headers: { + api_key: "", + }, + }; + + handleInitData(initData); + expect(config.stackDetails.environment).toBe( + "userenvironment" + ); + }); + + test("should set environment from stack sdk if available", () => { + const initData: Partial = { + enable: true, + stackSdk: { + live_preview: {}, + environment: "sdkenvironment", + headers: { + api_key: "", + }, + }, + }; + + handleInitData(initData); + expect(config.stackDetails.environment).toBe( + "sdkenvironment" + ); + }); + + test("should reset environment if it is not passed", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(config.stackDetails.environment).toBe(""); + }); + + test("should throw error if environment is not passed in editor mode", () => { + const initData: Partial = { + enable: true, + stackDetails: { + apiKey: "bltapikey", + }, + mode: "editor", + }; + + expect(() => { + handleInitData(initData); + }).toThrowError("Live preview SDK: environment is required"); + }); + + test("should prioritize branch from user config", () => { + const initData: Partial = { + enable: true, + stackDetails: { + branch: "userbranch", + }, + }; + + handleInitData(initData); + expect(config.stackDetails.branch).toBe("userbranch"); + + initData.stackSdk = { + live_preview: {}, + headers: { + api_key: "bltapikey", + branch: "sdkbranch", + }, + environment: "dev", + }; + + handleInitData(initData); + expect(config.stackDetails.branch).toBe("userbranch"); + }); + + test("should set branch from headers if available", () => { + const initData: Partial = { + enable: true, + + stackSdk: { + live_preview: {}, + headers: { + api_key: "sdkbranch", + branch: "sdkbranch", + }, + environment: "dev", + }, + }; + + handleInitData(initData); + expect(config.stackDetails.branch).toBe("sdkbranch"); + }); + + test("should reset branch if it is not passed", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(config.stackDetails.branch).toBe("main"); + }); + + test("should set locale from user config", () => { + const initData: Partial = { + enable: true, + stackDetails: { + locale: "userlocale", + }, + }; + + handleInitData(initData); + expect(config.stackDetails.locale).toBe("userlocale"); + }); + + test("should set default locale if it is not passed", () => { + const initData: Partial = { + enable: true, + }; + + handleInitData(initData); + expect(config.stackDetails.locale).toBe("en-us"); + }); + }); +}); describe("handleClientUrlParams()", () => { let config: DeepSignal; diff --git a/src/livePreview/editButton/editButton.ts b/src/livePreview/editButton/editButton.ts index e4ab071c..58f51f92 100644 --- a/src/livePreview/editButton/editButton.ts +++ b/src/livePreview/editButton/editButton.ts @@ -192,6 +192,9 @@ export function shouldRenderEditButton(editButton: IConfigEditButton): boolean { PublicLogger.error(error); } + console.log('[IN SDK] : WINDOWTYPE : ', Config.get().windowType); + + // case if inside live preview or inside live editor if ( inIframe() || @@ -309,7 +312,7 @@ export class LivePreviewEditButton { if (currentRectOfElement && currentRectOfParentOfElement) { const editButtonPosition = getEditButtonPosition( elements.highlightedElement as HTMLElement, - editButton.position as unknown as string + editButton.position ); let upperBoundOfTooltip = editButtonPosition.upperBoundOfTooltip; diff --git a/src/livePreview/eventManager/postMessageEvent.hooks.ts b/src/livePreview/eventManager/postMessageEvent.hooks.ts index a8044ca1..46844259 100644 --- a/src/livePreview/eventManager/postMessageEvent.hooks.ts +++ b/src/livePreview/eventManager/postMessageEvent.hooks.ts @@ -51,7 +51,7 @@ export function useOnEntryUpdatePostMessageEvent(): void { }); const { ssr, onChange } = Config.get(); if (!ssr) { - onChange!(); + onChange(); } } ); From 42a90fbd8486e97ac3d20d49b4f7f186c73f1461 Mon Sep 17 00:00:00 2001 From: Vishvam10 Date: Tue, 12 Mar 2024 11:39:40 +0530 Subject: [PATCH 10/10] chore: remove console.logs --- .../__test__/handleUserConfig.test.ts | 15 ++++----------- src/livePreview/editButton/editButton.ts | 3 --- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/configManager/__test__/handleUserConfig.test.ts b/src/configManager/__test__/handleUserConfig.test.ts index 6a07156f..3e9c126e 100644 --- a/src/configManager/__test__/handleUserConfig.test.ts +++ b/src/configManager/__test__/handleUserConfig.test.ts @@ -38,8 +38,7 @@ import { DeepSignal } from "deepsignal"; */ describe("handleInitData()", () => { - - let config : DeepSignal; + let config: DeepSignal; beforeEach(() => { Config.reset(); @@ -245,9 +244,7 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(config.stackDetails.environment).toBe( - "userenvironment" - ); + expect(config.stackDetails.environment).toBe("userenvironment"); initData.stackSdk = { live_preview: {}, @@ -258,9 +255,7 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(config.stackDetails.environment).toBe( - "userenvironment" - ); + expect(config.stackDetails.environment).toBe("userenvironment"); }); test("should set environment from stack sdk if available", () => { @@ -276,9 +271,7 @@ describe("handleInitData()", () => { }; handleInitData(initData); - expect(config.stackDetails.environment).toBe( - "sdkenvironment" - ); + expect(config.stackDetails.environment).toBe("sdkenvironment"); }); test("should reset environment if it is not passed", () => { diff --git a/src/livePreview/editButton/editButton.ts b/src/livePreview/editButton/editButton.ts index 58f51f92..d76f2d33 100644 --- a/src/livePreview/editButton/editButton.ts +++ b/src/livePreview/editButton/editButton.ts @@ -192,9 +192,6 @@ export function shouldRenderEditButton(editButton: IConfigEditButton): boolean { PublicLogger.error(error); } - console.log('[IN SDK] : WINDOWTYPE : ', Config.get().windowType); - - // case if inside live preview or inside live editor if ( inIframe() ||