UNPKG

box-ui-elements-mlh

Version:
1,079 lines (999 loc) 93.7 kB
import Cache from '../../utils/Cache'; import * as ErrorUtil from '../../utils/error'; import Metadata from '../Metadata'; import { METADATA_TEMPLATE_CLASSIFICATION, METADATA_SCOPE_GLOBAL, METADATA_TEMPLATE_PROPERTIES, ERROR_CODE_DELETE_METADATA, ERROR_CODE_CREATE_METADATA, ERROR_CODE_UPDATE_METADATA, ERROR_CODE_UPDATE_SKILLS, ERROR_CODE_FETCH_SKILLS, ERROR_CODE_FETCH_METADATA_TEMPLATES, ERROR_CODE_FETCH_METADATA, } from '../../constants'; let metadata; describe('api/Metadata', () => { beforeEach(() => { metadata = new Metadata({}); }); describe('getCacheKey()', () => { test('should return correct key', () => { expect(metadata.getCacheKey('foo')).toBe('file_foo'); }); }); describe('getMetadataCacheKey()', () => { test('should return correct key', () => { expect(metadata.getMetadataCacheKey('foo')).toBe('metadata_foo'); }); }); describe('getSkillsCacheKey()', () => { test('should return correct key', () => { expect(metadata.getSkillsCacheKey('foo')).toBe('metadata_foo_skills'); }); }); describe('getClassificationCacheKey()', () => { test('should return correct key', () => { expect(metadata.getClassificationCacheKey('foo')).toBe('metadata_foo_classification'); }); }); describe('getMetadataUrl()', () => { test('should return base api url when no template or scope', () => { expect(metadata.getMetadataUrl('foo')).toBe('https://api.box.com/2.0/files/foo/metadata'); expect(metadata.getMetadataUrl('foo', '', 'template')).toBe('https://api.box.com/2.0/files/foo/metadata'); expect(metadata.getMetadataUrl('foo', 'scope')).toBe('https://api.box.com/2.0/files/foo/metadata'); }); test('should return correct api url with scope and template', () => { expect(metadata.getMetadataUrl('foo', 'scope', 'template')).toBe( 'https://api.box.com/2.0/files/foo/metadata/scope/template', ); }); }); describe('getMetadataTemplateUrl()', () => { test('should return correct base api url', () => { expect(metadata.getMetadataTemplateUrl('scope')).toBe('https://api.box.com/2.0/metadata_templates'); }); }); describe('getMetadataTemplateUrlForInstance()', () => { test('should return template url for an instance', () => { expect(metadata.getMetadataTemplateUrlForInstance('id')).toBe( 'https://api.box.com/2.0/metadata_templates?metadata_instance_id=id', ); }); }); describe('getMetadataTemplateSchemaUrl()', () => { test('should return url for to get metadata schema using template key', () => { const templateKey = 'templateKey_123'; expect(metadata.getMetadataTemplateSchemaUrl(templateKey)).toBe( `https://api.box.com/2.0/metadata_templates/enterprise/${templateKey}/schema`, ); }); }); describe('getMetadataTemplateUrlForScope()', () => { test('should return correct template url for scope', () => { expect(metadata.getMetadataTemplateUrlForScope('scope')).toBe( 'https://api.box.com/2.0/metadata_templates/scope', ); }); }); describe('getCustomPropertiesTemplate()', () => { test('should return correct properties template', () => { expect(metadata.getCustomPropertiesTemplate()).toEqual({ id: expect.stringContaining('metadata_template_'), scope: METADATA_SCOPE_GLOBAL, templateKey: METADATA_TEMPLATE_PROPERTIES, hidden: false, }); }); }); describe('createEditor()', () => { test('should return an uneditable editor', () => { expect( metadata.createEditor( { $id: 'id', $foo: 'bar', foo: 'bar', $canEdit: true, }, { id: 'foo' }, false, ), ).toEqual({ template: { id: 'foo', }, instance: { id: 'id', canEdit: false, data: { foo: 'bar', }, }, }); }); test('should return an editable editor', () => { expect( metadata.createEditor( { $id: 'id', $foo: 'bar', foo: 'bar', $canEdit: true, }, { id: 'foo' }, true, ), ).toEqual({ template: { id: 'foo', }, instance: { id: 'id', canEdit: true, data: { foo: 'bar', }, }, }); }); }); describe('getTemplates()', () => { test('should return templates with enterprise scope', async () => { const templatesFromServer = [ { id: 1, hidden: false }, { id: 2, hidden: true }, { id: 3, hidden: false }, { id: 4, hidden: false }, { id: 5, hidden: true, templateKey: METADATA_TEMPLATE_CLASSIFICATION, }, { id: 6, hidden: false, templateKey: METADATA_TEMPLATE_CLASSIFICATION, }, ]; metadata.getMetadataTemplateUrlForScope = jest.fn().mockReturnValueOnce('template_url'); metadata.xhr.get = jest.fn().mockReturnValueOnce({ data: { entries: templatesFromServer, }, }); const templates = await metadata.getTemplates('id', 'enterprise'); expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA_TEMPLATES); expect(templates).toEqual(templates); expect(metadata.getMetadataTemplateUrlForScope).toHaveBeenCalledWith('enterprise'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'template_url', id: 'file_id', params: { limit: 1000, }, }); }); test('should return templates scoped to instance id', async () => { const templatesFromServer = [{ id: 1, hidden: false }]; metadata.getMetadataTemplateUrlForInstance = jest.fn().mockReturnValueOnce('template_url'); metadata.xhr.get = jest.fn().mockReturnValueOnce({ data: { entries: templatesFromServer, }, }); const templates = await metadata.getTemplates('id', 'scope', 'id'); expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA_TEMPLATES); expect(templates).toEqual(templates); expect(metadata.getMetadataTemplateUrlForInstance).toHaveBeenCalledWith('id'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'template_url', id: 'file_id', params: { limit: 1000, }, }); }); test('should return empty array of templates when error is 400', async () => { const error = new Error(); error.status = 400; metadata.getMetadataTemplateUrlForScope = jest.fn().mockReturnValueOnce('template_url'); metadata.xhr.get = jest.fn().mockReturnValueOnce(Promise.reject(error)); let templates; try { templates = await metadata.getTemplates('id', 'scope'); } catch (e) { expect(e.status).toEqual(400); } expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA_TEMPLATES); expect(templates).toEqual([]); expect(metadata.getMetadataTemplateUrlForScope).toHaveBeenCalledWith('scope'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'template_url', id: 'file_id', params: { limit: 1000, }, }); }); test('should throw error when error is not 400', async () => { const error = new Error(); error.status = 401; metadata.getMetadataTemplateUrlForScope = jest.fn().mockReturnValueOnce('template_url'); metadata.xhr.get = jest.fn().mockReturnValueOnce(Promise.reject(error)); let templates; try { templates = await metadata.getTemplates('id', 'scope'); } catch (e) { expect(e.status).toEqual(401); } expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA_TEMPLATES); expect(templates).toBeUndefined(); expect(metadata.getMetadataTemplateUrlForScope).toHaveBeenCalledWith('scope'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'template_url', id: 'file_id', params: { limit: 1000, }, }); }); }); describe('getSchemaByTemplateKey()', () => { test('should return metadata template for provided template key', async () => { const metadataTemplate = 'metadataTemplate'; const templateKey = 'templateKey_123'; const url = `https://api.box.com/2.0/metadata_templates/enterprise/${templateKey}/schema`; metadata.xhr.get = jest.fn().mockReturnValueOnce(Promise.resolve(metadataTemplate)); const response = await metadata.getSchemaByTemplateKey(templateKey); expect(metadata.xhr.get).toHaveBeenCalledWith({ url }); expect(response).toBe(metadataTemplate); }); }); describe('getInstances()', () => { test('should return templates with enterprise scope', async () => { const instancesFromServer = [ { id: 1, hidden: false }, { id: 2, hidden: true }, { id: 3, hidden: false }, { id: 4, hidden: false }, ]; metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('metadata_url'); metadata.xhr.get = jest.fn().mockReturnValueOnce({ data: { entries: instancesFromServer, }, }); const instances = await metadata.getInstances('id'); expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA); expect(instances).toEqual(instances); expect(metadata.getMetadataUrl).toHaveBeenCalledWith('id'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'metadata_url', id: 'file_id', }); }); test('should return empty array of templates when error is 400', async () => { const error = new Error(); error.status = 400; metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('metadata_url'); metadata.xhr.get = jest.fn().mockReturnValueOnce(Promise.reject(error)); let instances; try { instances = await metadata.getInstances('id'); } catch (e) { expect(e.status).toEqual(400); } expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA); expect(instances).toEqual([]); expect(metadata.getMetadataUrl).toHaveBeenCalledWith('id'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'metadata_url', id: 'file_id', }); }); test('should throw error when error is not 400', async () => { const error = new Error(); error.status = 401; metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('metadata_url'); metadata.xhr.get = jest.fn().mockReturnValueOnce(Promise.reject(error)); let instances; try { instances = await metadata.getInstances('id'); } catch (e) { expect(e.status).toEqual(401); } expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA); expect(instances).toBeUndefined(); expect(metadata.getMetadataUrl).toHaveBeenCalledWith('id'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'metadata_url', id: 'file_id', }); }); }); describe('getUserAddableTemplates()', () => { test('should return empty array when metadata feature is off', async () => { const custom = 'custom'; const ent = [{ templateKey: 'e1' }, { templateKey: 'e2' }]; const templates = [...ent, { templateKey: 'securityClassification-6VMVochwUWo' }]; expect(metadata.getUserAddableTemplates(custom, templates, false)).toEqual([]); }); test('should return only custom props tempalte when file is externally owned', async () => { const custom = 'custom'; const ent = [{ templateKey: 'e1' }, { templateKey: 'e2' }]; const templates = [...ent, { templateKey: 'securityClassification-6VMVochwUWo' }]; expect(metadata.getUserAddableTemplates(custom, templates, true, true)).toEqual(['custom']); }); test('should return all templates for file owner minus classification', async () => { const custom = 'custom'; const ent = [{ templateKey: 'e1' }, { templateKey: 'e2' }]; const templates = [...ent, { templateKey: 'securityClassification-6VMVochwUWo' }]; expect(metadata.getUserAddableTemplates(custom, templates, true)).toEqual(['custom', ...ent]); }); test('should return all templates for file owner minus hidden ones', async () => { const custom = 'custom'; const ent = [{ templateKey: 'e1', hidden: true }, { templateKey: 'e2' }]; const templates = [...ent, { templateKey: 'securityClassification-6VMVochwUWo' }]; expect(metadata.getUserAddableTemplates(custom, templates, true)).toEqual([ 'custom', { templateKey: 'e2' }, ]); }); }); describe('extractClassification()', () => { test('should extract and cache classification and return filtered instances', async () => { const cache = new Cache(); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getClassificationCacheKey = jest.fn().mockReturnValueOnce('cache_id_classification'); expect( metadata.extractClassification('id', [ { $template: 'foo' }, { $template: 'bad' }, { $template: 'securityClassification-6VMVochwUWo' }, ]), ).toEqual([{ $template: 'foo' }, { $template: 'bad' }]); expect(metadata.getClassificationCacheKey).toHaveBeenCalledWith('id'); expect(cache.get('cache_id_classification')).toEqual({ $template: 'securityClassification-6VMVochwUWo' }); }); test('should return instances if no classification found', async () => { const cache = new Cache(); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getClassificationCacheKey = jest.fn().mockReturnValueOnce('cache_id_classification'); expect(metadata.extractClassification('id', [{ $template: 'foo' }, { $template: 'bad' }])).toEqual([ { $template: 'foo' }, { $template: 'bad' }, ]); expect(metadata.getClassificationCacheKey).not.toHaveBeenCalled(); expect(cache.get('cache_id_classification')).toBeUndefined(); }); }); describe('getTemplateForInstance()', () => { const templatesFromServer = [ { id: 1, scope: 'global', templateKey: 'global1' }, { id: 2, scope: 'enterprise', templateKey: 'enterprise2' }, { id: 3, scope: 'enterprise', templateKey: 'enterprise3' }, { id: 4, scope: 'enterprise', templateKey: 'enterprise4' }, { id: 5, scope: 'global', templateKey: 'global5' }, { id: 6, scope: 'global', templateKey: 'global6' }, ]; test('should return undefined when no global template found', async () => { const template = await metadata.getTemplateForInstance( 'id', { $id: 'instanceId', $scope: 'global', $template: 'foo', }, templatesFromServer, ); expect(template).toBeUndefined(); }); test('should return found enterprise template', async () => { const template = await metadata.getTemplateForInstance( 'id', { $id: 'instanceId', $scope: 'enterprise', $template: 'enterprise2', }, templatesFromServer, ); expect(template).toBe(templatesFromServer[1]); }); test('should return templates scoped to instance id', async () => { metadata.getTemplates = jest.fn().mockResolvedValueOnce(['collabed_template']); const template = await metadata.getTemplateForInstance( 'id', { $id: 'instanceId', $scope: 'enterprise', $template: 'foobar', }, templatesFromServer, ); expect(template).toBe('collabed_template'); expect(metadata.getTemplates).toBeCalledWith('id', 'enterprise', 'instanceId'); }); }); describe('getEditors()', () => { test('should build and return editors with valid templates', async () => { const instances = [ { $id: '1', $scope: 'global', $template: 'global1', }, { $id: '2', $scope: 'enterprise', $template: 'enterprise2', }, { $id: '3', $scope: 'enterprise', $template: 'enterprise3', }, { $id: '4', $scope: 'global', $template: 'custom', }, { $id: '5', $scope: 'global', $template: 'bogus', }, ]; metadata.extractClassification = jest.fn().mockReturnValueOnce(instances); metadata.createEditor = jest .fn() .mockReturnValueOnce('editor1') .mockReturnValueOnce('editor2') .mockReturnValueOnce('editor3') .mockReturnValueOnce('editor4'); metadata.getTemplateForInstance = jest .fn() .mockResolvedValueOnce('template1') .mockResolvedValueOnce('template2') .mockResolvedValueOnce('template3') .mockResolvedValueOnce('template4') .mockResolvedValueOnce(); const editors = await metadata.getEditors('id', instances, {}, [], [], true); expect(editors).toEqual(['editor1', 'editor2', 'editor3', 'editor4']); expect(metadata.extractClassification).toBeCalledWith('id', instances); expect(metadata.createEditor).toBeCalledTimes(4); expect(metadata.createEditor.mock.calls[0][0]).toBe(instances[0]); expect(metadata.createEditor.mock.calls[0][1]).toBe('template1'); expect(metadata.createEditor.mock.calls[0][2]).toBe(true); expect(metadata.createEditor.mock.calls[1][0]).toBe(instances[1]); expect(metadata.createEditor.mock.calls[1][1]).toBe('template2'); expect(metadata.createEditor.mock.calls[1][2]).toBe(true); expect(metadata.createEditor.mock.calls[2][0]).toBe(instances[2]); expect(metadata.createEditor.mock.calls[2][1]).toBe('template3'); expect(metadata.createEditor.mock.calls[2][2]).toBe(true); expect(metadata.createEditor.mock.calls[3][0]).toBe(instances[3]); expect(metadata.createEditor.mock.calls[3][1]).toBe('template4'); expect(metadata.createEditor.mock.calls[3][2]).toBe(true); expect(metadata.getTemplateForInstance).toBeCalledTimes(5); expect(metadata.getTemplateForInstance.mock.calls[0][0]).toBe('id'); expect(metadata.getTemplateForInstance.mock.calls[0][1]).toBe(instances[0]); expect(metadata.getTemplateForInstance.mock.calls[0][2]).toEqual([{}]); expect(metadata.getTemplateForInstance.mock.calls[1][0]).toBe('id'); expect(metadata.getTemplateForInstance.mock.calls[1][1]).toBe(instances[1]); expect(metadata.getTemplateForInstance.mock.calls[1][2]).toEqual([{}]); expect(metadata.getTemplateForInstance.mock.calls[2][0]).toBe('id'); expect(metadata.getTemplateForInstance.mock.calls[2][1]).toBe(instances[2]); expect(metadata.getTemplateForInstance.mock.calls[2][2]).toEqual([{}]); expect(metadata.getTemplateForInstance.mock.calls[3][0]).toBe('id'); expect(metadata.getTemplateForInstance.mock.calls[3][1]).toBe(instances[3]); expect(metadata.getTemplateForInstance.mock.calls[3][2]).toEqual([{}]); expect(metadata.getTemplateForInstance.mock.calls[4][0]).toBe('id'); expect(metadata.getTemplateForInstance.mock.calls[4][1]).toBe(instances[4]); expect(metadata.getTemplateForInstance.mock.calls[4][2]).toEqual([{}]); }); }); describe('getMetadata()', () => { test('should call error callback with a bad item error when no id', () => { ErrorUtil.getBadItemError = jest.fn().mockReturnValueOnce('error'); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.getMetadata({}, jest.fn(), jest.fn(), true); expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA); expect(metadata.errorHandler).toBeCalledWith('error'); expect(metadata.successHandler).not.toBeCalled(); expect(ErrorUtil.getBadItemError).toBeCalled(); }); test('should call error callback with a bad item error when no permissions object', () => { ErrorUtil.getBadItemError = jest.fn().mockReturnValueOnce('error'); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.getMetadata({ id: 'id' }, jest.fn(), jest.fn(), true); expect(metadata.errorCode).toBe(ERROR_CODE_FETCH_METADATA); expect(metadata.errorHandler).toBeCalledWith('error'); expect(metadata.successHandler).not.toBeCalled(); expect(ErrorUtil.getBadItemError).toBeCalled(); }); test('should not make request and and return cached data', async () => { const file = { id: 'id', is_externally_owned: true, permissions: { can_upload: true, }, }; const cache = new Cache(); cache.set('cache_id_metadata', 'cached_metadata'); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getMetadataCacheKey = jest.fn().mockReturnValueOnce('cache_id_metadata'); metadata.getInstances = jest.fn().mockResolvedValueOnce('instances'); metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); metadata.getTemplates = jest .fn() .mockResolvedValueOnce('global') .mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true, { refreshCache: false }); expect(metadata.isDestroyed).not.toHaveBeenCalled(); expect(metadata.getCache).toHaveBeenCalled(); expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.getInstances).not.toHaveBeenCalledWith(); expect(metadata.getTemplates).not.toHaveBeenCalledWith(); expect(metadata.getTemplates).not.toHaveBeenCalledWith(); expect(metadata.getEditors).not.toHaveBeenCalledWith(); expect(metadata.getUserAddableTemplates).not.toHaveBeenCalledWith(); expect(metadata.successHandler).toHaveBeenCalledWith('cached_metadata'); expect(metadata.successHandler).toHaveBeenCalledTimes(1); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_metadata')).toEqual('cached_metadata'); }); test('should make request and update cache and call success handler', async () => { const file = { id: 'id', is_externally_owned: true, permissions: { can_upload: true, }, }; const cache = new Cache(); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getMetadataCacheKey = jest.fn().mockReturnValueOnce('cache_id_metadata'); metadata.getInstances = jest.fn().mockResolvedValueOnce('instances'); metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); metadata.getTemplates = jest .fn() .mockResolvedValueOnce('global') .mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true); expect(metadata.isDestroyed).toHaveBeenCalled(); expect(metadata.getCache).toHaveBeenCalled(); expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.getInstances).toHaveBeenCalledWith(file.id); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global'); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise'); expect(metadata.getEditors).toHaveBeenCalledWith( file.id, 'instances', 'custom', 'enterprise', 'global', true, ); expect(metadata.getUserAddableTemplates).toHaveBeenCalledWith('custom', 'enterprise', true, true); expect(metadata.successHandler).toHaveBeenCalledWith({ editors: 'editors', templates: 'templates', }); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_metadata')).toEqual({ editors: 'editors', templates: 'templates', }); }); test('should make request and update cache and call success handler after returning cached value when refreshCache is true', async () => { const file = { id: 'id', is_externally_owned: true, permissions: { can_upload: true, }, }; const cache = new Cache(); cache.set('cache_id_metadata', 'cached_metadata'); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getMetadataCacheKey = jest.fn().mockReturnValueOnce('cache_id_metadata'); metadata.getInstances = jest.fn().mockResolvedValueOnce('instances'); metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); metadata.getTemplates = jest .fn() .mockResolvedValueOnce('global') .mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true, { refreshCache: true }); expect(metadata.isDestroyed).toHaveBeenCalled(); expect(metadata.getCache).toHaveBeenCalled(); expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.getInstances).toHaveBeenCalledWith(file.id); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global'); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise'); expect(metadata.getEditors).toHaveBeenCalledWith( file.id, 'instances', 'custom', 'enterprise', 'global', true, ); expect(metadata.getUserAddableTemplates).toHaveBeenCalledWith('custom', 'enterprise', true, true); expect(metadata.successHandler).toHaveBeenCalledTimes(2); expect(metadata.successHandler).toHaveBeenCalledWith('cached_metadata'); expect(metadata.successHandler).toHaveBeenCalledWith({ editors: 'editors', templates: 'templates', }); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_metadata')).toEqual({ editors: 'editors', templates: 'templates', }); }); test('should ignore cache and make request and update cache and call success handler when forceFetch is true', async () => { const file = { id: 'id', is_externally_owned: true, permissions: { can_upload: true, }, }; const cache = new Cache(); cache.set('cache_id_metadata', 'cached_metadata'); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getMetadataCacheKey = jest.fn().mockReturnValueOnce('cache_id_metadata'); metadata.getInstances = jest.fn().mockResolvedValueOnce('instances'); metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); metadata.getTemplates = jest .fn() .mockResolvedValueOnce('global') .mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true, { forceFetch: true }); expect(metadata.isDestroyed).toHaveBeenCalled(); expect(metadata.getCache).toHaveBeenCalled(); expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.getInstances).toHaveBeenCalledWith(file.id); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global'); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise'); expect(metadata.getEditors).toHaveBeenCalledWith( file.id, 'instances', 'custom', 'enterprise', 'global', true, ); expect(metadata.getUserAddableTemplates).toHaveBeenCalledWith('custom', 'enterprise', true, true); expect(metadata.successHandler).toHaveBeenCalledTimes(1); expect(metadata.successHandler).not.toHaveBeenCalledWith('cached_metadata'); expect(metadata.successHandler).toHaveBeenCalledWith({ editors: 'editors', templates: 'templates', }); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_metadata')).toEqual({ editors: 'editors', templates: 'templates', }); }); test('should make request and update cache and call success handler with metadata feature off', async () => { const file = { id: 'id', is_externally_owned: true, permissions: { can_upload: true, }, }; const cache = new Cache(); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getMetadataCacheKey = jest.fn().mockReturnValueOnce('cache_id_metadata'); metadata.getInstances = jest.fn().mockResolvedValueOnce('instances'); metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); metadata.getTemplates = jest .fn() .mockResolvedValueOnce('global') .mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), false); expect(metadata.isDestroyed).toHaveBeenCalled(); expect(metadata.getCache).toHaveBeenCalled(); expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.getInstances).toHaveBeenCalledWith(file.id); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global'); expect(metadata.getTemplates).not.toHaveBeenCalledWith(file.id, 'enterprise'); expect(metadata.getEditors).toHaveBeenCalledWith(file.id, 'instances', 'custom', [], 'global', true); expect(metadata.getUserAddableTemplates).toHaveBeenCalledWith('custom', [], false, true); expect(metadata.successHandler).toHaveBeenCalledTimes(1); expect(metadata.successHandler).toHaveBeenCalledWith({ editors: 'editors', templates: 'templates', }); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_metadata')).toEqual({ editors: 'editors', templates: 'templates', }); }); test('should call error handler on an error', async () => { const file = { id: 'id', is_externally_owned: true, permissions: { can_upload: true, }, }; const cache = new Cache(); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getMetadataCacheKey = jest.fn().mockReturnValueOnce('cache_id_metadata'); metadata.getInstances = jest.fn().mockRejectedValueOnce('error'); metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); metadata.getTemplates = jest .fn() .mockResolvedValueOnce('global') .mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true); expect(metadata.isDestroyed).not.toHaveBeenCalled(); expect(metadata.getCache).toHaveBeenCalled(); expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.getInstances).toHaveBeenCalledWith(file.id); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global'); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise'); expect(metadata.getEditors).not.toHaveBeenCalled(); expect(metadata.getUserAddableTemplates).not.toHaveBeenCalled(); expect(metadata.successHandler).not.toHaveBeenCalled(); expect(metadata.errorHandler).toHaveBeenCalledWith('error'); expect(cache.get('cache_id_metadata')).toBeUndefined(); }); test('should not call any callback when destroyed but still update the cache', async () => { const file = { id: 'id', is_externally_owned: true, permissions: { can_upload: true, }, }; const cache = new Cache(); cache.set('cache_id_metadata', 'cached_metadata'); metadata.errorHandler = jest.fn(); metadata.successHandler = jest.fn(); metadata.isDestroyed = jest.fn().mockReturnValueOnce(true); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getMetadataCacheKey = jest.fn().mockReturnValueOnce('cache_id_metadata'); metadata.getInstances = jest.fn().mockResolvedValueOnce('instances'); metadata.getEditors = jest.fn().mockResolvedValueOnce('editors'); metadata.getCustomPropertiesTemplate = jest.fn().mockReturnValueOnce('custom'); metadata.getUserAddableTemplates = jest.fn().mockReturnValueOnce('templates'); metadata.getTemplates = jest .fn() .mockResolvedValueOnce('global') .mockResolvedValueOnce('enterprise'); await metadata.getMetadata(file, jest.fn(), jest.fn(), true, { forceFetch: true }); expect(metadata.isDestroyed).toHaveBeenCalled(); expect(metadata.getCache).toHaveBeenCalled(); expect(metadata.getMetadataCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.getInstances).toHaveBeenCalledWith(file.id); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'global'); expect(metadata.getTemplates).toHaveBeenCalledWith(file.id, 'enterprise'); expect(metadata.getEditors).toHaveBeenCalledWith( file.id, 'instances', 'custom', 'enterprise', 'global', true, ); expect(metadata.getUserAddableTemplates).toHaveBeenCalled(); expect(metadata.successHandler).not.toHaveBeenCalled(); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_metadata')).toEqual({ editors: 'editors', templates: 'templates', }); }); }); describe('getSkills()', () => { test('should call error callback with a bad item error when no id', () => { ErrorUtil.getBadItemError = jest.fn().mockReturnValueOnce('error'); const successCallback = jest.fn(); const errorCallback = jest.fn(); metadata.getSkills({}, successCallback, errorCallback); expect(errorCallback).toBeCalledWith('error', ERROR_CODE_FETCH_SKILLS); expect(successCallback).not.toBeCalled(); expect(ErrorUtil.getBadItemError).toBeCalled(); }); test('should not make request but get skills from cache and call success handler', async () => { const success = jest.fn(); const error = jest.fn(); const file = { id: 'id', permissions: { can_upload: true, }, metadata: { global: { boxSkillsCards: { cards: [], }, }, }, }; const cache = new Cache(); cache.set('cache_id_skills', ['card1', 'card2']); metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('url'); metadata.xhr.get = jest.fn().mockReturnValueOnce({ data: { cards: 'cards' } }); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getCacheKey = jest.fn().mockReturnValueOnce('cache_id'); metadata.getSkillsCacheKey = jest.fn().mockReturnValueOnce('cache_id_skills'); metadata.successHandler = jest.fn(); metadata.errorHandler = jest.fn(); await metadata.getSkills(file, success, error); expect(metadata.successCallback).toBe(success); expect(metadata.errorCallback).toBe(error); expect(metadata.getMetadataUrl).not.toHaveBeenCalled(); expect(metadata.xhr.get).not.toHaveBeenCalled(); expect(metadata.isDestroyed).not.toHaveBeenCalled(); expect(metadata.getSkillsCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.successHandler).toHaveBeenCalledWith(['card1', 'card2']); expect(metadata.errorHandler).not.toHaveBeenCalled(); }); test('should not make request but get skills from file and call success handler and ignore cache', async () => { const success = jest.fn(); const error = jest.fn(); const file = { id: 'id', permissions: { can_upload: true, }, metadata: { global: { boxSkillsCards: { cards: ['card3', 'card4'], }, }, }, }; const cache = new Cache(); cache.set('cache_id_skills', ['card1', 'card2']); metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('url'); metadata.xhr.get = jest.fn().mockReturnValueOnce({ data: { cards: 'cards' } }); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getCacheKey = jest.fn().mockReturnValueOnce('cache_id'); metadata.getSkillsCacheKey = jest.fn().mockReturnValueOnce('cache_id_skills'); metadata.successHandler = jest.fn(); metadata.errorHandler = jest.fn(); await metadata.getSkills(file, success, error, true); expect(metadata.successCallback).toBe(success); expect(metadata.errorCallback).toBe(error); expect(metadata.getMetadataUrl).not.toHaveBeenCalled(); expect(metadata.xhr.get).not.toHaveBeenCalled(); expect(metadata.isDestroyed).toHaveBeenCalled(); expect(metadata.getSkillsCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.successHandler).toHaveBeenCalledWith(['card3', 'card4']); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_skills')).toEqual(['card3', 'card4']); }); test('should make request and update cache and success handler', async () => { const success = jest.fn(); const error = jest.fn(); const file = { id: 'id', permissions: { can_upload: true, }, }; const cache = new Cache(); cache.set('cache_id_skills', ['card1', 'card2']); metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('url'); metadata.xhr.get = jest.fn().mockReturnValueOnce({ data: { cards: ['card3', 'card4'] } }); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getSkillsCacheKey = jest.fn().mockReturnValueOnce('cache_id_skills'); metadata.successHandler = jest.fn(); metadata.errorHandler = jest.fn(); await metadata.getSkills(file, success, error, true); expect(metadata.successCallback).toBe(success); expect(metadata.errorCallback).toBe(error); expect(metadata.getMetadataUrl).toHaveBeenCalledWith(file.id, 'global', 'boxSkillsCards'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'url', id: 'file_id', }); expect(metadata.isDestroyed).toHaveBeenCalled(); expect(metadata.getCache).toHaveBeenCalled(); expect(metadata.getSkillsCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.successHandler).toHaveBeenCalledWith(['card3', 'card4']); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_skills')).toEqual(['card3', 'card4']); }); test('should make request but update cache or call success handler when destroyed', async () => { const success = jest.fn(); const error = jest.fn(); const file = { id: 'id', permissions: { can_upload: true, }, }; const cache = new Cache(); cache.set('cache_id_skills', ['card1', 'card2']); metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('url'); metadata.xhr.get = jest.fn().mockReturnValueOnce({ data: { cards: ['card3', 'card4'] } }); metadata.isDestroyed = jest.fn().mockReturnValueOnce(true); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getSkillsCacheKey = jest.fn().mockReturnValueOnce('cache_id_skills'); metadata.successHandler = jest.fn(); metadata.errorHandler = jest.fn(); await metadata.getSkills(file, success, error, true); expect(metadata.successCallback).toBe(success); expect(metadata.errorCallback).toBe(error); expect(metadata.getMetadataUrl).toHaveBeenCalledWith(file.id, 'global', 'boxSkillsCards'); expect(metadata.xhr.get).toHaveBeenCalledWith({ url: 'url', id: 'file_id', }); expect(metadata.isDestroyed).toHaveBeenCalled(); expect(metadata.getSkillsCacheKey).toHaveBeenCalledWith(file.id); expect(metadata.successHandler).not.toHaveBeenCalled(); expect(metadata.errorHandler).not.toHaveBeenCalled(); expect(cache.get('cache_id_skills')).toBeUndefined(); }); test('should make request and call error handler for error', async () => { const success = jest.fn(); const error = jest.fn(); const file = { id: 'id', permissions: { can_upload: true, }, }; const cache = new Cache(); cache.set('cache_id_skills', ['card1', 'card2']); const xhrError = new Error('error'); metadata.getMetadataUrl = jest.fn().mockReturnValueOnce('url'); metadata.xhr.get = jest.fn().mockReturnValueOnce(Promise.reject(xhrError)); metadata.isDestroyed = jest.fn().mockReturnValueOnce(false); metadata.getCache = jest.fn().mockReturnValueOnce(cache); metadata.getSkillsCacheKey = jest.fn().mockReturnValueOnce('cache_id_skills'); metadata.successHandler = jest.fn(); metadata.errorHandler = jest.fn(); await metadata.getSkills(file, success, error, true); expect(metadata.successCallback).toBe(success); expect(metadata.errorCallback).toBe(error); expect(metadata.getMetadataUrl).toHaveBeenCalledWith(file.id, 'global', 'boxSkil