Added the "create_test_app" function in testlib.py to replace "create_app" to prevent common mistakes. Added a get_csrf_token_view route to the application, and changed the get_csrf_token function to retrieve the CSRF token with the route without parsing the HTML for the CSRF token.
This commit is contained in:
parent
5d31eb9172
commit
d9ecf51c6d
@ -26,8 +26,8 @@ from click.testing import Result
|
||||
from flask import Flask
|
||||
from flask.testing import FlaskCliRunner
|
||||
|
||||
from test_site import create_app, db
|
||||
from testlib import get_client, set_locale
|
||||
from test_site import db
|
||||
from testlib import create_test_app, get_client, set_locale
|
||||
|
||||
NEXT_URI: str = "/_next"
|
||||
"""The next URI."""
|
||||
@ -74,7 +74,7 @@ class AccountCommandTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
@ -127,7 +127,7 @@ class AccountTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
|
@ -26,8 +26,7 @@ from click.testing import Result
|
||||
from flask import Flask
|
||||
from flask.testing import FlaskCliRunner
|
||||
|
||||
from test_site import create_app
|
||||
from testlib import get_client
|
||||
from testlib import create_test_app, get_client
|
||||
|
||||
LIST_URI: str = "/accounting/base-accounts"
|
||||
"""The list URI."""
|
||||
@ -45,7 +44,7 @@ class BaseAccountCommandTestCase(unittest.TestCase):
|
||||
:return: None.
|
||||
"""
|
||||
from accounting.models import BaseAccount, BaseAccountL10n
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
@ -98,7 +97,7 @@ class BaseAccountTestCase(unittest.TestCase):
|
||||
:return: None.
|
||||
"""
|
||||
from accounting.models import BaseAccount
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
|
@ -27,8 +27,8 @@ from click.testing import Result
|
||||
from flask import Flask
|
||||
from flask.testing import FlaskCliRunner
|
||||
|
||||
from test_site import create_app, db
|
||||
from testlib import get_client, set_locale
|
||||
from test_site import db
|
||||
from testlib import create_test_app, get_client, set_locale
|
||||
|
||||
|
||||
class CurrencyData:
|
||||
@ -67,7 +67,7 @@ class CurrencyCommandTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
@ -123,7 +123,7 @@ class CurrencyTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
|
@ -24,8 +24,7 @@ from click.testing import Result
|
||||
from flask import Flask
|
||||
from flask.testing import FlaskCliRunner
|
||||
|
||||
from test_site import create_app
|
||||
from testlib import get_client
|
||||
from testlib import create_test_app, get_client
|
||||
from testlib_txn import Accounts, NEXT_URI, add_txn
|
||||
|
||||
|
||||
@ -38,7 +37,7 @@ class SummeryEditorTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
|
@ -26,8 +26,8 @@ from click.testing import Result
|
||||
from flask import Flask
|
||||
from flask.testing import FlaskCliRunner
|
||||
|
||||
from test_site import create_app, db
|
||||
from testlib import get_client
|
||||
from test_site import db
|
||||
from testlib import create_test_app, get_client
|
||||
from testlib_txn import Accounts, get_add_form, get_unchanged_update_form, \
|
||||
get_update_form, match_txn_detail, set_negative_amount, \
|
||||
remove_debit_in_a_currency, remove_credit_in_a_currency, NEXT_URI, \
|
||||
@ -48,7 +48,7 @@ class CashIncomeTransactionTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
@ -600,7 +600,7 @@ class CashExpenseTransactionTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
@ -1159,7 +1159,7 @@ class TransferTransactionTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
@ -1973,7 +1973,7 @@ class TransactionReorderTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
runner: FlaskCliRunner = self.app.test_cli_runner()
|
||||
with self.app.app_context():
|
||||
|
@ -21,13 +21,12 @@ import unittest
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
import httpx
|
||||
from flask import Flask, request, render_template_string
|
||||
from flask import Flask, request
|
||||
|
||||
from accounting.utils.next_uri import append_next, inherit_next, or_next
|
||||
from accounting.utils.pagination import Pagination, DEFAULT_PAGE_SIZE
|
||||
from accounting.utils.query import parse_query_keywords
|
||||
from test_site import create_app
|
||||
from testlib import TEST_SERVER
|
||||
from testlib import TEST_SERVER, create_test_app, get_csrf_token
|
||||
|
||||
|
||||
class NextUriTestCase(unittest.TestCase):
|
||||
@ -40,12 +39,7 @@ class NextUriTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
|
||||
@self.app.get("/test-csrf")
|
||||
def test_csrf() -> str:
|
||||
"""The test view to return the CSRF token."""
|
||||
return render_template_string("{{csrf_token()}}")
|
||||
self.app: Flask = create_test_app()
|
||||
|
||||
def test_next_uri(self) -> None:
|
||||
"""Tests the next URI utilities with the next URI.
|
||||
@ -69,7 +63,7 @@ class NextUriTestCase(unittest.TestCase):
|
||||
methods=["GET", "POST"])
|
||||
client: httpx.Client = httpx.Client(app=self.app, base_url=TEST_SERVER)
|
||||
client.headers["Referer"] = TEST_SERVER
|
||||
csrf_token: str = client.get("/test-csrf").text
|
||||
csrf_token: str = get_csrf_token(client)
|
||||
response: httpx.Response
|
||||
|
||||
response = client.get("/test-next?next=/next&q=abc&page-no=4")
|
||||
@ -98,7 +92,7 @@ class NextUriTestCase(unittest.TestCase):
|
||||
methods=["GET", "POST"])
|
||||
client: httpx.Client = httpx.Client(app=self.app, base_url=TEST_SERVER)
|
||||
client.headers["Referer"] = TEST_SERVER
|
||||
csrf_token: str = client.get("/test-csrf").text
|
||||
csrf_token: str = get_csrf_token(client)
|
||||
response: httpx.Response
|
||||
|
||||
response = client.get("/test-no-next?q=abc&page-no=4")
|
||||
@ -171,7 +165,7 @@ class PaginationTestCase(unittest.TestCase):
|
||||
|
||||
:return: None.
|
||||
"""
|
||||
self.app: Flask = create_app(is_testing=True)
|
||||
self.app: Flask = create_test_app()
|
||||
self.params = self.Params([], None, [], True)
|
||||
|
||||
@self.app.get("/test-pagination")
|
||||
|
@ -18,15 +18,41 @@
|
||||
|
||||
"""
|
||||
import typing as t
|
||||
from html.parser import HTMLParser
|
||||
|
||||
import httpx
|
||||
from flask import Flask
|
||||
from flask import Flask, render_template_string
|
||||
|
||||
from test_site import create_app
|
||||
|
||||
TEST_SERVER: str = "https://testserver"
|
||||
"""The test server URI."""
|
||||
|
||||
|
||||
def create_test_app() -> Flask:
|
||||
"""Creates and returns the testing Flask application.
|
||||
|
||||
:return: The testing Flask application.
|
||||
"""
|
||||
app: Flask = create_app(is_testing=True)
|
||||
|
||||
@app.get("/.csrf-token")
|
||||
def get_csrf_token_view() -> str:
|
||||
"""The test view to return the CSRF token."""
|
||||
return render_template_string("{{csrf_token()}}")
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def get_csrf_token(client: httpx.Client) -> str:
|
||||
"""Returns the CSRF token.
|
||||
|
||||
:param client: The httpx client.
|
||||
:return: The CSRF token.
|
||||
"""
|
||||
return client.get("/.csrf-token").text
|
||||
|
||||
|
||||
|
||||
def get_client(app: Flask, username: str) -> tuple[httpx.Client, str]:
|
||||
"""Returns a user client.
|
||||
|
||||
@ -36,7 +62,7 @@ def get_client(app: Flask, username: str) -> tuple[httpx.Client, str]:
|
||||
"""
|
||||
client: httpx.Client = httpx.Client(app=app, base_url=TEST_SERVER)
|
||||
client.headers["Referer"] = TEST_SERVER
|
||||
csrf_token: str = get_csrf_token(client, "/login")
|
||||
csrf_token: str = get_csrf_token(client)
|
||||
response: httpx.Response = client.post("/login",
|
||||
data={"csrf_token": csrf_token,
|
||||
"username": username})
|
||||
@ -45,38 +71,6 @@ def get_client(app: Flask, username: str) -> tuple[httpx.Client, str]:
|
||||
return client, csrf_token
|
||||
|
||||
|
||||
def get_csrf_token(client: httpx.Client, uri: str) -> str:
|
||||
"""Returns the CSRF token from a form in a URI.
|
||||
|
||||
:param client: The httpx client.
|
||||
:param uri: The URI.
|
||||
:return: The CSRF token.
|
||||
"""
|
||||
|
||||
class CsrfParser(HTMLParser):
|
||||
"""The CSRF token parser."""
|
||||
|
||||
def __init__(self):
|
||||
"""Constructs the CSRF token parser."""
|
||||
super().__init__()
|
||||
self.csrf_token: str | None = None
|
||||
"""The CSRF token."""
|
||||
|
||||
def handle_starttag(self, tag: str,
|
||||
attrs: list[tuple[str, str | None]]) -> None:
|
||||
"""Handles when a start tag is found."""
|
||||
attrs_dict: dict[str, str] = dict(attrs)
|
||||
if attrs_dict.get("name") == "csrf_token":
|
||||
self.csrf_token = attrs_dict["value"]
|
||||
|
||||
response: httpx.Response = client.get(uri)
|
||||
assert response.status_code == 200
|
||||
parser: CsrfParser = CsrfParser()
|
||||
parser.feed(response.text)
|
||||
assert parser.csrf_token is not None
|
||||
return parser.csrf_token
|
||||
|
||||
|
||||
def set_locale(client: httpx.Client, csrf_token: str,
|
||||
locale: t.Literal["en", "zh_Hant", "zh_Hans"]) -> None:
|
||||
"""Sets the current locale.
|
||||
|
Loading…
Reference in New Issue
Block a user