my_buds: strip bud-autocomplete bindings from _bud_add_panel.html — the autocomplete pool is request.user.buds (per search_buds view), so on the page where you ADD new buds the suggestions are the precise set you can't usefully re-add; post-share + gatekeeper-invite panels keep the binding (re-sharing w. an existing bud is a real flow); test_autocomplete_suggests_buds_by_username_prefix → test_no_autocomplete_suggestions_on_my_buds_page (asserts #id_bud_suggestions absent — deterministic, no debounce-window race); dead id_bud_suggestions click-outside guard + unused {% load static %} dropped — TDD

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-12 15:42:41 -04:00
parent 880408285a
commit 7015ddd534
2 changed files with 16 additions and 39 deletions

View File

@@ -5,7 +5,6 @@ will layer autocomplete (sky-place-style top-3 username suggestions) and
implicit auto-add on post-share / gate-invite.
"""
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from apps.lyric.models import User
@@ -57,30 +56,21 @@ class MyBudsPageTest(FunctionalTest):
self.alice, list(self.gamer.buds.all())
))
def test_autocomplete_suggests_buds_by_username_prefix(self):
"""Phase 2: typing in #id_recipient pulls top-3 prefix matches from
request.user.buds and renders them as .bud-suggestion-item buttons.
Click → input.value fills with the bud's username (or email if the
user typed an `@` already)."""
def test_no_autocomplete_suggestions_on_my_buds_page(self):
"""The bud-autocomplete pool is request.user.buds — surfacing buds
you've already added on the page where you ADD new buds is just
noise. Post-share + gatekeeper-invite panels keep it (re-sharing
with an existing bud is a real flow); the My Buds add-panel drops
the autocomplete bindings entirely. Absence of #id_bud_suggestions
is the deterministic check (no debounce-window races)."""
self.gamer.buds.add(self.alice)
bob = User.objects.create(email="bob@test.io", username="bob")
self.gamer.buds.add(bob)
self.browser.get(self.live_server_url + "/billboard/my-buds/")
btn = self.wait_for(lambda: self.browser.find_element(By.ID, "id_bud_btn"))
btn.click()
recipient = self.wait_for(lambda: self.browser.find_element(By.ID, "id_recipient"))
recipient.send_keys("al")
self.wait_for(lambda: self.browser.find_element(By.ID, "id_bud_btn"))
suggestions = self.wait_for(lambda: self.browser.find_element(
By.CSS_SELECTOR, "#id_bud_suggestions .bud-suggestion-item"
))
self.assertEqual(suggestions.text.strip(), "alice")
suggestions.click()
self.wait_for(lambda: self.assertEqual(
recipient.get_attribute("value"), "alice"
))
self.assertEqual(
self.browser.find_elements(By.ID, "id_bud_suggestions"),
[],
)
def test_add_unregistered_email_is_silent_noop(self):
self.browser.get(self.live_server_url + "/billboard/my-buds/")

View File

@@ -1,4 +1,3 @@
{% load static %}
{# ─────────────────────────────────────────────────────────────────────── #}
{# _bud_add_panel.html — bottom-left handshake btn + slide-out add- #}
{# bud field. Mirrors _bud_panel.html (post-share) but POSTs to #}
@@ -19,18 +18,10 @@
<button id="id_bud_ok" type="button" class="btn btn-confirm">OK</button>
</div>
{# Autocomplete suggestions list — sibling of #id_bud_panel because the #}
{# panel has overflow:hidden for its scaleX slide animation. #}
<div id="id_bud_suggestions" class="bud-suggestions" hidden></div>
<script src="{% static 'apps/billboard/bud-autocomplete.js' %}"></script>
<script>
bindBudAutocomplete(
document.getElementById('id_recipient'),
document.getElementById('id_bud_suggestions'),
{ searchUrl: '{% url "billboard:search_buds" %}' }
);
</script>
{# No autocomplete on this panel — the bud-autocomplete pool is the #}
{# user's existing buds, which is precisely the set you can't usefully #}
{# re-add. Post-share + gatekeeper-invite panels keep the autocomplete #}
{# binding (re-sharing with an existing bud is a real flow). #}
<script>
(function () {
@@ -77,10 +68,6 @@
if (!html.classList.contains('bud-open')) return;
if (panel.contains(e.target)) return;
if (e.target === btn || btn.contains(e.target)) return;
// Suggestions live outside the panel (panel has overflow:hidden
// for its scaleX slide); a click inside them must NOT close+clear.
var sg = document.getElementById('id_bud_suggestions');
if (sg && sg.contains(e.target)) return;
_close();
});