fix(09): WR-03 refuse writes that the compiled list and form do not declare
This commit is contained in:
@@ -498,3 +498,63 @@ func containsString(items []string, want string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TestCRUDOperationsFollowDeclarations pins WR-03: the compiled list and form
|
||||
// decide which writes the server accepts, not only what the SPA shows.
|
||||
func TestCRUDOperationsFollowDeclarations(t *testing.T) {
|
||||
_, httpSvc, cc, db, hooks := hookFixture(t)
|
||||
ctx := principalCtx(hooks, superUser())
|
||||
created := crudCall(httpSvc, http.MethodPost, "", []byte(`{"name":"Ada"}`), ctx)
|
||||
if created.Code != http.StatusCreated {
|
||||
t.Fatalf("declared create=%d %s", created.Code, created.Body.String())
|
||||
}
|
||||
id := uintString(decodeData(t, created.Body.Bytes())["id"])
|
||||
bulk := func() *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{"ids":[`+id+`]}`)).WithContext(ctx)
|
||||
req.SetPathValue("vendor", "acme")
|
||||
req.SetPathValue("plugin", "demo")
|
||||
req.SetPathValue("controller", "records")
|
||||
rec := httptest.NewRecorder()
|
||||
httpSvc.bulkDelete(rec, req)
|
||||
return rec
|
||||
}
|
||||
forbidden := func(name string, rec *httptest.ResponseRecorder) {
|
||||
t.Helper()
|
||||
if rec.Code != http.StatusForbidden || !strings.Contains(rec.Body.String(), `"forbidden"`) {
|
||||
t.Fatalf("%s=%d %s, want 403 forbidden", name, rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// No toolbar create button: the create route is closed, update is not.
|
||||
list := *cc.List
|
||||
cc.List = &list
|
||||
cc.List.ToolbarButtons = []string{"delete"}
|
||||
forbidden("create without a toolbar create button", crudCall(httpSvc, http.MethodPost, "", []byte(`{"name":"Bea"}`), ctx))
|
||||
if got := crudCall(httpSvc, http.MethodPut, id, []byte(`{"name":"Cid"}`), ctx); got.Code != http.StatusOK {
|
||||
t.Fatalf("update=%d %s", got.Code, got.Body.String())
|
||||
}
|
||||
|
||||
// No toolbar delete button: bulk delete is closed.
|
||||
cc.List.ToolbarButtons = []string{"create"}
|
||||
forbidden("bulk delete without a toolbar delete button", bulk())
|
||||
if n := countCrud(t, db); n != 1 {
|
||||
t.Fatalf("rows=%d, a refused bulk delete removed data", n)
|
||||
}
|
||||
|
||||
// No form: nothing can be created, updated or deleted one by one.
|
||||
form := cc.Form
|
||||
cc.Form = nil
|
||||
forbidden("create without a form", crudCall(httpSvc, http.MethodPost, "", []byte(`{"name":"Dan"}`), ctx))
|
||||
forbidden("update without a form", crudCall(httpSvc, http.MethodPut, id, []byte(`{"name":"Eve"}`), ctx))
|
||||
forbidden("delete without a form", crudCall(httpSvc, http.MethodDelete, id, nil, ctx))
|
||||
if n := countCrud(t, db); n != 1 {
|
||||
t.Fatalf("rows=%d, a refused write changed data", n)
|
||||
}
|
||||
cc.Form = form
|
||||
|
||||
// Declared again: bulk delete works.
|
||||
cc.List.ToolbarButtons = []string{"create", "delete"}
|
||||
if got := bulk(); got.Code != http.StatusOK || deletedCount(t, got.Body.Bytes()) != 1 {
|
||||
t.Fatalf("declared bulk delete=%d %s", got.Code, got.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user