From d9ecf51c6daf2fbaefe6d2406dbd302f81001368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=9D=E7=91=AA=E8=B2=93?= Date: Tue, 14 Mar 2023 21:28:35 +0800 Subject: [PATCH] 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. --- tests/test_account.py | 8 ++--- tests/test_base_account.py | 7 ++-- tests/test_currency.py | 8 ++--- tests/test_summary_editor.py | 5 ++- tests/test_transaction.py | 12 +++---- tests/test_utils.py | 18 ++++------ tests/testlib.py | 64 ++++++++++++++++-------------------- 7 files changed, 54 insertions(+), 68 deletions(-) diff --git a/tests/test_account.py b/tests/test_account.py index 0b845fa..81bd739 100644 --- a/tests/test_account.py +++ b/tests/test_account.py @@ -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(): diff --git a/tests/test_base_account.py b/tests/test_base_account.py index 6aa12f6..99f5afc 100644 --- a/tests/test_base_account.py +++ b/tests/test_base_account.py @@ -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(): diff --git a/tests/test_currency.py b/tests/test_currency.py index d9e1315..e1dacfc 100644 --- a/tests/test_currency.py +++ b/tests/test_currency.py @@ -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(): diff --git a/tests/test_summary_editor.py b/tests/test_summary_editor.py index 3f01f57..d631ea6 100644 --- a/tests/test_summary_editor.py +++ b/tests/test_summary_editor.py @@ -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(): diff --git a/tests/test_transaction.py b/tests/test_transaction.py index 9dd9513..0f3694d 100644 --- a/tests/test_transaction.py +++ b/tests/test_transaction.py @@ -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(): diff --git a/tests/test_utils.py b/tests/test_utils.py index bf2f268..54550dd 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -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") diff --git a/tests/testlib.py b/tests/testlib.py index a81ad47..3af90a5 100644 --- a/tests/testlib.py +++ b/tests/testlib.py @@ -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.