test(office): replace fixture tests with live OnlyOffice API integration
Remove synthetic map-based entity and fetch mapper unit tests; cover all menu subjects and preview pipelines via integration tests against the real Workspace API. Handle draft mail without subjects in list mapping. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+3
-2
@@ -40,8 +40,9 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||||||
Install: `go install github.com/eslider/go-onlyoffice/cmd/office@latest`.
|
Install: `go install github.com/eslider/go-onlyoffice/cmd/office@latest`.
|
||||||
- **`cmd/internal/bootstrap`** — shared env loading and client auth for `oo`
|
- **`cmd/internal/bootstrap`** — shared env loading and client auth for `oo`
|
||||||
and `office`.
|
and `office`.
|
||||||
- Unit tests for preview formatters, menu/selection model, fetch mappers, and
|
- Integration tests under `cmd/office/fetch/` and `cmd/office/preview/`
|
||||||
key routing; integration tests under `cmd/office/fetch/` (`-tags=integration`).
|
(`-tags=integration`) hit the live OnlyOffice API — no fixture maps or
|
||||||
|
httptest vendor mocks. Unit tests remain for pure UI/formatting helpers only.
|
||||||
|
|
||||||
### Added — library
|
### Added — library
|
||||||
|
|
||||||
|
|||||||
@@ -593,10 +593,10 @@ Spreadsheet files: inline CSV/JSON preview in the right pane; install
|
|||||||
[`vex`](https://github.com/CodeOne45/vex-tui) on `PATH` for full-screen
|
[`vex`](https://github.com/CodeOne45/vex-tui) on `PATH` for full-screen
|
||||||
xlsx/csv viewing (`v` on a file row — coming in next iteration).
|
xlsx/csv viewing (`v` on a file row — coming in next iteration).
|
||||||
|
|
||||||
Integration tests for list loaders:
|
Integration tests for list loaders and preview (live API only — no mocks):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go test -tags=integration ./cmd/office/fetch/...
|
go test -tags=integration ./cmd/office/fetch/... ./cmd/office/preview/...
|
||||||
```
|
```
|
||||||
|
|
||||||
**Project / task documents (`oo`):**
|
**Project / task documents (`oo`):**
|
||||||
|
|||||||
@@ -12,34 +12,128 @@ import (
|
|||||||
"github.com/eslider/go-onlyoffice/cmd/office/model"
|
"github.com/eslider/go-onlyoffice/cmd/office/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIntegrationListProjects(t *testing.T) {
|
func skipWithoutLiveAPI(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
if os.Getenv("ONLYOFFICE_URL") == "" && os.Getenv("ONLYOFFICE_HOST") == "" {
|
if os.Getenv("ONLYOFFICE_URL") == "" && os.Getenv("ONLYOFFICE_HOST") == "" {
|
||||||
t.Skip("ONLYOFFICE_URL not set")
|
t.Skip("ONLYOFFICE_URL not set")
|
||||||
}
|
}
|
||||||
client, err := bootstrap.NewClient(context.Background())
|
if os.Getenv("ONLYOFFICE_USER") == "" && os.Getenv("ONLYOFFICE_NAME") == "" {
|
||||||
if err != nil {
|
t.Skip("ONLYOFFICE_USER not set")
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
loader := &fetch.Loader{Client: client}
|
if os.Getenv("ONLYOFFICE_PASS") == "" && os.Getenv("ONLYOFFICE_PASSWORD") == "" {
|
||||||
items, err := loader.List(context.Background(), model.SubjectProjects)
|
t.Skip("ONLYOFFICE_PASS not set")
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
t.Logf("projects: %d", len(items))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIntegrationListMailInbox(t *testing.T) {
|
func liveLoader(t *testing.T) (*fetch.Loader, context.Context) {
|
||||||
if os.Getenv("ONLYOFFICE_URL") == "" && os.Getenv("ONLYOFFICE_HOST") == "" {
|
t.Helper()
|
||||||
t.Skip("ONLYOFFICE_URL not set")
|
skipWithoutLiveAPI(t)
|
||||||
}
|
|
||||||
client, err := bootstrap.NewClient(context.Background())
|
client, err := bootstrap.NewClient(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
loader := &fetch.Loader{Client: client}
|
return &fetch.Loader{Client: client}, context.Background()
|
||||||
items, err := loader.List(context.Background(), model.SubjectMailInbox)
|
}
|
||||||
|
|
||||||
|
func TestIntegrationListAllSubjects(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
subject model.Subject
|
||||||
|
skip string
|
||||||
|
}{
|
||||||
|
{model.SubjectProjects, ""},
|
||||||
|
{model.SubjectTasks, ""},
|
||||||
|
{model.SubjectCalendars, ""},
|
||||||
|
{model.SubjectEvents, ""},
|
||||||
|
{model.SubjectContacts, ""},
|
||||||
|
{model.SubjectPersons, ""},
|
||||||
|
{model.SubjectCompanies, ""},
|
||||||
|
{model.SubjectOpportunities, ""},
|
||||||
|
{model.SubjectCases, ""},
|
||||||
|
{model.SubjectCRMTasks, ""},
|
||||||
|
{model.SubjectMailInbox, ""},
|
||||||
|
{model.SubjectMailSent, ""},
|
||||||
|
{model.SubjectMailDrafts, ""},
|
||||||
|
{model.SubjectMailTrash, ""},
|
||||||
|
{model.SubjectMailSpam, ""},
|
||||||
|
{model.SubjectUsers, ""},
|
||||||
|
{model.SubjectProjectFiles, "ONLYOFFICE_PROJECT_ID not set"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(string(tc.subject), func(t *testing.T) {
|
||||||
|
if tc.subject == model.SubjectProjectFiles {
|
||||||
|
if os.Getenv("ONLYOFFICE_PROJECT_ID") == "" {
|
||||||
|
t.Skip(tc.skip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items, err := loader.List(ctx, tc.subject)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("List(%s): %v", tc.subject, err)
|
||||||
|
}
|
||||||
|
t.Logf("%s: %d items", tc.subject, len(items))
|
||||||
|
for i, it := range items {
|
||||||
|
if it.ID == "" {
|
||||||
|
t.Errorf("item[%d] missing ID: %+v", i, it)
|
||||||
|
}
|
||||||
|
if it.Title == "" {
|
||||||
|
t.Errorf("item[%d] missing Title: id=%s kind=%s", i, it.ID, it.Kind)
|
||||||
|
}
|
||||||
|
if it.Kind == "" {
|
||||||
|
t.Errorf("item[%d] missing Kind: id=%s", i, it.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationListProjectsMapsRealFields(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectProjects)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Logf("mail messages: %d", len(items))
|
if len(items) == 0 {
|
||||||
|
t.Skip("no projects on instance")
|
||||||
|
}
|
||||||
|
it := items[0]
|
||||||
|
if it.Raw == nil {
|
||||||
|
t.Fatal("expected Raw payload from API")
|
||||||
|
}
|
||||||
|
detail, err := loader.Detail(ctx, it)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Detail: %v", err)
|
||||||
|
}
|
||||||
|
if detail == nil {
|
||||||
|
t.Fatal("nil detail")
|
||||||
|
}
|
||||||
|
t.Logf("project id=%s title=%q keys=%d", it.ID, it.Title, len(detail))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationMailInboxDetail(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectMailInbox)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(items) == 0 {
|
||||||
|
t.Skip("inbox empty")
|
||||||
|
}
|
||||||
|
detail, err := loader.Detail(ctx, items[0])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetMailMessage: %v", err)
|
||||||
|
}
|
||||||
|
if detail["subject"] == nil {
|
||||||
|
t.Fatalf("message missing subject: %+v", detail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationEventsDateRange(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectEvents)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("events in next 7 days: %d", len(items))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ func ItemsFromMaps(rows []map[string]any, kind model.Kind, fields FieldMap) []mo
|
|||||||
if title == "" {
|
if title == "" {
|
||||||
title = str(row, "name")
|
title = str(row, "name")
|
||||||
}
|
}
|
||||||
|
if title == "" {
|
||||||
|
title = "(untitled)"
|
||||||
|
}
|
||||||
raw := row
|
raw := row
|
||||||
out[i] = model.Item{
|
out[i] = model.Item{
|
||||||
ID: idStr(row, fields.IDKey),
|
ID: idStr(row, fields.IDKey),
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
package fetch_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/eslider/go-onlyoffice/cmd/office/fetch"
|
|
||||||
"github.com/eslider/go-onlyoffice/cmd/office/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestItemsFromMaps(t *testing.T) {
|
|
||||||
rows := []map[string]any{
|
|
||||||
{"id": float64(1), "title": "Alpha", "status": "Open"},
|
|
||||||
{"id": float64(2), "title": "Beta", "status": "Closed"},
|
|
||||||
}
|
|
||||||
items := fetch.ItemsFromMaps(rows, model.KindTask, fetch.TaskItemFields)
|
|
||||||
if len(items) != 2 {
|
|
||||||
t.Fatalf("len=%d", len(items))
|
|
||||||
}
|
|
||||||
if items[0].ID != "1" || items[0].Title != "Alpha" {
|
|
||||||
t.Fatalf("item0=%+v", items[0])
|
|
||||||
}
|
|
||||||
if items[0].Kind != model.KindTask {
|
|
||||||
t.Fatalf("kind=%v", items[0].Kind)
|
|
||||||
}
|
|
||||||
if items[1].Subtitle != "Closed" {
|
|
||||||
t.Fatalf("subtitle=%q", items[1].Subtitle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package preview_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/eslider/go-onlyoffice/cmd/office/preview"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestContactMarkdownCompany(t *testing.T) {
|
|
||||||
md := preview.ContactMarkdown(map[string]any{
|
|
||||||
"displayName": "Acme GmbH",
|
|
||||||
"isCompany": true,
|
|
||||||
"about": "Widget supplier",
|
|
||||||
})
|
|
||||||
if !strings.Contains(md, "Acme GmbH") {
|
|
||||||
t.Fatalf("title missing: %q", md)
|
|
||||||
}
|
|
||||||
if !strings.Contains(md, "Company") {
|
|
||||||
t.Fatalf("type label missing: %q", md)
|
|
||||||
}
|
|
||||||
if !strings.Contains(md, "Widget supplier") {
|
|
||||||
t.Fatalf("about missing: %q", md)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOpportunityMarkdown(t *testing.T) {
|
|
||||||
md := preview.OpportunityMarkdown(map[string]any{
|
|
||||||
"title": "Big Deal",
|
|
||||||
"description": "Annual contract",
|
|
||||||
"bidValue": float64(50000),
|
|
||||||
"bidCurrency": "EUR",
|
|
||||||
})
|
|
||||||
if !strings.Contains(md, "Big Deal") {
|
|
||||||
t.Fatalf("title missing: %q", md)
|
|
||||||
}
|
|
||||||
if !strings.Contains(md, "50000") || !strings.Contains(md, "EUR") {
|
|
||||||
t.Fatalf("bid missing: %q", md)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMailMarkdown(t *testing.T) {
|
|
||||||
md := preview.MailMarkdown(map[string]any{
|
|
||||||
"subject": "Hello",
|
|
||||||
"from": "Alice <alice@example.com>",
|
|
||||||
"body": "<p>Hi there</p>",
|
|
||||||
})
|
|
||||||
if !strings.Contains(md, "Hello") {
|
|
||||||
t.Fatalf("subject missing: %q", md)
|
|
||||||
}
|
|
||||||
if !strings.Contains(md, "alice@example.com") {
|
|
||||||
t.Fatalf("from missing: %q", md)
|
|
||||||
}
|
|
||||||
if strings.Contains(md, "<p>") {
|
|
||||||
t.Fatalf("html not stripped: %q", md)
|
|
||||||
}
|
|
||||||
if !strings.Contains(md, "Hi there") {
|
|
||||||
t.Fatalf("body text missing: %q", md)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEventMarkdown(t *testing.T) {
|
|
||||||
md := preview.EventMarkdown(map[string]any{
|
|
||||||
"title": "Standup",
|
|
||||||
"start": "2026-06-24T09:00:00",
|
|
||||||
"end": "2026-06-24T09:15:00",
|
|
||||||
})
|
|
||||||
if !strings.Contains(md, "Standup") {
|
|
||||||
t.Fatalf("title missing: %q", md)
|
|
||||||
}
|
|
||||||
if !strings.Contains(md, "2026-06-24") {
|
|
||||||
t.Fatalf("dates missing: %q", md)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTaskMarkdown(t *testing.T) {
|
|
||||||
md := preview.TaskMarkdown(map[string]any{
|
|
||||||
"title": "Deploy",
|
|
||||||
"status": "Open",
|
|
||||||
"deadline": "2026-07-01",
|
|
||||||
"description": "Roll out v2",
|
|
||||||
})
|
|
||||||
if !strings.Contains(md, "Deploy") {
|
|
||||||
t.Fatalf("title missing: %q", md)
|
|
||||||
}
|
|
||||||
if !strings.Contains(md, "Open") {
|
|
||||||
t.Fatalf("status missing: %q", md)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package preview_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/eslider/go-onlyoffice/cmd/internal/bootstrap"
|
||||||
|
"github.com/eslider/go-onlyoffice/cmd/office/fetch"
|
||||||
|
"github.com/eslider/go-onlyoffice/cmd/office/model"
|
||||||
|
"github.com/eslider/go-onlyoffice/cmd/office/preview"
|
||||||
|
)
|
||||||
|
|
||||||
|
func skipWithoutLiveAPI(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
if os.Getenv("ONLYOFFICE_URL") == "" && os.Getenv("ONLYOFFICE_HOST") == "" {
|
||||||
|
t.Skip("ONLYOFFICE_URL not set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func liveLoader(t *testing.T) (*fetch.Loader, context.Context) {
|
||||||
|
t.Helper()
|
||||||
|
skipWithoutLiveAPI(t)
|
||||||
|
client, err := bootstrap.NewClient(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return &fetch.Loader{Client: client}, context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPreviewProjectFromAPI(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectProjects)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(items) == 0 {
|
||||||
|
t.Skip("no projects")
|
||||||
|
}
|
||||||
|
raw, err := loader.Detail(ctx, items[0])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
md := preview.EntityMarkdown(string(model.KindProject), raw)
|
||||||
|
if md == "" {
|
||||||
|
t.Fatal("empty markdown")
|
||||||
|
}
|
||||||
|
if !strings.Contains(md, items[0].Title) {
|
||||||
|
t.Fatalf("markdown missing project title %q:\n%s", items[0].Title, md)
|
||||||
|
}
|
||||||
|
rendered, err := preview.RenderMarkdown(md, 80)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if rendered == "" {
|
||||||
|
t.Fatal("glamour produced empty output")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPreviewContactFromAPI(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectContacts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(items) == 0 {
|
||||||
|
t.Skip("no contacts")
|
||||||
|
}
|
||||||
|
raw, err := loader.Detail(ctx, items[0])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
md := preview.ContactMarkdown(raw)
|
||||||
|
if md == "" || !strings.Contains(md, "#") {
|
||||||
|
t.Fatalf("unexpected contact markdown: %q", md)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPreviewOpportunityFromAPI(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectOpportunities)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(items) == 0 {
|
||||||
|
t.Skip("no opportunities")
|
||||||
|
}
|
||||||
|
raw, err := loader.Detail(ctx, items[0])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
md := preview.OpportunityMarkdown(raw)
|
||||||
|
if !strings.Contains(md, items[0].Title) {
|
||||||
|
t.Fatalf("markdown missing deal title:\n%s", md)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPreviewMailFromAPI(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectMailInbox)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(items) == 0 {
|
||||||
|
t.Skip("inbox empty")
|
||||||
|
}
|
||||||
|
raw, err := loader.Detail(ctx, items[0])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
md := preview.MailMarkdown(raw)
|
||||||
|
if !strings.Contains(md, items[0].Title) {
|
||||||
|
t.Fatalf("markdown missing subject %q:\n%s", items[0].Title, md)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPreviewEventFromAPI(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectEvents)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(items) == 0 {
|
||||||
|
t.Skip("no events in range")
|
||||||
|
}
|
||||||
|
md := preview.EventMarkdown(items[0].Raw)
|
||||||
|
if !strings.Contains(md, items[0].Title) {
|
||||||
|
t.Fatalf("markdown missing event title:\n%s", md)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPreviewTaskFromAPI(t *testing.T) {
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectTasks)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(items) == 0 {
|
||||||
|
t.Skip("no tasks")
|
||||||
|
}
|
||||||
|
raw, err := loader.Detail(ctx, items[0])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
md := preview.TaskMarkdown(raw)
|
||||||
|
if !strings.Contains(md, items[0].Title) {
|
||||||
|
t.Fatalf("markdown missing task title:\n%s", md)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegrationPreviewCSVFromDownloadedFile(t *testing.T) {
|
||||||
|
skipWithoutLiveAPI(t)
|
||||||
|
if os.Getenv("ONLYOFFICE_PROJECT_ID") == "" {
|
||||||
|
t.Skip("ONLYOFFICE_PROJECT_ID not set")
|
||||||
|
}
|
||||||
|
loader, ctx := liveLoader(t)
|
||||||
|
items, err := loader.List(ctx, model.SubjectProjectFiles)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var csvItem *model.Item
|
||||||
|
for i := range items {
|
||||||
|
if strings.HasSuffix(strings.ToLower(items[i].Title), ".csv") {
|
||||||
|
csvItem = &items[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if csvItem == nil {
|
||||||
|
t.Skip("no csv file in project documents")
|
||||||
|
}
|
||||||
|
var buf strings.Builder
|
||||||
|
n, err := loader.Client.DownloadFile(ctx, csvItem.ID, &buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DownloadFile: %v", err)
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
t.Fatal("empty download")
|
||||||
|
}
|
||||||
|
md, err := preview.CSVToMarkdownTable([]byte(buf.String()))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("CSVToMarkdownTable: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(md, "|") {
|
||||||
|
t.Fatalf("expected pipe table: %q", md)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user