From d056146a449c6d7e295039b25cba981d5eb6eea7 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Mon, 19 Feb 2024 08:14:35 +0000 Subject: [PATCH 1/9] #11 Added extra functional tests for admin endpoints --- tests/functional/__init__.py | 16 ++++++++++++++++ tests/functional/test_homepage.py | 26 ++++++++++++-------------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/tests/functional/__init__.py b/tests/functional/__init__.py index e69de29..06bf919 100644 --- a/tests/functional/__init__.py +++ b/tests/functional/__init__.py @@ -0,0 +1,16 @@ +from app import app +from flask.testing import FlaskClient +import pytest +import os + + +@pytest.fixture(scope="module") +def test_client() -> FlaskClient: + """ Test that required environment variables are set + ahead of runtime + """ + os.environ['CONFIG_TYPE'] = 'config.TestingConfig' + + with app.test_client() as testing_client: + with app.app_context(): + yield testing_client diff --git a/tests/functional/test_homepage.py b/tests/functional/test_homepage.py index b66d439..d570fc2 100644 --- a/tests/functional/test_homepage.py +++ b/tests/functional/test_homepage.py @@ -1,19 +1,6 @@ -from app import app from flask.testing import FlaskClient +from tests.functional import test_client import pytest -import os - - -@pytest.fixture(scope="module") -def test_client() -> FlaskClient: - """ Test that required environment variables are set - ahead of runtime - """ - os.environ['CONFIG_TYPE'] = 'config.TestingConfig' - - with app.test_client() as testing_client: - with app.app_context(): - yield testing_client def test_homepage(test_client: FlaskClient): @@ -39,3 +26,14 @@ def test_products(test_client: FlaskClient): response = test_client.get('/products/Books') assert response.status_code == 200 + + +def test_admin(test_client: FlaskClient): + """ Tests that the admin pages can be reached and redirect + upon reaching + """ + response = test_client.get('/admin/users/') + assert response.status_code == 302 + + response = test_client.get('/admin/products/') + assert response.status_code == 302 From bcde471f33fd9caedc6643ac030421ead94fcab2 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Fri, 23 Feb 2024 18:24:57 +0000 Subject: [PATCH 2/9] #11 Starting on the creation of an end to end test environment --- requirements.txt | Bin 491 -> 1128 bytes scripts/create_database.py | 23 ++++++++++++++--------- tests/__init__.py | 17 +++++++++++++++++ tests/endtoend/__init__.py | 0 tests/endtoend/use_cases_test.py | 8 ++++++++ tests/functional/__init__.py | 16 ---------------- tests/functional/test_homepage.py | 2 +- tests/unit/database/__init__.py | 3 +-- 8 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 tests/endtoend/__init__.py create mode 100644 tests/endtoend/use_cases_test.py diff --git a/requirements.txt b/requirements.txt index 361fe5c828949c6d16a86b580d673780ebfc8dc4..1ea46d7948919644f9a9696dc3ae3d4548ff1fb5 100644 GIT binary patch literal 1128 zcmYk5O;5sL5QO(^;!i2zTReF6VB*PxXRv^LwWOsG{PF5DyS$|#Mbn*~ota(!e&^QM z$x1ugl4oWwe1_JuKF`=5?ZFmQ0=2Of=)Kk88_;7%k3kN+XLQ5wZDWP)=&Kwt0P*CU z;`@SO!}rc>Gw)VCY9-Z@zPTNEq$ZT~Z0d-d-WtW?ShV$#PY^@SPFyAm0j*%nj z9Nsue=8L6rrEAMPgUn}ED9h=*+j65qbGD?sy2Oa4`Pvm&?$T* zCTzpxH5*ku)ZMFBPcuiq_IU-}bs}_{d1aDvU*FW~9;Tf+x|m?m9NnuB$;;P@^b;P0a<~n`J@?l?Vql1XFvSau7pT; HAL;)CR2!wy literal 491 zcmYjNyKciU4BQR)Q!Mz=Hp!s1LxD~mIxCW_GL}U_k`uUJUs49zjz=Ev!K;U`*d*m3 zPNHuc?LjY6o&{k-=rO5PN!g1h@zOR1a`A9wJTbw99QX2tLCTRBBTZ1}k|4OQV7IEY z7<|yS7sJ#xGkEKf4JN{3Xq#8Ba)mv+Lja9o2FG&8q-3LlvkAA%!+||+)?iyvyX2cK-C(u;DGi6#?sqDmQA;VgLVRhcoZ1`>Httbwyczd5(_W2OrC z6@#NA`on>X%|*%+)n<+Qh0f>L-7yIhxPII<8j7;}qcFMt#xYo`92FA75B*7xg#Z8m diff --git a/scripts/create_database.py b/scripts/create_database.py index 3a841eb..b8faef9 100644 --- a/scripts/create_database.py +++ b/scripts/create_database.py @@ -38,14 +38,19 @@ def create_connection(path: str, filename: str): # Ensure a directory is created given a path to it -dir = r"./data/" -db_name = r"wmgzon.db" +if __name__ == "__main__": + run() -# Check for test environ -if os.environ.get("ENVIRON") == "test": - # Remove the original test database - print("TEST ENVIRONMENT ACTIVE") - db_name = "test_" + db_name - remove_file(dir + db_name) +def run(): + """ Create the database for the application""" + dir = r"./data/" + db_name = r"wmgzon.db" -create_connection(dir, db_name) + # Check for test environ + if os.environ.get("ENVIRON") == "test": + # Remove the original test database + print("TEST ENVIRONMENT ACTIVE") + db_name = "test_" + db_name + remove_file(dir + db_name) + + create_connection(dir, db_name) diff --git a/tests/__init__.py b/tests/__init__.py index a6b29a5..59f2e74 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,5 +1,10 @@ +import pytest import os +from scripts.create_database import run +from app import app from dotenv import load_dotenv +from flask.testing import FlaskClient + # Setup test environment variables load_dotenv() @@ -8,3 +13,15 @@ load_dotenv() # Monitor current setting during tests old_env = os.environ.get("ENVIRON") os.environ["ENVIRON"] = "test" + +run() + +@pytest.fixture(scope="module") +def test_client() -> FlaskClient: + """ Enables tests to create requests to the web app + """ + os.environ['CONFIG_TYPE'] = 'config.TestingConfig' + + with app.test_client() as testing_client: + with app.app_context(): + yield testing_client diff --git a/tests/endtoend/__init__.py b/tests/endtoend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/endtoend/use_cases_test.py b/tests/endtoend/use_cases_test.py new file mode 100644 index 0000000..e9f315c --- /dev/null +++ b/tests/endtoend/use_cases_test.py @@ -0,0 +1,8 @@ +import pytest +from bs4 import BeautifulSoup +from tests import test_client +from flask.testing import FlaskClient + +# def test_use_case(test_client: FlaskClient): +# response = test_client.get('/products/Car Parts') +# assert response.status_code == 200 \ No newline at end of file diff --git a/tests/functional/__init__.py b/tests/functional/__init__.py index 06bf919..e69de29 100644 --- a/tests/functional/__init__.py +++ b/tests/functional/__init__.py @@ -1,16 +0,0 @@ -from app import app -from flask.testing import FlaskClient -import pytest -import os - - -@pytest.fixture(scope="module") -def test_client() -> FlaskClient: - """ Test that required environment variables are set - ahead of runtime - """ - os.environ['CONFIG_TYPE'] = 'config.TestingConfig' - - with app.test_client() as testing_client: - with app.app_context(): - yield testing_client diff --git a/tests/functional/test_homepage.py b/tests/functional/test_homepage.py index d570fc2..b2803cb 100644 --- a/tests/functional/test_homepage.py +++ b/tests/functional/test_homepage.py @@ -1,5 +1,5 @@ from flask.testing import FlaskClient -from tests.functional import test_client +from tests import test_client import pytest diff --git a/tests/unit/database/__init__.py b/tests/unit/database/__init__.py index 9bd5abe..2257c58 100644 --- a/tests/unit/database/__init__.py +++ b/tests/unit/database/__init__.py @@ -1,3 +1,2 @@ # Ensure test environment is set before using -# Runs the database creation scripts -import scripts.create_database +# Runs the database creation scripts \ No newline at end of file From 68f738a241065caa887b7293092c20447cd036e8 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Fri, 23 Feb 2024 18:33:19 +0000 Subject: [PATCH 3/9] #11 Fixed pep8 test failures --- scripts/create_database.py | 1 + tests/__init__.py | 1 + tests/endtoend/use_cases_test.py | 7 ++++--- tests/unit/database/__init__.py | 2 -- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/create_database.py b/scripts/create_database.py index b8faef9..9c8f1b8 100644 --- a/scripts/create_database.py +++ b/scripts/create_database.py @@ -41,6 +41,7 @@ def create_connection(path: str, filename: str): if __name__ == "__main__": run() + def run(): """ Create the database for the application""" dir = r"./data/" diff --git a/tests/__init__.py b/tests/__init__.py index 59f2e74..b79d54f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -16,6 +16,7 @@ os.environ["ENVIRON"] = "test" run() + @pytest.fixture(scope="module") def test_client() -> FlaskClient: """ Enables tests to create requests to the web app diff --git a/tests/endtoend/use_cases_test.py b/tests/endtoend/use_cases_test.py index e9f315c..17babdc 100644 --- a/tests/endtoend/use_cases_test.py +++ b/tests/endtoend/use_cases_test.py @@ -3,6 +3,7 @@ from bs4 import BeautifulSoup from tests import test_client from flask.testing import FlaskClient -# def test_use_case(test_client: FlaskClient): -# response = test_client.get('/products/Car Parts') -# assert response.status_code == 200 \ No newline at end of file + +def test_use_case(test_client: FlaskClient): + response = test_client.get('/products/Car Parts') + assert response.status_code == 200 diff --git a/tests/unit/database/__init__.py b/tests/unit/database/__init__.py index 2257c58..e69de29 100644 --- a/tests/unit/database/__init__.py +++ b/tests/unit/database/__init__.py @@ -1,2 +0,0 @@ -# Ensure test environment is set before using -# Runs the database creation scripts \ No newline at end of file From 7a9bc61d041d057267cd31ff6736943a238d24e5 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Fri, 23 Feb 2024 21:15:06 +0000 Subject: [PATCH 4/9] #11 REFACTOR: Moved all tests into test classes --- pep8.bat | 1 + scripts/create_database.py | 10 +-- tests/__init__.py | 28 -------- tests/base_test.py | 39 ++++++++++ tests/endtoend/use_cases_test.py | 10 +-- tests/functional/test_homepage.py | 39 ---------- tests/functional/test_pages.py | 41 +++++++++++ tests/unit/database/database_test_class.py | 8 +++ tests/unit/database/test_products.py | 82 +++++++++++----------- tests/unit/database/test_users.py | 79 +++++++++++---------- tests/unit/general/test_env.py | 46 ++++++------ tests/unit/general/test_pep8.py | 14 ++-- venv.bat | 1 - 13 files changed, 210 insertions(+), 188 deletions(-) create mode 100644 pep8.bat create mode 100644 tests/base_test.py delete mode 100644 tests/functional/test_homepage.py create mode 100644 tests/functional/test_pages.py create mode 100644 tests/unit/database/database_test_class.py delete mode 100644 venv.bat diff --git a/pep8.bat b/pep8.bat new file mode 100644 index 0000000..96105a1 --- /dev/null +++ b/pep8.bat @@ -0,0 +1 @@ +autopep8 --exclude '*/.*/*' --in-place --recursive . \ No newline at end of file diff --git a/scripts/create_database.py b/scripts/create_database.py index 9c8f1b8..31cfd0c 100644 --- a/scripts/create_database.py +++ b/scripts/create_database.py @@ -37,11 +37,6 @@ def create_connection(path: str, filename: str): conn.close() -# Ensure a directory is created given a path to it -if __name__ == "__main__": - run() - - def run(): """ Create the database for the application""" dir = r"./data/" @@ -55,3 +50,8 @@ def run(): remove_file(dir + db_name) create_connection(dir, db_name) + + +# Ensure a directory is created given a path to it +if __name__ == "__main__": + run() diff --git a/tests/__init__.py b/tests/__init__.py index b79d54f..e69de29 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,28 +0,0 @@ -import pytest -import os -from scripts.create_database import run -from app import app -from dotenv import load_dotenv -from flask.testing import FlaskClient - - -# Setup test environment variables -load_dotenv() - -# Capture environment variables at start of testing so we can -# Monitor current setting during tests -old_env = os.environ.get("ENVIRON") -os.environ["ENVIRON"] = "test" - -run() - - -@pytest.fixture(scope="module") -def test_client() -> FlaskClient: - """ Enables tests to create requests to the web app - """ - os.environ['CONFIG_TYPE'] = 'config.TestingConfig' - - with app.test_client() as testing_client: - with app.app_context(): - yield testing_client diff --git a/tests/base_test.py b/tests/base_test.py new file mode 100644 index 0000000..f503345 --- /dev/null +++ b/tests/base_test.py @@ -0,0 +1,39 @@ +import pytest +import os +from scripts.create_database import run +from app import app +from dotenv import load_dotenv +from flask.testing import FlaskClient + + +class TestBase: + """ Base test class that ensures environment variables + and test setup is complete before any other unit tests are run + """ + + def setup_class(self): + """ Setup class level resources or configurations + Setup test environment variables + """ + load_dotenv() + + # Capture environment variables at start of testing so we can + # Monitor current setting during tests + self.old_env = os.environ.get("ENVIRON") + os.environ["ENVIRON"] = "test" + + run() + + def teardown_class(self): + """ Teardown class level resources or configurations """ + pass + + @pytest.fixture(scope="class") + def test_client(self) -> FlaskClient: + """ Enables tests to create requests to the web app + """ + os.environ['CONFIG_TYPE'] = 'config.TestingConfig' + + with app.test_client() as testing_client: + with app.app_context(): + yield testing_client diff --git a/tests/endtoend/use_cases_test.py b/tests/endtoend/use_cases_test.py index 17babdc..d62a04f 100644 --- a/tests/endtoend/use_cases_test.py +++ b/tests/endtoend/use_cases_test.py @@ -1,9 +1,9 @@ -import pytest from bs4 import BeautifulSoup -from tests import test_client from flask.testing import FlaskClient +from tests.base_test import TestBase -def test_use_case(test_client: FlaskClient): - response = test_client.get('/products/Car Parts') - assert response.status_code == 200 +class TestFunctionalRequirements(TestBase): + def test_use_case(self, test_client: FlaskClient): + response = test_client.get('/products/Car Parts') + assert response.status_code == 200 diff --git a/tests/functional/test_homepage.py b/tests/functional/test_homepage.py deleted file mode 100644 index b2803cb..0000000 --- a/tests/functional/test_homepage.py +++ /dev/null @@ -1,39 +0,0 @@ -from flask.testing import FlaskClient -from tests import test_client -import pytest - - -def test_homepage(test_client: FlaskClient): - """ Tests that the main homepage loads correctly - once the '/' endpoint is hit - """ - response = test_client.get('/') - assert response.status_code == 302 - - response = test_client.get('/products') - assert response.status_code == 308 - - -def test_products(test_client: FlaskClient): - """ Tests that a product page is displayed when - hitting one of the product endpoints - """ - response = test_client.get('/products/2') - assert response.status_code == 200 - - response = test_client.get('/products/50') - assert response.status_code == 302 - - response = test_client.get('/products/Books') - assert response.status_code == 200 - - -def test_admin(test_client: FlaskClient): - """ Tests that the admin pages can be reached and redirect - upon reaching - """ - response = test_client.get('/admin/users/') - assert response.status_code == 302 - - response = test_client.get('/admin/products/') - assert response.status_code == 302 diff --git a/tests/functional/test_pages.py b/tests/functional/test_pages.py new file mode 100644 index 0000000..dbf51ef --- /dev/null +++ b/tests/functional/test_pages.py @@ -0,0 +1,41 @@ +from flask.testing import FlaskClient +from tests.base_test import TestBase + + +class TestPages(TestBase): + """ Test class that encapsulates tests for + the main pages on the site + """ + + def test_homepage(self, test_client: FlaskClient): + """ Tests that the main homepage loads correctly + once the '/' endpoint is hit + """ + response = test_client.get('/') + assert response.status_code == 302 + + response = test_client.get('/products') + assert response.status_code == 308 + + def test_products(self, test_client: FlaskClient): + """ Tests that a product page is displayed when + hitting one of the product endpoints + """ + response = test_client.get('/products/2') + assert response.status_code == 200 + + response = test_client.get('/products/50') + assert response.status_code == 302 + + response = test_client.get('/products/Books') + assert response.status_code == 200 + + def test_admin(self, test_client: FlaskClient): + """ Tests that the admin pages can be reached and redirect + upon reaching + """ + response = test_client.get('/admin/users/') + assert response.status_code == 302 + + response = test_client.get('/admin/products/') + assert response.status_code == 302 diff --git a/tests/unit/database/database_test_class.py b/tests/unit/database/database_test_class.py new file mode 100644 index 0000000..48007f0 --- /dev/null +++ b/tests/unit/database/database_test_class.py @@ -0,0 +1,8 @@ +from tests.base_test import TestBase + + +class TestDatabase(TestBase): + """ Class that controls the + testing of the WMGZON database + """ + pass diff --git a/tests/unit/database/test_products.py b/tests/unit/database/test_products.py index 0b61633..1ef4cbe 100644 --- a/tests/unit/database/test_products.py +++ b/tests/unit/database/test_products.py @@ -1,5 +1,4 @@ -import pytest -import sqlite3 +from tests.unit.database.database_test_class import TestDatabase from datetime import datetime from controllers.database.product import ProductController from models.products.product import Product @@ -15,53 +14,52 @@ product = Product( 1 ) -# Tests a new product can be created +class TestProduct(TestDatabase): + """ Class that controls the + testing of the WMGZON database + """ -def test_create_product(): - db = ProductController() - db.create(product) + def test_create_product(self): + """Tests a new product can be created""" + db = ProductController() + db.create(product) -# Tests the database maintains integrity when we try -# and add a product with the same details + def test_duplicate_product(self): + """ Tests the database maintains integrity when we try + and add a product with the same detail + """ + self.test_create_product() + def test_search_category(self): + """ Tests that products can be refined by category """ + db = ProductController() -def test_duplicate_product(): - test_create_product() + # Check each category for correct amount of test products + assert len(db.read_all("Car Parts")) == 9 + \ + 2 # Added in previous tests + assert len(db.read_all("Books")) == 9 + assert db.read_all("Phones") is None -# Tests that products can be refined by category + def test_search_term(self): + """ Tests that products can be refined by search term""" + db = ProductController() + # Check each search term for correct amount of test products + assert len(db.read_all(search_term="Alloy")) == 9 + assert len(db.read_all("Car Parts", "tur")) == 2 + assert len(db.read_all(search_term="fold")) == 8 + assert db.read_all(search_term="Twin") is None -def test_search_category(): - db = ProductController() + def test_read_product(self): + """ Test we the same product details get returned from the database """ + db = ProductController() - # Check each category for correct amount of test products - assert len(db.read_all("Car Parts")) == 9 + 2 # Added in previous tests - assert len(db.read_all("Books")) == 9 - assert db.read_all("Phones") is None + # Test the same product is returned + new_product = db.read("product") + assert isinstance(new_product, list) + assert isinstance(new_product[0], Product) - -# Tests that products can be refined by search term -def test_search_term(): - db = ProductController() - - # Check each search term for correct amount of test products - assert len(db.read_all(search_term="Alloy")) == 9 - assert len(db.read_all("Car Parts", "tur")) == 2 - assert len(db.read_all(search_term="fold")) == 8 - assert db.read_all(search_term="Twin") is None - -# Test we the same product details get returned from the database - - -def test_read_product(): - db = ProductController() - - # Test the same product is returned - new_product = db.read("product") - assert isinstance(new_product, list) - assert isinstance(new_product[0], Product) - - # Update the ID on the item as database assigns new id - product.id = new_product[0].id - assert new_product[0].__dict__ == product.__dict__ + # Update the ID on the item as database assigns new id + product.id = new_product[0].id + assert new_product[0].__dict__ == product.__dict__ diff --git a/tests/unit/database/test_users.py b/tests/unit/database/test_users.py index 1f50c8a..3804ce1 100644 --- a/tests/unit/database/test_users.py +++ b/tests/unit/database/test_users.py @@ -1,5 +1,6 @@ import pytest import sqlite3 +from tests.unit.database.database_test_class import TestDatabase from controllers.database.user import UserController from models.users.customer import Customer from models.users.seller import Seller @@ -22,53 +23,53 @@ seller = Seller( "987654321" ) -# Tests a new user can be created +class TestUsers(TestDatabase): + """ Class to encapsulate all of the user + datbase tests + """ -def test_create_user(): - db = UserController() - db.create(customer) - -# Tests the database maintains integrity when we try -# and add a user with the same details - - -def test_duplicate_user(): - db = UserController() - with pytest.raises(sqlite3.IntegrityError): + def test_create_user(self): + """ Tests a new user can be created """ + db = UserController() db.create(customer) -# Test we the same user details get returned from the database + def test_duplicate_user(self): + """ Tests the database maintains integrity when we try + and add a user with the same details + """ + db = UserController() + with pytest.raises(sqlite3.IntegrityError): + db.create(customer) + def test_read_user(self): + """ Test we the same user details get returned from the database """ + db = UserController() -def test_read_user(): - db = UserController() + # Test the same user is returned + user = db.read(customer.username) + assert isinstance(user, Customer) - # Test the same user is returned - user = db.read(customer.username) - assert isinstance(user, Customer) + # Update the ID on the item as database assigns new id + customer.id = user.id + assert user.__dict__ == customer.__dict__ - # Update the ID on the item as database assigns new id - customer.id = user.id - assert user.__dict__ == customer.__dict__ + def test_create_seller(self): + """ Tests a new seller can be created """ + db = UserController() + db.create(seller) + def test_read_seller(self): + """ Test that the same seller details get + returned from the database + """ + db = UserController() -# Tests a new seller can be created -def test_create_seller(): - db = UserController() - db.create(seller) + # Test the same user is returned + user = db.read(seller.username) + assert isinstance(user, Seller) -# Test that the same seller details get returned from the database - - -def test_read_seller(): - db = UserController() - - # Test the same user is returned - user = db.read(seller.username) - assert isinstance(user, Seller) - - # Update the ID on the item as database assigns new id - seller.id = user.id - user.store = "" - assert user.__dict__ == seller.__dict__ + # Update the ID on the item as database assigns new id + seller.id = user.id + user.store = "" + assert user.__dict__ == seller.__dict__ diff --git a/tests/unit/general/test_env.py b/tests/unit/general/test_env.py index 3ca13d5..c18f0d1 100644 --- a/tests/unit/general/test_env.py +++ b/tests/unit/general/test_env.py @@ -1,31 +1,31 @@ +from tests.base_test import TestBase from os import environ from warnings import warn -from tests import old_env - -# Tests environment variables used within the projects domain are -# set in the correct environment - -VARS = ['ENVIRON', 'APPSECRET', 'FILESTORE'] - -ENV_STATES = ['test', 'prod'] -def test_env_vars(): - """ Test that required environment variables are set - ahead of runtime +class TestEnv(TestBase): + """ Tests environment variables used within the projects domain are + set in the correct environment """ - for var in VARS: - env = environ.get(var) + VARS = ['ENVIRON', 'APPSECRET', 'FILESTORE'] - # Check to see what variable we are comparing - if env is None: - warn(f"Variable {var} is not set!") + ENV_STATES = ['test', 'prod'] + def test_env_vars(self): + """ Test that required environment variables are set + ahead of runtime + """ + for var in self.VARS: + env = environ.get(var) -def test_environment_var_state(): - """ Tests that the 'ENVIRON' Environment variable - is in a correct state - """ - var = old_env - assert var is not None - assert (var in ENV_STATES) + # Check to see what variable we are comparing + if env is None: + warn(f"Variable {var} is not set!") + + def test_environment_var_state(self): + """ Tests that the 'ENVIRON' Environment variable + is in a correct state + """ + var = self.old_env + assert var is not None + assert (var in self.ENV_STATES) diff --git a/tests/unit/general/test_pep8.py b/tests/unit/general/test_pep8.py index 38cc521..804854b 100644 --- a/tests/unit/general/test_pep8.py +++ b/tests/unit/general/test_pep8.py @@ -1,11 +1,13 @@ import pycodestyle +from tests.base_test import TestBase # Tests files to ensure they conform to pep8 standards -def test_pep8_conformance(): - """Test that we conform to PEP8.""" - pep8style = pycodestyle.StyleGuide() - dirs = ["./controllers", "./models", "./scripts", "./tests", "./utils"] - result = pep8style.check_files(dirs) - assert result.total_errors == 0 +class TestPep8(TestBase): + def test_pep8_conformance(self): + """Test that we conform to PEP8.""" + pep8style = pycodestyle.StyleGuide() + dirs = ["./controllers", "./models", "./scripts", "./tests", "./utils"] + result = pep8style.check_files(dirs) + assert result.total_errors == 0 diff --git a/venv.bat b/venv.bat deleted file mode 100644 index 1e5301b..0000000 --- a/venv.bat +++ /dev/null @@ -1 +0,0 @@ -./.venv/Scripts/activate From 0434d85ddbcdfe247c0584f2f6ab1557b918388f Mon Sep 17 00:00:00 2001 From: Luke Else Date: Fri, 23 Feb 2024 22:07:57 +0000 Subject: [PATCH 5/9] #11 Created product filter test :) --- tests/endtoend/use_cases_test.py | 62 ++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/tests/endtoend/use_cases_test.py b/tests/endtoend/use_cases_test.py index d62a04f..614e6a4 100644 --- a/tests/endtoend/use_cases_test.py +++ b/tests/endtoend/use_cases_test.py @@ -4,6 +4,64 @@ from tests.base_test import TestBase class TestFunctionalRequirements(TestBase): - def test_use_case(self, test_client: FlaskClient): - response = test_client.get('/products/Car Parts') + def test_product_filters(self, test_client: FlaskClient): + base_url = '/products/Car Part?filter={{FILTER}}' + + # Make get request for all products in car parts + response = test_client.get( + base_url.replace("{{FILTER}}", "Price: High -> Low") + ) assert response.status_code == 200 + + # Extract first and last product + first, last = self.get_first_and_last_product(response.data) + + # Get Prices of each + first_cost = float(self.get_tag_value( + str(first), "product-price").replace('£', '') + ) + last_cost = float(self.get_tag_value( + str(last), "product-price").replace('£', '') + ) + + # Check filter is working + assert first_cost >= last_cost + + # ============================================= + # Test the reverse of the previous filter + # Get html data + response = test_client.get( + base_url.replace("{{FILTER}}", "Price: Low -> High") + ) + assert response.status_code == 200 + + # Extract first and last product + first, last = self.get_first_and_last_product(response.data) + + # Get Prices of each + first_cost = float(self.get_tag_value( + str(first), "product-price").replace('£', '') + ) + last_cost = float(self.get_tag_value( + str(last), "product-price").replace('£', '') + ) + + # Check filter is working + assert first_cost <= last_cost + + def get_tag_value(self, html: str, class_name: str) -> str: + """ Returns the value of a given tag in a html element """ + soup = BeautifulSoup(html, features='html.parser') + return str(soup.find("div", {'class': class_name}).contents[0]) + + def get_first_and_last_product(self, html: str) -> (str, str): + """ Returns the first and last product on the page """ + soup = BeautifulSoup(html, features='html.parser') + + products = soup.findAll("a", {"class": "product"}) + + assert len(products) > 0 + first = products[0] + last = products[-1] + + return (first, last) From c5b60f22dad3da89acc1d25ae2b52b7fa738d9da Mon Sep 17 00:00:00 2001 From: Luke Else Date: Sat, 24 Feb 2024 08:47:57 +0000 Subject: [PATCH 6/9] #11 Added defaults to every fetch of 'ENVIRON' to ensure a value is available --- controllers/database/database.py | 2 +- scripts/create_database.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controllers/database/database.py b/controllers/database/database.py index f133281..c71001e 100644 --- a/controllers/database/database.py +++ b/controllers/database/database.py @@ -12,7 +12,7 @@ class DatabaseController(ABC): __db_name = "wmgzon.db" # Use test file if necessary - if os.environ.get("ENVIRON") == "test": + if os.environ.get("ENVIRON", "test") == "test": __db_name = "test_" + __db_name __sqlitefile = __data_dir + __db_name diff --git a/scripts/create_database.py b/scripts/create_database.py index 31cfd0c..c5e8f30 100644 --- a/scripts/create_database.py +++ b/scripts/create_database.py @@ -26,7 +26,7 @@ def create_connection(path: str, filename: str): print("Table creation complete") # Populate with test data if we are in Test Mode - if os.environ.get("ENVIRON") == "test": + if os.environ.get("ENVIRON", "test") == "test": sql = open("scripts/test_data.sql", "r") conn.executescript(sql.read()) @@ -43,7 +43,7 @@ def run(): db_name = r"wmgzon.db" # Check for test environ - if os.environ.get("ENVIRON") == "test": + if os.environ.get("ENVIRON", "test") == "test": # Remove the original test database print("TEST ENVIRONMENT ACTIVE") db_name = "test_" + db_name From 36bbd58e619d3ba78f2e38e792df13fdc60b621c Mon Sep 17 00:00:00 2001 From: Luke Else Date: Sat, 24 Feb 2024 14:09:25 +0000 Subject: [PATCH 7/9] #11 Changed test data to include differing prices --- controllers/web/stats.py | 5 ++--- scripts/test_data.sql | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/controllers/web/stats.py b/controllers/web/stats.py index 2d49f82..a1dba03 100644 --- a/controllers/web/stats.py +++ b/controllers/web/stats.py @@ -2,7 +2,6 @@ in the web app """ from flask import Blueprint - from flask import render_template, request, flash, session, redirect, url_for from controllers.database.stats import StatsController from controllers.database.product import ProductController @@ -48,8 +47,8 @@ def view_product_stats(id: int): # Recent Views product_view_frequency_data = dict(map( - lambda k, v: (k, random.randint(70, 100)), - # lambda k, v: (k, len(v)), + # lambda k, v: (k, random.randint(70, 100)), + lambda k, v: (k, len(v)), data.keys(), data.values() )) diff --git a/scripts/test_data.sql b/scripts/test_data.sql index 59328c3..ae30774 100644 --- a/scripts/test_data.sql +++ b/scripts/test_data.sql @@ -8,34 +8,34 @@ INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quan INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 2, 4, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 2, 3, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 3, 9, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 4, 3, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 4, 2, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 4, 1, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 129.99, 1, 4, 3, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 129.99, 1, 4, 2, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 129.99, 1, 4, 1, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 6, 7, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, quantityAvailable, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 6, 1232, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 1, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 1, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 1, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 2, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 2, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 3, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 4, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 17.37, 1, 1, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 17.37, 1, 2, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 17.37, 1, 2, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 17.37, 1, 3, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 17.37, 1, 4, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 4, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 4, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 6.99, 1, 4, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 6, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 6, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 1, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 1, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 1, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 2, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 2, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 6.99, 1, 1, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 6.99, 1, 2, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 69.99, 1, 2, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 3, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("12' Brake Disks", "brake-disks.bmp", "this is a product", 20.99, 1, 4, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 4, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 20.99, 1, 4, datetime()); -INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 20.99, 1, 6, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 6.99, 1, 4, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Single Turbo", "turbo.bmp", "this is a product", 69.99, 1, 4, datetime()); +INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("Exhaust Manifold", "manifold.bmp", "This is a super cool product that can be installed into your car to take the gasses from the inside all the way to the outside. Mad I know.", 6.99, 1, 6, datetime()); INSERT INTO Products (name, image, description, cost, sellerID, categoryID, postedDate) VALUES ("17' Alloy Wheels", "alloy.bmp", "These super stylish alloys offer a fresh trendy look for your car. Whether a brand new Mercedes or a niffty little banger, it will uplift the vehicle 10-fold", 20.99, 1, 6, datetime()); INSERT INTO Views (userID, productID, viewDate) VALUES (1, 1, datetime()); From 7dbdcdcd4fb29e64a0638374166e9fbb614d7f62 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Sun, 25 Feb 2024 14:49:32 +0000 Subject: [PATCH 8/9] Made test teardown reset environment variables --- tests/base_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/base_test.py b/tests/base_test.py index f503345..d98f05b 100644 --- a/tests/base_test.py +++ b/tests/base_test.py @@ -26,7 +26,7 @@ class TestBase: def teardown_class(self): """ Teardown class level resources or configurations """ - pass + os.environ["ENVIRON"] = self.old_env @pytest.fixture(scope="class") def test_client(self) -> FlaskClient: From db83438bae00e3ee8f07c87c51f2bc2131561817 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Mon, 26 Feb 2024 08:04:11 +0000 Subject: [PATCH 9/9] Added lazy loading to product images --- templates/content.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/content.html b/templates/content.html index cebc1bd..d8f05fe 100644 --- a/templates/content.html +++ b/templates/content.html @@ -7,7 +7,7 @@
{{product.name}}
- Brake Disks + Brake Disks
£{{product.cost}}