Skip to content

Commit e346e7f

Browse files
author
RTLcoil
authored
Align all structured metadata tests with reference implementation (#351)
* Align all structured metadata tests with reference implementation
1 parent 33906ed commit e346e7f

File tree

4 files changed

+525
-366
lines changed

4 files changed

+525
-366
lines changed

test/api_spec.js

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const itBehavesLike = helper.itBehavesLike;
1616
const TEST_TAG = helper.TEST_TAG;
1717
const UPLOAD_TAGS = helper.UPLOAD_TAGS;
1818
const uploadImage = helper.uploadImage;
19-
const TEST_ID = Date.now();
2019
const SUFFIX = helper.SUFFIX;
2120
const PUBLIC_ID_PREFIX = "npm_api_test";
2221
const PUBLIC_ID = PUBLIC_ID_PREFIX + SUFFIX;
@@ -44,12 +43,6 @@ const EXPLICIT_TRANSFORMATION2 = {
4443
crop: "scale",
4544
overlay: `text:Arial_60:${TEST_TAG}`,
4645
};
47-
const METADATA_EXTERNAL_ID_UPLOAD = "metadata_upload_" + TEST_ID;
48-
const METADATA_EXTERNAL_ID_UPDATE = "metadata_uploader_update_" + TEST_ID;
49-
const METADATA_EXTERNAL_ID_EXPLICIT = "metadata_explicit_" + TEST_ID;
50-
const LABEL_INT_1 = 'metadata_label_1_' + TEST_ID;
51-
const LABEL_INT_2 = 'metadata_label_2_' + TEST_ID;
52-
const LABEL_INT_3 = 'metadata_label_3_' + TEST_ID;
5346

5447
function wait(ms = 0) {
5548
return new Promise((resolve) => {
@@ -828,85 +821,6 @@ describe("api", function () {
828821
});
829822
});
830823
});
831-
describe("structured metadata fields", function () {
832-
this.timeout(helper.TIMEOUT_LONG);
833-
const METADATA_VALUE = "123456";
834-
before(function () {
835-
return Q.allSettled(
836-
[
837-
cloudinary.v2.api.add_metadata_field({
838-
external_id: METADATA_EXTERNAL_ID_UPDATE,
839-
label: LABEL_INT_1,
840-
type: "string",
841-
}),
842-
cloudinary.v2.api.add_metadata_field({
843-
external_id: METADATA_EXTERNAL_ID_UPLOAD,
844-
label: LABEL_INT_2,
845-
type: "string",
846-
}),
847-
cloudinary.v2.api.add_metadata_field({
848-
external_id: METADATA_EXTERNAL_ID_EXPLICIT,
849-
label: LABEL_INT_3,
850-
type: "string",
851-
}),
852-
]
853-
).finally(function () {});
854-
});
855-
after(function () {
856-
return Q.allSettled(
857-
[
858-
cloudinary.v2.api.delete_metadata_field(METADATA_EXTERNAL_ID_UPDATE),
859-
cloudinary.v2.api.delete_metadata_field(METADATA_EXTERNAL_ID_UPLOAD),
860-
cloudinary.v2.api.delete_metadata_field(METADATA_EXTERNAL_ID_EXPLICIT),
861-
]
862-
).finally(function () {});
863-
});
864-
it("should be updatable with uploader.update_metadata", function () {
865-
let publicId;
866-
return uploadImage({
867-
tags: [TEST_TAG],
868-
})
869-
.then((result) => {
870-
publicId = result.public_id;
871-
return cloudinary.v2.uploader.update_metadata({ [METADATA_EXTERNAL_ID_UPDATE]: METADATA_VALUE }, [publicId]);
872-
})
873-
.then((result) => {
874-
expect(result).not.to.be.empty();
875-
expect(result.public_ids[0]).to.eql(publicId);
876-
return cloudinary.v2.api.resource(publicId);
877-
})
878-
.then((result) => {
879-
expect(result.metadata[METADATA_EXTERNAL_ID_UPDATE]).to.eql(METADATA_VALUE);
880-
});
881-
});
882-
it("should be supported when uploading a resource with metadata", function () {
883-
return uploadImage({
884-
tags: [TEST_TAG],
885-
metadata: { [METADATA_EXTERNAL_ID_UPLOAD]: METADATA_VALUE },
886-
}).then((result) => {
887-
expect(result).not.to.be.empty();
888-
return cloudinary.v2.api.resource(result.public_id);
889-
}).then((result) => {
890-
expect(result.metadata[METADATA_EXTERNAL_ID_UPLOAD]).to.eql(METADATA_VALUE);
891-
});
892-
});
893-
it("should be supported when calling explicit with metadata", function () {
894-
return uploadImage({
895-
tags: [TEST_TAG],
896-
}).then((result) => {
897-
return cloudinary.v2.uploader.explicit(result.public_id, {
898-
type: "upload",
899-
tags: [TEST_TAG],
900-
metadata: { [METADATA_EXTERNAL_ID_EXPLICIT]: METADATA_VALUE },
901-
});
902-
}).then(function (result) {
903-
expect(result).not.to.be.empty();
904-
return cloudinary.v2.api.resource(result.public_id);
905-
}).then((result) => {
906-
expect(result.metadata[METADATA_EXTERNAL_ID_EXPLICIT]).to.eql(METADATA_VALUE);
907-
});
908-
});
909-
});
910824
it("should support listing by moderation kind and value", function () {
911825
itBehavesLike("a list with a cursor", cloudinary.v2.api.resources_by_moderation, "manual", "approved");
912826
return helper.mockPromise((xhr, write, request) => ["approved", "pending", "rejected"].forEach((stat) => {

test/spechelper.js

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,52 @@ expect.Assertion.prototype.beServedByCloudinary = function (done) {
115115
return this;
116116
};
117117

118+
/**
119+
* Asserts that a given object is a datasource.
120+
*
121+
* @returns {expect.Assertion}
122+
*/
123+
expect.Assertion.prototype.beADatasource = function () {
124+
let datasource;
125+
datasource = this.obj;
126+
this.assert('values' in datasource, function () {
127+
return `expected datasource to contain mandatory field: 'values'`;
128+
}, function () {
129+
return `expected datasource not to contain a 'values' field`;
130+
});
131+
if (!isEmpty(datasource.values)) {
132+
datasource.values.forEach((value) => {
133+
this.assert(typeof value.value === 'string', function () {
134+
return `expected datasource to contain item with mandatory field 'value' type string`;
135+
}, function () {
136+
return `expected datasource not to contain item with mandatory field 'value' type string`;
137+
});
138+
this.assert(typeof value.external_id === 'string', function () {
139+
return `expected datasource field to contain item with mandatory field: 'value' type string`;
140+
}, function () {
141+
return `expected datasource not to contain item with mandatory field 'external_id' type string`;
142+
});
143+
if (!isEmpty(value.state)) {
144+
const states = ['active', 'inactive'];
145+
this.assert(includes(states, value.state), function () {
146+
return `expected datasource field state to be one of ${states.join(', ')}. Unknown state ${value.state} received`;
147+
}, function () {
148+
return `expected datasource field state not to be of a certain state`;
149+
});
150+
}
151+
});
152+
}
153+
return this;
154+
};
155+
118156
/**
119157
* Asserts that a given object is a metadata field.
120158
* Optionally tests the values in the metadata field for equality
121159
*
160+
* @param {string} type The type of metadata field we expect
122161
* @returns {expect.Assertion}
123162
*/
124-
expect.Assertion.prototype.beAMetadataField = function () {
163+
expect.Assertion.prototype.beAMetadataField = function (type = '') {
125164
let metadataField, expectedValues;
126165
if (Array.isArray(this.obj)) {
127166
[metadataField, expectedValues] = this.obj;
@@ -145,16 +184,24 @@ expect.Assertion.prototype.beAMetadataField = function () {
145184
}, function () {
146185
return `expected metadata field of type ${metadataField.type} not to contain a datasource field`;
147186
});
187+
expect(metadataField.datasource).to.beADatasource();
148188
}
149189

150190
// Make sure type is acceptable
151-
const acceptableTypes = ['string', 'integer', 'date', 'enum', 'set'];
152-
this.assert(includes(acceptableTypes, metadataField.type), function () {
153-
return `expected metadata field type to be one of ${acceptableTypes.join(', ')}. Unknown field type ${metadataField.type} received`;
154-
}, function () {
155-
return `expected metadata field not to be of a certain type`;
156-
});
157-
191+
if (type) {
192+
this.assert(type === metadataField.type, function () {
193+
return `expected metadata field type to equal ${type}`;
194+
}, function () {
195+
return `expected metadata field type ${metadataField.type} not to equal ${type}`;
196+
});
197+
} else {
198+
const acceptableTypes = ['string', 'integer', 'date', 'enum', 'set'];
199+
this.assert(includes(acceptableTypes, metadataField.type), function () {
200+
return `expected metadata field type to be one of ${acceptableTypes.join(', ')}. Unknown field type ${metadataField.type} received`;
201+
}, function () {
202+
return `expected metadata field not to be of a certain type`;
203+
});
204+
}
158205
// Verify object values
159206
if (expectedValues) {
160207
Object.entries(expectedValues).forEach(([key, value]) => {
@@ -233,6 +280,23 @@ exports.apiParamMatcher = function (name, value) {
233280
};
234281
};
235282

283+
/**
284+
Create a matcher method for api JSON parameters
285+
@private
286+
@function helper.apiJsonParamMatcher
287+
@param {string} name the parameter name
288+
@param {*} value the parameter value
289+
@return {function} the matcher function as (arg)->Boolean
290+
*/
291+
exports.apiJsonParamMatcher = function (name, value) {
292+
return function (arg) {
293+
var expected, jsonArg;
294+
jsonArg = JSON.parse(arg);
295+
expected = JSON.stringify(value);
296+
return jsonArg[name] && JSON.stringify(jsonArg[name]) === expected;
297+
};
298+
};
299+
236300
/**
237301
Escape RegExp characters
238302
@private
@@ -328,3 +392,14 @@ exports.setupCache = function () {
328392
exports.uploadImage = function (options) {
329393
return cloudinary.v2.uploader.upload(exports.IMAGE_FILE, options);
330394
};
395+
396+
/**
397+
* Convert a timestamp to the date part of an ISO8601 string
398+
*
399+
* @param {string} timestamp The timestamp to convert
400+
* @returns {string} The date part of a ISO8601 date time
401+
*/
402+
exports.toISO8601DateOnly = function (timestamp) {
403+
const date = new Date(timestamp);
404+
return date.toISOString().split('T')[0];
405+
};

0 commit comments

Comments
 (0)