@@ -15,11 +15,12 @@ import {
1515 using ,
1616} from 'aws-core-vscode/test'
1717import { RecommendationHandler , RecommendationService , session } from 'aws-core-vscode/codewhisperer'
18- import { Commands , globals , sleep , waitUntil } from 'aws-core-vscode/shared'
18+ import { Commands , globals , sleep , waitUntil , collectionUtil } from 'aws-core-vscode/shared'
1919import { loginToIdC } from '../amazonq/utils/setup'
2020
2121describe ( 'Amazon Q Inline' , async function ( ) {
2222 let tempFolder : string
23+ const retries = 3
2324 const waitOptions = {
2425 interval : 500 ,
2526 timeout : 10000 ,
@@ -37,13 +38,24 @@ describe('Amazon Q Inline', async function () {
3738 const folder = await TestFolder . create ( )
3839 tempFolder = folder . path
3940 await closeAllEditors ( )
40- await resetCodeWhispererGlobalVariables ( false )
41+ await resetCodeWhispererGlobalVariables ( )
4142 } )
4243
4344 afterEach ( async function ( ) {
4445 await closeAllEditors ( )
46+ if ( this . currentTest ?. state === undefined || this . currentTest ?. isFailed ( ) || this . currentTest ?. isPending ( ) ) {
47+ logUserDecisionStatus ( )
48+ }
4549 } )
4650
51+ function logUserDecisionStatus ( ) {
52+ const events = getUserTriggerDecision ( )
53+ console . table ( {
54+ 'telemetry events' : JSON . stringify ( events ) ,
55+ 'recommendation service status' : RecommendationService . instance . isRunning ,
56+ } )
57+ }
58+
4759 async function setupEditor ( { name, contents } : { name ?: string; contents ?: string } = { } ) {
4860 const fileName = name ?? 'test.ts'
4961 const textContents =
@@ -58,16 +70,28 @@ describe('Amazon Q Inline', async function () {
5870 }
5971
6072 async function waitForRecommendations ( ) {
61- const ok = await waitUntil (
62- async ( ) =>
63- RecommendationHandler . instance . isSuggestionVisible ( ) || session . getSuggestionState ( 0 ) === 'Showed' ,
73+ const suggestionShown = await waitUntil ( async ( ) => session . getSuggestionState ( 0 ) === 'Showed' , waitOptions )
74+ if ( ! suggestionShown ) {
75+ throw new Error ( `Suggestion did not show. Suggestion States: ${ JSON . stringify ( session . suggestionStates ) } ` )
76+ }
77+ const suggestionVisible = await waitUntil (
78+ async ( ) => RecommendationHandler . instance . isSuggestionVisible ( ) ,
6479 waitOptions
6580 )
66- if ( ! ok ) {
67- assert . fail (
81+ if ( ! suggestionVisible ) {
82+ throw new Error (
6883 `Suggestions failed to become visible. Suggestion States: ${ JSON . stringify ( session . suggestionStates ) } `
6984 )
7085 }
86+ console . table ( {
87+ 'suggestions states' : JSON . stringify ( session . suggestionStates ) ,
88+ 'valid recommendation' : RecommendationHandler . instance . isValidResponse ( ) ,
89+ 'recommendation service status' : RecommendationService . instance . isRunning ,
90+ recommendations : session . recommendations ,
91+ } )
92+ if ( ! RecommendationHandler . instance . isValidResponse ( ) ) {
93+ throw new Error ( 'Did not find a valid response' )
94+ }
7195 }
7296
7397 /**
@@ -82,17 +106,23 @@ describe('Amazon Q Inline', async function () {
82106 } )
83107 return events . some ( ( event ) => event . codewhispererSuggestionState === suggestionState )
84108 } , waitOptions )
85- const events = globals . telemetry . logger . query ( {
86- metricName,
87- } )
88109 if ( ! ok ) {
89- assert. fail ( `Telemetry failed to be emitted. Current events: ${ JSON . stringify ( events ) } ` )
110+ assert. fail ( `Telemetry for ${ metricName } with suggestionState ${ suggestionState } was not emitted ` )
90111 }
112+ const events = getUserTriggerDecision ( )
91113 if ( events . length > 1 && events [ events . length - 1 ] . codewhispererSuggestionState !== suggestionState ) {
92- assert. fail ( `Telemetry events were emitted in the wrong order. Current events: ${ JSON . stringify ( events ) } ` )
114+ assert. fail ( `Telemetry events were emitted in the wrong order` )
93115 }
94116 }
95117
118+ function getUserTriggerDecision ( ) {
119+ return globals . telemetry . logger
120+ . query ( {
121+ metricName : 'codewhisperer_userTriggerDecision' ,
122+ } )
123+ . map ( ( e ) => collectionUtil . partialClone ( e , 3 , [ 'credentialStartUrl' ] , '[omitted]' ) )
124+ }
125+
96126 for ( const [ name , invokeCompletion ] of [
97127 [ 'automatic' , async ( ) => await vscode . commands . executeCommand ( 'type' , { text : '\n' } ) ] ,
98128 [ 'manual' , async ( ) => Commands . tryExecute ( 'aws.amazonq.invokeInlineCompletion' ) ] ,
@@ -101,7 +131,7 @@ describe('Amazon Q Inline', async function () {
101131 let originalEditorContents : string | undefined
102132
103133 describe ( 'supported filetypes' , ( ) => {
104- beforeEach ( async ( ) => {
134+ async function setup ( ) {
105135 await setupEditor ( )
106136
107137 /**
@@ -119,6 +149,31 @@ describe('Amazon Q Inline', async function () {
119149
120150 // wait until the ghost text appears
121151 await waitForRecommendations ( )
152+ }
153+
154+ beforeEach ( async ( ) => {
155+ /**
156+ * Every once and a while the backend won't respond with any recommendations.
157+ * In those cases, re-try the setup up-to ${retries} times
158+ */
159+ let attempt = 0
160+ while ( attempt < retries ) {
161+ try {
162+ await setup ( )
163+ console . log ( `test run ${ attempt } succeeded` )
164+ logUserDecisionStatus ( )
165+ break
166+ } catch ( e ) {
167+ console . log ( `test run ${ attempt } failed` )
168+ console . log ( e )
169+ logUserDecisionStatus ( )
170+ attempt ++
171+ await resetCodeWhispererGlobalVariables ( )
172+ }
173+ }
174+ if ( attempt === retries ) {
175+ assert . fail ( `Failed to invoke ${ name } tests after ${ attempt } attempts` )
176+ }
122177 } )
123178
124179 it ( `${ name } invoke accept` , async function ( ) {
0 commit comments