Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,34 @@ tap-html.html
coverage
.env
.dccache
dist/*
dist/
.idea/
.vscode/
*.swp
*.swo
*~
.cache
test-results/

# Build artifacts (should only be in dist/)
src/**/*.js
src/**/*.js.map

# Browser test bundle (generated)
test/e2e/sdk-browser-bundle.js
test/e2e/sdk-browser-bundle.js.map
docs
reports

# Bundler test artifacts (regenerated on test run)
test/bundlers/**/.next/
test/bundlers/**/dist/
test/bundlers/**/node_modules/
test/bundlers/**/package-lock.json

# Temporary internal scripts
test/docs/*.js
test/docs/*.mjs
test/docs/sanity-report*
*.log
.nx/
52 changes: 51 additions & 1 deletion .talismanrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
fileignoreconfig:
- filename: test/browser/import.spec.ts
checksum: 2e9a157e28b0ce71c4b6422c6b457996a2e6785a1ef591c8bb35276b3471a5d0
- filename: scripts/test-bundlers.js
checksum: 4a85cdc2f456d2f9d64d96eedaeddd34f192f243f352132957b1a9c0e979d635
- filename: test/browser/helpers/browser-stack-instance.ts
checksum: 333fdbd1229022736e6e3262c7f275cb22534ec149d4e9a8270f0745b60d8661
- filename: scripts/validate-browser-safe.js
checksum: 769b95cf55a6cf8455d057a662a8071286faf62a75862e3317d79367fe1ed5b4
- filename: test/browser/initialization.spec.ts
checksum: 4054847ebfcc980299240a27d0aa30c1f43a9482e6ba39ac0af6126e7db9e04a
- filename: test/e2e/browser-integration.spec.ts
checksum: 6646595d48bfaec3d9de111b22b36cf0925b33e18df55b068181c0bb81c1862b
- filename: test/browser/real-api-calls.spec.ts
checksum: 514930cdde28cdc8b37ab054031260d5703dc8bdf777906dd5f9baa270ab7c3a
- filename: package-lock.json
checksum: cb21e1b4fc8240b8ee33c6f974a9d1cf25d96afb9161c85633cbb061f069bbc4
- filename: test/api/live-preview-comprehensive.spec.ts
checksum: fe961d576a31f1ea502ecd10c890a78b77b6f3019dd810dd3be914e6abf298dd
ignore_detectors: [ base64 ]
- filename: test/unit/contentstack.spec.ts
checksum: d5b99c01459ab8bc597baaa9e6cc4aa91ac6d9bf78af08e1d0220d0c5db3d0b3
- filename: test/unit/utils.spec.ts
Expand All @@ -19,4 +36,37 @@ fileignoreconfig:
checksum: dc07b0a8111fd8e155b99f56c31ccdddd4f46c86f1b162b17d73e15dfed8e3c8
- filename: test/unit/retry-configuration.spec.ts
checksum: 359c8601c6205a65f3395cc209a93b278dfe7f5bb547c91b2eeab250b2c85aa3
version: ""
- filename: package-lock.json
checksum: 993afd503e9f5d399fac30ae230cb47538cec2c61c5364e88be72726fb723dda
ignore_detectors: [ base64, filecontent ]
- filename: src/lib/global-field.ts
checksum: 70b9652bcba16ddc4d853ac212ad909a8ecfc76f491c55a05e4e3cdf9ce476b5
- filename: src/lib/content-type.ts
checksum: 1dc0fa53ae209efb67d68a01493822e9dec560799f8309329213dae69459655f
- filename: src/lib/stack.ts
checksum: 145dd6add876a771a9a6ba024f57ef2c4b46a911fe1bf3885a69cf1f6c9dd72d
- filename: src/lib/entry.ts
checksum: 1c64ccf19226873d068d6896028bfb74546c1cfd993779515bccfcc747180ca0
- filename: src/lib/error-messages.ts
checksum: 3b960af19f3ba302522e912616b147b11d63dfe3f7ad2e0cf2de807815ee236a
- filename: src/lib/global-field-query.ts
checksum: 824c54061b80236380e776640e7f52f45164230bcc0ee88de302b30e9f83297f
- filename: src/lib/base-query.ts
checksum: 8d67435121581d43ba9c5f544daf30a0579b7faa7c8661000d8d37ddfc172112
- filename: test/unit/base-query.spec.ts
checksum: ceaceb1d65965b151edc9fc11d5a226460328b1913319994df51ca1b453cd6af
- filename: src/lib/entries.ts
checksum: 3ffe426234ef710d0fcfd8e41ca57f61ce6bc44298ee7dde6f4530fa3c16d2ee
- filename: test/unit/error-messages.spec.ts
checksum: b64be136b19890aa9e9000bac7df6eb1188828ee4b740d5c756396699716c428
- filename: test/api/modular-blocks.spec.ts
checksum: 1e536b0409f05f2d5c1d6e87b0ec4bda2c3fde9bc4ff331406f33464a26cff55
- filename: test/unit/centralized-error-handling.spec.ts
checksum: 66a5eb520414bd71da331338bfb4faa2fc9f233eadf0eb18ddd7915db6849238
- filename: src/lib/query.ts
checksum: f7200cb6e3b9ff681439482faaf882781dfb5f6ab6fefd4c98203ba8bf30d5e6
- filename: test/api/base-query-casting.specs.ts
checksum: 9185df498914e2966d78d9d216acaaa910d43cd7ac9a5e9a26e7241ac9edc9b5
- filename: test/reporting/generate-unified-report.js
checksum: 9e7a4696561b790cb93f3be8406a70ec6fdc90a3f8bbb9739504495690158fe3
version: "1.0"
68 changes: 68 additions & 0 deletions jest.config.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable */
/**
* Browser Environment Jest Configuration
*
* Purpose: Test SDK in browser-like environment (jsdom) to catch Node.js-only API usage
* This configuration will FAIL if code tries to use: fs, path, crypto, etc.
*/
export default {
displayName: "browser-environment",
preset: "./jest.preset.js",

// ⚠️ CRITICAL: Use jsdom (browser) instead of node environment
testEnvironment: "jest-environment-jsdom",

// Only run browser-specific tests
testMatch: ["**/test/browser/**/*.spec.ts"],

transform: {
"^.+\\.[tj]s$": [
"ts-jest",
{
tsconfig: {
// Browser-only libs
lib: ["dom", "dom.iterable", "es2020"],
// Include jest types for test files
types: ["jest", "@types/node"],
target: "es2020",
module: "commonjs",
esModuleInterop: true,
skipLibCheck: true
},
diagnostics: {
warnOnly: true
}
},
],
},

moduleFileExtensions: ["ts", "js", "html"],

// Browser globals (available in jsdom)
setupFilesAfterEnv: ['<rootDir>/jest.setup.browser.ts'],

// Collect coverage separately for browser tests
collectCoverage: true,
coverageDirectory: "./reports/browser-environment/coverage/",
collectCoverageFrom: ["src/**/*.ts", "!src/**/*.spec.ts", "!src/index.ts"],

// Timeout for browser environment tests
testTimeout: 10000,

// Don't mock Node.js modules globally - let natural browser environment catch issues
// moduleNameMapper: {},

reporters: [
"default",
[
"jest-html-reporter",
{
pageTitle: "Browser Environment Test Report",
outputPath: "reports/browser-environment/index.html",
includeFailureMsg: true,
includeConsoleLog: true,
},
],
],
};

