-
Notifications
You must be signed in to change notification settings - Fork 501
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
test(amazonq): Add inline completion e2e tests #6486
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/*! | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import * as vscode from 'vscode' | ||
import assert from 'assert' | ||
import { | ||
assertTelemetry, | ||
closeAllEditors, | ||
getTestWindow, | ||
registerAuthHook, | ||
resetCodeWhispererGlobalVariables, | ||
TestFolder, | ||
toTextEditor, | ||
using, | ||
} from 'aws-core-vscode/test' | ||
import { RecommendationHandler, RecommendationService } from 'aws-core-vscode/codewhisperer' | ||
import { Commands, globals, sleep, waitUntil } from 'aws-core-vscode/shared' | ||
import { loginToIdC } from '../amazonq/utils/setup' | ||
|
||
describe('Amazon Q Inline', async function () { | ||
let tempFolder: string | ||
const waitOptions = { | ||
interval: 500, | ||
timeout: 10000, | ||
retryOnFail: false, | ||
} | ||
|
||
before(async function () { | ||
await using(registerAuthHook('amazonq-test-account'), async () => { | ||
await loginToIdC() | ||
}) | ||
}) | ||
|
||
beforeEach(async function () { | ||
registerAuthHook('amazonq-test-account') | ||
const folder = await TestFolder.create() | ||
tempFolder = folder.path | ||
await closeAllEditors() | ||
await resetCodeWhispererGlobalVariables(false) | ||
}) | ||
|
||
afterEach(async function () { | ||
await closeAllEditors() | ||
}) | ||
|
||
async function setupEditor({ name, contents }: { name?: string; contents?: string } = {}) { | ||
const fileName = name ?? 'test.ts' | ||
const textContents = | ||
contents ?? | ||
`function fib() { | ||
|
||
|
||
}` | ||
await toTextEditor(textContents, fileName, tempFolder, { | ||
selection: new vscode.Range(new vscode.Position(1, 4), new vscode.Position(1, 4)), | ||
}) | ||
} | ||
|
||
async function waitForRecommendations() { | ||
const ok = await waitUntil(async () => RecommendationHandler.instance.isSuggestionVisible(), waitOptions) | ||
if (!ok) { | ||
assert.fail('Suggestions failed to become visible') | ||
} | ||
} | ||
|
||
async function waitForTelemetry() { | ||
const ok = await waitUntil( | ||
async () => | ||
globals.telemetry.logger.query({ | ||
Comment on lines
+69
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. assertTelemetry does the querying but it doesn't wait for the event to appear as far as I can tell. I want the tests to explicitly wait until those telemetry events appear and then finally assert on them |
||
metricName: 'codewhisperer_userTriggerDecision', | ||
}).length > 0, | ||
waitOptions | ||
) | ||
if (!ok) { | ||
assert.fail('Telemetry failed to be emitted') | ||
} | ||
} | ||
|
||
for (const [name, invokeCompletion] of [ | ||
['automatic', async () => await vscode.commands.executeCommand('type', { text: '\n' })], | ||
['manual', async () => Commands.tryExecute('aws.amazonq.invokeInlineCompletion')], | ||
] as const) { | ||
describe(`${name} invoke`, async function () { | ||
let originalEditorContents: string | undefined | ||
|
||
describe('supported filetypes', () => { | ||
beforeEach(async () => { | ||
await setupEditor() | ||
|
||
/** | ||
* Allow some time between when the editor is opened and when we start typing. | ||
* If we don't do this then the time between the initial editor selection | ||
* and invoking the "type" command is too low, causing completion to never | ||
* activate. AFAICT there isn't anything we can use waitUntil on here. | ||
* | ||
* note: this number is entirely arbitrary | ||
**/ | ||
await sleep(1000) | ||
|
||
await invokeCompletion() | ||
originalEditorContents = vscode.window.activeTextEditor?.document.getText() | ||
|
||
// wait until the ghost text appears | ||
await waitForRecommendations() | ||
}) | ||
|
||
it(`${name} invoke accept`, async function () { | ||
/** | ||
* keep accepting the suggestion until the text contents change | ||
* this is required because we have no access to the inlineSuggest panel | ||
**/ | ||
const suggestionAccepted = await waitUntil(async () => { | ||
// Accept the suggestion | ||
await vscode.commands.executeCommand('editor.action.inlineSuggest.commit') | ||
return vscode.window.activeTextEditor?.document.getText() !== originalEditorContents | ||
}, waitOptions) | ||
|
||
assert.ok(suggestionAccepted, 'Editor contents should have changed') | ||
|
||
await waitForTelemetry() | ||
assertTelemetry('codewhisperer_userTriggerDecision', { | ||
codewhispererSuggestionState: 'Accept', | ||
}) | ||
}) | ||
|
||
it(`${name} invoke reject`, async function () { | ||
// Reject the suggestion | ||
await vscode.commands.executeCommand('aws.amazonq.rejectCodeSuggestion') | ||
|
||
// Contents haven't changed | ||
assert.deepStrictEqual(vscode.window.activeTextEditor?.document.getText(), originalEditorContents) | ||
|
||
await waitForTelemetry() | ||
assertTelemetry('codewhisperer_userTriggerDecision', { | ||
codewhispererSuggestionState: 'Reject', | ||
}) | ||
}) | ||
|
||
it(`${name} invoke discard`, async function () { | ||
// Discard the suggestion by moving it back to the original position | ||
const position = new vscode.Position(1, 4) | ||
const editor = vscode.window.activeTextEditor | ||
if (!editor) { | ||
assert.fail('Could not find text editor') | ||
} | ||
editor.selection = new vscode.Selection(position, position) | ||
|
||
// Contents are the same | ||
assert.deepStrictEqual(vscode.window.activeTextEditor?.document.getText(), originalEditorContents) | ||
}) | ||
}) | ||
|
||
it(`${name} invoke on unsupported filetype`, async function () { | ||
await setupEditor({ | ||
name: 'test.zig', | ||
contents: `fn doSomething() void { | ||
|
||
}`, | ||
}) | ||
|
||
/** | ||
* Add delay between editor loading and invoking completion | ||
* @see beforeEach in supported filetypes for more information | ||
*/ | ||
await sleep(1000) | ||
await invokeCompletion() | ||
|
||
if (name === 'automatic') { | ||
// It should never get triggered since its not a supported file type | ||
assert.deepStrictEqual(RecommendationService.instance.isRunning, false) | ||
} else { | ||
await getTestWindow().waitForMessage('currently not supported by Amazon Q inline suggestions') | ||
} | ||
}) | ||
}) | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file is located at a new place, whereas all the other Q features are located in
packages/amazonq/test/e2e/amazonq
maybe the
e2e/amazonq/*
files should be lifted up into this location (followup PR)? since thee2e/amazonq
subdir seems redundant.