fix(media-library-cloudinary): fix options, add tests (#1938)
This commit is contained in:
parent
a7f7bd4dbf
commit
443f060ef9
@ -68,6 +68,7 @@
|
||||
"cache-me-outside": "^0.0.4",
|
||||
"cross-env": "^5.1.4",
|
||||
"cypress": "^3.0.3",
|
||||
"dom-testing-library": "^3.13.0",
|
||||
"eslint": "^5.3.0",
|
||||
"eslint-plugin-react": "^7.10.0",
|
||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
|
@ -0,0 +1,292 @@
|
||||
import { queryHelpers, waitForElement } from 'dom-testing-library';
|
||||
import cloudinary from '../index';
|
||||
|
||||
describe('cloudinary media library', () => {
|
||||
let mediaLibrary;
|
||||
let cloudinaryScript;
|
||||
let cloudinaryConfig;
|
||||
let cloudinaryInsertHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
/**
|
||||
* Mock of the Cloudinary library itself, which is otherwise created by
|
||||
* their script (which isn't actually run during testing).
|
||||
*/
|
||||
window.cloudinary = {
|
||||
createMediaLibrary: (config, { insertHandler }) => {
|
||||
cloudinaryConfig = config;
|
||||
cloudinaryInsertHandler = insertHandler;
|
||||
return mediaLibrary;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Mock of the object returned by the Cloudinary createMediaLibrary method.
|
||||
*/
|
||||
mediaLibrary = {
|
||||
show: jest.fn(),
|
||||
hide: jest.fn(),
|
||||
};
|
||||
|
||||
/**
|
||||
* Every time the integration is initialized, a script tag is dynamically
|
||||
* generated and added to the page. The initialization is on hold until
|
||||
* the `load` event is broadcast, but that doesn't happen during testing,
|
||||
* so we wait for the script tag to be added to the dom and then manually
|
||||
* call its `onreadystatechange` method, which resolves the promise and
|
||||
* allows initialization to continue.
|
||||
*
|
||||
* This also ensures that the script is being added to the DOM, and in a way
|
||||
* that is not tied to script loading implementation details.
|
||||
*/
|
||||
waitForElement(() => {
|
||||
const url = 'https://media-library.cloudinary.com/global/all.js';
|
||||
return queryHelpers.queryByAttribute('src', document, url);
|
||||
}).then(script => {
|
||||
cloudinaryScript = script;
|
||||
script.onreadystatechange();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
/**
|
||||
* Remove the script element from the dom after each test.
|
||||
*/
|
||||
if (cloudinaryScript) {
|
||||
document.head.removeChild(cloudinaryScript);
|
||||
}
|
||||
});
|
||||
|
||||
it('exports an object with expected properties', () => {
|
||||
expect(cloudinary).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"init": [Function],
|
||||
"name": "cloudinary",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
describe('configuration', () => {
|
||||
const defaultCloudinaryConfig = {
|
||||
button_class: undefined,
|
||||
inline_container: undefined,
|
||||
insert_transformation: false,
|
||||
z_index: '99999',
|
||||
multiple: false,
|
||||
};
|
||||
|
||||
it('has defaults', async () => {
|
||||
await cloudinary.init();
|
||||
expect(cloudinaryConfig).toEqual(defaultCloudinaryConfig);
|
||||
});
|
||||
|
||||
it('does not allow enforced values to be overridden', async () => {
|
||||
const options = {
|
||||
config: {
|
||||
button_class: 'foo',
|
||||
inline_container: 'foo',
|
||||
insert_transformation: 'foo',
|
||||
z_index: 0,
|
||||
},
|
||||
};
|
||||
await cloudinary.init({ options });
|
||||
expect(cloudinaryConfig).toEqual(defaultCloudinaryConfig);
|
||||
});
|
||||
|
||||
it('allows non-enforced defaults to be overridden', async () => {
|
||||
const options = {
|
||||
config: {
|
||||
multiple: true,
|
||||
},
|
||||
};
|
||||
await cloudinary.init({ options });
|
||||
expect(cloudinaryConfig).toEqual({ ...defaultCloudinaryConfig, ...options.config });
|
||||
});
|
||||
|
||||
it('allows unknown values', async () => {
|
||||
const options = {
|
||||
config: {
|
||||
foo: 'bar',
|
||||
},
|
||||
};
|
||||
await cloudinary.init({ options });
|
||||
expect(cloudinaryConfig).toEqual({ ...defaultCloudinaryConfig, ...options.config });
|
||||
});
|
||||
});
|
||||
|
||||
describe('insertHandler', () => {
|
||||
let handleInsert;
|
||||
const asset = {
|
||||
url: 'http://foo.bar/image.jpg',
|
||||
secure_url: 'https://foo.bar/image.jpg',
|
||||
public_id: 'image',
|
||||
format: 'jpg',
|
||||
};
|
||||
const assetWithDerived = {
|
||||
...asset,
|
||||
derived: [
|
||||
{
|
||||
secure_url: 'https://derived.foo.bar/image.jpg',
|
||||
url: 'http://derived.foo.bar/image.jpg',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
handleInsert = jest.fn();
|
||||
});
|
||||
|
||||
it('calls insert function with single asset', async () => {
|
||||
await cloudinary.init({ handleInsert });
|
||||
cloudinaryInsertHandler({ assets: [asset] });
|
||||
expect(handleInsert).toHaveBeenCalledWith(expect.any(String));
|
||||
});
|
||||
|
||||
it('calls insert function with multiple assets', async () => {
|
||||
const options = {
|
||||
config: {
|
||||
multiple: true,
|
||||
},
|
||||
};
|
||||
await cloudinary.init({ options, handleInsert });
|
||||
cloudinaryInsertHandler({ assets: [asset, asset] });
|
||||
expect(handleInsert).toHaveBeenCalledWith(expect.any(Array));
|
||||
});
|
||||
|
||||
it('calls insert function with secure url', async () => {
|
||||
await cloudinary.init({ handleInsert });
|
||||
cloudinaryInsertHandler({ assets: [asset] });
|
||||
expect(handleInsert).toHaveBeenCalledWith(asset.secure_url);
|
||||
});
|
||||
|
||||
it('calls insert function with insecure url', async () => {
|
||||
const options = {
|
||||
use_secure_url: false,
|
||||
};
|
||||
await cloudinary.init({ options, handleInsert });
|
||||
cloudinaryInsertHandler({ assets: [asset] });
|
||||
expect(handleInsert).toHaveBeenCalledWith(asset.url);
|
||||
});
|
||||
|
||||
it('supports derived assets', async () => {
|
||||
await cloudinary.init({ handleInsert });
|
||||
cloudinaryInsertHandler({ assets: [assetWithDerived] });
|
||||
expect(handleInsert).toHaveBeenCalledWith(assetWithDerived.derived[0].secure_url);
|
||||
});
|
||||
|
||||
it('ignores derived assets when use_transformations is false', async () => {
|
||||
const options = {
|
||||
use_transformations: false,
|
||||
};
|
||||
await cloudinary.init({ options, handleInsert });
|
||||
cloudinaryInsertHandler({ assets: [assetWithDerived] });
|
||||
expect(handleInsert).toHaveBeenCalledWith(assetWithDerived.secure_url);
|
||||
});
|
||||
|
||||
it('supports outputting filename only', async () => {
|
||||
const options = {
|
||||
output_filename_only: true,
|
||||
};
|
||||
await cloudinary.init({ options, handleInsert });
|
||||
cloudinaryInsertHandler({ assets: [asset] });
|
||||
expect(handleInsert.mock.calls[0][0]).toMatchInlineSnapshot(`"image.jpg"`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('show method', () => {
|
||||
const defaultOptions = {
|
||||
config: {
|
||||
multiple: false,
|
||||
},
|
||||
};
|
||||
|
||||
it('calls cloudinary instance show method with default options', async () => {
|
||||
const integration = await cloudinary.init();
|
||||
integration.show();
|
||||
expect(mediaLibrary.show).toHaveBeenCalledWith(defaultOptions);
|
||||
});
|
||||
|
||||
it('accepts unknown configuration keys', async () => {
|
||||
const showOptions = {
|
||||
config: {
|
||||
...defaultOptions.config,
|
||||
foo: 'bar',
|
||||
},
|
||||
};
|
||||
const integration = await cloudinary.init();
|
||||
integration.show(showOptions);
|
||||
expect(mediaLibrary.show).toHaveBeenCalledWith(showOptions);
|
||||
});
|
||||
|
||||
it('receives global configuration for behavior only', async () => {
|
||||
const behaviorOptions = {
|
||||
default_transformations: [{ foo: 'bar' }],
|
||||
max_files: 2,
|
||||
multiple: true,
|
||||
};
|
||||
const nonBehaviorOptions = {
|
||||
api_key: 123,
|
||||
};
|
||||
const options = {
|
||||
config: {
|
||||
...behaviorOptions,
|
||||
...nonBehaviorOptions,
|
||||
},
|
||||
};
|
||||
const expectedOptions = {
|
||||
config: behaviorOptions,
|
||||
};
|
||||
const integration = await cloudinary.init({ options });
|
||||
integration.show();
|
||||
expect(mediaLibrary.show).toHaveBeenCalledWith(expectedOptions);
|
||||
});
|
||||
|
||||
it('allows global/default configuration to be overridden', async () => {
|
||||
const showOptions = {
|
||||
config: {
|
||||
multiple: true,
|
||||
},
|
||||
};
|
||||
const integration = await cloudinary.init();
|
||||
integration.show(showOptions);
|
||||
expect(mediaLibrary.show).toHaveBeenCalledWith(showOptions);
|
||||
});
|
||||
|
||||
it('enforces multiple: false if allowMultiple is true', async () => {
|
||||
const options = {
|
||||
config: {
|
||||
multiple: true,
|
||||
},
|
||||
};
|
||||
const showOptions = {
|
||||
config: {
|
||||
multiple: true,
|
||||
},
|
||||
allowMultiple: false,
|
||||
};
|
||||
const expectedOptions = {
|
||||
config: {
|
||||
multiple: false,
|
||||
},
|
||||
};
|
||||
const integration = await cloudinary.init(options);
|
||||
integration.show(showOptions);
|
||||
expect(mediaLibrary.show).toHaveBeenCalledWith(expectedOptions);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hide method', () => {
|
||||
it('calls cloudinary instance hide method', async () => {
|
||||
const integration = await cloudinary.init();
|
||||
integration.hide();
|
||||
expect(mediaLibrary.hide).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('enableStandalone method', () => {
|
||||
it('returns true', async () => {
|
||||
const integration = await cloudinary.init();
|
||||
expect(integration.enableStandalone()).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
@ -45,7 +45,11 @@ function getAssetUrl(asset, { use_secure_url, use_transformations, output_filena
|
||||
return urlObject[urlKey];
|
||||
}
|
||||
|
||||
async function init({ options, handleInsert }) {
|
||||
async function init({ options = {}, handleInsert } = {}) {
|
||||
/**
|
||||
* Configuration is specific to Cloudinary, while options are specific to this
|
||||
* integration.
|
||||
*/
|
||||
const { config: providedConfig = {}, ...integrationOptions } = options;
|
||||
const resolvedOptions = { ...defaultOptions, ...integrationOptions };
|
||||
const cloudinaryConfig = { ...defaultConfig, ...providedConfig, ...enforcedConfig };
|
||||
@ -62,7 +66,7 @@ async function init({ options, handleInsert }) {
|
||||
const mediaLibrary = window.cloudinary.createMediaLibrary(cloudinaryConfig, { insertHandler });
|
||||
|
||||
return {
|
||||
show: ({ config: instanceConfig = {}, allowMultiple }) => {
|
||||
show: ({ config: instanceConfig = {}, allowMultiple } = {}) => {
|
||||
/**
|
||||
* Ensure multiple selection is not available if the field is configured
|
||||
* to disallow it.
|
||||
@ -70,7 +74,7 @@ async function init({ options, handleInsert }) {
|
||||
if (allowMultiple === false) {
|
||||
instanceConfig.multiple = false;
|
||||
}
|
||||
return mediaLibrary.show({ config: { ...cloudinaryBehaviorConfig, instanceConfig } });
|
||||
return mediaLibrary.show({ config: { ...cloudinaryBehaviorConfig, ...instanceConfig } });
|
||||
},
|
||||
hide: () => mediaLibrary.hide(),
|
||||
enableStandalone: () => true,
|
||||
|
19
yarn.lock
19
yarn.lock
@ -753,6 +753,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/runtime@^7.1.5":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f"
|
||||
integrity sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/template@7.0.0-beta.54":
|
||||
version "7.0.0-beta.54"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.54.tgz#d5b0d2d2d55c0e78b048c61a058f36cfd7d91af3"
|
||||
@ -4171,6 +4178,16 @@ dom-testing-library@^3.12.0:
|
||||
pretty-format "^23.6.0"
|
||||
wait-for-expect "^1.0.0"
|
||||
|
||||
dom-testing-library@^3.13.0:
|
||||
version "3.13.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-testing-library/-/dom-testing-library-3.13.0.tgz#3d9c48db2bc4629f097571612d138bf2e8c42421"
|
||||
integrity sha512-ImIZQrsEPQkmXNFzYmOsCJBjaBcZJe4vRJfP55DhYySD2LL56ACPaJATbXphLGred5efqGC1Q4H3UuqWCZ9Bqg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.5"
|
||||
"@sheerun/mutationobserver-shim" "^0.3.2"
|
||||
pretty-format "^23.6.0"
|
||||
wait-for-expect "^1.1.0"
|
||||
|
||||
dom-walk@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
|
||||
@ -12341,7 +12358,7 @@ w3c-hr-time@^1.0.1:
|
||||
dependencies:
|
||||
browser-process-hrtime "^0.1.2"
|
||||
|
||||
wait-for-expect@^1.0.0:
|
||||
wait-for-expect@^1.0.0, wait-for-expect@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.1.0.tgz#6607375c3f79d32add35cd2c87ce13f351a3d453"
|
||||
integrity sha512-vQDokqxyMyknfX3luCDn16bSaRcOyH6gGuUXMIbxBLeTo6nWuEWYqMTT9a+44FmW8c2m6TRWBdNvBBjA1hwEKg==
|
||||
|
Loading…
x
Reference in New Issue
Block a user