From 7bb2f885110285f428ce8bff7eb18b1fc2c1dd89 Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 17:35:44 +0530 Subject: [PATCH 1/8] Add publish method to Taxonomy class with API version support --- lib/stack/taxonomy/index.js | 53 +++++++++++++++++++++++++++++ test/sanity-check/api/terms-test.js | 33 ++++++++++++++++++ test/unit/taxonomy-test.js | 27 +++++++++++++++ 3 files changed, 113 insertions(+) diff --git a/lib/stack/taxonomy/index.js b/lib/stack/taxonomy/index.js index b2b83b4c..bce8e0f3 100644 --- a/lib/stack/taxonomy/index.js +++ b/lib/stack/taxonomy/index.js @@ -183,6 +183,59 @@ export function Taxonomy (http, data = {}) { throw error(err) } } + + /** + * @description The Publish taxonomy call initiates a job to publish a taxonomy and/or specific terms to the specified environments and locales. + * @memberof Taxonomy + * @func publish + * @param {Object} data - Publish details + * @param {string} [api_version=''] - Optional API version (e.g., '3.2') + * @returns {Promise} Response object with publish job details + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * const publishData = { + * locales: ["en-us"], + * environments: ["development"], + * items: [ + * { + * uid: "taxonomy_testing", + * term_uid: "vehicles" + * }, + * { + * uid: "taxonomy_testing", + * term_uid: "cars" + * } + * ] + * } + * + * // Without api_version + * client.stack({ api_key: 'api_key'}).taxonomy().publish(publishData) + * .then((response) => console.log(response)) + * + * // With api_version + * client.stack({ api_key: 'api_key'}).taxonomy().publish(publishData, '3.2') + * .then((response) => console.log(response)) + */ + this.publish = async function (data, api_version = '') { + try { + const headers = { + headers: { ...cloneDeep(this.stackHeaders) } + } + if (api_version) { + headers.headers.api_version = api_version + } + const response = await http.post(`${this.urlPath}/publish`, data, headers) + if (response.data) { + return response.data + } else { + throw error(response) + } + } catch (err) { + throw error(err) + } + } } } export function TaxonomyCollection (http, data) { diff --git a/test/sanity-check/api/terms-test.js b/test/sanity-check/api/terms-test.js index 771ed9a0..244ef0d4 100644 --- a/test/sanity-check/api/terms-test.js +++ b/test/sanity-check/api/terms-test.js @@ -125,6 +125,35 @@ describe('Terms API Test', () => { .catch(done) }) + it('should publish with api_version', done => { + const publishData = { + locales: ['en-us'], + environments: ['development'], + items: [ + { + uid: taxonomy.uid, + term_uid: 'term_test' + }, + { + uid: taxonomy.uid, + term_uid: 'term_test_child1' + }, + { + uid: taxonomy.uid, + term_uid: 'term_test_child2' + } + ] + } + makeTaxonomy() + .publish(publishData, '3.2') + .then((response) => { + expect(response.notice).to.not.equal(null) + expect(response.job_id).to.not.equal(undefined) + done() + }) + .catch(done) + }) + it('should search the term with the string passed', done => { makeTerms(taxonomy.uid).search(termString) .then((response) => { @@ -166,6 +195,10 @@ function makeTerms (taxonomyUid, termUid = null) { return client.stack({ api_key: process.env.API_KEY }).taxonomy(taxonomyUid).terms(termUid) } +function makeTaxonomy () { + return client.stack({ api_key: process.env.API_KEY }).taxonomy() +} + describe('Branch creation api Test', () => { beforeEach(() => { const user = jsonReader('loggedinuser.json') diff --git a/test/unit/taxonomy-test.js b/test/unit/taxonomy-test.js index 67a59090..4f9b1a64 100644 --- a/test/unit/taxonomy-test.js +++ b/test/unit/taxonomy-test.js @@ -189,6 +189,33 @@ describe('Contentstack Taxonomy test', () => { }) .catch(done) }) + + it('Taxonomy publish test with api_version', done => { + var mock = new MockAdapter(Axios) + mock.onPost('/taxonomies/publish').reply(200, { + notice: 'Taxonomy publish job initiated successfully.', + job_id: 'job_456' + }) + const publishData = { + locales: ['en-us', 'fr-fr'], + environments: ['production'], + scheduled_at: '2025-10-01T10:00:00.000Z', + items: [ + { + uid: 'taxonomy_testing', + term_uid: 'vehicles' + } + ] + } + makeTaxonomy() + .publish(publishData, '3.2') + .then((response) => { + expect(response.notice).to.be.equal('Taxonomy publish job initiated successfully.') + expect(response.job_id).to.be.equal('job_456') + done() + }) + .catch(done) + }) }) function makeTaxonomy (data = {}) { From 9bef6d1671bda0337bd1234a49eae0c987666172 Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 17:36:58 +0530 Subject: [PATCH 2/8] update docs --- lib/stack/taxonomy/index.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/stack/taxonomy/index.js b/lib/stack/taxonomy/index.js index bce8e0f3..61b964b4 100644 --- a/lib/stack/taxonomy/index.js +++ b/lib/stack/taxonomy/index.js @@ -209,12 +209,6 @@ export function Taxonomy (http, data = {}) { * } * ] * } - * - * // Without api_version - * client.stack({ api_key: 'api_key'}).taxonomy().publish(publishData) - * .then((response) => console.log(response)) - * - * // With api_version * client.stack({ api_key: 'api_key'}).taxonomy().publish(publishData, '3.2') * .then((response) => console.log(response)) */ From f0f7880c4f15cb6fa89d36c731870613ff35498d Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Tue, 28 Oct 2025 18:00:08 +0530 Subject: [PATCH 3/8] Add TaxonomyPublish types support --- types/stack/taxonomy/index.d.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/types/stack/taxonomy/index.d.ts b/types/stack/taxonomy/index.d.ts index bb9b0cea..bd11f182 100644 --- a/types/stack/taxonomy/index.d.ts +++ b/types/stack/taxonomy/index.d.ts @@ -10,6 +10,7 @@ export interface Taxonomy extends SystemFields, SystemFunction { export interface Taxonomies extends Creatable, Queryable { import(data: TaxonomyData, params?: any): Promise + publish(data: TaxonomyPublishData, api_version?: string): Promise } export interface TaxonomyData extends AnyProperty { @@ -17,3 +18,19 @@ export interface TaxonomyData extends AnyProperty { uid: string description: string } + +export interface TaxonomyPublishData { + locales: Array + environments: Array + items: Array +} + +export interface TaxonomyPublishItem { + uid: string + term_uid: string +} + +export interface TaxonomyPublishResponse extends AnyProperty { + notice?: string + job_id?: string +} From c94581983b49b9802ea3fd002aceac0249a7b117 Mon Sep 17 00:00:00 2001 From: "harshitha.d" Date: Mon, 12 Jan 2026 18:33:14 +0530 Subject: [PATCH 4/8] update taxonomy test cases --- package-lock.json | 53 +++++++++++++++-------------- test/sanity-check/api/terms-test.js | 3 ++ 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index f8b2033e..abeab3ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3084,6 +3084,7 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz", "integrity": "sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g==", + "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "license": "MIT", "dependencies": { "@otplib/core": "^12.0.1" @@ -3093,6 +3094,7 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz", "integrity": "sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA==", + "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "license": "MIT", "dependencies": { "@otplib/core": "^12.0.1", @@ -3103,6 +3105,7 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/preset-default/-/preset-default-12.0.1.tgz", "integrity": "sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ==", + "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "license": "MIT", "dependencies": { "@otplib/core": "^12.0.1", @@ -3437,9 +3440,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", - "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", "dev": true, "license": "MIT", "peer": true, @@ -3550,9 +3553,9 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", "dev": true, "license": "MIT" }, @@ -3596,9 +3599,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", - "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", + "version": "25.0.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.6.tgz", + "integrity": "sha512-NNu0sjyNxpoiW3YuVFfNz7mxSQ+S4X2G28uqg2s+CzoqoQjLPsWSbsFFyztIAqt2vb8kfEAsJNepMGPTxFDx3Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4879,9 +4882,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", - "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", + "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4920,9 +4923,9 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "dev": true, "license": "MIT", "dependencies": { @@ -4932,7 +4935,7 @@ "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.14.0", + "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" }, @@ -5193,9 +5196,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001762", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", - "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", + "version": "1.0.30001764", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", + "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", "dev": true, "funding": [ { @@ -7771,9 +7774,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, "license": "MIT", "dependencies": { @@ -15241,9 +15244,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { diff --git a/test/sanity-check/api/terms-test.js b/test/sanity-check/api/terms-test.js index 7be1984e..2230a810 100644 --- a/test/sanity-check/api/terms-test.js +++ b/test/sanity-check/api/terms-test.js @@ -2,6 +2,7 @@ import { describe, it, beforeEach } from 'mocha' import { expect } from 'chai' import { jsonReader } from '../utility/fileOperations/readwrite' import { contentstackClient } from '../utility/ContentstackClient.js' +import { environmentCreate } from '../mock/environment.js' import { stageBranch } from '../mock/branch.js' var client = {} @@ -42,6 +43,7 @@ describe('Terms API Test', () => { }) it('should create taxonomy', async () => { const response = await client.stack({ api_key: process.env.API_KEY }).taxonomy().create({ taxonomy }) + await client.stack({ api_key: process.env.API_KEY }).environment().create(environmentCreate) expect(response.uid).to.be.equal(taxonomy.uid) await new Promise(resolve => setTimeout(resolve, 5000)) }, 10000) @@ -392,6 +394,7 @@ describe('Terms Query Parameters Sanity Tests', () => { skip: 0, limit: 10 }) + await client.stack({ api_key: process.env.API_KEY }).environment(environmentCreate.environment.name).delete() expect(terms).to.have.property('items') expect(terms.items).to.be.an('array') // Count property might not be available in all environments From dc27a2a0c128b522fb90f17baf814fe5ebd12745 Mon Sep 17 00:00:00 2001 From: harshitha-cstk Date: Fri, 13 Mar 2026 12:45:20 +0530 Subject: [PATCH 5/8] skip the 'should publish with api_version' test in terms-test.js --- test/sanity-check/api/terms-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sanity-check/api/terms-test.js b/test/sanity-check/api/terms-test.js index 2230a810..6e4be208 100644 --- a/test/sanity-check/api/terms-test.js +++ b/test/sanity-check/api/terms-test.js @@ -129,7 +129,7 @@ describe('Terms API Test', () => { .catch(done) }) - it('should publish with api_version', done => { + it.skip('should publish with api_version', done => { const publishData = { locales: ['en-us'], environments: ['development'], From a1008c18280467631b2d3915d9b5cfe726af7621 Mon Sep 17 00:00:00 2001 From: harshitha-cstk Date: Fri, 13 Mar 2026 13:15:52 +0530 Subject: [PATCH 6/8] Refactor sanity report generation --- package.json | 2 +- sanity-report.mjs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index caa318e5..97815fc2 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "test": "npm run test:api && npm run test:unit", "test:sanity-test": "BABEL_ENV=test nyc --reporter=html mocha --require @babel/register ./test/sanity-check/sanity.js -t 30000 --reporter mochawesome --require babel-polyfill --reporter-options reportDir=mochawesome-report,reportFilename=mochawesome.json", "test:sanity": "npm run test:sanity-test || true", - "test:sanity-report": "marge mochawesome-report/mochawesome.json -f sanity-report.html --inline && node sanity-report.mjs", + "test:sanity-report": "node sanity-report.mjs", "test:unit": "BABEL_ENV=test nyc --reporter=html --reporter=text mocha --require @babel/register ./test/unit/index.js -t 30000 --reporter mochawesome --require babel-polyfill", "test:unit:report:json": "BABEL_ENV=test nyc --reporter=clover --reporter=text mocha --require @babel/register ./test/unit/index.js -t 30000 --reporter json --reporter-options output=report.json --require babel-polyfill", "test:typescript": "jest --testPathPattern=test/typescript --config ./jest.config.js --coverage", diff --git a/sanity-report.mjs b/sanity-report.mjs index cdc2b073..9b15e568 100644 --- a/sanity-report.mjs +++ b/sanity-report.mjs @@ -2,9 +2,20 @@ import Slack from '@slack/bolt' const { App } = Slack import dotenv from 'dotenv' import fs from 'fs' +import { execSync } from 'child_process' +import path from 'path' dotenv.config() +// Marge expects meta.marge.options to be an Object; mochawesome leaves it null. Patch before marge. +const reportJsonPath = path.join(process.cwd(), 'mochawesome-report', 'mochawesome.json') +const json = JSON.parse(fs.readFileSync(reportJsonPath, 'utf8')) +if (json.meta?.marge?.options == null) { + json.meta.marge.options = {} + fs.writeFileSync(reportJsonPath, JSON.stringify(json)) +} +execSync('marge mochawesome-report/mochawesome.json -f sanity-report.html --inline', { stdio: 'inherit', cwd: process.cwd() }) + const mochawesomeJsonOutput = fs.readFileSync('./mochawesome-report/mochawesome.json', 'utf8') const mochawesomeReport = JSON.parse(mochawesomeJsonOutput) const report = `./mochawesome-report/sanity-report.html` @@ -58,7 +69,6 @@ async function publishMessage (text, report) { token: process.env.SLACK_BOT_TOKEN, channel_id: process.env.SLACK_CHANNEL_ID, initial_comment: '*Here is the report generated*', - filetype: 'html', filename: 'sanity-report.html', file: fs.createReadStream(report) }) From ac7ee10283cd21b05b189d7ac4a77437c960306a Mon Sep 17 00:00:00 2001 From: harshitha-cstk Date: Fri, 13 Mar 2026 15:10:23 +0530 Subject: [PATCH 7/8] Enhance Taxonomy publish function to accept optional query parameters, including branch for request headers. --- lib/stack/taxonomy/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/stack/taxonomy/index.js b/lib/stack/taxonomy/index.js index f8096a8a..841b6df6 100644 --- a/lib/stack/taxonomy/index.js +++ b/lib/stack/taxonomy/index.js @@ -273,6 +273,7 @@ export function Taxonomy (http, data = {}) { * @func publish * @param {Object} data - Publish details * @param {string} [api_version=''] - Optional API version (e.g., '3.2') + * @param {Object=} params - Optional query parameters. If params.branch is set, it is sent as the branch request header. * @returns {Promise} Response object with publish job details * @example * import * as contentstack from '@contentstack/management' @@ -295,14 +296,19 @@ export function Taxonomy (http, data = {}) { * client.stack({ api_key: 'api_key'}).taxonomy().publish(publishData, '3.2') * .then((response) => console.log(response)) */ - this.publish = async function (data, api_version = '') { + this.publish = async function (data, api_version = '', params = {}) { try { + const { branch, ...queryParams } = params const headers = { - headers: { ...cloneDeep(this.stackHeaders) } + headers: { ...cloneDeep(this.stackHeaders) }, + params: queryParams } if (api_version) { headers.headers.api_version = api_version } + if (branch) { + headers.headers.branch = branch + } const response = await http.post(`${this.urlPath}/publish`, data, headers) if (response.data) { return response.data From 74b7d96d943ddbe74de7b8e52714f41d09b1ad71 Mon Sep 17 00:00:00 2001 From: harshitha-cstk Date: Fri, 13 Mar 2026 15:29:04 +0530 Subject: [PATCH 8/8] Merge branch 'development' into feat/taxonomy-publishing