17 changes: 17 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ export default {
// branches: 95,
// }
},
// Use single worker to avoid circular JSON serialization issues with error objects
// This prevents "Jest worker encountered 4 child process exceptions" errors
maxWorkers: 1,
// Increase timeout for integration tests that may take longer
testTimeout: 30000,
// Global setup file to suppress expected SDK validation errors
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
reporters: [
"default",
[
Expand All @@ -36,6 +43,9 @@ export default {
publicPath: "./reports/contentstack-delivery/html",
filename: "index.html",
expand: true,
// Enable console log capture in reports
enableMergeData: true,
dataMergeLevel: 2,
},
],
[
Expand All @@ -50,5 +60,12 @@ export default {
titleTemplate: "{title}",
},
],
// JSON reporter to capture console logs for unified report
[
"./test/reporting/jest-json-reporter.cjs",
{
outputPath: "test-results/jest-results.json",
},
],
],
};
18 changes: 15 additions & 3 deletions jest.preset.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
import nxPreset from '@nrwl/jest/preset/index.js';

export default { ...nxPreset };
export default {
testEnvironment: 'node',
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
transform: {
'^.+\\.ts$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'js', 'json'],
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!src/index.ts',
],
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
};
63 changes: 63 additions & 0 deletions jest.setup.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Browser Environment Test Setup
*
* Sets up browser-like globals and polyfills for testing
*/

