web: fix e2e tests to work with latest WebdriverIO and authentik 2024.8 (#11105)

* web: fix e2e tests to work with latest WebdriverIO and authentik 2024.8

- Adjust the ApplicationWizard "select provider type" typeslist to have the right OUIA tags when
  running
- Add OUIA tags to TypeCreateWizard
- Provide default values for `.jwksSources` when needed.
- Upgrade E2E WebUI tests to use WebdriverIO 9.
- Upgrade the linters to include `package.json` and `package-lock.json`.
- Adjust a *lot* of the WebdriverIO selectors!
- Provide a driver for the TypeCreate card-based radio interface.
- Split `Bad Logins` into two separate files.

Aside from the obvious, "because testing needs this" or "because there were warnings on the console
when this was running," the real issue is that WebdriverIO 9 has changed the syntax and semantics of
its ShadowDOM-piercing `$` mechanism.

For Oauth2 and Proxy, the field `.jwksSources` may be undefined, but `undefined` is not a legal
value for ak-dual-select's `selected` field. Provide a default or use `ifDefined()`. I chose to
provide a default of `[]`.

In the previous iteration, `$(">>>ak-search-select input")` would be sufficient for WebdriverIO to
find an input inside a component. Now, it needs to be written as: `$("ak-search-select").$("input")`.
And in rare cases, when you have a floating component that is separated from its invocation (such as
Notification or SearchSelect), even that doesn't work well and you have to fall back to some
old-school hacking (see `./tests/wdio/test/pageobjects/page.ts` for an example) to find some child
elements.

Also, the monadic nature of `$` seems to have faded a bit. `$` used to wrap all child invocations in
promises, making the entire expression a single valid promise; it seems that it is now necessary to
unwrap the promises yourself under some circumstances, resulting in a lot of `await (await (await
... )))` blocks in the tests.

We've slightly changed the semantics of our login mechanism, and now the default behavior is to not
reveal when a username is invalid, but to treat the entire login as a single failure mechanism, so
as not to expose any details about the username database.

The problem arises that now, we (or Chrome) cache the username between roundtrips, and WebdriverIO's
second pass was becoming confused by its presence.  By putting the Bad Logins into two separate
files, I get two separate browser instances with cleared caches, so each test can be run in the
pristine environment it needs to validate the behavior I'm expecting.

* web: added comment to explain the  hack

* Add comment to TypeCreateWizardPage to explain the component name hack.

* web: fix some lint found by CI/CD
This commit is contained in:
Ken Sternberg
2024-08-29 07:04:53 -07:00
committed by GitHub
parent 59fa449abe
commit 9c45ec1918
25 changed files with 2494 additions and 2158 deletions

View File

@ -21,10 +21,20 @@ export class ApplicationWizardAuthenticationMethodChoice extends WithLicenseSumm
const selectedTypes = providerModelsList.filter(
(t) => t.formName === this.wizard.providerModel,
);
// As a hack, the Application wizard has separate provider paths for our three types of
// proxy providers. This patch swaps the form we want to be directed to on page 3 from the
// modelName to the formName, so we get the right one. This information isn't modified
// or forwarded, so the proxy-plus-subtype is correctly mapped on submission.
const typesForWizard = providerModelsList.map((provider) => ({
...provider,
modelName: provider.formName,
}));
return providerModelsList.length > 0
? html`<form class="pf-c-form pf-m-horizontal">
<ak-wizard-page-type-create
.types=${providerModelsList}
.types=${typesForWizard}
layout=${TypeCreateWizardPageLayouts.grid}
.selectedType=${selectedTypes.length > 0 ? selectedTypes[0] : undefined}
@select=${(ev: CustomEvent<LocalTypeCreate>) => {

View File

@ -265,7 +265,7 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel {
>
<ak-dual-select-provider
.provider=${oauth2SourcesProvider}
.selected=${provider?.jwksSources}
.selected=${provider?.jwksSources ?? []}
available-label=${msg("Available Sources")}
selected-label=${msg("Selected Sources")}
></ak-dual-select-provider>

View File

@ -230,7 +230,7 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
>
<ak-dual-select-provider
.provider=${oauth2SourcesProvider}
.selected=${this.instance?.jwksSources}
.selected=${this.instance?.jwksSources ?? []}
available-label=${msg("Available Sources")}
selected-label=${msg("Selected Sources")}
></ak-dual-select-provider>

View File

@ -69,9 +69,19 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
}
renderGrid(): TemplateResult {
return html`<div class="pf-l-grid pf-m-gutter">
return html`<div
class="pf-l-grid pf-m-gutter"
data-ouid-component-type="ak-type-create-grid"
>
${this.types.map((type, idx) => {
const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
// It's valid to pass in a local modelName or the full name with application
// part. If the latter, we only want the part after the dot to appear as our
// OUIA tag for test automation.
const componentName = type.modelName.includes(".")
? (type.modelName.split(".")[1] ?? "--unknown--")
: type.modelName;
return html`<div
class="pf-l-grid__item pf-m-3-col pf-c-card ${requiresEnterprise
? "pf-m-non-selectable-raised"
@ -79,6 +89,8 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
? "pf-m-selected-raised"
: ""}"
tabindex=${idx}
data-ouid-component-type="ak-type-create-grid-card"
data-ouid-component-name=${componentName}
@click=${() => {
if (requiresEnterprise) {
return;
@ -107,10 +119,17 @@ export class TypeCreateWizardPage extends WithLicenseSummary(WizardPage) {
}
renderList(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
return html`<form
class="pf-c-form pf-m-horizontal"
data-ouid-component-type="ak-type-create-list"
>
${this.types.map((type) => {
const requiresEnterprise = type.requiresEnterprise && !this.hasEnterpriseLicense;
return html`<div class="pf-c-radio">
return html`<div
class="pf-c-radio"
data-ouid-component-type="ak-type-create-list-card"
data-ouid-component-name=${type.modelName.split(".")[1] ?? "--unknown--"}
>
<input
class="pf-c-radio__input"
type="radio"