mirror of
https://github.com/wahyd4/links.git
synced 2026-08-09 05:06:16 +10:00
feat(home): search-driven link library with mobile card layout
- /search/aliases/ now matches alias/url/description/text/tags and returns id, link_type, detail_url, edit_url, click_count for management actions - Library filter upgraded from client-side row filtering to live search cards: click card -> detail page, inline edit/delete, alias jumps - Mobile: table rows render as cards (kills 620px horizontal scroll), hidden cells stay hidden, no viewport overflow - Hero search no longer autofocuses on touch devices (no keyboard pop); desktop keeps autofocus via hover:fine media query - Nav bar unified to light frosted-glass (was dark green) across all pages - Fix hero-glow decorative overflow on mobile - Add tests/test_search_aliases.py (8 cases)
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
"""Tests for the enhanced /search/aliases/ endpoint (search-driven library)."""
|
||||
import pytest
|
||||
from django.test import Client
|
||||
from django.urls import reverse
|
||||
from links.models import Link, Tag
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def db_links(db):
|
||||
"""A small, deterministic link library for search tests."""
|
||||
l1 = Link.objects.create(
|
||||
alias="github", original_url="https://github.com", link_type="LINK", click_count=5,
|
||||
description="Code hosting",
|
||||
)
|
||||
l2 = Link.objects.create(
|
||||
alias="gitlab", original_url="https://gitlab.com", link_type="LINK", click_count=2,
|
||||
description="Another code host",
|
||||
)
|
||||
l3 = Link.objects.create(
|
||||
alias="docs", original_url="https://docs.example.com/{page,default=index}", link_type="LINK",
|
||||
click_count=0, description="Template link",
|
||||
)
|
||||
l4 = Link.objects.create(
|
||||
alias="notify", original_url="", link_type="ACTION",
|
||||
action_config={"action_type": "discord_send"}, click_count=0,
|
||||
)
|
||||
tag = Tag.objects.create(name="dev")
|
||||
l1.tags.add(tag)
|
||||
return [l1, l2, l3, l4]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search_aliases_matches_alias_and_returns_enriched_fields(client, db_links):
|
||||
resp = client.get(reverse("search_aliases"), {"q": "git"})
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
aliases = {item["alias"] for item in data}
|
||||
assert aliases == {"github", "gitlab"}
|
||||
|
||||
github = next(i for i in data if i["alias"] == "github")
|
||||
# Enriched management fields are present and correct
|
||||
assert github["id"] == db_links[0].id
|
||||
assert github["link_type"] == "LINK"
|
||||
assert github["detail_url"] == f"/link/{db_links[0].id}/"
|
||||
assert github["edit_url"] == f"/link/{db_links[0].id}/edit/"
|
||||
assert github["click_count"] == 5
|
||||
assert github["description"] == "Code hosting"
|
||||
assert github["original_url"] == "https://github.com"
|
||||
# Backwards-compatible fields (hero autocomplete relies on these)
|
||||
assert github["url"].endswith("/github/")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search_aliases_matches_original_url(client, db_links):
|
||||
resp = client.get(reverse("search_aliases"), {"q": "gitlab.com"})
|
||||
assert resp.status_code == 200
|
||||
assert [i["alias"] for i in resp.json()] == ["gitlab"]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search_aliases_matches_description(client, db_links):
|
||||
resp = client.get(reverse("search_aliases"), {"q": "template link"})
|
||||
assert resp.status_code == 200
|
||||
assert [i["alias"] for i in resp.json()] == ["docs"]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search_aliases_matches_tag_name(client, db_links):
|
||||
resp = client.get(reverse("search_aliases"), {"q": "dev"})
|
||||
assert resp.status_code == 200
|
||||
assert [i["alias"] for i in resp.json()] == ["github"]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search_aliases_priority_exact_first(client, db_links):
|
||||
resp = client.get(reverse("search_aliases"), {"q": "github"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()[0]["alias"] == "github"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search_aliases_empty_query_returns_recent(client, db_links):
|
||||
# Touch l2 so it becomes the most recently updated (auto_now needs the
|
||||
# field explicitly listed in update_fields to refresh).
|
||||
db_links[1].click_count = 3
|
||||
db_links[1].save(update_fields=["click_count", "updated_at"])
|
||||
resp = client.get(reverse("search_aliases"))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert len(data) >= 4
|
||||
assert data[0]["alias"] == "gitlab" # most recently updated first
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search_aliases_action_type_surfaces(client, db_links):
|
||||
resp = client.get(reverse("search_aliases"), {"q": "notify"})
|
||||
assert resp.status_code == 200
|
||||
item = resp.json()[0]
|
||||
assert item["link_type"] == "ACTION"
|
||||
assert item["detail_url"] == f"/link/{db_links[3].id}/"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_search_aliases_no_results(client, db_links):
|
||||
resp = client.get(reverse("search_aliases"), {"q": "zzzznothing"})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == []
|
||||
Reference in New Issue
Block a user