diff --git a/.changeset/fix-flat-taxonomy-term-description.md b/.changeset/fix-flat-taxonomy-term-description.md new file mode 100644 index 000000000..8208341e3 --- /dev/null +++ b/.changeset/fix-flat-taxonomy-term-description.md @@ -0,0 +1,11 @@ +--- +"emdash": patch +--- + +`getTaxonomyTerms()` now returns the term `description` for flat +(non-hierarchical) taxonomies (#1419) + +The query already fetched the `data` column, but the non-hierarchical branch +dropped it when mapping rows to `TaxonomyTerm` — only hierarchical taxonomies +(via `buildTree`) parsed the description. Descriptions set in the admin UI are +now returned for both kinds of taxonomies. diff --git a/packages/core/src/taxonomies/index.ts b/packages/core/src/taxonomies/index.ts index 38865d170..6d3ee776a 100644 --- a/packages/core/src/taxonomies/index.ts +++ b/packages/core/src/taxonomies/index.ts @@ -148,6 +148,7 @@ export async function getTaxonomyTerms( name: term.name, slug: term.slug, label: term.label, + description: term.data ? JSON.parse(term.data).description : undefined, children: [], count: counts.get(term.translation_group ?? term.id) ?? 0, locale: term.locale, diff --git a/packages/core/tests/unit/taxonomies/get-taxonomy-terms.test.ts b/packages/core/tests/unit/taxonomies/get-taxonomy-terms.test.ts new file mode 100644 index 000000000..f1feaa930 --- /dev/null +++ b/packages/core/tests/unit/taxonomies/get-taxonomy-terms.test.ts @@ -0,0 +1,67 @@ +import { afterEach, beforeEach, expect, it, vi } from "vitest"; + +import { TaxonomyRepository } from "../../../src/database/repositories/taxonomy.js"; +import { + describeEachDialect, + setupForDialectWithCollections, + teardownForDialect, + type DialectTestContext, +} from "../../utils/test-db.js"; + +// Mock loader.getDb so the runtime taxonomy functions read from our test db. +vi.mock("../../../src/loader.js", () => ({ + getDb: vi.fn(), +})); + +import { getDb } from "../../../src/loader.js"; +import { getTaxonomyTerms, invalidateTermCache } from "../../../src/taxonomies/index.js"; + +describeEachDialect("getTaxonomyTerms", (dialect) => { + let ctx: DialectTestContext; + let taxRepo: TaxonomyRepository; + + beforeEach(async () => { + ctx = await setupForDialectWithCollections(dialect); + taxRepo = new TaxonomyRepository(ctx.db); + vi.mocked(getDb).mockResolvedValue(ctx.db); + invalidateTermCache(); + }); + + afterEach(async () => { + invalidateTermCache(); + await teardownForDialect(ctx); + vi.restoreAllMocks(); + }); + + it("includes the description for flat (non-hierarchical) taxonomies", async () => { + // `tag` is seeded as non-hierarchical. + await taxRepo.create({ + name: "tag", + slug: "longevity", + label: "Longevity", + data: { description: "Healthy aging. wikidata:Q380274" }, + }); + await taxRepo.create({ name: "tag", slug: "wellness", label: "Wellness" }); + + const terms = await getTaxonomyTerms("tag"); + + expect(terms.map((t) => t.slug)).toEqual(["longevity", "wellness"]); + expect(terms[0].description).toBe("Healthy aging. wikidata:Q380274"); + expect(terms[1].description).toBeUndefined(); + }); + + it("includes the description for hierarchical taxonomies (control)", async () => { + // `category` is seeded as hierarchical. + await taxRepo.create({ + name: "category", + slug: "tech", + label: "Technology", + data: { description: "All things tech" }, + }); + + const terms = await getTaxonomyTerms("category"); + + expect(terms).toHaveLength(1); + expect(terms[0].description).toBe("All things tech"); + }); +});