feat: wallet Tokens applet shows CARTE + BAND + COIN + PASS independently — Chunk 1 of the Shop applet rollout per [[project-wallet-shop-expansion]]. Pre-Chunk-1 the _applet-wallet-tokens.html template used a {% if pass_token %} ... {% elif band %} ... {% elif coin %} chain that suppressed 2-of-3 trinkets from the wallet whenever the user held a higher-priority one — bad UX since the equip slot is now the user's opt-in for trinket-as-token use per [[feedback-equip-slot-gates-trinket-use]], so ALL owned trinkets need visibility. Fix: dropped the elif chain → independent {% if %} blocks for PASS / BAND / COIN; added a new CARTE block w. fa-money-check icon mirroring the Game Kit's render. View context (apps.dashboard.views.wallet + :toggle_wallet_applets) now passes carte = user.tokens.filter(token_type=Token.CARTE).first() alongside the existing pass/band/coin keys (no is_staff filter — CARTE has no admin gate). TDD — new WalletTokensAppletAllTrinketsVisibleTest (9 ITs): 6 pin individual #id_<token> visibility for a staff user holding all 5 types, 2 pin view-context shape (carte + band keys), 1 pins CARTE-on-non-staff. New FT test_wallet_tokens_applet_shows_all_owned_trinket_types reads BAND/CARTE .tt innerHTML directly (no hover ceremony — already covered by the COIN/FREE hover paths in test_new_user_wallet_shows_starting_balances) to pin the new template blocks server-render full tooltip prose. **Trap caught mid-build**: initial multi-line {# ... #} Django comment leaked as plain text into the rendered DOM (Django's hash-comment is single-line only), pushing the COIN tile off-screen + breaking the existing hover FT. Switched to {% comment %}...{% endcomment %}. Captured in [[feedback-django-comments-single-line-only]] — symptom signature: previously-passing Selenium hover times out + screendump shows literal {# ... text near the broken element. 1169 IT/UT + 6 wallet FTs green
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ from selenium.webdriver.common.by import By
|
||||
|
||||
from .base import FunctionalTest
|
||||
from apps.applets.models import Applet
|
||||
from apps.lyric.models import Token, User
|
||||
|
||||
|
||||
class WalletDisplayTest(FunctionalTest):
|
||||
@@ -179,6 +180,50 @@ class WalletDisplayTest(FunctionalTest):
|
||||
)
|
||||
self.assertEqual(rows, '3')
|
||||
|
||||
def test_wallet_tokens_applet_shows_all_owned_trinket_types(self):
|
||||
"""Wallet Tokens applet renders every owned trinket-as-token type
|
||||
independently — PASS (staff), BAND, COIN, CARTE — alongside FREE
|
||||
+ TITHE. Pre-2026-05-22 the template had an if/elif chain that
|
||||
only showed ONE of {PASS, BAND, COIN}; that hid BAND + COIN +
|
||||
CARTE entirely from the wallet for any staff user holding a PASS,
|
||||
even though all three are usable at the gate. Chunk 1 of the
|
||||
Shop applet rollout drops that exclusivity so each trinket gets
|
||||
its own tooltipped icon in the row."""
|
||||
# 1. Build a staff user holding every trinket-as-token type
|
||||
staff = User.objects.create(email="ledger@test.io", is_staff=True)
|
||||
# post_save signal already created COIN (auto-equipped) + FREE + PASS;
|
||||
# mint the rest manually so we exercise the full inventory render.
|
||||
Token.objects.create(user=staff, token_type=Token.BAND)
|
||||
Token.objects.create(user=staff, token_type=Token.CARTE)
|
||||
Token.objects.create(user=staff, token_type=Token.TITHE)
|
||||
# 2. Log in + land on wallet page
|
||||
self.create_pre_authenticated_session("ledger@test.io")
|
||||
self.browser.get(self.live_server_url + "/dashboard/wallet/")
|
||||
# 3. Every trinket-as-token icon is present (no if/elif suppression)
|
||||
self.wait_for(lambda: self.browser.find_element(By.ID, "id_pass_token"))
|
||||
self.browser.find_element(By.ID, "id_band_token")
|
||||
self.browser.find_element(By.ID, "id_coin_on_a_string")
|
||||
self.browser.find_element(By.ID, "id_carte_token")
|
||||
# 4. Consumable tokens still present
|
||||
self.browser.find_element(By.ID, "id_free_token")
|
||||
self.browser.find_element(By.ID, "id_tithe_token")
|
||||
# 5. BAND tile carries its tooltip content in the DOM (the wallet's
|
||||
# `initWalletTooltips` clones `.tt` innerHTML into the portal on
|
||||
# hover — already exercised by the COIN/FREE hover paths in
|
||||
# `test_new_user_wallet_shows_starting_balances`; here we just pin
|
||||
# that the new BAND/CARTE template blocks server-render their full
|
||||
# tooltip prose, which is the Chunk 1 contract).
|
||||
band_tt = self.browser.find_element(By.CSS_SELECTOR, "#id_band_token .tt").get_attribute("innerHTML")
|
||||
self.assertIn("Wristband", band_tt)
|
||||
self.assertIn("Admit All Entry", band_tt)
|
||||
self.assertIn("no expiry", band_tt)
|
||||
# 6. CARTE tile carries its tooltip content too
|
||||
carte_tt = self.browser.find_element(By.CSS_SELECTOR, "#id_carte_token .tt").get_attribute("innerHTML")
|
||||
self.assertIn("Carte Blanche", carte_tt)
|
||||
self.assertIn("Admit up to +6", carte_tt)
|
||||
self.assertIn("no expiry", carte_tt)
|
||||
|
||||
|
||||
def test_user_can_purchase_tithe_token_bundle(self):
|
||||
# 1. Log in, navigate to wallet page
|
||||
self.create_pre_authenticated_session("capman@test.io")
|
||||
|
||||
Reference in New Issue
Block a user