Files
python-tdd/src/functional_tests/test_sharing.py

77 lines
2.4 KiB
Python
Raw Normal View History

import os
from django.conf import settings
from django.test import tag
from selenium import webdriver
from selenium.webdriver.common.by import By
from .base import FunctionalTest
from .post_page import PostPage
from .my_posts_page import MyPostsPage
# Helper fns
def quit_if_possible(browser):
try:
browser.quit()
except:
pass
# Test mdls
class SharingTest(FunctionalTest):
@tag("two-browser")
def test_can_share_a_post_with_another_user(self):
self.create_pre_authenticated_session("disco@test.io")
disco_browser = self.browser
self.addCleanup(lambda: quit_if_possible(disco_browser))
options = webdriver.FirefoxOptions()
if os.environ.get("HEADLESS"):
options.add_argument("--headless")
ali_browser = webdriver.Firefox(options=options)
self.addCleanup(lambda: quit_if_possible(ali_browser))
self.browser = ali_browser
self.create_pre_authenticated_session("alice@test.io")
self.browser = disco_browser
self.browser.get(self.live_server_url + '/billboard/')
post_page = PostPage(self).add_post_line("Send help")
share_box = post_page.get_share_box()
self.assertEqual(
share_box.get_attribute("placeholder"),
"friend@example.com",
)
post_page.share_post_with("alice@test.io")
self.browser = ali_browser
MyPostsPage(self).go_to_my_posts_page("alice@test.io")
self.browser.find_element(By.LINK_TEXT, "Send help").click()
self.wait_for(
lambda: self.assertEqual(post_page.get_post_owner(), "disco@test.io")
)
post_page.add_post_line("At your command, Disco King")
self.browser = disco_browser
self.browser.refresh()
brief sprint C3.b+c+d+e: share-post Line+Brief async, magic-link / invalid-link banners use Brief styling, .alert-* retired — TDD Closes the C3 brief sprint. Three event sources (note unlock, share invite, login messages) now route through the Brief slide-down, & the legacy .alert-success/.alert-warning rendering in base.html is retired. C3.b — share-post async Line + Brief: - billboard.share_post detects Accept: application/json. JSON path appends a Line (text="Shared with X at <isoformat>", isoformat carries microseconds so two rapid shares of the same email don't collide on Line.unique_together(post,text)), spawns a Brief(kind=SHARE_INVITE) for the sharer, and returns {brief: brief.to_banner_dict() | None, line_text, recipient_display}. Sharer-shares-with-themselves stays a silent no-op (response carries brief: null). Legacy form-submit path preserved for non-AJAX (still redirects + flashes the privacy-safe message — kept for older FTs / no-JS fallback). - billboard.Brief.to_banner_dict() (moved from dashboard.views helper to a model method) shapes the JSON the banner JS consumes. - post.html: share form intercepted by JS — fetches POST w. Accept:application/json, then appends `data.line_text` as the next row in #id_post_table, calls Brief.showBanner(data.brief), and (when registered) appends a fresh `<span class="post-recipient">` to the new #id_post_recipients box. No page reload — the alert-success flash is gone. - 10 new ITs (SharePostAsyncTest + SharePostLegacyRedirectTest) cover the JSON path, line append, brief creation w. SHARE_INVITE kind, registered/unregistered recipient behaviour, sharer-self skip, line dedupe via timestamp, and that the legacy form-submit redirect path still works. - functional_tests.test_sharing line numbering updated: the share now records its own Line so the alice-reply lands at row 3 instead of 2. C3.c+d — magic-link confirmation + invalid-link error use Brief banner styling: - base.html's {% if messages %} block stops rendering .alert-success/.alert-warning divs. Instead each message renders as a transient Brief-styled banner: <div class="note-banner note-banner--message note-banner--{{level_tag}}"> with .note-banner__body / __description carrying the message text and a .btn-cancel NVM that removes the banner via inline onclick. No DB Brief row; no FYI; no square. Same Gaussian-glass look as note-unlock + share-invite Briefs. - _note.scss adds the note-banner--message variant (full-opacity description) + note-banner--error/--warning border-color override (priRd 0.6) so the invalid-link banner reads as red/abandon. C3.e — .alert-success/.alert-warning retired in markup; the SCSS class blocks aren't referenced anywhere else in templates so they sit dormant (left in place — base form styling keeps .form-control etc. working; no need to ripple into _base.scss). Banner JS (note.js / Brief module) was untouched in C3.b+c+d — the Brief.showBanner contract from C3.a already handles all three kinds (NOTE_UNLOCK / USER_POST / SHARE_INVITE) by reading kind off the brief; the message-banner path doesn't go through showBanner because there's no Brief row. Tests: 218 dashboard+billboard+api ITs + 322 lyric+dashboard+billboard ITs + 2 sharing FTs + 9 my_notes FTs + 1 Jasmine FT all green. Existing lyric.test_views login message-text assertions unchanged (they pull from messages framework — not the rendered HTML — so the markup swap doesn't affect them). Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 18:15:43 -04:00
# Line numbering: 1) "Send help" 2) "Shared with alice@test.io …"
# (auto-appended by share_post in C3.b) 3) Alice's reply.
post_page.wait_for_row_in_post_table("At your command, Disco King", 3)
class PostAccessTest(FunctionalTest):
def test_stranger_cannot_access_owned_post(self):
self.create_pre_authenticated_session("disco@test.io")
self.browser.get(self.live_server_url + '/billboard/')
PostPage(self).add_post_line("private eye")
post_url = self.browser.current_url
self.browser.delete_cookie(settings.SESSION_COOKIE_NAME)
self.browser.get(post_url)
self.assertNotEqual(self.browser.current_url, post_url)