package api_test import ( "net/http" "testing" "atlas9.dev/c/core" "atlas9.dev/c/core/assert" "atlas9.dev/c/demo/api" "atlas9.dev/c/demo/todos" ) func createList(t *testing.T, s *testServer, name string) todos.List { t.Helper() var res api.Todos_CreateListRes httpRes := s.call(t, "/Todos_CreateList", api.Todos_CreateListReq{ List: todos.List{Tenant: defaultTenant, Name: name}, }, &res) assert.Eq(t, httpRes.StatusCode, http.StatusOK) return res.List } func createItem(t *testing.T, s *testServer, item todos.Item) todos.Item { t.Helper() item.Tenant = defaultTenant var res api.Todos_CreateItemRes httpRes := s.call(t, "/Todos_CreateItem", api.Todos_CreateItemReq{Item: item}, &res) assert.Eq(t, httpRes.StatusCode, http.StatusOK) return res.Item } func TestTodosApi_CreateList(t *testing.T) { s := startServer(t) list := createList(t, s, "Groceries") assert.Eq(t, list.Name, "Groceries") assert.Eq(t, list.ID.IsEmpty(), false) var res api.Todos_GetListRes httpRes := s.call(t, "/Todos_GetList", api.Todos_GetListReq{ ID: list.ID, Tenant: defaultTenant, }, &res) assert.Eq(t, httpRes.StatusCode, http.StatusOK) assert.Eq(t, res.List.Name, "Groceries") } func TestTodosApi_CreateList_NameRequired(t *testing.T) { s := startServer(t) httpRes := s.call(t, "/Todos_CreateList", api.Todos_CreateListReq{ List: todos.List{Tenant: defaultTenant}, }, nil) assert.Eq(t, httpRes.StatusCode, http.StatusBadRequest) } func TestTodosApi_UpdateList(t *testing.T) { s := startServer(t) list := createList(t, s, "Old") list.Name = "New" var res api.Todos_UpdateListRes httpRes := s.call(t, "/Todos_UpdateList", api.Todos_UpdateListReq{List: list}, &res) assert.Eq(t, httpRes.StatusCode, http.StatusOK) var getRes api.Todos_GetListRes s.call(t, "/Todos_GetList", api.Todos_GetListReq{ID: list.ID, Tenant: defaultTenant}, &getRes) assert.Eq(t, getRes.List.Name, "New") } func TestTodosApi_ListLists(t *testing.T) { s := startServer(t) createList(t, s, "One") createList(t, s, "Two") var res api.Todos_ListListsRes httpRes := s.call(t, "/Todos_ListLists", api.Todos_ListListsReq{ Tenant: defaultTenant, }, &res) assert.Eq(t, httpRes.StatusCode, http.StatusOK) assert.Eq(t, len(res.Page.Items), 2) } func TestTodosApi_DeleteList(t *testing.T) { s := startServer(t) list := createList(t, s, "Doomed") httpRes := s.call(t, "/Todos_DeleteList", api.Todos_DeleteListReq{ ID: list.ID, Tenant: defaultTenant, }, nil) assert.Eq(t, httpRes.StatusCode, http.StatusOK) getRes := s.call(t, "/Todos_GetList", api.Todos_GetListReq{ ID: list.ID, Tenant: defaultTenant, }, nil) assert.Eq(t, getRes.StatusCode, http.StatusNotFound) } func TestTodosApi_CreateItem(t *testing.T) { s := startServer(t) item := createItem(t, s, todos.Item{Title: "Buy milk", Notes: "2%"}) assert.Eq(t, item.ID.IsEmpty(), false) assert.Eq(t, item.Status, todos.StatusOpen) var res api.Todos_GetItemRes httpRes := s.call(t, "/Todos_GetItem", api.Todos_GetItemReq{ ID: item.ID, Tenant: defaultTenant, }, &res) assert.Eq(t, httpRes.StatusCode, http.StatusOK) assert.Eq(t, res.Item.Title, "Buy milk") assert.Eq(t, res.Item.Notes, "2%") } func TestTodosApi_CreateItem_TitleRequired(t *testing.T) { s := startServer(t) httpRes := s.call(t, "/Todos_CreateItem", api.Todos_CreateItemReq{ Item: todos.Item{Tenant: defaultTenant}, }, nil) assert.Eq(t, httpRes.StatusCode, http.StatusBadRequest) } func TestTodosApi_UpdateItem_Status(t *testing.T) { s := startServer(t) item := createItem(t, s, todos.Item{Title: "Buy milk"}) item.Status = todos.StatusInProgress var res api.Todos_UpdateItemRes httpRes := s.call(t, "/Todos_UpdateItem", api.Todos_UpdateItemReq{Item: item}, &res) assert.Eq(t, httpRes.StatusCode, http.StatusOK) var getRes api.Todos_GetItemRes s.call(t, "/Todos_GetItem", api.Todos_GetItemReq{ID: item.ID, Tenant: defaultTenant}, &getRes) assert.Eq(t, getRes.Item.Status, todos.StatusInProgress) } func TestTodosApi_UpdateItem_InvalidStatus(t *testing.T) { s := startServer(t) item := createItem(t, s, todos.Item{Title: "Buy milk"}) item.Status = "someday" httpRes := s.call(t, "/Todos_UpdateItem", api.Todos_UpdateItemReq{Item: item}, nil) assert.Eq(t, httpRes.StatusCode, http.StatusBadRequest) } func TestTodosApi_AssignItem(t *testing.T) { s := startServer(t) // seedUser makes the user a member of defaultTenant. assignee := s.seedUser(t, "assignee@test", "pass") item := createItem(t, s, todos.Item{Title: "Assigned"}) item.Assignee = assignee httpRes := s.call(t, "/Todos_UpdateItem", api.Todos_UpdateItemReq{Item: item}, nil) assert.Eq(t, httpRes.StatusCode, http.StatusOK) var getRes api.Todos_GetItemRes s.call(t, "/Todos_GetItem", api.Todos_GetItemReq{ID: item.ID, Tenant: defaultTenant}, &getRes) assert.Eq(t, getRes.Item.Assignee, assignee) } func TestTodosApi_AssignItem_NotMember(t *testing.T) { s := startServer(t) httpRes := s.call(t, "/Todos_CreateItem", api.Todos_CreateItemReq{ Item: todos.Item{ Tenant: defaultTenant, Title: "Assigned to stranger", Assignee: core.NewID("t"), }, }, nil) assert.Eq(t, httpRes.StatusCode, http.StatusBadRequest) } func TestTodosApi_ListMembership(t *testing.T) { s := startServer(t) list1 := createList(t, s, "One") list2 := createList(t, s, "Two") shared := createItem(t, s, todos.Item{Title: "Shared"}) only1 := createItem(t, s, todos.Item{Title: "Only in one"}) for _, add := range []api.Todos_AddToListReq{ {Tenant: defaultTenant, List: list1.ID, Item: shared.ID}, {Tenant: defaultTenant, List: list2.ID, Item: shared.ID}, {Tenant: defaultTenant, List: list1.ID, Item: only1.ID}, } { httpRes := s.call(t, "/Todos_AddToList", add, nil) assert.Eq(t, httpRes.StatusCode, http.StatusOK) } var res api.Todos_ListItemsRes httpRes := s.call(t, "/Todos_ListItems", api.Todos_ListItemsReq{ Tenant: defaultTenant, List: list1.ID, }, &res) assert.Eq(t, httpRes.StatusCode, http.StatusOK) assert.Eq(t, len(res.Page.Items), 2) res = api.Todos_ListItemsRes{} s.call(t, "/Todos_ListItems", api.Todos_ListItemsReq{ Tenant: defaultTenant, List: list2.ID, }, &res) assert.Eq(t, len(res.Page.Items), 1) assert.Eq(t, res.Page.Items[0].ID, shared.ID) // no list filter: all items in the tenant res = api.Todos_ListItemsRes{} s.call(t, "/Todos_ListItems", api.Todos_ListItemsReq{ Tenant: defaultTenant, }, &res) assert.Eq(t, len(res.Page.Items), 2) // remove the shared item from list1 httpRes = s.call(t, "/Todos_RemoveFromList", api.Todos_RemoveFromListReq{ Tenant: defaultTenant, List: list1.ID, Item: shared.ID, }, nil) assert.Eq(t, httpRes.StatusCode, http.StatusOK) res = api.Todos_ListItemsRes{} s.call(t, "/Todos_ListItems", api.Todos_ListItemsReq{ Tenant: defaultTenant, List: list1.ID, }, &res) assert.Eq(t, len(res.Page.Items), 1) assert.Eq(t, res.Page.Items[0].ID, only1.ID) } func TestTodosApi_AddToList_UnknownItem(t *testing.T) { s := startServer(t) list := createList(t, s, "One") httpRes := s.call(t, "/Todos_AddToList", api.Todos_AddToListReq{ Tenant: defaultTenant, List: list.ID, Item: core.NewID("todo"), }, nil) assert.Eq(t, httpRes.StatusCode, http.StatusNotFound) } func TestTodosApi_Unauthorized(t *testing.T) { s := startServer(t) s.logout(t) httpRes := s.call(t, "/Todos_CreateList", api.Todos_CreateListReq{ List: todos.List{Tenant: defaultTenant, Name: "Nope"}, }, nil) assert.Eq(t, httpRes.StatusCode, http.StatusUnauthorized) }