Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(headless): add schema validation in engine configuration for analytics.trackingId #4853

Merged
merged 9 commits into from
Jan 20, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,63 @@ describe('buildCaseAssistEngine', () => {
initEngine();
});

describe('validating the basic configuration', () => {
it('passing an empty organizationId throws', () => {
options.configuration.organizationId = '';
expect(() => initEngine()).toThrow();
});

it('passing an empty accessToken throws', () => {
options.configuration.accessToken = '';
expect(initEngine).toThrow();
});

it('passing an empty name throws', () => {
options.configuration.name = '';
expect(initEngine).toThrow();
});
});

describe('validating the analytics configuration', () => {
it('passing a non-URL proxyBaseUrl throws', () => {
options.configuration.analytics = {
proxyBaseUrl: 'foo',
};
expect(() => initEngine()).toThrow();
});

it('passing a URL proxyBaseUrl does not throw', () => {
options.configuration.analytics = {
proxyBaseUrl: 'https://example.com/analytics',
};
expect(() => initEngine()).not.toThrow();
});

it('passing a trackingId containing 100 valid characters or less does not throw', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHI',
};
expect(initEngine).not.toThrow();
});

it('passing a trackingId containing 101 valid characters or more throws', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJ',
};
expect(initEngine).toThrow();
});

it('passing trackingId containing an invalid character throws', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.\\',
};
expect(initEngine).toThrow();
});
});

it('passing an invalid case assist ID throws', () => {
options.configuration.caseAssistId = '';
expect(initEngine).toThrow();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import {CartInitialState} from '../../controllers/commerce/context/cart/headless
import {ContextOptions} from '../../controllers/commerce/context/headless-context.js';
import {cartDefinition} from '../../features/commerce/context/cart/cart-validation.js';
import {contextDefinition} from '../../features/commerce/context/context-validation.js';
import {
nonEmptyString,
requiredNonEmptyString,
} from '../../utils/validate-payload.js';
import {nonEmptyString} from '../../utils/validate-payload.js';
import {
AnalyticsConfiguration,
EngineConfiguration,
Expand Down Expand Up @@ -58,7 +55,11 @@ export const commerceEngineConfigurationSchema =
'@coveo/quantic': nonEmptyString,
},
}),
trackingId: requiredNonEmptyString,
trackingId: new StringValue({
required: true,
emptyAllowed: false,
regex: /^[a-zA-Z0-9_\-.]{1,100}$/,
}),
},
}),
context: new RecordValue({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,58 @@ describe('buildCommerceEngine', () => {
expect(engine[stateKey]).toBeTruthy();
});

describe('validating the basic configuration', () => {
it('passing an empty organizationId throws', () => {
options.configuration.organizationId = '';
expect(() => initEngine()).toThrow();
});

it('passing an empty accessToken throws', () => {
options.configuration.accessToken = '';
expect(initEngine).toThrow();
});

it('passing an empty name throws', () => {
options.configuration.name = '';
expect(initEngine).toThrow();
});
});

describe('validating the analytics configuration', () => {
it('passing a non-URL proxyBaseUrl throws', () => {
options.configuration.analytics.proxyBaseUrl = 'foo';

expect(() => initEngine()).toThrow();
});

it('passing a URL proxyBaseUrl does not throw', () => {
options.configuration.analytics.proxyBaseUrl =
'https://example.com/analytics';

expect(() => initEngine()).not.toThrow();
});

it('passing a trackingId containing 100 valid characters or less does not throw', () => {
options.configuration.analytics.trackingId =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHI';

expect(initEngine).not.toThrow();
});

it('passing a trackingId containing 101 valid characters or more throws', () => {
options.configuration.analytics.trackingId =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJ';
expect(initEngine).toThrow();
});

it('passing trackingId containing an invalid character throws', () => {
options.configuration.analytics.trackingId =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.\\';

expect(initEngine).toThrow();
});
});

it('when #proxyBaseUrl is specified in the configuration, sets the #commerce.apiBaseUrl', () => {
options.configuration.proxyBaseUrl = 'https://example.com/commerce';
initEngine();
Expand Down
5 changes: 5 additions & 0 deletions packages/headless/src/app/engine-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ export const engineConfigurationDefinitions: SchemaDefinition<EngineConfiguratio
required: false,
url: true,
}),
trackingId: new StringValue({
required: false,
emptyAllowed: false,
regex: /^[a-zA-Z0-9_\-.]{1,100}$/,
}),
},
}),
environment: new StringValue<PlatformEnvironment>({
Expand Down
57 changes: 57 additions & 0 deletions packages/headless/src/app/insight-engine/insight-engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,63 @@ describe('buildInsightEngine', () => {
initEngine();
});

describe('validating the basic configuration', () => {
it('passing an empty organizationId throws', () => {
options.configuration.organizationId = '';
expect(() => initEngine()).toThrow();
});

it('passing an empty accessToken throws', () => {
options.configuration.accessToken = '';
expect(initEngine).toThrow();
});

it('passing an empty name throws', () => {
options.configuration.name = '';
expect(initEngine).toThrow();
});
});

describe('validating the analytics configuration', () => {
it('passing a non-URL proxyBaseUrl throws', () => {
options.configuration.analytics = {
proxyBaseUrl: 'foo',
};
expect(() => initEngine()).toThrow();
});

it('passing a URL proxyBaseUrl does not throw', () => {
options.configuration.analytics = {
proxyBaseUrl: 'https://example.com/analytics',
};
expect(() => initEngine()).not.toThrow();
});

it('passing a trackingId containing 100 valid characters or less does not throw', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHI',
};
expect(initEngine).not.toThrow();
});

it('passing a trackingId containing 101 valid characters or more throws', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJ',
};
expect(initEngine).toThrow();
});

