dana-medical-site/internal/onec/client_test.go
2026-10-14 13:33:13 +00:00

94 lines
3.1 KiB
Go

package onec
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"testing"
"time"
)
func newFake(t *testing.T, h http.HandlerFunc) *Client {
t.Helper()
srv := httptest.NewServer(h)
t.Cleanup(srv.Close)
return New(srv.URL, "secret", "")
}
func TestClientSendsKeyAndParsesBothShapes(t *testing.T) {
c := newFake(t, func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-Api-Key") != "secret" {
http.Error(w, `{"code":"unauthorized","message":"нет ключа"}`, http.StatusUnauthorized)
return
}
switch r.URL.Path {
case "/branches":
_, _ = w.Write([]byte(`[{"id":"b1","name":"Ляхова, 22","address":"ул. Ляхова, 22"}]`))
case "/doctors":
_, _ = w.Write([]byte(`{"doctors":[{"id":"d1","name":"Иванов Иван Иванович","branch_ids":["b1"],"active":false}]}`))
case "/schedule":
if r.URL.Query().Get("doctor_id") != "d1" {
t.Errorf("doctor_id не передан: %s", r.URL.RawQuery)
}
_, _ = w.Write([]byte(`{"slots":[{"doctor_id":"d1","branch_id":"b1","start":"2026-10-01T10:00:00+03:00","end":"2026-10-01T10:30:00+03:00","status":"free"}]}`))
}
})
ctx := context.Background()
br, err := c.Branches(ctx)
if err != nil || len(br) != 1 || br[0].ID != "b1" {
t.Fatalf("branches: %v %+v", err, br)
}
docs, err := c.Doctors(ctx)
if err != nil || len(docs) != 1 || docs[0].IsActive() {
t.Fatalf("doctors: %v %+v", err, docs)
}
from := time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC)
slots, err := c.Schedule(ctx, from, from.Add(24*time.Hour), "d1")
if err != nil || len(slots) != 1 || !slots[0].Free() {
t.Fatalf("schedule: %v %+v", err, slots)
}
bad := New(c.Base, "wrong", "")
if _, err := bad.Branches(ctx); !errors.Is(err, ErrUnauthorized) {
t.Fatalf("ждали ErrUnauthorized, получили %v", err)
}
}
func TestBookErrors(t *testing.T) {
cases := []struct {
status int
body string
want error
}{
{409, `{"code":"slot_busy","message":"Окно занято"}`, ErrSlotBusy},
{404, `{"error":{"code":"doctor_not_found","message":"нет врача"}}`, ErrDoctorNotFound},
{400, `{"code":"validation","message":"нет телефона"}`, ErrValidation},
{500, `oops`, ErrUnavailable},
}
for _, tc := range cases {
c := newFake(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(tc.status)
_, _ = w.Write([]byte(tc.body))
})
_, err := c.Book(context.Background(), AppointmentRequest{DoctorID: "d1"})
if !errors.Is(err, tc.want) {
t.Errorf("HTTP %d: ждали %v, получили %v", tc.status, tc.want, err)
}
}
}
func TestBookSuccess(t *testing.T) {
c := newFake(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost || r.URL.Path != "/appointments" {
t.Errorf("не тот запрос: %s %s", r.Method, r.URL.Path)
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"appointment_id":"A-1","status":"booked","start":"2026-10-01T10:00:00+03:00","end":"2026-10-01T10:30:00+03:00"}`))
})
a, err := c.Book(context.Background(), AppointmentRequest{DoctorID: "d1", Source: "Сайт"})
if err != nil || a.ID != "A-1" || a.Status != "booked" {
t.Fatalf("book: %v %+v", err, a)
}
}