@@ -15,11 +15,12 @@ import {
15
15
using ,
16
16
} from 'aws-core-vscode/test'
17
17
import { 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'
19
19
import { loginToIdC } from '../amazonq/utils/setup'
20
20
21
21
describe ( 'Amazon Q Inline' , async function ( ) {
22
22
let tempFolder : string
23
+ const retries = 3
23
24
const waitOptions = {
24
25
interval : 500 ,
25
26
timeout : 10000 ,
@@ -37,13 +38,24 @@ describe('Amazon Q Inline', async function () {
37
38
const folder = await TestFolder . create ( )
38
39
tempFolder = folder . path
39
40
await closeAllEditors ( )
40
- await resetCodeWhispererGlobalVariables ( false )
41
+ await resetCodeWhispererGlobalVariables ( )
41
42
} )
42
43
43
44
afterEach ( async function ( ) {
44
45
await closeAllEditors ( )
46
+ if ( this . currentTest ?. state === undefined || this . currentTest ?. isFailed ( ) || this . currentTest ?. isPending ( ) ) {
47
+ logUserDecisionStatus ( )
48
+ }
45
49
} )
46
50
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
+
47
59
async function setupEditor ( { name, contents } : { name ?: string; contents ?: string } = { } ) {
48
60
const fileName = name ?? 'test.ts'
49
61
const textContents =
@@ -58,16 +70,28 @@ describe('Amazon Q Inline', async function () {
58
70
}
59
71
60
72
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 ( ) ,
64
79
waitOptions
65
80
)
66
- if ( ! ok ) {
67
- assert . fail (
81
+ if ( ! suggestionVisible ) {
82
+ throw new Error (
68
83
`Suggestions failed to become visible. Suggestion States: ${ JSON . stringify ( session . suggestionStates ) } `
69
84
)
70
85
}
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
+ }
71
95
}
72
96
73
97
/**
@@ -82,17 +106,23 @@ describe('Amazon Q Inline', async function () {
82
106
} )
83
107
return events . some ( ( event ) => event . codewhispererSuggestionState === suggestionState )
84
108
} , waitOptions )
85
- const events = globals . telemetry . logger . query ( {
86
- metricName,
87
- } )
88
109
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 ` )
90
111
}
112
+ const events = getUserTriggerDecision ( )
91
113
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` )
93
115
}
94
116
}
95
117
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
+
96
126
for ( const [ name , invokeCompletion ] of [
97
127
[ 'automatic' , async ( ) => await vscode . commands . executeCommand ( 'type' , { text : '\n' } ) ] ,
98
128
[ 'manual' , async ( ) => Commands . tryExecute ( 'aws.amazonq.invokeInlineCompletion' ) ] ,
@@ -101,7 +131,7 @@ describe('Amazon Q Inline', async function () {
101
131
let originalEditorContents : string | undefined
102
132
103
133
describe ( 'supported filetypes' , ( ) => {
104
- beforeEach ( async ( ) => {
134
+ async function setup ( ) {
105
135
await setupEditor ( )
106
136
107
137
/**
@@ -119,6 +149,31 @@ describe('Amazon Q Inline', async function () {
119
149
120
150
// wait until the ghost text appears
121
151
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
+ }
122
177
} )
123
178
124
179
it ( `${ name } invoke accept` , async function ( ) {
0 commit comments