Skip to content

Commit 79ade6b

Browse files
authored
🧪 Enhance searchAndRequestFix method (#1112)
[Jenkins linux Run](https://jenkins-csb-migrationqe-main.dno.corp.redhat.com/job/mta/job/kai-e2e-nightly-linux/237/console) [Jenkins Windows Run](https://jenkins-csb-migrationqe-main.dno.corp.redhat.com/job/mta/job/kai-e2e-nightly-windows/114/console) Introduce ResolutionAction enum and enhance searchAndRequestFix method **New Features** - Added `ResolutionAction` enum to define possible resolution actions: ACCEPT, REJECT, and REVIEW_IN_EDITOR. - Updated `searchAndRequestFix` method in `VSCode` class to accept an optional `resolutionAction` parameter, allowing for more flexible handling of solution requests. - Refactored test cases to utilize the new method and enum for improved clarity and functionality. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- ## PR Title Prefix Every **PR Title** should be prefixed with :text: to indicate its type. - Breaking change: ⚠️ (`⚠️`) - Non-breaking feature: ✨ (`✨`) - Patch fix: 🐛 (`🐛`) - Docs: 📖 (`📖`) - Infra/Tests/Other: 🌱 (`🌱`) - No release note: 👻 (`👻`) For example, a pull request containing breaking changes might look like `⚠️ My pull request contains breaking changes`. Since GitHub supports emoji aliases (ie. `👻`), there is no need to include the emoji directly in the PR title -- **please use the alias**. It used to be the case that projects using emojis for PR typing had to include the emoji directly because GitHub didn't render the alias. Given that `⚠️` is easy enough to read as text, easy to parse in release tooling, and rendered in GitHub well, we prefer to standardize on the alias. For more information, please see the Konveyor [Versioning Doc](https://github.com/konveyor/release-tools/blob/main/VERSIONING.md). --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added explicit resolution actions: Accept, Reject, Review in Editor, Apply All, Reject All. * **Tests** * Replaced multi-step UI fix flows with a single action-based flow. * Integrated previous “accept all” behavior into the new action flow and removed the legacy UI path. * Updated wait/confirmation behavior and migrated tests to use the new action API. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: mohamed idays <[email protected]> Signed-off-by: [Your Name] <[email protected]>
1 parent 8853c77 commit 79ade6b

File tree

7 files changed

+90
-49
lines changed

7 files changed

+90
-49
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export enum ResolutionAction {
2+
Accept = 'Accept',
3+
Reject = 'Reject',
4+
ReviewInEditor = 'Review in Editor',
5+
ApplyAll = '^Apply All \\(\\d+\\)$',
6+
RejectAll = 'Reject All',
7+
}

tests/e2e/pages/vscode.page.ts

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ProfileActions } from '../enums/profile-action-types.enum';
88
import { OutputPanel } from './output.page';
99
import path from 'path';
1010
import { SCREENSHOTS_FOLDER } from '../utilities/consts';
11+
import { ResolutionAction } from '../enums/resolution-action.enum';
1112

1213
type SortOrder = 'ascending' | 'descending';
1314
type ListKind = 'issues' | 'files';
@@ -437,16 +438,62 @@ export abstract class VSCode {
437438
}
438439
}
439440

