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:
依瑪貓 2023-03-14 21:28:35 +08:00
parent 5d31eb9172
commit d9ecf51c6d
7 changed files with 54 additions and 68 deletions

View File

@ -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():

View File

@ -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():

View File

@ -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():

View File

@ -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():

View File

@ -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():

View File

@ -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")

View File

@ -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.