package bitrix import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" ) // fakeBitrix отвечает на методы REST так, как отвечает Битрикс24, и запоминает тела запросов. func fakeBitrix(t *testing.T, answers map[string]string) (*Client, map[string]map[string]any) { t.Helper() got := map[string]map[string]any{} srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { method := strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/rest/1/key/"), ".json") var body map[string]any _ = json.NewDecoder(r.Body).Decode(&body) got[method] = body ans, ok := answers[method] if !ok { w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(`{"error":"ERROR_METHOD_NOT_FOUND","error_description":"нет такого метода"}`)) return } _, _ = w.Write([]byte(ans)) })) t.Cleanup(srv.Close) return New(srv.URL + "/rest/1/key/"), got } func TestAddLeadSendsFieldsAndReturnsID(t *testing.T) { c, got := fakeBitrix(t, map[string]string{"crm.lead.add": `{"result":683100,"time":{}}`}) id, err := c.AddLead(context.Background(), LeadDraft{ Title: "Онлайн-запись: Иванов — 10.10 15:00", Name: "Анна", Phone: "+79280000000", SourceID: "112", SourceDescr: "Онлайн-запись на сайте", Comments: "строка
строка", }) if err != nil || id != "683100" { t.Fatalf("id=%q err=%v", id, err) } f, _ := got["crm.lead.add"]["fields"].(map[string]any) if f["STATUS_ID"] != "NEW" || f["SOURCE_ID"] != "112" || f["NAME"] != "Анна" || f["TITLE"] == nil { t.Fatalf("поля лида: %v", f) } phones, _ := f["PHONE"].([]any) if len(phones) != 1 || phones[0].(map[string]any)["VALUE"] != "+79280000000" { t.Fatalf("телефон: %v", f["PHONE"]) } } func TestAddLeadReportsBitrixError(t *testing.T) { c, _ := fakeBitrix(t, map[string]string{"crm.lead.add": `{"error":"ACCESS_DENIED","error_description":"нет прав"}`}) if _, err := c.AddLead(context.Background(), LeadDraft{Title: "x"}); err == nil || !strings.Contains(err.Error(), "ACCESS_DENIED") { t.Fatalf("ожидали ошибку прав, получили %v", err) } } func TestLeadSemanticsFiltersByIDs(t *testing.T) { c, got := fakeBitrix(t, map[string]string{ "crm.lead.list": `{"result":[{"ID":"1","STATUS_SEMANTIC_ID":"S"},{"ID":"2","STATUS_SEMANTIC_ID":"F"}],"total":2}`, }) m, err := c.LeadSemantics(context.Background(), []string{"1", "2", "3"}) if err != nil { t.Fatal(err) } // лида 3 в ответе нет (удалён в CRM) — в карте его тоже нет if m["1"] != SemanticSuccess || m["2"] != SemanticFailure || len(m) != 2 { t.Fatalf("семантика: %v", m) } filter, _ := got["crm.lead.list"]["filter"].(map[string]any) if ids, _ := filter["@ID"].([]any); len(ids) != 3 { t.Fatalf("фильтр по ID: %v", filter) } } func TestFailLeadAndComment(t *testing.T) { c, got := fakeBitrix(t, map[string]string{ "crm.lead.update": `{"result":true}`, "crm.timeline.comment.add": `{"result":55}`, }) if err := c.FailLead(context.Background(), "7"); err != nil { t.Fatal(err) } if err := c.AddLeadComment(context.Background(), "7", "Запись отменена"); err != nil { t.Fatal(err) } upd, _ := got["crm.lead.update"]["fields"].(map[string]any) if got["crm.lead.update"]["id"] != "7" || upd["STATUS_ID"] != FailedStatusID { t.Fatalf("обновление лида: %v", got["crm.lead.update"]) } cm, _ := got["crm.timeline.comment.add"]["fields"].(map[string]any) if cm["ENTITY_TYPE"] != "lead" || cm["ENTITY_ID"] != "7" { t.Fatalf("комментарий: %v", cm) } }