diff --git a/.gitignore b/.gitignore index 536668f0..cf6c86b8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,9 +10,12 @@ *.code-workspace !project.code-workspace -# Please, add your custom content below! +# Specific to this blueprint __pycache__/ .pytest_cache/ test-results/ axe-reports/ +local.env + +# Please, add your custom content below! diff --git a/README.md b/README.md index adb260bb..19c42127 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ This project is designed to provide a blueprint to allow for development teams t - [Configuration](#configuration) - [Getting Started](#getting-started) - [Utilities](#utilities) + - [Using Environment Variables For Secrets](#using-environment-variables-for-secrets) - [Contributing](#contributing) - [Contacts](#contacts) - [Licence](#licence) @@ -33,8 +34,6 @@ To utilise the blueprint code, you will need to have the following installed: - [Python](https://www.python.org/downloads/) 3.12 or greater -> NOTE: There are currently known issues with Python 3.13 and Playwright, so if you encounter issues running this project whilst using Python 3.13 it is recommended to downgrade to Python 3.12 in the interim. - Whilst not required to get started, you may also want to [configure a Python virtual environment for your project](https://docs.python.org/3/library/venv.html) before proceeding with the configuration. If you are using an IDE such as Visual Studio Code or PyCharm, you will normally be prompted to do this automatically. @@ -73,14 +72,44 @@ For additional reading and guidance on writing tests, we also recommend reviewin ## Utilities -This blueprint also provides the following utility classes, that can be used to aid in testing: +This blueprint provides the following utility classes, that can be used to aid in testing: + +| Utility | Description | +| ------------------------------------------------------------- | -------------------------------------------- | +| [Axe](./docs/utility-guides/Axe.md) | Accessibility scanning using axe-core. | +| [Date Time Utility](./docs/utility-guides/DateTimeUtility.md) | Basic functionality for managing date/times. | +| [NHSNumberTools](./docs/utility-guides/NHSNumberTools.md) | Basic tools for working with NHS numbers. | +| [User Tools](./docs/utility-guides/UserTools.md) | Basic user management tool. | + +## Using Environment Variables For Secrets + +This blueprint provides functionality for saving secret / sensitive values that you would not want present +in the codebase, but require to execute tests locally (such as passwords or API keys). A local.env file can +be generated by running the [following script](./setup_env_file.py): + +```shell +python ./setup_env_file.py +``` + +This script file is design to be amended / updated as your project evolves, so as more sensitive values are required +for executing tests, the list of keys provided can be updated so for subsequent runs of the script, all the expected +keys are populated within the local.env file (which will need their values setting manually). The intent is that this +script can be run to onboard new team members and provide a local file with all the variables they need to populate. + +The local.env file (if present), is read at the start of any test session (via the [conftest.py file](./conftest.py)) +and any variables can be accessed by using the Python os library like so: + +```python +# Import the OS library +import os + +# Access environment variable +os.getenv('') +``` + +The local.env file is set in the [.gitignore file](./.gitignore), so by default it will not commit if amended. -|Utility|Description| -|-------|-----------| -|[Axe](./docs/utility-guides/Axe.md)|Accessibility scanning using axe-core.| -|[Date Time Utility](./docs/utility-guides/DateTimeUtility.md)|Basic functionality for managing date/times.| -|[NHSNumberTools](./docs/utility-guides/NHSNumberTools.md)|Basic tools for working with NHS numbers.| -|[User Tools](./docs/utility-guides/UserTools.md)|Basic user management tool.| + > NOTE: You should never commit this file or any secrets in the codebase directly. ## Contributing diff --git a/conftest.py b/conftest.py new file mode 100644 index 00000000..99c9ee54 --- /dev/null +++ b/conftest.py @@ -0,0 +1,26 @@ +""" +This is a conftest.py file for pytest, which is used to set up fixtures and hooks for testing. +This file is used to define fixtures that can be used across multiple test files. +It is also used to define hooks that can be used to modify the behavior of pytest. +""" + +import pytest +import os +from dotenv import load_dotenv +from pathlib import Path + +LOCAL_ENV_PATH = Path(os.getcwd()) / 'local.env' + + +@pytest.fixture(autouse=True, scope="session") +def import_local_env_file() -> None: + """ + This fixture is used to import the local.env file into the test environment (if the file is present), + and will populate the environment variables prior to any tests running. + If environment variables are set in a different way when running (e.g. via cli), this will + prioritise those values over the local.env file. + + NOTE: You should not use this logic to read a .env file in a pipeline or workflow to set sensitive values. + """ + if Path.is_file(LOCAL_ENV_PATH): + load_dotenv(LOCAL_ENV_PATH, override=False) diff --git a/requirements.txt b/requirements.txt index 1fd57964..3b2268e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ pytest-playwright>=0.5.1 pytest-html>=4.1.1 pytest-json-report>=1.5.0 pytest-playwright-axe>=4.10.3 +python-dotenv>=1.1.0 diff --git a/setup_env_file.py b/setup_env_file.py new file mode 100644 index 00000000..e36e2fc6 --- /dev/null +++ b/setup_env_file.py @@ -0,0 +1,30 @@ +""" +This script creates a local.env file that can be used to populate secrets such as passwords or API keys +locally. This is useful for local development and testing, as it allows you to keep sensitive information +out of your codebase. + +This is designed to be generated when setting up this project, so if new variables are required, these +should be added to the REQUIRED_KEYS list below to automatically populate the local.env file with the +keys required to run this project. +""" + +import os +from pathlib import Path + +REQUIRED_KEYS = ["USER_PASS"] +DEFAULT_LOCAL_ENV_PATH = Path(os.getcwd()) / 'local.env' + +def create_env_file(): + """ + Create a local.env file with the required keys. + """ + with open(DEFAULT_LOCAL_ENV_PATH, 'w') as f: + f.write("# Use this file to populate secrets without committing them to the codebase (as this file is set in .gitignore).\n") + f.write("# To retrieve values as part of your tests, use os.getenv('VARIABLE_NAME').\n") + f.write("# Note: When running in a pipeline or workflow, you should pass these variables in at runtime.\n\n") + for key in REQUIRED_KEYS: + f.write(f'{key}=\n') + + +if __name__ == "__main__": + create_env_file()