package webui import ( "strings" "testing" ) // What a table renders on the SERVER, in each of the three shapes. The distinction // exists because a saved layout lives in localStorage, which the server cannot read: // // - no persistence -> nothing can arrive late. Render in full. (default) // - persistence -> a skeleton, until the client says what the layout is. // - persistence + ShowWhile.. -> render the DECLARED table at once, and accept that // the client may rearrange it (the flash). func ssrTable(t *testing.T, cols AutoTableColumnOptions) string { t.Helper() s := NewAutoTableState([]AutoTableColumn{ {Key: "name", DisplayName: "Client", SortIdentifier: "Name"}, }, AutoTableStateOptions{Columns: cols}) s.SetRows([]any{calcRec{"Ada", "100", "40"}}) return renderNode(s.Render()) } // A plain, static table — no personalisation — must server-render its CONTENT. This // is the common case and it must not pay for a feature it does not use. func TestStaticTableServerRendersInFull(t *testing.T) { html := ssrTable(t, AutoTableColumnOptions{}) if !strings.Contains(html, "Client") { t.Errorf("a table with no persistence must SSR its content:\n%s", html) } if strings.Contains(html, `aria-busy="true"`) { t.Error("a table with no persistence rendered a skeleton — it has nothing to wait for") } } // Turn persistence on and the server no longer knows the layout, so it holds a // skeleton rather than showing a table that is about to rearrange itself. func TestPersistedTableHoldsASkeletonUntilTheLayoutSettles(t *testing.T) { html := ssrTable(t, AutoTableColumnOptions{StorageKey: "k"}) if !strings.Contains(html, `aria-busy="true"`) { t.Errorf("a persisted table should hold a skeleton on the server:\n%s", html) } if strings.Contains(html, "Client") { t.Error("it rendered table content — a user with a saved layout would watch it rearrange") } } // ...unless the caller says it would rather have the content and accept the flash. func TestShowWhileRestoringServerRendersInFull(t *testing.T) { html := ssrTable(t, AutoTableColumnOptions{StorageKey: "k", ShowWhileRestoring: true}) if !strings.Contains(html, "Client") { t.Errorf("ShowWhileRestoring must SSR the declared table:\n%s", html) } if strings.Contains(html, `aria-busy="true"`) { t.Error("ShowWhileRestoring rendered a skeleton anyway") } } // And once the layout has settled, a persisted table renders normally. func TestPersistedTableRevealsAfterRestore(t *testing.T) { s := NewAutoTableState([]AutoTableColumn{ {Key: "name", DisplayName: "Client", SortIdentifier: "Name"}, }, AutoTableStateOptions{Columns: AutoTableColumnOptions{StorageKey: "k"}}) s.SetRows([]any{calcRec{"Ada", "100", "40"}}) if s.LayoutSettled() { t.Fatal("a persisted table should not start settled") } s.RestoreLayout() // nothing to restore here; it just settles if !s.LayoutSettled() { t.Fatal("RestoreLayout did not settle the layout") } if html := renderNode(s.Render()); !strings.Contains(html, "Client") { t.Errorf("the table did not reveal after restore:\n%s", html) } }