Files
treg/tests/test_dashboard_markup.py
T

1255 lines
68 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Source regressions for the compiled Vue dashboard.
Components are expanded at their mount sites so conditional ancestry remains visible.
Browser tests complement these checks with real navigation and event handling.
"""
from __future__ import annotations
import re
from pathlib import Path
import pytest
from treg import api
from dashboard_source import dashboard_source
INDEX = dashboard_source()
TUTORIAL = (Path(api.__file__).parent / "web" / "tutorial.html").read_text(encoding="utf-8")
# Dialogs reachable from more than one view. Each is opened by a button that exists on both the
# marketplace list and an integration page.
SHARED_DIALOGS = ["tokenAsk", "capAsk", "methodAsk", "resPick"]
def test_paid_key_probe_warning_is_rendered_from_typed_provider_data():
assert 'v-if="tokenAsk.provider.probe_cost_micro"' in INDEX
assert "money(tokenAsk.provider.probe_cost_micro)" in INDEX
assert "treg will not reuse this paid request for health checks" in INDEX
def test_oauth_entry_opens_the_existing_sign_in_modal_without_minting_a_sandbox():
assert "qs.get('signin')==='oauth'" in INDEX
assert "else this.demo.signin=true; // OAuth returns, use-case CTA arrivals (?ref=)" in INDEX
assert "Sign in to continue connecting Treg" in INDEX
assert "After sign-in, review the requested access before you approve it." in INDEX
assert '<details v-if="!oauthSignin" style="margin-top:12px;text-align:left">' in INDEX
def test_ref_entry_opens_sign_in_without_minting_a_sandbox():
boot = INDEX[INDEX.index("const qs = new URLSearchParams(location.search)") :]
assert "ref = qs.get('ref')" in boot
assert "ref || oauthSignin" in boot
assert "else this.demo.signin=true; // OAuth returns, use-case CTA arrivals (?ref=)" in boot
assert "sbxInit" not in boot
assert "/demo/sandbox" not in INDEX
assert '<section ref="demo">' not in INDEX
assert "localStorage.getItem('treg-sbx')" not in INDEX
# Every <template> open/close, because only a balanced count locates the view boundaries: the file
# nests plain `v-if`/`v-for` templates inside views, and each of those closes with a `</template>`
# that would otherwise be read as closing the view. (Corollary: don't write a literal `<template`
# inside an HTML comment in index.html — this counts it as a real open tag.)
_TPL = re.compile(r"<template\b(?P<attrs>[^>]*)>|</template>")
_VIEW_ATTR = re.compile(r"""v-if="view==='(\w+)'""")
def _enclosing_views(needle: str) -> list[str]:
"""Which `<template v-if="view===...">` blocks, if any, contain `needle`."""
at = INDEX.index(needle)
stack: list[str | None] = []
for m in _TPL.finditer(INDEX[:at]):
if m.group(0).startswith("</"):
if stack:
stack.pop()
else:
v = _VIEW_ATTR.search(m.group("attrs"))
stack.append(v.group(1) if v else None)
return [v for v in stack if v]
@pytest.mark.parametrize("dialog", SHARED_DIALOGS)
def test_shared_dialogs_are_not_trapped_inside_one_view(dialog: str):
"""A dialog nested in `view==='connections'` does not render on the integration page — the
Connect button looks dead, and the modal appears on the list view once you navigate back.
Vue reports nothing, because a v-if that never matches is not an error."""
enclosing = _enclosing_views(f'v-if="{dialog}"')
assert not enclosing, f"{dialog} dialog is trapped inside view(s) {enclosing}; move it to root"
def test_the_parser_can_actually_see_a_trapped_dialog():
"""Guard the guard: a check that can't detect the bug it exists for is worse than none."""
assert _enclosing_views('v-for="p in g.items"') == ["connections"]
def test_separate_oauth_methods_share_one_single_choice_modal():
"""Instagram's second grant used to live in a red provider-page banner while Add account
silently chose direct Login. Multi-method providers now get one radio decision and one CTA;
ordinary providers must retain the old zero/one-method path."""
assert 'v-if="methodAsk"' in INDEX
assert 'v-model="methodAsk.selected"' in INDEX
assert 'class="chip ok">Recommended</span>' in INDEX
assert 'v-if="method.in_review" class="chip warn">In review</span>' in INDEX
assert 'v-if="capInReview(cap,capAsk)" class="chip warn"' in INDEX
assert "mkProvider.permission_capabilities||mkProvider.capabilities" in INDEX
assert '@click="continueMethod()">Continue</button>' in INDEX
assert "if(methods.length>1 && !conn)" in INDEX
assert "if(methods.length===1 && !conn) return this.connectProvider" in INDEX
assert "connectProvider(mkProvider,'page-tools')" not in INDEX
assert "Instagram Login {{mkInstagramDirect" not in INDEX
assert "if((method.capabilities||[]).length>1){ this.capAsk=" in INDEX
assert "if(ask && ask.method) return [...(ask.method.capabilities||[])].reverse()" in INDEX
def test_connection_rows_retain_the_shared_production_layout():
assert "<b>{{c.identity_label || c.name}}</b>" in INDEX
assert "{{c.resource_name || c.resource_ref" in INDEX
assert "<span class=\"mono\" :title=\"'treg call '+c.name\">{{c.name}}</span>" in INDEX
assert "c.provider==='instagram'" not in INDEX[INDEX.index('<tr v-for="c in mkConns"') : INDEX.index('</table>', INDEX.index('<tr v-for="c in mkConns"'))]
def test_permission_cards_can_use_method_specific_incremental_benefits():
panel = INDEX[INDEX.index('<div class="tgh">Permissions') : INDEX.index('<!-- Cross-link into the endpoint catalog:')]
assert "mkCapabilityIntro(cap)" in panel
assert "mkCapabilityDetails(cap)" in panel
computed = INDEX[INDEX.index("computed:{") : INDEX.index("methods:{")]
assert "mkCapabilityMethod(cap){" not in computed
logic = INDEX[INDEX.index("mkCapabilityMethod(cap){") : INDEX.index("capLabel(cap, ask){")]
assert "m.capability_details && (m.capability_details[cap]||[]).length" in logic
assert "this.mkProvider&&this.mkProvider.scope_detail" in logic
assert "page-tools" not in logic and "instagram" not in logic
# --- endpoint catalog: the marketplace's platform axis (view==='platform') --------------------
def test_the_platform_header_stacks_instead_of_putting_providers_in_a_column():
"""`.tut-head` is two columns, and a platform can be served by a dozen providers — as a
right-hand column that chip list steals half the width and wraps the title into a ribbon
("People & / contact / data"). Title full width, intro under it, providers as their own row."""
at = INDEX.index('<div class="plat-head">')
head = INDEX[at : INDEX.index('v-if="platLoading"', at)]
assert head.index('class="plat-title"') < head.index('plat-intro"') < head.index('class="plat-provs"')
assert 'v-for="s in platProviders"' in head
assert "tut-actions" not in head # the two-column header is gone from this view
def test_platform_provider_navigation_does_not_wait_for_connection_registry_state():
block = INDEX[INDEX.index("platProviders(){") : INDEX.index("// ---- the ledger ----")]
assert "this.providers.some" not in block
assert "seen.filter(s=>s!=='treg')" in block
def test_platform_view_is_a_top_level_view():
"""`view==='platform'` nested inside another view would render nowhere — the platform cards
would look like dead buttons, exactly the failure the dialog checks above exist for."""
assert _enclosing_views("<template v-if=\"view==='platform'\">") == []
def test_platform_shelf_lives_on_the_marketplace_list():
"""The only way into a platform page is the tile grid on the marketplace list view."""
assert _enclosing_views("openPlatform(pl.slug)") == ["connections"]
def test_platform_shelf_disappears_without_the_catalog():
"""/catalog is served by a newer build than some deployments run: the tab bar must be v-if'd on
having platforms, so a 404 leaves the marketplace exactly as it was rather than showing an
empty section or an error."""
tabs = INDEX.index('<div class="mk-tabs-wrap"')
assert 'v-if="plats.list.length"' in INDEX[tabs : tabs + 200]
# ...and with no tiles to show, the active tab resolves to the original provider shelves.
assert "mkTabActive(){ return this.platCategories.length ? this.mkTab : 'platform'; }" in INDEX
# --- marketplace tab bar: capability-first tiles, with the original shelves on the last tab ------
def test_the_tab_bar_is_all_plus_the_catalog_categories_plus_platform():
"""The founder's bar reads All | <categories> | Platform. The middle is derived from the
catalog's own `category` field rather than hard-coded, so a new category can't go missing."""
assert 'v-for="t in mkTabs"' in INDEX
tabs = INDEX[INDEX.index("mkTabs(){") : INDEX.index("mkTabs(){") + 420]
assert "key:'all'" in tabs
assert "for(const g of this.platCategories)" in tabs
assert "key:'platform'" in tabs
# The canonical reading order, straight from the founder's list. It is only an ORDER: the
# categories themselves are whatever the catalog rows carry, so this list may not gate them.
order = INDEX[INDEX.index("platCategories(){") :][:900]
assert (
"['Enrichment','SEO/AEO','Social','Advertising','E-commerce','Reviews & Apps',"
"'AI generation','Community']" in order
)
def test_the_category_list_comes_from_the_data_not_the_order_list():
"""Categories keep changing ("Social media" became "Social", "China Social" is new). A category
the catalog invents must still get a shelf and a tab — sorted to the end, never dropped."""
body = INDEX[INDEX.index("platCategories(){") :][:2000]
assert "for(const pl of this.plats.list)" in body # the categories are read off the rows...
assert "Object.keys(by).filter(c=>!order.includes(c)).sort()" in body # ...and unknown ones survive
# The old catalog names, gone from the data. The answer engines were their own shelf twice over
# ("AI Search", then "AEO / GEO"); they are unfeatured SEO platforms now, so they surface inside
# that shelf's overflow row instead. (`providerGroups` has its own, unrelated category set from
# /oauth/providers — "Social media" there is an integration shelf, not a platform one.)
for gone in ("'Social media'", "'AI Search'", "'AEO / GEO'"):
assert gone not in body, f"{gone} is no longer a catalog category — remove the reference"
def test_ai_generation_shelf_names_all_three_media_modalities():
assert "'AI generation':'video, image and voice models" in INDEX
def test_tiles_are_grouped_by_category_on_every_capability_tab():
""""All" is not a flat wall of tiles: it keeps the category headings, and a category tab is the
same grouping filtered to one — so the page never loses its place."""
assert 'v-for="g in platCatGroups"' in INDEX
assert _enclosing_views('v-for="g in platCatGroups"') == ["connections"]
grp = INDEX[INDEX.index("platCatGroups(){") :][:260]
assert "this.mkTabActive==='all' ? this.platCategories" in grp
assert "filter(g=>g.category===this.mkTabActive)" in grp
def test_platforms_categorised_as_other_get_no_tile():
"""`account` and friends are capabilities of a platform page, not destinations — a tile for
"Other" would be a dead end."""
cats = INDEX[INDEX.index("platCategories(){") :][:2000]
assert "if(c==='Other') continue;" in cats
# --- featured shelves: a long category shows its ranked tiles, then one "more" row ---------------
def test_a_long_category_shows_only_its_featured_tiles():
"""China Social carries 14 platforms. A wall of 14 tiles is scrolled past, not read, so past the
threshold only the catalog's `featured` ranks get a full tile."""
grp = INDEX[INDEX.index("platCatGroups(){") :][:1400]
assert "items.filter(p=>p.featured!=null)" in grp
assert "items.length<=8" in grp
assert "this.platShelfOpen[g.category]" in grp # ...until the row is clicked
def test_featured_tiles_are_ordered_by_rank_then_size():
"""`featured` is a rank, so 1 comes first; the unranked tail has only endpoint count left to
sort by. An unranked platform must sort AFTER every ranked one, not before it."""
grp = INDEX[INDEX.index("platCatGroups(){") :][:1400]
assert "(a.featured==null?1e9:a.featured)-(b.featured==null?1e9:b.featured)" in grp
assert "(b.endpoints||0)-(a.endpoints||0)" in grp
def test_a_category_with_no_featured_ranks_still_shows_its_tiles():
"""A shelf whose rows are all unranked would collapse to an empty grid over a "more" row —
the whole category hidden behind a click, which is worse than a long shelf."""
assert "|| !feat.length ||" in INDEX[INDEX.index("platCatGroups(){") :][:1400]
def test_the_shelf_count_is_the_whole_category_not_the_visible_tiles():
"""A header reading "SEO 5" under a tab reading "SEO 10" looks like tiles went missing."""
assert 'class="sec-n">{{g.total}}' in INDEX
assert "total:items.length" in INDEX
def test_a_category_heading_is_a_real_heading():
"""The page is browsed by category, so the category has to be the loudest thing on it after the
page title — a small muted caption made the whole marketplace read as undifferentiated."""
head = INDEX[INDEX.index('<div class="sec-head">') :][:500]
assert '<h2 class="sec-h"><b>{{g.category}}</b>' in head
assert "{{g.hint}}" in head # the one-line explainer stays, under the heading
def test_the_more_row_names_the_platforms_it_is_hiding():
""""See Zhihu, WeChat Channels, and 6 more" — a stack of the marks plus two names, so the row
says what KIND of thing is hidden rather than only how much of it."""
at = INDEX.index('class="pt-more"')
row = INDEX[at : at + 1200]
assert "platShelfOpen[g.category]=true" in row
assert 'v-for="pl in g.rest.slice(0,7)"' in row # the little logo stack
assert "'/logos/platforms/'+pl.slug+'.svg'" in row
assert "moreLabel(g.rest)" in row
lbl = INDEX[INDEX.index("moreLabel(rest){") :][:400]
assert "rest.slice(0,2)" in lbl
assert "(rest.length-2)+' more'" in lbl
# --- the platform card: enough to choose a platform without opening it --------------------------
def _card() -> str:
at = INDEX.index('class="pt-card"')
return INDEX[at : INDEX.index("</button>", at)]
def test_a_card_leads_with_the_platforms_own_mark_and_name():
"""TikTok's card wears TikTok's mark, with the category as the subtitle — the headline answers
"which data", which is the question the whole browse surface is organised around."""
card = _card()
assert "'/logos/platforms/'+pl.slug+'.svg'" in card
assert 'class="pt-name">{{platShort(pl.label)}}' in card
assert 'class="pt-cat">{{pl.category}}' in card
def test_a_card_corner_answers_whether_you_can_call_it_today():
"""The corner is the one browse-time fact that changes what you do next: call it, or go and
sign up first. WHICH provider serves it is a decision for the platform page, so the provider
logo stack that used to live here is gone."""
card = _card()
assert 'v-if="platConnected(pl)" class="chip go"' in card
assert ">Connected</span>" in card
assert 'v-else class="pt-quiet"' in card and ">not connected<" in card
assert "'/logos/'+s+'.svg'" not in card # the provider stack is gone
fn = INDEX[INDEX.index("platConnected(pl){") :][:220]
assert "some(s=>this.catConnected(s))" in fn # ANY serving provider being connected is enough
def test_a_card_is_a_name_and_two_facts_with_no_description_paragraph():
"""Size and starting price are what turn a wall of logos into a comparison, and both come from
the catalog row (`price_from`) — no detail call needed. The summary paragraph does NOT: it
repeated what the name and category already said and made every card tall enough that a shelf
of twelve became a scroll. It survives as the card's hover title, nowhere else."""
card = _card()
assert "pt-desc" not in card and "pt-desc" not in INDEX, "the paragraph and its CSS are both gone"
assert "{{pl.endpoints}} endpoint" in card
assert 'v-if="platPrice(pl)"' in card
assert ":title=\"pl.summary ? pl.label+' — '+pl.summary : pl.label\"" in card
def test_the_card_price_is_the_servers_computed_usd():
"""Every price the marketplace shows is in one unit, so two numbers on the same screen can be
compared. The conversion is the server's (`usd`), not the dashboard's — a local FX constant
would drift from the CLI the moment the rate table changed."""
fn = INDEX[INDEX.index("platPrice(pl){") :][:1400]
assert "typeof pf.usd==='number'" in fn
assert "typeof pf.display_usd==='number' ? pf.display_usd : pf.usd" in fn
assert "pf.display_unit || this.priceUnit(pf.type)" in fn
assert "return null; }" in fn # priced but unpublished → say nothing, not "from —"
# "from" is a floor: an OAuth provider among the platform's providers makes the floor $0, even
# when metered providers publish a rate — that rate demotes to the tooltip.
assert fn.index("if(hasOauth) return {free:true") < fn.index("if(paid) return {free:false")
def test_an_empty_price_from_object_reads_as_no_price_at_all():
"""`price_from` arrives as null OR as `{}`. A truthy empty object short-circuits the OAuth-free
branch below it, silently costing an OAuth-only platform its "free with your account"."""
fn = INDEX[INDEX.index("platPrice(pl){") :][:1400]
assert "(raw && Object.keys(raw).length) ? raw : null" in fn
def test_fish_voice_actions_use_dashboard_state_not_native_dialogs():
block = INDEX[INDEX.index("async loadFishVoices(){") : INDEX.index("async runTry(){")]
assert "prompt(" not in block and "confirm(" not in block
assert "fishVoiceDialog={action:'rename'" in block
assert "fishVoiceDialog={action:'delete'" in block
assert "detail.endpoint||detail" in block
assert "inspectFishVoice" not in INDEX
assert "fishaudio.voices.get" not in INDEX
def test_fish_voice_design_is_not_exposed_in_the_dashboard():
assert "fishaudio.voice-design.create" not in INDEX
assert "saveVoiceCandidate" not in INDEX
assert "voice_design_signatures" not in INDEX
def test_fish_voice_panel_uses_the_server_unified_resource_view():
block = INDEX[INDEX.index("async loadFishVoices(){") : INDEX.index("async useFishVoice(voice){")]
assert "/provider-resources?provider=fishaudio&kind=voice" in block
assert "X-Treg-Resource-Source" in block
assert "/call/fishaudio.voices.list" not in block
assert "No BYOK key is required for team voices" in INDEX
assert "treg resources list --provider fishaudio --kind voice" in INDEX
def test_team_resources_is_a_vault_tab_with_platform_only_rows_and_pagination():
assert _enclosing_views("<template v-if=\"view==='resources'\">") == []
assert INDEX.count("Team resources</button>") == 3
assert "provider-resources?source=platform" in INDEX
assert "pagedTeamResources" in INDEX
assert "teamResourcePageCount>1" in INDEX
assert "Page {{teamResourceCurrentPage}} of {{teamResourcePageCount}}" in INDEX
assert "view==='tools'||view==='secrets'||view==='resources'" in INDEX
def test_team_resources_is_registered_in_both_view_whitelists():
assert INDEX.count("'start','resources','connections','referrals'") == 2
def test_a_converted_price_still_shows_the_providers_own_figure():
"""Nobody should have to wonder whether we invented the number: the native amount rides along
wherever the provider bills in something other than USD. On the platform card it rides in the
hover title, not the footer — "(1 credit)" after an already-long price wrapped the card."""
assert ".cost-nat{" in INDEX
fn = INDEX[INDEX.index("nativeAmount(c){") :][:500]
assert "c.currency==='USD'" in fn # ...and is omitted when there is nothing to convert
assert "n.toFixed(2)" in fn # money keeps its cents: ¥0.10, not ¥0.1
# the two roomy price surfaces carry it inline; the platform card only in its tooltip
assert "platPrice(pl).native" not in INDEX
assert "'billed as '+p.native" in INDEX
assert "r.priceNative" in INDEX
assert 'v-if="costNative(e.cost)"' in INDEX
def test_sub_cent_prices_get_two_significant_figures():
"""$0.01476 as "$0.01" is wrong and as "$0.014760" is noise. Two significant figures reads as a
price at every magnitude the catalog carries ($0.00015 through $0.044)."""
fn = INDEX[INDEX.index("usdNum(n){") :][:500]
assert "n.toPrecision(2)" in fn
assert "n.toFixed(2)" in fn # ...but a dollar or more is just cents
assert "indexOf('e')" in fn # toPrecision goes exponential below 1e-6
def test_an_oauth_only_platform_reads_as_free_with_your_account():
"""`price_from` is null both when a rate is unpublished and when there is nothing to charge for.
Every-provider-is-OAuth separates them: the account you connect IS the licence."""
fn = INDEX[INDEX.index("platPrice(pl){") :][:1200]
assert "p.auth_kind==='oauth'" in fn
assert "free with your account" in fn
def test_an_undrawn_platform_falls_back_to_a_generated_initial_tile():
"""60 platforms and counting: a missing SVG must degrade to a coloured initial, not a broken
image. The colour is derived from the slug so it is stable across reloads."""
card = _card()
assert '@error="platLogoBad[pl.slug]=true"' in card
assert 'v-else class="pt-i"' in card
assert "platTileBg(slug){" in INDEX
def test_the_platform_tab_is_the_original_provider_marketplace():
"""The last tab is the pre-existing integration shelves, unchanged — connect flows all live
there, so nothing may be lost behind the new default view."""
at = INDEX.index("""<template v-if="mkTabActive==='platform'">""")
block = INDEX[at : INDEX.index('v-if="view===\'provider\' && mkProvider"')]
assert 'v-for="g in shownGroups"' in block # the category shelves
assert 'v-for="p in g.items"' in block # the provider cards
assert 'openProvider(p.service)' in block # ...still opening the integration page
# --- platform detail: ONE ledger, sectioned by domain -------------------------------------------
def _ledger() -> str:
"""The platform view's markup, from the filter bar to the end of the table."""
view = INDEX[INDEX.index("<template v-if=\"view==='platform'\">") :]
return view[: view.index("<template v-if=\"view==='tools'\">")]
def test_the_platform_is_one_table_not_a_stack_of_capability_cards():
"""A platform page is a ledger you scan top to bottom: one table, section headings inside it.
The old per-capability card stack made the shape of the platform unreadable — every job looked
the same size, and nothing could be compared without opening two cards."""
block = _ledger()
assert '<table class="ledger">' in block
assert 'v-for="sec in platLedger"' in block
assert '<tr class="lsec"' in block
assert "cap-card" not in INDEX, "the capability card is gone, and so is its CSS"
def test_sections_are_domains_with_other_pinned_last():
"""`other` is the junk drawer: it is the one section whose position carries meaning, and it
can't be allowed to outrank a real subject just because it is large. The order is decided
server-side so the API, the CLI and this page can't disagree about it."""
src = (Path(api.__file__).parent / "domain" / "catalog" / "store.py").read_text(encoding="utf-8")
fn = src[src.index("def domain_rows("):]
assert "key=lambda d: (d == DOMAIN_OTHER, -len(sections[d]), d)" in fn
# ...and the page renders that order rather than re-sorting it.
led = INDEX[INDEX.index("platLedger(){") :][:900]
assert "this.platData.domains||[]" in led
def test_merged_rows_come_before_single_rows_in_a_section():
"""A job several providers do is the comparison the catalog exists to make, so it leads its
section; the endpoints only one provider offers follow."""
src = (Path(api.__file__).parent / "domain" / "catalog" / "store.py").read_text(encoding="utf-8")
fn = src[src.index("def domain_rows("):]
assert 'section.sort(key=lambda r: (r["kind"] != "merged"' in fn
def test_a_collapsed_merged_row_prices_its_providers_in_short_pills():
"""The pills are the comparison the merge exists to make, so they stay — but each one is a name,
a price only when the price is a REAL number, and a ✓. The long filler ("per result · price in
provider dashboard") is what wrapped a six-provider row over four lines, and it appears on no
collapsed surface. Short pills may wrap to a second line; prose may not."""
block = _ledger()
assert 'v-for="pill in r.pills"' in block and 'class="pchip"' in block
assert "{{pill.name}}" in block and 'v-if="pill.price"' in block
assert "costLabel" not in block, "the long form is a sentence — it belongs in the facts list"
price = INDEX[INDEX.index("pillPrice(c){") :][:500]
assert "if(c.type==='free') return 'free';" in price, "free is a real price and worth showing"
assert "typeof c.usd==='number' ? this.costLabel(c) : ''" in price
assert "l.length<=8 ? l : ''" in price, "a quota label only if it fits — '2 rows' yes, longer no"
# The cheapest of them still stands in the price column, so the row answers "what does it cost".
rows = INDEX[INDEX.index("platRowsAll(){") :][:3600]
assert "const cheapest=this.capCheapest(eps);" in rows
assert "cheapest.n>0?'from ':''" in rows, '"from free" hedges the one price that needs none'
def test_the_pill_strip_never_wraps_three_pills_then_a_count():
"""The hard rule: a collapsed merged row is EXACTLY one line. Wrapped chips gave the shelf
ragged row heights and left the title cell's border ending mid-row. Three pills and a `+N`,
on a strip that cannot wrap — the rest of the providers are one click down, on the sub-rows."""
block = _ledger()
assert 'v-if="r.pillsMore" class="pchip more"' in block and "+{{r.pillsMore}}" in block
assert ':title="r.pillsMoreTitle"' in block, "the hidden names stay reachable"
rows = INDEX[INDEX.index("platRowsAll(){") :][:3600]
assert "pills:pills.slice(0,3), pillsMore:Math.max(0, pills.length-3)" in rows
def test_the_three_visible_pills_are_the_ones_worth_seeing():
"""Only three survive, so they are sorted cheapest-first then verified — and the providers with
no price to show, whose pill would be a bare name, sort to the tail."""
fn = INDEX[INDEX.index("provPills(eps){") :][:900]
assert ".sort((a,b)=>(a.n==null)-(b.n==null) || (a.n-b.n) || (b.verified-a.verified))" in fn
def test_a_pill_is_per_provider_not_per_endpoint():
"""TikHub offers the same job four ways; four identical TikHub pills is noise, not a comparison.
One pill per provider, carrying that provider's cheapest priced endpoint."""
fn = INDEX[INDEX.index("provPills(eps){") :][:700]
assert "by.set(e.provider" in fn
assert "if(n!=null && (cur.n==null || n<cur.n))" in fn # ...its cheapest
assert "cur.verified = cur.verified || !!e.verified" in fn # ...verified if ANY of them is
def test_a_merged_row_counts_providers_and_endpoints_separately():
"""One provider can offer the same job three ways, so the two numbers differ — and the endpoint
count standing in for the provider count read "6 providers" on a 3-provider row."""
rows = INDEX[INDEX.index("platRowsAll(){") :][:2900]
assert "provN:provs.length" in rows
assert "' provider'+(provs.length===1?'':'s')" in rows
assert "' endpoint'+(eps.length===1?'':'s')" in rows
# ...in the cell's tooltip, not on a second line — a second line is what made these rows look
# broken next to the single ones.
assert ':title="r.provTitle"' in _ledger()
def test_a_single_row_is_led_by_a_short_title_never_a_paragraph():
""""Get Showcase Product List" says more than `tiktok.shop.showcase` ever could, so a row only
one provider serves is led by the endpoint's curated `name`, falling back to its `summary`. But
a summary is documentation prose — DataForSEO's run to a paragraph — so the row CLIPS it and the
two-line clamp catches whatever still overflows. The full text is never lost: the expansion
shows it whole, and the clipped row keeps it in a title attribute."""
block = _ledger()
assert "{{r.title}}" in block
assert 'v-if="r.kind===\'merged\'"' in block
rows = INDEX[INDEX.index("platRowsAll(){") :][:2400]
assert "title:this.clip(r.description, 90)" in rows
clip = INDEX[INDEX.index("clip(text, n){") :][:400]
assert "lastIndexOf(' ')" in clip, "clip at a word boundary, not mid-token"
# ...and the server picks name-over-summary before it ever reaches the row.
src = (Path(api.__file__).parent / "domain" / "catalog" / "store.py").read_text(encoding="utf-8")
fn = src[src.index("def domain_rows("):]
assert '"description": e["name"] or e["summary"] or title' in fn
assert '"description": view["name"] or view["summary"]' in fn
def test_the_expansion_still_carries_the_full_summary():
"""The row is a title; the prose the row clipped is the expansion's description. Losing it to
the clip would make the ledger less informative than the page it replaced."""
block = _ledger()
assert '<p class="cat-sum">{{e.summary||' in block
assert block.index('<div class="lep"') < block.index('<p class="cat-sum">')
def test_every_row_expands_not_just_the_merged_ones():
"""The row says what it does; the expansion says how to call it. Which of the two a visitor
needs is not something the row's shape can decide for them."""
block = _ledger()
assert '@click="toggleRow(r)"' in block
assert ':aria-expanded="!!platOpen[r.key]"' in block
assert '<tr v-if="platOpen[r.key]"' in block
tog = INDEX[INDEX.index("toggleRow(r){") :][:200]
assert "this.platOpen[r.key] = !this.platOpen[r.key]" in tog
def test_a_merged_row_expands_to_collapsed_provider_sub_rows():
"""Level two. Dropping six full parameter tables on one click buried the comparison the merge
exists to make, so a merged row opens to its providers — one line each: name, short price,
verification, route — and a provider opens to its own instruction."""
block = _ledger()
sub = block[block.index('<button v-if="r.kind===\'merged\'" class="lsub"') :]
assert '@click.stop="toggleEp(e)"' in sub
assert ':aria-expanded="!!epOpen[e.id]"' in sub
assert "{{costShort(e.cost)}}" in sub
assert 'class="lsub-path mono"' in sub
assert '<div class="lep" v-if="r.kind!==\'merged\' || epOpen[e.id]">' in block
tog = INDEX[INDEX.index("toggleEp(e){") :][:120]
assert "this.epOpen[e.id] = !this.epOpen[e.id]" in tog
def test_a_single_row_still_opens_straight_to_its_detail():
"""One provider is nothing to compare, so a single row skips the middle level — and it renders
the SAME detail block, so the two paths can't present the instruction differently."""
block = _ledger()
assert '<div class="lgrp" v-for="e in r.endpoints"' in block
assert block.count('<div class="lep"') == 1, "one copy of the detail markup, shared by both paths"
assert '<button v-if="r.kind===\'merged\'" class="lsub"' in block # ...the sub-row is the only extra
def test_the_long_metered_phrasing_never_reaches_a_collapsed_line():
""""per success · price in provider dashboard" is true and belongs in the expanded detail; on a
collapsed line it wraps the row onto three lines. Collapsed surfaces say "credit-priced"."""
short = INDEX[INDEX.index("costShort(c){") :][:400]
assert "return 'credit-priced'" in short
# a price table has no scalar value but does have a range, so only an unpublished number is
# "credit-priced" — a video or image model shows its per-second rate or range instead
assert "if(c.value==null && !(c.table && typeof c.usd==='number')) return 'credit-priced'" in short
assert "return this.costLabel(c)" in short # ...a published number is short already
block = _ledger()
assert "costLabel" not in block, "the long form is a sentence, not a label — it belongs in the facts"
facts = INDEX[INDEX.index("epFacts(e){") :][:900]
assert "does not publish the rate" in facts
assert "this.priceUnit(c.type)" in facts, "...naming the unit it IS billed by"
def test_a_domain_section_needs_a_visible_row_to_exist():
"""A section filed the account/utility plumbing under whatever capability id it happened to
carry, which conjured sections that had nothing else in them — CAMPAIGNS 0, LOCATION 0, PERSON
0, SCHOOL 0, TITLE 0 on the People page. A domain renders only if a browse row lands in it."""
led = INDEX[INDEX.index("platLedger(){") :][:1200]
assert "if(r.mgmt || (this.platDomain && r.domain!==this.platDomain)) continue;" in led
assert ".filter(s=>vis[s.domain])" in led, "no visible row, no section"
def test_management_endpoints_collapse_into_one_actions_section_at_the_bottom():
"""Account/utility routes are the provider's own plumbing (webhooks, saved lists, token
helpers). ONE collapsed section for the whole platform, at the foot of the ledger, counted in
its heading — not one expander per domain, and not filed by a domain that means nothing here."""
block = _ledger()
assert 'v-if="sec.actions"' in block and ">Actions" in block
assert '@click="platActionsOpen=!platActionsOpen"' in block
assert "{{sec.count}}" in block
assert "lmore" not in INDEX, "the per-section management expander and its CSS are gone"
led = INDEX[INDEX.index("platLedger(){") :][:1200]
assert "out.push({domain:'Actions', actions:true" in led
assert "rows:this.platActionsOpen?acts:[]" in led, "collapsed by default, and it renders no rows"
# ...and it is platform-wide, so a domain chip hides it rather than filtering it
fn = INDEX[INDEX.index("platActionRows(){") :][:220]
assert "this.platDomain ? [] : this.platRowsPreDomain.filter(r=>r.mgmt)" in fn
# ...and "All" counts what the domain chips add up to, not the plumbing behind them
assert "{{platBrowseCount}}" in block
assert "platBrowseCount(){ return this.platRowsPreDomain.filter(r=>!r.mgmt).length; }" in INDEX
# ...and an Actions row says which kind of plumbing it is — the only thing telling them apart
assert 'v-if="r.mgmt" class="chip lkind"' in block
assert "{{r.endpoints[0].kind}}" in block
def test_the_filter_bar_narrows_by_domain_text_and_verification():
block = _ledger()
assert 'v-for="d in platDomainTabs"' in block
assert 'v-model="platQ"' in block and 'v-model="platVerifiedOnly"' in block
assert "{{platStats.rows}} row" in block and "{{platStats.eps}} endpoint" in block
pre = INDEX[INDEX.index("platRowsPreDomain(){") :][:400]
assert "!this.platVerifiedOnly||r.verified" in pre
assert "!q||r.hay.includes(q)" in pre
def test_a_chip_counts_what_it_would_actually_show():
"""The chip counts are taken AFTER the text/verified filters and before the domain one, so a
chip never promises rows that the other filters have already removed."""
tabs = INDEX[INDEX.index("platDomainTabs(){") :][:600]
assert "for(const r of this.platRowsPreDomain)" in tabs
assert "this.platData.domains||[]" in tabs, "the server's order, so the bar can't reshuffle as you type"
def test_an_empty_filter_result_says_so_instead_of_showing_a_bare_table():
block = _ledger()
assert 'v-if="platLedger.length"' in block
assert "Nothing on this platform matches that filter" in block
assert '@click="platClearFilters"' in block
def test_the_filter_bar_and_section_headings_are_both_sticky():
"""Two sticky layers under the 57px top bar. The bar's chips SCROLL rather than wrap, because a
bar that grows a second row as you filter would push the headings out from under it."""
assert ".lbar{position:sticky;top:var(--lbar-top)" in INDEX
assert ".lsec td{position:sticky;top:var(--lsec-top)" in INDEX
assert ".lchips{display:flex;gap:6px;min-width:0;overflow-x:auto" in INDEX
# An `overflow:hidden` ancestor is a scroll container, and sticky inside one never escapes it.
assert ".lwrap{overflow:visible" in INDEX and ".ledger{overflow:visible" in INDEX
# --- "you can call this right now" has to survive being skimmed ---------------------------------
def test_the_ready_state_has_a_green_of_its_own():
"""`.chip.ok` is not styled anywhere, so it renders muted grey — a ready capability looked
exactly like an unavailable one. `.chip.go` is the marketplace's single "runnable" green."""
css = INDEX[INDEX.index(".chip.go{") :][:400]
assert "color:var(--green)" in css
assert "font-weight:600" in css
assert ".godot{" in INDEX # ...led by a dot, so it reads as a status and not a label
def test_a_callable_row_is_marked_down_its_leading_edge():
"""Picking the option you can already call is the reason to read the table, so a row with a
connected provider carries a rule down its edge — findable without reading."""
block = _ledger()
assert ':class="{open:platOpen[r.key], go:r.ready}"' in block
rows = INDEX[INDEX.index("platRowsAll(){") :][:3400]
assert "ready: eps.some(e=>this.catEndpointConnected(e))" in rows
def test_cheapest_orders_on_the_servers_usd_not_a_local_fx_constant():
"""A ¥0.10 endpoint and a $0.001 one have to be orderable. The catalog owns the FX table so one
rate refresh re-prices every screen at once and the dashboard cannot drift from the CLI."""
usd = INDEX[INDEX.index("costUsd(c){") :][:500]
assert "typeof c.usd==='number' ? c.usd : null" in usd
assert "0.14" not in usd # no hard-coded rate survives here
cheap = INDEX[INDEX.index("capCheapest(eps){") :][:600]
assert "this.nativeAmount(e.cost)" in cheap # ...with the provider's own figure alongside
def test_an_unpriced_endpoint_can_never_be_the_cheapest_option():
""""from —" is worse than naming the cheapest price we do know. A row quota is not a price
either, so it cannot win against a per-call rate — and the server would happily convert its
row COUNT into dollars, which is why it is excluded before `usd` is read."""
usd = INDEX[INDEX.index("costUsd(c){") :][:500]
assert "if(c.type==='quota_rows') return null;" in usd
assert usd.index("quota_rows") < usd.index("c.usd")
def test_credit_metered_providers_are_not_reported_as_unpriced():
"""Apollo, PDL, Hunter and friends bill in their own credits: no dollar figure, but the price IS
documented, in the note on every row. An em-dash would be flatly wrong there, and it is the
entire People/Company half of the catalog."""
rows = INDEX[INDEX.index("platRowsAll(){") :][:3400]
assert "eps.some(e=>e.cost&&e.cost.note) ? 'see provider' : '—'" in rows
def test_a_connected_oauth_endpoint_counts_as_the_free_path():
"""The account you already connected is the licence — calling it costs nothing more, which is
usually the right answer and must beat any metered scraper."""
free = INDEX[INDEX.index("capFree(e){") :][:400]
assert "this.catEndpointConnected(e)" in free
assert "e.scope==='own_account'" in free
assert "e.cost.type==='free'" in free
# --- the expansion: the whole instruction, without leaving the page -----------------------------
def test_the_expansion_is_two_tabs_request_first():
"""What you SEND and what comes BACK are two documents; stacked, the expansion was a page you
scrolled rather than read. Request leads — it is the half that was missing, and the half that
tells you whether the endpoint is callable at all."""
block = _ledger()
bar = block[block.index('<div class="ltabs">') : block.index('</div>', block.index('<div class="ltabs">'))]
assert bar.index(">Request<") < bar.index(">Example response<")
assert "epTabOf(e)===\'req\'" in block and "epTabOf(e)===\'res\'" in block
def test_an_endpoint_with_no_example_has_no_second_tab_at_all():
"""Not a greyed-out tab, not a placeholder: a disabled tab is a promise the catalog can't keep,
and it draws the eye to the one thing that isn't there. Such an endpoint has one tab, which
reads as a label for the pane under it."""
block = _ledger()
assert '<button v-if="e.has_example" class="ltab"' in block
assert "disabled" not in block, "no faded tab, and no placeholder to go with it"
assert "No captured example" not in INDEX and "No example was captured for this" in INDEX # ...only as a load error
# ...and a stale 'res' tab state can't survive on an endpoint that has no example
fn = INDEX[INDEX.index("epTabOf(e){") :][:200]
assert "(t==='res' && !e.has_example) ? 'req'" in fn
assert "if(tab==='res' && !e.has_example) return;" in INDEX[INDEX.index("setEpTab(e, tab){") :][:300]
def test_an_expanded_endpoint_lists_its_parameters():
"""The captured response answered "what comes back" while this half was missing, so every
endpoint looked uncallable until you left for the provider's docs."""
block = _ledger()
assert '<div class="prm"' in block
assert "{{p.name}}" in block and "{{p.type||'—'}}" in block
assert ">required</span>" in block and ">optional</span>" in block
assert "e.g. {{fmtExample(p.example)}}" in block
assert "v-if=\"e.input && e.input.note\"" in block # the top-level hint line
def test_parameters_are_grouped_by_where_they_go():
"""A name alone doesn't tell you whether it belongs in the query string, the path or the body.
Query first, then path, then body — the order you fill them in for the common GET."""
fn = INDEX[INDEX.index("paramSections(e){") :][:700]
assert fn.index("add('query'") < fn.index("add('path'") < fn.index("add('body'")
assert "i.bodyType" in fn # the body section says which encoding it wants
def test_an_endpoint_with_no_catalogued_params_says_so_rather_than_showing_an_empty_table():
"""Every one of the ~1850 extended endpoints carries `input: null`, so this is the common case,
not an edge one."""
block = _ledger()
assert 'v-else class="prm-none"' in block
assert "provider's docs have them" in block
def test_the_expansion_carries_a_paste_ready_call_line():
"""Finding the endpoint was never the goal — running it is. The `treg call` line is served on
the row itself (`call_template`), so the instruction is complete without a second request."""
block = _ledger()
assert '<div class="lcall" v-if="e.call_template">' in block
assert "{{e.call_template}}" in block
assert '@click.stop="copyCall(e)"' in block
def test_the_expansion_carries_the_provider_wide_facts():
"""Limits and the rate card live once per provider at the top of its yaml, and an expanded row
is exactly where they are needed — so the platform response ships them alongside the rows."""
block = _ledger()
assert 'v-if="epFacts(e).length"' in block
facts = INDEX[INDEX.index("epFacts(e){") :][:900]
assert "c.note" in facts and "'limits'" in facts and "'pricing_url'" in facts
assert "this.platData.providers" in INDEX[INDEX.index("provFact(service, key){") :][:260]
def test_own_account_rows_are_labelled_and_distinct_from_scraper_rows():
"""An OAuth endpoint reads the account you connected; a scraper endpoint reads any handle. That
is the difference between two different products, so it gets a badge and a colour."""
assert """<span v-if="e.scope==='own_account'" class="chip own\"""" in INDEX
assert "?'team or your account':'your account'" in INDEX
assert "Reads the account YOU connect via OAuth, not arbitrary public accounts" in INDEX
assert """v-else-if="e.scope==='any_account'" class="chip any\"""" in INDEX
assert ".chip.own{" in INDEX
def test_a_metered_endpoint_with_no_published_rate_says_where_the_price_lives():
"""A bare "per success" reads as free, and an em-dash hides that we do know how it is billed."""
cost = INDEX[INDEX.index("costLabel(c){") :][:700]
assert "per '+per+' · price in provider dashboard'" in cost
def test_maximum_price_disclosure_is_rendered_as_up_to():
cost = INDEX[INDEX.index("costLabel(c){") :][:500]
assert "(c.display_prefix||'')+'$'" in cost
def test_the_ledger_rows_and_their_detail_live_in_the_platform_view():
assert _enclosing_views('v-for="r in sec.rows"') == ["platform"]
assert _enclosing_views('<tr v-if="platOpen[r.key]"') == ["platform"]
def test_no_ledger_cell_is_taken_out_of_the_table_layout():
"""A `<td>` with `display:flex` stops being a table-cell: the browser wraps it in an anonymous
cell that stretches to the row height while the flex box sizes to its content and keeps the
border. The separator under column one then lands a pixel above the one under column two — a
visible seam down the table, with the hover background split along it. Flex goes on a wrapper
INSIDE the cell, never on the cell."""
block = _ledger()
assert '<td class="lsum">' in block and '<div class="lsum-i">' in block
css = INDEX[INDEX.index(".lsum-i{") :][:200]
assert "display:flex" in css
# ...and no rule anywhere gives a ledger cell its own display.
for rule in ("td.lsum{", ".lsum{display", ".lprice{display", ".ledger td{display"):
assert rule not in INDEX, f"{rule} takes a ledger cell out of the table layout"
def test_the_row_pair_rides_a_template_inside_the_table():
"""A row and its expanded detail are two <tr>s, so they must be wrapped in a <template>, not a
<tbody> — a per-row <tbody> makes `tr:last-child` strip every row separator."""
block = _ledger()
table = block.index('<table class="ledger">')
assert block.index('<template v-for="r in sec.rows"') > table
assert "<tbody" not in block
def test_example_responses_are_fetched_only_when_their_tab_is_opened():
"""A platform can carry hundreds of endpoints; fetching every captured response with the page
would make the view cost more than the calls it describes. Opening the tab is the trigger, and
it fires once — a second visit to the tab must not re-fetch."""
fn = INDEX[INDEX.index("async loadExample(e){") :][:700]
assert "if(this.platEx[e.id]) return;" in fn, "loaded once, not on every tab switch"
assert "'/catalog/examples/'" in fn
assert "if(tab==='res') this.loadExample(e);" in INDEX[INDEX.index("setEpTab(e, tab){") :][:300]
def test_anonymous_catalog_access_is_runnable_and_never_claims_a_provider_key():
"""A verified public upstream route is a callable access tier. The Try drawer must not send it
through the missing-key branch or describe the absent provider credential as injected."""
drawer = INDEX[INDEX.index('v-if="epTry"') : INDEX.index("methods:{")]
assert "epTryAccess.tier==='anonymous'" in drawer
blocked = drawer[drawer.index('<div v-if="epTryAccess &&') :][:500]
assert "epTryAccess.tier!=='anonymous'" in blocked
assert "no provider key is needed" in drawer
assert "This verified public upstream route needs no provider key." in drawer
assert "free — no provider key ⓘ" in drawer
def test_activity_names_each_access_tier_without_calling_anonymous_a_team_key():
assert "{{servedOn(callView.credential_tier)}}" in INDEX
labels = INDEX[INDEX.index("servedOn(tier){") :][:350]
assert "anonymous:'public provider route (no key)'" in labels
assert "platform:'treg key'" in labels
assert "credential:'your key'" in labels
assert "tool:'your registered tool'" in labels
assert "'platform-overflow':'treg overflow'" in labels
def test_the_run_actions_lead_the_expansion_tab_bar():
"""The tab bar carries docs + the two run actions, visible the moment the expansion opens.
Try-it is the primary (ink-fill) CTA for a key/token provider — trying on treg's key is what most
visitors want — with the own-key path demoted to a secondary "Bring your own key". For an OAuth
provider treg can't serve on its own key, so Connect is the primary instead and Try-it is
secondary. The green Connected state replaces the connect button once an account exists.
Each action is ONE button whose handler forks on `publicCatalog` — signed out, all three open
the sign-in modal instead, because calling needs a team. The member half of every fork is what
is asserted below; it must keep its shape when someone edits the public half."""
block = _ledger()
# Sized to the whole action group, not a round number — the window has been outgrown once
# already (by the publicCatalog forks) and silently cut the last assertions out of range.
bar = block[block.index('<span class="ltabs-r">') :][:3400]
# Try-it: primary UNLESS the provider is OAuth
assert 'openEpTry(e)' in bar and ':class="{primary:!mkOauth(e.provider)}"' in bar
# OAuth → Connect is the ink-fill primary
assert 'v-else-if="mkOauth(e.provider)" class="btn sm primary"' in bar and "openProvider(e.provider)" in bar
assert "{{endpointConnectLabel(e)}}</button>" in bar
# key/token → own key is the secondary
assert 'v-else-if="mkKnown(e.provider)" class="btn sm"' in bar and ">Bring your own key</button>" in bar
assert 'v-if="catEndpointConnected(e)" class="chip go"' in bar and ">Connected</span>" in bar
assert 'v-if="e.docs_url"' in bar # ...docs sit up here too, not below the fold
assert ".ltabs-r .btn.primary{background:var(--inverse)" in INDEX
def test_try_it_post_snippets_carry_the_method_and_shell_safe_body():
"""The drawer must copy the request shown in Manual, not silently turn every endpoint into GET."""
block = INDEX[INDEX.index("epTryShellBody(){") : INDEX.index("epTrySetupLine(){")]
assert "replace(/'/g,\"'\\\"'\\\"'\")" in block
assert "if(method!=='GET') s+=` --method ${method}`" in block
assert "--data ${this.epTryShellBody}" in block
assert "curl -X ${method}" in block
assert '-H "Content-Type: application/json"' in block
def test_try_it_get_snippets_keep_query_and_auth_without_a_body():
"""GET stays explicit in curl, keeps query and org selection, and does not gain body options."""
block = INDEX[INDEX.index("epTryQuery(){") : INDEX.index("epTrySetupLine(){")]
assert "const q=this.epTryQuery" in block and "${q?'?'+q:''}" in block
assert "curl -X ${method}" in block
assert "if(this.sessionMode && this.activeSlugNow)" in block
assert block.count("method!=='GET' && this.epTryBody.trim()") == 2
def test_try_it_selects_registry_authorization_and_updates_every_call_surface():
start = INDEX.index('<!-- Try a MARKETPLACE endpoint right here.')
drawer = INDEX[start : INDEX.index('<!-- access reminder toast:', start)]
assert 'v-model="epTryAuthMethod"' in drawer
assert 'v-if="epTryShowAuthSelector"' in drawer
assert 'class="field auth-method-field"' in drawer
assert "authorizationMethodLabel(epTry.provider,m)" in drawer
assert "m==='instagram-login'" not in drawer
logic = INDEX[INDEX.index("epTryVisibleParams(){") : INDEX.index("tryExamples(){")]
assert "--authorization-method ${this.epTryAuthMethod}" in logic
assert 'X-Treg-Authorization-Method: ${this.epTryAuthMethod}' in logic
runner = INDEX[INDEX.index("openEpTry(e){") : INDEX.index("async runTry(){")]
assert "this.epTryAuthMethod=e.authorization_method" in runner
assert "opts.headers['X-Treg-Authorization-Method']=this.epTryAuthMethod" in runner
assert "(this.epTry.authorization_paths||{})[this.epTryAuthMethod]||this.epTry.path" in INDEX
def test_instagram_try_it_only_shows_method_picker_when_both_grants_are_connected():
logic = INDEX[INDEX.index("epTryAuthMethods(){") : INDEX.index("epTryVisibleParams(){")]
assert "a.tier==='tool'||a.tier==='credential'" in logic
assert "this.epTryAuthMethods.length>1 && this.epTryConnectedMethods.length>1" in logic
policy = INDEX[INDEX.index("async loadEpTryAccessPolicy(){") : INDEX.index("async runEpTry(){")]
assert "if(connected.length===1) this.epTryAuthMethod=connected[0]" in policy
assert "else this.epTryAuthMethod=e.authorization_method||methods[0]||''" in policy
def test_multi_method_picker_uses_only_available_methods():
picker = INDEX[INDEX.index("startConnect(p, conn){") : INDEX.index("async continueMethod(){")]
assert "const available=methods.filter(method=>method.configured)" in picker
def test_catalog_connection_badges_require_an_endpoint_compatible_grant():
logic = INDEX[INDEX.index("catConnected(service){") : INDEX.index("catMetered(service){")]
assert "endpointAuthMethods(e)" in logic
assert "c.provider===e.provider && methods.includes(c.authorization_method)" in logic
assert "endpointConnectLabel(e)" in logic
drawer = INDEX[INDEX.index("<!-- MANUAL — the live test form -->") : INDEX.index("<!-- access reminder toast:")]
assert "epTryAccess.connect_command" not in drawer
assert "openProvider(epTry.provider); closeEpTry()" in drawer
assert "epTryAccess.action_label||endpointConnectLabel(epTry)" in drawer
def test_provider_page_links_into_the_catalog():
"""Navigation runs both ways: an integration page names the platforms its catalog covers."""
assert _enclosing_views('v-for="pl in mkPlatforms"') == ["provider"]
# --- code surfaces follow the theme -------------------------------------------------------------
def test_the_syntax_ramp_is_themed_not_hard_coded_for_dark():
"""Light mode painted the code BLOCK light (the generic `[data-theme=light] pre` rule outranks
`.lc-codewrap pre`) while the ramp stayed drawn for a dark one — a near-white command on a
near-white background. One ramp, as variables, with a light set that clears 4.5:1."""
for page in (INDEX, TUTORIAL):
for var in ("--sx-cmd", "--sx-var", "--sx-str", "--sx-flag", "--sx-cmt"):
assert page.count(var) >= 3, f"{var} needs a dark value, a light value and a use"
# No syntax rule may carry a hex literal: a literal is one theme's value, and three earlier
# generations of this ramp each left one behind (#5f9ea0, #19D0E8, #e0703f, #f0f0ee…).
rule = re.compile(r"(?m)^\s*(\.(?:hl|s)-[\w-]+[^{}\n]*)\{([^}]*)\}")
for page, name in ((INDEX, "index.html"), (TUTORIAL, "tutorial.html")):
for sel, body in rule.findall(page):
assert "#" not in body, f"{name}: {sel.strip()} hard-codes {body} — use the --sx-* ramp"
assert ".hl-cmd,.hl-kw,.s-kw{color:var(--sx-cmd)" in INDEX
assert "--sx-cmd:#1a1a1a" in INDEX and "--sx-cmd:#f0f0ee" in INDEX
def test_a_code_block_and_its_ink_come_from_the_same_theme():
"""The surface is a token too, so a block and the text on it can never again be specified by
different generations of the sheet. The inner <pre> must out-specify BOTH generic `pre` rules —
that mismatch is what put a light panel inside a dark wrapper."""
assert "--code-bg:#161518" in INDEX and "--code-bg:#f4f4f1" in INDEX
css = INDEX[INDEX.index("RESTYLE — 3.8 code surfaces") :]
assert ".term,.lc-codewrap," in css and "background:var(--code-bg);color:var(--code-ink)" in css
assert ":root[data-theme=light] .lc-codewrap pre" in css
assert ":root:not([data-theme=light]) .lc-codewrap pre" in css
# ...and the copy button is not a dark pill on a light block
assert ".lc-cp{background:var(--code-btn);color:var(--code-ink)" in css
def test_muted_output_panes_use_the_ramps_comment_grey():
"""`--muted` is 3.7:1 on the light code surface — fine for a caption, not for the pane that
shows what a command printed."""
assert "pre.term.out{color:var(--sx-cmt)}" in INDEX
assert "pre.out{color:var(--sx-cmt)}" in TUTORIAL
def test_dashboard_delete_org_sends_the_confirmation_slug():
"""DELETE /orgs/{id} refuses without `?confirm=<slug>` (it is irreversible and reachable by path
normalization from any deeper org route). The dashboard already makes the human type the slug —
if this ever stops being sent, Delete org silently 422s for every dashboard user."""
assert "'/orgs/'+this.activeOrgId+'?confirm='" in INDEX
# --- referrals (view==='referrals') -----------------------------------------------------------
def test_referrals_is_a_top_level_view():
"""Nested inside another view it would render nowhere, and the nav button would look dead —
the exact silent failure the dialog checks above exist for."""
assert _enclosing_views("<template v-if=\"view==='referrals'\">") == []
def test_referrals_is_registered_in_BOTH_view_whitelists():
"""`go('referrals')` works on click regardless; these two lists are what make it survive a
RELOAD and a BACK button. One is `viewFromHash` (fresh load / deep link), the other is the
popstate handler. Missing either is invisible until someone refreshes the page."""
assert INDEX.count("'connections','referrals'") == 2
def test_referral_page_shows_why_a_referral_paid_nothing():
""""I referred someone and got nothing" is the ticket this program generates. `capped` and
`rejected` must render a reason on the page rather than an empty cell."""
assert "refStatus(r)" in INDEX
assert "Over your limit" in INDEX and "Not eligible" in INDEX
def test_the_referral_link_is_not_gated_behind_paying_us():
"""Every signed-in person gets a link, free tier included — they are most of the userbase on a
product pitched as "$1.00 free, no card", and the likeliest to tell a friend. The `!eligible`
branch survives only for the degenerate case of having no team to pay a reward into, so it must
NOT ask anyone to add funds."""
assert 'v-if="!ref.eligible"' in INDEX
assert "Create a team to unlock your link" in INDEX
assert "Add funds once to unlock your link" not in INDEX
def _referrals_view() -> str:
"""The Referrals view block ONLY. Anchored on the template tag, not the bare `view==='referrals'`
string — the nav button matches that first and would slice from the sidebar."""
start = INDEX.index("<template v-if=\"view==='referrals'\">")
end = INDEX.index("<template v-if=\"view==='help'\">", start)
return INDEX[start:end]
def test_referral_stat_tiles_use_the_sheets_own_class_names():
"""`.stat` styles `.n` (the figure, 26px accent) and `.l` (the uppercase caption) — and nothing
else. A hand-rolled `.k`/`.v` pair renders as two lines of unstyled body text that still *look*
like content, so nothing errors and the bug ships. Order matters too: figure first."""
block = _referrals_view()
assert 'class="statgrid"' in block
assert block.count('<div class="n">') == 3 and block.count('<div class="l">') == 3
assert 'class="k"' not in block and 'class="v"' not in block
assert block.index('<div class="n">') < block.index('<div class="l">')
def test_the_billing_page_names_the_bonus_on_the_qualifying_presets():
"""A referred team decides HOW MUCH to add on this screen, and the first preset ($5) is below the
minimum. A note alone is not enough — the amount is chosen at the buttons, so the qualifying ones
have to say so themselves."""
at = INDEX.index('<div class="fundgrid"')
grid = INDEX[at : INDEX.index("</div>", INDEX.index("</button>", at))]
assert "refPresetBonus(p)" in grid, "presets must mark which ones earn the bonus"
assert "billing.referral_offer" in INDEX
def test_the_referral_offer_is_hidden_from_teams_that_were_not_referred():
"""`v-if` on the offer object, so a team that arrived on its own sees the billing page exactly as
it was before this shipped."""
assert 'v-if="billing.referral_offer"' in INDEX
def test_the_billing_prompt_renders_the_masked_referrer_never_a_raw_one():
"""The template must read `referrer_masked`. Reaching for any full-address field here would
publish an influencer's email to every stranger who signs up through their public link."""
at = INDEX.index("You were invited")
block = INDEX[at : INDEX.index("</div>", at)]
assert "billing.referral_offer.referrer_masked" in block
assert "referrer_email" not in INDEX
def test_the_referral_preset_helper_null_guards_before_reading_the_offer():
"""`referral_offer` is null for every team that was NOT referred — most of them. Reading through
it throws inside a render, and a render error in Vue blanks the entire dashboard, not just the
row. This shipped once, as a blank billing page, when a guard clause was folded into a larger
expression and then edited away."""
at = INDEX.index("refPresetBonus(usd)")
body = INDEX[at : INDEX.index("},", at)]
assert "if(!o) return 0;" in body
assert body.index("if(!o) return 0;") < body.index("o.remaining_micro")
def test_the_topup_modal_offers_four_presets_plus_other_and_an_auto_toggle():
"""The amount, its bonus and auto top-up are one decision in one modal. The toggle's label is the
mandate text and names the amount being chosen (`topupUsd`), never a config default the payer
did not see; consent is posted BEFORE the Checkout that saves the card."""
at = INDEX.index('v-if="topupOpen&&billing"')
modal = INDEX[at : INDEX.index('v-if="capAsk"', at)]
assert 'v-for="p in billing.topup.presets"' in modal
assert "pickOther()" in modal and 'topupPick===\'other\'' in modal
assert 'v-model="topupAuto"' in modal
assert "I authorize treg to charge my saved card <b>${{autoAmount}}</b>" in modal
assert "Processing fee" not in modal, "treg charges no fee; do not copy one from elsewhere"
js = INDEX[INDEX.index("async payTopup("):]
js = js[: js.index("autoToggled(")]
assert js.index("/billing/autotopup") < js.index("/billing/topup"), "consent must precede Checkout"
assert "consent:true" in js and "setup_url:false" in js
def test_the_topup_modal_defaults_auto_on_only_without_a_mandate():
js = INDEX[INDEX.index("openTopup(){"):]
js = js[: js.index("tierBonus(")]
assert "this.topupAuto=!(this.billing.autotopup.enabled||this.billing.autotopup.consented_at)" in js
def test_api_key_dashboard_uses_server_permissions_and_safe_assignment_metadata():
start = INDEX.index('v-if="orgTab===\'keys\'"')
block = INDEX[start:INDEX.index("<!-- PROJECTS tab -->", start)]
menu = INDEX[INDEX.index('v-if="keyMenu"'):INDEX.index('v-if="keyConfirm"')]
assert "group.name" in block and "group.identity" in block and "group.type" in block
assert "k.created_at?when(k.created_at)" in block
assert '<table class="key-table"><tr><th>Key</th><th>Status</th><th>Created</th><th>Last used</th><th></th></tr>' in block
assert "<th>Created by</th>" not in block
assert "k.can_rotate" in block
for permission in ("can_rename", "can_disable", "can_enable", "can_revoke", "can_hide"):
assert f"keyMenu.key.{permission}" in menu
assert "{{maskedKey(k)}}" in block
assert "k.safe_prefix+'••••••••'" in INDEX
assert "k.kind==='legacy_human'?'prefix unavailable — older key':'prefix unavailable'" in INDEX
assert "newApiKey.secret" in block
assert "apiKeyGroups(){" in INDEX and "assigned_name||row.identity" in INDEX
assert "humanByIdentity[(row.created_by||'').toLowerCase()]" in INDEX
assert "owner.rows.push(row)" in INDEX
assert "group.type==='human' && k.assigned_type==='agent'" in block
assert "↳" in block and "?k.assigned_name:k.name" in block
assert 'class="key-meta mono"' in block
assert "requestKeyAction(k,'rotate')" in block
assert "toggleKeyMenu(k,$event)" in block
assert 'aria-haspopup="menu"' in block
assert "The current key will stop working immediately." in INDEX
assert "Default key rotated — copy the new key" in block
assert "This team-specific key remains revealable on Getting Started." in block
assert "CLI users can run <code>treg login</code> again to save the new key." in block
assert "was removed from this team, and all its keys were revoked" in INDEX
assert "newApiKey.assigned_type==='agent'" in block
assert "I’ve updated '+newApiKey.assigned_name" in block
assert "Replace <code>TREG_TOKEN</code> in every environment" in block
default_rotate = INDEX[INDEX.index("if(r.secret && k.kind==='default_human')") :]
default_rotate = default_rotate[: default_rotate.index("else if(r.secret)")]
assert "this.newApiKey={...r,rotated:true}" in default_rotate
def test_api_key_secondary_actions_use_a_custom_menu_and_impact_modal():
assert 'class="key-actions-menu" role="menu"' in INDEX
assert 'role="menuitem"' in INDEX
assert "if(['rotate','disable','revoke','hide'].includes(action))" in INDEX
assert 'v-if="keyConfirm" class="scrim" role="dialog" aria-modal="true"' in INDEX
assert "Calls using this key will stop until you enable it again." in INDEX
assert "Historical Activity will remain available." in INDEX
assert "if(this.keyMenu)this.keyMenu=null" in INDEX
confirm = INDEX[INDEX.index('v-if="keyConfirm"'):INDEX.index('<!-- REGISTER SKILL', INDEX.index('v-if="keyConfirm"'))]
assert '<h3 id="key-confirm-title" style="margin:0">' in confirm
assert 'aria-label="Close"' not in confirm
def test_empty_api_key_name_uses_field_validation_without_a_banner():
assert ":class=\"{'field-invalid':keyNameInvalid}\"" in INDEX
assert ':aria-invalid="keyNameInvalid"' in INDEX
assert '@input="keyNameInvalid=false"' in INDEX
create = INDEX[INDEX.index("async createApiKey(){"):INDEX.index("async renameApiKey(")]
assert "if(!name){ this.keyErr=''; this.keyNameInvalid=true; return; }" in create
assert "this.keyErr='Enter a key name.'" not in create
def test_member_agent_actions_have_spacing_without_hiding_actions():
at = INDEX.index('@click="showAgentSetup(m)"')
actions = INDEX[at - 80:at + 900]
assert 'class="row-actions"' in actions
assert ">Setup</button>" in actions
assert "rotateAgent(m)" in actions
assert "revokeAgent(m)" in actions
def test_agent_lifecycle_guidance_is_transient_and_action_specific():
start = INDEX.index("v-if=\"canAdmin && orgTab==='members'\"")
block = INDEX[start:INDEX.index("<!-- API KEYS tab", start)]
assert "Its current key will stop immediately." in block
assert "This removes the agent and revokes all its keys." in block
assert "I’ve updated '+newAgent.name" in block
assert "Anyone holding it can act as {{newAgent.name}}" in block
assert "Its key is unchanged, and the new tool and project permissions apply immediately." in INDEX
def test_agent_key_revoke_copy_matches_membership_removal():
assert "This removes the agent from the team and revokes all its keys." in INDEX
assert "was removed from this team, and all its keys were revoked." in INDEX
assert "if(r.agent_revoked) await this.loadOrgAdmin()" in INDEX
assert "remains on Members, but it cannot authenticate" not in INDEX
def test_activity_shows_agent_name_with_owner_badge_not_internal_identity():
assert "{{activityWho(a)}}" in INDEX
assert "owner: {{activityOwner(a)}}" in INDEX
assert "activityAgentKey(a)" in INDEX
assert "k.assigned_type==='agent'" in INDEX
assert "k.assigned_name||this.short(k.identity)" in INDEX
assert "if(!this.apiKeys.length)await this.loadApiKeys()" in INDEX
assert "{{a.api_key_name}}<span v-if=\"a.api_key_prefix\"" in INDEX
def test_activity_feed_marks_cached_calls_without_changing_the_charge():
feed = INDEX[INDEX.index('<template v-if="actTab===\'feed\'">') :]
start = feed.index('<tr v-for="a in activityShown"')
row = feed[start : feed.index("</tr>", start)]
assert "{{a.cost!=null?money(a.cost):'—'}}" in row
assert 'v-if="a.cached" class="chip cached"' in row
assert "Served from treg's archive instead of calling the provider." in row
assert row.index("{{a.cost!=null?money(a.cost):'—'}}") < row.index('v-if="a.cached"')
assert ".chip.cached{" in INDEX and "background:var(--panel2)" in INDEX
def test_activity_feed_summarizes_cached_calls_in_the_loaded_window():
assert 'v-if="activityCachedCount" class="sub"' in INDEX
assert "{{activityCachedCount}} of {{activityCallCount}} loaded" in INDEX
assert "activityCallCount(){ return this.activityRows.filter(a=>a.kind==='call').length; }" in INDEX
assert "activityCachedCount(){ return this.activityRows.filter(a=>a.kind==='call' && a.cached).length; }" in INDEX
def test_agent_creation_requires_explicit_tool_scope_and_default_key_has_disabled_state():
assert 'value="all" v-model="agentAccessMode"' in INDEX
assert 'value="choose" v-model="agentAccessMode"' in INDEX
assert "body.tool_access=this.agentAccessMode==='all' ? null" in INDEX
assert "agentBusy||!agentAccessMode" in INDEX
assert "defaultKeyState==='disabled'" in INDEX
assert "Additional and agent keys are random secrets shown only once" in INDEX
assert "This team's current Getting Started token will stop working immediately." in INDEX