it('passing trackingId containing an invalid character throws', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.\\',
};
expect(initEngine).toThrow();
});
});

it('passing an invalid insight ID throws', () => {
options.configuration.insightId = '';
expect(initEngine).toThrow();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,63 @@ describe('buildRecommendationEngine', () => {
initEngine();
});

describe('validating the basic configuration', () => {
it('passing an empty organizationId throws', () => {
options.configuration.organizationId = '';
expect(() => initEngine()).toThrow();
});

it('passing an empty accessToken throws', () => {
options.configuration.accessToken = '';
expect(initEngine).toThrow();
});

it('passing an empty name throws', () => {
options.configuration.name = '';
expect(initEngine).toThrow();
});
});

describe('validating the analytics configuration', () => {
it('passing a non-URL proxyBaseUrl throws', () => {
options.configuration.analytics = {
proxyBaseUrl: 'foo',
};
expect(() => initEngine()).toThrow();
});

it('passing a URL proxyBaseUrl does not throw', () => {
options.configuration.analytics = {
proxyBaseUrl: 'https://example.com/analytics',
};
expect(() => initEngine()).not.toThrow();
});

it('passing a trackingId containing 100 valid characters or less does not throw', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHI',
};
expect(initEngine).not.toThrow();
});

it('passing a trackingId containing 101 valid characters or more throws', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJ',
};
expect(initEngine).toThrow();
});

it('passing trackingId containing an invalid character throws', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.\\',
};
expect(initEngine).toThrow();
});
});

it('passing an invalid searchHub throws', () => {
options.configuration.searchHub = '';
expect(initEngine).toThrow();
Expand Down
57 changes: 57 additions & 0 deletions packages/headless/src/app/search-engine/search-engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,63 @@ describe('searchEngine', () => {
initEngine();
});

describe('validating the basic configuration', () => {
it('passing an empty organizationId throws', () => {
options.configuration.organizationId = '';
expect(() => initEngine()).toThrow();
});

it('passing an empty accessToken throws', () => {
options.configuration.accessToken = '';
expect(initEngine).toThrow();
});

it('passing an empty name throws', () => {
options.configuration.name = '';
expect(initEngine).toThrow();
});
});

describe('validating the analytics configuration', () => {
it('passing a non-URL proxyBaseUrl throws', () => {
options.configuration.analytics = {
proxyBaseUrl: 'foo',
};
expect(() => initEngine()).toThrow();
});

it('passing a URL proxyBaseUrl does not throw', () => {
options.configuration.analytics = {
proxyBaseUrl: 'https://example.com/analytics',
};
expect(() => initEngine()).not.toThrow();
});

it('passing a trackingId containing 100 valid characters or less does not throw', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHI',
};
expect(initEngine).not.toThrow();
});

it('passing a trackingId containing 101 valid characters or more throws', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJ',
};
expect(initEngine).toThrow();
});

it('passing trackingId containing an invalid character throws', () => {
options.configuration.analytics = {
trackingId:
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.\\',
};
expect(initEngine).toThrow();
});
});

describe('validating the search configuration', () => {
it('passing an empty pipeline does not throw', () => {
options.configuration.search!.pipeline = '';
Expand Down
Loading