test: expand coverage across readers, writers, cmd, ui, diff and merge

Implements tests/_plans and previously deferred packages; updates plan
README with new coverage numbers.
This commit is contained in:
2026-10-03 21:33:59 +02:00
parent a32647ee16
commit 495a21b67b
50 changed files with 8461 additions and 8 deletions
+198
View File
@@ -0,0 +1,198 @@
package ui
import (
"reflect"
"testing"
"git.warky.dev/wdevs/relspecgo/pkg/models"
)
func TestColumnDataOps(t *testing.T) {
se := newTestEditor()
if se.CreateColumn(5, 0, "x", "int", false, false) != nil || se.CreateColumn(0, 5, "x", "int", false, false) != nil {
t.Error("create with bad index must return nil")
}
col := se.CreateColumn(0, 0, "age", "integer", true, true)
if col == nil || col.Type != "integer" || !col.IsPrimaryKey || !col.NotNull {
t.Fatalf("create: %+v", col)
}
if se.GetColumn(0, 0, "age") != col || se.GetColumn(0, 0, "nope") != nil || se.GetColumn(9, 0, "age") != nil {
t.Error("get mismatch")
}
if se.CreateColumn(0, 0, "a", "text", false, false) == nil {
t.Error("create second column")
}
tests := []struct {
name string
si, ti int
old, new string
want bool
}{
{"bad table", 0, 9, "age", "age", false},
{"missing column", 0, 0, "zzz", "zzz", false},
{"in place", 0, 0, "age", "age", true},
{"rename", 0, 0, "age", "years", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := se.UpdateColumn(tt.si, tt.ti, tt.old, tt.new, "bigint", false, true, "0", "desc"); got != tt.want {
t.Errorf("got %v", got)
}
})
}
got := se.GetColumn(0, 0, "years")
if got == nil || got.Name != "years" || got.Type != "bigint" || got.IsPrimaryKey || got.Default != "0" || got.Description != "desc" {
t.Errorf("after update: %+v", got)
}
if se.GetColumn(0, 0, "age") != nil {
t.Error("old name must be gone")
}
if len(se.GetAllColumns(0, 0)) != 4 || se.GetAllColumns(0, 9) != nil {
t.Error("GetAllColumns")
}
if se.DeleteColumn(0, 9, "a") || se.DeleteColumn(0, 0, "zzz") {
t.Error("delete bad target must fail")
}
if !se.DeleteColumn(0, 0, "a") || se.DeleteColumn(0, 0, "a") {
t.Error("delete should succeed once")
}
}
func TestCreateColumn_NilMap(t *testing.T) {
se := newTestEditor()
se.db.Schemas[0].Tables[0].Columns = nil
if se.CreateColumn(0, 0, "a", "text", false, false) == nil {
t.Error("create with nil map")
}
}
func TestRelationshipDataOps(t *testing.T) {
se := newTestEditor()
rel := &models.Relationship{Name: "fk_a", FromTable: "users", ToTable: "orders"}
if se.CreateRelationship(9, 0, rel) != nil || se.CreateRelationship(0, 9, rel) != nil || se.CreateRelationship(0, -1, rel) != nil {
t.Error("create bad index")
}
// Before any relationship exists, update/delete/get/names report nothing.
se.db.Schemas[0].Tables[0].Relationships = nil
if se.UpdateRelationship(0, 0, "fk_a", rel) || se.DeleteRelationship(0, 0, "fk_a") ||
se.GetRelationship(0, 0, "fk_a") != nil || se.GetRelationshipNames(0, 0) != nil {
t.Error("nil map handling")
}
if se.CreateRelationship(0, 0, rel) != rel {
t.Fatal("create")
}
se.CreateRelationship(0, 0, &models.Relationship{Name: "fk_0"})
if got := se.GetRelationshipNames(0, 0); !reflect.DeepEqual(got, []string{"fk_0", "fk_a"}) {
t.Errorf("names must be sorted: %v", got)
}
if se.GetRelationship(0, 0, "fk_a") != rel || se.GetRelationship(0, 0, "none") != nil {
t.Error("get")
}
renamed := &models.Relationship{Name: "fk_b"}
if !se.UpdateRelationship(0, 0, "fk_a", renamed) {
t.Fatal("update")
}
if se.GetRelationship(0, 0, "fk_a") != nil || se.GetRelationship(0, 0, "fk_b") != renamed {
t.Error("rename")
}
if se.UpdateRelationship(9, 0, "x", renamed) || se.UpdateRelationship(0, 9, "x", renamed) {
t.Error("update bad index")
}
if se.DeleteRelationship(9, 0, "x") || se.DeleteRelationship(0, 9, "x") {
t.Error("delete bad index")
}
if !se.DeleteRelationship(0, 0, "fk_b") || se.GetRelationship(0, 0, "fk_b") != nil {
t.Error("delete")
}
if se.GetRelationship(9, 0, "x") != nil || se.GetRelationship(0, 9, "x") != nil ||
se.GetRelationshipNames(9, 0) != nil || se.GetRelationshipNames(0, 9) != nil {
t.Error("bad index reads")
}
}
func TestSchemaDataOps(t *testing.T) {
se := newTestEditor()
s := se.CreateSchema("sales", "desc")
if s == nil || s.Name != "sales" || s.Description != "desc" || s.Tables == nil || s.Sequences == nil || s.Enums == nil {
t.Fatalf("create: %+v", s)
}
if len(se.GetAllSchemas()) != 2 || se.GetSchema(1) != s || se.GetSchema(2) != nil || se.GetSchema(-1) != nil {
t.Error("get")
}
se.UpdateSchema(1, "billing", "owner", "d2")
if s.Name != "billing" || s.Owner != "owner" || s.Description != "d2" {
t.Errorf("update: %+v", s)
}
se.UpdateSchema(9, "x", "x", "x") // no panic
if se.DeleteSchema(9) || se.DeleteSchema(-1) {
t.Error("delete bad index")
}
if !se.DeleteSchema(1) || len(se.db.Schemas) != 1 {
t.Error("delete")
}
}
func TestTableDataOps(t *testing.T) {
se := newTestEditor()
if se.CreateTable(9, "x", "") != nil {
t.Error("create bad schema")
}
tbl := se.CreateTable(0, "orders", "d")
if tbl == nil || tbl.Schema != "public" || tbl.Columns == nil || tbl.Constraints == nil || tbl.Indexes == nil {
t.Fatalf("create: %+v", tbl)
}
if se.GetTable(0, 1) != tbl || se.GetTable(0, 2) != nil || se.GetTable(9, 0) != nil || se.GetTable(0, -1) != nil {
t.Error("get")
}
if len(se.GetAllTables()) != 2 || len(se.GetTablesInSchema(0)) != 2 || se.GetTablesInSchema(9) != nil {
t.Error("get all")
}
se.UpdateTable(0, 1, "orders2", "d2")
if tbl.Name != "orders2" || tbl.Description != "d2" {
t.Errorf("update: %+v", tbl)
}
se.UpdateTable(9, 0, "x", "x")
se.UpdateTable(0, 9, "x", "x")
if se.DeleteTable(9, 0) || se.DeleteTable(0, 9) {
t.Error("delete bad index")
}
if !se.DeleteTable(0, 1) || len(se.db.Schemas[0].Tables) != 1 {
t.Error("delete")
}
}
func TestUpdateDatabase(t *testing.T) {
se := newTestEditor()
se.updateDatabase("n", "d", "c", "pgsql", "16")
db := se.db
if db.Name != "n" || db.Description != "d" || db.Comment != "c" || db.DatabaseType != models.PostgresqlDatabaseType || db.DatabaseVersion != "16" {
t.Errorf("%+v", db)
}
}
func TestDomainDataOps(t *testing.T) {
se := NewSchemaEditor(models.InitDatabase("d"))
se.createDomain("a", "da")
se.createDomain("b", "db")
if len(se.db.Domains) != 2 || se.db.Domains[1].Sequence != 1 {
t.Fatalf("create: %+v", se.db.Domains)
}
se.updateDomain(0, "a2", "da2")
se.updateDomain(9, "x", "x")
if se.db.Domains[0].Name != "a2" || se.db.Domains[0].Description != "da2" {
t.Error("update")
}
se.deleteDomain(9)
se.deleteDomain(-1)
se.deleteDomain(0)
if len(se.db.Domains) != 1 || se.db.Domains[0].Name != "b" {
t.Errorf("delete: %+v", se.db.Domains)
}
}
+294
View File
@@ -0,0 +1,294 @@
package ui
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/rivo/tview"
"git.warky.dev/wdevs/relspecgo/pkg/models"
)
const uiFixtures = "../../tests/assets"
func newUIEditor() *SchemaEditor {
se := NewSchemaEditor(models.InitDatabase("start"))
se.db = newTestEditor().db
return se
}
func hasPage(se *SchemaEditor, name string) bool {
return se.pages.HasPage(name)
}
func TestSortedKeysAndColumnNames(t *testing.T) {
if got := sortedKeys(map[string]int{"b": 1, "a": 2, "c": 3}); strings.Join(got, ",") != "a,b,c" {
t.Errorf("sortedKeys: %v", got)
}
if got := sortedKeys[int](nil); len(got) != 0 {
t.Errorf("nil map: %v", got)
}
tbl := models.InitTable("t", "s")
tbl.Columns["z"] = models.InitColumn("z", "t", "s")
tbl.Columns["a"] = models.InitColumn("a", "t", "s")
if got := getColumnNames(tbl); strings.Join(got, ",") != "a,z" {
t.Errorf("getColumnNames: %v", got)
}
}
func TestLocations(t *testing.T) {
se := newTestEditor()
se.db.Schemas = append(se.db.Schemas, models.InitSchema("empty"))
sl := se.schemaLocations()
if len(sl) != 2 || sl[0].label != "public" || sl[1].schemaIndex != 1 || sl[0].tableIndex != -1 {
t.Errorf("schemaLocations: %+v", sl)
}
tl := se.tableLocations()
if len(tl) != 1 || tl[0].label != "public.users" || tl[0].schemaIndex != 0 || tl[0].tableIndex != 0 {
t.Errorf("tableLocations: %+v", tl)
}
}
func TestParseSkipTablesUI(t *testing.T) {
if got := parseSkipTablesUI(""); len(got) != 0 {
t.Errorf("empty: %v", got)
}
got := parseSkipTablesUI(" Users , ORDERS ,, ")
if len(got) != 2 || !got["users"] || !got["orders"] {
t.Errorf("got %v", got)
}
}
func TestHelpTexts(t *testing.T) {
for name, fn := range map[string]func() string{"load": getLoadHelpText, "save": getSaveHelpText, "import": getImportHelpText} {
if txt := fn(); !strings.Contains(txt, "dbml") && name != "save" || txt == "" {
t.Errorf("%s help text: %q", name, txt)
}
}
}
func TestObjectKinds(t *testing.T) {
se := newTestEditor()
if err := se.SaveIndex(0, 0, "", &models.Index{Name: "idx_e", Columns: []string{"email"}, Unique: true}); err != nil {
t.Fatal(err)
}
if err := se.SaveView(0, -1, &models.View{Name: "v1", Definition: "select 1"}); err != nil {
t.Fatal(err)
}
if err := se.SaveSequence(0, -1, &models.Sequence{Name: "s1", IncrementBy: 1, StartValue: 1}); err != nil {
t.Fatal(err)
}
if err := se.SaveScript(0, -1, &models.Script{Name: "sc1", SQL: "select 1"}); err != nil {
t.Fatal(err)
}
kinds := map[string]objectKind{
"indexes": se.indexKind(), "views": se.viewKind(), "sequences": se.sequenceKind(), "scripts": se.scriptKind(),
}
for page, k := range kinds {
t.Run(page, func(t *testing.T) {
if k.page != page || k.title == "" || k.singular == "" || len(k.headers) == 0 {
t.Fatalf("metadata: %+v", k)
}
rows := k.rows()
if len(rows) != 1 {
t.Fatalf("rows: %+v", rows)
}
for _, r := range rows {
if len(r.cells) != len(k.headers) {
t.Errorf("cells %v do not match headers %v", r.cells, k.headers)
}
}
if len(k.locations()) == 0 {
t.Error("no locations")
}
// Editing an existing row without changes keeps it valid.
form := tview.NewForm()
save := k.buildForm(form, &rows[0])
if form.GetFormItemCount() == 0 {
t.Error("no form fields")
}
loc := k.locations()[0]
loc.schemaIndex, loc.tableIndex = rows[0].schemaIndex, rows[0].tableIndex
if err := save(loc); err != nil {
t.Errorf("save unchanged: %v", err)
}
// A blank new form is rejected by validation.
blank := tview.NewForm()
saveBlank := k.buildForm(blank, nil)
if err := saveBlank(k.locations()[0]); err == nil {
t.Error("blank form accepted")
}
if !k.remove(rows[0]) || len(k.rows()) != 0 {
t.Error("remove failed")
}
})
}
}
func TestObjectKind_CreateIndexFromForm(t *testing.T) {
se := newTestEditor()
k := se.indexKind()
form := tview.NewForm()
save := k.buildForm(form, nil)
form.GetFormItemByLabel("Name").(*tview.InputField).SetText("idx_new")
form.GetFormItemByLabel("Columns (comma separated)").(*tview.InputField).SetText("id, email")
if err := save(k.locations()[0]); err != nil {
t.Fatal(err)
}
idx := se.db.Schemas[0].Tables[0].Indexes["idx_new"]
if idx == nil || len(idx.Columns) != 2 || idx.Type != "btree" {
t.Errorf("index: %+v", idx)
}
}
func TestLoadDatabase(t *testing.T) {
for _, tt := range []struct{ format, path string }{
{"dbml", "dbml/simple.dbml"}, {"json", "json/database.json"}, {"yaml", "yaml/database.yaml"},
{"drawdb", "drawdb/simple.json"}, {"dctx", "dctx/p1.dctx"}, {"graphql", "graphql/simple.graphql"},
{"prisma", "prisma/example.prisma"}, {"typeorm", "typeorm/example.ts"},
{"drizzle", "drizzle/schema.ts"}, {"gorm", "gorm/simple.go"}, {"bun", "bun/simple.go"},
} {
t.Run(tt.format, func(t *testing.T) {
se := newUIEditor()
se.loadDatabase(tt.format, filepath.Join(uiFixtures, tt.path), "")
if hasPage(se, "error-dialog") || !hasPage(se, "success-dialog") {
t.Fatalf("expected success dialog (pages: error=%v)", hasPage(se, "error-dialog"))
}
if se.loadConfig == nil || se.loadConfig.SourceType != tt.format || len(se.db.Schemas) == 0 {
t.Errorf("state: %+v db=%+v", se.loadConfig, se.db)
}
})
}
errCases := []struct {
name, format, path, conn string
}{
{"pgsql no conn", "pgsql", "", ""},
{"file required", "json", "", ""},
{"unsupported", "nope", "x", ""},
{"missing file", "json", filepath.Join(t.TempDir(), "missing.json"), ""},
}
for _, tt := range errCases {
t.Run(tt.name, func(t *testing.T) {
se := newUIEditor()
before := se.db
se.loadDatabase(tt.format, tt.path, tt.conn)
if !hasPage(se, "error-dialog") {
t.Error("expected error dialog")
}
if se.db != before || se.loadConfig != nil {
t.Error("state must be unchanged on error")
}
})
}
}
func TestCreateNewDatabase(t *testing.T) {
se := newUIEditor()
se.loadConfig = &LoadConfig{SourceType: "json"}
se.createNewDatabase()
if se.db.Name != "New Database" || len(se.db.Schemas) != 0 || se.loadConfig != nil || !hasPage(se, "success-dialog") {
t.Errorf("state: %+v", se.db)
}
}
func TestSaveDatabase(t *testing.T) {
for _, tt := range []struct{ format, file string }{
{"json", "o.json"}, {"yaml", "o.yaml"}, {"dbml", "o.dbml"}, {"drawdb", "o.drawdb.json"},
{"graphql", "o.graphql"}, {"prisma", "o.prisma"}, {"typeorm", "o.ts"}, {"drizzle", "d.ts"},
{"gorm", "g.go"}, {"bun", "b.go"},
} {
t.Run(tt.format, func(t *testing.T) {
se := newUIEditor()
out := filepath.Join(t.TempDir(), tt.file)
se.saveDatabase(tt.format, out)
if hasPage(se, "error-dialog") {
t.Fatal("unexpected error dialog")
}
if se.saveConfig == nil || se.saveConfig.FilePath != out || se.saveConfig.TargetType != tt.format {
t.Errorf("saveConfig: %+v", se.saveConfig)
}
if info, err := os.Stat(out); err != nil || info.Size() == 0 {
t.Errorf("output: %v", err)
}
})
}
for name, args := range map[string][2]string{
"pgsql unsupported": {"pgsql", "x.sql"},
"path required": {"json", ""},
"unknown format": {"nope", "x"},
} {
t.Run(name, func(t *testing.T) {
se := newUIEditor()
se.saveDatabase(args[0], args[1])
if !hasPage(se, "error-dialog") || se.saveConfig != nil {
t.Error("expected error dialog and no saveConfig")
}
})
}
}
func TestImportAndMerge(t *testing.T) {
se := newUIEditor()
se.importAndMergeDatabase("json", filepath.Join(uiFixtures, "json/database.json"), "", false, false, false, false, false, "")
if hasPage(se, "error-dialog") {
t.Fatal("unexpected error dialog")
}
for name, args := range map[string][3]string{
"pgsql no conn": {"pgsql", "", ""},
"file required": {"json", "", ""},
"unsupported": {"nope", "x", ""},
"missing file": {"json", filepath.Join(t.TempDir(), "missing.json"), ""},
} {
t.Run(name, func(t *testing.T) {
se := newUIEditor()
se.importAndMergeDatabase(args[0], args[1], args[2], false, false, false, false, false, "")
if !hasPage(se, "error-dialog") {
t.Error("expected error dialog")
}
})
}
}
func TestPerformMerge(t *testing.T) {
se := newUIEditor()
src := models.InitDatabase("src")
s := models.InitSchema("public")
tbl := models.InitTable("orders", "public")
tbl.Columns["id"] = models.InitColumn("id", "orders", "public")
skip := models.InitTable("skipme", "public")
s.Tables = append(s.Tables, tbl, skip)
src.Schemas = append(src.Schemas, s)
se.performMerge(src, false, false, false, false, false, "SkipMe")
if !hasPage(se, "success-dialog") {
t.Error("expected success dialog")
}
names := map[string]bool{}
for _, tb := range se.db.Schemas[0].Tables {
names[tb.Name] = true
}
if !names["users"] || !names["orders"] || names["skipme"] || len(names) != 2 {
t.Errorf("tables after merge: %v", names)
}
}
func TestEditorAccessors(t *testing.T) {
db := models.InitDatabase("d")
lc, sc := &LoadConfig{SourceType: "json"}, &SaveConfig{TargetType: "yaml"}
se := NewSchemaEditorWithConfigs(db, lc, sc)
if se.GetDatabase() != db || se.loadConfig != lc || se.saveConfig != sc || se.app == nil || se.pages == nil {
t.Errorf("%+v", se)
}
if se.createMainMenu() == nil {
t.Error("main menu")
}
}
+113
View File
@@ -0,0 +1,113 @@
package ui
import (
"testing"
"git.warky.dev/wdevs/relspecgo/pkg/models"
)
// richEditor returns an editor whose database has one of every object the screens render.
func richEditor(t *testing.T) *SchemaEditor {
t.Helper()
se := NewSchemaEditor(newTestEditor().db)
db := se.db
tbl := db.Schemas[0].Tables[0]
col := tbl.Columns["id"]
col.Type, col.IsPrimaryKey, col.NotNull = "integer", true, true
tbl.Relationships["fk_self"] = &models.Relationship{Name: "fk_self", FromTable: "users", ToTable: "users", FromColumns: []string{"id"}, ToColumns: []string{"id"}}
se.createDomainNoUI("core")
if err := se.AssignTableToDomain(0, "public", "users"); err != nil {
t.Fatal(err)
}
_ = se.SaveIndex(0, 0, "", &models.Index{Name: "idx_e", Columns: []string{"email"}})
_ = se.SaveView(0, -1, &models.View{Name: "v", Definition: "select 1"})
_ = se.SaveSequence(0, -1, &models.Sequence{Name: "s", IncrementBy: 1, StartValue: 1})
_ = se.SaveScript(0, -1, &models.Script{Name: "sc", SQL: "select 1"})
return se
}
// TestScreensRender builds every screen and dialog against a populated database
// and checks that none panics and that each registers a page.
func TestScreensRender(t *testing.T) {
col := func(se *SchemaEditor) *models.Column { return se.db.Schemas[0].Tables[0].Columns["id"] }
cases := []struct {
name string
page string
run func(se *SchemaEditor)
}{
{"schema list", "schemas", func(se *SchemaEditor) { se.showSchemaList() }},
{"schema editor", "schema-editor", func(se *SchemaEditor) { se.showSchemaEditor(0, se.db.Schemas[0]) }},
{"new schema", "new-schema", func(se *SchemaEditor) { se.showNewSchemaDialog() }},
{"edit schema", "edit-schema", func(se *SchemaEditor) { se.showEditSchemaDialog(0) }},
{"table list", "tables", func(se *SchemaEditor) { se.showTableList() }},
{"table editor", "table-editor", func(se *SchemaEditor) { se.showTableEditor(0, 0, se.db.Schemas[0].Tables[0]) }},
{"new table", "new-table", func(se *SchemaEditor) { se.showNewTableDialog(0) }},
{"new table from list", "new-table-from-list", func(se *SchemaEditor) { se.showNewTableDialogFromList() }},
{"edit table", "edit-table", func(se *SchemaEditor) { se.showEditTableDialog(0, 0) }},
{"column editor", "column-editor", func(se *SchemaEditor) { se.showColumnEditor(0, 0, 0, col(se)) }},
{"new column", "new-column", func(se *SchemaEditor) { se.showNewColumnDialog(0, 0) }},
{"relationship list", "relationships", func(se *SchemaEditor) { se.showRelationshipList(0, 0) }},
{"new relationship", "new-relationship", func(se *SchemaEditor) { se.showNewRelationshipDialog(0, 0) }},
{"edit relationship", "edit-relationship", func(se *SchemaEditor) { se.showEditRelationshipDialog(0, 0, "fk_self") }},
{"delete relationship", "delete-relationship-confirm", func(se *SchemaEditor) { se.showDeleteRelationshipConfirm(0, 0, "fk_self") }},
{"domain list", "domains", func(se *SchemaEditor) { se.showDomainList() }},
{"new domain", "new-domain", func(se *SchemaEditor) { se.showNewDomainDialog() }},
{"domain editor", "edit-domain", func(se *SchemaEditor) { se.showDomainEditor(0, se.db.Domains[0]) }},
{"delete domain", "delete-domain-confirm", func(se *SchemaEditor) { se.showDeleteDomainConfirm(0) }},
{"domain tables", "domain-tables", func(se *SchemaEditor) { se.showDomainTables(0) }},
{"assign domain table", "assign-domain-table", func(se *SchemaEditor) { se.showAssignDomainTable(0, func() {}) }},
{"edit database", "edit-database", func(se *SchemaEditor) { se.showEditDatabaseForm() }},
{"exit confirm", "exit-confirm", func(se *SchemaEditor) { se.showExitConfirmation("a", "main") }},
{"exit editor confirm", "exit-editor-confirm", func(se *SchemaEditor) { se.showExitEditorConfirm() }},
{"delete schema confirm", "confirm-delete-schema", func(se *SchemaEditor) { se.showDeleteSchemaConfirm(0) }},
{"delete table confirm", "confirm-delete-table", func(se *SchemaEditor) { se.showDeleteTableConfirm(0, 0) }},
{"delete column confirm", "confirm-delete-column", func(se *SchemaEditor) { se.showDeleteColumnConfirm(0, 0, "id") }},
{"load screen", "load-database", func(se *SchemaEditor) { se.showLoadScreen() }},
{"save screen", "save-database", func(se *SchemaEditor) { se.showSaveScreen() }},
{"import screen", "import-database", func(se *SchemaEditor) { se.showImportScreen() }},
{"update existing confirm", "update-confirm", func(se *SchemaEditor) {
se.loadConfig = &LoadConfig{SourceType: "json", FilePath: "x.json"}
se.showUpdateExistingDatabaseConfirm()
}},
{"import confirm", "import-confirm", func(se *SchemaEditor) {
se.showImportConfirmation(models.InitDatabase("src"), false, false, false, false, false, "")
}},
{"conn builder", "", func(se *SchemaEditor) { se.showConnStringBuilder("", "", "main", func(string) {}) }},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
se := richEditor(t)
before := len(se.pages.GetPageNames(false))
defer func() {
if r := recover(); r != nil {
t.Fatalf("panic: %v", r)
}
}()
tt.run(se)
if tt.page != "" && !se.pages.HasPage(tt.page) {
t.Errorf("page %q not registered; pages: %v", tt.page, se.pages.GetPageNames(false))
}
if tt.page == "" && len(se.pages.GetPageNames(false)) <= before {
t.Error("no page added")
}
})
}
}
func TestObjectScreensRender(t *testing.T) {
se := richEditor(t)
for name, k := range map[string]objectKind{
"indexes": se.indexKind(), "views": se.viewKind(), "sequences": se.sequenceKind(), "scripts": se.scriptKind(),
} {
t.Run(name, func(t *testing.T) {
se.showObjectList(k)
if !se.pages.HasPage(k.page) {
t.Errorf("list page %q missing; pages: %v", k.page, se.pages.GetPageNames(false))
}
rows := k.rows()
se.showObjectForm(k, nil)
se.showObjectForm(k, &rows[0])
})
}
}