Skip to content

Commit

Permalink
add basic testing framework: pytest
Browse files Browse the repository at this point in the history
  • Loading branch information
nerdoc committed Apr 7, 2024
1 parent d7dff91 commit 0d2ae3e
Show file tree
Hide file tree
Showing 20 changed files with 498 additions and 6 deletions.
4 changes: 4 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ title: Changelog
- give users more hints when no components are found
- MkDocs based documentation
- format codebase with Black

### Added
- basic testing using pytest

### Fixed
- correctly find components

Expand Down
20 changes: 20 additions & 0 deletions docs/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Testing
---

# Testing

Testing Tetra is done using pytest. Make sure you have npm (or yarn etc.) installed, Tetra needs esbuild for building
the frontend components before testing.

```bash
python -m pip install .[dev]
cd tests
npm install
```

Within the `tests` directory, just call `pytest` to test Tetra components.

```bash
pytest
```
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ dev = [
"build",
"twine",
"pytest",
"pytest-django",
"pre-commit",
"black",
"python-dateutil>=2.8.2",
"beautifulsoup4",
"tetra[demo]", # include all the demo packages too
]
demo = [
Expand All @@ -58,3 +60,6 @@ version = {attr = "tetra.__version__"}

[tool.setuptools.packages.find]
exclude = ["docs", "tests", "demosite"]

#[tool.pytest.ini_options]
#DJANGO_SETTINGS_MODULE="tests.settings"
Empty file added tests/__init__.py
Empty file.
66 changes: 66 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import pytest
from pathlib import Path

from bs4 import BeautifulSoup
from django.conf import settings
from django.core.management import call_command

BASE_DIR = Path(__file__).resolve().parent


@pytest.fixture(scope="session", autouse=True)
def setup_django_environment():
# Call your `tetrabuild` command before running tests - to make sure the Js
# scripts and CSS files are built.
call_command("tetrabuild")


def pytest_configure():
settings.configure(
BASE_DIR=BASE_DIR,
SECRET_KEY="django-insecure1234567890",
ROOT_URLCONF="tests.urls",
INSTALLED_APPS=[
"tetra",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.staticfiles",
"tests.main",
],
MIDDLEWARE=[
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"tetra.middleware.TetraMiddleware",
],
DATABASES={
"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}
},
TEMPLATES=[
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
},
],
STATIC_URL="/static/",
STATIC_ROOT=BASE_DIR / "staticfiles",
DEBUG=True,
STORAGES={
"staticfiles": {
"BACKEND": "whitenoise.storage.CompressedStaticFilesStorage",
},
},
)


def extract_component(html: str | bytes):
"""Helper to extract the `div#component` content from the given HTML.
Also cuts out ALL newlines from the output.
"""
return BeautifulSoup(html).html.body.find(id="component").text.replace("\n", "")
Empty file added tests/main/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions tests/main/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class MainConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "tests.main"
48 changes: 48 additions & 0 deletions tests/main/components.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from tetra import BasicComponent, Component, Library
from sourcetypes import django_html, css

default = Library()


@default.register
class SimpleBasicComponent(BasicComponent):
template: django_html = "<div id='component'>foo</div>"


@default.register
class SimpleBasicComponentWithCSS(BasicComponent):
template: django_html = "<div id='component' class='text-red'>bar</div>"
style: css = ".text-red { color: red; }"


@default.register
class SimpleComponentWithDefaultBlock(BasicComponent):
template: django_html = (
"<div id='component'>{% block default %}{% endblock %}</div>"
)


@default.register
class SimpleComponentWithNamedBlock(BasicComponent):
template: django_html = "<div id='component'>{% block foo %}{% endblock %}</div>"


@default.register
class SimpleComponentWithNamedBlockWithContent(BasicComponent):
template: django_html = "<div id='component'>{% block foo %}foo{% endblock %}</div>"


@default.register
class SimpleComponentWithConditionalBlock(BasicComponent):
template: django_html = """
<div id="component">
{% if blocks.foo %}BEFORE{% block foo %}content{% endblock %}AFTER{% endif %}always
</div>
"""


@default.register
class SimpleComponentWith2Blocks(BasicComponent):
template: django_html = """
<div id="component">{% block default %}default{% endblock %}{% block foo %}foo{% endblock %}</div>
"""
16 changes: 16 additions & 0 deletions tests/main/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django.template import Template, Context


def render_component(request, component_string):
"""Helper function to return a full html document with loaded Tetra stuff."""
context = Context()
context.request = request
return Template(
"{% load tetra %}<!doctype html>"
"<html><head>"
"{% tetra_styles %}"
"{% tetra_scripts include_alpine=True %}"
"</head><body>"
f"{component_string}"
"</body></html>"
).render(context)
Empty file.
2 changes: 2 additions & 0 deletions tests/main/static/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# dynamically generated files of Tetra tests
main/tetra/default
11 changes: 11 additions & 0 deletions tests/main/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% load tetra %}
<!doctype html>
<html lang="en">
<head>
{# Even in a test environment, we need the full tetra stuff for components to work properly.#}
{% tetra_styles %}
{% tetra_scripts include_alpine=True %}
<title>Tetra test project</title>
</head>
<body>{% block content %}{% endblock %}</body>
</html>
5 changes: 5 additions & 0 deletions tests/main/templates/basic_component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% extends 'base.html' %}
{% load tetra %}
{% block content %}
{% @ main.default.simple_basic_component / %}
{% endblock %}
11 changes: 11 additions & 0 deletions tests/main/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.http import HttpResponse

from tests.main.helpers import render_component


def simple_basic_component_with_css(request):
return HttpResponse(
render_component(
request, "{% @ main.default.simple_basic_component_with_css / %}"
)
)
66 changes: 66 additions & 0 deletions tests/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "tetra-tests",
"private": true,
"version": "0.0.6",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"esbuild": "^0.14.54"
},
"author": "Christian González <christian.gonzalez@nerdocs.at>",
"license": "MIT"
}
Loading

0 comments on commit 0d2ae3e

Please sign in to comment.