From 45d24e8643a64a10bfba5347cbc1617d21533a27 Mon Sep 17 00:00:00 2001 From: Patrick Tolosa Date: Tue, 21 Jul 2020 17:55:46 +0300 Subject: [PATCH] Refactor sharedExamples where possible. - api_spec - image_spec The only remaining work is in util_spec, but that file has proven to be far too complex to refactor at this time --- test/integration/api/admin/api_spec.js | 94 ++++--------------- test/integration/api/uploader/archivespec.js | 15 ++- test/spechelper.js | 15 +-- .../reusableTests/api/toAcceptNextCursor.js | 22 +++++ .../reusableTests/api/toBeACursor.js | 39 ++++++++ .../image/imageAttributesWithClientHInts.js | 28 ++++++ test/testUtils/reusableTests/reusableTests.js | 11 +++ test/testUtils/testBootstrap.js | 5 + test/unit/tags/image_spec.js | 30 ++---- 9 files changed, 144 insertions(+), 115 deletions(-) create mode 100644 test/testUtils/reusableTests/api/toAcceptNextCursor.js create mode 100644 test/testUtils/reusableTests/api/toBeACursor.js create mode 100644 test/testUtils/reusableTests/image/imageAttributesWithClientHInts.js create mode 100644 test/testUtils/reusableTests/reusableTests.js diff --git a/test/integration/api/admin/api_spec.js b/test/integration/api/admin/api_spec.js index b8f37983..d67ebafa 100644 --- a/test/integration/api/admin/api_spec.js +++ b/test/integration/api/admin/api_spec.js @@ -1,15 +1,12 @@ const sinon = require('sinon'); const ClientRequest = require('_http_client').ClientRequest; -const http = require('http'); const Q = require('q'); const cloudinary = require("../../../../cloudinary"); const helper = require("../../../spechelper"); const describe = require('../../../testUtils/suite'); const wait = require('../../../testUtils/helpers/wait'); -const sharedExamples = helper.sharedExamples; -const itBehavesLike = helper.itBehavesLike; const uploadImage = helper.uploadImage; - +const callReusableTest = require('../../../testUtils/reusableTests/reusableTests').callReusableTest; const testConstants = require('../../../testUtils/testConstants'); const API_V2 = cloudinary.v2.api; @@ -70,66 +67,6 @@ const EXPLICIT_TRANSFORMATION2 = { -sharedExamples("a list with a cursor", function (testFunc, ...args) { - specify(":max_results", function () { - return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) { - testFunc(...args, { - max_results: 10 - }); - if (writeSpy.called) { - sinon.assert.calledWith(writeSpy, sinon.match(/max_results=10/)); - } else { - sinon.assert.calledWith(requestSpy, sinon.match({ - query: sinon.match(/max_results=10/) - })); - } - }); - }); - specify(":next_cursor", function () { - return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) { - testFunc(...args, { - next_cursor: 23452342 - }); - if (writeSpy.called) { - sinon.assert.calledWith(writeSpy, sinon.match(/next_cursor=23452342/)); - } else { - sinon.assert.calledWith(requestSpy, sinon.match({ - query: sinon.match(/next_cursor=23452342/) - })); - } - }); - }); -}); - -sharedExamples("accepts next_cursor", function (testFunc, ...args) { - var requestSpy; - var writeSpy; - var xhr; - - before(function () { - xhr = sinon.useFakeXMLHttpRequest(); - writeSpy = sinon.spy(ClientRequest.prototype, 'write'); - requestSpy = sinon.spy(http, 'request'); - }); - after(function () { - writeSpy.restore(); - requestSpy.restore(); - xhr.restore(); - }); - specify(":next_cursor", function () { - testFunc(...args, { - next_cursor: 23452342 - }); - if (writeSpy.called) { - sinon.assert.calledWith(writeSpy, sinon.match(/next_cursor=23452342/)); - } else { - sinon.assert.calledWith(requestSpy, sinon.match({ - query: sinon.match(/next_cursor=23452342/) - })); - } - }); -}); - function getAllTags({ resources }) { return resources .map(e => e.tags) @@ -191,7 +128,10 @@ describe("api", function () { }); describe("resources", function () { - itBehavesLike("a list with a cursor", cloudinary.v2.api.resources); + callReusableTest("a list with a cursor", cloudinary.v2.api.resources); + callReusableTest("a list with a cursor", cloudinary.v2.api.resources_by_tag, TEST_TAG); + + it("should allow listing resource_types", function () { this.timeout(TIMEOUT.MEDIUM); return cloudinary.v2.api.resource_types().then(function (result) { @@ -240,7 +180,7 @@ describe("api", function () { }); }); }); - itBehavesLike("a list with a cursor", cloudinary.v2.api.resources_by_tag, TEST_TAG); + it("should allow listing resources by tag", function () { this.timeout(TIMEOUT.MEDIUM); return cloudinary.v2.api.resources_by_tag(TEST_TAG, { @@ -453,7 +393,7 @@ describe("api", function () { }); }); describe("delete_resources_by_prefix", function () { - itBehavesLike("accepts next_cursor", cloudinary.v2.api.delete_resources_by_prefix, "prefix_foobar"); + callReusableTest("accepts next_cursor", cloudinary.v2.api.delete_resources_by_prefix, "prefix_foobar"); return it("should allow deleting resources by prefix", function () { this.timeout(TIMEOUT.MEDIUM); return uploadImage({ @@ -476,7 +416,7 @@ describe("api", function () { }); describe("delete_resources_by_tag", function () { let deleteTestTag = TEST_TAG + "_delete"; - itBehavesLike("accepts next_cursor", cloudinary.v2.api.delete_resources_by_prefix, deleteTestTag); + callReusableTest("accepts next_cursor", cloudinary.v2.api.delete_resources_by_prefix, deleteTestTag); it("should allow deleting resources by tags", function () { this.timeout(TIMEOUT.MEDIUM); return uploadImage({ @@ -499,7 +439,7 @@ describe("api", function () { }); }); describe("tags", function () { - itBehavesLike("a list with a cursor", cloudinary.v2.api.tags); + callReusableTest("a list with a cursor", cloudinary.v2.api.tags); it("should allow listing tags", function () { this.timeout(TIMEOUT.MEDIUM); return cloudinary.v2.api.tags({ @@ -533,8 +473,8 @@ describe("api", function () { }); describe("transformations", function () { var transformationName; - itBehavesLike("a list with a cursor", cloudinary.v2.api.transformation, EXPLICIT_TRANSFORMATION_NAME); - itBehavesLike("a list with a cursor", cloudinary.v2.api.transformations); + callReusableTest("a list with a cursor", cloudinary.v2.api.transformation, EXPLICIT_TRANSFORMATION_NAME); + callReusableTest("a list with a cursor", cloudinary.v2.api.transformations); transformationName = "api_test_transformation3" + UNIQUE_JOB_SUFFIX_ID; after(function () { return Q.allSettled( @@ -679,7 +619,7 @@ describe("api", function () { }); }); describe("upload_preset", function () { - itBehavesLike("a list with a cursor", cloudinary.v2.api.upload_presets); + callReusableTest("a list with a cursor", cloudinary.v2.api.upload_presets); it("should allow listing upload_presets", function () { return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) { cloudinary.v2.api.upload_presets(); @@ -753,7 +693,7 @@ describe("api", function () { .then(usage => expect(usage.last_update).not.to.eql(null)); }); describe("delete_all_resources", function () { - itBehavesLike("accepts next_cursor", cloudinary.v2.api.delete_all_resources); + callReusableTest("accepts next_cursor", cloudinary.v2.api.delete_all_resources); describe("keep_original: yes", function () { it("should allow deleting all derived resources", function () { return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) { @@ -886,7 +826,7 @@ describe("api", function () { }); }); it("should support listing by moderation kind and value", function () { - itBehavesLike("a list with a cursor", cloudinary.v2.api.resources_by_moderation, "manual", "approved"); + callReusableTest("a list with a cursor", cloudinary.v2.api.resources_by_moderation, "manual", "approved"); return helper.provideMockObjects((mockXHR, writeSpy, requestSpy) => ["approved", "pending", "rejected"].forEach((stat) => { var status, status2; status = stat; @@ -995,10 +935,10 @@ describe("api", function () { }); }); describe("root_folders", function () { - itBehavesLike("a list with a cursor", cloudinary.v2.api.root_folders); + callReusableTest("a list with a cursor", cloudinary.v2.api.root_folders); }) describe("sub_folders", function () { - itBehavesLike("a list with a cursor", cloudinary.v2.api.sub_folders, '/'); + callReusableTest("a list with a cursor", cloudinary.v2.api.sub_folders, '/'); }); }); describe('.restore', function () { @@ -1119,7 +1059,7 @@ describe("api", function () { after(function () { return this.deleteMapping ? cloudinary.v2.api.delete_upload_mapping(this.mapping) : null; }); - itBehavesLike("a list with a cursor", cloudinary.v2.api.upload_mappings); + callReusableTest("a list with a cursor", cloudinary.v2.api.upload_mappings); it('should create mapping', function () { this.timeout(TIMEOUT.LONG); return cloudinary.v2.api diff --git a/test/integration/api/uploader/archivespec.js b/test/integration/api/uploader/archivespec.js index 7ec07537..821bea5b 100644 --- a/test/integration/api/uploader/archivespec.js +++ b/test/integration/api/uploader/archivespec.js @@ -10,6 +10,9 @@ const cloudinary = require("../../../../cloudinary"); const helper = require("../../../spechelper"); const testConstants = require('../../../testUtils/testConstants'); +const callReusableTest = require('../../../testUtils/reusableTests/reusableTests').callReusableTest; +const registerReusableTest = require('../../../testUtils/reusableTests/reusableTests').registerReusableTest; + const { TIMEOUT, @@ -28,8 +31,6 @@ const { } = URLS; const { utils, api, uploader } = cloudinary.v2; -const sharedExamples = helper.sharedExamples; -const includeContext = helper.includeContext; const ARCHIVE_TAG = TEST_TAG + "_archive"; const PUBLIC_ID1 = ARCHIVE_TAG + "_1"; const PUBLIC_ID2 = ARCHIVE_TAG + "_2"; @@ -37,9 +38,11 @@ const PUBLIC_ID_RAW = ARCHIVE_TAG + "_3"; const FULLY_QUALIFIED_IMAGE = "image/upload/sample"; const FULLY_QUALIFIED_VIDEO = "video/upload/dog"; -sharedExamples('archive', function () { + +describe("archive", function () { + this.timeout(TIMEOUT.LONG); + before(function () { - this.timeout(TIMEOUT.LONG); return Q.all([ uploader.upload(IMAGE_URL, { @@ -76,13 +79,9 @@ sharedExamples('archive', function () { api.delete_resources_by_tag(ARCHIVE_TAG); } }); -}); -describe("archive", function () { - includeContext('archive'); describe("utils", function () { describe('.generate_zip_download_url', function () { - this.timeout(TIMEOUT.LONG); this.archive_result = void 0; before(function () { this.archive_result = utils.download_zip_url({ diff --git a/test/spechelper.js b/test/spechelper.js index d5408c69..2ed830ac 100644 --- a/test/spechelper.js +++ b/test/spechelper.js @@ -61,6 +61,12 @@ exports.test_cloudinary_url = function(public_id, options, expected_url, expecte const allExamples = {}; +/** + * @Deprecated, please use testUtils/reusableTests/reusableTests.js + * @param name + * @param examples + * @return {(function(...[*]=))|*} + */ function sharedExamples(name, examples) { switch (true) { case isFunction(examples): @@ -75,19 +81,14 @@ function sharedExamples(name, examples) { } } -exports.sharedContext = sharedExamples; -exports.sharedExamples = exports.sharedContext; +exports.sharedExamples = sharedExamples; exports.itBehavesLike = function (name, ...args) { - return context(`behaves like ${name}`, function () { + return it(`behaves like ${name}`, function () { return sharedExamples(name).apply(this, args); }); }; -exports.includeContext = function (name, ...args) { - return sharedExamples(name).apply(this, args); -}; - /** Create a matcher method for upload parameters @private diff --git a/test/testUtils/reusableTests/api/toAcceptNextCursor.js b/test/testUtils/reusableTests/api/toAcceptNextCursor.js new file mode 100644 index 00000000..415fc3fc --- /dev/null +++ b/test/testUtils/reusableTests/api/toAcceptNextCursor.js @@ -0,0 +1,22 @@ +const registerReusableTest = require('../reusableTests').registerReusableTest; +const sinon = require('sinon'); +const helper = require("../../../spechelper"); + +registerReusableTest("accepts next_cursor", function (testFunc, ...args) { + it("Has a next cursor", function () { + return helper.provideMockObjects((mockXHR, writeSpy, requestSpy) => { + testFunc(...args, { + next_cursor: 23452342 + }); + + // TODO Why aren't we sure what's called here? + if (writeSpy.called) { + sinon.assert.calledWith(writeSpy, sinon.match(/next_cursor=23452342/)); + } else { + sinon.assert.calledWith(requestSpy, sinon.match({ + query: sinon.match(/next_cursor=23452342/) + })); + } + }); + }); +}); diff --git a/test/testUtils/reusableTests/api/toBeACursor.js b/test/testUtils/reusableTests/api/toBeACursor.js new file mode 100644 index 00000000..1a1fe9bf --- /dev/null +++ b/test/testUtils/reusableTests/api/toBeACursor.js @@ -0,0 +1,39 @@ +const registerReusableTest = require('../reusableTests').registerReusableTest; +const sinon = require('sinon'); +const helper = require("../../../spechelper"); + +registerReusableTest("a list with a cursor", function (testFunc, ...args) { + it("Cursor has max results", function () { + return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) { + testFunc(...args, { + max_results: 10 + }); + + // TODO why don't we know what is used? + if (writeSpy.called) { + sinon.assert.calledWith(writeSpy, sinon.match(/max_results=10/)); + } else { + sinon.assert.calledWith(requestSpy, sinon.match({ + query: sinon.match(/max_results=10/) + })); + } + }); + }); + it("Cursor has next cursor", function () { + return helper.provideMockObjects(function (mockXHR, writeSpy, requestSpy) { + testFunc(...args, { + next_cursor: 23452342 + }); + + // TODO why don't we know what is used? + if (writeSpy.called) { + sinon.assert.calledWith(writeSpy, sinon.match(/next_cursor=23452342/)); + } else { + sinon.assert.calledWith(requestSpy, sinon.match({ + query: sinon.match(/next_cursor=23452342/) + })); + } + }); + }); +}); + diff --git a/test/testUtils/reusableTests/image/imageAttributesWithClientHInts.js b/test/testUtils/reusableTests/image/imageAttributesWithClientHInts.js new file mode 100644 index 00000000..e458c777 --- /dev/null +++ b/test/testUtils/reusableTests/image/imageAttributesWithClientHInts.js @@ -0,0 +1,28 @@ +const registerReusableTest = require('../reusableTests').registerReusableTest; +const cloudinary = require('../../../../cloudinary'); + +const UPLOAD_PATH = "http://res.cloudinary.com/test123/image/upload"; +const srcRegExp = function (name, path) { + return RegExp(`${name}=["']${UPLOAD_PATH}/${path}["']`.replace("/", "\/")); +}; + +registerReusableTest("Expects correct image tag attributes when client hints are used", function(options) { + it("should not use data-src or set responsive class", function() { + var tag = cloudinary.image('sample.jpg', options); + expect(tag).to.match(//); + expect(tag).not.to.match(/<.*class.*>/); + expect(tag).not.to.match(/\bdata-src\b/); + expect(tag).to.match(srcRegExp("src", "c_scale,dpr_auto,w_auto/sample.jpg")); + }); + it("should override responsive", function () { + var tag; + cloudinary.config({ + responsive: true + }); + tag = cloudinary.image('sample.jpg', options); + expect(tag).to.match(//); + expect(tag).not.to.match(/<.*class.*>/); + expect(tag).not.to.match(/\bdata-src\b/); + expect(tag).to.match(srcRegExp("src", "c_scale,dpr_auto,w_auto/sample.jpg")); + }); +}); diff --git a/test/testUtils/reusableTests/reusableTests.js b/test/testUtils/reusableTests/reusableTests.js new file mode 100644 index 00000000..37e9e80c --- /dev/null +++ b/test/testUtils/reusableTests/reusableTests.js @@ -0,0 +1,11 @@ +const registeredTests = {}; + +function registerReusableTest(name, testFn) { + registeredTests[name] = testFn; +} + +function callReusableTest(name, ...args) { + registeredTests[name].apply(this, args); +} + +module.exports = {registerReusableTest, callReusableTest}; diff --git a/test/testUtils/testBootstrap.js b/test/testUtils/testBootstrap.js index cc6af249..741be507 100644 --- a/test/testUtils/testBootstrap.js +++ b/test/testUtils/testBootstrap.js @@ -5,3 +5,8 @@ const path = require('path'); glob.sync(`${__dirname}/assertions/*.js`).forEach(function (file) { require(path.resolve(file)); }); + +// Import all reusable tests so they can be used with a name +glob.sync(`${__dirname}/reusableTests/**/*.js`).forEach(function (file) { + require(path.resolve(file)); +}); diff --git a/test/unit/tags/image_spec.js b/test/unit/tags/image_spec.js index e157ed33..450f3f41 100644 --- a/test/unit/tags/image_spec.js +++ b/test/unit/tags/image_spec.js @@ -1,5 +1,5 @@ const cloudinary = require('../../../cloudinary'); -const { setupCache, sharedExamples, includeContext } = require("../../spechelper"); +const { setupCache } = require("../../spechelper"); const { extend, isEmpty } = cloudinary.utils; const BREAKPOINTS = [5, 3, 7, 5]; @@ -10,6 +10,9 @@ const srcRegExp = function (name, path) { }; const createTestConfig = require('../../testUtils/createTestConfig'); +const callReusableTest = require('../../testUtils/reusableTests/reusableTests').callReusableTest; + + describe('image helper', function () { var commonTrans, commonTransformationStr, customAttributes; @@ -109,29 +112,10 @@ describe('image helper', function () { alt: "asdfg\"'asdf" })).to.eql(`asdfg"'asdf`); }); - sharedExamples("client_hints", function(options) { - it("should not use data-src or set responsive class", function() { - var tag = cloudinary.image('sample.jpg', options); - expect(tag).to.match(//); - expect(tag).not.to.match(/<.*class.*>/); - expect(tag).not.to.match(/\bdata-src\b/); - expect(tag).to.match(srcRegExp("src", "c_scale,dpr_auto,w_auto/sample.jpg")); - }); - it("should override responsive", function () { - var tag; - cloudinary.config({ - responsive: true - }); - tag = cloudinary.image('sample.jpg', options); - expect(tag).to.match(//); - expect(tag).not.to.match(/<.*class.*>/); - expect(tag).not.to.match(/\bdata-src\b/); - expect(tag).to.match(srcRegExp("src", "c_scale,dpr_auto,w_auto/sample.jpg")); - }); - }); + describe(":client_hints", function () { describe("as option", function () { - includeContext("client_hints", { + callReusableTest("Expects correct image tag attributes when client hints are used", { dpr: "auto", cloud_name: "test123", width: "auto", @@ -143,7 +127,7 @@ describe('image helper', function () { beforeEach(function () { cloudinary.config().client_hints = true; }); - includeContext("client_hints", { + callReusableTest("Expects correct image tag attributes when client hints are used", { dpr: "auto", cloud_name: "test123", width: "auto",