intent/tests/test_example_flow.py

137 lines
5.1 KiB
Python
Raw Permalink Normal View History

"""The example flow from docs/concept.md, steps 1–7, driven through the views like a browser."""
from django.urls import reverse
from intent.comments.models import CommentThread
from intent.features.models import Feature
from intent.issues.models import Issue, IssueStatus
P = {"org_slug": "catbriar", "project_slug": "intent"}
def issue_url(name, number, **kwargs):
return reverse(f"issues:{name}", kwargs={**P, "number": number, **kwargs})
def feature_url(name, key, **kwargs):
return reverse(f"features:{name}", kwargs={**P, "feature_key": key, **kwargs})
def reply_url(thread):
return reverse("comments:reply", kwargs={**P, "thread_id": thread.pk})
def test_example_flow(client, open_project, outsider, editor):
# 1. A general user creates a new issue in a project.
client.force_login(outsider)
client.post(
reverse("issues:create", kwargs=P),
{"title": "Remember me on shared computers", "body": "Sessions last too long."},
)
issue = Issue.objects.get()
# 2. Users, including team members, discuss in comments on the issue.
issue_thread = issue.threads.get()
client.post(reply_url(issue_thread), {"body": "Public library computers especially."})
client.force_login(editor)
client.post(reply_url(issue_thread), {"body": "Agreed, let's define this."})
# 3. A team member accepts the issue and creates a feature from it, linked to the issue.
create = reverse("features:create", kwargs=P) + f"?issue={issue.number}"
client.post(
create,
{
"title": "Session length",
"description": "Sessions end after 12 hours.\n\nShared computers end at close.\n",
"note": "",
"accept_issue": "on",
},
)
issue.refresh_from_db()
feature = Feature.objects.get()
assert issue.status == IssueStatus.ACCEPTED
assert list(issue.features.all()) == [feature]
assert feature.revisions.get().issues.get() == issue
# 4. The team member updates the feature's status manually.
client.post(
feature_url("edit", feature.key),
{
"title": feature.title,
"description": feature.description,
"status": "withdrawn",
"note": "Paused until the login rework.",
},
)
feature.refresh_from_db()
assert (feature.status, feature.current_revision) == ("withdrawn", 2)
client.post(
feature_url("edit", feature.key),
{
"title": feature.title,
"description": feature.description,
"status": "active",
"note": "Back on.",
},
)
# 5. Later, a user starts a comment thread on lines of the feature.
client.force_login(outsider)
client.post(
feature_url("thread_create", feature.key),
{"body": "What counts as close?", "revision": 3, "line_start": 3, "line_end": 3},
)
thread = CommentThread.objects.get(feature=feature)
# 6. After some discussion, the user promotes the thread to an issue.
client.force_login(editor)
client.post(reply_url(thread), {"body": "Browser close, I think."})
client.force_login(outsider)
promote = reverse("comments:promote", kwargs={**P, "thread_id": thread.pk})
client.post(promote, {"title": "Define 'close'", "body": "From the thread."})
follow_up = Issue.objects.get(number=2)
thread.refresh_from_db()
assert thread.promoted_to == follow_up and thread.is_resolved
assert list(follow_up.features.all()) == [feature]
# 7. More discussion, then a team member accepts the issue and updates the feature.
client.post(reply_url(follow_up.threads.get()), {"body": "Tab close too?"})
client.force_login(editor)
client.post(
feature_url("edit", feature.key) + f"?issue={follow_up.number}",
{
"title": feature.title,
"description": (
"Sessions end after 12 hours.\n\nShared computers end when the browser closes.\n"
),
"status": "active",
"note": "Define close as browser close.",
"accept_issue": "on",
},
)
follow_up.refresh_from_db()
feature.refresh_from_db()
assert follow_up.status == IssueStatus.ACCEPTED
assert feature.current_revision == 4
assert feature.revisions.get(revision=4).issues.get() == follow_up
# The line thread is now outdated, and the feature page shows both issues.
page = client.get(feature_url("detail", feature.key)).content.decode()
assert "Comments on earlier revisions" in page
assert "#1 Remember me on shared computers" in page and "#2 Define" in page
# 7, alternative: a third issue is rejected but stays linked, so the proposal is visible.
client.force_login(outsider)
client.post(
reverse("issues:create", kwargs=P),
{"title": "Never expire sessions", "features": [feature.pk]},
)
client.force_login(editor)
client.post(issue_url("status", 3), {"status": "rejected"})
rejected = Issue.objects.get(number=3)
assert rejected.status == IssueStatus.REJECTED
assert (
"#3 Never expire sessions"
in client.get(feature_url("detail", feature.key)).content.decode()
)