93 lines
3.7 KiB
Go
93 lines
3.7 KiB
Go
package api
|
||
|
||
import (
|
||
"net/http/httptest"
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
func TestSlugFromTitle(t *testing.T) {
|
||
cases := map[string]string{
|
||
"Я в сад": "ya-v-sad",
|
||
"Здоровый ЖКТ": "zdorovyy-zhkt",
|
||
"Мне год (1–2 года)": "mne-god-1-2-goda",
|
||
" Чек-ап «Я подросток»! ": "chek-ap-ya-podrostok",
|
||
"Подъезд, щука": "podezd-shchuka",
|
||
"EMSELLA 2026": "emsella-2026",
|
||
"!!!": "",
|
||
}
|
||
for title, want := range cases {
|
||
if got := slugFromTitle(title); got != want {
|
||
t.Errorf("slugFromTitle(%q) = %q, want %q", title, got, want)
|
||
}
|
||
}
|
||
}
|
||
|
||
func decodePromoBody(body string) (int, string) {
|
||
w := httptest.NewRecorder()
|
||
r := httptest.NewRequest("POST", "/api/v1/admin/promos", strings.NewReader(body))
|
||
if _, valid := decodePromo(w, r); valid {
|
||
return 200, ""
|
||
}
|
||
return w.Code, w.Body.String()
|
||
}
|
||
|
||
func TestDecodePromoRules(t *testing.T) {
|
||
cases := []struct {
|
||
name string
|
||
body string
|
||
wantCode int
|
||
wantText string
|
||
}{
|
||
{"valid published promo", `{"title":"Я в сад","discount_percent":20,"terms":"Скидка на программу чек-апа","ends_at":"2026-12-31","published":true}`, 200, ""},
|
||
{"draft without terms is allowed", `{"title":"Черновик","published":false}`, 200, ""},
|
||
{"no title", `{"title":" ","published":false}`, 422, "название"},
|
||
{"published without terms", `{"title":"Я в сад","published":true}`, 422, "условия"},
|
||
{"discount without end date", `{"title":"Я в сад","discount_percent":20,"terms":"x","published":true}`, 422, "последний день"},
|
||
{"discount out of range", `{"title":"Я в сад","discount_percent":150,"published":false}`, 422, "от 1 до 99"},
|
||
{"end before start", `{"title":"Я в сад","starts_at":"2026-10-01","ends_at":"2026-09-01","published":false}`, 422, "раньше начала"},
|
||
{"bad date", `{"title":"Я в сад","ends_at":"31.12.2026","published":false}`, 422, "ГГГГ-ММ-ДД"},
|
||
{"bad slug", `{"title":"Я в сад","slug":"Я в сад","published":false}`, 422, "латинские"},
|
||
}
|
||
for _, tc := range cases {
|
||
code, body := decodePromoBody(tc.body)
|
||
if code != tc.wantCode || (tc.wantText != "" && !strings.Contains(body, tc.wantText)) {
|
||
t.Errorf("%s: got %d %s, want %d containing %q", tc.name, code, body, tc.wantCode, tc.wantText)
|
||
}
|
||
}
|
||
}
|
||
|
||
func decodeCheckupBody(body string) (int, string, int) {
|
||
w := httptest.NewRecorder()
|
||
r := httptest.NewRequest("POST", "/api/v1/admin/checkups", strings.NewReader(body))
|
||
in, valid := decodeCheckup(w, r)
|
||
if valid {
|
||
return 200, "", len(in.Items)
|
||
}
|
||
return w.Code, w.Body.String(), 0
|
||
}
|
||
|
||
func TestDecodeCheckupRules(t *testing.T) {
|
||
code, body, items := decodeCheckupBody(`{"name":"Здоровая девочка","audience":"kids","price":5000,"old_price":6000,"items":["УЗИ"," ","Ферритин"]}`)
|
||
if code != 200 || items != 2 {
|
||
t.Fatalf("valid checkup rejected or empty items kept: %d %s items=%d", code, body, items)
|
||
}
|
||
|
||
cases := []struct {
|
||
name string
|
||
body string
|
||
wantText string
|
||
}{
|
||
{"unknown audience", `{"name":"X","audience":"pets"}`, "для кого"},
|
||
{"old price not above price", `{"name":"X","audience":"adults","price":5000,"old_price":5000}`, "больше цены"},
|
||
{"old price without price", `{"name":"X","audience":"adults","old_price":5000}`, "больше цены"},
|
||
{"negative price", `{"name":"X","audience":"adults","price":-1}`, "отрицательной"},
|
||
}
|
||
for _, tc := range cases {
|
||
code, body, _ := decodeCheckupBody(tc.body)
|
||
if code != 422 || !strings.Contains(body, tc.wantText) {
|
||
t.Errorf("%s: got %d %s, want 422 containing %q", tc.name, code, body, tc.wantText)
|
||
}
|
||
}
|
||
}
|