package web_test import ( "context" "net/url" "strings" "testing" "time" ) // TestDashboardPinTogglesItem seeds an item with pinned=false, POSTs to // /dashboard/pin with pin=true, then asserts the row in projax.items is // now pinned and the Tiles view renders the tile with the .pinned class. func TestDashboardPinTogglesItem(t *testing.T) { srv, pool := mustServer(t) defer pool.Close() h := srv.Routes() ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() stamp := strings.ReplaceAll(time.Now().UTC().Format("150405.000000"), ".", "") slug := "pin-target-" + stamp var dev, id string if err := pool.QueryRow(ctx, `select id from projax.items where slug='dev' and cardinality(parent_ids)=0`).Scan(&dev); err != nil { t.Fatalf("dev: %v", err) } if err := pool.QueryRow(ctx, `insert into projax.items (kind, title, slug, parent_ids) values (array['project']::text[], 'pin target', $1, ARRAY[$2]::uuid[]) returning id`, slug, dev, ).Scan(&id); err != nil { t.Fatalf("seed item: %v", err) } defer pool.Exec(context.Background(), `delete from projax.items where id=$1`, id) // POST pin=true. form := url.Values{"id": {id}, "pin": {"true"}} code, _ := post(t, h, "/dashboard/pin", form) if code != 200 { t.Fatalf("POST /dashboard/pin → %d", code) } var pinned bool if err := pool.QueryRow(ctx, `select pinned from projax.items where id=$1`, id).Scan(&pinned); err != nil { t.Fatalf("read pinned: %v", err) } if !pinned { t.Errorf("expected pinned=true after POST") } // The re-render should mark the tile as .tile-pinned. _, body := get(t, h, "/views/dashboard") tileIdx := strings.Index(body, `data-item-id="`+id+`"`) if tileIdx < 0 { t.Fatalf("pinned tile not found in re-render") } openTag := body[strings.LastIndex(body[:tileIdx], "