From 240d7f5472ce1c843128ba028a9fe3f70efc8dfd Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Mon, 13 Oct 2025 14:00:32 +0530 Subject: [PATCH 01/13] feat: Implement Taxonomy class and update TaxonomyQuery for enhanced taxonomy management --- src/index.ts | 1 + src/lib/stack.ts | 8 +++++++- src/lib/taxonomy-query.ts | 35 ++++++++++++++++++++++++++++------- src/lib/taxonomy.ts | 23 +++++++++++++++++++++++ test/api/taxonomy.spec.ts | 22 ++++++++++++++++++++++ test/api/types.ts | 17 +++++++++++++++++ test/unit/taxonomy.spec.ts | 26 ++++++++++++++++++++++++++ test/utils/mocks.ts | 26 +++++++++++++++++++++++++- 8 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 src/lib/taxonomy.ts create mode 100644 test/api/taxonomy.spec.ts create mode 100644 test/unit/taxonomy.spec.ts diff --git a/src/index.ts b/src/index.ts index d108292b..704c9bde 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,5 +11,6 @@ export type { ImageTransform } from './lib/image-transform'; export type { AssetQuery } from './lib/asset-query'; export type { TaxonomyQuery } from './lib/taxonomy-query'; export type { ContentTypeQuery } from './lib/contenttype-query'; +export type { Taxonomy } from './lib/taxonomy'; export default contentstack; diff --git a/src/lib/stack.ts b/src/lib/stack.ts index 324533d5..815697d2 100644 --- a/src/lib/stack.ts +++ b/src/lib/stack.ts @@ -8,6 +8,7 @@ import { synchronization } from './synchronization'; import {TaxonomyQuery} from './taxonomy-query'; import { GlobalFieldQuery } from './global-field-query'; import { GlobalField } from './global-field'; +import { Taxonomy } from './taxonomy'; export class Stack { readonly config: StackConfig; @@ -27,6 +28,7 @@ export class Stack { * @returns {Asset} * @example * import contentstack from '@contentstack/delivery-sdk' +import { Taxonomy } from './taxonomy'; * * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); * const asset = stack.asset() // For collection of asset @@ -77,7 +79,11 @@ export class Stack { * const taxonomy = stack.taxonomy() // For taxonomy query object */ - taxonomy(): TaxonomyQuery { + taxonomy(): TaxonomyQuery; + taxonomy(uid: string): Taxonomy; + taxonomy(uid?: string): Taxonomy | TaxonomyQuery { + if (uid) return new Taxonomy(this._client, uid); + return new TaxonomyQuery(this._client); } diff --git a/src/lib/taxonomy-query.ts b/src/lib/taxonomy-query.ts index 7ece8970..ec8ae9d6 100644 --- a/src/lib/taxonomy-query.ts +++ b/src/lib/taxonomy-query.ts @@ -1,10 +1,31 @@ import { Query } from "./query"; -import { AxiosInstance } from "@contentstack/core"; +import { AxiosInstance, getData } from "@contentstack/core"; +import { FindResponse } from "./types"; export class TaxonomyQuery extends Query { - constructor(client: AxiosInstance) { - super(client, {}, {}); // will need make changes to Query class so that CT uid is not mandatory - this._client = client; - this._urlPath = `/taxonomies/entries`; - } -}; \ No newline at end of file + constructor(client: AxiosInstance) { + super(client, {}, {}); // will need make changes to Query class so that CT uid is not mandatory + this._client = client; + this._urlPath = `/taxonomies/entries`; + } + /** + * @method find + * @memberof TaxonomyQuery + * @description Fetches all taxonomies of the stack using /taxonomy-manager endpoint + * @returns {Promise>} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const taxonomyQuery = stack.taxonomy(); + * const result = await taxonomyQuery.find(); + */ + override async find(): Promise> { + this._urlPath = "/taxonomy-manager"; // TODO: change to /taxonomies + const response = await getData(this._client, this._urlPath, { + params: this._queryParams, + }); + + return response as FindResponse; + } +} \ No newline at end of file diff --git a/src/lib/taxonomy.ts b/src/lib/taxonomy.ts new file mode 100644 index 00000000..6e7a8745 --- /dev/null +++ b/src/lib/taxonomy.ts @@ -0,0 +1,23 @@ +import { AxiosInstance, getData } from '@contentstack/core'; + +export class Taxonomy { + private _client: AxiosInstance; + private _taxonomyUid: string; + private _urlPath: string; + + _queryParams: { [key: string]: string | number } = {}; + + constructor(client: AxiosInstance, taxonomyUid: string) { + this._client = client; + this._taxonomyUid = taxonomyUid; + this._urlPath = `/taxonomy-manager/${this._taxonomyUid}`; // TODO: change to /taxonomies/${this._taxonomyUid} + } + + async fetch(): Promise { + const response = await getData(this._client, this._urlPath); + + if (response.taxonomy) return response.taxonomy as T; + + return response; + } +} diff --git a/test/api/taxonomy.spec.ts b/test/api/taxonomy.spec.ts new file mode 100644 index 00000000..86850733 --- /dev/null +++ b/test/api/taxonomy.spec.ts @@ -0,0 +1,22 @@ +/* eslint-disable no-console */ +/* eslint-disable promise/always-return */ +import { stackInstance } from '../utils/stack-instance'; +import { TTaxonomies } from './types'; +import dotenv from 'dotenv'; +import { TaxonomyQuery } from '../../src/lib/taxonomy-query'; + +dotenv.config() + +const stack = stackInstance(); +describe('ContentType API test cases', () => { + it('should give taxonomies when taxonomies method is called', async () => { + const result = await makeTaxonomy().find(); + expect(result).toBeDefined(); + }); +}); + +function makeTaxonomy(): TaxonomyQuery { + const taxonomy = stack.taxonomy(); + + return taxonomy; +} diff --git a/test/api/types.ts b/test/api/types.ts index 776e3b2c..11197b6f 100644 --- a/test/api/types.ts +++ b/test/api/types.ts @@ -86,3 +86,20 @@ export interface TContentType { export interface TContentTypes { content_types: TContentType[]; } + +export interface TTaxonomies { + taxonomies: TTaxonomy[]; +} + +export interface TTaxonomy { + uid: string; + name: string; + description?: string; + terms_count: number; + created_at: string; + updated_at: string; + created_by: string; + updated_by: string; + type: string; + publish_details: PublishDetails; +} \ No newline at end of file diff --git a/test/unit/taxonomy.spec.ts b/test/unit/taxonomy.spec.ts new file mode 100644 index 00000000..5d37ac4e --- /dev/null +++ b/test/unit/taxonomy.spec.ts @@ -0,0 +1,26 @@ +import { TaxonomyQuery } from '../../src/lib/taxonomy-query'; +import { AxiosInstance, httpClient } from '@contentstack/core'; +import MockAdapter from 'axios-mock-adapter'; +import { taxonomyFindResponseDataMock } from '../utils/mocks'; +import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; + +describe('ta class', () => { + let taxonomy: TaxonomyQuery; + let client: AxiosInstance; + let mockClient: MockAdapter; + + beforeAll(() => { + client = httpClient(MOCK_CLIENT_OPTIONS); + mockClient = new MockAdapter(client as any); + }); + + beforeEach(() => { + taxonomy = new TaxonomyQuery(client); + }); + + it('should return response data when successful', async () => { + mockClient.onGet('/taxonomy-manager').reply(200, taxonomyFindResponseDataMock); //TODO: change to /taxonomies + const response = await taxonomy.find(); + expect(response).toEqual(taxonomyFindResponseDataMock); + }); +}); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index a265d0cd..27e79be3 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -1676,6 +1676,29 @@ const gfieldQueryFindResponseDataMock = { ] } +const taxonomyFindResponseDataMock = { + "taxonomies": [ + { + "uid": "taxonomy_testing", + "name": "taxonomy testing", + "description": "", + "terms_count": 1, + "created_at": "2025-10-10T06:42:48.644Z", + "updated_at": "2025-10-10T06:42:48.644Z", + "created_by": "created_by", + "updated_by": "updated_by", + "type": "TAXONOMY", + "ACL": {}, + "publish_details": { + "time": "2025-10-10T08:01:48.174Z", + "user": "user", + "environment": "env", + "locale": "en-us" + } + } + ] +} + const syncResult: any = { ...axiosGetMock.data }; export { @@ -1688,5 +1711,6 @@ export { entryFindMock, entryFetchMock, gfieldFetchDataMock, - gfieldQueryFindResponseDataMock + gfieldQueryFindResponseDataMock, + taxonomyFindResponseDataMock }; From df96f25ca34f45a7c25bbf5220302bbe915b6fb8 Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Fri, 17 Oct 2025 15:16:25 +0530 Subject: [PATCH 02/13] get a single taxonomy --- test/api/taxonomy.spec.ts | 21 ++++++++++++++++----- test/unit/taxonomy.spec.ts | 17 +++++++++++++---- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/test/api/taxonomy.spec.ts b/test/api/taxonomy.spec.ts index 86850733..09a8f291 100644 --- a/test/api/taxonomy.spec.ts +++ b/test/api/taxonomy.spec.ts @@ -1,22 +1,33 @@ /* eslint-disable no-console */ /* eslint-disable promise/always-return */ import { stackInstance } from '../utils/stack-instance'; -import { TTaxonomies } from './types'; +import { TTaxonomies, TTaxonomy } from './types'; import dotenv from 'dotenv'; import { TaxonomyQuery } from '../../src/lib/taxonomy-query'; +import { Taxonomy } from '../../src/lib/taxonomy'; dotenv.config() const stack = stackInstance(); describe('ContentType API test cases', () => { it('should give taxonomies when taxonomies method is called', async () => { - const result = await makeTaxonomy().find(); + const result = await makeTaxonomies().find(); + expect(result).toBeDefined(); + }); + + it('should give a single taxonomy when taxonomy method is called with taxonomyUid', async () => { + const result = await makeTaxonomy('taxonomy_testing').fetch(); expect(result).toBeDefined(); }); }); -function makeTaxonomy(): TaxonomyQuery { - const taxonomy = stack.taxonomy(); +function makeTaxonomies(): TaxonomyQuery { + const taxonomies = stack.taxonomy(); - return taxonomy; + return taxonomies; } + +function makeTaxonomy(taxonomyUid: string): Taxonomy { + const taxonomy = stack.taxonomy(taxonomyUid); + return taxonomy; +} \ No newline at end of file diff --git a/test/unit/taxonomy.spec.ts b/test/unit/taxonomy.spec.ts index 5d37ac4e..0c4670e5 100644 --- a/test/unit/taxonomy.spec.ts +++ b/test/unit/taxonomy.spec.ts @@ -1,11 +1,13 @@ import { TaxonomyQuery } from '../../src/lib/taxonomy-query'; +import { Taxonomy } from '../../src/lib/taxonomy'; import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; import { taxonomyFindResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; describe('ta class', () => { - let taxonomy: TaxonomyQuery; + let taxonomies: TaxonomyQuery; + let taxonomy: Taxonomy; let client: AxiosInstance; let mockClient: MockAdapter; @@ -15,12 +17,19 @@ describe('ta class', () => { }); beforeEach(() => { - taxonomy = new TaxonomyQuery(client); + taxonomies = new TaxonomyQuery(client); + taxonomy = new Taxonomy(client, 'taxonomy_testing'); }); - it('should return response data when successful', async () => { + it('should return all taxonomies in the response data when successful', async () => { mockClient.onGet('/taxonomy-manager').reply(200, taxonomyFindResponseDataMock); //TODO: change to /taxonomies - const response = await taxonomy.find(); + const response = await taxonomies.find(); expect(response).toEqual(taxonomyFindResponseDataMock); }); + + it('should return single taxonomy in the response data when successful', async () => { + mockClient.onGet('/taxonomy-manager/taxonomy_testing').reply(200, taxonomyFindResponseDataMock.taxonomies[0]); //TODO: change to /taxonomies/taxonomyUid + const response = await taxonomy.fetch(); + expect(response).toEqual(taxonomyFindResponseDataMock.taxonomies[0]); //TODO: change to taxonomyFindResponseDataMock + }); }); From c213dd86632672bdce544603460bc9e769db475a Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Thu, 23 Oct 2025 17:01:07 +0530 Subject: [PATCH 03/13] feat: Add Term and TermQuery classes for enhanced taxonomy term management --- src/lib/taxonomy.ts | 10 ++++++++++ src/lib/term-query.ts | 20 ++++++++++++++++++++ src/lib/term.ts | 22 ++++++++++++++++++++++ src/lib/types.ts | 2 ++ test/api/term-query.spec.ts | 23 +++++++++++++++++++++++ test/api/term.spec.ts | 20 ++++++++++++++++++++ test/api/types.ts | 22 ++++++++++++++++++++-- test/unit/taxonomy.spec.ts | 14 +++++++++++++- test/unit/term-query.spec.ts | 26 ++++++++++++++++++++++++++ test/unit/term.spec.ts | 28 ++++++++++++++++++++++++++++ test/utils/mocks.ts | 32 +++++++++++++++++++++++++++++++- 11 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 src/lib/term-query.ts create mode 100644 src/lib/term.ts create mode 100644 test/api/term-query.spec.ts create mode 100644 test/api/term.spec.ts create mode 100644 test/unit/term-query.spec.ts create mode 100644 test/unit/term.spec.ts diff --git a/src/lib/taxonomy.ts b/src/lib/taxonomy.ts index 6e7a8745..84b05072 100644 --- a/src/lib/taxonomy.ts +++ b/src/lib/taxonomy.ts @@ -1,4 +1,6 @@ import { AxiosInstance, getData } from '@contentstack/core'; +import { TermQuery } from './term-query'; +import { Term } from './term'; export class Taxonomy { private _client: AxiosInstance; @@ -13,6 +15,14 @@ export class Taxonomy { this._urlPath = `/taxonomy-manager/${this._taxonomyUid}`; // TODO: change to /taxonomies/${this._taxonomyUid} } + term(uid: string): Term; + term(): TermQuery; + term(uid?: string): Term | TermQuery { + if (uid) return new Term(this._client, this._taxonomyUid, uid); + + return new TermQuery(this._client, this._taxonomyUid); + } + async fetch(): Promise { const response = await getData(this._client, this._urlPath); diff --git a/src/lib/term-query.ts b/src/lib/term-query.ts new file mode 100644 index 00000000..23a8698f --- /dev/null +++ b/src/lib/term-query.ts @@ -0,0 +1,20 @@ +import { AxiosInstance, getData } from '@contentstack/core'; +import { FindResponse } from './types'; + +export class TermQuery { + private _taxonomyUid: string; + private _client: AxiosInstance; + private _urlPath: string; + _queryParams: { [key: string]: string | number } = {}; + + constructor(client: AxiosInstance, taxonomyUid: string) { + this._client = client; + this._taxonomyUid = taxonomyUid; + this._urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms`; + } + + async find(): Promise> { + const response = await getData(this._client, this._urlPath, { params: this._queryParams }); + return response as FindResponse; + } +} diff --git a/src/lib/term.ts b/src/lib/term.ts new file mode 100644 index 00000000..615e95f5 --- /dev/null +++ b/src/lib/term.ts @@ -0,0 +1,22 @@ +import { AxiosInstance, getData } from "@contentstack/core"; + +export class Term { + protected _client: AxiosInstance; + private _taxonomyUid: string; + private _termUid: string; + private _urlPath: string; + + constructor(client: AxiosInstance, taxonomyUid: string, termUid: string) { + this._client = client; + this._taxonomyUid = taxonomyUid; + this._termUid = termUid; + this._urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms/${this._termUid}`; // TODO: change to /taxonomies + } + async fetch(): Promise { + const response = await getData(this._client, this._urlPath); + + if (response.term) return response.term as T; + + return response; + } +} diff --git a/src/lib/types.ts b/src/lib/types.ts index e19a0326..a5106675 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -317,6 +317,8 @@ export interface FindResponse { assets?: T[]; global_fields?: T[]; count?: number; + taxonomies?: T[]; + terms?: T[]; } export interface LivePreviewQuery { diff --git a/test/api/term-query.spec.ts b/test/api/term-query.spec.ts new file mode 100644 index 00000000..58f59574 --- /dev/null +++ b/test/api/term-query.spec.ts @@ -0,0 +1,23 @@ +import { TermQuery } from "../../src/lib/term-query"; +import { stackInstance } from "../utils/stack-instance"; +import { TTerm } from "./types"; + +const stack = stackInstance(); + +describe("Terms API test cases", () => { + it("should check for terms is defined", async () => { + const result = await makeTerms("taxonomy_testing").find(); + if (result.terms) { + expect(result.terms).toBeDefined(); + expect(result.terms[0].taxonomy_uid).toBeDefined(); + expect(result.terms[0].uid).toBeDefined(); + expect(result.terms[0].created_by).toBeDefined(); + expect(result.terms[0].updated_by).toBeDefined(); + } + }); +}); +function makeTerms(taxonomyUid = ""): TermQuery { + const terms = stack.taxonomy(taxonomyUid).term(); + + return terms; +} diff --git a/test/api/term.spec.ts b/test/api/term.spec.ts new file mode 100644 index 00000000..72c1c6eb --- /dev/null +++ b/test/api/term.spec.ts @@ -0,0 +1,20 @@ +import { Term } from "../../src/lib/term"; +import { stackInstance } from "../utils/stack-instance"; +import { TTerm } from "./types"; + +const stack = stackInstance(); + +describe("Terms API test cases", () => { + it("should get a term by uid", async () => { + const result = await makeTerms("term1").fetch(); + expect(result).toBeDefined(); + expect(result.taxonomy_uid).toBeDefined(); + expect(result.uid).toBeDefined(); + expect(result.created_by).toBeDefined(); + expect(result.updated_by).toBeDefined(); + }); +}); +function makeTerms(termUid = ""): Term { + const terms = stack.taxonomy("taxonomy_testing").term(termUid); + return terms; +} diff --git a/test/api/types.ts b/test/api/types.ts index 11197b6f..f59f73cd 100644 --- a/test/api/types.ts +++ b/test/api/types.ts @@ -95,11 +95,29 @@ export interface TTaxonomy { uid: string; name: string; description?: string; - terms_count: number; + terms_count?: number; created_at: string; updated_at: string; created_by: string; updated_by: string; type: string; - publish_details: PublishDetails; + publish_details?: PublishDetails; +} + +export interface TTerms { + terms: TTerm[]; +} + +export interface TTerm { + taxonomy_uid: string; + uid: string; + ancestors: TTerm[]; + name: string; + created_by: string; + created_at: string; + updated_by: string; + updated_at: string; + children_count?: number; + depth?: number; + publish_details?: PublishDetails; } \ No newline at end of file diff --git a/test/unit/taxonomy.spec.ts b/test/unit/taxonomy.spec.ts index 0c4670e5..5db38cb6 100644 --- a/test/unit/taxonomy.spec.ts +++ b/test/unit/taxonomy.spec.ts @@ -4,6 +4,8 @@ import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; import { taxonomyFindResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; +import { Term } from '../../src/lib/term'; +import { TermQuery } from '../../src/lib/term-query'; describe('ta class', () => { let taxonomies: TaxonomyQuery; @@ -21,6 +23,16 @@ describe('ta class', () => { taxonomy = new Taxonomy(client, 'taxonomy_testing'); }); + it('should give term instance when term method is called with termUid', () => { + const query = taxonomy.term('termUid'); + expect(query).toBeInstanceOf(Term); + }); + + it('should give term query instance when term method is called without termUid', () => { + const query = taxonomy.term() + expect(query).toBeInstanceOf(TermQuery); + }); + it('should return all taxonomies in the response data when successful', async () => { mockClient.onGet('/taxonomy-manager').reply(200, taxonomyFindResponseDataMock); //TODO: change to /taxonomies const response = await taxonomies.find(); @@ -30,6 +42,6 @@ describe('ta class', () => { it('should return single taxonomy in the response data when successful', async () => { mockClient.onGet('/taxonomy-manager/taxonomy_testing').reply(200, taxonomyFindResponseDataMock.taxonomies[0]); //TODO: change to /taxonomies/taxonomyUid const response = await taxonomy.fetch(); - expect(response).toEqual(taxonomyFindResponseDataMock.taxonomies[0]); //TODO: change to taxonomyFindResponseDataMock + expect(response).toEqual(taxonomyFindResponseDataMock.taxonomies[0]); }); }); diff --git a/test/unit/term-query.spec.ts b/test/unit/term-query.spec.ts new file mode 100644 index 00000000..ea00e0a4 --- /dev/null +++ b/test/unit/term-query.spec.ts @@ -0,0 +1,26 @@ +import { TermQuery } from '../../src/lib/term-query'; +import { AxiosInstance, httpClient } from '@contentstack/core'; +import MockAdapter from 'axios-mock-adapter'; +import { TermQueryFindResponseDataMock } from '../utils/mocks'; +import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; + +describe('TermQuery class', () => { + let termQuery: TermQuery; + let client: AxiosInstance; + let mockClient: MockAdapter; + + beforeAll(() => { + client = httpClient(MOCK_CLIENT_OPTIONS); + mockClient = new MockAdapter(client as any); + }); + + beforeEach(() => { + termQuery = new TermQuery(client, 'taxonomy_testing'); + }); + + it('should return response data when successful', async () => { + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms').reply(200, TermQueryFindResponseDataMock); + const response = await termQuery.find(); + expect(response).toEqual(TermQueryFindResponseDataMock); + }); +}); diff --git a/test/unit/term.spec.ts b/test/unit/term.spec.ts new file mode 100644 index 00000000..d1e34c9d --- /dev/null +++ b/test/unit/term.spec.ts @@ -0,0 +1,28 @@ +import { AxiosInstance, httpClient } from '@contentstack/core'; +import MockAdapter from 'axios-mock-adapter'; +import { TermQueryFindResponseDataMock } from '../utils/mocks'; +import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; +import { Term } from '../../src/lib/term'; +import { Taxonomy } from '../../src/lib/taxonomy'; + +describe('Term class', () => { + let term: Term; + let client: AxiosInstance; + let mockClient: MockAdapter; + + beforeAll(() => { + client = httpClient(MOCK_CLIENT_OPTIONS); + mockClient = new MockAdapter(client as any); + }); + + beforeEach(() => { + term = new Term(client, 'taxonomy_testing', 'term1'); + }); + + it('should fetch the term by uid response when fetch method is called', async () => { + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1').reply(200, TermQueryFindResponseDataMock.terms[0]); //TODO: change to /taxonomies + + const response = await term.fetch(); + expect(response).toEqual(TermQueryFindResponseDataMock.terms[0]); + }); +}); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index 27e79be3..15fa28a0 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -1698,6 +1698,35 @@ const taxonomyFindResponseDataMock = { } ] } +const TermQueryFindResponseDataMock = { + "terms": [ + { + "taxonomy_uid": "taxonomy_testing", + "uid": "term1", + "ancestors": [ + { + "uid": "taxonomy_testing", + "name": "taxonomy testing", + "type": "TAXONOMY" + } + ], + "name": "term1", + "created_by": "created_by", + "created_at": "2025-10-10T06:43:13.799Z", + "updated_by": "updated_by", + "updated_at": "2025-10-10T06:43:13.799Z", + "children_count": 0, + "depth": 1, + "ACL": {}, + "publish_details": { + "time": "2025-10-10T08:01:48.351Z", + "user": "user", + "environment": "environment", + "locale": "en-us" + } + } +] +} const syncResult: any = { ...axiosGetMock.data }; @@ -1712,5 +1741,6 @@ export { entryFetchMock, gfieldFetchDataMock, gfieldQueryFindResponseDataMock, - taxonomyFindResponseDataMock + taxonomyFindResponseDataMock, + TermQueryFindResponseDataMock, }; From b7e629ab4776b34b950814b5fb59868c1e7d147c Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Thu, 23 Oct 2025 17:03:10 +0530 Subject: [PATCH 04/13] refactor: Rename TermQueryFindResponseDataMock to termQueryFindResponseDataMock for consistency in tests --- test/unit/term-query.spec.ts | 6 +++--- test/unit/term.spec.ts | 6 +++--- test/utils/mocks.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/unit/term-query.spec.ts b/test/unit/term-query.spec.ts index ea00e0a4..a96019d0 100644 --- a/test/unit/term-query.spec.ts +++ b/test/unit/term-query.spec.ts @@ -1,7 +1,7 @@ import { TermQuery } from '../../src/lib/term-query'; import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; -import { TermQueryFindResponseDataMock } from '../utils/mocks'; +import { termQueryFindResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; describe('TermQuery class', () => { @@ -19,8 +19,8 @@ describe('TermQuery class', () => { }); it('should return response data when successful', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms').reply(200, TermQueryFindResponseDataMock); + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms').reply(200, termQueryFindResponseDataMock); const response = await termQuery.find(); - expect(response).toEqual(TermQueryFindResponseDataMock); + expect(response).toEqual(termQueryFindResponseDataMock); }); }); diff --git a/test/unit/term.spec.ts b/test/unit/term.spec.ts index d1e34c9d..65d4140e 100644 --- a/test/unit/term.spec.ts +++ b/test/unit/term.spec.ts @@ -1,6 +1,6 @@ import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; -import { TermQueryFindResponseDataMock } from '../utils/mocks'; +import { termQueryFindResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; import { Term } from '../../src/lib/term'; import { Taxonomy } from '../../src/lib/taxonomy'; @@ -20,9 +20,9 @@ describe('Term class', () => { }); it('should fetch the term by uid response when fetch method is called', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1').reply(200, TermQueryFindResponseDataMock.terms[0]); //TODO: change to /taxonomies + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1').reply(200, termQueryFindResponseDataMock.terms[0]); //TODO: change to /taxonomies const response = await term.fetch(); - expect(response).toEqual(TermQueryFindResponseDataMock.terms[0]); + expect(response).toEqual(termQueryFindResponseDataMock.terms[0]); }); }); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index 15fa28a0..82c4becc 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -1698,7 +1698,7 @@ const taxonomyFindResponseDataMock = { } ] } -const TermQueryFindResponseDataMock = { +const termQueryFindResponseDataMock = { "terms": [ { "taxonomy_uid": "taxonomy_testing", @@ -1742,5 +1742,5 @@ export { gfieldFetchDataMock, gfieldQueryFindResponseDataMock, taxonomyFindResponseDataMock, - TermQueryFindResponseDataMock, + termQueryFindResponseDataMock, }; From 908f2063c2d70c6aea95325f749e2564a7005392 Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 11:54:19 +0530 Subject: [PATCH 05/13] feat: Add locales method to Term class and corresponding tests --- src/lib/term.ts | 17 +++++++++++++++++ test/api/term.spec.ts | 8 ++++++++ test/unit/term.spec.ts | 9 ++++++++- test/utils/mocks.ts | 17 +++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/lib/term.ts b/src/lib/term.ts index 615e95f5..917d55c2 100644 --- a/src/lib/term.ts +++ b/src/lib/term.ts @@ -12,6 +12,23 @@ export class Term { this._termUid = termUid; this._urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms/${this._termUid}`; // TODO: change to /taxonomies } + + /** + * @method locales + * @memberof Term + * @description Fetches locales for the term + * @returns {Promise} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').locales().fetch(); + */ + locales(): this { + this._urlPath = `${this._urlPath}/locales`; + return this; + } + async fetch(): Promise { const response = await getData(this._client, this._urlPath); diff --git a/test/api/term.spec.ts b/test/api/term.spec.ts index 72c1c6eb..c599655d 100644 --- a/test/api/term.spec.ts +++ b/test/api/term.spec.ts @@ -13,7 +13,15 @@ describe("Terms API test cases", () => { expect(result.created_by).toBeDefined(); expect(result.updated_by).toBeDefined(); }); + + it("should get locales for a term", async () => { + // const result = await makeTerms("term1").locales().fetch(); + // API under building phase, so it should throw error + expect(async () => await makeTerms("term1").locales().fetch()).rejects.toThrow(); + // TODO: add assertions + }); }); + function makeTerms(termUid = ""): Term { const terms = stack.taxonomy("taxonomy_testing").term(termUid); return terms; diff --git a/test/unit/term.spec.ts b/test/unit/term.spec.ts index 65d4140e..9f600023 100644 --- a/test/unit/term.spec.ts +++ b/test/unit/term.spec.ts @@ -1,6 +1,6 @@ import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; -import { termQueryFindResponseDataMock } from '../utils/mocks'; +import { termQueryFindResponseDataMock, termLocalesFindResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; import { Term } from '../../src/lib/term'; import { Taxonomy } from '../../src/lib/taxonomy'; @@ -25,4 +25,11 @@ describe('Term class', () => { const response = await term.fetch(); expect(response).toEqual(termQueryFindResponseDataMock.terms[0]); }); + + it('should fetch locales for a term when locales().fetch() is called', async () => { + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/locales').reply(200, termLocalesFindResponseDataMock); + + const response = await term.locales().fetch(); + expect(response).toEqual(termLocalesFindResponseDataMock.locales); + }); }); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index 82c4becc..51d2b32a 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -1698,6 +1698,22 @@ const taxonomyFindResponseDataMock = { } ] } + +const termLocalesFindResponseDataMock = { + "locales": [ + { + "code": "en-us", + "name": "English (United States)", + "fallback_code": null + }, + { + "code": "es-es", + "name": "Spanish (Spain)", + "fallback_code": "en-us" + } + ] +} + const termQueryFindResponseDataMock = { "terms": [ { @@ -1743,4 +1759,5 @@ export { gfieldQueryFindResponseDataMock, taxonomyFindResponseDataMock, termQueryFindResponseDataMock, + termLocalesFindResponseDataMock, }; From 92d633d1dc5e302ddb35b984e2f7291e004829df Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 12:07:24 +0530 Subject: [PATCH 06/13] refactor: Update locales method in Term class to return data directly and adjust related tests --- src/lib/term.ts | 10 ++++++---- test/api/term.spec.ts | 2 +- test/unit/term.spec.ts | 10 +++++----- test/utils/mocks.ts | 17 +++-------------- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/lib/term.ts b/src/lib/term.ts index 917d55c2..e1596b29 100644 --- a/src/lib/term.ts +++ b/src/lib/term.ts @@ -22,11 +22,13 @@ export class Term { * import contentstack from '@contentstack/delivery-sdk' * * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); - * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').locales().fetch(); + * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').locales(); */ - locales(): this { - this._urlPath = `${this._urlPath}/locales`; - return this; + async locales(): Promise { + const urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms/${this._termUid}/locales`; + const response = await getData(this._client, urlPath); + if (response.locales) return response.locales as T; + return response; } async fetch(): Promise { diff --git a/test/api/term.spec.ts b/test/api/term.spec.ts index c599655d..cb3f41be 100644 --- a/test/api/term.spec.ts +++ b/test/api/term.spec.ts @@ -17,7 +17,7 @@ describe("Terms API test cases", () => { it("should get locales for a term", async () => { // const result = await makeTerms("term1").locales().fetch(); // API under building phase, so it should throw error - expect(async () => await makeTerms("term1").locales().fetch()).rejects.toThrow(); + expect(async () => await makeTerms("term1").locales()).rejects.toThrow(); // TODO: add assertions }); }); diff --git a/test/unit/term.spec.ts b/test/unit/term.spec.ts index 9f600023..4c78f7f2 100644 --- a/test/unit/term.spec.ts +++ b/test/unit/term.spec.ts @@ -1,6 +1,6 @@ import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; -import { termQueryFindResponseDataMock, termLocalesFindResponseDataMock } from '../utils/mocks'; +import { termQueryFindResponseDataMock, termLocalesResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; import { Term } from '../../src/lib/term'; import { Taxonomy } from '../../src/lib/taxonomy'; @@ -26,10 +26,10 @@ describe('Term class', () => { expect(response).toEqual(termQueryFindResponseDataMock.terms[0]); }); - it('should fetch locales for a term when locales().fetch() is called', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/locales').reply(200, termLocalesFindResponseDataMock); + it('should fetch locales for a term when locales() is called', async () => { + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/locales').reply(200, termLocalesResponseDataMock.terms); //TODO: change to /taxonomies - const response = await term.locales().fetch(); - expect(response).toEqual(termLocalesFindResponseDataMock.locales); + const response = await term.locales(); + expect(response).toEqual(termLocalesResponseDataMock.terms); }); }); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index 51d2b32a..d1808aea 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -1699,19 +1699,8 @@ const taxonomyFindResponseDataMock = { ] } -const termLocalesFindResponseDataMock = { - "locales": [ - { - "code": "en-us", - "name": "English (United States)", - "fallback_code": null - }, - { - "code": "es-es", - "name": "Spanish (Spain)", - "fallback_code": "en-us" - } - ] +const termLocalesResponseDataMock = { + terms: [] } const termQueryFindResponseDataMock = { @@ -1759,5 +1748,5 @@ export { gfieldQueryFindResponseDataMock, taxonomyFindResponseDataMock, termQueryFindResponseDataMock, - termLocalesFindResponseDataMock, + termLocalesResponseDataMock, }; From c4695d8f397d654043ea366d6dab740352fadcce Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 12:54:36 +0530 Subject: [PATCH 07/13] feat: Add ancestors method to Term class and update related tests --- src/lib/term.ts | 20 ++++++++++++++++++-- test/api/taxonomy.spec.ts | 2 +- test/api/term-query.spec.ts | 2 +- test/api/term.spec.ts | 17 ++++++++++++----- test/unit/term.spec.ts | 9 ++++++++- test/utils/mocks.ts | 36 ++++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/lib/term.ts b/src/lib/term.ts index e1596b29..f33ec0e0 100644 --- a/src/lib/term.ts +++ b/src/lib/term.ts @@ -25,12 +25,28 @@ export class Term { * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').locales(); */ async locales(): Promise { - const urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms/${this._termUid}/locales`; - const response = await getData(this._client, urlPath); + const response = await getData(this._client, `${this._urlPath}/locales`); if (response.locales) return response.locales as T; return response; } + /** + * @method ancestors + * @memberof Term + * @description Fetches ancestors for the term + * @returns {Promise} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').ancestors(); + */ + async ancestors(): Promise { + const response = await getData(this._client, `${this._urlPath}/ancestors`); + if (response.ancestors) return response.ancestors as T; + return response; + } + async fetch(): Promise { const response = await getData(this._client, this._urlPath); diff --git a/test/api/taxonomy.spec.ts b/test/api/taxonomy.spec.ts index 09a8f291..10e975c7 100644 --- a/test/api/taxonomy.spec.ts +++ b/test/api/taxonomy.spec.ts @@ -16,7 +16,7 @@ describe('ContentType API test cases', () => { }); it('should give a single taxonomy when taxonomy method is called with taxonomyUid', async () => { - const result = await makeTaxonomy('taxonomy_testing').fetch(); + const result = await makeTaxonomy('taxonomy_testing_3').fetch(); expect(result).toBeDefined(); }); }); diff --git a/test/api/term-query.spec.ts b/test/api/term-query.spec.ts index 58f59574..8ea808db 100644 --- a/test/api/term-query.spec.ts +++ b/test/api/term-query.spec.ts @@ -6,7 +6,7 @@ const stack = stackInstance(); describe("Terms API test cases", () => { it("should check for terms is defined", async () => { - const result = await makeTerms("taxonomy_testing").find(); + const result = await makeTerms("taxonomy_testing_3").find(); if (result.terms) { expect(result.terms).toBeDefined(); expect(result.terms[0].taxonomy_uid).toBeDefined(); diff --git a/test/api/term.spec.ts b/test/api/term.spec.ts index cb3f41be..b09094be 100644 --- a/test/api/term.spec.ts +++ b/test/api/term.spec.ts @@ -1,12 +1,12 @@ import { Term } from "../../src/lib/term"; import { stackInstance } from "../utils/stack-instance"; -import { TTerm } from "./types"; +import { TTerm, TTerms } from "./types"; const stack = stackInstance(); describe("Terms API test cases", () => { it("should get a term by uid", async () => { - const result = await makeTerms("term1").fetch(); + const result = await makeTerms("vehicles").fetch(); expect(result).toBeDefined(); expect(result.taxonomy_uid).toBeDefined(); expect(result.uid).toBeDefined(); @@ -15,14 +15,21 @@ describe("Terms API test cases", () => { }); it("should get locales for a term", async () => { - // const result = await makeTerms("term1").locales().fetch(); + // const result = await makeTerms("vehicles").locales().fetch(); // API under building phase, so it should throw error - expect(async () => await makeTerms("term1").locales()).rejects.toThrow(); + expect(async () => await makeTerms("vehicles").locales()).rejects.toThrow(); // TODO: add assertions }); + + it("should get ancestors for a term", async () => { + const result = await makeTerms("sleeper").ancestors(); + expect(result).toBeDefined(); + expect(result.terms).toBeDefined(); + expect(result.terms[0].name).toBeDefined(); + }); }); function makeTerms(termUid = ""): Term { - const terms = stack.taxonomy("taxonomy_testing").term(termUid); + const terms = stack.taxonomy("taxonomy_testing_3").term(termUid); return terms; } diff --git a/test/unit/term.spec.ts b/test/unit/term.spec.ts index 4c78f7f2..244b3e88 100644 --- a/test/unit/term.spec.ts +++ b/test/unit/term.spec.ts @@ -1,6 +1,6 @@ import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; -import { termQueryFindResponseDataMock, termLocalesResponseDataMock } from '../utils/mocks'; +import { termQueryFindResponseDataMock, termLocalesResponseDataMock, termAncestorsResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; import { Term } from '../../src/lib/term'; import { Taxonomy } from '../../src/lib/taxonomy'; @@ -32,4 +32,11 @@ describe('Term class', () => { const response = await term.locales(); expect(response).toEqual(termLocalesResponseDataMock.terms); }); + + it('should fetch ancestors for a term when ancestors() is called', async () => { + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/ancestors').reply(200, termAncestorsResponseDataMock); + + const response = await term.ancestors(); + expect(response).toEqual(termAncestorsResponseDataMock); + }); }); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index d1808aea..5ff3626b 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -1703,6 +1703,41 @@ const termLocalesResponseDataMock = { terms: [] } +const termAncestorsResponseDataMock = { + "terms": [ + { + "uid": "vehicles", + "name": "vehicles", + "publish_details": { + "time": "2025-10-28T06:54:12.505Z", + "user": "user", + "environment": "environment", + "locale": "en-us" + } + }, + { + "uid": "buses", + "name": "buses", + "publish_details": { + "time": "2025-10-28T06:54:12.514Z", + "user": "user", + "environment": "environment", + "locale": "en-us" + } + }, + { + "uid": "vrl", + "name": "vrl", + "publish_details": { + "time": "2025-10-28T06:54:12.570Z", + "user": "user", + "environment": "environment", + "locale": "en-us" + } + } + ] +} + const termQueryFindResponseDataMock = { "terms": [ { @@ -1749,4 +1784,5 @@ export { taxonomyFindResponseDataMock, termQueryFindResponseDataMock, termLocalesResponseDataMock, + termAncestorsResponseDataMock, }; From 4e97212511abd7f968345e19397c744bad597e4e Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 13:44:18 +0530 Subject: [PATCH 08/13] feat: Add descendants method to Term class and update related tests --- src/lib/term.ts | 19 +++++++- test/api/taxonomy.spec.ts | 2 +- test/api/term-query.spec.ts | 2 +- test/api/term.spec.ts | 9 +++- test/unit/term.spec.ts | 9 +++- test/utils/mocks.ts | 88 +++++++++++++++++++++++++++++++++++++ 6 files changed, 123 insertions(+), 6 deletions(-) diff --git a/src/lib/term.ts b/src/lib/term.ts index f33ec0e0..20847ef7 100644 --- a/src/lib/term.ts +++ b/src/lib/term.ts @@ -47,11 +47,26 @@ export class Term { return response; } + /** + * @method descendants + * @memberof Term + * @description Fetches descendants for the term + * @returns {Promise} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').descendants(); + */ + async descendants(): Promise { + const response = await getData(this._client, `${this._urlPath}/descendants`); + if (response.descendants) return response.descendants as T; + return response; + } + async fetch(): Promise { const response = await getData(this._client, this._urlPath); - if (response.term) return response.term as T; - return response; } } diff --git a/test/api/taxonomy.spec.ts b/test/api/taxonomy.spec.ts index 10e975c7..09a8f291 100644 --- a/test/api/taxonomy.spec.ts +++ b/test/api/taxonomy.spec.ts @@ -16,7 +16,7 @@ describe('ContentType API test cases', () => { }); it('should give a single taxonomy when taxonomy method is called with taxonomyUid', async () => { - const result = await makeTaxonomy('taxonomy_testing_3').fetch(); + const result = await makeTaxonomy('taxonomy_testing').fetch(); expect(result).toBeDefined(); }); }); diff --git a/test/api/term-query.spec.ts b/test/api/term-query.spec.ts index 8ea808db..58f59574 100644 --- a/test/api/term-query.spec.ts +++ b/test/api/term-query.spec.ts @@ -6,7 +6,7 @@ const stack = stackInstance(); describe("Terms API test cases", () => { it("should check for terms is defined", async () => { - const result = await makeTerms("taxonomy_testing_3").find(); + const result = await makeTerms("taxonomy_testing").find(); if (result.terms) { expect(result.terms).toBeDefined(); expect(result.terms[0].taxonomy_uid).toBeDefined(); diff --git a/test/api/term.spec.ts b/test/api/term.spec.ts index b09094be..3d994036 100644 --- a/test/api/term.spec.ts +++ b/test/api/term.spec.ts @@ -27,9 +27,16 @@ describe("Terms API test cases", () => { expect(result.terms).toBeDefined(); expect(result.terms[0].name).toBeDefined(); }); + + it("should get descendants for a term", async () => { + const result = await makeTerms("vrl").descendants(); + expect(result).toBeDefined(); + expect(result.terms).toBeDefined(); + expect(result.terms[0].name).toBeDefined(); + }); }); function makeTerms(termUid = ""): Term { - const terms = stack.taxonomy("taxonomy_testing_3").term(termUid); + const terms = stack.taxonomy("taxonomy_testing").term(termUid); return terms; } diff --git a/test/unit/term.spec.ts b/test/unit/term.spec.ts index 244b3e88..0c404a43 100644 --- a/test/unit/term.spec.ts +++ b/test/unit/term.spec.ts @@ -1,6 +1,6 @@ import { AxiosInstance, httpClient } from '@contentstack/core'; import MockAdapter from 'axios-mock-adapter'; -import { termQueryFindResponseDataMock, termLocalesResponseDataMock, termAncestorsResponseDataMock } from '../utils/mocks'; +import { termQueryFindResponseDataMock, termLocalesResponseDataMock, termAncestorsResponseDataMock, termDescendantsResponseDataMock } from '../utils/mocks'; import { MOCK_CLIENT_OPTIONS } from '../utils/constant'; import { Term } from '../../src/lib/term'; import { Taxonomy } from '../../src/lib/taxonomy'; @@ -39,4 +39,11 @@ describe('Term class', () => { const response = await term.ancestors(); expect(response).toEqual(termAncestorsResponseDataMock); }); + + it('should fetch descendants for a term when descendants() is called', async () => { + mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/descendants').reply(200, termDescendantsResponseDataMock); + + const response = await term.descendants(); + expect(response).toEqual(termDescendantsResponseDataMock); + }); }); diff --git a/test/utils/mocks.ts b/test/utils/mocks.ts index 5ff3626b..14957541 100644 --- a/test/utils/mocks.ts +++ b/test/utils/mocks.ts @@ -1738,6 +1738,93 @@ const termAncestorsResponseDataMock = { ] } +const termDescendantsResponseDataMock = { + "terms": [ + { + "taxonomy_uid": "taxonomy_testing", + "uid": "sleeper", + "ancestors": [ + { + "uid": "taxonomy_testing", + "name": "taxonomy_testing", + "type": "TAXONOMY" + }, + { + "uid": "vehicles", + "name": "vehicles", + "type": "" + }, + { + "uid": "buses", + "name": "buses", + "type": "" + }, + { + "uid": "vrl", + "name": "vrl", + "type": "" + } + ], + "name": "sleeper", + "parent_uid": "vrl", + "created_by": "created_by", + "created_at": "2025-10-28T07:58:46.870Z", + "updated_by": "updated_by", + "updated_at": "2025-10-28T07:58:46.870Z", + "children_count": 0, + "depth": 4, + "ACL": {}, + "publish_details": { + "time": "2025-10-28T07:59:12.557Z", + "user": "user", + "environment": "environment", + "locale": "en-us" + } + }, + { + "taxonomy_uid": "taxonomy_testing", + "uid": "intercity", + "ancestors": [ + { + "uid": "taxonomy_testing", + "name": "taxonomy_testing", + "type": "TAXONOMY" + }, + { + "uid": "vehicles", + "name": "vehicles", + "type": "" + }, + { + "uid": "buses", + "name": "buses", + "type": "" + }, + { + "uid": "vrl", + "name": "vrl", + "type": "" + } + ], + "name": "intercity", + "parent_uid": "vrl", + "created_by": "created_by", + "created_at": "2025-10-28T07:58:46.870Z", + "updated_by": "updated_by", + "updated_at": "2025-10-28T07:58:46.870Z", + "children_count": 0, + "depth": 4, + "ACL": {}, + "publish_details": { + "time": "2025-10-28T07:59:12.565Z", + "user": "user", + "environment": "environment", + "locale": "en-us" + } + } + ] +} + const termQueryFindResponseDataMock = { "terms": [ { @@ -1785,4 +1872,5 @@ export { termQueryFindResponseDataMock, termLocalesResponseDataMock, termAncestorsResponseDataMock, + termDescendantsResponseDataMock, }; From 519c7a3cebcc3adae1b92cb831b825c23fc010e6 Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 15:21:53 +0530 Subject: [PATCH 09/13] feat: Enhance Taxonomy and TermQuery classes with detailed documentation and fetch methods --- src/lib/taxonomy.ts | 35 +++++++++++++++++++++++++++++++++++ src/lib/term-query.ts | 20 ++++++++++++++++++++ src/lib/term.ts | 21 +++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/src/lib/taxonomy.ts b/src/lib/taxonomy.ts index 84b05072..1e25ca6f 100644 --- a/src/lib/taxonomy.ts +++ b/src/lib/taxonomy.ts @@ -2,6 +2,10 @@ import { AxiosInstance, getData } from '@contentstack/core'; import { TermQuery } from './term-query'; import { Term } from './term'; +/** + * @class Taxonomy + * @description Represents a taxonomy with methods to fetch taxonomy data and manage terms + */ export class Taxonomy { private _client: AxiosInstance; private _taxonomyUid: string; @@ -9,12 +13,32 @@ export class Taxonomy { _queryParams: { [key: string]: string | number } = {}; + /** + * @constructor + * @param {AxiosInstance} client - The HTTP client instance + * @param {string} taxonomyUid - The taxonomy UID + */ constructor(client: AxiosInstance, taxonomyUid: string) { this._client = client; this._taxonomyUid = taxonomyUid; this._urlPath = `/taxonomy-manager/${this._taxonomyUid}`; // TODO: change to /taxonomies/${this._taxonomyUid} } + /** + * @method term + * @memberof Taxonomy + * @description Gets a specific term or creates a term query + * @param {string} [uid] - Optional term UID. If provided, returns a Term instance. If not provided, returns a TermQuery instance. + * @returns {Term | TermQuery} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * // Get a specific term + * const term = stack.taxonomy('taxonomy_uid').term('term_uid'); + * // Get all terms + * const termQuery = stack.taxonomy('taxonomy_uid').term(); + */ term(uid: string): Term; term(): TermQuery; term(uid?: string): Term | TermQuery { @@ -23,6 +47,17 @@ export class Taxonomy { return new TermQuery(this._client, this._taxonomyUid); } + /** + * @method fetch + * @memberof Taxonomy + * @description Fetches the taxonomy data by UID + * @returns {Promise} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').fetch(); + */ async fetch(): Promise { const response = await getData(this._client, this._urlPath); diff --git a/src/lib/term-query.ts b/src/lib/term-query.ts index 23a8698f..f589db41 100644 --- a/src/lib/term-query.ts +++ b/src/lib/term-query.ts @@ -1,18 +1,38 @@ import { AxiosInstance, getData } from '@contentstack/core'; import { FindResponse } from './types'; +/** + * @class TermQuery + * @description Represents a query for fetching multiple terms from a taxonomy + */ export class TermQuery { private _taxonomyUid: string; private _client: AxiosInstance; private _urlPath: string; _queryParams: { [key: string]: string | number } = {}; + /** + * @constructor + * @param {AxiosInstance} client - The HTTP client instance + * @param {string} taxonomyUid - The taxonomy UID + */ constructor(client: AxiosInstance, taxonomyUid: string) { this._client = client; this._taxonomyUid = taxonomyUid; this._urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms`; } + /** + * @method find + * @memberof TermQuery + * @description Fetches all terms from the taxonomy + * @returns {Promise>} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').term().find(); + */ async find(): Promise> { const response = await getData(this._client, this._urlPath, { params: this._queryParams }); return response as FindResponse; diff --git a/src/lib/term.ts b/src/lib/term.ts index 20847ef7..0209acd5 100644 --- a/src/lib/term.ts +++ b/src/lib/term.ts @@ -1,11 +1,21 @@ import { AxiosInstance, getData } from "@contentstack/core"; +/** + * @class Term + * @description Represents a taxonomy term with methods to fetch term data, locales, ancestors, and descendants + */ export class Term { protected _client: AxiosInstance; private _taxonomyUid: string; private _termUid: string; private _urlPath: string; + /** + * @constructor + * @param {AxiosInstance} client - The HTTP client instance + * @param {string} taxonomyUid - The taxonomy UID + * @param {string} termUid - The term UID + */ constructor(client: AxiosInstance, taxonomyUid: string, termUid: string) { this._client = client; this._taxonomyUid = taxonomyUid; @@ -64,6 +74,17 @@ export class Term { return response; } + /** + * @method fetch + * @memberof Term + * @description Fetches the term data by UID + * @returns {Promise} + * @example + * import contentstack from '@contentstack/delivery-sdk' + * + * const stack = contentstack.stack({ apiKey: "apiKey", deliveryToken: "deliveryToken", environment: "environment" }); + * const result = await stack.taxonomy('taxonomy_uid').term('term_uid').fetch(); + */ async fetch(): Promise { const response = await getData(this._client, this._urlPath); if (response.term) return response.term as T; From 62e3994076fd86a09c29e79165c12e8f20d96a4a Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 15:30:40 +0530 Subject: [PATCH 10/13] docs: Update descriptions in Taxonomy and Term classes to clarify published status and feature flag requirements --- src/lib/taxonomy-query.ts | 2 +- src/lib/taxonomy.ts | 2 +- src/lib/term-query.ts | 4 ++-- src/lib/term.ts | 10 +++++----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib/taxonomy-query.ts b/src/lib/taxonomy-query.ts index ec8ae9d6..26da6a8b 100644 --- a/src/lib/taxonomy-query.ts +++ b/src/lib/taxonomy-query.ts @@ -11,7 +11,7 @@ export class TaxonomyQuery extends Query { /** * @method find * @memberof TaxonomyQuery - * @description Fetches all taxonomies of the stack using /taxonomy-manager endpoint + * @description Fetches a list of all published taxonomies available in the stack. * @returns {Promise>} * @example * import contentstack from '@contentstack/delivery-sdk' diff --git a/src/lib/taxonomy.ts b/src/lib/taxonomy.ts index 1e25ca6f..64a7086f 100644 --- a/src/lib/taxonomy.ts +++ b/src/lib/taxonomy.ts @@ -4,7 +4,7 @@ import { Term } from './term'; /** * @class Taxonomy - * @description Represents a taxonomy with methods to fetch taxonomy data and manage terms + * @description Represents a published taxonomy with methods to fetch taxonomy data and manage terms. Requires taxonomy_publish feature flag to be enabled. */ export class Taxonomy { private _client: AxiosInstance; diff --git a/src/lib/term-query.ts b/src/lib/term-query.ts index f589db41..8f0a4ce2 100644 --- a/src/lib/term-query.ts +++ b/src/lib/term-query.ts @@ -3,7 +3,7 @@ import { FindResponse } from './types'; /** * @class TermQuery - * @description Represents a query for fetching multiple terms from a taxonomy + * @description Represents a query for fetching multiple published terms from a taxonomy. Requires taxonomy_publish feature flag to be enabled. */ export class TermQuery { private _taxonomyUid: string; @@ -25,7 +25,7 @@ export class TermQuery { /** * @method find * @memberof TermQuery - * @description Fetches all terms from the taxonomy + * @description Fetches a list of all published terms within a specific taxonomy. * @returns {Promise>} * @example * import contentstack from '@contentstack/delivery-sdk' diff --git a/src/lib/term.ts b/src/lib/term.ts index 0209acd5..c4799db8 100644 --- a/src/lib/term.ts +++ b/src/lib/term.ts @@ -2,7 +2,7 @@ import { AxiosInstance, getData } from "@contentstack/core"; /** * @class Term - * @description Represents a taxonomy term with methods to fetch term data, locales, ancestors, and descendants + * @description Represents a published taxonomy term with methods to fetch term data, locales, ancestors, and descendants. Requires taxonomy_publish feature flag to be enabled. */ export class Term { protected _client: AxiosInstance; @@ -26,7 +26,7 @@ export class Term { /** * @method locales * @memberof Term - * @description Fetches locales for the term + * @description Fetches all published, localized versions of a single term. * @returns {Promise} * @example * import contentstack from '@contentstack/delivery-sdk' @@ -43,7 +43,7 @@ export class Term { /** * @method ancestors * @memberof Term - * @description Fetches ancestors for the term + * @description Fetches all ancestors of a single published term, up to the root. * @returns {Promise} * @example * import contentstack from '@contentstack/delivery-sdk' @@ -60,7 +60,7 @@ export class Term { /** * @method descendants * @memberof Term - * @description Fetches descendants for the term + * @description Fetches all descendants of a single published term. * @returns {Promise} * @example * import contentstack from '@contentstack/delivery-sdk' @@ -77,7 +77,7 @@ export class Term { /** * @method fetch * @memberof Term - * @description Fetches the term data by UID + * @description Fetches all descendants of a single published term. * @returns {Promise} * @example * import contentstack from '@contentstack/delivery-sdk' From 6a8122f307796035c17a772648c787ab4ccb58cb Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 17:17:36 +0530 Subject: [PATCH 11/13] feat: type definitions for taxonomy management --- src/lib/types.ts | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/lib/types.ts b/src/lib/types.ts index a5106675..b80e80e8 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -14,25 +14,25 @@ export type queryParams = { /** * Interface for creating Contentstack plugins - * + * * @example * ```typescript * import { ContentstackPlugin } from '@contentstack/delivery-sdk'; - * + * * class MyPlugin implements ContentstackPlugin { * onRequest(config: any): any { * // Modify request configuration * console.log('Processing request:', config.url); * return { ...config, headers: { ...config.headers, 'X-Custom-Header': 'value' } }; * } - * + * * onResponse(request: any, response: any, data: any): any { * // Process response data * console.log('Processing response:', response.status); * return { ...response, data: { ...data, processed: true } }; * } * } - * + * * const stack = contentstack.stack({ * apiKey: 'your-api-key', * deliveryToken: 'your-delivery-token', @@ -342,3 +342,31 @@ export type LivePreview = { management_token?: string; preview_token?: string; }; + +export interface BaseTaxonomy { + uid: string; + name: string; + description?: string; + terms_count?: number; + created_at: string; + updated_at: string; + created_by: string; + updated_by: string; + type: string; + ACL: ACL; + publish_details?: PublishDetails; +} + +export interface BaseTerm { + taxonomy_uid: string; + uid: string; + name: string; + created_by: string; + created_at: string; + updated_by: string; + updated_at: string; + children_count?: number; + depth?: number; + ACL: ACL; + publish_details?: PublishDetails; +} \ No newline at end of file From 13fa7d9c25d2cca9c49cabedff54d897d3a1811c Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Mon, 15 Dec 2025 13:12:33 +0530 Subject: [PATCH 12/13] refactor: update API endpoints from /taxonomy-manager to /taxonomies --- src/lib/taxonomy-query.ts | 2 +- src/lib/taxonomy.ts | 2 +- src/lib/term-query.ts | 2 +- src/lib/term.ts | 2 +- test/unit/taxonomy.spec.ts | 4 ++-- test/unit/term-query.spec.ts | 2 +- test/unit/term.spec.ts | 8 ++++---- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/lib/taxonomy-query.ts b/src/lib/taxonomy-query.ts index 26da6a8b..11e6d9ba 100644 --- a/src/lib/taxonomy-query.ts +++ b/src/lib/taxonomy-query.ts @@ -21,7 +21,7 @@ export class TaxonomyQuery extends Query { * const result = await taxonomyQuery.find(); */ override async find(): Promise> { - this._urlPath = "/taxonomy-manager"; // TODO: change to /taxonomies + this._urlPath = "/taxonomies"; const response = await getData(this._client, this._urlPath, { params: this._queryParams, }); diff --git a/src/lib/taxonomy.ts b/src/lib/taxonomy.ts index 64a7086f..719fefd5 100644 --- a/src/lib/taxonomy.ts +++ b/src/lib/taxonomy.ts @@ -21,7 +21,7 @@ export class Taxonomy { constructor(client: AxiosInstance, taxonomyUid: string) { this._client = client; this._taxonomyUid = taxonomyUid; - this._urlPath = `/taxonomy-manager/${this._taxonomyUid}`; // TODO: change to /taxonomies/${this._taxonomyUid} + this._urlPath = `/taxonomies/${this._taxonomyUid}`; } /** diff --git a/src/lib/term-query.ts b/src/lib/term-query.ts index 8f0a4ce2..e707bcdb 100644 --- a/src/lib/term-query.ts +++ b/src/lib/term-query.ts @@ -19,7 +19,7 @@ export class TermQuery { constructor(client: AxiosInstance, taxonomyUid: string) { this._client = client; this._taxonomyUid = taxonomyUid; - this._urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms`; + this._urlPath = `/taxonomies/${this._taxonomyUid}/terms`; } /** diff --git a/src/lib/term.ts b/src/lib/term.ts index c4799db8..bfbb7657 100644 --- a/src/lib/term.ts +++ b/src/lib/term.ts @@ -20,7 +20,7 @@ export class Term { this._client = client; this._taxonomyUid = taxonomyUid; this._termUid = termUid; - this._urlPath = `/taxonomy-manager/${this._taxonomyUid}/terms/${this._termUid}`; // TODO: change to /taxonomies + this._urlPath = `/taxonomies/${this._taxonomyUid}/terms/${this._termUid}`; } /** diff --git a/test/unit/taxonomy.spec.ts b/test/unit/taxonomy.spec.ts index 5db38cb6..e0f172db 100644 --- a/test/unit/taxonomy.spec.ts +++ b/test/unit/taxonomy.spec.ts @@ -34,13 +34,13 @@ describe('ta class', () => { }); it('should return all taxonomies in the response data when successful', async () => { - mockClient.onGet('/taxonomy-manager').reply(200, taxonomyFindResponseDataMock); //TODO: change to /taxonomies + mockClient.onGet('/taxonomies').reply(200, taxonomyFindResponseDataMock); const response = await taxonomies.find(); expect(response).toEqual(taxonomyFindResponseDataMock); }); it('should return single taxonomy in the response data when successful', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing').reply(200, taxonomyFindResponseDataMock.taxonomies[0]); //TODO: change to /taxonomies/taxonomyUid + mockClient.onGet('/taxonomies/taxonomy_testing').reply(200, taxonomyFindResponseDataMock.taxonomies[0]); const response = await taxonomy.fetch(); expect(response).toEqual(taxonomyFindResponseDataMock.taxonomies[0]); }); diff --git a/test/unit/term-query.spec.ts b/test/unit/term-query.spec.ts index a96019d0..8b09fa11 100644 --- a/test/unit/term-query.spec.ts +++ b/test/unit/term-query.spec.ts @@ -19,7 +19,7 @@ describe('TermQuery class', () => { }); it('should return response data when successful', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms').reply(200, termQueryFindResponseDataMock); + mockClient.onGet('/taxonomies/taxonomy_testing/terms').reply(200, termQueryFindResponseDataMock); const response = await termQuery.find(); expect(response).toEqual(termQueryFindResponseDataMock); }); diff --git a/test/unit/term.spec.ts b/test/unit/term.spec.ts index 0c404a43..3d41c234 100644 --- a/test/unit/term.spec.ts +++ b/test/unit/term.spec.ts @@ -20,28 +20,28 @@ describe('Term class', () => { }); it('should fetch the term by uid response when fetch method is called', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1').reply(200, termQueryFindResponseDataMock.terms[0]); //TODO: change to /taxonomies + mockClient.onGet('/taxonomies/taxonomy_testing/terms/term1').reply(200, termQueryFindResponseDataMock.terms[0]); const response = await term.fetch(); expect(response).toEqual(termQueryFindResponseDataMock.terms[0]); }); it('should fetch locales for a term when locales() is called', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/locales').reply(200, termLocalesResponseDataMock.terms); //TODO: change to /taxonomies + mockClient.onGet('/taxonomies/taxonomy_testing/terms/term1/locales').reply(200, termLocalesResponseDataMock.terms); const response = await term.locales(); expect(response).toEqual(termLocalesResponseDataMock.terms); }); it('should fetch ancestors for a term when ancestors() is called', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/ancestors').reply(200, termAncestorsResponseDataMock); + mockClient.onGet('/taxonomies/taxonomy_testing/terms/term1/ancestors').reply(200, termAncestorsResponseDataMock); const response = await term.ancestors(); expect(response).toEqual(termAncestorsResponseDataMock); }); it('should fetch descendants for a term when descendants() is called', async () => { - mockClient.onGet('/taxonomy-manager/taxonomy_testing/terms/term1/descendants').reply(200, termDescendantsResponseDataMock); + mockClient.onGet('/taxonomies/taxonomy_testing/terms/term1/descendants').reply(200, termDescendantsResponseDataMock); const response = await term.descendants(); expect(response).toEqual(termDescendantsResponseDataMock); From 43bc2aa86673e85f50dfcc9801b52756d0d20d4e Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Mon, 19 Jan 2026 14:01:49 +0530 Subject: [PATCH 13/13] test: update locales test case to include assertions --- test/api/term.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/api/term.spec.ts b/test/api/term.spec.ts index 3d994036..c7fbc126 100644 --- a/test/api/term.spec.ts +++ b/test/api/term.spec.ts @@ -15,10 +15,10 @@ describe("Terms API test cases", () => { }); it("should get locales for a term", async () => { - // const result = await makeTerms("vehicles").locales().fetch(); - // API under building phase, so it should throw error - expect(async () => await makeTerms("vehicles").locales()).rejects.toThrow(); - // TODO: add assertions + const result = await makeTerms("vehicles").locales(); + expect(result).toBeDefined(); + expect(result.terms).toBeDefined(); + expect(result.terms[0].name).toBeDefined(); }); it("should get ancestors for a term", async () => {