mirror of
https://github.com/superdesigndev/treg.git
synced 2026-10-02 03:24:35 +08:00
test(web): remove template-shape assertions and unused logo
This commit is contained in:
@@ -491,7 +491,6 @@ Regenerate via `scripts/build-map.py`.
|
||||
| `tests/test_catalog_api.py` | architecture/catalog.md |
|
||||
| `tests/test_catalog_validate.py` | architecture/catalog.md |
|
||||
| `tests/test_cli_key_compatibility.py` | interface/cli.md |
|
||||
| `tests/test_dashboard_markup.py` | architecture/auth-secrets.md |
|
||||
| `tests/test_dashboard_rollout.py` | interface/dashboard.md |
|
||||
| `tests/test_dataforseo_constraints.py` | architecture/catalog.md |
|
||||
| `tests/test_enrich_arena.py` | interface/enrich-arena.md |
|
||||
@@ -533,7 +532,7 @@ Regenerate via `scripts/build-map.py`.
|
||||
|---|---|
|
||||
| `architecture/ads-conversions.md` | `adsconv.py`, `signup.py`, `adtrack.js`, `gtag.js` |
|
||||
| `architecture/archive.md` | `archive.py`, `hunter.yaml`, `results.py`, `0031_archive_result_admission.py`, `test_cache_result_admission.py`, `archive_bodies.py`, `config.py`, `object_store.py`, `0032_archive_body_storage.py`, `test_archive_r2.py`, `fake_object_store.py`, `smoke_archive_r2.py`, `0002_archive_tables.py`, `0003_callrecord_cached.py`, `0004_archivekey_request_shape.py`, `0011_callrecord_archive_link.py`, `service.py`, `settle.py`, `0039_archive_own_key_and_repeat_pricing.py`, `backfill_call_archive_links.py`, `api.py`, `bootstrap.py`, `admin.py`, `asynctasks.py` |
|
||||
| `architecture/auth-secrets.md` | `injectors.py`, `ssrf.py`, `crypto.py`, `oauth.py`, `__init__.py`, `authorization.py`, `oauth_flow.py`, `refresh.py`, `oauth_exchange.py`, `oauth_refresh.py`, `oauth_providers.py`, `session.js`, `keys.js`, `TeamPage.vue`, `health.py`, `connect.py`, `connections.py`, `resources.py`, `__init__.py`, `bindings.py`, `bundles.py`, `api_keys.py`, `access.py`, `api_keys.py`, `test_api_keys.py`, `test_oauth_refresh.py`, `test_financialdatasets.py`, `test_key_providers.py`, `test_dashboard_markup.py`, `config.py` |
|
||||
| `architecture/auth-secrets.md` | `injectors.py`, `ssrf.py`, `crypto.py`, `oauth.py`, `__init__.py`, `authorization.py`, `oauth_flow.py`, `refresh.py`, `oauth_exchange.py`, `oauth_refresh.py`, `oauth_providers.py`, `session.js`, `keys.js`, `TeamPage.vue`, `health.py`, `connect.py`, `connections.py`, `resources.py`, `__init__.py`, `bindings.py`, `bundles.py`, `api_keys.py`, `access.py`, `api_keys.py`, `test_api_keys.py`, `test_oauth_refresh.py`, `test_financialdatasets.py`, `test_key_providers.py`, `config.py` |
|
||||
| `architecture/catalog.md` | `fishaudio.yaml`, `fishaudio.tts.s2-1-pro.json`, `fishaudio.voices.create.json`, `fishaudio.voices.discover.json`, `provider_resources.py`, `provider_resources.py`, `provider_resources.py`, `tavily.yaml`, `exa.yaml`, `anyapi.extended.yaml`, `trestleiq.yaml`, `financialdatasets.yaml`, `test_financialdatasets.py`, `quickenrich.yaml`, `influencersclub.yaml`, `quickenrich.extended.yaml`, `trykitt.yaml`, `contracts.yaml`, `millionverifier.yaml`, `adapters.yaml`, `prospeo.yaml`, `test_route_cost_ceiling.py`, `tomba.yaml`, `__init__.py`, `contracts.py`, `paths.py`, `plan.py`, `synthetic.py`, `route.py`, `test_routing.py`, `catalog-drift.yml`, `catalog_drift.py`, `catalog_ingest.py`, `catalog_validate.py`, `aliases.yaml`, `fx.yaml`, `cloro.yaml`, `aviato.yaml`, `crustdata.yaml`, `google-search-console.yaml`, `google-search-console.extended.yaml`, `google-tag-manager.yaml`, `google-tag-manager.extended.yaml`, `instagram.yaml`, `instagram.extended.yaml`, `justoneapi.extended.yaml`, `minimax.yaml`, `apify.yaml`, `brightdata.yaml`, `companyenrich.yaml`, `oceanio.yaml`, `akta.extended.yaml`, `dataforseo.yaml`, `dataforseo.extended.yaml`, `test_dataforseo_constraints.py`, `scrapecreators.yaml`, `scrapecreators.extended.yaml`, `serpapi.yaml`, `serpapi.extended.yaml`, `diffbot.yaml`, `diffbot.extended.yaml`, `tikhub.extended.yaml`, `lusha.extended.yaml`, `openrouter.yaml`, `openrouter.extended.yaml`, `replicate.yaml`, `replicate.extended.yaml`, `reapi.yaml`, `piapi.yaml`, `__init__.py`, `store.py`, `hunter.yaml`, `mcp.py`, `settlement.py`, `stats.py`, `catalog_observations.py`, `catalog_stats.py`, `0038_endpoint_day_stats.py`, `catalog.py`, `test_aigc_pr_b.py`, `test_catalog_api.py`, `test_catalog_validate.py` |
|
||||
| `architecture/composition.md` | `bootstrap.py`, `bootstrap_handlers.py`, `bootstrap_http.py`, `call_surface.py`, `connect.py`, `mcp_oauth.py`, `session.py`, `admin.py`, `auth.py`, `billing.py`, `call.py`, `connections.py`, `onboard.py`, `orgs.py`, `resources.py`, `referrals.py`, `web.py`, `dump_surface.py`, `test_app_roles.py` |
|
||||
| `architecture/data-model.md` | `0042_pinned_read_scope.py`, `alembic.ini`, `env.py`, `0001_baseline_current_schema.py`, `0002_archive_tables.py`, `0003_callrecord_cached.py`, `0004_archivekey_request_shape.py`, `0005_capacity_policy_snapshot.py`, `0006_overflow_route.py`, `0007_overflow_spend.py`, `0008_org_platform_overflow_disabled.py`, `0009_callrecord_hit.py`, `0017_async_task_record.py`, `0018_async_resource_ownership.py`, `0019_async_poll_failures.py`, `0020_callrecord_created_at_indexes.py`, `0021_ledgerentry_org_created_at_index.py`, `0022_org_spent_today_counter.py`, `0023_callrecord_org_user_created_at_index.py`, `0024_membership_calls_today_counter.py`, `0027_enrich_arena.py`, `0028_arena_insights.py`, `0029_arena_verification_snapshot.py`, `0011_callrecord_archive_link.py`, `0015_idempotentcall_membership_cascade.py`, `0034_managed_api_keys.py`, `0035_default_key_generation.py`, `0036_activity_key_indexes.py`, `0038_endpoint_day_stats.py`, `maintenance.py`, `sitetrack.js`, `models.py`, `0031_archive_result_admission.py`, `0032_archive_body_storage.py`, `0039_archive_own_key_and_repeat_pricing.py`, `0043_provider_resources.py`, `provider_resources.py`, `provider_resources.py`, `0033_signup_promo_eligibility.py`, `0041_searchlog.py`, `timeutil.py`, `db.py`, `referrals.py`, `audit.py`, `analytics.py`, `bootstrap_handlers.py`, `ratestore.py`, `auth.py`, `test_postgres_reset.py`, `test_alembic_expand_safety.py`, `test_api_keys.py` |
|
||||
|
||||
@@ -30,7 +30,6 @@ sources:
|
||||
- tests/test_oauth_refresh.py
|
||||
- tests/test_financialdatasets.py
|
||||
- tests/test_key_providers.py
|
||||
- tests/test_dashboard_markup.py
|
||||
- src/treg/config.py
|
||||
related:
|
||||
- architecture/proxy-model.md
|
||||
|
||||
@@ -988,32 +988,10 @@ line rather than an empty table. `.prm-t` explicitly resets the global `table`/`
|
||||
background, border, radius, filled header bar), which otherwise reads as a stray highlight inside the
|
||||
`.prm` box and clips the first column against the table's own border. Navigation runs both ways: an integration page carries a
|
||||
**Covered in the catalog** chip row (`mkPlatforms`) into the platform pages, and each platform page
|
||||
header links back out to the providers that serve it (`platProviders`). `tests/test_dashboard_markup.py`
|
||||
pins this provider navigation to the platform response itself; it does not disappear while the
|
||||
separate OAuth connection registry is still loading. The same test
|
||||
locks the structure (top-level view, the row/detail `<template>` pair inside the `.ttable`, the
|
||||
`v-if`'d tab bar and its `platform` fallback, the derived tab list and category order, tiles wearing the
|
||||
platform's own logo with the generated-initial fallback, the `Platform` tab still carrying the provider
|
||||
shelves and their connect flow, the category heading being a real heading, the card's four regions
|
||||
(mark + name + category, the connected-state corner, the count/price footer — and NO summary
|
||||
paragraph, with the name wrapping instead of ellipsising), the
|
||||
unified-USD price rule (server `usd`, no local FX constant, native suffix, `{}`-normalisation,
|
||||
`quota_rows` excluded first) and its unmetered-OAuth-only "free with your account" branch,
|
||||
the runnable green on all three of its surfaces, the stacked platform header, the always-both
|
||||
provider/endpoint counts, the credit-priced fallback ranking ahead of "price not published",
|
||||
the parameters block sitting before the example
|
||||
toggle with its query/path/body order and its no-params fallback,
|
||||
the featured-shelf split and its two guards, the ledger being one table
|
||||
with `other`-last domain sections that need a visible row to exist, the single platform-wide Actions
|
||||
section holding every management endpoint, and merged-before-single rows, a row title that is a name or a clipped
|
||||
summary and never a paragraph, the collapsed merged row's non-wrapping three-pills-and-a-count strip, its pills being per-provider,
|
||||
sorted cheapest-first and priced only when the price is a real number,
|
||||
the two-level expansion (provider sub-rows, then one detail block shared with the single-row path), the
|
||||
long metered phrasing never reaching a collapsed line, the filter bar's three controls and their chip
|
||||
counts, both sticky layers and the overflow rules that let them stick, the two-tab expansion (Request first, no response tab at
|
||||
all without an example, both panes capped at 320px), the prominent Connect in the tab bar with its
|
||||
Connected state, the `treg call` line and the provider facts, the cross-currency cheapest rules, the credit-priced "see provider" fallback, the scope
|
||||
chips, and lazy examples). `tests/test_catalog_api.py` locks the server half: the section order, the
|
||||
header links back out to the providers that serve it (`platProviders`). Provider navigation derives
|
||||
from the platform response itself, so it remains available while the separate OAuth connection
|
||||
registry loads. Browser tests in `frontend/e2e/` cover navigation and interactions; they do not pin
|
||||
CSS classes or template source spelling. `tests/test_catalog_api.py` locks the server half: the section order, the
|
||||
merged/single split, the domain resolution ladder, and a delivery-mode path segment never becoming a
|
||||
subject.
|
||||
|
||||
|
||||
@@ -242,11 +242,8 @@ on a public shelf renders as its bare slug and the whole action chain collapses
|
||||
`mkOauth` has no public fallback — the open response carries no `auth_kind` — so the public branch
|
||||
offers BYOK, which is true for every provider, rather than guessing Connect.
|
||||
|
||||
**Each action is ONE button whose handler forks on `publicCatalog`**, not a duplicated public
|
||||
template. `tests/test_dashboard_markup.py` asserts the member chain's exact shape
|
||||
(`v-else-if="mkOauth(e.provider)" class="btn sm primary"`, `openProvider(e.provider)`, …), and a
|
||||
fork keeps those substrings intact where a parallel branch drifts. That test reads a fixed-size
|
||||
window of the markup and has already been outgrown once by these forks.
|
||||
Each catalog action chooses sign-in or the member flow based on `publicCatalog`. Browser coverage
|
||||
in `frontend/e2e/dashboard.spec.ts` checks public catalog navigation and reachable sign-in.
|
||||
|
||||
### The no-JS fallback
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ npm --prefix frontend run test:e2e
|
||||
uv build
|
||||
```
|
||||
|
||||
Test behavior, not template source strings, CSS class names or component arrangement. Keep transport
|
||||
unit tests and HTTP rollout/packaging checks; use browser tests for user interactions.
|
||||
|
||||
Browser tests start their own server on :18791 with a disposable database and no dotenv file.
|
||||
They use full Chromium in headless mode so back/forward cache restoration is exercised.
|
||||
`PLAYWRIGHT_CHANNEL=chrome` can use an installed Chrome for local checks.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 306 KiB |
@@ -1,34 +0,0 @@
|
||||
"""Read the authored dashboard for existing source-level regression checks.
|
||||
|
||||
Component templates are expanded at their actual mount sites, preserving conditional ancestry.
|
||||
Runtime navigation and event bindings are covered separately by the browser suite.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
FRONTEND = Path(__file__).resolve().parents[1] / "frontend" / "src"
|
||||
|
||||
|
||||
def template_source(path: Path) -> str:
|
||||
source = path.read_text()
|
||||
template = source.split("<template>", 1)[1].rsplit("</template>", 1)[0]
|
||||
imports = re.findall(r"import (\w+) from ['\"](.+?\.vue)['\"]", source)
|
||||
for name, relative in imports:
|
||||
child = template_source((path.parent / relative).resolve())
|
||||
template = re.sub(
|
||||
rf"<{name}\b([^>]*?)/>",
|
||||
lambda match: "<template" + (" " + match[1].strip() if match[1].strip() else "") + ">" + child + "</template>",
|
||||
template,
|
||||
)
|
||||
return template
|
||||
|
||||
|
||||
def dashboard_source() -> str:
|
||||
state = FRONTEND / "state"
|
||||
computed = "\n".join(p.read_text() for p in sorted(state.glob("*Computed.js")))
|
||||
methods = "\n".join(p.read_text() for p in sorted(state.glob("*.js")) if not p.stem.endswith("Computed"))
|
||||
return (
|
||||
(FRONTEND / "styles/base.css").read_text()
|
||||
+ template_source(FRONTEND / "App.vue")
|
||||
+ "\ncomputed:{\n" + computed + "\nmethods:{\n" + methods
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1009,11 +1009,6 @@ async def test_arena_and_dashboard_share_setup_components(clients):
|
||||
page = (await clients.get('/enrich-arena')).text
|
||||
dashboard = (await clients.get('/app')).text
|
||||
assert '/agent-setup.js' in page and '/agent-setup.js' in dashboard
|
||||
from dashboard_source import FRONTEND
|
||||
assert 'treg-setup-instructions' in page
|
||||
assert 'treg-setup-instructions' in (FRONTEND / 'dialogs/WelcomeDialog.vue').read_text()
|
||||
assert "app.component('TregSetupInstructions', setup.SetupInstructions!)" in (FRONTEND / 'main.ts').read_text()
|
||||
assert 'Setup treg in' in page and 'ref="setupDialog"' in page
|
||||
|
||||
|
||||
def test_discovery_public_cohorts_keep_all_requested_constraints():
|
||||
|
||||
+3
-10
@@ -47,17 +47,10 @@ async def test_auth_me_user_hash_is_hmac_of_the_email(clients, monkeypatch):
|
||||
assert "s3cret" not in r.text # the secret itself never leaves the server
|
||||
|
||||
|
||||
def test_pages_gate_on_meta_app_id():
|
||||
from dashboard_source import FRONTEND
|
||||
assert "intercom_app_id" in (FRONTEND / "state/analytics.js").read_text()
|
||||
# each Intercom-bearing page keys its loader off /meta's intercom_app_id (empty = inert)
|
||||
for page in ("landing.html", "support.html"):
|
||||
assert "intercom_app_id" in (WEB / page).read_text(), page
|
||||
|
||||
|
||||
def test_no_hardcoded_workspace_id_anywhere():
|
||||
# the only allowed form of the widget URL is the config-driven concatenation
|
||||
pat = re.compile(r"widget\.intercom\.io/widget/(?!'\+app)")
|
||||
for f in WEB.rglob("*"):
|
||||
if "dashboard" not in f.relative_to(WEB).parts and f.is_file() and f.suffix in {".html", ".js", ".md", ".txt"}:
|
||||
sources = [*WEB.rglob("*"), *(WEB.parents[2] / "frontend" / "src").rglob("*")]
|
||||
for f in sources:
|
||||
if "dashboard" not in f.parts and f.is_file() and f.suffix in {".html", ".js", ".md", ".txt"}:
|
||||
assert not pat.search(f.read_text()), f"hardcoded Intercom workspace id in {f.name}"
|
||||
|
||||
@@ -347,55 +347,6 @@ def test_no_shelf_is_published_that_the_app_grid_hides():
|
||||
"publish /catalog/<slug> for each while the app's tile grid hides them")
|
||||
|
||||
|
||||
# -------------------------------------------------------------------- public-mode chrome & CTAs
|
||||
# Markup assertions rather than behaviour: these live in index.html's Vue template, which the test
|
||||
# suite reads as text (see tests/test_dashboard_markup.py). Both were reported from the browser.
|
||||
|
||||
def _spa() -> str:
|
||||
from dashboard_source import dashboard_source
|
||||
return dashboard_source()
|
||||
|
||||
|
||||
def test_public_catalog_drops_the_workspace_chrome():
|
||||
"""A catalog visitor is reading a website, not operating an app. The org switcher, the global
|
||||
tool search and the member nav are furniture for a job they have not started."""
|
||||
spa = _spa()
|
||||
assert '<template v-if="publicCatalog">' in spa # marketing nav instead
|
||||
member_header = '<header class="rd-top" >'
|
||||
assert member_header in spa # app bar only for members
|
||||
header = spa.split(member_header, 1)[1].split('</header>', 1)[0]
|
||||
assert 'class="orgblock"' in header and 'class="rd-navs"' in header
|
||||
assert 'v-if="!publicCatalog && (view===\'tools\'||view===\'resources\'||view===\'connections\')"' in spa
|
||||
assert 'v-if="authed && !publicCatalog" class="rd-referral"' in spa
|
||||
assert '.layout.solo{grid-template-columns:minmax(0,1fr)}' in spa # main spans the full width
|
||||
|
||||
|
||||
def test_no_public_cta_navigates_to_a_page_that_bounces():
|
||||
"""/app sends a logged-out visitor straight back to the landing (`location.replace('/')`), so a
|
||||
CTA pointing there is a dead end that loses the page they were reading. Every one of them opens
|
||||
the sign-in modal in place instead."""
|
||||
spa = _spa()
|
||||
assert "location.href='/app'" not in spa
|
||||
assert spa.count("publicCatalog ? openSignin()") >= 5 # try-it, connect, byok ×3, chips
|
||||
|
||||
|
||||
def test_the_signin_modal_is_reachable_from_public_mode():
|
||||
"""It used to live inside the logged-out landing branch, which public mode does not render —
|
||||
so there was nothing for a CTA to open."""
|
||||
spa = _spa()
|
||||
lp = spa.index('class="lp"')
|
||||
modal = spa.index('<div class="lc-scrim"')
|
||||
shell = spa.index("<template v-else>")
|
||||
assert not (lp < modal < shell), "the modal is trapped inside the logged-out landing branch"
|
||||
|
||||
|
||||
def test_the_modal_does_not_talk_about_a_sandbox_on_the_catalog():
|
||||
"""Default copy is the sandbox's ('bring it into a real account') — nonsense to someone who
|
||||
arrived from a search result."""
|
||||
spa = _spa()
|
||||
assert 'v-else-if="publicCatalog" class="sub">Verify your new account' in spa
|
||||
|
||||
|
||||
async def test_no_page_ships_an_unsubstituted_base(clients: AsyncClient):
|
||||
"""`{BASE}` reaching a browser means a canonical or og:url is pointing at nothing."""
|
||||
for path in ("/", "/support", "/terms", "/privacy", "/tutorial", "/catalog"):
|
||||
|
||||
Reference in New Issue
Block a user