@globisnv/cypress-core 2.4.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -570,9 +570,11 @@ declare global {
|
|
|
570
570
|
*/
|
|
571
571
|
GLO_clickButtonInGrid(buttonColumn: string, rowFilter?: string | number, validationColumn?: string, x?: number, y?: number): Chainable<JQuery>;
|
|
572
572
|
/**
|
|
573
|
-
*
|
|
573
|
+
* Log out and continue as the default (username) or the alternate (username2) SSO user, Okta or Keycloak.
|
|
574
574
|
*
|
|
575
|
-
*
|
|
575
|
+
* The login is stateless: the logout ends only the app session and the IdP signs the app straight back in.
|
|
576
|
+
* Returning to the user that holds the IdP session is therefore only a logout. Switching to the other user
|
|
577
|
+
* clears the IdP session and logs in on the IdP page.
|
|
576
578
|
*
|
|
577
579
|
* @param {usernameFlag} [altUser] - Switch to decide whether a secondary (alternateUsername) account has to be logged into or (defaultUsername) the primary account.
|
|
578
580
|
* @param {string} [company] - Name of a company to switch to after successfully logging in.
|
|
@@ -192,43 +192,46 @@ const waitForWebSocketAfterSso = (idp = ssoUrl()) => {
|
|
|
192
192
|
cy.task('log', `WebSocket spy confirmed connected, ${win.wsMessages?.messages.length} messages captured so far`);
|
|
193
193
|
});
|
|
194
194
|
};
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
// userEnv/passwordEnv name the env values to log in with, 'username2'/'password2' for the alternate user
|
|
196
|
+
const oktaIdpLogin = (userEnv = 'username', passwordEnv = 'password') => {
|
|
197
|
+
cy.origin(ssoUrl(), { args: { userEnv, passwordEnv } }, ({ userEnv, passwordEnv }) => {
|
|
197
198
|
cy.get('.o-form-input', { timeout: 60000 })
|
|
198
199
|
.find('[autocomplete="username"]')
|
|
199
200
|
.clear()
|
|
200
|
-
.type(Cypress.expose(
|
|
201
|
+
.type(Cypress.expose(userEnv));
|
|
201
202
|
cy.task('log', 'Filled in username');
|
|
202
203
|
cy.get('[type="submit"]').click();
|
|
203
|
-
cy.env([
|
|
204
|
+
cy.env([passwordEnv]).then((envVars) => {
|
|
204
205
|
cy.get('.o-form-input')
|
|
205
206
|
.find('[type="password"]', { timeout: 20000 })
|
|
206
|
-
.type(
|
|
207
|
+
.type(envVars[passwordEnv], { log: false });
|
|
207
208
|
});
|
|
208
209
|
cy.task('log', 'Filled in password');
|
|
209
210
|
cy.get('[type="submit"]').click();
|
|
210
211
|
});
|
|
211
212
|
};
|
|
212
|
-
// Keycloak: username page, password page, then a one-time code page when the user has OTP (otpSecret is set)
|
|
213
|
-
|
|
213
|
+
// Keycloak: username page, password page, then a one-time code page when the user has OTP (otpSecret is set).
|
|
214
|
+
// otpSecret belongs to the default user, so the alternate user is logged in without a code.
|
|
215
|
+
const keycloakIdpLogin = (userEnv = 'username', passwordEnv = 'password') => {
|
|
214
216
|
// The code is made outside cy.origin: a task that waits for a free OTP window times out after 4s inside it.
|
|
215
217
|
// It is claimed right before the IdP pages, so it is still fresh when typed.
|
|
216
218
|
cy.env(['otpSecret']).then(({ otpSecret }) => {
|
|
217
|
-
if (otpSecret)
|
|
218
|
-
cy.task('totp', otpSecret, { log: false, timeout: 200000 }).then((code) => keycloakOrigin(code));
|
|
219
|
+
if (otpSecret && userEnv === 'username') {
|
|
220
|
+
cy.task('totp', otpSecret, { log: false, timeout: 200000 }).then((code) => keycloakOrigin(code, userEnv, passwordEnv));
|
|
221
|
+
}
|
|
219
222
|
else
|
|
220
|
-
keycloakOrigin(undefined);
|
|
223
|
+
keycloakOrigin(undefined, userEnv, passwordEnv);
|
|
221
224
|
});
|
|
222
225
|
};
|
|
223
|
-
const keycloakOrigin = (code) => {
|
|
224
|
-
cy.origin(ssoUrl(), { args: { code } }, ({ code }) => {
|
|
226
|
+
const keycloakOrigin = (code, userEnv, passwordEnv) => {
|
|
227
|
+
cy.origin(ssoUrl(), { args: { code, userEnv, passwordEnv } }, ({ code, userEnv, passwordEnv }) => {
|
|
225
228
|
cy.get('input[name="username"]', { timeout: 60000 })
|
|
226
229
|
.clear()
|
|
227
|
-
.type(Cypress.expose(
|
|
230
|
+
.type(Cypress.expose(userEnv));
|
|
228
231
|
cy.task('log', 'Filled in username');
|
|
229
232
|
cy.get('#kc-login').click();
|
|
230
|
-
cy.env([
|
|
231
|
-
cy.get('input[name="password"]', { timeout: 20000 }).type(
|
|
233
|
+
cy.env([passwordEnv]).then((envVars) => {
|
|
234
|
+
cy.get('input[name="password"]', { timeout: 20000 }).type(envVars[passwordEnv], { log: false });
|
|
232
235
|
cy.task('log', 'Filled in password');
|
|
233
236
|
cy.get('#kc-login').click();
|
|
234
237
|
if (code) {
|
|
@@ -240,6 +243,15 @@ const keycloakOrigin = (code) => {
|
|
|
240
243
|
});
|
|
241
244
|
});
|
|
242
245
|
};
|
|
246
|
+
const idpLogin = (userEnv = 'username', passwordEnv = 'password') => {
|
|
247
|
+
if (ssoProvider() === 'okta')
|
|
248
|
+
oktaIdpLogin(userEnv, passwordEnv);
|
|
249
|
+
else
|
|
250
|
+
keycloakIdpLogin(userEnv, passwordEnv);
|
|
251
|
+
};
|
|
252
|
+
// Whether the IdP session currently belongs to the alternate user (username2), see GLO_oktaAlternativeLogin.
|
|
253
|
+
// ssoLogin restores the default user's IdP session, so it resets this.
|
|
254
|
+
let ssoAlternateUserActive = false;
|
|
243
255
|
// One IdP login per run (cy.session, also across specs): every later call only revisits the app,
|
|
244
256
|
// which the IdP signs in silently, so no password/OTP is asked again.
|
|
245
257
|
// ponytail: no `validate` — an expired IdP session shows up as a login page, add a validate if that happens
|
|
@@ -262,10 +274,7 @@ const ssoLogin = (company, urlType, skipvNavCheck) => {
|
|
|
262
274
|
// AUT page load (see websocketDetector.ts), which covers this server-side redirect too.
|
|
263
275
|
cy.visit(url);
|
|
264
276
|
cy.task('log', `Redirect to ${provider} url`);
|
|
265
|
-
|
|
266
|
-
oktaIdpLogin();
|
|
267
|
-
else
|
|
268
|
-
keycloakIdpLogin();
|
|
277
|
+
idpLogin();
|
|
269
278
|
// Let the app finish its login callback, then keep only the IdP cookies: the app's own client session
|
|
270
279
|
// does not survive a restore, so every call starts a fresh app client that the IdP signs in silently.
|
|
271
280
|
if (cypressWebsocketLoader)
|
|
@@ -292,6 +301,7 @@ const ssoLogin = (company, urlType, skipvNavCheck) => {
|
|
|
292
301
|
}
|
|
293
302
|
});
|
|
294
303
|
}, { cacheAcrossSpecs: true });
|
|
304
|
+
ssoAlternateUserActive = false;
|
|
295
305
|
cy.visit(url);
|
|
296
306
|
if (company) {
|
|
297
307
|
cy.GLO_selectCompany(company);
|
|
@@ -2056,56 +2066,37 @@ Cypress.Commands.add('GLO_clickButtonInGrid', { prevSubject: ['optional', 'eleme
|
|
|
2056
2066
|
}
|
|
2057
2067
|
cy.GLO_checkLoadingIndicator();
|
|
2058
2068
|
});
|
|
2069
|
+
// Stateless SSO login: the logout only ends the app's Servoy client, the IdP session stays. The app starts a
|
|
2070
|
+
// fresh client right away, which the IdP signs in silently as the user that holds the IdP session, so there is
|
|
2071
|
+
// no IdP login page to fill in. Getting back to that user is just the logout. Another user needs the IdP session
|
|
2072
|
+
// dropped first, so the IdP asks for credentials again.
|
|
2059
2073
|
Cypress.Commands.add('GLO_oktaAlternativeLogin', (altUser, company) => {
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2074
|
+
const userEnv = altUser ? 'username2' : 'username';
|
|
2075
|
+
const passwordEnv = altUser ? 'password2' : 'password';
|
|
2076
|
+
const switchIdpUser = Boolean(altUser) !== ssoAlternateUserActive;
|
|
2063
2077
|
if (cypressWebsocketLoader) {
|
|
2064
2078
|
cy.on('window:before:load', (win) => {
|
|
2065
2079
|
attachWebSocketSpy(win);
|
|
2066
2080
|
});
|
|
2067
2081
|
}
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
cy.
|
|
2076
|
-
cy.
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
});
|
|
2082
|
-
cy.task('log', 'Filled in password');
|
|
2083
|
-
cy.get('[type="submit"]').click();
|
|
2084
|
-
});
|
|
2085
|
-
cy.GLO_log(`Logged in as ${Cypress.expose('username2')}`);
|
|
2086
|
-
}
|
|
2087
|
-
else {
|
|
2088
|
-
cy.origin(ssoUrl(), () => {
|
|
2089
|
-
cy.get('.okta-container', { timeout: 120000 });
|
|
2090
|
-
cy.get('.o-form-input', { timeout: 60000 })
|
|
2091
|
-
.find('[autocomplete="username"]')
|
|
2092
|
-
.clear()
|
|
2093
|
-
.type(Cypress.expose('username'));
|
|
2094
|
-
cy.task('log', 'Filled in username');
|
|
2095
|
-
cy.get('[type="submit"]').click();
|
|
2096
|
-
cy.env(['password']).then(({ password }) => {
|
|
2097
|
-
cy.get('.o-form-input')
|
|
2098
|
-
.find('[type="password"]', { timeout: 20000 })
|
|
2099
|
-
.type(password, { log: false });
|
|
2100
|
-
});
|
|
2101
|
-
cy.task('log', 'Filled in password');
|
|
2102
|
-
cy.get('[type="submit"]').click();
|
|
2103
|
-
});
|
|
2104
|
-
cy.GLO_log(`Logged in as ${Cypress.expose('username')}`);
|
|
2105
|
-
}
|
|
2082
|
+
// Come back on the solution the test is in (GLO_login can start another one than globisUrl), without the hash state
|
|
2083
|
+
cy.location({ log: false }).then((location) => {
|
|
2084
|
+
const appUrl = `${location.origin}${location.pathname}${location.search}`;
|
|
2085
|
+
cy.GLO_logout();
|
|
2086
|
+
if (switchIdpUser) {
|
|
2087
|
+
// clearAllCookies clears every domain, the IdP session included (clearCookies would only clear the app's)
|
|
2088
|
+
cy.clearAllCookies({ log: false });
|
|
2089
|
+
cy.clearAllSessionStorage({ log: false }); // the solution start fails on a missing owner_id otherwise
|
|
2090
|
+
cy.visit(appUrl);
|
|
2091
|
+
idpLogin(userEnv, passwordEnv);
|
|
2092
|
+
ssoAlternateUserActive = Boolean(altUser);
|
|
2093
|
+
}
|
|
2094
|
+
});
|
|
2106
2095
|
if (cypressWebsocketLoader)
|
|
2107
2096
|
waitForWebSocketAfterSso();
|
|
2108
2097
|
cy.get('[data-cy$="ng$main_form2.navbar_top"]', { timeout: 120000 }).should('exist');
|
|
2098
|
+
cy.GLO_checkLoadingIndicator();
|
|
2099
|
+
cy.GLO_log(`Logged in as ${Cypress.expose(userEnv)}`);
|
|
2109
2100
|
if (company)
|
|
2110
2101
|
cy.GLO_checkAndSelectCompany(company);
|
|
2111
2102
|
});
|