|
13 | 13 | import { use, expect } from 'chai'; |
14 | 14 | import sinon from 'sinon'; |
15 | 15 | import sinonChai from 'sinon-chai'; |
| 16 | +import esmock from 'esmock'; |
16 | 17 |
|
17 | 18 | use(sinonChai); |
18 | 19 |
|
@@ -95,3 +96,160 @@ describe('scheduledRun precedence logic', () => { |
95 | 96 | }); |
96 | 97 | }); |
97 | 98 | }); |
| 99 | + |
| 100 | +/** |
| 101 | + * Integration-style tests verifying that onboardSingleSite does NOT enable audit |
| 102 | + * handlers in Configuration for free-trial one-shot onboards, and disables any |
| 103 | + * previously-enabled ones. This guards the in-process enable/disable logic |
| 104 | + * introduced by SITES-45860. |
| 105 | + */ |
| 106 | +describe('onboardSingleSite — audit handler enable/disable gating', () => { |
| 107 | + const SITE_URL = 'https://example.com'; |
| 108 | + const IMS_ORG_ID = 'ABCDEF1234567890ABCDEF12@AdobeOrg'; |
| 109 | + |
| 110 | + let sandbox; |
| 111 | + let onboardSingleSite; |
| 112 | + let enableHandlerStub; |
| 113 | + let disableHandlerStub; |
| 114 | + let configSaveStub; |
| 115 | + let sayStub; |
| 116 | + |
| 117 | + // Minimal happy-path site that survives far enough into onboardSingleSite |
| 118 | + // to reach the audit enable/disable block. |
| 119 | + const makeHappyPathSite = () => { |
| 120 | + const siteConfig = { |
| 121 | + getImports: () => [], |
| 122 | + getOnboardConfig: () => undefined, |
| 123 | + updateOnboardConfig: sinon.stub(), |
| 124 | + updateFetchConfig: sinon.stub(), |
| 125 | + getFetchConfig: () => undefined, |
| 126 | + updateRumConfig: sinon.stub(), |
| 127 | + enableImport: sinon.stub(), |
| 128 | + }; |
| 129 | + return { |
| 130 | + getId: () => 'site-happy', |
| 131 | + getBaseURL: () => SITE_URL, |
| 132 | + getOrganizationId: () => 'org-happy', |
| 133 | + getProjectId: () => undefined, |
| 134 | + getLanguage: () => undefined, |
| 135 | + getRegion: () => undefined, |
| 136 | + getCode: () => undefined, |
| 137 | + getAuthoringType: () => undefined, |
| 138 | + getDeliveryType: () => undefined, |
| 139 | + getDeliveryConfig: () => ({}), |
| 140 | + getConfig: () => siteConfig, |
| 141 | + setConfig: sinon.stub(), |
| 142 | + setProjectId: sinon.stub(), |
| 143 | + setLanguage: sinon.stub(), |
| 144 | + setRegion: sinon.stub(), |
| 145 | + save: sinon.stub().resolves(), |
| 146 | + }; |
| 147 | + }; |
| 148 | + |
| 149 | + before(async () => { |
| 150 | + ({ onboardSingleSite } = await esmock('../../src/support/utils.js', { |
| 151 | + '@aws-sdk/client-sfn': { |
| 152 | + // eslint-disable-next-line func-style |
| 153 | + SFNClient: function SFNClient() { this.send = () => Promise.resolve({ executionArn: 'arn:test' }); }, |
| 154 | + // eslint-disable-next-line func-style |
| 155 | + StartExecutionCommand: function StartExecutionCommand() {}, |
| 156 | + }, |
| 157 | + '@adobe/spacecat-shared-utils': { |
| 158 | + isValidUrl: () => true, |
| 159 | + isValidIMSOrgId: () => true, |
| 160 | + hasText: (s) => !!(s && s.trim && s.trim().length > 0), |
| 161 | + isObject: (o) => o !== null && typeof o === 'object', |
| 162 | + isNonEmptyObject: (o) => o !== null && typeof o === 'object' && Object.keys(o).length > 0, |
| 163 | + resolveCanonicalUrl: sinon.stub().resolves(SITE_URL), |
| 164 | + detectLocale: sinon.stub().resolves({ language: 'en', region: 'US' }), |
| 165 | + detectAEMVersion: sinon.stub().resolves(null), |
| 166 | + tracingFetch: sinon.stub().resolves({ ok: false }), |
| 167 | + wwwUrlResolver: sinon.stub().returns(SITE_URL), |
| 168 | + getLastNumberOfWeeks: sinon.stub().returns([]), |
| 169 | + }, |
| 170 | + '@adobe/spacecat-shared-tier-client': { |
| 171 | + default: { |
| 172 | + createForSite: async () => ({ |
| 173 | + createEntitlement: async () => ({ |
| 174 | + entitlement: { getId: () => 'ent-test' }, |
| 175 | + siteEnrollment: { getId: () => 'enr-test' }, |
| 176 | + }), |
| 177 | + }), |
| 178 | + }, |
| 179 | + }, |
| 180 | + '../../src/support/rum-config-service.js': { |
| 181 | + updateRumConfig: sinon.stub().resolves(true), |
| 182 | + }, |
| 183 | + })); |
| 184 | + }); |
| 185 | + |
| 186 | + beforeEach(() => { |
| 187 | + sandbox = sinon.createSandbox(); |
| 188 | + sayStub = sandbox.stub().resolves(); |
| 189 | + enableHandlerStub = sandbox.stub(); |
| 190 | + disableHandlerStub = sandbox.stub(); |
| 191 | + configSaveStub = sandbox.stub().resolves(); |
| 192 | + }); |
| 193 | + |
| 194 | + afterEach(() => { |
| 195 | + sandbox.restore(); |
| 196 | + }); |
| 197 | + |
| 198 | + const makeContext = (site) => ({ |
| 199 | + log: { |
| 200 | + info: sandbox.stub(), warn: sandbox.stub(), error: sandbox.stub(), debug: sandbox.stub(), |
| 201 | + }, |
| 202 | + env: { |
| 203 | + DEMO_IMS_ORG: IMS_ORG_ID, |
| 204 | + WORKFLOW_WAIT_TIME_IN_SECONDS: 300, |
| 205 | + ONBOARD_WORKFLOW_STATE_MACHINE_ARN: 'arn:aws:states:us-east-1:123:stateMachine:test', |
| 206 | + AUDIT_JOBS_QUEUE_URL: 'https://sqs.us-east-1.amazonaws.com/123/audit-jobs', |
| 207 | + }, |
| 208 | + dataAccess: { |
| 209 | + Site: { findByBaseURL: sandbox.stub().resolves(site) }, |
| 210 | + Configuration: { |
| 211 | + findLatest: sandbox.stub().resolves({ |
| 212 | + isHandlerEnabledForSite: sandbox.stub().returns(false), |
| 213 | + enableHandlerForSite: enableHandlerStub, |
| 214 | + disableHandlerForSite: disableHandlerStub, |
| 215 | + save: configSaveStub, |
| 216 | + }), |
| 217 | + }, |
| 218 | + Organization: { findByImsOrgId: sandbox.stub().rejects(new Error('not needed')) }, |
| 219 | + Project: { |
| 220 | + allByOrganizationId: sandbox.stub().resolves([]), |
| 221 | + create: sandbox.stub().resolves({ getId: () => 'proj-test', getProjectName: () => 'test-proj' }), |
| 222 | + }, |
| 223 | + }, |
| 224 | + imsClient: { getImsOrganizationDetails: sandbox.stub() }, |
| 225 | + sqs: { sendMessage: sandbox.stub().resolves() }, |
| 226 | + }); |
| 227 | + |
| 228 | + const freeTrialProfile = { audits: { cwv: {}, 'lhs-mobile': {} }, imports: {}, config: {} }; |
| 229 | + |
| 230 | + it('does NOT call enableHandlerForSite or Configuration.save for a free-trial one-shot onboard', async () => { |
| 231 | + const site = makeHappyPathSite(); |
| 232 | + const ctx = makeContext(site); |
| 233 | + |
| 234 | + try { |
| 235 | + await onboardSingleSite( |
| 236 | + SITE_URL, |
| 237 | + IMS_ORG_ID, |
| 238 | + {}, |
| 239 | + freeTrialProfile, |
| 240 | + 300, |
| 241 | + { say: sayStub, channelId: 'C1', threadTs: '1.0' }, |
| 242 | + ctx, |
| 243 | + {}, |
| 244 | + { profileName: 'demo' }, |
| 245 | + ); |
| 246 | + } catch { |
| 247 | + // Downstream deps may not be fully mocked — expected. |
| 248 | + } |
| 249 | + |
| 250 | + expect(enableHandlerStub).not.to.have.been.called; |
| 251 | + // No previously-enabled handlers → no disable either (isHandlerEnabledForSite returns false) |
| 252 | + expect(disableHandlerStub).not.to.have.been.called; |
| 253 | + expect(configSaveStub).not.to.have.been.called; |
| 254 | + }); |
| 255 | +}); |
0 commit comments