authentik.flows.tests
Test helpers
1"""Test helpers""" 2 3from collections.abc import Callable, Generator 4from contextlib import contextmanager 5from json import loads 6from typing import Any 7from unittest.mock import MagicMock, patch 8 9from django.http.response import HttpResponse 10from django.urls.base import reverse 11from rest_framework.test import APITestCase 12 13from authentik.core.models import User 14from authentik.flows.models import Flow 15from authentik.flows.planner import FlowPlan 16from authentik.flows.views.executor import SESSION_KEY_PLAN 17 18 19class FlowTestCase(APITestCase): 20 """Helpers for testing flows and stages.""" 21 22 def assertStageResponse( 23 self, 24 response: HttpResponse, 25 flow: Flow | None = None, 26 user: User | None = None, 27 **kwargs, 28 ) -> dict[str, Any]: 29 """Assert various attributes of a stage response""" 30 self.assertEqual(response.status_code, 200) 31 raw_response = loads(response.content.decode()) 32 self.assertIsNotNone(raw_response["component"]) 33 if flow: 34 self.assertIn("flow_info", raw_response) 35 self.assertTrue( 36 raw_response["flow_info"]["cancel_url"].startswith( 37 reverse("authentik_flows:cancel") 38 ) 39 ) 40 # We don't check the flow title since it will most likely go 41 # through ChallengeStageView.format_title() so might not match 1:1 42 # self.assertEqual(raw_response["flow_info"]["title"], flow.title) 43 self.assertIsNotNone(raw_response["flow_info"]["title"]) 44 if user: 45 self.assertEqual(raw_response["pending_user"], user.username) 46 self.assertEqual(raw_response["pending_user_avatar"], user.avatar) 47 for key, expected in kwargs.items(): 48 self.assertEqual(raw_response[key], expected) 49 return raw_response 50 51 def get_flow_plan(self) -> FlowPlan | None: 52 return self.client.session.get(SESSION_KEY_PLAN) 53 54 def set_flow_plan(self, plan: FlowPlan): 55 session = self.client.session 56 session[SESSION_KEY_PLAN] = plan 57 session.save() 58 59 def assertStageRedirects(self, response: HttpResponse, to: str) -> dict[str, Any]: 60 """Wrapper around assertStageResponse that checks for a redirect""" 61 return self.assertStageResponse(response, component="xak-flow-redirect", to=to) 62 63 @contextmanager 64 def assertFlowFinishes(self) -> Generator[Callable[[], FlowPlan]]: 65 """Capture the flow plan before the flow finishes and return it""" 66 try: 67 with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()): 68 yield lambda: self.client.session.get(SESSION_KEY_PLAN) 69 finally: 70 pass
class
FlowTestCase(rest_framework.test.APITestCase):
20class FlowTestCase(APITestCase): 21 """Helpers for testing flows and stages.""" 22 23 def assertStageResponse( 24 self, 25 response: HttpResponse, 26 flow: Flow | None = None, 27 user: User | None = None, 28 **kwargs, 29 ) -> dict[str, Any]: 30 """Assert various attributes of a stage response""" 31 self.assertEqual(response.status_code, 200) 32 raw_response = loads(response.content.decode()) 33 self.assertIsNotNone(raw_response["component"]) 34 if flow: 35 self.assertIn("flow_info", raw_response) 36 self.assertTrue( 37 raw_response["flow_info"]["cancel_url"].startswith( 38 reverse("authentik_flows:cancel") 39 ) 40 ) 41 # We don't check the flow title since it will most likely go 42 # through ChallengeStageView.format_title() so might not match 1:1 43 # self.assertEqual(raw_response["flow_info"]["title"], flow.title) 44 self.assertIsNotNone(raw_response["flow_info"]["title"]) 45 if user: 46 self.assertEqual(raw_response["pending_user"], user.username) 47 self.assertEqual(raw_response["pending_user_avatar"], user.avatar) 48 for key, expected in kwargs.items(): 49 self.assertEqual(raw_response[key], expected) 50 return raw_response 51 52 def get_flow_plan(self) -> FlowPlan | None: 53 return self.client.session.get(SESSION_KEY_PLAN) 54 55 def set_flow_plan(self, plan: FlowPlan): 56 session = self.client.session 57 session[SESSION_KEY_PLAN] = plan 58 session.save() 59 60 def assertStageRedirects(self, response: HttpResponse, to: str) -> dict[str, Any]: 61 """Wrapper around assertStageResponse that checks for a redirect""" 62 return self.assertStageResponse(response, component="xak-flow-redirect", to=to) 63 64 @contextmanager 65 def assertFlowFinishes(self) -> Generator[Callable[[], FlowPlan]]: 66 """Capture the flow plan before the flow finishes and return it""" 67 try: 68 with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()): 69 yield lambda: self.client.session.get(SESSION_KEY_PLAN) 70 finally: 71 pass
Helpers for testing flows and stages.
def
assertStageResponse( self, response: django.http.response.HttpResponse, flow: authentik.flows.models.Flow | None = None, user: authentik.core.models.User | None = None, **kwargs) -> dict[str, typing.Any]:
23 def assertStageResponse( 24 self, 25 response: HttpResponse, 26 flow: Flow | None = None, 27 user: User | None = None, 28 **kwargs, 29 ) -> dict[str, Any]: 30 """Assert various attributes of a stage response""" 31 self.assertEqual(response.status_code, 200) 32 raw_response = loads(response.content.decode()) 33 self.assertIsNotNone(raw_response["component"]) 34 if flow: 35 self.assertIn("flow_info", raw_response) 36 self.assertTrue( 37 raw_response["flow_info"]["cancel_url"].startswith( 38 reverse("authentik_flows:cancel") 39 ) 40 ) 41 # We don't check the flow title since it will most likely go 42 # through ChallengeStageView.format_title() so might not match 1:1 43 # self.assertEqual(raw_response["flow_info"]["title"], flow.title) 44 self.assertIsNotNone(raw_response["flow_info"]["title"]) 45 if user: 46 self.assertEqual(raw_response["pending_user"], user.username) 47 self.assertEqual(raw_response["pending_user_avatar"], user.avatar) 48 for key, expected in kwargs.items(): 49 self.assertEqual(raw_response[key], expected) 50 return raw_response
Assert various attributes of a stage response
def
assertStageRedirects( self, response: django.http.response.HttpResponse, to: str) -> dict[str, typing.Any]:
60 def assertStageRedirects(self, response: HttpResponse, to: str) -> dict[str, Any]: 61 """Wrapper around assertStageResponse that checks for a redirect""" 62 return self.assertStageResponse(response, component="xak-flow-redirect", to=to)
Wrapper around assertStageResponse that checks for a redirect
@contextmanager
def
assertFlowFinishes(self) -> Generator[Callable[[], authentik.flows.planner.FlowPlan]]:
64 @contextmanager 65 def assertFlowFinishes(self) -> Generator[Callable[[], FlowPlan]]: 66 """Capture the flow plan before the flow finishes and return it""" 67 try: 68 with patch("authentik.flows.views.executor.FlowExecutorView.cancel", MagicMock()): 69 yield lambda: self.client.session.get(SESSION_KEY_PLAN) 70 finally: 71 pass
Capture the flow plan before the flow finishes and return it