mirror of
https://github.com/simonw/datasette.git
synced 2026-06-18 14:57:48 +02:00
147 lines
4.3 KiB
Python
147 lines
4.3 KiB
Python
import socket
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from datasette.fixtures import write_fixture_database
|
|
|
|
|
|
def find_free_port():
|
|
with socket.socket() as sock:
|
|
sock.bind(("127.0.0.1", 0))
|
|
return sock.getsockname()[1]
|
|
|
|
|
|
def wait_for_server(process, url, timeout=10):
|
|
deadline = time.monotonic() + timeout
|
|
last_error = None
|
|
while time.monotonic() < deadline:
|
|
if process.poll() is not None:
|
|
stdout, stderr = process.communicate()
|
|
raise AssertionError(
|
|
"Datasette server exited early\n"
|
|
f"stdout:\n{stdout}\n"
|
|
f"stderr:\n{stderr}"
|
|
)
|
|
try:
|
|
response = httpx.get(url, timeout=1.0)
|
|
if response.status_code < 500:
|
|
return
|
|
last_error = f"HTTP {response.status_code}: {response.text[:200]}"
|
|
except httpx.HTTPError as ex:
|
|
last_error = repr(ex)
|
|
time.sleep(0.1)
|
|
raise AssertionError(f"Timed out waiting for {url}: {last_error}")
|
|
|
|
|
|
@pytest.fixture
|
|
def datasette_server(tmp_path):
|
|
db_path = tmp_path / "fixtures.db"
|
|
write_fixture_database(str(db_path))
|
|
port = find_free_port()
|
|
process = subprocess.Popen(
|
|
[
|
|
sys.executable,
|
|
"-m",
|
|
"datasette",
|
|
str(db_path),
|
|
"--host",
|
|
"127.0.0.1",
|
|
"--port",
|
|
str(port),
|
|
"--setting",
|
|
"num_sql_threads",
|
|
"1",
|
|
],
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
text=True,
|
|
)
|
|
url = f"http://127.0.0.1:{port}/"
|
|
try:
|
|
wait_for_server(process, url)
|
|
yield url
|
|
finally:
|
|
process.terminate()
|
|
try:
|
|
process.wait(timeout=5)
|
|
except subprocess.TimeoutExpired:
|
|
process.kill()
|
|
process.wait()
|
|
|
|
|
|
@pytest.mark.playwright
|
|
def test_datasette_homepage_contains_datasette(page, datasette_server):
|
|
page.goto(datasette_server)
|
|
assert "Datasette" in page.locator("body").inner_text()
|
|
|
|
|
|
@pytest.mark.playwright
|
|
def test_navigation_search_tracks_and_renders_recent_items(page, datasette_server):
|
|
page.goto(datasette_server)
|
|
result = page.evaluate("""
|
|
async () => {
|
|
await customElements.whenDefined("navigation-search");
|
|
const element = document.querySelector("navigation-search");
|
|
const key = element.recentItemsStorageKey();
|
|
localStorage.removeItem(key);
|
|
|
|
const items = Array.from({ length: 6 }, (_, index) => ({
|
|
name: `Item ${index + 1}`,
|
|
url: `/item-${index + 1}`,
|
|
type: "table",
|
|
description: "Table",
|
|
}));
|
|
items[5].name = "content: recent_datasette_releases";
|
|
items[5].display_name = "Recent Datasette releases";
|
|
|
|
for (const item of items) {
|
|
element.saveRecentItem(item);
|
|
}
|
|
|
|
const stored = JSON.parse(localStorage.getItem(key));
|
|
element.matches = [
|
|
items[5],
|
|
items[4],
|
|
{
|
|
name: "Other",
|
|
url: "/other",
|
|
type: "database",
|
|
description: "Database",
|
|
},
|
|
];
|
|
element.shadowRoot.querySelector(".search-input").value = "";
|
|
element.renderResults();
|
|
const html = element.shadowRoot.querySelector(".results-container").innerHTML;
|
|
|
|
element.clearRecentItems();
|
|
const clearedValue = localStorage.getItem(key);
|
|
element.renderResults();
|
|
const htmlAfterClear = element.shadowRoot
|
|
.querySelector(".results-container")
|
|
.innerHTML;
|
|
|
|
return { stored, html, clearedValue, htmlAfterClear };
|
|
}
|
|
""")
|
|
assert [item["url"] for item in result["stored"]] == [
|
|
"/item-6",
|
|
"/item-5",
|
|
"/item-4",
|
|
"/item-3",
|
|
"/item-2",
|
|
]
|
|
assert result["stored"][0]["display_name"] == "Recent Datasette releases"
|
|
assert "Recent" in result["html"]
|
|
assert "Recent Datasette releases" in result["html"]
|
|
assert "Item 5" in result["html"]
|
|
assert "content: recent_datasette_releases" in result["html"]
|
|
assert "Item 4" in result["html"]
|
|
assert "Item 2" in result["html"]
|
|
assert "Other" not in result["html"]
|
|
assert "Clear recent" in result["html"]
|
|
assert result["clearedValue"] is None
|
|
assert "Clear recent" not in result["htmlAfterClear"]
|