tests/e2e: Add E2E tests for Flow SFE (#14484)
* add e2e test for SFE login Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add helper text in SFE on password stage Signed-off-by: Jens Langhammer <jens@goauthentik.io> * build sfe for e2e Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix ci e2e cache key not considering sfe Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix sfe missing from docker build Signed-off-by: Jens Langhammer <jens@goauthentik.io> * sigh I forgot npm Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
3
.github/workflows/ci-main.yml
vendored
3
.github/workflows/ci-main.yml
vendored
@ -200,7 +200,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: web/dist
|
path: web/dist
|
||||||
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**') }}
|
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
|
||||||
- name: prepare web ui
|
- name: prepare web ui
|
||||||
if: steps.cache-web.outputs.cache-hit != 'true'
|
if: steps.cache-web.outputs.cache-hit != 'true'
|
||||||
working-directory: web
|
working-directory: web
|
||||||
@ -208,6 +208,7 @@ jobs:
|
|||||||
npm ci
|
npm ci
|
||||||
make -C .. gen-client-ts
|
make -C .. gen-client-ts
|
||||||
npm run build
|
npm run build
|
||||||
|
npm run build:sfe
|
||||||
- name: run e2e
|
- name: run e2e
|
||||||
run: |
|
run: |
|
||||||
uv run coverage run manage.py test ${{ matrix.job.glob }}
|
uv run coverage run manage.py test ${{ matrix.job.glob }}
|
||||||
|
@ -40,7 +40,8 @@ COPY ./web /work/web/
|
|||||||
COPY ./website /work/website/
|
COPY ./website /work/website/
|
||||||
COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
|
COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
|
||||||
|
|
||||||
RUN npm run build
|
RUN npm run build && \
|
||||||
|
npm run build:sfe
|
||||||
|
|
||||||
# Stage 3: Build go proxy
|
# Stage 3: Build go proxy
|
||||||
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
|
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
|
||||||
|
51
tests/e2e/test_flows_login_sfe.py
Normal file
51
tests/e2e/test_flows_login_sfe.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
"""test default login (using SFE interface) flow"""
|
||||||
|
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
|
||||||
|
from authentik.blueprints.tests import apply_blueprint
|
||||||
|
from tests.e2e.utils import SeleniumTestCase, retry
|
||||||
|
|
||||||
|
|
||||||
|
class TestFlowsLoginSFE(SeleniumTestCase):
|
||||||
|
"""test default login flow"""
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
"""Do entire login flow adjusted for SFE"""
|
||||||
|
flow_executor = self.driver.find_element(By.ID, "flow-sfe-container")
|
||||||
|
identification_stage = flow_executor.find_element(By.ID, "ident-form")
|
||||||
|
|
||||||
|
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uid_field]").click()
|
||||||
|
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uid_field]").send_keys(
|
||||||
|
self.user.username
|
||||||
|
)
|
||||||
|
identification_stage.find_element(By.CSS_SELECTOR, "input[name=uid_field]").send_keys(
|
||||||
|
Keys.ENTER
|
||||||
|
)
|
||||||
|
|
||||||
|
password_stage = flow_executor.find_element(By.ID, "password-form")
|
||||||
|
password_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(
|
||||||
|
self.user.username
|
||||||
|
)
|
||||||
|
password_stage.find_element(By.CSS_SELECTOR, "input[name=password]").send_keys(Keys.ENTER)
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
@retry()
|
||||||
|
@apply_blueprint(
|
||||||
|
"default/flow-default-authentication-flow.yaml",
|
||||||
|
"default/flow-default-invalidation-flow.yaml",
|
||||||
|
)
|
||||||
|
def test_login(self):
|
||||||
|
"""test default login flow"""
|
||||||
|
self.driver.get(
|
||||||
|
self.url(
|
||||||
|
"authentik_core:if-flow",
|
||||||
|
flow_slug="default-authentication-flow",
|
||||||
|
query={"sfe": True},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.login()
|
||||||
|
self.wait_for_url(self.if_user_url("/library"))
|
||||||
|
self.assert_user(self.user)
|
@ -241,7 +241,7 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
|
|||||||
return element
|
return element
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
"""Do entire login flow and check user afterwards"""
|
"""Do entire login flow"""
|
||||||
flow_executor = self.get_shadow_root("ak-flow-executor")
|
flow_executor = self.get_shadow_root("ak-flow-executor")
|
||||||
identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
|
identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
|
||||||
|
|
||||||
|
@ -210,6 +210,9 @@ class PasswordStage extends Stage<PasswordChallenge> {
|
|||||||
<form id="password-form">
|
<form id="password-form">
|
||||||
<img class="mb-4 brand-icon" src="${ak().brand.branding_logo}" alt="">
|
<img class="mb-4 brand-icon" src="${ak().brand.branding_logo}" alt="">
|
||||||
<h1 class="h3 mb-3 fw-normal text-center">${this.challenge?.flowInfo?.title}</h1>
|
<h1 class="h3 mb-3 fw-normal text-center">${this.challenge?.flowInfo?.title}</h1>
|
||||||
|
<div class="form-label-group my-3">
|
||||||
|
<input type="text" readonly class="form-control-plaintext" value="Welcome, ${this.challenge?.pendingUser}.">
|
||||||
|
</div>
|
||||||
<div class="form-label-group my-3 has-validation">
|
<div class="form-label-group my-3 has-validation">
|
||||||
<input type="password" autofocus class="form-control ${this.error("password").length > 0 ? IS_INVALID : ""}" name="password" placeholder="Password">
|
<input type="password" autofocus class="form-control ${this.error("password").length > 0 ? IS_INVALID : ""}" name="password" placeholder="Password">
|
||||||
${this.renderInputError("password")}
|
${this.renderInputError("password")}
|
||||||
|
Reference in New Issue
Block a user