440-
public async searchAndRequestFix(searchTerm: string, fixType: FixTypes) {
441+
public async searchAndRequestAction(
442+
searchTerm?: string,
443+
fixType?: FixTypes,
444+
resolutionAction?: ResolutionAction
445+
) {
446+
// (midays) todo: add a filesToFix: string[] parameter to define which files to fix
441447
const analysisView = await this.getView(KAIViews.analysisView);
442-
await this.searchViolation(searchTerm);
443-
await analysisView.locator('div.pf-v6-c-card__header-toggle').nth(0).click();
444-
await analysisView.locator('button#get-solution-button').nth(fixType).click();
445-
}
446448

447-
public async searchViolationAndAcceptAllSolutions(violation: string) {
448-
await this.searchAndRequestFix(violation, FixTypes.Issue);
449-
await this.acceptAllSolutions();
449+
if (searchTerm) {
450+
await this.searchViolation(searchTerm);
451+
await analysisView.locator('div.pf-v6-c-card__header-toggle').nth(0).click();
452+
}
453+
454+
if (fixType) {
455+
await analysisView.locator('button#get-solution-button').nth(fixType).click();
456+
}
457+
458+
if (resolutionAction) {
459+
const resolutionView = await this.getView(KAIViews.resolutionDetails);
460+
const actionLocator = resolutionView.getByRole('button', {
461+
name: new RegExp(resolutionAction),
462+
});
463+
const headerLocator = resolutionView.locator('h1.pf-v6-c-title.pf-m-2xl', {
464+
hasText: 'Generative AI Results',
465+
});
466+
await expect(headerLocator.locator('.loading-indicator')).toHaveCount(0, {
467+
timeout: 600_000,
468+
}); // 10 minutes
469+
if (resolutionAction === ResolutionAction.Accept) {
470+
let fixedFiles: string[] = [];
471+
// Parse the "(current of total)" from the header to get file count
472+
const reviewHeaderLocator = resolutionView.locator(
473+
'.batch-review-expandable-header .batch-review-title'
474+
);
475+
await reviewHeaderLocator.waitFor({ state: 'visible', timeout: 10000 });
476+
let headerText = await reviewHeaderLocator.textContent();
477+
const match = headerText && headerText.match(/\((\d+)\s+of\s+(\d+)\)/);
478+
const totalFiles = match ? parseInt(match[2], 10) : 1;
479+
console.log('Total files found to accept solutions for: ', totalFiles);
480+
for (let i = 0; i < totalFiles; i++) {
481+
headerText = await reviewHeaderLocator.textContent();
482+
const fileNameMatch = headerText && headerText.match(/^Reviewing:\s*([^\(]+)\s*\(/);
483+
const fileToFix = fileNameMatch && fileNameMatch[1] ? fileNameMatch[1].trim() : '';
484+
console.log('Reviewing file: ', fileToFix);
485+
fixedFiles.push(fileToFix);
486+
await actionLocator.waitFor({ state: 'visible', timeout: 10000 });
487+
await actionLocator.dispatchEvent('click');
488+
console.log('Accepted solution for file: ', fileToFix);
489+
}
490+
return fixedFiles;
491+
} else {
492+
await actionLocator.waitFor({ state: 'visible', timeout: 30000 });
493+
await actionLocator.dispatchEvent('click');
494+
return [];
495+
}
496+
}
450497
}
451498

452499
public async waitForSolutionConfirmation(): Promise<void> {
@@ -464,29 +511,6 @@ export abstract class VSCode {
464511
]);
465512
}
466513

467-
public async acceptAllSolutions() {
468-
const resolutionView = await this.getView(KAIViews.resolutionDetails);
469-
const fixLocator = resolutionView.getByRole('button', { name: 'Accept' });
470-
const loadingIndicator = resolutionView.locator('.loading-indicator');
471-
472-
await this.waitDefault();
473-
// Avoid fixing issues forever
474-
const MAX_FIXES = 500;
475-
476-
for (let i = 0; i < MAX_FIXES; i++) {
477-
await expect(fixLocator.first()).toBeVisible({ timeout: 300_000 });
478-
// Ensures the button is clicked even if there are notifications overlaying it due to screen size
479-
await fixLocator.first().dispatchEvent('click');
480-
await this.waitDefault();
481-
482-
if ((await loadingIndicator.count()) === 0) {
483-
return;
484-
}
485-
}
486-
487-
throw new Error('MAX_FIXES limit reached while requesting solutions');
488-
}
489-
490514
public async waitDefault() {
491515
await this.window.waitForTimeout(process.env.CI ? 5000 : 3000);
492516
}

tests/e2e/tests/analyze_coolstore.test.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import { DEFAULT_PROVIDER, getAvailableProviders } from '../fixtures/provider-co
66
import path from 'path';
77
import { runEvaluation } from '../../kai-evaluator/core';
88
import { prepareEvaluationData, saveOriginalAnalysisFile } from '../utilities/evaluation.utils';
9-
import { KAIViews } from '../enums/views.enum';
109
import { isAWSConfigured } from '../../kai-evaluator/utils/s3.utils';
1110
import * as VSCodeFactory from '../utilities/vscode.factory';
11+
import { ResolutionAction } from '../enums/resolution-action.enum';
12+
import { FixTypes } from '../enums/fix-types.enum';
1213

1314
const providers = process.env.CI ? getAvailableProviders() : [DEFAULT_PROVIDER];
1415

@@ -64,10 +65,7 @@ providers.forEach((config) => {
6465
test('Fix all issues', async () => {
6566
test.setTimeout(3600000);
6667
await vscodeApp.openAnalysisView();
67-
const analysisView = await vscodeApp.getView(KAIViews.analysisView);
68-
await analysisView.locator('button#get-solution-button').first().click({ timeout: 300000 });
69-
70-
await vscodeApp.acceptAllSolutions();
68+
await vscodeApp.searchAndRequestAction(undefined, FixTypes.Issue, ResolutionAction.Accept);
7169
});
7270

7371
test.afterEach(async () => {

tests/e2e/tests/base/fix-one-issue.test.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { expect, test } from '../../fixtures/test-repo-fixture';
22
import { VSCode } from '../../pages/vscode.page';
33
import { getAvailableProviders } from '../../fixtures/provider-configs.fixture';
44
import { generateRandomString, parseLogEntries } from '../../utilities/utils';
5-
import { KAIViews } from '../../enums/views.enum';
65
import { FixTypes } from '../../enums/fix-types.enum';
76
import * as VSCodeFactory from '../../utilities/vscode.factory';
87
import { Configuration } from '../../pages/configuration.page';
98
import { logLevel } from '../../enums/configuration-options.enum';
109
import { LogLevel } from '../../enums/Log-level.enum';
1110
import { OutputChannel } from '../../enums/output.enum';
11+
import { ResolutionAction } from '../../enums/resolution-action.enum';
1212

1313
getAvailableProviders().forEach((provider) => {
1414
test.describe(`@tier0 Run analysis and fix one issue - ${provider.model}`, () => {
@@ -40,12 +40,11 @@ getAvailableProviders().forEach((provider) => {
4040
test('Fix one issue', async () => {
4141
test.setTimeout(600000);
4242
await vscodeApp.openAnalysisView();
43-
await vscodeApp.searchAndRequestFix('InventoryEntity', FixTypes.Incident);
44-
const resolutionView = await vscodeApp.getView(KAIViews.resolutionDetails);
45-
const fixLocator = resolutionView.getByRole('button', { name: 'Accept' }).first();
46-
await expect(fixLocator).toBeVisible({ timeout: 60000 });
47-
// Ensures the button is clicked even if there are notifications overlaying it due to screen size
48-
await fixLocator.dispatchEvent('click');
43+
await vscodeApp.searchAndRequestAction(
44+
'InventoryEntity',
45+
FixTypes.Incident,
46+
ResolutionAction.Accept
47+
);
4948
await expect(vscodeApp.getWindow().getByText('Analysis completed').first()).toBeVisible({
5049
timeout: 600000,
5150
});

tests/e2e/tests/base/llm-revert-check.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { generateRandomString } from '../../utilities/utils';
77
import path from 'path';
88
import { getFileImports } from '../../utilities/file.utils';
99
import * as VSCodeFactory from '../../utilities/vscode.factory';
10+
import { FixTypes } from '../../enums/fix-types.enum';
11+
import { ResolutionAction } from '../../enums/resolution-action.enum';
1012
/**
1113
* Automates https://github.com/konveyor/kai/issues/798
1214
* Tests that fixes applied by the LLM do not unintentionally revert .
@@ -56,7 +58,7 @@ getAvailableProviders().forEach((provider) => {
5658
const violation = "The package 'javax' has been replaced by 'jakarta'";
5759

5860
await vscodeApp.openAnalysisView();
59-
await vscodeApp.searchViolationAndAcceptAllSolutions(violation);
61+
await vscodeApp.searchAndRequestAction(violation, FixTypes.Issue, ResolutionAction.Accept);
6062
await vscodeApp.openAnalysisView();
6163
await vscodeApp.waitForSolutionConfirmation();
6264

@@ -69,7 +71,7 @@ getAvailableProviders().forEach((provider) => {
6971
'Implicit name determination for sequences and tables associated with identifier generation has changed';
7072

7173
await vscodeApp.openAnalysisView();
72-
await vscodeApp.searchViolationAndAcceptAllSolutions(violation);
74+
await vscodeApp.searchAndRequestAction(violation, FixTypes.Issue, ResolutionAction.Accept);
7375
await vscodeApp.openAnalysisView();
7476
await vscodeApp.waitForSolutionConfirmation();
7577

tests/e2e/tests/solution-server/analysis-validation.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
SuccessRateResponse,
1212
} from '../../../mcp-client/mcp-client-responses.model';
1313
import * as VSCodeFactory from '../../utilities/vscode.factory';
14+
import { ResolutionAction } from '../../enums/resolution-action.enum';
1415

1516
test.describe(`Solution server analysis validations`, () => {
1617
let vsCode: VSCode;
@@ -83,9 +84,10 @@ test.describe(`Solution server analysis validations`, () => {
8384
* 7. Asserts that the UI displays the correct success rate counts
8485
*/
8586
async function requestFixAndAssertSolution(accept: boolean) {
86-
await vsCode.searchAndRequestFix(
87+
await vsCode.searchAndRequestAction(
8788
'Replace the `javax.persistence` import statement with `jakarta.persistence`',
88-
FixTypes.Incident
89+
FixTypes.Incident,
90+
ResolutionAction.Accept
8991
);
9092

9193
const resolutionView = await vsCode.getView(KAIViews.resolutionDetails);

tests/e2e/tests/solution-server/partially-migrated-apps-scenario.test.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import * as fs from 'fs';
2828
import { TestLogger } from '../../utilities/logger';
2929
import { solutionServerEnabled } from '../../enums/configuration-options.enum';
3030
import * as VSCodeFactory from '../../utilities/vscode.factory';
31+
import { ResolutionAction } from '../../enums/resolution-action.enum';
3132

3233
class SolutionServerWorkflowHelper {
3334
public logger: TestLogger;
@@ -206,7 +207,11 @@ class SolutionServerWorkflowHelper {
206207

207208
const violationText =
208209
'Replace `FileSystemAuditLogger` instantiation with `StreamableAuditLogger` over TCP';
209-
await vsCode.searchAndRequestFix(violationText, FixTypes.Incident);
210+
await vsCode.searchAndRequestAction(
211+
violationText,
212+
FixTypes.Incident,
213+
ResolutionAction.Accept
214+
);
210215

211216
const resolutionView = await vsCode.getView(KAIViews.resolutionDetails);
212217

@@ -251,7 +256,11 @@ class SolutionServerWorkflowHelper {
251256

252257
const violationText =
253258
'The java.annotation (Common Annotations) module has been removed from OpenJDK 11';
254-
await vsCode.searchAndRequestFix(violationText, FixTypes.Incident);
259+
await vsCode.searchAndRequestAction(
260+
violationText,
261+
FixTypes.Incident,
262+
ResolutionAction.Accept
263+
);
255264

256265
const resolutionView = await vsCode.getView(KAIViews.resolutionDetails);
257266

0 commit comments

Comments
 (0)