@@ -27,6 +27,7 @@ describe('LlmoOnboardCommand', () => {
2727 let mockConfig ;
2828 let mockDataAccess ;
2929 let mockLog ;
30+ let mockConfiguration ;
3031 let slackContext ;
3132
3233 beforeEach ( ( ) => {
@@ -40,6 +41,7 @@ describe('LlmoOnboardCommand', () => {
4041 getContentAiConfig : sinon . stub ( ) . returns ( { } ) ,
4142 getImports : sinon . stub ( ) . returns ( [ ] ) ,
4243 getCdnLogsConfig : sinon . stub ( ) . returns ( { } ) ,
44+ enableImport : sinon . stub ( ) ,
4345 } ;
4446
4547 // Create mock site
@@ -50,11 +52,21 @@ describe('LlmoOnboardCommand', () => {
5052 save : sinon . stub ( ) . resolves ( ) ,
5153 } ;
5254
55+ // Mock global Configuration
56+ mockConfiguration = {
57+ enableHandlerForSite : sinon . stub ( ) ,
58+ save : sinon . stub ( ) . resolves ( ) ,
59+ getQueues : sinon . stub ( ) . returns ( { imports : 'queue-imports' } ) ,
60+ } ;
61+
5362 // Create mock data access
5463 mockDataAccess = {
5564 Site : {
5665 findByBaseURL : sinon . stub ( ) . resolves ( mockSite ) ,
5766 } ,
67+ Configuration : {
68+ findLatest : sinon . stub ( ) . resolves ( mockConfiguration ) ,
69+ } ,
5870 } ;
5971
6072 // Create mock log
@@ -67,6 +79,9 @@ describe('LlmoOnboardCommand', () => {
6779 mockContext = {
6880 dataAccess : mockDataAccess ,
6981 log : mockLog ,
82+ sqs : {
83+ sendMessage : sinon . stub ( ) ,
84+ } ,
7085 } ;
7186
7287 // Create slack context
@@ -130,12 +145,38 @@ describe('LlmoOnboardCommand', () => {
130145 ) ;
131146 } ) ;
132147
133- it ( 'should successfully onboard LLMO for a valid site' , async ( ) => {
148+ it ( 'should successfully onboard LLMO for a valid site and enable referral traffic processing + backfill ' , async ( ) => {
134149 await command . handleExecution ( [ 'https://example.com' , 'adobe' , 'Adobe' ] , slackContext ) ;
135150
151+ // site lookup and config update
136152 expect ( mockDataAccess . Site . findByBaseURL ) . to . have . been . calledWith ( 'https://example.com' ) ;
137153 expect ( mockSite . setConfig ) . to . have . been . called ;
138- expect ( mockSite . save ) . to . have . been . called ;
154+
155+ // enable traffic-analysis import on the site config
156+ expect ( mockConfig . enableImport ) . to . have . been . calledWith ( 'traffic-analysis' ) ;
157+
158+ // enable handler for site in Configuration and save it
159+ expect ( mockDataAccess . Configuration . findLatest ) . to . have . been . calledOnce ;
160+ expect ( mockConfiguration . enableHandlerForSite ) . to . have . been . calledWith ( 'llmo-referral-traffic' , mockSite ) ;
161+ expect ( mockConfiguration . save ) . to . have . been . calledOnce ;
162+
163+ // save site config after configuration saved
164+ expect ( mockSite . save ) . to . have . been . calledOnce ;
165+ sinon . assert . callOrder ( mockConfiguration . save , mockSite . save ) ;
166+
167+ // referral-traffic backfill should enqueue 4 messages (last 4 weeks)
168+ expect ( mockContext . sqs . sendMessage . callCount ) . to . equal ( 4 ) ;
169+ const calls = mockContext . sqs . sendMessage . getCalls ( ) ;
170+ calls . forEach ( ( call ) => {
171+ const [ queue , payload ] = call . args ;
172+ expect ( queue ) . to . equal ( 'queue-imports' ) ;
173+ expect ( payload ) . to . include ( { type : 'traffic-analysis' , siteId : 'test-site-id' } ) ;
174+ expect ( payload . auditContext ) . to . include ( { auditType : 'llmo-referral-traffic' } ) ;
175+ expect ( payload . auditContext . week ) . to . be . a ( 'number' ) ;
176+ expect ( payload . auditContext . year ) . to . be . a ( 'number' ) ;
177+ } ) ;
178+
179+ // success message
139180 expect ( slackContext . say ) . to . have . been . calledWith (
140181 sinon . match . string . and ( sinon . match ( / L L M O o n b o a r d i n g c o m p l e t e d s u c c e s s f u l l y / ) ) ,
141182 ) ;
@@ -165,7 +206,7 @@ describe('LlmoOnboardCommand', () => {
165206 expect ( mockSite . save ) . to . have . been . called ;
166207 } ) ;
167208
168- it ( 'should handle save errors gracefully' , async ( ) => {
209+ it ( 'should handle site save errors gracefully' , async ( ) => {
169210 const saveError = new Error ( 'Database error' ) ;
170211 mockSite . save . rejects ( saveError ) ;
171212
@@ -179,6 +220,22 @@ describe('LlmoOnboardCommand', () => {
179220 ) ;
180221 } ) ;
181222
223+ it ( 'should handle configuration save errors gracefully' , async ( ) => {
224+ const saveError = new Error ( 'Conf DB error' ) ;
225+ mockConfiguration . save . rejects ( saveError ) ;
226+
227+ await command . handleExecution ( [ 'https://example.com' , 'adobe' , 'Adobe' ] , slackContext ) ;
228+
229+ expect ( mockLog . error ) . to . have . been . calledWith (
230+ sinon . match ( / E r r o r s a v i n g L L M O c o n f i g f o r s i t e t e s t - s i t e - i d / ) ,
231+ ) ;
232+ expect ( slackContext . say ) . to . have . been . calledWith (
233+ ':x: Failed to save LLMO configuration: Conf DB error' ,
234+ ) ;
235+ // site.save should not be called when configuration.save fails
236+ expect ( mockSite . save ) . to . not . have . been . called ;
237+ } ) ;
238+
182239 it ( 'sends a message for all other errors' , async ( ) => {
183240 const error = new Error ( 'Unexpected error' ) ;
184241 mockDataAccess . Site . findByBaseURL . rejects ( error ) ;
0 commit comments