Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ venv
.envrc
.venv
.vscode
*.sqlite3
126 changes: 126 additions & 0 deletions tests/test_tutorial_project_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import os
import sys
from pathlib import Path

import pytest

# Add the tutorial project to the Python path
tutorial_path = Path(__file__).parent / "tutorial_project"
sys.path.insert(0, str(tutorial_path))


import django
from django.test import Client
from django.utils import timezone

# Set up Django settings for the tutorial project
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial_project.settings")
django.setup()

from polls.models import Choice, Question


@pytest.mark.django_db
class TestTutorialProjectIntegration:
"""Test the Django Debug Toolbar with the official tutorial project."""

def setup_method(self):
"""Set up the test client."""
self.client = Client()

def test_part1_models(self):
"""Test Part 1: Models - Creating questions and choices."""
# Create a question with timezone-aware datetime
question = Question.objects.create(
question_text="What's new?", pub_date=timezone.now()
)
assert str(question) == "What's new?"

# Create choices
choice1 = Choice.objects.create(
question=question, choice_text="Not much", votes=0
)
choice2 = Choice.objects.create(
question=question, choice_text="Just coding", votes=0
)

assert question.choice_set.count() == 2
assert str(choice1) == "Not much"
assert str(choice2) == "Just coding"

def test_part2_admin_access(self):
"""Test Part 2: Admin - Admin interface loads."""
response = self.client.get("/admin/")
assert response.status_code == 302 # Redirects to login

def test_part3_views_with_toolbar(self):
"""Test Part 3: Views - Index and detail views with toolbar."""
# Create test data with timezone-aware datetime
question = Question.objects.create(
question_text="Test question", pub_date=timezone.now()
)
Choice.objects.create(question=question, choice_text="Option A", votes=0)

# Test index view
response = self.client.get("/polls/")
assert response.status_code == 200
content = response.content.decode()
assert "Test question" in content
assert "djdt" in content # Debug toolbar should be present

# Test detail view
response = self.client.get(f"/polls/{question.id}/")
assert response.status_code == 200
content = response.content.decode()
assert "Option A" in content
assert "djdt" in content

def test_part4_forms_and_voting(self):
"""Test Part 4: Forms - Voting functionality with toolbar."""
# Create question with choices
question = Question.objects.create(
question_text="Vote test", pub_date=timezone.now()
)
choice = Choice.objects.create(
question=question, choice_text="Option 1", votes=0
)

# Test voting
response = self.client.post(
f"/polls/{question.id}/vote/", {"choice": choice.id}
)
assert response.status_code == 200
content = response.content.decode()

# Check vote was counted
choice.refresh_from_db()
assert choice.votes == 1
assert "Option 1 -- 1 vote" in content
assert "djdt" in content

# Test results view
response = self.client.get(f"/polls/{question.id}/results/")
assert response.status_code == 200
content = response.content.decode()
assert "Option 1" in content
assert "1 vote" in content
assert "djdt" in content

def test_invalid_vote_handling(self):
"""Test error handling when voting without selecting a choice."""
question = Question.objects.create(
question_text="Invalid vote test", pub_date=timezone.now()
)
Choice.objects.create(question=question, choice_text="Only choice", votes=0)

# Post without selecting a choice
response = self.client.post(
f"/polls/{question.id}/vote/",
{}, # No choice selected
)
assert response.status_code == 200
content = response.content.decode()

# Check for the error message (with HTML escaping)
assert "You didn't select a choice." in content
assert "djdt" in content
Empty file.
11 changes: 11 additions & 0 deletions tests/tutorial_project/debug_templates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import django
from django.conf import settings
from django.template import engines

print("Django version:", django.get_version())
print("\nTEMPLATES setting:")
print(settings.TEMPLATES)

print("\nAvailable template engines:")
for engine in engines.all():
print(f" - {engine.name} ({engine.__class__.__name__})")
23 changes: 23 additions & 0 deletions tests/tutorial_project/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""

import os
import sys


def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial_project.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)


if __name__ == "__main__":
main()
Empty file.
19 changes: 19 additions & 0 deletions tests/tutorial_project/polls/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.contrib import admin

from .models import Choice, Question


class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3


@admin.register(Question)
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"]}),
]
inlines = [ChoiceInline]
list_display = ("question_text", "pub_date", "was_published_recently")
list_filter = ["pub_date"]
25 changes: 25 additions & 0 deletions tests/tutorial_project/polls/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField("date published")

def __str__(self):
return self.question_text

def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now


class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)

def __str__(self):
return self.choice_text
22 changes: 22 additions & 0 deletions tests/tutorial_project/polls/templates/polls/detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ question.question_text }}</title>
</head>
<body>
<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>

<p><a href="{% url 'polls:index' %}">Back to polls</a></p>
</body>
</html>
18 changes: 18 additions & 0 deletions tests/tutorial_project/polls/templates/polls/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>Polls</title>
</head>
<body>
<h1>Polls</h1>
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
</body>
</html>
18 changes: 18 additions & 0 deletions tests/tutorial_project/polls/templates/polls/results.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ question.question_text }} - Results</title>
</head>
<body>
<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

<p><a href="{% url 'polls:detail' question.id %}">Vote again?</a></p>
<p><a href="{% url 'polls:index' %}">Back to polls</a></p>
</body>
</html>
11 changes: 11 additions & 0 deletions tests/tutorial_project/polls/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.urls import path

from . import views

app_name = "polls"
urlpatterns = [
path("", views.IndexView.as_view(), name="index"),
path("<int:pk>/", views.DetailView.as_view(), name="detail"),
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
path("<int:question_id>/vote/", views.vote, name="vote"),
]
47 changes: 47 additions & 0 deletions tests/tutorial_project/polls/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from django.shortcuts import get_object_or_404, render
from django.utils import timezone
from django.views import generic

from .models import Choice, Question


class IndexView(generic.ListView):
template_name = "polls/index.html"
context_object_name = "latest_question_list"

def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now()).order_by(
"-pub_date"
)[:5]


class DetailView(generic.DetailView):
model = Question
template_name = "polls/detail.html"

def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now())


class ResultsView(generic.DetailView):
model = Question
template_name = "polls/results.html"


def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST["choice"])
except (KeyError, Choice.DoesNotExist):
return render(
request,
"polls/detail.html",
{
"question": question,
"error_message": "You didn't select a choice.",
},
)
else:
selected_choice.votes += 1
selected_choice.save()
return render(request, "polls/results.html", {"question": question})
Empty file.
Loading