From a448fd1506fbbcddcda142f903c2130d3d8b255d Mon Sep 17 00:00:00 2001 From: abhinav <63039365+abhinav-from-contentstack@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:19:49 +0530 Subject: [PATCH] Next (#97) * fix: fixed issue while updating entries with assets * feat: added api test * fix: updated changelog and package lock file * Implemented Management token support (#99) * Implemented Management token support * Fixed PR Comments * test: added sanity tests for user and contenttype * added a script in package.json --------- Co-authored-by: sunil-lakshman <104969541+sunil-lakshman@users.noreply.github.com> Co-authored-by: harshithad0703 Co-authored-by: harshithad0703 <104908717+harshithad0703@users.noreply.github.com> --- .gitignore | 1 + CHANGELOG.md | 6 + lib/entity.js | 24 ++- lib/stack/index.js | 23 +++ lib/stack/managementToken/index.js | 111 ++++++++++ package-lock.json | 157 +++++++++++--- package.json | 5 +- test/api/entry-test.js | 37 ++++ test/api/managementToken-test.js | 136 +++++++++++++ test/api/mock/managementToken.js | 73 +++++++ .../api/contentType-delete-test.js | 28 +++ test/sanity-check/api/contentType-test.js | 123 +++++++++++ test/sanity-check/api/user-test.js | 77 +++++++ test/sanity-check/mock/content-type.js | 179 ++++++++++++++++ test/sanity-check/mock/contentType.json | 36 ++++ test/sanity-check/sanity.js | 3 + .../utility/ContentstackClient.js | 12 ++ .../utility/fileOperations/readwrite.js | 35 ++++ test/test.js | 1 + test/typescript/index.test.ts | 6 + test/typescript/managementToken.ts | 131 ++++++++++++ test/typescript/mock/managementToken.ts | 73 +++++++ test/unit/entry-test.js | 191 ++++++++++++++++++ test/unit/index.js | 1 + test/unit/managementToken-test.js | 180 +++++++++++++++++ test/unit/mock/objects.js | 19 +- types/stack/index.d.ts | 4 + types/stack/managementToken/index.ts | 27 +++ 28 files changed, 1664 insertions(+), 35 deletions(-) create mode 100644 lib/stack/managementToken/index.js create mode 100644 test/api/managementToken-test.js create mode 100644 test/api/mock/managementToken.js create mode 100644 test/sanity-check/api/contentType-delete-test.js create mode 100644 test/sanity-check/api/contentType-test.js create mode 100644 test/sanity-check/api/user-test.js create mode 100644 test/sanity-check/mock/content-type.js create mode 100644 test/sanity-check/mock/contentType.json create mode 100644 test/sanity-check/sanity.js create mode 100644 test/sanity-check/utility/ContentstackClient.js create mode 100644 test/sanity-check/utility/fileOperations/readwrite.js create mode 100644 test/typescript/managementToken.ts create mode 100644 test/typescript/mock/managementToken.ts create mode 100644 test/unit/managementToken-test.js create mode 100644 types/stack/managementToken/index.ts diff --git a/.gitignore b/.gitignore index b6a96d1c..52bba02c 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ jspm_packages/ mochawesome-report/ coverage/ test/utility/dataFiles/ +test/sanity-check/utility/dataFiles/ report.json # TypeScript v1 declaration files diff --git a/CHANGELOG.md b/CHANGELOG.md index b19a1660..23923286 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [v1.13.1](https://github.com/contentstack/contentstack-management-javascript/tree/v1.13.1) (2023-12-13) + - Fixes + - Fix for issue while updating entries with assets +## [v1.14.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.14.0) (2023-12-19) + - Feature + - Management token feature added ## [v1.13.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.13.0) (2023-11-21) - Feature - Teams API support diff --git a/lib/entity.js b/lib/entity.js index 7a9246b3..268d930d 100644 --- a/lib/entity.js +++ b/lib/entity.js @@ -137,7 +137,8 @@ export const update = (http, type, params = {}) => { delete json.updated_by delete json.updated_at if (type) { - updateData[type] = json + updateData[type] = json; + if (type === "entry") updateData[type] = cleanAssets(updateData[type]); } else { updateData = json } @@ -309,3 +310,24 @@ export const move = (http, type, force = false, params = {}) => { } } } + +function isAsset (data) { + const element = (Array.isArray(data) && data.length > 0) ? data[0] : data; + return (!!element.file_size || !!element.content_type) && !!element.uid; +} + +export function cleanAssets (data) { + if (typeof data === "object" && Object.keys(data).length > 0) { + const keys = Object.keys(data); + for (const key of keys) { + if (typeof data[key] === "object" && Object.keys(data[key]).length > 0) { + if (isAsset(data[key])) { + data[key] = (Array.isArray(data[key])) ? data[key].map(element => element.uid) : data[key].uid; + } else { + cleanAssets(data[key]); + } + } + } + } + return data; +} diff --git a/lib/stack/index.js b/lib/stack/index.js index d86f72cb..f63bb264 100644 --- a/lib/stack/index.js +++ b/lib/stack/index.js @@ -19,6 +19,7 @@ import { Branch } from './branch' import { BranchAlias } from './branchAlias' import { AuditLog } from './auditlog' import { Taxonomy } from './taxonomy' +import { ManagementToken } from './managementToken' /** * A stack is a space that stores the content of a project (a web or mobile property). Within a stack, you can create content structures, content entries, users, etc. related to the project. Read more about Stacks. @@ -257,6 +258,28 @@ export function Stack (http, data) { return new DeliveryToken(http, data) } + /** + * @description Management Tokens are tokens that provide you with read-write access to the content of your stack. + * @param {String} managementTokenUid The UID of the Management Token field you want to get details. + * @returns {ManagementToken} Instance of ManagementToken. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.stack({ api_key: 'api_key'}).managementToken().create() + * .then((managementToken) => console.log(managementToken)) + * + * client.stack({ api_key: 'api_key'}).managementToken('managementToken_uid').fetch() + * .then((managementToken) => console.log(managementToken)) + */ + this.managementToken = (managementTokenUid = null) => { + const data = { stackHeaders: this.stackHeaders } + if (managementTokenUid) { + data.token = { uid: managementTokenUid } + } + return new ManagementToken(http, data) + } + /** * @description Extensions let you create custom fields and custom widgets that lets you customize Contentstack's default UI and behavior. * @param {String} extensionUid The UID of the Extension you want to get details. diff --git a/lib/stack/managementToken/index.js b/lib/stack/managementToken/index.js new file mode 100644 index 00000000..d8b455e6 --- /dev/null +++ b/lib/stack/managementToken/index.js @@ -0,0 +1,111 @@ +import cloneDeep from 'lodash/cloneDeep' +import { create, update, deleteEntity, fetch, query } from '../../entity' + +/** + * Management tokens provide read-only access to the associated environments. Read more about ManagementToken. + * @namespace ManagementToken + */ +export function ManagementToken (http, data = {}) { + this.stackHeaders = data.stackHeaders + this.urlPath = `/stacks/management_tokens` + if (data.token) { + Object.assign(this, cloneDeep(data.token)) + this.urlPath = `/stacks/management_tokens/${this.uid}` + /** + * @description The Update ManagementToken call lets you update the name and description of an existing ManagementToken. + * @memberof ManagementToken + * @func update + * @returns {Promise} Promise for ManagementToken instance + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.stack({ api_key: 'api_key'}).managementToken('management_token_uid').fetch() + * .then((managementToken) => { + * managementToken.title = 'My New management token' + * managementToken.description = 'management token description' + * return managementToken.update() + * }) + * .then((managementToken) => console.log(managementToken)) + * + */ + this.update = update(http, 'token') + + /** + * @description The Delete ManagementToken call is used to delete an existing ManagementToken permanently from your Stack. + * @memberof ManagementToken + * @func delete + * @returns {Object} Response Object. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.stack({ api_key: 'api_key'}).managementToken('management_token_uid').delete() + * .then((response) => console.log(response.notice)) + */ + this.delete = deleteEntity(http) + + /** + * @description The fetch ManagementToken call fetches ManagementToken details. + * @memberof ManagementToken + * @func fetch + * @returns {Promise} Promise for ManagementToken instance + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.stack({ api_key: 'api_key'}).managementToken('management_token_uid').fetch() + * .then((managementToken) => console.log(managementToken)) + * + */ + this.fetch = fetch(http, 'token') + } else { + /** + * @description The Create a ManagementToken call creates a new ManagementToken in a particular stack of your Contentstack account. + * @memberof ManagementToken + * @func create + * @returns {Promise} Promise for ManagementToken instance + * + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * const token = { + * name: 'Test', + * description: 'This is a demo token.', + * scope: [{ + * module: 'environment', + * environments: ['development'], + * acl: { + * read: true + * } + * }] + * } + * + * client.stack().managementToken().create({ token }) + * .then((managementToken) => console.log(managementToken)) + */ + this.create = create({ http: http }) + + /** + * @description The ‘Get all managementToken’ request returns comprehensive information about all managementToken created in a stack. + * @memberof ManagementToken + * @func query + * @returns {ContentstackCollection} Instance of ContentstackCollection. + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * client.stack().managementToken().query({ query: { name: 'token_name' } })).find() + * .then((contentstackCollection) => console.log(contentstackCollection)) + */ + this.query = query({ http: http, wrapperCollection: ManagementTokenCollection }) + } +} + +export function ManagementTokenCollection (http, data) { + const obj = cloneDeep(data.tokens) || [] + const managementTokenCollection = obj.map((managementTokenData) => { + return new ManagementToken(http, { token: managementTokenData, stackHeaders: data.stackHeaders }) + }) + return managementTokenCollection +} diff --git a/package-lock.json b/package-lock.json index aaa58d6e..f621ba2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "@contentstack/management", - "version": "1.11.0", - "lockfileVersion": 2, + "version": "1.14.0", + "lockfileVersion": 1, "requires": true, "packages": { "": { @@ -12870,8 +12870,7 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "requires": {} + "dev": true }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -13691,21 +13690,112 @@ } }, "@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", - "debug": "^4.1.0", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "requires": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/types": { @@ -14592,6 +14682,12 @@ "@babel/types": "^7.20.7" } }, + "@types/chai": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", + "dev": true + }, "@types/eslint": { "version": "8.44.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz", @@ -14689,6 +14785,12 @@ "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", "dev": true }, + "@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true + }, "@types/markdown-it": { "version": "12.2.3", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", @@ -14906,8 +15008,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", - "dev": true, - "requires": {} + "dev": true }, "@webpack-cli/info": { "version": "1.5.0", @@ -14922,8 +15023,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", - "dev": true, - "requires": {} + "dev": true }, "@xtuc/ieee754": { "version": "1.2.0", @@ -14947,15 +15047,13 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "requires": {} + "dev": true }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "aggregate-error": { "version": "3.1.0", @@ -14983,8 +15081,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "ansi-colors": { "version": "4.1.1", @@ -16441,8 +16538,7 @@ "version": "13.0.1", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-13.0.1.tgz", "integrity": "sha512-zLKp4QOgq6JFgRm1dDCVv1Iu0P5uZ4v5Wa4DTOkg2RFMxdCX/9Qf7lz9ezRj2dBRa955cWQF/O/LWEiYWAHbTw==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.9", @@ -16565,8 +16661,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz", "integrity": "sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ==", - "dev": true, - "requires": {} + "dev": true }, "eslint-scope": { "version": "7.2.2", @@ -18310,8 +18405,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "28.0.2", @@ -19299,8 +19393,7 @@ "version": "8.6.7", "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", - "dev": true, - "requires": {} + "dev": true }, "marked": { "version": "4.3.0", diff --git a/package.json b/package.json index af403433..619ad9a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/management", - "version": "1.13.0", + "version": "1.14.0", "description": "The Content Management API is used to manage the content of your Contentstack account", "main": "./dist/node/contentstack-management.js", "browser": "./dist/web/contentstack-management.js", @@ -30,6 +30,7 @@ "buildnativescript": "webpack --config webpack/webpack.nativescript.js --mode production", "buildweb": "webpack --config webpack/webpack.web.js --mode production", "test": "npm run test:api && npm run test:unit", + "test:sanity": "BABEL_ENV=test nyc --reporter=html --reporter=text mocha --require @babel/register ./test/sanity-check/sanity.js -t 30000 --reporter mochawesome --require babel-polyfill", "test:api": "BABEL_ENV=test nyc --reporter=html --reporter=text mocha --require @babel/register ./test/test.js -t 30000 --reporter mochawesome --require babel-polyfill", "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", @@ -66,7 +67,9 @@ "@babel/preset-env": "^7.18.2", "@babel/register": "^7.17.7", "@babel/runtime": "^7.18.3", + "@types/chai": "^4.3.11", "@types/jest": "^28.1.0", + "@types/lodash": "^4.14.202", "@types/mocha": "^7.0.2", "axios-mock-adapter": "^1.21.1", "babel-loader": "^8.2.5", diff --git a/test/api/entry-test.js b/test/api/entry-test.js index d2a14cc2..73ed20ae 100644 --- a/test/api/entry-test.js +++ b/test/api/entry-test.js @@ -190,8 +190,45 @@ describe('Entry api Test', () => { }) .catch(done) }) + + it('Create and update an entry with asset', done => { + // get asset + let asset; + makeAsset() + .query() + .find() + .then((collection) => { + asset = collection.items[0]; + // create entry + let entry = { + ...entryFirst, + title: "uniqueTitle45", + modular_blocks: [ + { + block1: { + file: asset.uid + } + } + ] + }; + makeEntry(multiPageCT.content_type.uid) + .create({entry: entry}) + .then(entry => { + const newTitle = "updated title"; + entry.title = newTitle; + entry.update().then(updatedEntry => { + expect(updatedEntry.title).to.be.equal(newTitle); + done(); + }) + }) + }) + }); }) function makeEntry (contentType, uid = null) { return client.stack({ api_key: stack.api_key }).contentType(contentType).entry(uid) } + +function makeAsset (uid = null) { + return client.stack({ api_key: stack.api_key }).asset(uid) +} diff --git a/test/api/managementToken-test.js b/test/api/managementToken-test.js new file mode 100644 index 00000000..70aeb0df --- /dev/null +++ b/test/api/managementToken-test.js @@ -0,0 +1,136 @@ +import { expect } from 'chai' +import { describe, it, setup } from 'mocha' +import { jsonReader } from '../utility/fileOperations/readwrite' +import { createManagementToken, createManagementToken2 } from './mock/managementToken.js' +import { contentstackClient } from '../utility/ContentstackClient.js' + +var client = {} + +var stack = {} +var tokenUID = '' +describe('Management Token api Test', () => { + setup(() => { + const user = jsonReader('loggedinuser.json') + stack = jsonReader('stack.json') + client = contentstackClient(user.authtoken) + }) + + it('Add a Management Token', done => { + makeManagementToken() + .create(createManagementToken) + .then((token) => { + expect(token.name).to.be.equal(createManagementToken.token.name) + expect(token.description).to.be.equal(createManagementToken.token.description) + expect(token.scope[0].module).to.be.equal(createManagementToken.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + it('Add a Management Token for production', done => { + makeManagementToken() + .create(createManagementToken2) + .then((token) => { + tokenUID = token.uid + expect(token.name).to.be.equal(createManagementToken2.token.name) + expect(token.description).to.be.equal(createManagementToken2.token.description) + expect(token.scope[0].module).to.be.equal(createManagementToken2.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + it('Get a Management Token from uid', done => { + makeManagementToken(tokenUID) + .fetch() + .then((token) => { + expect(token.name).to.be.equal(createManagementToken2.token.name) + expect(token.description).to.be.equal(createManagementToken2.token.description) + expect(token.scope[0].module).to.be.equal(createManagementToken2.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + it('Query to get all Management Token', done => { + makeManagementToken() + .query() + .find() + .then((tokens) => { + tokens.items.forEach((token) => { + expect(token.name).to.be.not.equal(null) + expect(token.description).to.be.not.equal(null) + expect(token.scope[0].module).to.be.not.equal(null) + expect(token.uid).to.be.not.equal(null) + }) + done() + }) + .catch(done) + }) + + it('Query to get a Management Token from name', done => { + makeManagementToken() + .query({ query: { name: createManagementToken.token.name } }) + .find() + .then((tokens) => { + tokens.items.forEach((token) => { + expect(token.name).to.be.equal(createManagementToken.token.name) + expect(token.description).to.be.equal(createManagementToken.token.description) + expect(token.scope[0].module).to.be.equal(createManagementToken.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + }) + done() + }) + .catch(done) + }) + + it('Fetch and update a Management Token from uid', done => { + makeManagementToken(tokenUID) + .fetch() + .then((token) => { + token.name = 'Update Production Name' + token.description = 'Update Production description' + token.scope = createManagementToken2.token.scope + return token.update() + }) + .then((token) => { + expect(token.name).to.be.equal('Update Production Name') + expect(token.description).to.be.equal('Update Production description') + expect(token.scope[0].module).to.be.equal(createManagementToken2.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + it('Update a Management Token from uid', done => { + const token = makeManagementToken(tokenUID) + Object.assign(token, createManagementToken2.token) + token.update() + .then((token) => { + expect(token.name).to.be.equal(createManagementToken2.token.name) + expect(token.description).to.be.equal(createManagementToken2.token.description) + expect(token.scope[0].module).to.be.equal(createManagementToken2.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + it('Delete a Management Token from uid', done => { + makeManagementToken(tokenUID) + .delete() + .then((data) => { + expect(data.notice).to.be.equal('Management Token deleted successfully.') + done() + }) + .catch(done) + }) +}) + +function makeManagementToken (uid = null) { + return client.stack({ api_key: stack.api_key }).managementToken(uid) +} diff --git a/test/api/mock/managementToken.js b/test/api/mock/managementToken.js new file mode 100644 index 00000000..bd08d49e --- /dev/null +++ b/test/api/mock/managementToken.js @@ -0,0 +1,73 @@ +const createManagementToken = { + "token":{ + "name":"Test Token", + "description":"This is a sample management token.", + "scope":[ + { + "module":"content_type", + "acl":{ + "read":true, + "write":true + } + }, + { + "module":"branch", + "branches":[ + "main" + ], + "acl":{ + "read":true + } + }, + { + "module":"branch_alias", + "branch_aliases":[ + "tst" + ], + "acl":{ + "read":true + } + } + ], + "expires_on":"2024-12-10", + "is_email_notification_enabled":true + } +} +const createManagementToken2 = { + "token":{ + "name":"Test Token", + "description":"This is a sample management token.", + "scope":[ + { + "module":"content_type", + "acl":{ + "read":true, + "write":true + } + }, + { + "module":"branch", + "branches":[ + "main" + ], + "acl":{ + "read":true + } + }, + { + "module":"branch_alias", + "branch_aliases":[ + "tst" + ], + "acl":{ + "read":true + } + } + ], + "expires_on":"2024-12-10", + "is_email_notification_enabled":true + } +} + + export { createManagementToken, createManagementToken2 } + \ No newline at end of file diff --git a/test/sanity-check/api/contentType-delete-test.js b/test/sanity-check/api/contentType-delete-test.js new file mode 100644 index 00000000..e50722c5 --- /dev/null +++ b/test/sanity-check/api/contentType-delete-test.js @@ -0,0 +1,28 @@ +import { expect } from 'chai' +import { describe, it, setup } from 'mocha' +import { jsonReader } from '../utility/fileOperations/readwrite' +import { multiPageCT, singlepageCT } from '../mock/content-type' +import { contentstackClient } from '../utility/ContentstackClient' + +var client = {} + +describe('Content Type delete api Test', () => { + setup(() => { + const user = jsonReader('loggedinuser.json') + client = contentstackClient(user.authtoken) + }) + + it('Content Type delete', done => { + makeContentType(multiPageCT.content_type.uid) + .delete().then((data) => { + expect(data.notice).to.be.equal('Content Type deleted successfully.') + done() + }) + makeContentType(singlepageCT.content_type.uid).delete() + .catch(done) + }) +}) + +function makeContentType (uid = null) { + return client.stack({ api_key: process.env.API_KEY }).contentType(uid) +} diff --git a/test/sanity-check/api/contentType-test.js b/test/sanity-check/api/contentType-test.js new file mode 100644 index 00000000..49b09e7f --- /dev/null +++ b/test/sanity-check/api/contentType-test.js @@ -0,0 +1,123 @@ +import path from 'path' +import { expect } from 'chai' +import { describe, it, setup } from 'mocha' +import { jsonReader } from '../utility/fileOperations/readwrite.js' +import { singlepageCT, multiPageCT, schema } from '../mock/content-type.js' +import { contentstackClient } from '../utility/ContentstackClient.js' + +let client = {} +let multiPageCTUid = '' +let importCTUid = '' + +describe('Content Type api Test', () => { + setup(() => { + const user = jsonReader('loggedinuser.json') + client = contentstackClient(user.authtoken) + }) + + it('Create Single page ContentType Schema', done => { + makeContentType() + .create(singlepageCT) + .then((contentType) => { + expect(contentType.uid).to.be.equal(singlepageCT.content_type.uid) + expect(contentType.title).to.be.equal(singlepageCT.content_type.title) + done() + }) + .catch(done) + }) + + it('Create Multi page ContentType Schema', done => { + makeContentType() + .create(multiPageCT) + .then((contentType) => { + multiPageCTUid = contentType.uid + expect(contentType.uid).to.be.equal(multiPageCT.content_type.uid) + expect(contentType.title).to.be.equal(multiPageCT.content_type.title) + done() + }) + .catch(done) + }) + + it('Get all ContentType', done => { + makeContentType() + .query() + .find() + .then((response) => { + response.items.forEach(contentType => { + expect(contentType.uid).to.be.not.equal(null) + expect(contentType.title).to.be.not.equal(null) + expect(contentType.schema).to.be.not.equal(null) + }) + done() + }) + .catch(done) + }) + + it('Query ContentType title', done => { + makeContentType() + .query({ query: { title: singlepageCT.content_type.title } }) + .find() + .then((response) => { + response.items.forEach(contentType => { + expect(contentType.uid).to.be.not.equal(null) + expect(contentType.title).to.be.not.equal(null) + expect(contentType.schema).to.be.not.equal(null) + expect(contentType.uid).to.be.equal(singlepageCT.content_type.uid, 'UID not mathcing') + expect(contentType.title).to.be.equal(singlepageCT.content_type.title, 'Title not mathcing') + }) + done() + }) + .catch(done) + }) + + it('Fetch ContentType from uid', done => { + makeContentType(multiPageCT.content_type.uid) + .fetch() + .then((contentType) => { + expect(contentType.uid).to.be.equal(multiPageCT.content_type.uid) + expect(contentType.title).to.be.equal(multiPageCT.content_type.title) + done() + }) + .catch(done) + }) + + it('Fetch and Update ContentType schema', done => { + makeContentType(multiPageCTUid) + .fetch() + .then((contentType) => { + contentType.schema = schema + return contentType.update() + }) + .then((contentType) => { + expect(contentType.schema.length).to.be.equal(6) + done() + }) + .catch(done) + }) + + it('Import content type', done => { + makeContentType().import({ + content_type: path.join(__dirname, '../mock/contentType.json') + }) + .then((response) => { + importCTUid = response.uid + expect(response.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + it('Delete ContentTypes', done => { + makeContentType(importCTUid) + .delete() + .then((contentType) => { + expect(contentType.notice).to.be.equal('Content Type deleted successfully.') + done() + }) + .catch(done) + }) +}) + +function makeContentType (uid = null) { + return client.stack({ api_key: process.env.API_KEY }).contentType(uid) +} diff --git a/test/sanity-check/api/user-test.js b/test/sanity-check/api/user-test.js new file mode 100644 index 00000000..d47bdf73 --- /dev/null +++ b/test/sanity-check/api/user-test.js @@ -0,0 +1,77 @@ +import { expect } from 'chai' +import { describe, it } from 'mocha' +import { contentstackClient } from '../../utility/ContentstackClient' +import { jsonWrite } from '../../utility/fileOperations/readwrite' +import axios from 'axios' +import dotenv from 'dotenv' + +dotenv.config() +var authtoken = '' +var loggedinUserID = '' +var client = contentstackClient() +describe('Contentstack User Session api Test', () => { + it('User login wrong credentials', done => { + contentstackClient().login({ email: process.env.EMAIL, password: process.env.PASSWORD }) + .then((response) => { + done() + }).catch((error) => { + const jsonMessage = JSON.parse(error.message) + const payload = JSON.parse(jsonMessage.request.data) + expect(jsonMessage.status).to.be.equal(422, 'Status code does not match') + expect(jsonMessage.errorMessage).to.not.equal(null, 'Error message not proper') + expect(jsonMessage.errorCode).to.be.equal(104, 'Error code does not match') + expect(payload.user.email).to.be.equal(process.env.EMAIL, 'Email id does not match') + expect(payload.user.password).to.be.equal('contentstack', 'Password does not match') + done() + }) + }) + + it('User Login test', done => { + client.login({ email: process.env.EMAIL, password: process.env.PASSWORD }, { include_orgs: true, include_orgs_roles: true, include_stack_roles: true, include_user_settings: true }).then((response) => { + jsonWrite(response.user, 'loggedinuser.json') + expect(response.notice).to.be.equal('Login Successful.', 'Login success messsage does not match.') + done() + }) + .catch(done) + }) + + it('User logout test', done => { + client.logout() + .then((response) => { + expect(axios.defaults.headers.common.authtoken).to.be.equal(undefined) + expect(response.notice).to.be.equal('You\'ve logged out successfully.') + done() + }) + .catch(done) + }) + + it('User login with credentials', done => { + client.login({ email: process.env.EMAIL, password: process.env.PASSWORD }, { include_orgs: true, include_orgs_roles: true, include_stack_roles: true, include_user_settings: true }).then((response) => { + loggedinUserID = response.user.uid + jsonWrite(response.user, 'loggedinuser.json') + expect(response.notice).to.be.equal('Login Successful.', 'Login success messsage does not match.') + done() + }) + .catch(done) + }) + + it('Get Current user info test', done => { + client.getUser().then((user) => { + authtoken = user.authtoken + expect(user.uid).to.be.equal(loggedinUserID) + done() + }) + .catch(done) + }) + + it('Get user info from authtoken', done => { + contentstackClient(authtoken) + .getUser() + .then((user) => { + expect(user.uid).to.be.equal(loggedinUserID) + expect(true).to.be.equal(true) + done() + }) + .catch(done) + }) +}) diff --git a/test/sanity-check/mock/content-type.js b/test/sanity-check/mock/content-type.js new file mode 100644 index 00000000..2e4a7713 --- /dev/null +++ b/test/sanity-check/mock/content-type.js @@ -0,0 +1,179 @@ +const singlepageCT = { + content_type: + { + options: + { + is_page: true, + singleton: true, + title: 'title', + sub_title: [] + }, + title: 'Single Page', + uid: 'single_page', + schema: [ + { + display_name: 'Title', + uid: 'title', + data_type: 'text', + mandatory: true, + unique: true, + field_metadata: + { + _default: true + } + }, + { + display_name: 'URL', + uid: 'url', + data_type: 'text', + mandatory: true, + field_metadata: { + _default: true, + instruction: '' + } + } + ] + }, + prevcreate: true +} + +const multiPageCT = { + content_type: + { + options: + { + is_page: true, + singleton: false, + title: 'title', + sub_title: [], + url_pattern: '/:title' + }, + title: 'Multi page', + uid: 'multi_page', + schema: + [ + { + display_name: 'Title', + uid: 'title', + data_type: 'text', + mandatory: true, + unique: true, + field_metadata: + { + _default: true + } + }, + { + display_name: 'URL', + uid: 'url', + data_type: 'text', + mandatory: false, + field_metadata: + { + _default: true + } + } + ] + }, + prevcreate: true +} + +const schema = [ + { + display_name: 'Title', + uid: 'title', + data_type: 'text', + mandatory: true, + unique: true, + field_metadata: + { + _default: true, + version: 3 + }, + non_localizable: false, + multiple: false, + fldUid: 'title' + }, + { + display_name: 'URL', + uid: 'url', + data_type: 'text', + mandatory: true, + field_metadata: + { + _default: true, + version: 3 + }, + non_localizable: false, + multiple: false, + unique: false, + fldUid: 'url' + }, + { + data_type: 'text', + display_name: 'Single line textbox', + abstract: 'Name, title, email address, any short text', + uid: 'single_line', + field_metadata: + { + description: '', + default_value: '' + }, + class: 'high-lighter', + format: '', + error_messages: { format: '' }, + fldUid: 'single_line' + }, + { + data_type: 'text', + display_name: 'Multi line textbox', + abstract: 'Descriptions, paragraphs, long text', + uid: 'multi_line', + field_metadata: + { + description: '', + default_value: '', + multiline: true + }, + class: 'high-lighter', + format: '', + error_messages: + { + format: '' + }, + fldUid: 'multi_line' + }, + { + data_type: 'text', + display_name: 'Markdown', + abstract: 'Input text in markdown language', + uid: 'markdown', + field_metadata: + { + description: '', + markdown: true + }, + class: 'high-lighter', + fldUid: 'markdown' + }, + { + data_type: 'blocks', + display_name: 'Modular Blocks', + abstract: 'Create content dynamically', + blocks: + [ + { + title: 'Block1', + uid: 'block1', + blockType: 'custom', + autoEdit: true, + schema: + [ + { data_type: 'file', display_name: 'File', abstract: 'Upload images, videos, docs, etc.', uid: 'file', icon_class: 'icon-file-text-alt', class: 'high-lighter', size: { min: '', max: '' }, extensions: '', field_metadata: { description: '', rich_text_type: 'standard' }, fldUid: 'modular_blocks > block1 > file' }, { data_type: 'link', display_name: 'Link', abstract: 'Add links to text', uid: 'link', icon_class: 'icon-link', class: 'high-lighter', field_metadata: { description: '', default_value: { title: '', url: '' } }, fldUid: 'modular_blocks > block1 > link' }] }], + multiple: true, + uid: 'modular_blocks', + field_metadata: {}, + class: 'high-lighter', + fldUid: 'modular_blocks' }] + +export { singlepageCT, multiPageCT, schema } diff --git a/test/sanity-check/mock/contentType.json b/test/sanity-check/mock/contentType.json new file mode 100644 index 00000000..df456dd6 --- /dev/null +++ b/test/sanity-check/mock/contentType.json @@ -0,0 +1,36 @@ +{ + "options": + { + "is_page": true, + "singleton": false, + "title": "title", + "sub_title": [], + "url_pattern": "/:title" + }, + "title": "Multi page from JSON", + "uid": "multi_page_from_json", + "schema": + [ + { + "display_name": "Title", + "uid": "title", + "data_type": "text", + "mandatory": true, + "unique": true, + "field_metadata": + { + "_default": true + } + }, + { + "display_name": "URL", + "uid": "url", + "data_type": "text", + "mandatory": false, + "field_metadata": + { + "_default": true + } + } + ] + } \ No newline at end of file diff --git a/test/sanity-check/sanity.js b/test/sanity-check/sanity.js new file mode 100644 index 00000000..8faf2378 --- /dev/null +++ b/test/sanity-check/sanity.js @@ -0,0 +1,3 @@ +require('./api/user-test') +require('./api/contentType-test') +require('./api/contentType-delete-test') diff --git a/test/sanity-check/utility/ContentstackClient.js b/test/sanity-check/utility/ContentstackClient.js new file mode 100644 index 00000000..a91c1171 --- /dev/null +++ b/test/sanity-check/utility/ContentstackClient.js @@ -0,0 +1,12 @@ +import * as contentstack from '../../../lib/contentstack.js' +import dotenv from 'dotenv' +dotenv.config() +function contentstackClient (authtoken = null) { + var params = { host: process.env.HOST, defaultHostName: process.env.DEFAULTHOST } + if (authtoken) { + params.authtoken = authtoken + } + return contentstack.client(params) +} + +export { contentstackClient } diff --git a/test/sanity-check/utility/fileOperations/readwrite.js b/test/sanity-check/utility/fileOperations/readwrite.js new file mode 100644 index 00000000..c06fe895 --- /dev/null +++ b/test/sanity-check/utility/fileOperations/readwrite.js @@ -0,0 +1,35 @@ +import fs from 'fs' +import path from 'path' +const dataFiles = './test/utility/dataFiles/' +export function jsonReader (fileName) { + if (!fs.existsSync(`${dataFiles}${fileName}`)) { + return + } + const fileContents = fs.readFileSync(`${dataFiles}${fileName}`, 'utf8') + try { + const object = JSON.parse(fileContents) + return object + } catch (err) { + return err + } +} + +export function jsonWrite (json, fileName) { + const jsonString = JSON.stringify(json) + ensureDirectoryExistence(`${dataFiles}${fileName}`) + fs.writeFileSync(`${dataFiles}${fileName}`, jsonString) +} + +function ensureDirectoryExistence (filePath) { + var dirname = path.dirname(filePath) + if (!fs.existsSync(dirname)) { + ensureDirectoryExistence(dirname) + fs.mkdirSync(dirname) + } +} + +export function writeDownloadedFile (response, fileName) { + const filePath = path.resolve(dataFiles, fileName) + ensureDirectoryExistence(`${dataFiles}${fileName}`) + response.data.pipe(fs.createWriteStream(filePath)) +} diff --git a/test/test.js b/test/test.js index 8b4ec6b2..a66cd167 100644 --- a/test/test.js +++ b/test/test.js @@ -30,3 +30,4 @@ require('./api/terms-test') require('./api/team-test') require('./api/team-users-test') require('./api/team-stack-role-mapping-test') +require('./api/managementToken-test') diff --git a/test/typescript/index.test.ts b/test/typescript/index.test.ts index e7546da4..e6ab2d97 100644 --- a/test/typescript/index.test.ts +++ b/test/typescript/index.test.ts @@ -12,6 +12,7 @@ import { createBranchAlias, deleteBranchAlias, queryBranchAlias } from './branch import { createLocale, deleteLocale, getLocale } from './locale'; import { createEnvironment, deleteEnvironment, getEnvironment, updateEnvironment } from './environment'; import { createDeliveryToken, deleteDeliveryToken, deliveryToken, queryDeliveryToken } from './deliveryToken'; +import { createManagementToken, deleteManagementToken, managementToken, queryManagementToken } from './managementToken'; import { createRole, findAllRole, getRole, getRoleUid, queryRole } from './role'; import { createApp, deleteApp, fetchApp, installation, updateApp, updateAuth } from './app'; import { deployment, hosting } from './hosting'; @@ -79,6 +80,11 @@ describe('Typescript API test', () => { deliveryToken(stack) deleteDeliveryToken(stack) + createManagementToken(stack.managementToken()) + queryManagementToken(stack.managementToken()) + managementToken(stack) + deleteManagementToken(stack) + findAllRole(stack.role()) createRole(stack.role()) getRole(stack) diff --git a/test/typescript/managementToken.ts b/test/typescript/managementToken.ts new file mode 100644 index 00000000..7fb2dff2 --- /dev/null +++ b/test/typescript/managementToken.ts @@ -0,0 +1,131 @@ +import { expect } from "chai" +import path from "path" +import { Stack } from "../../types/stack"; +import { ManagementToken, ManagementTokens } from "../../types/stack/managementToken"; +import { managementToken1, managementToken2 } from "./mock/managementToken"; +var tokenUID = '' +export function createManagementToken(managementToken: ManagementTokens) { + describe('Management token create', () => { + test('Create a management token', done => { + managementToken.create(managementToken1) + .then((token) => { + expect(token.name).to.be.equal(managementToken1.token.name) + expect(token.description).to.be.equal(managementToken1.token.description) + expect(token.scope[0].module).to.be.equal(managementToken1.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + test('Create management token for production', done => { + managementToken.create(managementToken2) + .then((token) => { + tokenUID = token.uid + expect(token.name).to.be.equal(managementToken2.token.name) + expect(token.description).to.be.equal(managementToken2.token.description) + expect(token.scope[0].module).to.be.equal(managementToken2.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + }) +} + +export function queryManagementToken(managementToken: ManagementTokens) { + describe('Query management token', () => { + test('Get all management token', done => { + managementToken.query().find() + .then((tokens) => { + tokens.items.forEach((token) => { + expect(token.name).to.be.not.equal(null) + expect(token.description).to.be.not.equal(null) + expect(token.scope[0].module).to.be.not.equal(null) + expect(token.uid).to.be.not.equal(null) + }) + done() + }) + .catch(done) + }) + + test('Get management token from name', done => { + managementToken.query({query: {name: managementToken1.token.name}}) + .find() + .then((tokens) => { + tokens.items.forEach((token) => { + expect(token.name).to.be.equal(managementToken1.token.name) + expect(token.description).to.be.equal(managementToken1.token.description) + expect(token.scope[0].module).to.be.equal(managementToken1.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + }) + done() + }) + .catch(done) + }) + }) +} +export function managementToken(stack: Stack) { + describe('Management token operations', () => { + test('Fetch management token', done => { + stack.managementToken(tokenUID) + .fetch() + .then((token) => { + expect(token.name).to.be.equal(managementToken2.token.name) + expect(token.description).to.be.equal(managementToken2.token.description) + expect(token.scope[0].module).to.be.equal(managementToken2.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + test('Fetch and update a Management Token from uid', done => { + stack.managementToken(tokenUID) + .fetch() + .then((token) => { + token.name = 'Update Production Name' + token.description = 'Update Production description' + token.scope = managementToken2.token.scope + return token.update() + }) + .then((token) => { + expect(token.name).to.be.equal('Update Production Name') + expect(token.description).to.be.equal('Update Production description') + expect(token.scope[0].module).to.be.equal(managementToken2.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + + test('Update management token from uid', done => { + const token = stack.managementToken(tokenUID) + Object.assign(token, managementToken2.token) + + token.update() + .then((token) => { + expect(token.name).to.be.equal(managementToken2.token.name) + expect(token.description).to.be.equal(managementToken2.token.description) + expect(token.scope[0].module).to.be.equal(managementToken2.token.scope[0].module) + expect(token.uid).to.be.not.equal(null) + done() + }) + .catch(done) + }) + }) +} + +export function deleteManagementToken(stack: Stack) { + describe('Delete management token', () => { + test('Delete token from uid', done => { + stack.managementToken(tokenUID) + .delete() + .then((data) => { + expect(data.notice).to.be.equal('Management Token deleted successfully.') + done() + }) + .catch(done) + }) + }) +} \ No newline at end of file diff --git a/test/typescript/mock/managementToken.ts b/test/typescript/mock/managementToken.ts new file mode 100644 index 00000000..d035c9d0 --- /dev/null +++ b/test/typescript/mock/managementToken.ts @@ -0,0 +1,73 @@ +const managementToken1 = { + "token":{ + "name":"Test Token", + "description":"This is a sample management token.", + "scope":[ + { + "module":"content_type", + "acl":{ + "read":true, + "write":true + } + }, + { + "module":"branch", + "branches":[ + "main" + ], + "acl":{ + "read":true + } + }, + { + "module":"branch_alias", + "branch_aliases":[ + "tst" + ], + "acl":{ + "read":true + } + } + ], + "expires_on":"2024-12-10", + "is_email_notification_enabled":true + } +} +const managementToken2 = { + "token":{ + "name":"Test Token", + "description":"This is a sample management token.", + "scope":[ + { + "module":"content_type", + "acl":{ + "read":true, + "write":true + } + }, + { + "module":"branch", + "branches":[ + "main" + ], + "acl":{ + "read":true + } + }, + { + "module":"branch_alias", + "branch_aliases":[ + "tst" + ], + "acl":{ + "read":true + } + } + ], + "expires_on":"2024-12-10", + "is_email_notification_enabled":true + } +} + + export { managementToken1, managementToken2 } + \ No newline at end of file diff --git a/test/unit/entry-test.js b/test/unit/entry-test.js index db87571d..5515c2e0 100644 --- a/test/unit/entry-test.js +++ b/test/unit/entry-test.js @@ -4,6 +4,7 @@ import { expect } from 'chai' import { describe, it } from 'mocha' import MockAdapter from 'axios-mock-adapter' import { Entry, EntryCollection, createFormData } from '../../lib/stack/contentType/entry' +import { cleanAssets } from '../../lib/entity' import { systemUidMock, stackHeadersMock, entryMock, noticeMock, checkSystemFields } from './mock/objects' describe('Contentstack Entry test', () => { @@ -375,6 +376,196 @@ describe('Contentstack Entry test', () => { }) .catch(done) }) + + it('Entry with asset object', done => { + const entry = { + empty_array: [], + empty_object: {}, + single_file: { + file_size: 69420, + uid: 'single_file' + }, + title: 'test entry', + property: 'test property 3', + array_file: [ + { file_size: 69420, uid: 'array_file_1' }, + { file_size: 69420, uid: 'array_file_2' }, + { file_size: 69420, uid: 'array_file_3' }, + ], + wrapper1: { + something: 'something', + something_else: 'something_else', + file_inside_wrapper : { + file_size: 69420, + uid: 'single_file' + }, + file_array_wrapper : [ + { file_size: 69420, uid: 'array_file_wrap_1' }, + { file_size: 69420, uid: 'array_file_wrap_2' }, + { file_size: 69420, uid: 'array_file_wrap_3' }, + ], + array_wrapper: [ + { + something: 'something', + single_file: { + file_size: 69420, + uid: 'single_file_1' + }, + something_else: 'something_else' + }, + { + something: 'something', + single_file: { + file_size: 69420, + uid: 'single_file_2' + }, + something_else: 'something_else' + }, + { + something: 'something', + single_file: { + file_size: 69420, + uid: 'single_file_3' + }, + something_else: 'something_else' + } + ], + wrapper2: { + array_of_array_wrapper: [ + { + something: 'something', + oneMoreWrapper : { + file_array_wrapper : [ + { file_size: 69420, uid: 'array_file_wrap_1' }, + { file_size: 69420, uid: 'array_file_wrap_2' }, + { file_size: 69420, uid: 'array_file_wrap_3' }, + ], + array_wrapper: [ + { + something: 'something', + single_file: { + file_size: 69420, + uid: 'single_file_1' + }, + something_else: 'something_else' + }, + { + something: 'something', + single_file: { + file_size: 69420, + uid: 'single_file_2' + }, + something_else: 'something_else' + }, + { + something: 'something', + single_file: { + file_size: 69420, + uid: 'single_file_3' + }, + something_else: 'something_else' + } + ], + }, + something_else: 'something_else' + }, + { + something: 'something', + file_array_wrapper : [ + { file_size: 69420, uid: 'array_file_wrap_1' }, + { file_size: 69420, uid: 'array_file_wrap_2' }, + { file_size: 69420, uid: 'array_file_wrap_3' }, + ], + something_else: 'something_else' + }, + { + something: 'something', + file_array_wrapper : [ + { file_size: 69420, uid: 'array_file_wrap_1' }, + { file_size: 69420, uid: 'array_file_wrap_2' }, + { file_size: 69420, uid: 'array_file_wrap_3' }, + ], + something_else: 'something_else' + } + ] + } + }, + ...systemUidMock + }; + const expectedResult = { + empty_array: [], + empty_object: {}, + single_file: 'single_file', + title: 'test entry', + property: 'test property 3', + array_file: ['array_file_1', 'array_file_2', 'array_file_3'], + wrapper1: { + something: 'something', + something_else: 'something_else', + file_inside_wrapper : 'single_file', + file_array_wrapper : ['array_file_wrap_1', 'array_file_wrap_2', 'array_file_wrap_3'], + array_wrapper: [ + { + something: 'something', + single_file: 'single_file_1', + something_else: 'something_else' + }, + { + something: 'something', + single_file: 'single_file_2', + something_else: 'something_else' + }, + { + something: 'something', + single_file: 'single_file_3', + something_else: 'something_else' + } + ], + wrapper2: { + array_of_array_wrapper: [ + { + something: 'something', + oneMoreWrapper : { + file_array_wrapper : ['array_file_wrap_1', 'array_file_wrap_2', 'array_file_wrap_3'], + array_wrapper: [ + { + something: 'something', + single_file: 'single_file_1', + something_else: 'something_else' + }, + { + something: 'something', + single_file: 'single_file_2', + something_else: 'something_else' + }, + { + something: 'something', + single_file: 'single_file_3', + something_else: 'something_else' + } + ], + }, + something_else: 'something_else' + }, + { + something: 'something', + file_array_wrapper : ['array_file_wrap_1', 'array_file_wrap_2', 'array_file_wrap_3'], + something_else: 'something_else' + }, + { + something: 'something', + file_array_wrapper : ['array_file_wrap_1', 'array_file_wrap_2', 'array_file_wrap_3'], + something_else: 'something_else' + } + ] + } + }, + ...systemUidMock + }; + const result = cleanAssets(entry); + expect(result).to.deep.equal(expectedResult); + done(); + }) }) function makeEntry (data) { diff --git a/test/unit/index.js b/test/unit/index.js index 1eccb05e..a06cb20b 100644 --- a/test/unit/index.js +++ b/test/unit/index.js @@ -38,3 +38,4 @@ require('./terms-test') require('./team-test') require('./team-users-test') require('./team-stack-role-mapping-test') +require('./managementToken-test') diff --git a/test/unit/managementToken-test.js b/test/unit/managementToken-test.js new file mode 100644 index 00000000..27f55400 --- /dev/null +++ b/test/unit/managementToken-test.js @@ -0,0 +1,180 @@ +import Axios from 'axios' +import { expect } from 'chai' +import { describe, it } from 'mocha' +import MockAdapter from 'axios-mock-adapter' +import { ManagementToken, ManagementTokenCollection } from '../../lib/stack/managementToken' +import { systemUidMock, stackHeadersMock, managementTokenMock, noticeMock, checkSystemFields } from './mock/objects' +import { checkEnvironment } from './environment-test' + +describe('Contentstack ManagementToken test', () => { + it('ManagementToken test without uid', done => { + const managementToken = makeManagementToken() + expect(managementToken.urlPath).to.be.equal('/stacks/management_tokens') + expect(managementToken.stackHeaders).to.be.equal(undefined) + expect(managementToken.update).to.be.equal(undefined) + expect(managementToken.delete).to.be.equal(undefined) + expect(managementToken.fetch).to.be.equal(undefined) + expect(managementToken.create).to.not.equal(undefined) + expect(managementToken.query).to.not.equal(undefined) + done() + }) + + it('ManagementToken test with uid', done => { + const managementToken = makeManagementToken({ + token: { + ...systemUidMock + } + }) + expect(managementToken.urlPath).to.be.equal(`/stacks/management_tokens/${systemUidMock.uid}`) + expect(managementToken.stackHeaders).to.be.equal(undefined) + expect(managementToken.update).to.not.equal(undefined) + expect(managementToken.delete).to.not.equal(undefined) + expect(managementToken.fetch).to.not.equal(undefined) + expect(managementToken.create).to.be.equal(undefined) + expect(managementToken.query).to.be.equal(undefined) + done() + }) + + it('ManagementToken test with Stack Headers', done => { + const managementToken = makeManagementToken({ + token: { + ...systemUidMock + }, + stackHeaders: stackHeadersMock + }) + expect(managementToken.urlPath).to.be.equal(`/stacks/management_tokens/${systemUidMock.uid}`) + expect(managementToken.stackHeaders).to.not.equal(undefined) + expect(managementToken.stackHeaders.api_key).to.be.equal(stackHeadersMock.api_key) + expect(managementToken.update).to.not.equal(undefined) + expect(managementToken.delete).to.not.equal(undefined) + expect(managementToken.fetch).to.not.equal(undefined) + expect(managementToken.create).to.be.equal(undefined) + expect(managementToken.query).to.be.equal(undefined) + done() + }) + + it('ManagementToken Collection test with blank data', done => { + const managementToken = new ManagementTokenCollection(Axios, {}) + expect(managementToken.length).to.be.equal(0) + done() + }) + + it('ManagementToken Collection test with data', done => { + const managementToken = new ManagementTokenCollection(Axios, { + tokens: [ + managementTokenMock + ] + }) + expect(managementToken.length).to.be.equal(1) + checkManagementToken(managementToken[0]) + done() + }) + + it('ManagementToken create test', done => { + var mock = new MockAdapter(Axios) + mock.onPost('/stacks/management_tokens').reply(200, { + token: { + ...managementTokenMock + } + }) + makeManagementToken() + .create() + .then((managementToken) => { + checkManagementToken(managementToken) + done() + }) + .catch(done) + }) + + it('ManagementToken Query test', done => { + var mock = new MockAdapter(Axios) + mock.onGet('/stacks/management_tokens').reply(200, { + tokens: [ + managementTokenMock + ] + }) + makeManagementToken() + .query() + .find() + .then((managementTokens) => { + checkManagementToken(managementTokens.items[0]) + done() + }) + .catch(done) + }) + + it('ManagementToken update test', done => { + var mock = new MockAdapter(Axios) + mock.onPut('/stacks/management_tokens/UID').reply(200, { + token: { + ...managementTokenMock + } + }) + makeManagementToken({ + token: { + ...systemUidMock + }, + stackHeaders: stackHeadersMock + }) + .update() + .then((managementToken) => { + checkManagementToken(managementToken) + done() + }) + .catch(done) + }) + + it('ManagementToken fetch test', done => { + var mock = new MockAdapter(Axios) + mock.onGet('/stacks/management_tokens/UID').reply(200, { + token: { + ...managementTokenMock + } + }) + makeManagementToken({ + token: { + ...systemUidMock + }, + stackHeaders: stackHeadersMock + }) + .fetch() + .then((managementToken) => { + checkManagementToken(managementToken) + done() + }) + .catch(done) + }) + + it('ManagementToken delete test', done => { + var mock = new MockAdapter(Axios) + mock.onDelete('/stacks/management_tokens/UID').reply(200, { + ...noticeMock + }) + makeManagementToken({ + token: { + ...systemUidMock + }, + stackHeaders: stackHeadersMock + }) + .delete() + .then((response) => { + expect(response.notice).to.be.equal(noticeMock.notice) + done() + }) + .catch(done) + }) +}) + +function makeManagementToken (data = {}) { + return new ManagementToken(Axios, data) +} + +function checkManagementToken (managementToken) { + checkSystemFields(managementToken) + expect(managementToken.name).to.be.equal('Test') + expect(managementToken.description).to.be.equal('description') + expect(managementToken.token).to.be.equal('token') + expect(managementToken.type).to.be.equal('management') + expect(managementToken.scope.length).to.be.equal(1) + checkEnvironment(managementToken.scope[0].environments[0]) +} diff --git a/test/unit/mock/objects.js b/test/unit/mock/objects.js index a8dbf9a9..85f0cc09 100644 --- a/test/unit/mock/objects.js +++ b/test/unit/mock/objects.js @@ -418,6 +418,22 @@ const deliveryTokenMock = { type: 'delivery' } +const managementTokenMock = { + ...systemFieldsMock, + ...systemFieldsUserMock, + name: 'Test', + scope: [{ + environments: [environmentMock], + module: 'environment', + acl: { + read: true + } + }], + description: 'description', + token: 'token', + type: 'management' +} + const userAssignments = { ...stackHeadersMock, content_type: 'CT_UID', @@ -873,5 +889,6 @@ export { stackRoleMappingMock, mockCollection, entryMockCollection, - checkSystemFields + checkSystemFields, + managementTokenMock } diff --git a/types/stack/index.d.ts b/types/stack/index.d.ts index a1363af3..331f036d 100644 --- a/types/stack/index.d.ts +++ b/types/stack/index.d.ts @@ -19,6 +19,7 @@ import { Role, Roles } from "./role"; import { Webhook, Webhooks } from "./webhook"; import { Workflow, Workflows } from "./workflow"; import { Taxonomy, Taxonomies } from "./taxonomy"; +import { ManagementToken, ManagementTokens } from "./managementToken"; export interface StackConfig { api_key:string @@ -96,4 +97,7 @@ export interface Stack extends SystemFields { taxonomy(): Taxonomies taxonomy(uid: string): Taxonomy + + managementToken(): ManagementTokens + managementToken(uid: string): ManagementToken } diff --git a/types/stack/managementToken/index.ts b/types/stack/managementToken/index.ts new file mode 100644 index 00000000..e8d5e34b --- /dev/null +++ b/types/stack/managementToken/index.ts @@ -0,0 +1,27 @@ +import { AnyProperty, SystemFields } from "../../utility/fields"; +import { Queryable, SystemFunction } from "../../utility/operations"; + +export interface ManagementToken extends SystemFields, SystemFunction { +} + +export interface ManagementTokens extends Queryable { +} + +export interface ManagementTokenData extends AnyProperty { + name: string + description: string + scope: Array +} + +export interface Scope { + module: string + environments?: Array + locales?: Array + acl: ACL +} +export interface ACL extends AnyProperty { + read?: boolean + write?: boolean + create?: boolean + update?: boolean +} \ No newline at end of file