diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..e69de29bb diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..fbf9358b0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.c text +*.h text + +# Declare files that will always have CRLF line endings on checkout. +*.sln text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..e4a5bece1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.11.0a5-alpine + +WORKDIR /src/app/ + +COPY ./requirements.txt . + +RUN ["pip", "install", "-r", "./requirements.txt"] + +COPY . . + +RUN addgroup -S projects && adduser -S -H projects -G projects +RUN chown -R projects:projects /src/app +USER projects diff --git a/README.md b/README.md index d9cca4f37..798fcf313 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Once that completes, also run this command from the same folder. Windows ``` -\venv\Scripts\activate.bat +venv\Scripts\activate.bat ``` macOS & Linux @@ -46,4 +46,4 @@ Every time you want to check your work locally you can type that command, and it ### Previewing Your Work -You can preview your work by running `flask run` in the root of your fork and then visit`http://localhost:5000` in your browser. \ No newline at end of file +You can preview your work by running `flask run` in the root of your fork and then visit`http://localhost:5000` in your browser. diff --git a/pytest.ini b/pytest.ini index d03e9e5d0..ccfcc2693 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,2 @@ [pytest] -addopts = --json-report \ No newline at end of file +addopts = -rN --tb=short -p no:warnings diff --git a/requirements.txt b/requirements.txt index 7b72215f2..37f6ff698 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -beautifulsoup4==4.6.3 -Flask==1.0.2 -pytest==3.7.1 -pytest-json-report==0.7.0 -python-dotenv==0.9.1 \ No newline at end of file +beautifulsoup4==4.9.0 +Flask==1.1.2 +pytest==5.4.1 +pytest-json-report==1.2.1 +python-dotenv==0.13.0 diff --git a/tasks.md b/tasks.md index c8c700e51..ca0828c68 100644 --- a/tasks.md +++ b/tasks.md @@ -1,12 +1,10 @@ -# Build a Job Board with Python & Flask +# Setup -## Setup - -### Create Virtual Environment +## Create Virtual Environment In a terminal run the following commands from the root folder of the forked project. -``` shell +``` python -m venv venv ``` @@ -14,162 +12,162 @@ Once that completes, also run this command from the same folder. Windows -``` shell +``` \venv\Scripts\activate.bat ``` macOS & Linux -``` shell +``` source venv/bin/activate ``` Now that you are working in the virtualenv, install the project dependencies with the following command. -``` shell +``` pip install -r requirements.txt ``` -### Verify Setup +## Verify Setup In order to verify that everything is setup correctly, run the following command, which should show you the failing tests. This is good! We’ll be fixing this test once we jump into the build step. -``` shell +``` pytest ``` Every time you want to check your work locally you can type that command, and it will report the status of every task in the project. -### Previewing Your Work +## Previewing Your Work You can preview your work by running `flask run` in the root of your fork. Then visit `http://localhost:5000` in your browser. -## Module 01 - Flask Setup +# Module 01 - Flask Setup -### 1.1 - Import Flask +## 1.1 - Import Flask @pytest.mark.app_import_flask In order to create a flask application, import the `Flask` class and the `render_template` function from `flask` at the top of the `jobs/app.py` file. -### 1.2 - Create a Flask Application +## 1.2 - Create a Flask Application @pytest.mark.app_create_flask_app Still in `app.py` create an instance of the `Flask` class called `app`. Pass the special variable `__name__` to the `Flask` class constructor. -### 1.3 - Templates Folder +## 1.3 - Templates Folder @pytest.mark.templates_folder Create a folder called `templates` in the `jobs` directory. -### 1.4 - Create Index Template +## 1.4 - Create Index Template @pytest.mark.index_template In the root of the `templates` folder, create a file called `index.html`. Add a single line to the file: - `
` tag with a class of `card_header_title`.
-- Add an `` tag with an `href` of `{{ url_for('job', job_id=job['id']) }}`.
-- The content should be `{{ job['title'] }}`.
+- Add an `` tag with an `href` of `{{ url_for('job', job_id=job['id']) }}`.
+- The content should be `{{ job['title'] }}`.
-### 4.5 - Show Job Macro Body
+## 4.5 - Show Job Macro Body
-@pytest.mark.show_job_macro_body Next find the ` ` tag.
+@pytest.mark.show_job_macro_body Next find the ` ` tag.
In ` ` tag add the following:
-- `` tag with an `href` of `{{ url_for('employer', employer_id=job['employer_id']) }}`. The content should be `{{ job['employer_name'] }}`.
+- `` tag with an `href` of `{{ url_for('employer', employer_id=job['employer_id']) }}`. The content should be `{{ job['employer_name'] }}`.
- Line break
-- ${{ job['salary'] }}
+- ${{ job['salary'] }}
- Line break
- {{ job['description'] }}
-### 4.6 - Show Jobs Macro Definition
+## 4.6 - Show Jobs Macro Definition
@pytest.mark.show_jobs_macro_definition In `_macros.html` create a template macro using the `macro` tag call it `show_jobs`. `show_jobs` should take one parameter called `jobs`. Don't forgot to end the macro.
-### 4.7 - Show Jobs Macro For Loop
+## 4.7 - Show Jobs Macro For Loop
@pytest.mark.show_jobs_macro_for_loop Still in `_macros.html` and in the body of the `show_jobs` macro add the following HTML:
- Add a ` ` with the content {{ employer['description'] }}
-### 6.3 - Employer Template All Jobs
+## 6.3 - Employer Template All Jobs
@pytest.mark.employer_template_all_jobs Below the `` with the copied HTML structure.
-### 4.11 - Display All Jobs
+## 4.11 - Display All Jobs
@pytest.mark.display_all_jobs In the `index.html` template above the `{% endblock %}` add a call to the `show_jobs` macro passing in the argument `jobs`.
-### 4.12 - Gather All Jobs
+## 4.12 - Gather All Jobs
-@pytest.mark.app_jobs_route_jobs In `app.py` locate the `jobs` function.
+@pytest.mark.app_jobs_route_jobs In `app.py` locate the `jobs` function.
Above the `render_template` function, call the `execute_sql` function:
-- Pass in the SQL statement: `'SELECT job.id, job.title, job.description, job.salary, employer.id as employer_id, employer.name as employer_name FROM job JOIN employer ON employer.id = job.employer_id'`.
-- Assign the results of the call to a variable called `jobs`.
+- Pass in the SQL statement: `'SELECT job.id, job.title, job.description, job.salary, employer.id as employer_id, employer.name as employer_name FROM job JOIN employer ON employer.id = job.employer_id'`.
+- Assign the results of the call to a variable called `jobs`.
- In the `render_template` function, pass a keyword argument of `jobs=jobs`.
-### Preview Module 4
+**Preview**
At this point you can see all jobs on the homepage:
- Open a terminal at the root of the project
-- Run the command `flask run`.
-- Open a browser and navigate to the URL: `http://localhost:5000`.
+- Run the command `flask run`.
+- Open a browser and navigate to the URL: `http://localhost:5000`.
**Note: Appending `/jobs` should display the same page.**
-## Module 05 - Display Individual Jobs
+# Module 05 - Display Individual Jobs
-### 5.1 - Job Template
+## 5.1 - Job Template
-@pytest.mark.app_job_template We need a template to display an individual job. Create a new file called `job.html` in the `template` folder.
+@pytest.mark.app_job_template We need a template to display an individual job. Create a new file called `job.html` in the `template` folder.
-In the file use an `extends` template tag to inherit `layout.html`.
+In the file use an `extends` template tag to inherit `layout.html`.
After the `extends` tag add a template `block` called `content`. In the block call the `show_job` macro passing in `job`. **Note: Use the `{{}}` for the macro call.**
-### 5.2 - Job Route Function
+## 5.2 - Job Route Function
@pytest.mark.app_job_route In `app.py` create a function called `job`. In the body return a call to the `render_template` function passing in the newly created `job.html` template.
-### 5.3 - Job Route Decorator
+## 5.3 - Job Route Decorator
-@pytest.mark.app_job_route_decorator We only need one job from the database, we will use the `execute_sql` function passing in a query with a where clause. In the where clause we will need a `job_id`. We are going to get this from the URL.
+@pytest.mark.app_job_route_decorator We only need one job from the database, we will use the `execute_sql` function passing in a query with a where clause. In the where clause we will need a `job_id`. We are going to get this from the URL.
-Still in `app.py`, add a route decorator with the URL path `/job/
` Jobs header in `employer.html` add a call to the `show_jobs` macro passing in `jobs`.
-### 6.4 - Employer Template Reviews
+## 6.4 - Employer Template Reviews
-@pytest.mark.employer_template_reviews Still in `employer.html` find the review `
`, remove the comment surrounding the empty `{% %}` template tag. To this tag add a `for in` loop to loop through all `reviews`. Add the `endfor` directive to the second empty `{% %}` template tag, don't forget to the remove the comment.
+@pytest.mark.employer_template_reviews Still in `employer.html` find the review `
`, remove the comment surrounding the empty `{% %}` template tag. To this tag add a `for in` loop to loop through all `reviews`. Add the `endfor` directive to the second empty `{% %}` template tag, don't forget to the remove the comment.
-### 6.5 - Employer Template Review Stars
+## 6.5 - Employer Template Review Stars
@pytest.mark.employer_template_review_stars Still `employer.html` in the `
` in the `index.html` template does not contain the contents 'Jobs'."
- assert template_find('index', 'h1', limit=1)[0].text == 'Jobs', "The `
` in the `index.html` template does not contain the contents 'Jobs'."
+ template_dir = os.path.isdir("jobs/templates")
+ assert template_dir, "The `templates` folder has not been created."
+
+ index_exists = template_exists("index")
+ assert (
+ index_exists
+ ), "The `index.html` template does not exist in the `templates` folder."
+
+ h1_exists = template_find("index", "h1", limit=1)
+ assert (
+ h1_exists
+ ), "The `
` in the `index.html` template does not contain the contents 'Jobs'."
+
+ h1_jobs = template_find("index", "h1", limit=1)[0].text == "Jobs"
+ assert (
+ h1_jobs
+ ), "The `
` in the `index.html` template does not contain the contents 'Jobs'."
+
@pytest.mark.test_app_index_route_function_module1
def test_app_index_route_function_module1():
- assert 'app' in dir(app), 'Have you created an instance of the `Flask` class called `app`?'
- assert 'jobs' in dir(app), 'Have you created the `jobs` function?'
- result = [item for item in get_functions(app.jobs) if item.startswith('render_template:index.html')]
- assert len(result) == 1, 'Have you called the `render_template` function.'
+ flask_app = "app" in dir(app)
+ assert flask_app, "Have you created an instance of the `Flask` class called `app`?"
+
+ jobs_function = "jobs" in dir(app)
+ assert jobs_function, "Have you created the `jobs` function?"
+
+ result = [
+ item
+ for item in get_functions(app.jobs)
+ if item.startswith("render_template:index.html")
+ ]
+ result_len = len(result) == 1
+ assert result_len, "Have you called the `render_template` function."
+
+ return_values = get_functions_returns(app.jobs)[0]
+ return_exists = (
+ return_values["value/args/s"] == "index.html"
+ and return_values["value/func/id"] == "render_template"
+ )
+ assert return_exists, "Did you return the `render_template` call?"
+
@pytest.mark.test_app_route_decoractors_module1
def test_app_route_decoractors_module1():
- assert 'app' in dir(app), 'Have you created an instance of the `Flask` class called `app`?'
- assert template_exists('index'), 'The `index.html` template does not exist in the `templates` folder.'
- assert 'jobs' in dir(app), 'Have you created the `jobs` function?'
+ flask_app = "app" in dir(app)
+ assert flask_app, "Have you created an instance of the `Flask` class called `app`?"
+
+ index_exists = template_exists("index")
+ assert (
+ index_exists
+ ), "The `index.html` template does not exist in the `templates` folder."
+
+ jobs_function = "jobs" in dir(app)
+ assert jobs_function, "Have you created the `jobs` function?"
rules = list_routes(app.app)
+ root_route = "jobs:GET,HEAD,OPTIONS:/" in rules
+ assert root_route, "Have you decorated the `jobs` function with the `/` route?"
- assert 'jobs:GET,HEAD,OPTIONS:/' in rules, 'Have you decorated the `jobs` function with the `/` route?'
- assert 'jobs:GET,HEAD,OPTIONS:/jobs' in rules, 'Have you decorated the `jobs` function with the `/jobs` route?'
+ jobs_route = "jobs:GET,HEAD,OPTIONS:/jobs" in rules
+ assert jobs_route, "Have you decorated the `jobs` function with the `/jobs` route?"
diff --git a/tests/test_module2.py b/tests/test_module2.py
index fe9d7f0ba..a1a5eeae3 100644
--- a/tests/test_module2.py
+++ b/tests/test_module2.py
@@ -3,33 +3,68 @@
from jobs import app
from .utils import *
-calls = template_functions('layout', 'url_for')
+calls = template_functions("layout", "url_for")
+
@pytest.mark.test_layout_template_module2
def test_layout_template_module2():
- assert template_exists('layout'), 'The `layout.html` template does not exist in the `templates` folder.'
+ layout_exists = template_exists("layout")
+ assert (
+ layout_exists
+ ), "The `layout.html` template does not exist in the `templates` folder."
+
@pytest.mark.test_add_bulma_css_framework_module2
def test_add_bulma_css_framework_module2():
- assert template_exists('layout'), 'The `layout.html` template does not exist in the `templates` folder.'
- assert 'static:filename:css/bulma.min.css' in calls, 'Looks like `bulma.min.css` is not linked in `layout.html`.'
+ layout_exists = template_exists("layout")
+ assert (
+ layout_exists
+ ), "The `layout.html` template does not exist in the `templates` folder."
+
+ css_exists = "static:filename:css/bulma.min.css" in calls
+ assert css_exists, "Looks like `bulma.min.css` is not linked in `layout.html`."
+
@pytest.mark.test_add_custom_css_module2
def test_add_custom_css_module2():
- assert template_exists('layout'), 'The `layout.html` template does not exist in the `templates` folder.'
- assert 'static:filename:css/app.css' in calls, 'Looks like `app.css` is not linked in `layout.html`.'
+ layout_exists = template_exists("layout")
+ assert (
+ layout_exists
+ ), "The `layout.html` template does not exist in the `templates` folder."
+
+ css_exists = "static:filename:css/app.css" in calls
+ assert css_exists, "Looks like `app.css` is not linked in `layout.html`."
+
@pytest.mark.test_add_fontawesome_module2
def test_add_fontawesome_module2():
- assert template_exists('layout'), 'The `layout.html` template does not exist in the `templates` folder.'
+ layout_exists = template_exists("layout")
+ assert (
+ layout_exists
+ ), "The `layout.html` template does not exist in the `templates` folder."
+
attr = {
- 'href': 'https://use.fontawesome.com/releases/v5.2.0/css/all.css',
- 'rel': 'stylesheet'
+ "href": "https://use.fontawesome.com/releases/v5.2.0/css/all.css",
+ "rel": "stylesheet",
}
- assert template_soup('layout').find('link', attr), 'Looks like FontAwesome is not linked in `layout.html`.'
+ layout_link_exists = template_soup("layout").find("link", attr)
+ assert layout_link_exists, "Looks like FontAwesome is not linked in `layout.html`."
+
@pytest.mark.test_extend_base_template_module2
def test_extend_base_template_module2():
- assert template_exists('index'), 'The `index.html` template does not exist in the `templates` folder.'
- assert template_exists('layout'), 'The `layout.html` template does not exist in the `templates` folder.'
- assert 'layout.html' in template_extends('index'), 'The `index.html` template does not extend `layout.html`.'
+ index_exists = template_exists("index")
+ assert (
+ index_exists
+ ), "The `index.html` template does not exist in the `templates` folder."
+
+ layout_exists = template_exists("layout")
+ assert (
+ layout_exists
+ ), "The `layout.html` template does not exist in the `templates` folder."
+
+ index_extends = "layout.html" in template_extends("index")
+ assert index_extends, "The `index.html` template does not extend `layout.html`."
+
+ content_block = "content" in template_block("index")
+ assert content_block, "Have you added a template `block` called `content`?"
diff --git a/tests/test_module3.py b/tests/test_module3.py
index d64986d31..e0cc62461 100644
--- a/tests/test_module3.py
+++ b/tests/test_module3.py
@@ -4,82 +4,197 @@
from jobs import app
from .utils import *
+
@pytest.mark.test_app_import_sqlite_module3
def test_app_import_sqlite_module3():
- assert 'sqlite3' in dir(app), 'Have you imported `sqlite`?'
+ sqlite_import = "sqlite3" in dir(app)
+ assert sqlite_import, "Have you imported `sqlite`?"
+
@pytest.mark.test_app_import_g_module3
def test_app_import_g_module3():
- assert 'g' in dir(app), 'Have you imported the `g` class from `flask`?'
+ g_import = "g" in dir(app)
+ assert g_import, "Have you imported the `g` class from `flask`?"
+
@pytest.mark.test_app_db_path_module3
def test_app_db_path_module3():
- assert 'PATH' in dir(app), 'Have you created a constant called `PATH`.'
- assert app.PATH == 'db/jobs.sqlite', 'Have you created a constant called `PATH`?'
+ assert "PATH" in dir(app), "Have you created a constant called `PATH`?"
+ assert app.PATH == "db/jobs.sqlite", "Have you created a constant called `PATH`?"
+
@pytest.mark.test_app_open_connection_get_attribute_module3
def test_app_open_connection_get_attribute_module3():
- assert 'open_connection' in dir(app), 'Have you defined a function named `open_connection`.'
- assert 'getattr:g:_connection:None' in get_functions(app.open_connection), 'Have you used the `getattr` function to get the global `_connection`?'
+
+ open_connection = "open_connection" in dir(app)
+ assert open_connection, "Have you defined a function named `open_connection`?"
+
+ result = [
+ item
+ for item in get_functions(app.open_connection)
+ if item.startswith("getattr:g:_connection")
+ ]
+ result_len = len(result) == 1
+ assert (
+ result_len
+ ), "Have you used the `getattr` function to get the global `_connection`?"
+
@pytest.mark.test_app_open_connection_connection_module3
def test_app_open_connection_connection_module3():
- assert 'g' in dir(app), 'Have you imported the `g` class from `flask`?'
- assert 'app' in dir(app), 'Have you created an instance of the `Flask` class called `app`?'
- assert 'open_connection' in dir(app), 'Have you defined a function named `open_connection`.'
+ g_import = "g" in dir(app)
+ assert g_import, "Have you imported the `g` class from `flask`?"
+
+ flask_app = "app" in dir(app)
+ assert flask_app, "Have you created an instance of the `Flask` class called `app`?"
+
+ open_connection = "open_connection" in dir(app)
+ assert open_connection, "Have you defined a function named `open_connection`?"
+
with app.app.app_context():
app.open_connection()
- assert hasattr(app.g, '_connection'), 'Did you assign the `_connection` attribute to `g`?'
- _, _, db_name = app.g._connection.execute('PRAGMA database_list').fetchone()
- assert os.path.join(os.getcwd(), 'db', 'jobs.sqlite') == db_name, 'Did you pass the `connect` function the `PATH` constant?'
+
+ connection_exists = hasattr(app.g, "_connection")
+ assert connection_exists, "Did you assign the `_connection` attribute to `g`?"
+
+ _, _, db_name = app.g._connection.execute("PRAGMA database_list").fetchone()
+ db_exists = os.path.join(os.getcwd(), "db", "jobs.sqlite") == db_name
+ assert db_exists, "Did you pass the `connect` function the `PATH` constant?"
+
@pytest.mark.test_app_open_connection_row_factory_module3
def test_app_open_connection_row_factory_module3():
- assert 'g' in dir(app), 'Have you imported the `g` class from `flask`?'
- assert 'app' in dir(app), 'Have you created an instance of the `Flask` class called `app`?'
- assert 'open_connection' in dir(app), 'Have you defined a function named `open_connection`.'
+ g_import = "g" in dir(app)
+ assert g_import, "Have you imported the `g` class from `flask`?"
+
+ flask_app = "app" in dir(app)
+ assert flask_app, "Have you created an instance of the `Flask` class called `app`?"
+
+ open_connection = "open_connection" in dir(app)
+ assert open_connection, "Have you defined a function named `open_connection`?"
+
with app.app.app_context():
db = app.open_connection()
- assert isinstance(db, app.sqlite3.Connection), 'Are you returning the database connection?'
- assert id(db.row_factory) == id(app.sqlite3.Row), 'Have you set the database `row_factory` to the sqlite3.Row class?'
+ return_connection = isinstance(db, app.sqlite3.Connection)
+ assert return_connection, "Are you returning the database connection?"
+
+ row_factory = id(db.row_factory) == id(app.sqlite3.Row)
+ assert (
+ row_factory
+ ), "Have you set the database `row_factory` to the sqlite3.Row class?"
+
@pytest.mark.test_app_execute_sql_module3
def test_app_execute_sql_module3():
- assert 'app' in dir(app), 'Have you created an instance of the `Flask` class called `app`?'
- assert 'execute_sql' in dir(app), 'Have you defined a function named `execute_sql`.'
- assert 'open_connection' in get_functions(app.execute_sql), 'Have you called the `open_connection` function in `execute_sql`?'
+ flask_app = "app" in dir(app)
+ assert flask_app, "Have you created an instance of the `Flask` class called `app`?"
+
+ execute_sql_function = "execute_sql" in dir(app)
+ assert execute_sql_function, "Have you defined a function named `execute_sql`?"
+
+ open_call = "open_connection" in get_functions(app.execute_sql)
+ assert open_call, "Have you called the `open_connection` function in `execute_sql`?"
+
@pytest.mark.test_app_execute_sql_parameters_module3
def test_app_execute_sql_parameters_module3():
- assert 'execute_sql' in dir(app), 'Have you defined a function named `execute_sql`.'
+ execute_sql_function = "execute_sql" in dir(app)
+ assert execute_sql_function, "Have you defined a function named `execute_sql`?"
+
parameters = inspect.getfullargspec(app.execute_sql)
- assert parameters.args[0] == 'sql' and parameters.args[1] == 'values' and parameters.args[2] == 'commit' and parameters.args[3] == 'single', 'Have you added the correct parameters to the `execute_sql` function parameters list?'
- assert parameters.defaults[0] == () and parameters.defaults[1] == False and parameters.defaults[2] == False, 'Do the `args` and `one` parameters have the correct defaults in the `execute_sql` function parameters list?'
+ arg_len = len(parameters.args) == 4
+ assert arg_len, "Have you added parameters to the `execute_sql` function?"
+
+ args = (
+ parameters.args[0] == "sql"
+ and parameters.args[1] == "values"
+ and parameters.args[2] == "commit"
+ and parameters.args[3] == "single"
+ )
+ assert (
+ args
+ ), "Have you added the correct parameters to the `execute_sql` function parameters list?"
+
+ defaults = (
+ parameters.defaults[0] == ()
+ and parameters.defaults[1] == False
+ and parameters.defaults[2] == False
+ )
+ assert (
+ defaults
+ ), "Do the `args` and `one` parameters have the correct defaults in the `execute_sql` function parameters list?"
+
@pytest.mark.test_app_execute_sql_execute_module3
def test_app_execute_sql_execute_module3():
- assert 'execute_sql' in dir(app), 'Have you defined a function named `execute_sql`.'
- assert 'execute:sql:values' in get_functions(app.execute_sql), 'Have you called the `execute` function in `execute_sql`?'
+ execute_sql_function = "execute_sql" in dir(app)
+ assert execute_sql_function, "Have you defined a function named `execute_sql`?"
+
+ execute_call = "execute:sql:values" in get_functions(app.execute_sql)
+ assert execute_call, "Have you called the `execute` function in `execute_sql`?"
+
@pytest.mark.test_app_execute_sql_results_module3
def test_app_execute_sql_results_module3():
- assert 'execute_sql' in dir(app), 'Have you defined a function named `execute_sql`.'
- assert 'fetchall' in get_functions(app.execute_sql), 'Have you called the `fetchall` function in `execute_sql`?'
- assert 'fetchone' in get_functions(app.execute_sql), 'Have you called the `fetchone` function in `execute_sql`?'
- assert 'commit' in get_functions(app.execute_sql), 'Have you called the `close` function in `execute_sql`?'
- assert 'close' in get_functions(app.execute_sql), 'Have you called the `close` function in `execute_sql`?'
+ execute_sql_function = "execute_sql" in dir(app)
+ assert execute_sql_function, "Have you defined a function named `execute_sql`?"
+
+ fetchall = "fetchall" in get_functions(app.execute_sql)
+ assert fetchall, "Have you called the `fetchall` function in `execute_sql`?"
+
+ fetchone = "fetchone" in get_functions(app.execute_sql)
+ assert fetchone, "Have you called the `fetchone` function in `execute_sql`?"
+
+ commit = "commit" in get_functions(app.execute_sql)
+ assert commit, "Have you called the `commit` function in `execute_sql`?"
+
+ close = "close" in get_functions(app.execute_sql)
+ assert close, "Have you called the `close` function in `execute_sql`?"
+
+ if_statement = len(get_statements(app.execute_sql)) >= 0
+ assert if_statement, "Have created an if statement in the `execute_sql` function?"
+
+ results_exists = "results" == get_statements(app.execute_sql)[0]["body/targets/id"]
+ assert (
+ results_exists
+ ), "Have you assigned the `results` variable to `connection.commit()`?"
+
with app.app.app_context():
- results = app.execute_sql('SELECT * FROM job', single=True)
- assert type(results) != list, 'Have you create an if statement to only return one result in `one` is true?'
+ results = type(app.execute_sql("SELECT * FROM job", single=True)) != list
+ assert (
+ results
+ ), "Have you create an if statement to only return one result in `one` is true?"
+
@pytest.mark.test_app_close_connection_module3
def test_app_close_connection_module3():
- assert 'close_connection' in dir(app), 'Have you defined a function named `close_connection`.'
- assert 'getattr:g:_connection:None' in get_functions(app.open_connection), 'Have you used the `getattr` function to get the global `_connection`?'
- assert 'close' in get_functions(app.execute_sql), 'Have you called the `close` function in `execute_sql`?'
+ close_connection = "close_connection" in dir(app)
+ assert close_connection, "Have you defined a function named `close_connection`?"
+
+ result = [
+ item
+ for item in get_functions(app.open_connection)
+ if item.startswith("getattr:g:_connection")
+ ]
+ result_len = len(result) == 1
+ assert (
+ result_len
+ ), "Have you used the `getattr` function to get the global `_connection`?"
+
+ close = "close" in get_functions(app.close_connection)
+ assert close, "Have you called the `close` function in `close_connection`?"
+
@pytest.mark.test_app_close_connection_decorator_module3
def test_app_close_connection_decorator_module3():
- assert 'close_connection' in dir(app), 'Have you defined a function named `close_connection`.'
- decorator = get_decorators(app.close_connection)['close_connection'][0][0]
- assert decorator == 'teardown_appcontext', 'Does `close_connection` have a `teardown_appcontext` decorator?'
\ No newline at end of file
+ close_connection = "close_connection" in dir(app)
+ assert close_connection, "Have you defined a function named `close_connection`?"
+
+ decorators = get_decorators(app.close_connection)["close_connection"]
+
+ decorators_len = len(decorators) == 1
+ assert decorators_len, "Have you added the correct decorator to `close_connection`?"
+
+ decorator = decorators[0][0]
+ teardown = decorator == "teardown_appcontext"
+ assert teardown, "Does `close_connection` have a `teardown_appcontext` decorator?"
diff --git a/tests/test_module4.py b/tests/test_module4.py
index 503d7d5b4..7887d41ca 100644
--- a/tests/test_module4.py
+++ b/tests/test_module4.py
@@ -4,77 +4,175 @@
from jobs import app
from .utils import *
+
@pytest.mark.test_template_macros_module4
def test_template_macros_module4():
- assert template_exists('_macros'), 'The `_macros.html` template does not exist in the `templates` folder.'
+ macros_exists = template_exists("_macros")
+ assert (
+ macros_exists
+ ), "The `_macros.html` template does not exist in the `templates` folder."
+
@pytest.mark.test_show_job_macro_definition_module4
def test_show_job_macro_definition_module4():
- assert template_exists('_macros'), 'The `_macros.html` template does not exist in the `templates` folder.'
- assert 'show_job:job' in template_macros('_macros'), 'Have you created the `show_job` macro and added the correct parameter?'
+ macros_exists = template_exists("_macros")
+ assert (
+ macros_exists
+ ), "The `_macros.html` template does not exist in the `templates` folder."
+
+ show_job = "show_job:job" in template_macros("_macros")
+ assert (
+ show_job
+ ), "Have you created the `show_job` macro and added the correct parameter?"
+
@pytest.mark.test_show_job_macro_html_module4
def test_show_job_macro_html_module4():
- assert template_exists('_macros'), 'The `_macros.html` template does not exist in the `templates` folder.'
- html = template_macro_soup('_macros', 'show_job')
- p = html.select('.card .card-header .card-header-title')
- div = html.select('.card-content .content')
- assert len(p) == 1 and len(div) == 1, 'Has the `HTML` from `templates.html` been copied to the `show_job` macro?'
+ macros_exists = template_exists("_macros")
+ assert (
+ macros_exists
+ ), "The `_macros.html` template does not exist in the `templates` folder."
+
+ html = template_macro_soup("_macros", "show_job")
+ p = html.select(".card .card-header .card-header-title")
+ div = html.select(".card-content .content")
+
+ copied = len(p) == 1 and len(div) == 1
+ assert (
+ copied
+ ), "Has the `HTML` from `templates.html` been copied to the `show_job` macro?"
+
@pytest.mark.test_show_job_macro_header_module4
def test_show_job_macro_header_module4():
- assert template_exists('_macros'), 'The `_macros.html` template does not exist in the `templates` folder.'
- assert 'job:job_id:job:id' in template_functions('_macros', 'url_for'), 'Looks like the job title link `href` is incorrect.'
- assert 'job:title' in template_variables('_macros'), 'Looks like the job title link does not have content.'
+ macros_exists = template_exists("_macros")
+ assert (
+ macros_exists
+ ), "The `_macros.html` template does not exist in the `templates` folder."
+
+ job_title = "job:title" in template_variables("_macros")
+ assert job_title, "Looks like the job title link does not have content."
+
@pytest.mark.test_show_job_macro_body_module4
def test_show_job_macro_body_module4():
- assert template_exists('_macros'), 'The `_macros.html` template does not exist in the `templates` folder.'
- assert 'employer:employer_id:job:employer_id' in template_functions('_macros', 'url_for'), 'Looks like the job title link `href` is incorrect.'
- assert 'job:employer_name' in template_variables('_macros'), 'Are you showing the employer name?'
- assert 'job:salary' in template_variables('_macros'), 'Are you showing the job salary?'
- assert 'job:description' in template_variables('_macros'), 'Are you showing the job description?'
+ macros_exists = template_exists("_macros")
+ assert (
+ macros_exists
+ ), "The `_macros.html` template does not exist in the `templates` folder."
+
+ employer_name = "job:employer_name" in template_variables("_macros")
+ assert employer_name, "Are you showing the employer name?"
+
+ salary = "job:salary" in template_variables("_macros")
+ assert salary, "Are you showing the job salary?"
+
+ description = "job:description" in template_variables("_macros")
+ assert description, "Are you showing the job description?"
+
@pytest.mark.test_show_jobs_macro_definition_module4
def test_show_jobs_macro_definition_module4():
- assert template_exists('_macros'), 'The `_macros.html` template does not exist in the `templates` folder.'
- assert 'show_jobs:jobs' in template_macros('_macros'), 'Have you created the `show_jobs` macro and added the correct parameter?'
+ macros_exists = template_exists("_macros")
+ assert (
+ macros_exists
+ ), "The `_macros.html` template does not exist in the `templates` folder."
+
+ show_jobs = "show_jobs:jobs" in template_macros("_macros")
+ assert (
+ show_jobs
+ ), "Have you created the `show_jobs` macro and added the correct parameter?"
+
@pytest.mark.test_show_jobs_macro_for_loop_module4
def test_show_jobs_macro_for_loop_module4():
- assert template_exists('_macros'), 'The `_macros.html` template does not exist in the `templates` folder.'
- html = template_macro_soup('_macros', 'show_jobs')
- div = html.select('div.columns.is-multiline')
- assert len(div) == 1, 'Has a `