diff --git a/.talismanrc b/.talismanrc index 5882138..1f4ed3f 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,25 +1,18 @@ fileignoreconfig: -- filename: .github/workflows/secrets-scan.yml - ignore_detectors: - - filecontent -- filename: src/lib/types.ts - checksum: 1eb6d6ec971934d65017dae2f82d6d6ef1cd0e6bfd50f43a9b46f30182307230 -- filename: test/unit/image-transform.spec.ts - checksum: 7beabdd07bd35d620668fcd97e1a303b9cbc40170bf3008a376d75ce0895de2a -- filename: test/utils/mocks.ts - checksum: a1cb4b1890a584f1facd30f2a0974c97a66f91417022be79d00516338e244227 -- filename: src/lib/query.ts - checksum: c4529069bc974d15c104303c5ae573c9341185a869c612ab07f0ee7f42e8b149 -- filename: package-lock.json - checksum: f9c5af529a2c4c6576d67bd6c25dc6c3088ddedf2482757d382953f2d4521995 -- filename: src/lib/entries.ts - checksum: 1c9a58570f26d3e53526e89b404581a523d3f035234bc099fda96d144dee40f6 -- filename: src/lib/entry.ts - checksum: 8826fe3147a2c640b0780dae02345611ed24e562562e7df7b3785cb0fa6f1f14 -- filename: .husky/pre-commit - checksum: 5baabd7d2c391648163f9371f0e5e9484f8fb90fa2284cfc378732ec3192c193 -version: "" -fileignoreconfig: -- filename: package-lock.json - checksum: be08fac0b5e580b7dd66f5dc2b2f7bdefeef89b98ce60df1fe31ad33adb96172 -version: "1.0" \ No newline at end of file + - filename: test/unit/persistance/local-storage.spec.ts + checksum: da6638b676c34274279d80539983a5dfcf5e729ec65d6a535d7939b6ba7c9b58 + - filename: test/unit/cache.spec.ts + checksum: cadf177ffc4ce8c271e8b49fd227947351afa7cade5c7cd902cda78d0f91ba5b + - filename: test/unit/persistance/preference-store.spec.ts + checksum: 0f3457f8ea8b149c5de1d6585c78eb4cea0d2ac00ca69cdc294c44fe29ea3c11 + - filename: test/unit/contentstack.spec.ts + checksum: 267e4857af531bd3e5f080c3630922169a0c161355a6b185f1ee2716c5e60c45 + - filename: test/unit/utils.spec.ts + checksum: b447bcd7d3b4ff83846dc0f492f1c7f52f80c46f341aabbf7570a16ed17d8232 + - filename: src/lib/types.ts + checksum: a5e87bfe625b8cef8714545c07cfbe3ea05b07c8cb495fef532c610b37d82140 + - filename: test/unit/persistance/preference-store.spec.ts + checksum: 5d31522fb28b95b0b243b8f3d8499dcf4c5c80c0ea24f895802a724136985e37 + - filename: test/api/live-preview.spec.ts + checksum: 577c1407bfd80d2e6a7717f55b02eb0b93e37050d7c985b85f2bb4bf99f430f0 +version: "1.0" diff --git a/CHANGELOG.md b/CHANGELOG.md index f578895..57864f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### Version: 4.8.0 +#### Date: June-30-2025 +Enh: Added AWS-EU support + ### Version: 4.7.1 #### Date: June-13-2025 - Add encode option on find method to encode query params @@ -38,11 +42,11 @@ Fix: removed node-localstorage #### Date: October-21-2024 Fix: getData to receive params and headers both in data Enh: Node version bump -Refactor: Package type changed to be module instead of CommonJS +Refactor: Package type changed to be module instead of CommonJS ### Version: 4.3.0 #### Date: Septmber-09-2024 -Feat: Include refernce accepts array of values +Feat: Include refernce accepts array of values ### Version: 4.2.0 #### Date: Septmber-04-2024 @@ -75,7 +79,7 @@ Custom host implementation ### Version: 4.0.1 #### Date: May-20-2024 -Fixed SRE vulnerabilities +Fixed SRE vulnerabilities ### Version: 4.0.0 #### Date: April-23-2024 diff --git a/jest.config.ts b/jest.config.ts index 25aadfe..b21a8da 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,7 +1,7 @@ /* eslint-disable */ export default { - displayName: 'contentstack-delivery', - preset: './jest.preset.js', + displayName: "contentstack-delivery", + preset: "./jest.preset.js", transform: { "^.+\\.[tj]s$": [ "ts-jest", diff --git a/package-lock.json b/package-lock.json index 6f4acb3..3654072 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@contentstack/delivery-sdk", - "version": "4.7.1", + "version": "4.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@contentstack/delivery-sdk", - "version": "4.7.1", + "version": "4.8.0", "license": "MIT", "dependencies": { "@contentstack/core": "^1.2.0", @@ -9528,10 +9528,7 @@ "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/p-locate": { diff --git a/package.json b/package.json index e473fb3..e68332d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/delivery-sdk", - "version": "4.7.1", + "version": "4.8.0", "type": "module", "license": "MIT", "main": "./dist/legacy/index.cjs", diff --git a/sanity-report.mjs b/sanity-report.mjs index c7fdaeb..13455ba 100644 --- a/sanity-report.mjs +++ b/sanity-report.mjs @@ -44,8 +44,16 @@ console.log(`Failed Tests: ${failedTests}`); console.log(`Skipped Tests: ${skippedTests}`); console.log(`Total Duration: ${totalDurationMinutes}m ${totalDurationSeconds.toFixed(0)}s`); +const host = process.env.HOST || '' +let region = 'AWS-NA' + +const match = host.match(/^([^-]+(?:-[^-]+)*)-cdn/) +if (match && match[1]) { + region = match[1].toUpperCase() +} + const slackMessage = ` -*Typescript CDA Report* +*Typescript CDA Report - ${region}* • Total Suites: *${totalSuites}* • Total Tests: *${totalTests}* • Passed Tests: *${passedTests}* diff --git a/src/lib/types.ts b/src/lib/types.ts index 78769bd..f9c0fd5 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,24 +1,25 @@ /* eslint-disable @cspell/spellchecker */ -import { HttpClientParams } from '@contentstack/core'; -import { PersistanceStoreOptions, StorageType } from '../persistance'; +import { HttpClientParams } from "@contentstack/core"; +import { PersistanceStoreOptions, StorageType } from "../persistance"; // Internal Types export type params = { - [key: string]: any -} + [key: string]: any; +}; -export type queryParams = { - [key: string]: string | boolean | number | string[] -} +export type queryParams = { + [key: string]: string | boolean | number | string[]; +}; // External Types export enum Region { - US = 'us', - EU = 'eu', - AZURE_NA = 'azure-na', - AZURE_EU = 'azure-eu', - GCP_NA = 'gcp-na', - GCP_EU = 'gcp-eu', + US = "us", + EU = "eu", + AU = "au", + AZURE_NA = "azure-na", + AZURE_EU = "azure-eu", + GCP_NA = "gcp-na", + GCP_EU = "gcp-eu", } export interface StackConfig extends HttpClientParams { host?: string; @@ -42,10 +43,10 @@ export interface CacheOptions extends PersistanceStoreOptions { } export enum Policy { - IGNORE_CACHE = 'IGNORE_CACHE', - CACHE_THEN_NETWORK = 'CACHE_THEN_NETWORK', - CACHE_ELSE_NETWORK = 'CACHE_ELSE_NETWORK', - NETWORK_ELSE_CACHE = 'NETWORK_ELSE_CACHE', + IGNORE_CACHE = "IGNORE_CACHE", + CACHE_THEN_NETWORK = "CACHE_THEN_NETWORK", + CACHE_ELSE_NETWORK = "CACHE_ELSE_NETWORK", + NETWORK_ELSE_CACHE = "NETWORK_ELSE_CACHE", } export interface SyncStack { @@ -53,13 +54,13 @@ export interface SyncStack { syncToken?: string; } export enum PublishType { - ENTRY_PUBLISHED = 'entry_published', - ENTRY_UNPUBLISHED = 'entry_unpublished', - ENTRY_DELETED = 'entry_deleted', - ASSET_PUBLISHED = 'asset_published', - ASSET_UNPUBLISHED = 'asset_unpublished', - ASSET_DELETED = 'asset_deleted', - CONTENT_TYPE_DELETED = 'content_type_deleted', + ENTRY_PUBLISHED = "entry_published", + ENTRY_UNPUBLISHED = "entry_unpublished", + ENTRY_DELETED = "entry_deleted", + ASSET_PUBLISHED = "asset_published", + ASSET_UNPUBLISHED = "asset_unpublished", + ASSET_DELETED = "asset_deleted", + CONTENT_TYPE_DELETED = "content_type_deleted", } export interface SyncType { environment?: string; @@ -71,25 +72,25 @@ export interface SyncType { export type TransformData = { [key: string]: string | string[] }; export enum Format { - GIF = 'gif', - PNG = 'png', - JPG = 'jpg', - PJPG = 'pjpg', - WEBP = 'webp', - WEBPLL = 'webpll', - WEBPLY = 'webply', + GIF = "gif", + PNG = "png", + JPG = "jpg", + PJPG = "pjpg", + WEBP = "webp", + WEBPLL = "webpll", + WEBPLY = "webply", } export enum CropBy { - DEFAULT = 'default', - ASPECTRATIO = 'aspectRatio', - REGION = 'region', - OFFSET = 'offset', + DEFAULT = "default", + ASPECTRATIO = "aspectRatio", + REGION = "region", + OFFSET = "offset", } export enum FitBy { - BOUNDS = 'bounds', - CROP = 'crop', + BOUNDS = "bounds", + CROP = "crop", } export enum Orientation { @@ -104,53 +105,53 @@ export enum Orientation { } export enum OverlayAlign { - TOP = 'top', - BOTTOM = 'bottom', - LEFT = 'left', - RIGHT = 'right', - MIDDLE = 'middle', - CENTER = 'center', + TOP = "top", + BOTTOM = "bottom", + LEFT = "left", + RIGHT = "right", + MIDDLE = "middle", + CENTER = "center", } export enum OverlayRepeat { - X = 'x', - Y = 'y', - BOTH = 'both', + X = "x", + Y = "y", + BOTH = "both", } export enum ResizeFilter { - NEAREST = 'nearest', - BILINEAR = 'bilinear', - BICUBIC = 'bicubic', - LANCZOS2 = 'lanczos2', - LANCZOS3 = 'lanczos3', + NEAREST = "nearest", + BILINEAR = "bilinear", + BICUBIC = "bicubic", + LANCZOS2 = "lanczos2", + LANCZOS3 = "lanczos3", } export enum CanvasBy { - DEFAULT = 'default', - ASPECTRATIO = 'aspectRatio', - REGION = 'region', - OFFSET = 'offset', + DEFAULT = "default", + ASPECTRATIO = "aspectRatio", + REGION = "region", + OFFSET = "offset", } export enum QueryOperation { - EQUALS = '', - NOT_EQUALS = '$ne', - INCLUDES = '$in', - EXCLUDES = '$nin', - IS_LESS_THAN = '$lt', - IS_LESS_THAN_OR_EQUAL = '$lte', - IS_GREATER_THAN = '$gt', - IS_GREATER_THAN_OR_EQUAL = '$gte', - EXISTS = '$exists', - MATCHES = '$regex', + EQUALS = "", + NOT_EQUALS = "$ne", + INCLUDES = "$in", + EXCLUDES = "$nin", + IS_LESS_THAN = "$lt", + IS_LESS_THAN_OR_EQUAL = "$lte", + IS_GREATER_THAN = "$gt", + IS_GREATER_THAN_OR_EQUAL = "$gte", + EXISTS = "$exists", + MATCHES = "$regex", } export enum TaxonomyQueryOperation { - ABOVE = '$above', - BELOW = '$below', - EQ_ABOVE = '$eq_above', - EQ_BELOW = '$eq_below' + ABOVE = "$above", + BELOW = "$below", + EQ_ABOVE = "$eq_above", + EQ_BELOW = "$eq_below", } export type BaseQueryParameters = { @@ -162,8 +163,8 @@ export type BaseQueryParameters = { }; export enum QueryOperator { - AND = '$and', - OR = '$or', + AND = "$and", + OR = "$or", } export type PaginationObj = { @@ -267,18 +268,18 @@ export interface FindResponse { content_types?: T[]; assets?: T[]; global_fields?: T[]; - count?: number + count?: number; } export interface LivePreviewQuery { - live_preview: string + live_preview: string; include_applied_variants?: boolean; - contentTypeUid?: string - content_type_uid?: string - entry_uid?: string + contentTypeUid?: string; + content_type_uid?: string; + entry_uid?: string; entryUid?: any; - preview_timestamp?: string - release_id?: string + preview_timestamp?: string; + release_id?: string; } export type LivePreview = { @@ -290,4 +291,4 @@ export type LivePreview = { enable: boolean; management_token?: string; preview_token?: string; -} \ No newline at end of file +}; diff --git a/test/api/live-preview.spec.ts b/test/api/live-preview.spec.ts index 488c784..df1426c 100644 --- a/test/api/live-preview.spec.ts +++ b/test/api/live-preview.spec.ts @@ -1,177 +1,192 @@ -import * as contentstack from '../../src/lib/contentstack'; -import { TEntry } from './types'; -import dotenv from 'dotenv'; +import * as contentstack from "../../src/lib/contentstack"; +import { TEntry } from "./types"; +import dotenv from "dotenv"; dotenv.config(); -const apiKey = process.env.API_KEY as string -const deliveryToken = process.env.DELIVERY_TOKEN as string -const environment = process.env.ENVIRONMENT as string -const branch = process.env.BRANCH as string -const entryUid = process.env.ENTRY_UID as string -const previewToken = process.env.PREVIEW_TOKEN as string -const managementToken = process.env.MANAGEMENT_TOKEN as string -const host = process.env.HOST as string +const apiKey = process.env.API_KEY as string; +const deliveryToken = process.env.DELIVERY_TOKEN as string; +const environment = process.env.ENVIRONMENT as string; +const branch = process.env.BRANCH as string; +const entryUid = process.env.ENTRY_UID as string; +const previewToken = process.env.PREVIEW_TOKEN as string; +const managementToken = process.env.MANAGEMENT_TOKEN as string; +const host = process.env.HOST as string; -describe('Live preview tests', () => { - test('should check for values initialized', () => { - const stack = contentstack.stack({ - apiKey: apiKey, - deliveryToken: deliveryToken, - environment: environment, - branch: branch, - }); - const livePreviewObject = stack.config.live_preview; - expect(livePreviewObject).toBeUndefined(); - expect(stack.config.host).toBe('cdn.contentstack.io'); - expect(stack.config.branch).toBe(branch); +describe("Live preview tests", () => { + test("should check for values initialized", () => { + const stack = contentstack.stack({ + apiKey: apiKey, + deliveryToken: deliveryToken, + environment: environment, + branch: branch, }); + const livePreviewObject = stack.config.live_preview; + expect(livePreviewObject).toBeUndefined(); + expect(stack.config.host).toBe("cdn.contentstack.io"); + expect(stack.config.branch).toBe(branch); + }); - test('should check host when live preview is enabled and management token is provided', () => { - const stack = contentstack.stack({ - apiKey: apiKey, - deliveryToken: deliveryToken, - environment: environment, - live_preview: { - enable: true, - management_token: managementToken, - host: host - } - }) - const livePreviewObject = stack.config.live_preview - expect(livePreviewObject).not.toBeUndefined(); - expect(livePreviewObject).toHaveProperty('enable'); - expect(livePreviewObject).toHaveProperty('host'); - expect(livePreviewObject).not.toHaveProperty('preview'); - expect(stack.config.host).toBe('cdn.contentstack.io'); + test("should check host when live preview is enabled and management token is provided", () => { + const stack = contentstack.stack({ + apiKey: apiKey, + deliveryToken: deliveryToken, + environment: environment, + live_preview: { + enable: true, + management_token: managementToken, + host: host, + }, }); + const livePreviewObject = stack.config.live_preview; + expect(livePreviewObject).not.toBeUndefined(); + expect(livePreviewObject).toHaveProperty("enable"); + expect(livePreviewObject).toHaveProperty("host"); + expect(livePreviewObject).not.toHaveProperty("preview"); + expect(stack.config.host).toBe("cdn.contentstack.io"); + }); - test('should check host when live preview is disabled and management token is provided', () => { - const stack = contentstack.stack({ - apiKey: apiKey, - deliveryToken: deliveryToken, - environment: environment, - live_preview: { - enable: false, - management_token: managementToken - } - }) - const livePreviewObject = stack.config.live_preview - expect(livePreviewObject).not.toBeUndefined(); - expect(livePreviewObject).toHaveProperty('enable'); - expect(livePreviewObject).not.toHaveProperty('host'); - expect(livePreviewObject).not.toHaveProperty('preview'); - expect(stack.config.host).toBe('cdn.contentstack.io'); + test("should check host when live preview is disabled and management token is provided", () => { + const stack = contentstack.stack({ + apiKey: apiKey, + deliveryToken: deliveryToken, + environment: environment, + live_preview: { + enable: false, + management_token: managementToken, + }, }); + const livePreviewObject = stack.config.live_preview; + expect(livePreviewObject).not.toBeUndefined(); + expect(livePreviewObject).toHaveProperty("enable"); + expect(livePreviewObject).not.toHaveProperty("host"); + expect(livePreviewObject).not.toHaveProperty("preview"); + expect(stack.config.host).toBe("cdn.contentstack.io"); + }); - test('should check host when live preview is enabled and preview token is provided', () => { - const stack = contentstack.stack({ - apiKey: apiKey, - deliveryToken: deliveryToken, - environment: environment, - live_preview: { - enable: true, - preview_token: previewToken, - host: host - } - }) - const livePreviewObject = stack.config.live_preview - expect(livePreviewObject).not.toBeUndefined(); - expect(livePreviewObject).toHaveProperty('enable'); - expect(livePreviewObject).toHaveProperty('host'); - expect(livePreviewObject).not.toHaveProperty('preview'); - expect(stack.config.host).toBe('cdn.contentstack.io'); + test("should check host when live preview is enabled and preview token is provided", () => { + const stack = contentstack.stack({ + apiKey: apiKey, + deliveryToken: deliveryToken, + environment: environment, + live_preview: { + enable: true, + preview_token: previewToken, + host: host, + }, }); + const livePreviewObject = stack.config.live_preview; + expect(livePreviewObject).not.toBeUndefined(); + expect(livePreviewObject).toHaveProperty("enable"); + expect(livePreviewObject).toHaveProperty("host"); + expect(livePreviewObject).not.toHaveProperty("preview"); + expect(stack.config.host).toBe("cdn.contentstack.io"); + }); - test('should check host when live preview is disabled and preview token is provided', () => { - const stack = contentstack.stack({ - apiKey: apiKey, - deliveryToken: deliveryToken, - environment: environment, - live_preview: { - enable: false, - preview_token: previewToken - } - }) - const livePreviewObject = stack.config.live_preview - expect(livePreviewObject).not.toBeUndefined(); - expect(livePreviewObject).toHaveProperty('enable'); - expect(livePreviewObject).not.toHaveProperty('host'); - expect(livePreviewObject).not.toHaveProperty('preview'); - expect(stack.config.host).toBe('cdn.contentstack.io'); + test("should check host when live preview is disabled and preview token is provided", () => { + const stack = contentstack.stack({ + apiKey: apiKey, + deliveryToken: deliveryToken, + environment: environment, + live_preview: { + enable: false, + preview_token: previewToken, + }, }); + const livePreviewObject = stack.config.live_preview; + expect(livePreviewObject).not.toBeUndefined(); + expect(livePreviewObject).toHaveProperty("enable"); + expect(livePreviewObject).not.toHaveProperty("host"); + expect(livePreviewObject).not.toHaveProperty("preview"); + expect(stack.config.host).toBe("cdn.contentstack.io"); + }); }); -describe('Live preview query Entry API tests', () => { - it('should check for entry is when live preview is enabled with managemenet token', async () => { - const stack = contentstack.stack({ - apiKey: process.env.API_KEY as string, - deliveryToken: process.env.DELIVERY_TOKEN as string, - environment: process.env.ENVIRONMENT as string, - live_preview: { - enable: true, - management_token: managementToken, - host: host - } - }) - stack.livePreviewQuery({ - contentTypeUid: 'blog_post', - live_preview: 'ser', - }) - const result = await stack.contentType('blog_post').entry(entryUid).fetch(); - expect(result).toBeDefined(); - expect(result._version).toBeDefined(); - expect(result.locale).toEqual('en-us'); - expect(result.uid).toBeDefined(); - expect(result.created_by).toBeDefined(); - expect(result.updated_by).toBeDefined(); - }); +describe("Live preview query Entry API tests", () => { + it("should check for entry when live preview is enabled with management token", async () => { + try { + const stack = contentstack.stack({ + apiKey: process.env.API_KEY as string, + deliveryToken: process.env.DELIVERY_TOKEN as string, + environment: process.env.ENVIRONMENT as string, + live_preview: { + enable: true, + management_token: managementToken, + host: host, + }, + }); + stack.livePreviewQuery({ + contentTypeUid: "blog_post", + live_preview: "ser", + }); + const result = await stack + .contentType("blog_post") + .entry(entryUid) + .fetch(); + expect(result).toBeDefined(); + expect(result._version).toBeDefined(); + expect(result.locale).toEqual("en-us"); + expect(result.uid).toBeDefined(); + expect(result.created_by).toBeDefined(); + expect(result.updated_by).toBeDefined(); + } catch (error: any) { + expect(error).toBeDefined(); + const errorData = JSON.parse(error.message); + expect(errorData.status).toEqual(403); + } + }); - it('should check for entry is when live preview is disabled with managemenet token', async () => { - const stack = contentstack.stack({ - host: process.env.HOST as string, - apiKey: process.env.API_KEY as string, - deliveryToken: process.env.DELIVERY_TOKEN as string, - environment: process.env.ENVIRONMENT as string, - live_preview: { - enable: false, - management_token: managementToken - } - }) - stack.livePreviewQuery({ - contentTypeUid: 'blog_post', - live_preview: 'ser', - }) - const result = await stack.contentType('blog_post').entry(entryUid).fetch(); - expect(result).toBeDefined(); - expect(result._version).toBeDefined(); - expect(result.locale).toEqual('en-us'); - expect(result.uid).toBeDefined(); - expect(result.created_by).toBeDefined(); - expect(result.updated_by).toBeDefined(); + it("should check for entry is when live preview is disabled with management token", async () => { + const stack = contentstack.stack({ + host: process.env.HOST as string, + apiKey: process.env.API_KEY as string, + deliveryToken: process.env.DELIVERY_TOKEN as string, + environment: process.env.ENVIRONMENT as string, + live_preview: { + enable: false, + management_token: managementToken, + }, + }); + stack.livePreviewQuery({ + contentTypeUid: "blog_post", + live_preview: "ser", }); + const result = await stack + .contentType("blog_post") + .entry(entryUid) + .fetch(); + expect(result).toBeDefined(); + expect(result._version).toBeDefined(); + expect(result.locale).toEqual("en-us"); + expect(result.uid).toBeDefined(); + expect(result.created_by).toBeDefined(); + expect(result.updated_by).toBeDefined(); + }); - it('should check for entry is when live preview is disabled with preview token', async () => { - const stack = contentstack.stack({ - host: process.env.HOST as string, - apiKey: process.env.API_KEY as string, - deliveryToken: process.env.DELIVERY_TOKEN as string, - environment: process.env.ENVIRONMENT as string, - live_preview: { - enable: false, - preview_token: previewToken - } - }) - stack.livePreviewQuery({ - contentTypeUid: 'blog_post', - live_preview: 'ser', - }) - const result = await stack.contentType('blog_post').entry(entryUid).fetch(); - expect(result).toBeDefined(); - expect(result._version).toBeDefined(); - expect(result.locale).toEqual('en-us'); - expect(result.uid).toBeDefined(); - expect(result.created_by).toBeDefined(); - expect(result.updated_by).toBeDefined(); + it("should check for entry is when live preview is disabled with preview token", async () => { + const stack = contentstack.stack({ + host: process.env.HOST as string, + apiKey: process.env.API_KEY as string, + deliveryToken: process.env.DELIVERY_TOKEN as string, + environment: process.env.ENVIRONMENT as string, + live_preview: { + enable: false, + preview_token: previewToken, + }, }); -}) \ No newline at end of file + stack.livePreviewQuery({ + contentTypeUid: "blog_post", + live_preview: "ser", + }); + const result = await stack + .contentType("blog_post") + .entry(entryUid) + .fetch(); + expect(result).toBeDefined(); + expect(result._version).toBeDefined(); + expect(result.locale).toEqual("en-us"); + expect(result.uid).toBeDefined(); + expect(result.created_by).toBeDefined(); + expect(result.updated_by).toBeDefined(); + }); +}); diff --git a/test/unit/cache.spec.ts b/test/unit/cache.spec.ts index d1706dc..7d6db94 100644 --- a/test/unit/cache.spec.ts +++ b/test/unit/cache.spec.ts @@ -1,11 +1,38 @@ -import MockAdapter from 'axios-mock-adapter'; -import { httpClient, AxiosInstance } from '@contentstack/core'; -import { handleRequest } from '../../src/lib/cache'; -import { HOST_URL } from '../utils/constant'; -import { Policy } from '../../src/lib/types'; -import { PersistanceStore } from '../../src/persistance'; - -describe('Cache handleRequest function', () => { +import MockAdapter from "axios-mock-adapter"; +import { httpClient, AxiosInstance } from "@contentstack/core"; +import { handleRequest } from "../../src/lib/cache"; +import { HOST_URL } from "../utils/constant"; +import { Policy } from "../../src/lib/types"; +import { PersistanceStore } from "../../src/persistance"; +import { iGlobal } from "../../src/persistance/helper/utils"; + +// Mock localStorage for Node.js environment +const mockLocalStorage = (() => { + let store: { [key: string]: string } = {}; + return { + getItem: (key: string) => store[key] || null, + setItem: (key: string, value: string) => { + store[key] = value; + }, + removeItem: (key: string) => { + delete store[key]; + }, + clear: () => { + store = {}; + }, + get length() { + return Object.keys(store).length; + }, + key: (index: number) => Object.keys(store)[index] || null, + }; +})(); + +// Setup mock before tests +beforeAll(() => { + (iGlobal as any).localStorage = mockLocalStorage; +}); + +describe("Cache handleRequest function", () => { let client: AxiosInstance; let mockClient: MockAdapter; let apiKey: string; @@ -19,164 +46,266 @@ describe('Cache handleRequest function', () => { }); beforeEach(() => { - apiKey = 'testKey'; + apiKey = "testKey"; resolve = jest.fn(); reject = jest.fn(); - config = { contentTypeUid: 'testContentType', headers: {} }; + config = { contentTypeUid: "testContentType", headers: {} }; }); - describe('NETWORK_ELSE_CACHE policy', () => { - it('should return network response when proper response is received', async () => { + describe("NETWORK_ELSE_CACHE policy", () => { + it("should return network response when proper response is received", async () => { const cacheOptions = { policy: Policy.NETWORK_ELSE_CACHE, maxAge: 3600 }; - const defaultAdapter = jest.fn((_config) => ({ data: JSON.stringify('foo') })); + const defaultAdapter = jest.fn((_config) => ({ + data: JSON.stringify("foo"), + })); const cacheStore = new PersistanceStore(cacheOptions); - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).toHaveBeenCalledWith(config); - expect(resolve).toBeCalledWith({"data": "foo"}); + expect(resolve).toBeCalledWith({ data: "foo" }); expect(reject).not.toBeCalled(); cacheStore.removeItem(apiKey, config.contentTypeUid); }); - it('should return cache data when proper network response is not received', async () => { + it("should return cache data when proper network response is not received", async () => { const cacheOptions = { policy: Policy.NETWORK_ELSE_CACHE, maxAge: 3600 }; const defaultAdapter = jest.fn().mockReturnValue({ - foo: 'bar', - baz: 'quux', + foo: "bar", + baz: "quux", }); const cacheStore = new PersistanceStore(cacheOptions); - cacheStore.setItem(apiKey, 'cacheData', config.contentTypeUid, cacheOptions.maxAge); - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + cacheStore.setItem( + apiKey, + "cacheData", + config.contentTypeUid, + cacheOptions.maxAge + ); + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).toHaveBeenCalledWith(config); - expect(resolve).toBeCalledWith({ config: {}, data: 'cacheData', headers: {}, status: 200, statusText: 'OK' }); + expect(resolve).toBeCalledWith({ + config: {}, + data: "cacheData", + headers: {}, + status: 200, + statusText: "OK", + }); expect(reject).not.toBeCalled(); cacheStore.removeItem(apiKey, config.contentTypeUid); }); - it('should return error data when network response has error', async () => { + it("should return error data when network response has error", async () => { const cacheOptions = { policy: Policy.NETWORK_ELSE_CACHE, maxAge: 3600 }; const defaultAdapter = jest.fn().mockReturnValue({ - foo: 'bar', - baz: 'quux', + foo: "bar", + baz: "quux", }); const cacheStore = new PersistanceStore(cacheOptions); - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).toHaveBeenCalledWith(config); expect(resolve).not.toBeCalled(); expect(reject).toBeCalledWith({ - foo: 'bar', - baz: 'quux', + foo: "bar", + baz: "quux", }); cacheStore.removeItem(apiKey, config.contentTypeUid); }); }); - describe('CACHE_THEN_NETWORK policy', () => { - it('should return cache response when proper cache is available then return network response', async () => { + describe("CACHE_THEN_NETWORK policy", () => { + it("should return cache response when proper cache is available then return network response", async () => { const cacheOptions = { policy: Policy.CACHE_THEN_NETWORK, maxAge: 3600 }; - const defaultAdapter = jest.fn((_config) => ({ data: 'foo' })); + const defaultAdapter = jest.fn((_config) => ({ data: "foo" })); const cacheStore = new PersistanceStore(cacheOptions); - cacheStore.setItem(apiKey, 'cacheData', config.contentTypeUid, cacheOptions.maxAge); - - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + cacheStore.setItem( + apiKey, + "cacheData", + config.contentTypeUid, + cacheOptions.maxAge + ); + + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).not.toHaveBeenCalled(); - expect(resolve).toBeCalledWith({ config: {}, data: 'cacheData', headers: {}, status: 200, statusText: 'OK' }); + expect(resolve).toBeCalledWith({ + config: {}, + data: "cacheData", + headers: {}, + status: 200, + statusText: "OK", + }); expect(reject).not.toBeCalled(); cacheStore.removeItem(apiKey, config.contentTypeUid); }); - it('should return api response when proper cache is not available', async () => { + it("should return api response when proper cache is not available", async () => { const cacheOptions = { policy: Policy.CACHE_THEN_NETWORK, maxAge: 3600 }; - const defaultAdapter = jest.fn((_config) => ({ data: JSON.stringify('foo') })); + const defaultAdapter = jest.fn((_config) => ({ + data: JSON.stringify("foo"), + })); const cacheStore = new PersistanceStore(cacheOptions); - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).toHaveBeenCalled(); - expect(resolve).toBeCalledWith({"data": "foo"}); + expect(resolve).toBeCalledWith({ data: "foo" }); expect(reject).not.toBeCalled(); cacheStore.removeItem(apiKey, config.contentTypeUid); }); - it('should return error api response when data is not available in network or cache', async () => { + it("should return error api response when data is not available in network or cache", async () => { const cacheOptions = { policy: Policy.CACHE_THEN_NETWORK, maxAge: 3600 }; const defaultAdapter = jest.fn().mockReturnValue({ - foo: 'bar', - baz: 'quux', + foo: "bar", + baz: "quux", }); const cacheStore = new PersistanceStore(cacheOptions); - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).toHaveBeenCalled(); expect(resolve).not.toBeCalled(); expect(reject).toBeCalledWith({ - foo: 'bar', - baz: 'quux', + foo: "bar", + baz: "quux", }); cacheStore.removeItem(apiKey, config.contentTypeUid); }); }); - describe('CACHE_ELSE_NETWORK policy', () => { - it('should return cache response when proper cache is available', async () => { + describe("CACHE_ELSE_NETWORK policy", () => { + it("should return cache response when proper cache is available", async () => { const cacheOptions = { policy: Policy.CACHE_ELSE_NETWORK, maxAge: 3600 }; - const defaultAdapter = jest.fn((_config) => ({ data: 'foo' })); + const defaultAdapter = jest.fn((_config) => ({ data: "foo" })); const cacheStore = new PersistanceStore(cacheOptions); - cacheStore.setItem(apiKey, 'cacheData', config.contentTypeUid, cacheOptions.maxAge); - - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + cacheStore.setItem( + apiKey, + "cacheData", + config.contentTypeUid, + cacheOptions.maxAge + ); + + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).not.toHaveBeenCalledWith(config); - expect(resolve).toBeCalledWith({ config: {}, data: 'cacheData', headers: {}, status: 200, statusText: 'OK' }); + expect(resolve).toBeCalledWith({ + config: {}, + data: "cacheData", + headers: {}, + status: 200, + statusText: "OK", + }); expect(reject).not.toBeCalled(); cacheStore.removeItem(apiKey, config.contentTypeUid); }); - it('should return network response data when cache is not available', async () => { + it("should return network response data when cache is not available", async () => { const cacheOptions = { policy: Policy.CACHE_ELSE_NETWORK, maxAge: 3600 }; - const defaultAdapter = jest.fn((_config) => ({ data: JSON.stringify('foo') })); + const defaultAdapter = jest.fn((_config) => ({ + data: JSON.stringify("foo"), + })); const cacheStore = new PersistanceStore(cacheOptions); - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).toHaveBeenCalledWith(config); - expect(resolve).toBeCalledWith({"data": "foo"}); + expect(resolve).toBeCalledWith({ data: "foo" }); expect(reject).not.toBeCalled(); cacheStore.removeItem(apiKey, config.contentTypeUid); }); - it('should return error data when network response has error', async () => { + it("should return error data when network response has error", async () => { const cacheOptions = { policy: Policy.CACHE_ELSE_NETWORK, maxAge: 3600 }; const defaultAdapter = jest.fn().mockReturnValue({ - foo: 'bar', - baz: 'quux', + foo: "bar", + baz: "quux", }); const cacheStore = new PersistanceStore(cacheOptions); - await handleRequest(cacheOptions, apiKey, defaultAdapter, resolve, reject, config); + await handleRequest( + cacheOptions, + apiKey, + defaultAdapter, + resolve, + reject, + config + ); expect(defaultAdapter).toHaveBeenCalled(); expect(resolve).not.toBeCalled(); expect(reject).toBeCalledWith({ - foo: 'bar', - baz: 'quux', + foo: "bar", + baz: "quux", }); cacheStore.removeItem(apiKey, config.contentTypeUid); diff --git a/test/unit/contentstack.spec.ts b/test/unit/contentstack.spec.ts index 525258f..2205c66 100644 --- a/test/unit/contentstack.spec.ts +++ b/test/unit/contentstack.spec.ts @@ -1,18 +1,26 @@ -import exp = require('constants'); -import * as core from '@contentstack/core'; -import * as Contentstack from '../../src/lib/contentstack'; -import { Stack } from '../../src/lib/stack'; -import { Policy, Region, StackConfig } from '../../src/lib/types'; -import { CUSTOM_HOST, DUMMY_URL, HOST_EU_REGION, HOST_URL } from '../utils/constant'; -import { AxiosRequestConfig, AxiosResponse } from 'axios'; +import exp = require("constants"); +import * as core from "@contentstack/core"; +import * as Contentstack from "../../src/lib/contentstack"; +import { Stack } from "../../src/lib/stack"; +import { Policy, Region, StackConfig } from "../../src/lib/types"; +import { + CUSTOM_HOST, + DUMMY_URL, + HOST_AU_REGION, + HOST_EU_REGION, + HOST_URL, +} from "../utils/constant"; +import { AxiosRequestConfig, AxiosResponse } from "axios"; -jest.mock('@contentstack/core'); -const createHttpClientMock = >(core.httpClient); +jest.mock("@contentstack/core"); +const createHttpClientMock = >( + (core.httpClient) +); const reqInterceptor = jest.fn(); const resInterceptor = jest.fn(); -describe('Contentstack', () => { +describe("Contentstack", () => { beforeEach(() => createHttpClientMock.mockReturnValue({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -34,70 +42,75 @@ describe('Contentstack', () => { createHttpClientMock.mockReset(); }); - const createStackInstance = (config: StackConfig) => Contentstack.stack(config); + const createStackInstance = (config: StackConfig) => + Contentstack.stack(config); - it('should throw error when api key is empty', (done) => { + it("should throw error when api key is empty", (done) => { const config = { - apiKey: '', - deliveryToken: '', - environment: '', + apiKey: "", + deliveryToken: "", + environment: "", }; - expect(() => createStackInstance(config)).toThrow('API key for Stack is required.'); + expect(() => createStackInstance(config)).toThrow( + "API key for Stack is required." + ); done(); }); - it('should throw error when Delivery Token is empty', (done) => { + it("should throw error when Delivery Token is empty", (done) => { expect(() => { const config = { - apiKey: 'apiKey', - deliveryToken: '', - environment: '', + apiKey: "apiKey", + deliveryToken: "", + environment: "", }; createStackInstance(config); - }).toThrow('Delivery token for Stack is required.'); + }).toThrow("Delivery token for Stack is required."); done(); }); - it('should throw error when Environment is empty', (done) => { + it("should throw error when Environment is empty", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery_token', - environment: '', + apiKey: "apiKey", + deliveryToken: "delivery_token", + environment: "", }; - expect(() => createStackInstance(config)).toThrow('Environment for Stack is required'); + expect(() => createStackInstance(config)).toThrow( + "Environment for Stack is required" + ); done(); }); - it('should create stack instance when the mandatory params are passed', (done) => { + it("should create stack instance when the mandatory params are passed", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", }; const stackInstance = createStackInstance(config); expect(stackInstance).toBeInstanceOf(Stack); done(); }); - it('should create stack instance when the mandatory params are passed', (done) => { + it("should create stack instance when the mandatory params are passed", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', - early_access: ['newCDA', 'taxonomy'], + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", + early_access: ["newCDA", "taxonomy"], }; const stackInstance = createStackInstance(config); expect(stackInstance).toBeInstanceOf(Stack); done(); }); - it('should set defaultHost, header and params when stack instance is created', (done) => { + it("should set defaultHost, header and params when stack instance is created", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', - branch: 'branch', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", + branch: "branch", }; const stackInstance = createStackInstance(config); expect(stackInstance).toBeInstanceOf(Stack); @@ -108,11 +121,11 @@ describe('Contentstack', () => { done(); }); - it('should change default host when host config is passed', (done) => { + it("should change default host when host config is passed", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", host: HOST_EU_REGION, }; const stackInstance = createStackInstance(config); @@ -120,11 +133,23 @@ describe('Contentstack', () => { done(); }); - it('should change the host when custom host config is passed', (done) => { + it("should change default host to AU when AU host config is passed", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", + host: HOST_AU_REGION, + }; + const stackInstance = createStackInstance(config); + expect(stackInstance).toBeInstanceOf(Stack); + done(); + }); + + it("should change the host when custom host config is passed", (done) => { + const config = { + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", host: CUSTOM_HOST, }; const stackInstance = createStackInstance(config); @@ -132,11 +157,11 @@ describe('Contentstack', () => { done(); }); - it('should change default host to config host when region and host in config passed', (done) => { + it("should change default host to config host when region and host in config passed", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", host: DUMMY_URL, region: Region.EU, }; @@ -145,22 +170,22 @@ describe('Contentstack', () => { done(); }); - it('should change default host to EU when EU region in config is passed', (done) => { + it("should change default host to US when US region in config is passed", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", region: Region.US, }; const stackInstance = createStackInstance(config); expect(stackInstance).toBeInstanceOf(Stack); done(); }); - it('should change default host to EU when EU region in config is passed', (done) => { + it("should change default host to EU when EU region in config is passed", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", region: Region.EU, }; const stackInstance = createStackInstance(config); @@ -168,11 +193,23 @@ describe('Contentstack', () => { done(); }); - it('should change default host to azure-na when AZURE_NA region in config is passed', (done) => { + it("should change default host to AU when AU region in config is passed", (done) => { + const config = { + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", + region: Region.AU, + }; + const stackInstance = createStackInstance(config); + expect(stackInstance).toBeInstanceOf(Stack); + done(); + }); + + it("should change default host to azure-na when AZURE_NA region in config is passed", (done) => { const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", region: Region.AZURE_NA, }; @@ -181,17 +218,17 @@ describe('Contentstack', () => { done(); }); - it('should add logHandler', async () => { + it("should add logHandler", async () => { const mockLogHandler = jest.fn(); const config = { - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", region: Region.AZURE_NA, logHandler: mockLogHandler, cacheOptions: { - policy: Policy.IGNORE_CACHE - } + policy: Policy.IGNORE_CACHE, + }, }; const stackInstance = createStackInstance(config); @@ -200,17 +237,16 @@ describe('Contentstack', () => { mockLogHandler.mockReset(); }); - it('should add plugins onRequest and onResponse as req and res interceptors when plugin is passed', (done) => { - + it("should add plugins onRequest and onResponse as req and res interceptors when plugin is passed", (done) => { const mockPlugin = { onRequest: jest.fn((request) => request), onResponse: jest.fn((response) => response), }; const stackInstance = createStackInstance({ - apiKey: 'apiKey', - deliveryToken: 'delivery', - environment: 'env', + apiKey: "apiKey", + deliveryToken: "delivery", + environment: "env", plugins: [mockPlugin], }); diff --git a/test/unit/persistance/local-storage.spec.ts b/test/unit/persistance/local-storage.spec.ts index d5da9c4..434dbfd 100644 --- a/test/unit/persistance/local-storage.spec.ts +++ b/test/unit/persistance/local-storage.spec.ts @@ -1,74 +1,99 @@ -import { iGlobal } from '../../../src/persistance/helper/utils'; -import { localStorage } from '../../../src/persistance/storages/local-storage'; -import { Storage } from '../../../src/persistance/types/storage'; -describe('local store', () => { +import { iGlobal } from "../../../src/persistance/helper/utils"; +import { localStorage } from "../../../src/persistance/storages/local-storage"; +import { Storage } from "../../../src/persistance/types/storage"; + +// Mock localStorage for Node.js environment +const mockLocalStorage = (() => { + let store: { [key: string]: string } = {}; + return { + getItem: (key: string) => store[key] || null, + setItem: (key: string, value: string) => { + store[key] = value; + }, + removeItem: (key: string) => { + delete store[key]; + }, + clear: () => { + store = {}; + }, + get length() { + return Object.keys(store).length; + }, + key: (index: number) => Object.keys(store)[index] || null, + }; +})(); + +describe("local store", () => { let store: Storage; beforeAll(() => { + // Mock localStorage on iGlobal + (iGlobal as any).localStorage = mockLocalStorage; + (iGlobal as any).document = { cookie: "" }; store = localStorage; }); - it('should create store store', () => { - expect(store.name).toEqual('localStorage'); - expect(typeof store.clear).toEqual('function'); - expect(typeof store.each).toEqual('function'); - expect(typeof store.getItem).toEqual('function'); - expect(typeof store.setItem).toEqual('function'); - expect(typeof store.removeItem).toEqual('function'); + it("should create store store", () => { + expect(store.name).toEqual("localStorage"); + expect(typeof store.clear).toEqual("function"); + expect(typeof store.each).toEqual("function"); + expect(typeof store.getItem).toEqual("function"); + expect(typeof store.setItem).toEqual("function"); + expect(typeof store.removeItem).toEqual("function"); }); - it('should set item for key with value', () => { - store.setItem('foo', 'bar'); - expect(store.getItem('foo')).toEqual('bar'); + it("should set item for key with value", () => { + store.setItem("foo", "bar"); + expect(store.getItem("foo")).toEqual("bar"); }); - it('should not blank key', () => { - store.setItem('', 'bar'); - expect(store.getItem('')).toEqual(null); + it("should not blank key", () => { + store.setItem("", "bar"); + expect(store.getItem("")).toEqual(null); }); - it('should remove item for key', () => { - store.removeItem('foo'); - expect(store.getItem('foo')).toEqual(null); + it("should remove item for key", () => { + store.removeItem("foo"); + expect(store.getItem("foo")).toEqual(null); }); - it('should not throw on blank or not present key', () => { - store.removeItem(''); - store.removeItem('foo'); - expect(store.getItem('')).toEqual(null); + it("should not throw on blank or not present key", () => { + store.removeItem(""); + store.removeItem("foo"); + expect(store.getItem("")).toEqual(null); }); - it('should update item for key', () => { - store.setItem('foo', 'bar1'); - store.setItem('foo', 'bar2'); - expect(store.getItem('foo')).toEqual('bar2'); + it("should update item for key", () => { + store.setItem("foo", "bar1"); + store.setItem("foo", "bar2"); + expect(store.getItem("foo")).toEqual("bar2"); }); - it('should contain key value on removed another key', () => { - store.setItem('foo', 'bar'); - store.setItem('bar', 'foo'); - store.removeItem('foo'); - expect(store.getItem('foo')).toEqual(null); - expect(store.getItem('bar')).toEqual('foo'); + it("should contain key value on removed another key", () => { + store.setItem("foo", "bar"); + store.setItem("bar", "foo"); + store.removeItem("foo"); + expect(store.getItem("foo")).toEqual(null); + expect(store.getItem("bar")).toEqual("foo"); }); - it('should not contain key value clear', () => { - store.setItem('foo', 'bar'); - store.setItem('bar', 'foo'); + it("should not contain key value clear", () => { + store.setItem("foo", "bar"); + store.setItem("bar", "foo"); store.clear(); - expect(store.getItem('foo')).toEqual(null); - expect(store.getItem('bar')).toEqual(null); + expect(store.getItem("foo")).toEqual(null); + expect(store.getItem("bar")).toEqual(null); }); - it('should not contain key value clear', () => { - iGlobal.document.cookie = ' = ; path=/'; - store.setItem('foo', 'bar'); - store.setItem('bar', 'foo'); + it("should not contain key value clear", () => { + iGlobal.document.cookie = " = ; path=/"; + store.setItem("foo", "bar"); + store.setItem("bar", "foo"); store.each((_, key) => { - expect(['foo', 'bar'].includes(key)).toBeTruthy(); + expect(["foo", "bar"].includes(key)).toBeTruthy(); }); store.clear(); - expect(store.getItem('foo')).toEqual(null); - expect(store.getItem('bar')).toEqual(null); + expect(store.getItem("foo")).toEqual(null); + expect(store.getItem("bar")).toEqual(null); }); }); diff --git a/test/unit/persistance/preference-store.spec.ts b/test/unit/persistance/preference-store.spec.ts index 40be660..fc3d520 100644 --- a/test/unit/persistance/preference-store.spec.ts +++ b/test/unit/persistance/preference-store.spec.ts @@ -1,42 +1,70 @@ -import { PersistanceStore } from '../../../src/persistance/persistance-store'; -import { StorageType } from '../../../src/persistance/types/storage-type'; -import { memoryStorage } from '../../../src/persistance/storages/memory-storage'; -describe('persistance store intiialization test', () => { - it('should initialize default persistance ', () => { +import { PersistanceStore } from "../../../src/persistance/persistance-store"; +import { StorageType } from "../../../src/persistance/types/storage-type"; +import { memoryStorage } from "../../../src/persistance/storages/memory-storage"; +import { iGlobal } from "../../../src/persistance/helper/utils"; + +// Mock localStorage for Node.js environment +const mockLocalStorage = (() => { + let store: { [key: string]: string } = {}; + return { + getItem: (key: string) => store[key] || null, + setItem: (key: string, value: string) => { + store[key] = value; + }, + removeItem: (key: string) => { + delete store[key]; + }, + clear: () => { + store = {}; + }, + get length() { + return Object.keys(store).length; + }, + key: (index: number) => Object.keys(store)[index] || null, + }; +})(); + +// Setup mock before tests +beforeAll(() => { + (iGlobal as any).localStorage = mockLocalStorage; +}); + +describe("persistence store initialization test", () => { + it("should initialize default persistence ", () => { const persistance = new PersistanceStore(); expect(persistance).toBeDefined(); expect(persistance.config).toBeDefined(); expect(persistance.config.maxAge).toEqual(86400000); - expect(persistance.config.storeType).toEqual('localStorage'); + expect(persistance.config.storeType).toEqual("localStorage"); }); - it('should initialize persistance with name and local storage type ', () => { - const storeType = 'localStorage'; + it("should initialize persistance with name and local storage type ", () => { + const storeType = "localStorage"; const persistance = makePersistance({ storeType }); expect(persistance).toBeDefined(); expect(persistance.config).toBeDefined(); expect(persistance.config.maxAge).toEqual(86400000); expect(persistance.config.storeType).toEqual(storeType); }); - it('should initialize persistance with name and memory storage type ', () => { - const storeType = 'memoryStorage'; + it("should initialize persistance with name and memory storage type ", () => { + const storeType = "memoryStorage"; const persistance = makePersistance({ storeType }); expect(persistance).toBeDefined(); expect(persistance.config).toBeDefined(); expect(persistance.config.maxAge).toEqual(86400000); expect(persistance.config.storeType).toEqual(storeType); }); - it('should initialize persistance with name and local storage type ', () => { - const storeType = 'customStorage'; + it("should initialize persistance with name and local storage type ", () => { + const storeType = "customStorage"; const persistance = makePersistance({ storeType }); expect(persistance).toBeDefined(); expect(persistance.config).toBeDefined(); expect(persistance.config.maxAge).toEqual(86400000); expect(persistance.config.storeType).toEqual(storeType); }); - it('should throw error on custom storage without storage', () => { - const config: any = { name: 'foobar', storeType: 'customStorage' }; - config.storage = ''; + it("should throw error on custom storage without storage", () => { + const config: any = { name: "foobar", storeType: "customStorage" }; + config.storage = ""; const persistance = () => { new PersistanceStore(config); }; @@ -44,124 +72,131 @@ describe('persistance store intiialization test', () => { }); }); -describe('persistance store init', () => { - it('should set max age, serializer and deserializer', () => { +describe("persistance store init", () => { + it("should set max age, serializer and deserializer", () => { const serializer = jest.fn(); const deserializer = jest.fn(); const maxAge = 1000 * 60; - const persistance = new PersistanceStore({ serializer, deserializer, maxAge }); + const persistance = new PersistanceStore({ + serializer, + deserializer, + maxAge, + }); expect(persistance.config.maxAge).toEqual(maxAge); - persistance.config.serializer!('foo'); - persistance.config.deserializer!('foo'); + persistance.config.serializer!("foo"); + persistance.config.deserializer!("foo"); expect(serializer.mock.calls.length).toEqual(1); expect(deserializer.mock.calls.length).toEqual(1); }); }); -describe('persistance functionality', () => { +describe("persistance functionality", () => { const persistance = new PersistanceStore(); - const namespace = 'namespace'; - it('should set item for key with value', () => { - persistance.setItem('foo', 'bar'); - expect(persistance.getItem('foo')).toEqual('bar'); + const namespace = "namespace"; + it("should set item for key with value", () => { + persistance.setItem("foo", "bar"); + expect(persistance.getItem("foo")).toEqual("bar"); }); - it('should not blank key', () => { - persistance.setItem('', 'bar'); - expect(persistance.getItem('')).toEqual(undefined); + it("should not blank key", () => { + persistance.setItem("", "bar"); + expect(persistance.getItem("")).toEqual(undefined); }); - it('should remove item for key', () => { - persistance.setItem('foo', 'bar', namespace); - persistance.removeItem('foo'); - expect(persistance.getItem('foo')).toEqual(undefined); - expect(persistance.getItem('foo', namespace)).toEqual('bar'); + it("should remove item for key", () => { + persistance.setItem("foo", "bar", namespace); + persistance.removeItem("foo"); + expect(persistance.getItem("foo")).toEqual(undefined); + expect(persistance.getItem("foo", namespace)).toEqual("bar"); }); - it('should not throw on blank or not present key', () => { - persistance.removeItem(''); - persistance.removeItem('foo'); - expect(persistance.getItem('')).toEqual(undefined); + it("should not throw on blank or not present key", () => { + persistance.removeItem(""); + persistance.removeItem("foo"); + expect(persistance.getItem("")).toEqual(undefined); }); - it('should update item for key', () => { - persistance.setItem('foo', 'bar1'); - persistance.setItem('foo', 'bar2'); - expect(persistance.getItem('foo')).toEqual('bar2'); - }); - it('should contain key value on removed another key', () => { - persistance.setItem('foo', 'bar'); - persistance.setItem('bar', 'foo'); - persistance.removeItem('foo'); - expect(persistance.getItem('foo')).toEqual(undefined); - expect(persistance.getItem('bar')).toEqual('foo'); - }); - it('should return undefined on expiry', (done) => { - persistance.setItem('foo', 'bar', undefined, 10); + it("should update item for key", () => { + persistance.setItem("foo", "bar1"); + persistance.setItem("foo", "bar2"); + expect(persistance.getItem("foo")).toEqual("bar2"); + }); + it("should contain key value on removed another key", () => { + persistance.setItem("foo", "bar"); + persistance.setItem("bar", "foo"); + persistance.removeItem("foo"); + expect(persistance.getItem("foo")).toEqual(undefined); + expect(persistance.getItem("bar")).toEqual("foo"); + }); + it("should return undefined on expiry", (done) => { + persistance.setItem("foo", "bar", undefined, 10); setTimeout(() => { - expect(persistance.getItem('foo')).toEqual(undefined); + expect(persistance.getItem("foo")).toEqual(undefined); done(); }, 20); }); - it('should allow to set value undefined', () => { - persistance.setItem('foo', 'bar'); - persistance.setItem('foo', undefined); + it("should allow to set value undefined", () => { + persistance.setItem("foo", "bar"); + persistance.setItem("foo", undefined); - expect(persistance.getItem('foo')).toEqual(undefined); + expect(persistance.getItem("foo")).toEqual(undefined); }); - it('should not contain key value clear', () => { - persistance.setItem('foo', 'bar'); - persistance.setItem('bar', 'foo'); + it("should not contain key value clear", () => { + persistance.setItem("foo", "bar"); + persistance.setItem("bar", "foo"); persistance.clear(); - expect(persistance.getItem('foo')).toEqual(undefined); - expect(persistance.getItem('bar')).toEqual(undefined); + expect(persistance.getItem("foo")).toEqual(undefined); + expect(persistance.getItem("bar")).toEqual(undefined); }); }); -describe('persistance with namespace functionality', () => { +describe("persistance with namespace functionality", () => { const persistance = new PersistanceStore(); - const namespace = 'namespace'; + const namespace = "namespace"; - it('should set item for key, value', () => { - persistance.setItem('foo', 'bar', namespace); - expect(persistance.getItem('foo')).toEqual(undefined); - expect(persistance.getItem('foo', namespace)).toEqual('bar'); - }); - it('should remove item for key', () => { - persistance.setItem('foo', 'bar'); - persistance.removeItem('foo', namespace); - expect(persistance.getItem('foo')).toEqual('bar'); - expect(persistance.getItem('foo', namespace)).toEqual(undefined); - }); - it('should update item for key', () => { - persistance.setItem('foo', 'bar1', namespace); - persistance.setItem('foo', 'bar2', namespace); - expect(persistance.getItem('foo', namespace)).toEqual('bar2'); + it("should set item for key, value", () => { + persistance.setItem("foo", "bar", namespace); + expect(persistance.getItem("foo")).toEqual(undefined); + expect(persistance.getItem("foo", namespace)).toEqual("bar"); + }); + it("should remove item for key", () => { + persistance.setItem("foo", "bar"); + persistance.removeItem("foo", namespace); + expect(persistance.getItem("foo")).toEqual("bar"); + expect(persistance.getItem("foo", namespace)).toEqual(undefined); + }); + it("should update item for key", () => { + persistance.setItem("foo", "bar1", namespace); + persistance.setItem("foo", "bar2", namespace); + expect(persistance.getItem("foo", namespace)).toEqual("bar2"); }); - it('should contain key value on removed another key', () => { - persistance.setItem('foo', 'bar', namespace); - persistance.setItem('bar', 'foo', namespace); - persistance.removeItem('foo', namespace); - expect(persistance.getItem('foo', namespace)).toEqual(undefined); - expect(persistance.getItem('bar', namespace)).toEqual('foo'); - }); - it('should not contain key value clear', () => { - persistance.setItem('foo', 'bar', namespace); - persistance.setItem('bar', 'foo', namespace); + it("should contain key value on removed another key", () => { + persistance.setItem("foo", "bar", namespace); + persistance.setItem("bar", "foo", namespace); + persistance.removeItem("foo", namespace); + expect(persistance.getItem("foo", namespace)).toEqual(undefined); + expect(persistance.getItem("bar", namespace)).toEqual("foo"); + }); + it("should not contain key value clear", () => { + persistance.setItem("foo", "bar", namespace); + persistance.setItem("bar", "foo", namespace); persistance.clear(namespace); - expect(persistance.getItem('foo', namespace)).toEqual(undefined); - expect(persistance.getItem('bar', namespace)).toEqual(undefined); + expect(persistance.getItem("foo", namespace)).toEqual(undefined); + expect(persistance.getItem("bar", namespace)).toEqual(undefined); }); }); -describe('persistance with 0 maxAge', () => { - it('should allow max age to be set to 0', () => { +describe("persistance with 0 maxAge", () => { + it("should allow max age to be set to 0", () => { const persistance = new PersistanceStore({ maxAge: 0 }); - persistance.setItem('foo', 'bar'); - expect(persistance.getItem('foo')).toEqual(undefined); + persistance.setItem("foo", "bar"); + expect(persistance.getItem("foo")).toEqual(undefined); }); }); -function makePersistance(config: { storeType: StorageType | 'customStorage' }) { - return new PersistanceStore({ storeType: config.storeType, storage: memoryStorage }); +function makePersistance(config: { storeType: StorageType | "customStorage" }) { + return new PersistanceStore({ + storeType: config.storeType, + storage: memoryStorage, + }); } diff --git a/test/unit/utils.spec.ts b/test/unit/utils.spec.ts index 8adee38..ef2be9b 100644 --- a/test/unit/utils.spec.ts +++ b/test/unit/utils.spec.ts @@ -1,10 +1,18 @@ -import { Region } from '../../src/lib/types'; -import { getHost } from '../../src/lib/utils'; -import { DUMMY_URL, HOST_EU_REGION, HOST_GCP_NA_REGION, HOST_URL, MOCK_CLIENT_OPTIONS, HOST_GCP_EU_REGION } from '../utils/constant'; -import { httpClient, AxiosInstance } from '@contentstack/core'; -import MockAdapter from 'axios-mock-adapter'; -import { assetQueryFindResponseDataMock } from '../utils/mocks'; -import { encodeQueryParams } from '../../src/lib/utils'; +import { Region } from "../../src/lib/types"; +import { getHost } from "../../src/lib/utils"; +import { + DUMMY_URL, + HOST_EU_REGION, + HOST_AU_REGION, + HOST_GCP_NA_REGION, + HOST_URL, + MOCK_CLIENT_OPTIONS, + HOST_GCP_EU_REGION, +} from "../utils/constant"; +import { httpClient, AxiosInstance } from "@contentstack/core"; +import MockAdapter from "axios-mock-adapter"; +import { assetQueryFindResponseDataMock } from "../utils/mocks"; +import { encodeQueryParams } from "../../src/lib/utils"; let client: AxiosInstance; let mockClient: MockAdapter; @@ -14,101 +22,105 @@ beforeAll(() => { mockClient = new MockAdapter(client as any); }); -describe('Utils', () => { - it('should return host when region or host is passed', () => { +describe("Utils", () => { + it("should return EU host when region or host is passed", () => { const url = getHost(Region.EU); expect(url).toEqual(HOST_EU_REGION); }); - it('should return host when region or host is passed', () => { + it("should return AU host when region or host is passed", () => { + const url = getHost(Region.AU); + expect(url).toEqual(HOST_AU_REGION); + }); + it("should return GCP NA host when region or host is passed", () => { const url = getHost(Region.GCP_NA); expect(url).toEqual(HOST_GCP_NA_REGION); }); - it('should return host when region or host is passed', () => { + it("should return GCP EU host when region or host is passed", () => { const url = getHost(Region.GCP_EU); expect(url).toEqual(HOST_GCP_EU_REGION); }); - it('should return proper US region when nothing is passed', () => { + it("should return proper US region when nothing is passed", () => { const url = getHost(); expect(url).toEqual(HOST_URL); }); - it('should return the host url if host is passed instead of region', () => { + it("should return the host url if host is passed instead of region", () => { const host = DUMMY_URL; const url = getHost(Region.US, host); expect(url).toEqual(DUMMY_URL); }); }); -describe('Utils functions', () => { - describe('encodeQueryParams function', () => { - it('should encode special characters in strings', () => { +describe("Utils functions", () => { + describe("encodeQueryParams function", () => { + it("should encode special characters in strings", () => { const testParams = { - simple: 'hello world', - special: 'test & encode + me!', - symbols: 'hello@world.com?param=value', - unicode: 'café français' + simple: "hello world", + special: "test & encode + me!", + symbols: "hello@world.com?param=value", + unicode: "café français", }; const result = encodeQueryParams(testParams); expect(result).toEqual({ - simple: 'hello%20world', - special: 'test%20%26%20encode%20%2B%20me!', - symbols: 'hello%40world.com%3Fparam%3Dvalue', - unicode: 'caf%C3%A9%20fran%C3%A7ais' + simple: "hello%20world", + special: "test%20%26%20encode%20%2B%20me!", + symbols: "hello%40world.com%3Fparam%3Dvalue", + unicode: "caf%C3%A9%20fran%C3%A7ais", }); }); - it('should handle nested objects recursively', () => { + it("should handle nested objects recursively", () => { const testParams = { - title: 'test & title', + title: "test & title", nested: { - name: 'John & Jane', + name: "John & Jane", deeply: { - nested: 'value + with & symbols' - } - } + nested: "value + with & symbols", + }, + }, }; const result = encodeQueryParams(testParams); expect(result).toEqual({ - title: 'test%20%26%20title', + title: "test%20%26%20title", nested: { - name: 'John%20%26%20Jane', + name: "John%20%26%20Jane", deeply: { - nested: 'value%20%2B%20with%20%26%20symbols' - } - } + nested: "value%20%2B%20with%20%26%20symbols", + }, + }, }); }); - it('should preserve non-string primitive values', () => { + it("should preserve non-string primitive values", () => { const testParams = { - stringValue: 'encode me', + stringValue: "encode me", numberValue: 42, booleanTrue: true, booleanFalse: false, nullValue: null, - undefinedValue: undefined + undefinedValue: undefined, }; const result = encodeQueryParams(testParams); expect(result).toEqual({ - stringValue: 'encode%20me', + stringValue: "encode%20me", numberValue: 42, booleanTrue: true, booleanFalse: false, nullValue: null, - undefinedValue: undefined + undefinedValue: undefined, }); }); - it('should handle arrays correctly', () => { + it("should handle arrays correctly", () => { const testParams = { - tags: ['tech & innovation', 'development + coding'], - categories: ['news', 'tech'] + tags: ["tech & innovation", "development + coding"], + categories: ["news", "tech"], }; const result = encodeQueryParams(testParams); @@ -118,12 +130,12 @@ describe('Utils functions', () => { expect(result.categories).toBeDefined(); }); - it('should handle empty objects and special values', () => { + it("should handle empty objects and special values", () => { const testParams = { empty: {}, nullValue: null, - emptyString: '', - whitespace: ' ' + emptyString: "", + whitespace: " ", }; const result = encodeQueryParams(testParams); @@ -131,8 +143,8 @@ describe('Utils functions', () => { expect(result).toEqual({ empty: {}, nullValue: null, - emptyString: '', - whitespace: '%20%20%20' + emptyString: "", + whitespace: "%20%20%20", }); }); }); diff --git a/test/utils/constant.ts b/test/utils/constant.ts index 6d58e0b..5a667d7 100644 --- a/test/utils/constant.ts +++ b/test/utils/constant.ts @@ -1,9 +1,13 @@ -export const HOST_URL = 'cdn.contentstack.io'; -export const LOCALE = 'en-155'; -export const CUSTOM_HOST = 'example-cdn.csnonprod.com'; -export const HOST_EU_REGION = 'eu-cdn.contentstack.com'; -export const HOST_AZURE_NA_REGION = 'azure-na-cdn.contentstack.com'; -export const HOST_GCP_NA_REGION = 'gcp-na-cdn.contentstack.com'; -export const HOST_GCP_EU_REGION = 'gcp-eu-cdn.contentstack.com'; -export const DUMMY_URL = 'www.example.com'; -export const MOCK_CLIENT_OPTIONS = { defaultHostname: HOST_URL, params: { environment: 'env' } }; +export const HOST_URL = "cdn.contentstack.io"; +export const LOCALE = "en-155"; +export const CUSTOM_HOST = "example-cdn.csnonprod.com"; +export const HOST_EU_REGION = "eu-cdn.contentstack.com"; +export const HOST_AU_REGION = "au-cdn.contentstack.com"; +export const HOST_AZURE_NA_REGION = "azure-na-cdn.contentstack.com"; +export const HOST_GCP_NA_REGION = "gcp-na-cdn.contentstack.com"; +export const HOST_GCP_EU_REGION = "gcp-eu-cdn.contentstack.com"; +export const DUMMY_URL = "www.example.com"; +export const MOCK_CLIENT_OPTIONS = { + defaultHostname: HOST_URL, + params: { environment: "env" }, +};