Skip to content
6 changes: 5 additions & 1 deletion .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@ fileignoreconfig:
ignore_detectors:
- filecontent
- filename: README.md
checksum: f9e1aee750713c9c4aea3c1027686a1aefcebd759de0ffd06dbea6fdf9f576e6
checksum: 568289bbe7c088967493db246dbf29e465382648ac574c1b1236be57d5662a38
- filename: CHANGELOG.md
checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee
- filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx
checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e
version: "1.0"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ npm install @contentstack/live-preview-utils
Alternatively, if you want to include the package directly in your website HTML code, use the following command:

```html
<script type='module' integrity='sha384-SHUnMbbEHjE8k0KW44O7mqfIkMq3FXetFL0TBcsLnyje7aLZch0lhjcp2HxvHC8B' crossorigin="anonymous">
<script type='module' integrity='sha384-b6G+ggU20rGxqCqsgaS6zludFgj5N11xsuXhMEIARMuQY2PtyDS04TU0H5goP+32' crossorigin="anonymous">
import ContentstackLivePreview from 'https://esm.sh/@contentstack/live-preview-utils@3.2.2';

ContentstackLivePreview.init({
Expand Down
177 changes: 177 additions & 0 deletions src/__test__/contentstack-live-preview.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { vi } from 'vitest';
import type { OnEntryChangeCallback, OnEntryChangeConfig } from '../livePreview/types/onEntryChangeCallback.type';
import type { IStackSdk, IExportedConfig, IInitData } from '../types/types';

// Store original env and window
const originalEnv = process.env;
const originalWindow = global.window;

describe('ContentstackLivePreview HOC Class Integration Tests', () => {
let ContentstackLivePreview: any;
let ContentstackLivePreviewHOC: any;

beforeEach(() => {
// Reset modules and env before each test
vi.resetModules();
process.env = { ...originalEnv };
});

afterEach(() => {
process.env = originalEnv;
vi.clearAllMocks();

// Restore window to original state
Object.defineProperty(global, 'window', {
value: originalWindow,
writable: true,
configurable: true
});
});

describe('SDK Selection Tests', () => {
test('should use LightLivePreviewHoC when PURGE_PREVIEW_SDK is true', async () => {
process.env.PURGE_PREVIEW_SDK = 'true';

const { default: CSLivePreview } = await import('../index');
const { default: CSLivePreviewHOC } = await import('../preview/contentstack-live-preview-HOC');

ContentstackLivePreview = CSLivePreview;
ContentstackLivePreviewHOC = CSLivePreviewHOC;

expect(ContentstackLivePreview.name).toBe('LightLivePreviewHoC');
});

test('should use LightLivePreviewHoC when REACT_APP_PURGE_PREVIEW_SDK is true', async () => {
process.env.REACT_APP_PURGE_PREVIEW_SDK = 'true';

const { default: CSLivePreview } = await import('../index');
ContentstackLivePreview = CSLivePreview;

expect(ContentstackLivePreview.name).toBe('LightLivePreviewHoC');
});

test('should use ContentstackLivePreviewHOC by default', async () => {
process.env.PURGE_PREVIEW_SDK = 'false';
process.env.REACT_APP_PURGE_PREVIEW_SDK = 'false';

const { default: CSLivePreview } = await import('../index');
const { default: CSLivePreviewHOC } = await import('../preview/contentstack-live-preview-HOC');

ContentstackLivePreview = CSLivePreview;
ContentstackLivePreviewHOC = CSLivePreviewHOC;

expect(ContentstackLivePreview).toBe(ContentstackLivePreviewHOC);
});
});

describe('LightLivePreviewHoC Functionality Tests', () => {
beforeEach(async () => {
process.env.PURGE_PREVIEW_SDK = 'true';
const { default: CSLivePreview } = await import('../index');
ContentstackLivePreview = CSLivePreview;
});

test('should initialize with empty constructors', async () => {
const result = await ContentstackLivePreview.init();
expect(result).toEqual({
livePreview: {},
visualBuilder: {},
});
});

test('should return empty hash', () => {
expect(ContentstackLivePreview.hash).toBe('');
});

test('should return empty config', () => {
const config = ContentstackLivePreview.config as IExportedConfig;
expect(config).toEqual({});
});

test('should allow access to stackDetails from config without type error', () => {
expect(ContentstackLivePreview.config.stackDetails).toEqual(undefined);
});

test('should handle onEntryChange with immediate callback execution', () => {
const mockCallback = vi.fn() as OnEntryChangeCallback;
const config: OnEntryChangeConfig = { skipInitialRender: false };

const callbackId = ContentstackLivePreview.onEntryChange(mockCallback, config);

expect(callbackId).toBe('live-preview-id');
expect(mockCallback).toHaveBeenCalledTimes(1);
});

test('should handle onEntryChange with skipped initial render', () => {
const mockCallback = vi.fn() as OnEntryChangeCallback;
const config: OnEntryChangeConfig = { skipInitialRender: true };

const callbackId = ContentstackLivePreview.onEntryChange(mockCallback, config);

expect(callbackId).toBe('live-preview-id');
expect(mockCallback).not.toHaveBeenCalled();
});

test('should handle onLiveEdit', () => {
const mockCallback = vi.fn() as OnEntryChangeCallback;
const result = ContentstackLivePreview.onLiveEdit(mockCallback);
expect(result).toBe('live-preview-id');
});

test('should handle unsubscribeOnEntryChange without errors', () => {
const mockCallback = vi.fn() as OnEntryChangeCallback;
const callbackId = ContentstackLivePreview.onEntryChange(mockCallback);
expect(() => {
ContentstackLivePreview.unsubscribeOnEntryChange(callbackId);
}).not.toThrow();
});

test('should return package version from environment', () => {
process.env.PACKAGE_VERSION = '1.0.0';
expect(ContentstackLivePreview.getSdkVersion()).toBe('1.0.0');
});
});

describe('Browser Environment Tests', () => {
beforeEach(async () => {
process.env.PURGE_PREVIEW_SDK = 'true';
vi.resetModules();
const { default: CSLivePreview } = await import('../index');
ContentstackLivePreview = CSLivePreview;
});

test('should handle initialization in non-browser environment', async () => {
// Mock window as undefined
Object.defineProperty(global, 'window', {
value: undefined,
writable: true,
configurable: true
});

const result = await ContentstackLivePreview.init();

expect(result).toEqual({});
});

test('should initialize properly in browser environment', async () => {
// Mock window with minimum required properties
Object.defineProperty(global, 'window', {
value: {
location: {
search: '',
hash: ''
}
},
writable: true,
configurable: true
});

const result = await ContentstackLivePreview.init();

expect(result).toEqual({
livePreview: {},
visualBuilder: {},
});
});
});
});
66 changes: 1 addition & 65 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,10 @@
import ContentstackLivePreviewHOC from "./preview/contentstack-live-preview-HOC";
import { IStackSdk as ExternalStackSdkType } from "./types/types";

import {
OnEntryChangeCallback,
OnEntryChangeCallbackUID,
OnEntryChangeConfig,
} from "./livePreview/types/onEntryChangeCallback.type";
import LightLivePreviewHoC from "./light-sdk";

export type IStackSdk = ExternalStackSdkType;

class LightLivePreviewHoC {
private static previewConstructors = {};
private static onEntryChangeCallbacks = {};

static init() {
if (typeof window === "undefined") {
return Promise.resolve(LightLivePreviewHoC.previewConstructors);
}

return LightLivePreviewHoC.initializePreview();
}

private static initializePreview() {
LightLivePreviewHoC.previewConstructors = {
livePreview: {},
visualBuilder: {},
};

LightLivePreviewHoC.onEntryChangeCallbacks = {};

return Promise.resolve(LightLivePreviewHoC.previewConstructors);
}

static get hash() {
return "";
}

static get config() {
return {};
}

static isInitialized() {
return false;
}

static onEntryChange(
callback: OnEntryChangeCallback,
config: OnEntryChangeConfig = {}
): OnEntryChangeCallbackUID {
const { skipInitialRender = false } = config;

if (!skipInitialRender) {
callback();
}

return "live-preview-id";
}

static onLiveEdit(callback: OnEntryChangeCallback) {
return "live-preview-id";
}

static unsubscribeOnEntryChange() {
// intentionally empty
}

static getSdkVersion(): string {
return process?.env?.PACKAGE_VERSION!;
}
}

const ContentstackLivePreview =
typeof process !== "undefined" &&
Expand Down
67 changes: 67 additions & 0 deletions src/light-sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { OnEntryChangeCallbackUID, OnEntryChangeConfig } from "./livePreview/types/onEntryChangeCallback.type";

import { OnEntryChangeCallback } from "./livePreview/types/onEntryChangeCallback.type";
import { IExportedConfig } from "./types/types";

class LightLivePreviewHoC {
private static previewConstructors = {};
private static onEntryChangeCallbacks = {};

static init() {
if (typeof window === "undefined") {
return Promise.resolve(LightLivePreviewHoC.previewConstructors);
}

return LightLivePreviewHoC.initializePreview();
}

private static initializePreview() {
LightLivePreviewHoC.previewConstructors = {
livePreview: {},
visualBuilder: {},
};

LightLivePreviewHoC.onEntryChangeCallbacks = {};

return Promise.resolve(LightLivePreviewHoC.previewConstructors);
}

static get hash() {
return "";
}

static get config() {
return {} as IExportedConfig;
}

static isInitialized() {
return false;
}

static onEntryChange(
callback: OnEntryChangeCallback,
config: OnEntryChangeConfig = {}
): OnEntryChangeCallbackUID {
const { skipInitialRender = false } = config;

if (!skipInitialRender) {
callback();
}

return "live-preview-id";
}

static onLiveEdit(callback: OnEntryChangeCallback) {
return "live-preview-id";
}

static unsubscribeOnEntryChange() {
// intentionally empty
}

static getSdkVersion(): string {
return process?.env?.PACKAGE_VERSION!;
}
}

export default LightLivePreviewHoC;
Loading