721 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			721 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
| package forms_test
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 	"net/http"
 | |
| 	"net/http/httptest"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 
 | |
| 	validation "github.com/go-ozzo/ozzo-validation/v4"
 | |
| 	"github.com/labstack/echo/v5"
 | |
| 	"github.com/pocketbase/pocketbase/core"
 | |
| 	"github.com/pocketbase/pocketbase/daos"
 | |
| 	"github.com/pocketbase/pocketbase/forms"
 | |
| 	"github.com/pocketbase/pocketbase/models"
 | |
| 	"github.com/pocketbase/pocketbase/tests"
 | |
| 	"github.com/pocketbase/pocketbase/tools/list"
 | |
| )
 | |
| 
 | |
| func TestRecordUpsertPanic1(t *testing.T) {
 | |
| 	defer func() {
 | |
| 		if recover() == nil {
 | |
| 			t.Fatal("The form did not panic")
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	forms.NewRecordUpsert(nil, nil)
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertPanic2(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	defer func() {
 | |
| 		if recover() == nil {
 | |
| 			t.Fatal("The form did not panic")
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	forms.NewRecordUpsert(app, nil)
 | |
| }
 | |
| 
 | |
| func TestNewRecordUpsert(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo")
 | |
| 	record := models.NewRecord(collection)
 | |
| 	record.SetDataValue("title", "test_value")
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, record)
 | |
| 
 | |
| 	val := form.Data["title"]
 | |
| 	if val != "test_value" {
 | |
| 		t.Errorf("Expected record data to be loaded, got %v", form.Data)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertLoadDataUnsupported(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	record, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	testData := "title=test123"
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, record)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", strings.NewReader(testData))
 | |
| 	req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationForm)
 | |
| 
 | |
| 	if err := form.LoadData(req); err == nil {
 | |
| 		t.Fatal("Expected LoadData to fail, got nil")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertLoadDataJson(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	record, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	testData := map[string]any{
 | |
| 		"id":      "test_id",
 | |
| 		"title":   "test123",
 | |
| 		"unknown": "test456",
 | |
| 		// file fields unset/delete
 | |
| 		"onefile":     nil,
 | |
| 		"manyfiles.0": "",
 | |
| 		"manyfiles.1": "test.png", // should be ignored
 | |
| 		"onlyimages":  nil,
 | |
| 	}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, record)
 | |
| 	jsonBody, _ := json.Marshal(testData)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", bytes.NewReader(jsonBody))
 | |
| 	req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
 | |
| 	loadErr := form.LoadData(req)
 | |
| 	if loadErr != nil {
 | |
| 		t.Fatal(loadErr)
 | |
| 	}
 | |
| 
 | |
| 	if form.Id != "test_id" {
 | |
| 		t.Fatalf("Expect id field to be %q, got %q", "test_id", form.Id)
 | |
| 	}
 | |
| 
 | |
| 	if v, ok := form.Data["title"]; !ok || v != "test123" {
 | |
| 		t.Fatalf("Expect title field to be %q, got %q", "test123", v)
 | |
| 	}
 | |
| 
 | |
| 	if v, ok := form.Data["unknown"]; ok {
 | |
| 		t.Fatalf("Didn't expect unknown field to be set, got %v", v)
 | |
| 	}
 | |
| 
 | |
| 	onefile, ok := form.Data["onefile"]
 | |
| 	if !ok {
 | |
| 		t.Fatal("Expect onefile field to be set")
 | |
| 	}
 | |
| 	if onefile != "" {
 | |
| 		t.Fatalf("Expect onefile field to be empty string, got %v", onefile)
 | |
| 	}
 | |
| 
 | |
| 	manyfiles, ok := form.Data["manyfiles"]
 | |
| 	if !ok || manyfiles == nil {
 | |
| 		t.Fatal("Expect manyfiles field to be set")
 | |
| 	}
 | |
| 	manyfilesRemains := len(list.ToUniqueStringSlice(manyfiles))
 | |
| 	if manyfilesRemains != 1 {
 | |
| 		t.Fatalf("Expect only 1 manyfiles to remain, got \n%v", manyfiles)
 | |
| 	}
 | |
| 
 | |
| 	onlyimages := form.Data["onlyimages"]
 | |
| 	if len(list.ToUniqueStringSlice(onlyimages)) != 0 {
 | |
| 		t.Fatalf("Expect onlyimages field to be deleted, got \n%v", onlyimages)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertLoadDataMultipart(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	record, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	formData, mp, err := tests.MockMultipartData(map[string]string{
 | |
| 		"id":      "test_id",
 | |
| 		"title":   "test123",
 | |
| 		"unknown": "test456",
 | |
| 		// file fields unset/delete
 | |
| 		"onefile":     "",
 | |
| 		"manyfiles.0": "", // delete by index
 | |
| 		"manyfiles.b635c395-6837-49e5-8535-b0a6ebfbdbf3.png": "", // delete by name
 | |
| 		"manyfiles.1": "test.png", // should be ignored
 | |
| 		"onlyimages":  "",
 | |
| 	}, "onlyimages")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, record)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", formData)
 | |
| 	req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
 | |
| 	loadErr := form.LoadData(req)
 | |
| 	if loadErr != nil {
 | |
| 		t.Fatal(loadErr)
 | |
| 	}
 | |
| 
 | |
| 	if form.Id != "test_id" {
 | |
| 		t.Fatalf("Expect id field to be %q, got %q", "test_id", form.Id)
 | |
| 	}
 | |
| 
 | |
| 	if v, ok := form.Data["title"]; !ok || v != "test123" {
 | |
| 		t.Fatalf("Expect title field to be %q, got %q", "test123", v)
 | |
| 	}
 | |
| 
 | |
| 	if v, ok := form.Data["unknown"]; ok {
 | |
| 		t.Fatalf("Didn't expect unknown field to be set, got %v", v)
 | |
| 	}
 | |
| 
 | |
| 	onefile, ok := form.Data["onefile"]
 | |
| 	if !ok {
 | |
| 		t.Fatal("Expect onefile field to be set")
 | |
| 	}
 | |
| 	if onefile != "" {
 | |
| 		t.Fatalf("Expect onefile field to be empty string, got %v", onefile)
 | |
| 	}
 | |
| 
 | |
| 	manyfiles, ok := form.Data["manyfiles"]
 | |
| 	if !ok || manyfiles == nil {
 | |
| 		t.Fatal("Expect manyfiles field to be set")
 | |
| 	}
 | |
| 	manyfilesRemains := len(list.ToUniqueStringSlice(manyfiles))
 | |
| 	if manyfilesRemains != 0 {
 | |
| 		t.Fatalf("Expect 0 manyfiles to remain, got %v", manyfiles)
 | |
| 	}
 | |
| 
 | |
| 	onlyimages, ok := form.Data["onlyimages"]
 | |
| 	if !ok || onlyimages == nil {
 | |
| 		t.Fatal("Expect onlyimages field to be set")
 | |
| 	}
 | |
| 	onlyimagesRemains := len(list.ToUniqueStringSlice(onlyimages))
 | |
| 	expectedRemains := 1 // -2 removed + 1 new upload
 | |
| 	if onlyimagesRemains != expectedRemains {
 | |
| 		t.Fatalf("Expect onlyimages to be %d, got %d (%v)", expectedRemains, onlyimagesRemains, onlyimages)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertValidateFailure(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	record, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	// try with invalid test data to check whether the RecordDataValidator is triggered
 | |
| 	formData, mp, err := tests.MockMultipartData(map[string]string{
 | |
| 		"id":      "",
 | |
| 		"unknown": "test456", // should be ignored
 | |
| 		"title":   "a",
 | |
| 		"onerel":  "00000000-84ab-4057-a592-4604a731f78f",
 | |
| 	}, "manyfiles", "manyfiles")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	expectedErrors := []string{"title", "onerel", "manyfiles"}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, record)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", formData)
 | |
| 	req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
 | |
| 	form.LoadData(req)
 | |
| 
 | |
| 	result := form.Validate()
 | |
| 
 | |
| 	// parse errors
 | |
| 	errs, ok := result.(validation.Errors)
 | |
| 	if !ok && result != nil {
 | |
| 		t.Fatalf("Failed to parse errors %v", result)
 | |
| 	}
 | |
| 
 | |
| 	// check errors
 | |
| 	if len(errs) > len(expectedErrors) {
 | |
| 		t.Fatalf("Expected error keys %v, got %v", expectedErrors, errs)
 | |
| 	}
 | |
| 	for _, k := range expectedErrors {
 | |
| 		if _, ok := errs[k]; !ok {
 | |
| 			t.Errorf("Missing expected error key %q in %v", k, errs)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertValidateSuccess(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	record, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	formData, mp, err := tests.MockMultipartData(map[string]string{
 | |
| 		"id":      record.Id,
 | |
| 		"unknown": "test456", // should be ignored
 | |
| 		"title":   "abc",
 | |
| 		"onerel":  "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2",
 | |
| 	}, "manyfiles", "onefile")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, record)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", formData)
 | |
| 	req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
 | |
| 	form.LoadData(req)
 | |
| 
 | |
| 	result := form.Validate()
 | |
| 	if result != nil {
 | |
| 		t.Fatal(result)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertDrySubmitFailure(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	recordBefore, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	formData, mp, err := tests.MockMultipartData(map[string]string{
 | |
| 		"title":  "a",
 | |
| 		"onerel": "00000000-84ab-4057-a592-4604a731f78f",
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, recordBefore)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", formData)
 | |
| 	req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
 | |
| 	form.LoadData(req)
 | |
| 
 | |
| 	callbackCalls := 0
 | |
| 
 | |
| 	// ensure that validate is triggered
 | |
| 	// ---
 | |
| 	result := form.DrySubmit(func(txDao *daos.Dao) error {
 | |
| 		callbackCalls++
 | |
| 		return nil
 | |
| 	})
 | |
| 	if result == nil {
 | |
| 		t.Fatal("Expected error, got nil")
 | |
| 	}
 | |
| 	if callbackCalls != 0 {
 | |
| 		t.Fatalf("Expected callbackCalls to be 0, got %d", callbackCalls)
 | |
| 	}
 | |
| 
 | |
| 	// ensure that the record changes weren't persisted
 | |
| 	// ---
 | |
| 	recordAfter, err := app.Dao().FindFirstRecordByData(collection, "id", recordBefore.Id)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if recordAfter.GetStringDataValue("title") == "a" {
 | |
| 		t.Fatalf("Expected record.title to be %v, got %v", recordAfter.GetStringDataValue("title"), "a")
 | |
| 	}
 | |
| 
 | |
| 	if recordAfter.GetStringDataValue("onerel") == "00000000-84ab-4057-a592-4604a731f78f" {
 | |
| 		t.Fatalf("Expected record.onerel to be %s, got %s", recordBefore.GetStringDataValue("onerel"), recordAfter.GetStringDataValue("onerel"))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertDrySubmitSuccess(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	recordBefore, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	formData, mp, err := tests.MockMultipartData(map[string]string{
 | |
| 		"title":   "dry_test",
 | |
| 		"onefile": "",
 | |
| 	}, "manyfiles")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, recordBefore)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", formData)
 | |
| 	req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
 | |
| 	form.LoadData(req)
 | |
| 
 | |
| 	callbackCalls := 0
 | |
| 
 | |
| 	result := form.DrySubmit(func(txDao *daos.Dao) error {
 | |
| 		callbackCalls++
 | |
| 		return nil
 | |
| 	})
 | |
| 	if result != nil {
 | |
| 		t.Fatalf("Expected nil, got error %v", result)
 | |
| 	}
 | |
| 
 | |
| 	// ensure callback was called
 | |
| 	if callbackCalls != 1 {
 | |
| 		t.Fatalf("Expected callbackCalls to be 1, got %d", callbackCalls)
 | |
| 	}
 | |
| 
 | |
| 	// ensure that the record changes weren't persisted
 | |
| 	// ---
 | |
| 	recordAfter, err := app.Dao().FindFirstRecordByData(collection, "id", recordBefore.Id)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if recordAfter.GetStringDataValue("title") == "dry_test" {
 | |
| 		t.Fatalf("Expected record.title to be %v, got %v", recordAfter.GetStringDataValue("title"), "dry_test")
 | |
| 	}
 | |
| 	if recordAfter.GetStringDataValue("onefile") == "" {
 | |
| 		t.Fatal("Expected record.onefile to be set, got empty string")
 | |
| 	}
 | |
| 
 | |
| 	// file wasn't removed
 | |
| 	if !hasRecordFile(app, recordAfter, recordAfter.GetStringDataValue("onefile")) {
 | |
| 		t.Fatal("onefile file should not have been deleted")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertSubmitFailure(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	recordBefore, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	formData, mp, err := tests.MockMultipartData(map[string]string{
 | |
| 		"title":   "a",
 | |
| 		"onefile": "",
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, recordBefore)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", formData)
 | |
| 	req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
 | |
| 	form.LoadData(req)
 | |
| 
 | |
| 	interceptorCalls := 0
 | |
| 	interceptor := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
 | |
| 		return func() error {
 | |
| 			interceptorCalls++
 | |
| 			return next()
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// ensure that validate is triggered
 | |
| 	// ---
 | |
| 	result := form.Submit(interceptor)
 | |
| 	if result == nil {
 | |
| 		t.Fatal("Expected error, got nil")
 | |
| 	}
 | |
| 
 | |
| 	// check interceptor calls
 | |
| 	// ---
 | |
| 	if interceptorCalls != 0 {
 | |
| 		t.Fatalf("Expected interceptor to be called 0 times, got %d", interceptorCalls)
 | |
| 	}
 | |
| 
 | |
| 	// ensure that the record changes weren't persisted
 | |
| 	// ---
 | |
| 	recordAfter, err := app.Dao().FindFirstRecordByData(collection, "id", recordBefore.Id)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if recordAfter.GetStringDataValue("title") == "a" {
 | |
| 		t.Fatalf("Expected record.title to be %v, got %v", recordAfter.GetStringDataValue("title"), "a")
 | |
| 	}
 | |
| 
 | |
| 	if recordAfter.GetStringDataValue("onefile") == "" {
 | |
| 		t.Fatal("Expected record.onefile to be set, got empty string")
 | |
| 	}
 | |
| 
 | |
| 	// file wasn't removed
 | |
| 	if !hasRecordFile(app, recordAfter, recordAfter.GetStringDataValue("onefile")) {
 | |
| 		t.Fatal("onefile file should not have been deleted")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertSubmitSuccess(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	recordBefore, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	formData, mp, err := tests.MockMultipartData(map[string]string{
 | |
| 		"title":      "test_save",
 | |
| 		"onefile":    "",
 | |
| 		"onlyimages": "",
 | |
| 	}, "manyfiles.1", "manyfiles") // replace + new file
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, recordBefore)
 | |
| 	req := httptest.NewRequest(http.MethodGet, "/", formData)
 | |
| 	req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
 | |
| 	form.LoadData(req)
 | |
| 
 | |
| 	interceptorCalls := 0
 | |
| 	interceptor := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
 | |
| 		return func() error {
 | |
| 			interceptorCalls++
 | |
| 			return next()
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	result := form.Submit(interceptor)
 | |
| 	if result != nil {
 | |
| 		t.Fatalf("Expected nil, got error %v", result)
 | |
| 	}
 | |
| 
 | |
| 	// check interceptor calls
 | |
| 	// ---
 | |
| 	if interceptorCalls != 1 {
 | |
| 		t.Fatalf("Expected interceptor to be called 1 time, got %d", interceptorCalls)
 | |
| 	}
 | |
| 
 | |
| 	// ensure that the record changes were persisted
 | |
| 	// ---
 | |
| 	recordAfter, err := app.Dao().FindFirstRecordByData(collection, "id", recordBefore.Id)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	if recordAfter.GetStringDataValue("title") != "test_save" {
 | |
| 		t.Fatalf("Expected record.title to be %v, got %v", recordAfter.GetStringDataValue("title"), "test_save")
 | |
| 	}
 | |
| 
 | |
| 	if hasRecordFile(app, recordAfter, recordAfter.GetStringDataValue("onefile")) {
 | |
| 		t.Fatal("Expected record.onefile to be deleted")
 | |
| 	}
 | |
| 
 | |
| 	onlyimages := (recordAfter.GetStringSliceDataValue("onlyimages"))
 | |
| 	if len(onlyimages) != 0 {
 | |
| 		t.Fatalf("Expected all onlyimages files to be deleted, got %d (%v)", len(onlyimages), onlyimages)
 | |
| 	}
 | |
| 
 | |
| 	manyfiles := (recordAfter.GetStringSliceDataValue("manyfiles"))
 | |
| 	if len(manyfiles) != 3 {
 | |
| 		t.Fatalf("Expected 3 manyfiles, got %d (%v)", len(manyfiles), manyfiles)
 | |
| 	}
 | |
| 	for _, f := range manyfiles {
 | |
| 		if !hasRecordFile(app, recordAfter, f) {
 | |
| 			t.Fatalf("Expected file %q to exist", f)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertSubmitInterceptors(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo4")
 | |
| 	record, err := app.Dao().FindFirstRecordByData(collection, "id", "054f9f24-0a0a-4e09-87b1-bc7ff2b336a2")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	form := forms.NewRecordUpsert(app, record)
 | |
| 	form.Data["title"] = "test_new"
 | |
| 
 | |
| 	testErr := errors.New("test_error")
 | |
| 	interceptorRecordTitle := ""
 | |
| 
 | |
| 	interceptor1Called := false
 | |
| 	interceptor1 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
 | |
| 		return func() error {
 | |
| 			interceptor1Called = true
 | |
| 			return next()
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	interceptor2Called := false
 | |
| 	interceptor2 := func(next forms.InterceptorNextFunc) forms.InterceptorNextFunc {
 | |
| 		return func() error {
 | |
| 			interceptorRecordTitle = record.GetStringDataValue("title") // to check if the record was filled
 | |
| 			interceptor2Called = true
 | |
| 			return testErr
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	submitErr := form.Submit(interceptor1, interceptor2)
 | |
| 	if submitErr != testErr {
 | |
| 		t.Fatalf("Expected submitError %v, got %v", testErr, submitErr)
 | |
| 	}
 | |
| 
 | |
| 	if !interceptor1Called {
 | |
| 		t.Fatalf("Expected interceptor1 to be called")
 | |
| 	}
 | |
| 
 | |
| 	if !interceptor2Called {
 | |
| 		t.Fatalf("Expected interceptor2 to be called")
 | |
| 	}
 | |
| 
 | |
| 	if interceptorRecordTitle != form.Data["title"].(string) {
 | |
| 		t.Fatalf("Expected the form model to be filled before calling the interceptors")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func hasRecordFile(app core.App, record *models.Record, filename string) bool {
 | |
| 	fs, _ := app.NewFilesystem()
 | |
| 	defer fs.Close()
 | |
| 
 | |
| 	fileKey := filepath.Join(
 | |
| 		record.Collection().Id,
 | |
| 		record.Id,
 | |
| 		filename,
 | |
| 	)
 | |
| 
 | |
| 	exists, _ := fs.Exists(fileKey)
 | |
| 
 | |
| 	return exists
 | |
| }
 | |
| 
 | |
| func TestRecordUpsertWithCustomId(t *testing.T) {
 | |
| 	app, _ := tests.NewTestApp()
 | |
| 	defer app.Cleanup()
 | |
| 
 | |
| 	collection, _ := app.Dao().FindCollectionByNameOrId("demo3")
 | |
| 	existingRecord, err := app.Dao().FindFirstRecordByData(collection, "id", "2c542824-9de1-42fe-8924-e57c86267760")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	scenarios := []struct {
 | |
| 		name        string
 | |
| 		data        map[string]string
 | |
| 		record      *models.Record
 | |
| 		expectError bool
 | |
| 	}{
 | |
| 		{
 | |
| 			"empty data",
 | |
| 			map[string]string{},
 | |
| 			models.NewRecord(collection),
 | |
| 			false,
 | |
| 		},
 | |
| 		{
 | |
| 			"empty id",
 | |
| 			map[string]string{"id": ""},
 | |
| 			models.NewRecord(collection),
 | |
| 			false,
 | |
| 		},
 | |
| 		{
 | |
| 			"id < 15 chars",
 | |
| 			map[string]string{"id": "a23"},
 | |
| 			models.NewRecord(collection),
 | |
| 			true,
 | |
| 		},
 | |
| 		{
 | |
| 			"id > 15 chars",
 | |
| 			map[string]string{"id": "a234567890123456"},
 | |
| 			models.NewRecord(collection),
 | |
| 			true,
 | |
| 		},
 | |
| 		{
 | |
| 			"id = 15 chars (invalid chars)",
 | |
| 			map[string]string{"id": "a@3456789012345"},
 | |
| 			models.NewRecord(collection),
 | |
| 			true,
 | |
| 		},
 | |
| 		{
 | |
| 			"id = 15 chars (valid chars)",
 | |
| 			map[string]string{"id": "a23456789012345"},
 | |
| 			models.NewRecord(collection),
 | |
| 			false,
 | |
| 		},
 | |
| 		{
 | |
| 			"changing the id of an existing record",
 | |
| 			map[string]string{"id": "b23456789012345"},
 | |
| 			existingRecord,
 | |
| 			true,
 | |
| 		},
 | |
| 		{
 | |
| 			"using the same existing record id",
 | |
| 			map[string]string{"id": existingRecord.Id},
 | |
| 			existingRecord,
 | |
| 			false,
 | |
| 		},
 | |
| 		{
 | |
| 			"skipping the id for existing record",
 | |
| 			map[string]string{},
 | |
| 			existingRecord,
 | |
| 			false,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, scenario := range scenarios {
 | |
| 		formData, mp, err := tests.MockMultipartData(scenario.data)
 | |
| 		if err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 
 | |
| 		form := forms.NewRecordUpsert(app, scenario.record)
 | |
| 		req := httptest.NewRequest(http.MethodGet, "/", formData)
 | |
| 		req.Header.Set(echo.HeaderContentType, mp.FormDataContentType())
 | |
| 		form.LoadData(req)
 | |
| 
 | |
| 		dryErr := form.DrySubmit(nil)
 | |
| 		hasDryErr := dryErr != nil
 | |
| 
 | |
| 		submitErr := form.Submit()
 | |
| 		hasSubmitErr := submitErr != nil
 | |
| 
 | |
| 		if hasDryErr != hasSubmitErr {
 | |
| 			t.Errorf("[%s] Expected hasDryErr and hasSubmitErr to have the same value, got %v vs %v", scenario.name, hasDryErr, hasSubmitErr)
 | |
| 		}
 | |
| 
 | |
| 		if hasSubmitErr != scenario.expectError {
 | |
| 			t.Errorf("[%s] Expected hasSubmitErr to be %v, got %v (%v)", scenario.name, scenario.expectError, hasSubmitErr, submitErr)
 | |
| 		}
 | |
| 
 | |
| 		if id, ok := scenario.data["id"]; ok && id != "" && !hasSubmitErr {
 | |
| 			_, err := app.Dao().FindRecordById(collection, id, nil)
 | |
| 			if err != nil {
 | |
| 				t.Errorf("[%s] Expected to find record with id %s, got %v", scenario.name, id, err)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |