sfcc-dev-mcp
Version:
MCP server for Salesforce B2C Commerce Cloud development assistance including logs, debugging, and development tools
311 lines (250 loc) • 10.9 kB
text/typescript
/**
* Tests for OCAPISystemObjectsClient
* Tests system objects operations
*/
import { OCAPISystemObjectsClient } from '../src/clients/ocapi/system-objects-client.js';
import { OCAPIConfig } from '../src/types/types.js';
import { QueryBuilder } from '../src/utils/query-builder.js';
import { Validator } from '../src/utils/validator.js';
// Mock dependencies
jest.mock('../src/clients/base/ocapi-auth-client.js');
jest.mock('../src/utils/query-builder.js');
jest.mock('../src/utils/validator.js');
describe('OCAPISystemObjectsClient', () => {
let client: OCAPISystemObjectsClient;
let mockValidateRequired: jest.MockedFunction<typeof Validator.validateRequired>;
let mockValidateObjectType: jest.MockedFunction<typeof Validator.validateObjectType>;
let mockValidateSearchRequest: jest.MockedFunction<typeof Validator.validateSearchRequest>;
let mockQueryBuilderFromObject: jest.MockedFunction<typeof QueryBuilder.fromObject>;
const mockConfig: OCAPIConfig = {
hostname: 'test-instance.demandware.net',
clientId: 'test-client-id',
clientSecret: 'test-client-secret',
version: 'v21_3',
};
beforeEach(() => {
jest.clearAllMocks();
// Mock Validator methods
mockValidateRequired = Validator.validateRequired as jest.MockedFunction<typeof Validator.validateRequired>;
mockValidateObjectType = Validator.validateObjectType as jest.MockedFunction<typeof Validator.validateObjectType>;
mockValidateSearchRequest = Validator.validateSearchRequest as jest.MockedFunction<
typeof Validator.validateSearchRequest
>;
// Reset mock implementations to default behavior
mockValidateRequired.mockImplementation(() => {});
mockValidateObjectType.mockImplementation(() => {});
mockValidateSearchRequest.mockImplementation(() => {});
// Mock QueryBuilder
mockQueryBuilderFromObject = QueryBuilder.fromObject as jest.MockedFunction<typeof QueryBuilder.fromObject>;
client = new OCAPISystemObjectsClient(mockConfig);
// Mock the inherited methods by adding them as properties - avoid protected access
(client as any).get = jest.fn().mockResolvedValue({ data: 'mocked' });
(client as any).post = jest.fn().mockResolvedValue({ data: 'mocked' });
});
describe('constructor', () => {
it('should initialize with correct base URL', () => {
expect(client).toBeInstanceOf(OCAPISystemObjectsClient);
});
it('should use default version when not provided', () => {
const configWithoutVersion = {
hostname: 'test.demandware.net',
clientId: 'client-id',
clientSecret: 'client-secret',
};
const clientWithDefaults = new OCAPISystemObjectsClient(configWithoutVersion);
expect(clientWithDefaults).toBeInstanceOf(OCAPISystemObjectsClient);
});
});
describe('getSystemObjectDefinitions', () => {
it('should make GET request to system_object_definitions endpoint', async () => {
await client.getSystemObjectDefinitions();
expect((client as any).get).toHaveBeenCalledWith('/system_object_definitions');
});
it('should include query parameters when provided', async () => {
const params = { start: 0, count: 10, select: '(**)' };
mockQueryBuilderFromObject.mockReturnValue('start=0&count=10&select=%28%2A%2A%29');
await client.getSystemObjectDefinitions(params);
expect(QueryBuilder.fromObject).toHaveBeenCalledWith(params);
expect((client as any).get).toHaveBeenCalledWith('/system_object_definitions?start=0&count=10&select=%28%2A%2A%29');
});
it('should not include query string when no parameters provided', async () => {
mockQueryBuilderFromObject.mockReturnValue('');
await client.getSystemObjectDefinitions({});
expect((client as any).get).toHaveBeenCalledWith('/system_object_definitions');
});
});
describe('getSystemObjectDefinition', () => {
it('should validate required parameters', async () => {
const objectType = 'Product';
await client.getSystemObjectDefinition(objectType);
expect(Validator.validateRequired).toHaveBeenCalledWith({ objectType }, ['objectType']);
expect(Validator.validateObjectType).toHaveBeenCalledWith(objectType);
});
it('should make GET request with encoded object type', async () => {
const objectType = 'Custom Object';
await client.getSystemObjectDefinition(objectType);
expect((client as any).get).toHaveBeenCalledWith('/system_object_definitions/Custom%20Object');
});
it('should handle special characters in object type', async () => {
const objectType = 'Product/Variant';
await client.getSystemObjectDefinition(objectType);
expect((client as any).get).toHaveBeenCalledWith('/system_object_definitions/Product%2FVariant');
});
});
describe('searchSystemObjectDefinitions', () => {
it('should validate search request', async () => {
const searchRequest = {
query: {
text_query: {
fields: ['id', 'display_name'],
search_phrase: 'product',
},
},
};
await client.searchSystemObjectDefinitions(searchRequest);
expect(Validator.validateSearchRequest).toHaveBeenCalledWith(searchRequest);
});
it('should make POST request to system object definition search endpoint', async () => {
const searchRequest = {
query: {
text_query: {
fields: ['id', 'display_name'],
search_phrase: 'product',
},
},
};
await client.searchSystemObjectDefinitions(searchRequest);
expect((client as any).post).toHaveBeenCalledWith('/system_object_definition_search', searchRequest);
});
});
describe('searchSystemObjectAttributeDefinitions', () => {
it('should validate all required parameters', async () => {
const objectType = 'Product';
const searchRequest = {
query: {
text_query: {
fields: ['id', 'display_name'],
search_phrase: 'custom',
},
},
};
await client.searchSystemObjectAttributeDefinitions(objectType, searchRequest);
expect(Validator.validateRequired).toHaveBeenCalledWith({ objectType }, ['objectType']);
expect(Validator.validateObjectType).toHaveBeenCalledWith(objectType);
expect(Validator.validateSearchRequest).toHaveBeenCalledWith(searchRequest);
});
it('should make POST request to attribute definition search endpoint', async () => {
const objectType = 'Product';
const searchRequest = {
query: {
text_query: {
fields: ['id', 'display_name'],
search_phrase: 'custom',
},
},
};
await client.searchSystemObjectAttributeDefinitions(objectType, searchRequest);
expect((client as any).post).toHaveBeenCalledWith('/system_object_definitions/Product/attribute_definition_search', searchRequest);
});
});
describe('searchSystemObjectAttributeGroups', () => {
it('should validate all required parameters', async () => {
const objectType = 'SitePreferences';
const searchRequest = {
query: { match_all_query: {} },
};
await client.searchSystemObjectAttributeGroups(objectType, searchRequest);
expect(Validator.validateRequired).toHaveBeenCalledWith({ objectType }, ['objectType']);
expect(Validator.validateObjectType).toHaveBeenCalledWith(objectType);
expect(Validator.validateSearchRequest).toHaveBeenCalledWith(searchRequest);
});
it('should make POST request to attribute group search endpoint', async () => {
const objectType = 'SitePreferences';
const searchRequest = {
query: {
text_query: {
fields: ['id', 'display_name'],
search_phrase: 'general',
},
},
sorts: [{ field: 'position', sort_order: 'asc' as const }],
};
await client.searchSystemObjectAttributeGroups(objectType, searchRequest);
expect((client as any).post).toHaveBeenCalledWith(
'/system_object_definitions/SitePreferences/attribute_group_search',
searchRequest,
);
});
});
describe('error handling', () => {
it('should propagate validation errors', async () => {
const validationError = new Error('Validation failed');
mockValidateRequired.mockImplementation(() => {
throw validationError;
});
await expect(client.getSystemObjectDefinition('Product')).rejects.toThrow(validationError);
});
it('should propagate HTTP errors from base client', async () => {
const httpError = new Error('HTTP request failed');
(client as any).get = jest.fn().mockRejectedValue(httpError);
await expect(client.getSystemObjectDefinitions()).rejects.toThrow(httpError);
});
it('should propagate search validation errors', async () => {
const searchValidationError = new Error('Invalid search request');
mockValidateSearchRequest.mockImplementation(() => {
throw searchValidationError;
});
const searchRequest = { query: {} };
await expect(client.searchSystemObjectDefinitions(searchRequest)).rejects.toThrow(searchValidationError);
});
});
describe('integration scenarios', () => {
it('should handle complex search with all options', async () => {
const objectType = 'Product';
const searchRequest = {
query: {
bool_query: {
must: [
{
text_query: {
fields: ['id'],
search_phrase: 'custom',
},
},
],
must_not: [
{
term_query: {
fields: ['system'],
operator: 'is',
values: [true],
},
},
],
},
},
sorts: [
{ field: 'display_name', sort_order: 'asc' as const },
{ field: 'id' },
],
start: 10,
count: 25,
select: '(**)',
};
await client.searchSystemObjectAttributeDefinitions(objectType, searchRequest);
expect(Validator.validateRequired).toHaveBeenCalled();
expect(Validator.validateObjectType).toHaveBeenCalled();
expect(Validator.validateSearchRequest).toHaveBeenCalledWith(searchRequest);
expect((client as any).post).toHaveBeenCalledWith(
'/system_object_definitions/Product/attribute_definition_search',
searchRequest,
);
});
it('should handle empty query parameters gracefully', async () => {
const params = {};
mockQueryBuilderFromObject.mockReturnValue('');
await client.getSystemObjectDefinitions(params);
expect((client as any).get).toHaveBeenCalledWith('/system_object_definitions');
});
});
});