126 lines
3.9 KiB
Go
126 lines
3.9 KiB
Go
package api_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"strconv"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"havenllo/internal/api"
|
|
"havenllo/internal/app"
|
|
"havenllo/internal/database"
|
|
)
|
|
|
|
func newHandler(t *testing.T) http.Handler {
|
|
t.Helper()
|
|
db, err := database.Open(context.Background(), filepath.Join(t.TempDir(), "havenllo.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = db.Close() })
|
|
return api.NewHandler(app.New(db), fstest.MapFS{"index.html": {Data: []byte("<html></html>")}})
|
|
}
|
|
|
|
func request(t *testing.T, handler http.Handler, method, path, body string, jsonBody bool) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
r := httptest.NewRequest(method, path, bytes.NewBufferString(body))
|
|
if jsonBody {
|
|
r.Header.Set("Content-Type", "application/json")
|
|
}
|
|
w := httptest.NewRecorder()
|
|
handler.ServeHTTP(w, r)
|
|
return w
|
|
}
|
|
|
|
func TestBoardAndHealth(t *testing.T) {
|
|
t.Parallel()
|
|
handler := newHandler(t)
|
|
for _, path := range []string{"/api/health", "/api/board"} {
|
|
response := request(t, handler, http.MethodGet, path, "", false)
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("%s status = %d, body %s", path, response.Code, response.Body)
|
|
}
|
|
}
|
|
var snapshot struct {
|
|
Lists []json.RawMessage `json:"lists"`
|
|
}
|
|
if err := json.Unmarshal(request(t, handler, http.MethodGet, "/api/board", "", false).Body.Bytes(), &snapshot); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(snapshot.Lists) != 3 {
|
|
t.Fatalf("snapshot lists = %d, want 3", len(snapshot.Lists))
|
|
}
|
|
}
|
|
|
|
func TestJSONValidationAndLastListConflict(t *testing.T) {
|
|
t.Parallel()
|
|
handler := newHandler(t)
|
|
if got := request(t, handler, http.MethodPost, "/api/lists", `{"name":"later","unknown":true}`, true); got.Code != http.StatusBadRequest {
|
|
t.Fatalf("unknown field status = %d", got.Code)
|
|
}
|
|
if got := request(t, handler, http.MethodPost, "/api/lists", `{"name":"later"}`, false); got.Code != http.StatusUnsupportedMediaType {
|
|
t.Fatalf("content type status = %d", got.Code)
|
|
}
|
|
response := request(t, handler, http.MethodGet, "/api/lists", "", false)
|
|
var lists struct {
|
|
Lists []struct {
|
|
ID int64 `json:"id"`
|
|
} `json:"lists"`
|
|
}
|
|
if err := json.Unmarshal(response.Body.Bytes(), &lists); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, list := range lists.Lists[:2] {
|
|
if got := request(t, handler, http.MethodDelete, "/api/lists/"+strconv.FormatInt(list.ID, 10), "", false); got.Code != http.StatusNoContent {
|
|
t.Fatalf("delete list status = %d", got.Code)
|
|
}
|
|
}
|
|
if got := request(t, handler, http.MethodDelete, "/api/lists/"+strconv.FormatInt(lists.Lists[2].ID, 10), "", false); got.Code != http.StatusConflict {
|
|
t.Fatalf("last list status = %d", got.Code)
|
|
}
|
|
}
|
|
|
|
func TestCardDoneFieldIsNotPartOfTheAPI(t *testing.T) {
|
|
t.Parallel()
|
|
handler := newHandler(t)
|
|
var board struct {
|
|
Lists []struct {
|
|
ID int64 `json:"id"`
|
|
} `json:"lists"`
|
|
}
|
|
if err := json.Unmarshal(request(t, handler, http.MethodGet, "/api/board", "", false).Body.Bytes(), &board); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(board.Lists) == 0 {
|
|
t.Fatal("board has no lists")
|
|
}
|
|
|
|
created := request(t, handler, http.MethodPost, "/api/lists/"+strconv.FormatInt(board.Lists[0].ID, 10)+"/cards", `{"title":"status comes from the list"}`, true)
|
|
if created.Code != http.StatusCreated {
|
|
t.Fatalf("create card status = %d, body %s", created.Code, created.Body)
|
|
}
|
|
var payload struct {
|
|
Card map[string]json.RawMessage `json:"card"`
|
|
}
|
|
if err := json.Unmarshal(created.Body.Bytes(), &payload); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, exists := payload.Card["done"]; exists {
|
|
t.Fatalf("card response unexpectedly contains done: %s", created.Body)
|
|
}
|
|
|
|
cardID := payload.Card["id"]
|
|
var id int64
|
|
if err := json.Unmarshal(cardID, &id); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := request(t, handler, http.MethodPatch, "/api/cards/"+strconv.FormatInt(id, 10), `{"done":true}`, true); got.Code != http.StatusBadRequest {
|
|
t.Fatalf("done patch status = %d, body %s", got.Code, got.Body)
|
|
}
|
|
}
|