Create tests for savedobject.js in prep of refactoring and changes (#9127)

* Create tests for savedobject.js in prep of refactoring and changes

* Address code review comments

* Remove needless injector param, replace with es
This commit is contained in:
Stacey Gammon 2016-11-28 09:40:06 -05:00 committed by GitHub
parent 6d271b04bf
commit 469a211483
4 changed files with 389 additions and 10 deletions

View file

@ -0,0 +1,17 @@
import MapperService from 'ui/index_patterns/_mapper';
import stubbedLogstashFields from 'fixtures/logstash_fields';
import sinon from 'auto-release-sinon';
export function stubMapper(Private, mockLogstashFields = Private(stubbedLogstashFields)) {
let stubbedMapper = Private(MapperService);
sinon.stub(stubbedMapper, 'getFieldsForIndexPattern', function () {
return Promise.resolve(mockLogstashFields.filter(field => field.scripted === false));
});
sinon.stub(stubbedMapper, 'clearCache', function () {
return Promise.resolve();
});
return stubbedMapper;
}

View file

@ -0,0 +1,364 @@
/**
* Tests functionality in ui/public/courier/saved_object/saved_object.js
*/
import ngMock from 'ng_mock';
import expect from 'expect.js';
import sinon from 'auto-release-sinon';
import BluebirdPromise from 'bluebird';
import SavedObjectFactory from '../saved_object/saved_object';
import { stubMapper } from 'test_utils/stub_mapper';
import IndexPatternFactory from 'ui/index_patterns/_index_pattern';
describe('Saved Object', function () {
require('test_utils/no_digest_promises').activateForSuite();
let SavedObject;
let IndexPattern;
let esStub;
/**
* Some default es stubbing to avoid timeouts and allow a default type of 'dashboard'.
*/
function mockEsService() {
// Allows the type 'dashboard' to be used.
// Unfortunately we need to use bluebird here instead of native promises because there is
// a call to finally.
sinon.stub(esStub.indices, 'getFieldMapping').returns(BluebirdPromise.resolve({
'.kibana' : {
'mappings': {
'dashboard': {}
}
}
}));
// Necessary to avoid a timeout condition.
sinon.stub(esStub.indices, 'putMapping').returns(BluebirdPromise.resolve());
}
/**
* Returns a fake doc response with the given index and id, of type dashboard
* that can be used to stub es calls.
* @param indexPatternId
* @param additionalOptions - object that will be assigned to the mocked doc response.
* @returns {{_source: {}, _index: *, _type: string, _id: *, found: boolean}}
*/
function getMockedDocResponse(indexPatternId, additionalOptions = {}) {
return Object.assign(
{
_source: {},
_index: indexPatternId,
_type: 'dashboard',
_id: indexPatternId,
found: true
},
additionalOptions);
}
/**
* Stubs some of the es retrieval calls so it returns the given response.
* @param {Object} mockDocResponse
*/
function stubESResponse(mockDocResponse) {
sinon.stub(esStub, 'mget').returns(BluebirdPromise.resolve({ docs: [mockDocResponse] }));
sinon.stub(esStub, 'index').returns(BluebirdPromise.resolve(mockDocResponse));
}
/**
* Creates a new saved object with the given configuration and initializes it.
* Returns the promise that will be completed when the initialization finishes.
*
* @param {Object} config
* @returns {Promise<SavedObject>} A promise that resolves with an instance of
* SavedObject
*/
function createInitializedSavedObject(config = {}) {
let savedObject = new SavedObject(config);
return savedObject.init();
}
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (es, Private) {
SavedObject = Private(SavedObjectFactory);
IndexPattern = Private(IndexPatternFactory);
esStub = es;
mockEsService();
stubMapper(Private);
}));
describe('applyESResp', function () {
it('throws error if not found', function () {
return createInitializedSavedObject({ type: 'dashboard' }).then(savedObject => {
const response = {found: false};
try {
savedObject.applyESResp(response);
expect(true).to.be(false);
} catch (err) {
expect(!!err).to.be(true);
}
});
});
it('preserves original defaults if not overridden', function () {
const id = 'anid';
const preserveMeValue = 'here to stay!';
const config = {
defaults: {
preserveMe: preserveMeValue
},
type: 'dashboard',
id: id
};
const mockDocResponse = getMockedDocResponse(id);
stubESResponse(mockDocResponse);
const savedObject = new SavedObject(config);
return savedObject.init()
.then(() => {
expect(savedObject._source.preserveMe).to.equal(preserveMeValue);
const response = {found: true, _source: {}};
return savedObject.applyESResp(response);
}).then(() => {
expect(savedObject._source.preserveMe).to.equal(preserveMeValue);
});
});
it('overrides defaults', function () {
const id = 'anid';
const config = {
defaults: {
flower: 'rose'
},
type: 'dashboard',
id: id
};
const mockDocResponse = getMockedDocResponse(id);
stubESResponse(mockDocResponse);
const savedObject = new SavedObject(config);
return savedObject.init()
.then(() => {
expect(savedObject._source.flower).to.equal('rose');
const response = {
found: true,
_source: {
flower: 'orchid'
}
};
return savedObject.applyESResp(response);
}).then(() => {
expect(savedObject._source.flower).to.equal('orchid');
});
});
it('overrides previous _source and default values', function () {
const id = 'anid';
const config = {
defaults: {
dinosaurs: {
tRex: 'is the scariest'
}
},
type: 'dashboard',
id: id
};
const mockDocResponse = getMockedDocResponse(
id,
{ _source: { dinosaurs: { tRex: 'is not so bad'}, } });
stubESResponse(mockDocResponse);
let savedObject = new SavedObject(config);
return savedObject.init()
.then(() => {
const response = {
found: true,
_source: { dinosaurs: { tRex: 'has big teeth' } }
};
return savedObject.applyESResp(response);
})
.then(() => {
expect(savedObject._source.dinosaurs.tRex).to.equal('has big teeth');
});
});
});
describe ('config', function () {
it('afterESResp is called', function () {
const afterESRespCallback = sinon.spy();
const config = {
type: 'dashboard',
afterESResp: afterESRespCallback
};
return createInitializedSavedObject(config).then(() => {
expect(afterESRespCallback.called).to.be(true);
});
});
it('init is called', function () {
const initCallback = sinon.spy();
const config = {
type: 'dashboard',
init: initCallback
};
return createInitializedSavedObject(config).then(() => {
expect(initCallback.called).to.be(true);
});
});
describe('searchSource', function () {
it('when true, creates index', function () {
const indexPatternId = 'testIndexPattern';
const afterESRespCallback = sinon.spy();
const config = {
type: 'dashboard',
afterESResp: afterESRespCallback,
searchSource: true,
indexPattern: indexPatternId
};
stubESResponse(getMockedDocResponse(indexPatternId));
const savedObject = new SavedObject(config);
expect(!!savedObject.searchSource.get('index')).to.be(false);
return savedObject.init().then(() => {
expect(afterESRespCallback.called).to.be(true);
const index = savedObject.searchSource.get('index');
expect(index instanceof IndexPattern).to.be(true);
expect(index.id).to.equal(indexPatternId);
});
});
it('when false, does not create index', function () {
const indexPatternId = 'testIndexPattern';
const afterESRespCallback = sinon.spy();
const config = {
type: 'dashboard',
afterESResp: afterESRespCallback,
searchSource: false,
indexPattern: indexPatternId
};
stubESResponse(getMockedDocResponse(indexPatternId));
const savedObject = new SavedObject(config);
expect(!!savedObject.searchSource).to.be(false);
return savedObject.init().then(() => {
expect(afterESRespCallback.called).to.be(true);
expect(!!savedObject.searchSource).to.be(false);
});
});
});
describe('type', function () {
it('that is not specified throws an error', function () {
const config = {};
const savedObject = new SavedObject(config);
try {
savedObject.init();
expect(false).to.be(true);
} catch (err) {
expect(err).to.not.be(null);
}
});
it('that is invalid invalid throws an error', function () {
const config = { type: 'notypeexists' };
const savedObject = new SavedObject(config);
try {
savedObject.init();
expect(false).to.be(true);
} catch (err) {
expect(err).to.not.be(null);
}
});
it('that is valid passes', function () {
const config = { type: 'dashboard' };
return new SavedObject(config).init();
});
});
describe('defaults', function () {
function getTestDefaultConfig(extraOptions) {
return Object.assign({
defaults: { testDefault: 'hi' },
type: 'dashboard'
}, extraOptions);
}
function expectDefaultApplied(config) {
return createInitializedSavedObject(config).then((savedObject) => {
expect(savedObject.defaults).to.be(config.defaults);
});
}
describe('applied to object when id', function () {
it('is not specified', function () {
expectDefaultApplied(getTestDefaultConfig());
});
it('is undefined', function () {
expectDefaultApplied(getTestDefaultConfig({ id: undefined }));
});
it('is 0', function () {
expectDefaultApplied(getTestDefaultConfig({ id: 0 }));
});
it('is false', function () {
expectDefaultApplied(getTestDefaultConfig({ id: false }));
});
});
it('applied to source if an id is given', function () {
const myId = 'myid';
const customDefault = 'hi';
const initialOverwriteMeValue = 'this should get overwritten by the server response';
const config = {
defaults: {
overwriteMe: initialOverwriteMeValue,
customDefault: customDefault
},
type: 'dashboard',
id: myId
};
const serverValue = 'this should override the initial default value given';
const mockDocResponse = getMockedDocResponse(
myId,
{ _source: { overwriteMe: serverValue } });
stubESResponse(mockDocResponse);
return createInitializedSavedObject(config).then((savedObject) => {
expect(!!savedObject._source).to.be(true);
expect(savedObject.defaults).to.be(config.defaults);
expect(savedObject._source.overwriteMe).to.be(serverValue);
expect(savedObject._source.customDefault).to.be(customDefault);
});
});
});
});
});

