73 lines
2.9 KiB
Python
73 lines
2.9 KiB
Python
|
|
"""Phase 4 exit: a feature with a prototype image has a pinned thread; an implementation shows
|
||
|
|
one feature shipped and one behind. Driven through the views."""
|
||
|
|
|
||
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||
|
|
from django.urls import reverse
|
||
|
|
|
||
|
|
from intent.comments.models import CommentThread, ThreadKind
|
||
|
|
from intent.features.models import Feature
|
||
|
|
|
||
|
|
P = {"org_slug": "catbriar", "project_slug": "intent"}
|
||
|
|
PNG = b"\x89PNG\r\n\x1a\n" + b"\x00" * 64
|
||
|
|
|
||
|
|
|
||
|
|
def test_prototype_pin_and_implementation_status(client, open_project, editor, outsider):
|
||
|
|
client.force_login(editor)
|
||
|
|
for title in ("Checkout", "Receipts"):
|
||
|
|
client.post(reverse("features:create", kwargs=P), {"title": title, "note": ""})
|
||
|
|
checkout, receipts = Feature.objects.order_by("number")
|
||
|
|
|
||
|
|
# A prototype image on the feature.
|
||
|
|
client.post(
|
||
|
|
reverse("files:add", kwargs={**P, "feature_key": checkout.key}),
|
||
|
|
{
|
||
|
|
"kind": "prototype",
|
||
|
|
"upload": SimpleUploadedFile("checkout.png", PNG),
|
||
|
|
"note": "First mockup",
|
||
|
|
},
|
||
|
|
)
|
||
|
|
file = checkout.files.get()
|
||
|
|
|
||
|
|
# Someone pins a comment to a point on it.
|
||
|
|
client.force_login(outsider)
|
||
|
|
client.post(
|
||
|
|
reverse(
|
||
|
|
"files:thread_create", kwargs={**P, "feature_key": checkout.key, "file_id": file.pk}
|
||
|
|
),
|
||
|
|
{"body": "Pay button is hard to find", "across": "80", "down": "90"},
|
||
|
|
)
|
||
|
|
pin = CommentThread.objects.get(kind=ThreadKind.IMAGE)
|
||
|
|
file_page = client.get(
|
||
|
|
reverse("files:detail", kwargs={**P, "feature_key": checkout.key, "file_id": file.pk})
|
||
|
|
).content.decode()
|
||
|
|
assert '<circle cx="80.0%" cy="90.0%"' in file_page
|
||
|
|
assert f'href="#thread-{pin.pk}"' in file_page
|
||
|
|
|
||
|
|
# An implementation ships both features, then one feature changes.
|
||
|
|
client.force_login(editor)
|
||
|
|
client.post(
|
||
|
|
reverse("implementations:create", kwargs=P),
|
||
|
|
{"name": "Storefront", "url": "https://forge.example/shop/storefront"},
|
||
|
|
)
|
||
|
|
impl = open_project.implementations.get()
|
||
|
|
statuses = reverse("implementations:statuses", kwargs={**P, "impl_id": impl.pk})
|
||
|
|
client.post(statuses, {f"status-{checkout.pk}": "shipped", f"status-{receipts.pk}": "shipped"})
|
||
|
|
client.post(
|
||
|
|
reverse("features:edit", kwargs={**P, "feature_key": receipts.key}),
|
||
|
|
{
|
||
|
|
"title": "Receipts",
|
||
|
|
"description": "Email a receipt.",
|
||
|
|
"status": "active",
|
||
|
|
"note": "Email",
|
||
|
|
},
|
||
|
|
)
|
||
|
|
|
||
|
|
page = client.get(
|
||
|
|
reverse("implementations:detail", kwargs={**P, "impl_id": impl.pk})
|
||
|
|
).content.decode()
|
||
|
|
checkout_row = page[page.index(f'id="{checkout.key}"') : page.index(f'id="{receipts.key}"')]
|
||
|
|
receipts_row = page[page.index(f'id="{receipts.key}"') :]
|
||
|
|
assert "behind" not in checkout_row
|
||
|
|
assert "<strong>behind</strong> (now 2)" in receipts_row
|
||
|
|
assert "Shipped: 2" in page and "Behind the current revision: 1" in page
|