Skip to content

Commit 684bf58

Browse files
committed
fix: Use proven pattern from detection-translation for ServiceNow configuration
1 parent 25cdec0 commit 684bf58

File tree

1 file changed

+95
-40
lines changed

1 file changed

+95
-40
lines changed

e2e/src/pages/AppCatalogPage.ts

Lines changed: 95 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,21 @@ export class AppCatalogPage extends BasePage {
7070

7171
if (await this.elementExists(installButton, 3000)) {
7272
await this.smartClick(installButton, 'Install button');
73-
await this.waiter.delay(2000);
73+
this.logger.info('Clicked Install button, waiting for install page to load');
74+
75+
// Wait for URL to change to install page and page to stabilize
76+
await this.page.waitForURL(/\/foundry\/app-catalog\/[^\/]+\/install$/, { timeout: 10000 });
77+
await this.page.waitForLoadState('domcontentloaded');
78+
await this.page.waitForLoadState('networkidle');
79+
80+
// Handle permissions dialog
81+
await this.handlePermissionsDialog();
7482

7583
// Check for ServiceNow configuration screen
76-
await this.handleServiceNowConfiguration();
84+
await this.configureServiceNowIfNeeded();
85+
86+
// Click final Install app button
87+
await this.clickInstallAppButton();
7788

7889
// Wait for installation to complete
7990
await this.waitForInstallation(appName);
@@ -87,50 +98,94 @@ export class AppCatalogPage extends BasePage {
8798
}
8899

89100
/**
90-
* Handle ServiceNow configuration screen if present
101+
* Handle permissions dialog if present
91102
*/
92-
private async handleServiceNowConfiguration(): Promise<void> {
93-
// Check if ServiceNow configuration modal appears
94-
const configHeading = this.page.getByRole('heading', { name: /servicenow|configuration/i });
95-
96-
if (await this.elementExists(configHeading, 3000)) {
97-
this.logger.info('ServiceNow configuration screen detected, filling dummy values');
98-
99-
// Fill Instance URL
100-
const instanceUrlField = this.page.getByLabel(/instance.*url/i)
101-
.or(this.page.getByPlaceholder(/instance.*url/i))
102-
.first();
103-
if (await this.elementExists(instanceUrlField, 2000)) {
104-
await instanceUrlField.fill('https://dummy.service-now.com');
105-
this.logger.info('Filled Instance URL');
106-
}
103+
private async handlePermissionsDialog(): Promise<void> {
104+
const acceptButton = this.page.getByRole('button', { name: /accept.*continue/i });
107105

108-
// Fill Username
109-
const usernameField = this.page.getByLabel(/username/i)
110-
.or(this.page.getByPlaceholder(/username/i))
111-
.first();
112-
if (await this.elementExists(usernameField, 2000)) {
113-
await usernameField.fill('dummy_user');
114-
this.logger.info('Filled Username');
115-
}
106+
if (await this.elementExists(acceptButton, 3000)) {
107+
this.logger.info('Permissions dialog detected, accepting');
108+
await this.smartClick(acceptButton, 'Accept and continue button');
109+
await this.waiter.delay(2000);
110+
}
111+
}
116112

117-
// Fill Password (must be >8 characters)
118-
const passwordField = this.page.getByLabel(/password/i)
119-
.or(this.page.getByPlaceholder(/password/i))
120-
.first();
121-
if (await this.elementExists(passwordField, 2000)) {
122-
await passwordField.fill('DummyPassword123');
123-
this.logger.info('Filled Password');
124-
}
113+
/**
114+
* Configure ServiceNow API integration if configuration form is present
115+
*/
116+
private async configureServiceNowIfNeeded(): Promise<void> {
117+
this.logger.info('Checking if ServiceNow API configuration is required...');
118+
119+
// Check if there are text input fields (configuration form)
120+
const textInputs = this.page.locator('input[type="text"]');
121+
122+
try {
123+
await textInputs.first().waitFor({ state: 'visible', timeout: 15000 });
124+
const count = await textInputs.count();
125+
this.logger.info(`ServiceNow configuration form detected with ${count} input fields`);
126+
} catch (error) {
127+
this.logger.info('No ServiceNow configuration required - no input fields found');
128+
return;
129+
}
130+
131+
this.logger.info('ServiceNow configuration required, filling dummy values');
132+
133+
// Fill configuration fields using index-based selection
134+
// Field 1: Name
135+
const nameField = this.page.locator('input[type="text"]').first();
136+
await nameField.fill('ServiceNow Test Instance');
137+
this.logger.debug('Filled Name field');
138+
139+
// Field 2: Instance (the {instance} part of {instance}.service-now.com)
140+
const instanceField = this.page.locator('input[type="text"]').nth(1);
141+
await instanceField.fill('dev12345');
142+
this.logger.debug('Filled Instance field');
143+
144+
// Field 3: Username
145+
const usernameField = this.page.locator('input[type="text"]').nth(2);
146+
await usernameField.fill('dummy_user');
147+
this.logger.debug('Filled Username field');
148+
149+
// Field 4: Password (must be >8 characters)
150+
const passwordField = this.page.locator('input[type="password"]').first();
151+
if (await this.elementExists(passwordField, 2000)) {
152+
await passwordField.fill('DummyPassword123');
153+
this.logger.debug('Filled Password field');
154+
} else {
155+
// Try as text input if password field not found
156+
const passwordTextInput = this.page.locator('input[type="text"]').nth(3);
157+
await passwordTextInput.fill('DummyPassword123');
158+
this.logger.debug('Filled Password field (text input)');
159+
}
160+
161+
// Wait for network to settle after filling form
162+
await this.page.waitForLoadState('networkidle');
125163

126-
// Click Next or Install button to proceed
127-
const proceedButton = this.page.getByRole('button', { name: /next|install|continue/i });
128-
if (await this.elementExists(proceedButton, 2000)) {
129-
await this.smartClick(proceedButton, 'Proceed button');
130-
this.logger.info('Clicked proceed button after configuration');
131-
await this.waiter.delay(2000);
164+
this.logger.success('ServiceNow API configuration completed');
165+
}
166+
167+
/**
168+
* Click the final "Install app" button
169+
*/
170+
private async clickInstallAppButton(): Promise<void> {
171+
const installButton = this.page.getByRole('button', { name: 'Install app' });
172+
173+
// Wait for button to be enabled after form completion
174+
await this.waiter.waitForVisible(installButton, { description: 'Install app button' });
175+
176+
// Ensure button is enabled before clicking
177+
let attempts = 0;
178+
while (attempts < 10) {
179+
const isEnabled = await installButton.isEnabled();
180+
if (isEnabled) {
181+
break;
132182
}
183+
await this.waiter.delay(1000);
184+
attempts++;
133185
}
186+
187+
await this.smartClick(installButton, 'Install app button');
188+
this.logger.info('Clicked Install app button');
134189
}
135190

136191
/**

0 commit comments

Comments
 (0)