View file

@ -8,11 +8,11 @@ import IndexedArray from 'ui/indexed_array';
import FixturesLogstashFieldsProvider from 'fixtures/logstash_fields';
import FixturesStubbedDocSourceResponseProvider from 'fixtures/stubbed_doc_source_response';
import DocSourceProvider from 'ui/courier/data_source/doc_source';
import IndexPatternsMapperProvider from 'ui/index_patterns/_mapper';
import UtilsMappingSetupProvider from 'ui/utils/mapping_setup';
import IndexPatternsIntervalsProvider from 'ui/index_patterns/_intervals';
import IndexPatternsIndexPatternProvider from 'ui/index_patterns/_index_pattern';
import NoDigestPromises from 'test_utils/no_digest_promises';
import { stubMapper } from 'test_utils/stub_mapper';
describe('index pattern', function () {
NoDigestPromises.activateForSuite();
@ -40,15 +40,7 @@ describe('index pattern', function () {
DocSource = Private(DocSourceProvider);
sinon.stub(DocSource.prototype, 'doIndex');
sinon.stub(DocSource.prototype, 'fetch');
// stub mapper
mapper = Private(IndexPatternsMapperProvider);
sinon.stub(mapper, 'getFieldsForIndexPattern', function () {
return Promise.resolve(_.filter(mockLogstashFields, { scripted: false }));
});
sinon.stub(mapper, 'clearCache', function () {
return Promise.resolve();
});
mapper = stubMapper(Private, mockLogstashFields);
// stub mappingSetup
mappingSetup = Private(UtilsMappingSetupProvider);

View file

@ -22,6 +22,12 @@ describe('Promise service', function () {
});
});
it('Promise.resolve', function (done) {
Promise.resolve(true).then(() => { done(); });
// Ugly, but necessary for promises to resolve: https://github.com/angular/angular.js/issues/12555
$rootScope.$apply();
});
describe('Promise.fromNode', function () {
it('creates a callback that controls a promise', function () {
let callback;