// jsdom provides fetch natively in newer versions
// No need to import node-fetch

// Suppress expected console errors during tests
const originalError = console.error;
const originalWarn = console.warn;

beforeAll(() => {
console.error = (...args: any[]) => {
// Suppress specific expected errors
const message = args[0]?.toString() || '';
if (
message.includes('Not implemented: HTMLFormElement.prototype.submit') ||
message.includes('Not implemented: navigation')
) {
return;
}
originalError.call(console, ...args);
};

console.warn = (...args: any[]) => {
// Suppress specific expected warnings
const message = args[0]?.toString() || '';
if (message.includes('jsdom')) {
return;
}
originalWarn.call(console, ...args);
};
});

afterAll(() => {
console.error = originalError;
console.warn = originalWarn;
});

// Add custom matchers for browser testing if needed
expect.extend({
toBeBrowserSafe(received: any) {
const forbidden = ['fs', 'path', 'crypto', 'Buffer', 'process'];
const receivedString = JSON.stringify(received);

for (const api of forbidden) {
if (receivedString.includes(api)) {
return {
pass: false,
message: () => `Expected code to be browser-safe, but found Node.js API: ${api}`,
};
}
}

return {
pass: true,
message: () => 'Code is browser-safe',
};
},
});

104 changes: 104 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* Global Jest Setup File
*
* 1. Captures console logs for test reports
* 2. Suppresses expected SDK validation errors to reduce console noise during tests.
*/
import * as fs from 'fs';
import * as path from 'path';

// Store captured console logs
interface ConsoleLog {
type: 'log' | 'warn' | 'error' | 'info' | 'debug';
message: string;
timestamp: string;
testFile?: string;
}

declare global {
var __CONSOLE_LOGS__: ConsoleLog[];
var __CURRENT_TEST_FILE__: string;
}

// Initialize global console log storage
global.__CONSOLE_LOGS__ = [];
global.__CURRENT_TEST_FILE__ = '';

// Store original console methods
const originalConsole = {
log: console.log,
warn: console.warn,
error: console.error,
info: console.info,
debug: console.debug
};

// List of expected SDK validation errors to suppress
const expectedErrors = [
'Invalid key:', // From query.search() validation
'Invalid value (expected string or number):', // From query.equalTo() validation
'Argument should be a String or an Array.', // From entry/entries.includeReference() validation
'Invalid fieldUid:', // From asset query validation
];

// Helper to capture and optionally forward console output
function captureConsole(type: 'log' | 'warn' | 'error' | 'info' | 'debug') {
return (...args: any[]) => {
const message = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
).join(' ');

// Store the log
global.__CONSOLE_LOGS__.push({
type,
message,
timestamp: new Date().toISOString(),
testFile: global.__CURRENT_TEST_FILE__
});

// For errors, check if it's expected (suppress if so)
if (type === 'error') {
const isExpectedError = expectedErrors.some(pattern => message.includes(pattern));
if (!isExpectedError) {
originalConsole[type].apply(console, args);
}
} else {
// Forward other logs normally
originalConsole[type].apply(console, args);
}
};
}

// Override console methods to capture logs
console.log = captureConsole('log');
console.warn = captureConsole('warn');
console.error = captureConsole('error');
console.info = captureConsole('info');
console.debug = captureConsole('debug');

// After all tests complete, write logs to file
afterAll(() => {
const logsPath = path.resolve(__dirname, 'test-results', 'console-logs.json');
const logsDir = path.dirname(logsPath);

if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir, { recursive: true });
}

// Append to existing logs (in case of multiple test files)
let existingLogs: ConsoleLog[] = [];
if (fs.existsSync(logsPath)) {
try {
existingLogs = JSON.parse(fs.readFileSync(logsPath, 'utf8'));
} catch {
existingLogs = [];
}
}

const allLogs = [...existingLogs, ...global.__CONSOLE_LOGS__];
fs.writeFileSync(logsPath, JSON.stringify(allLogs, null, 2));

// Clear for next file
global.__CONSOLE_LOGS__ = [];
});

Loading