mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-07 23:01:06 +02:00
ghcr.io pull baseline (~10k/day rising → ~8-12k active installs) puts
sponsor conversion at 0.08% — roughly an order of magnitude under
industry-benchmark for OSS with visible CTA. The Settings banner from
0d4b9d4e gives passive every-visit visibility on one page; this adds
opt-out-able active visibility at moments where the user has just
earned something with Bambuddy.
Five trigger families with a 14-day cross-family cooldown: prints
(100/500/1000/2500/5000), cost (100/500/1000 tracked filament +
energy), archives (50/250/1000), anniversary (1 year), version-update
(re-armable on each major bump). New sponsor_toast_state table with
nullable user_id so auth-disabled installs get the same trigger logic
through one code path (NULL-keyed install-default row).
49 lines
1.9 KiB
Python
49 lines
1.9 KiB
Python
"""Integration tests for /sponsor-prompt routes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from httpx import AsyncClient
|
|
|
|
|
|
class TestSponsorPromptAPI:
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.integration
|
|
async def test_check_returns_show_false_for_empty_install(self, async_client: AsyncClient):
|
|
response = await async_client.get("/api/v1/sponsor-prompt/check")
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["show"] is False
|
|
assert body.get("milestone") is None
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.integration
|
|
async def test_dismiss_requires_milestone(self, async_client: AsyncClient):
|
|
response = await async_client.post("/api/v1/sponsor-prompt/dismiss", json={})
|
|
# Pydantic missing-field → 422.
|
|
assert response.status_code == 422
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.integration
|
|
async def test_dismiss_returns_204(self, async_client: AsyncClient):
|
|
response = await async_client.post(
|
|
"/api/v1/sponsor-prompt/dismiss",
|
|
json={"milestone": "version-update"},
|
|
)
|
|
assert response.status_code == 204
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.integration
|
|
async def test_check_then_dismiss_then_recheck_is_silent(self, async_client: AsyncClient):
|
|
"""End-to-end: even if no trigger is currently eligible, dismissing
|
|
anchors the cooldown, so a subsequent check stays {show: false}."""
|
|
first = await async_client.get("/api/v1/sponsor-prompt/check")
|
|
assert first.json()["show"] is False
|
|
dismiss = await async_client.post(
|
|
"/api/v1/sponsor-prompt/dismiss",
|
|
json={"milestone": "version-update"},
|
|
)
|
|
assert dismiss.status_code == 204
|
|
second = await async_client.get("/api/v1/sponsor-prompt/check")
|
|
assert second.json()["show"] is False
|