Initial commit
This commit is contained in:
@@ -0,0 +1,438 @@
|
||||
var Backbone = require('backbone');
|
||||
var _ = require('underscore');
|
||||
var carto = require('../../../../../src/api/v4/index');
|
||||
var createEngine = require('../../../fixtures/engine.fixture.js');
|
||||
|
||||
function createInternalModelMock () {
|
||||
var internalModelMock = {
|
||||
set: function () {},
|
||||
get: function () {}
|
||||
};
|
||||
spyOn(internalModelMock, 'set');
|
||||
spyOn(internalModelMock, 'get').and.callFake(function (key) {
|
||||
switch (key) {
|
||||
case 'count': return 42;
|
||||
case 'max': return 9;
|
||||
case 'min': return 1;
|
||||
case 'nulls': return 0;
|
||||
case 'data': return [
|
||||
{
|
||||
name: 'cat1',
|
||||
value: 1,
|
||||
agg: false
|
||||
},
|
||||
{
|
||||
name: 'others',
|
||||
value: 9,
|
||||
agg: true
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
_.extend(internalModelMock, Backbone.Events);
|
||||
|
||||
return internalModelMock;
|
||||
}
|
||||
|
||||
function createSourceMock () {
|
||||
return new carto.source.Dataset('foo');
|
||||
}
|
||||
|
||||
describe('api/v4/dataview/category', function () {
|
||||
var source = createSourceMock();
|
||||
|
||||
describe('initialization', function () {
|
||||
it('source must be provided', function () {
|
||||
var error;
|
||||
try { new carto.dataview.Category(); } catch (err) { error = err; } // eslint-disable-line no-new
|
||||
|
||||
expect(error).toEqual(jasmine.objectContaining({
|
||||
message: 'Source property is required.',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:source-required'
|
||||
}));
|
||||
});
|
||||
|
||||
it('column must be provided', function () {
|
||||
var error;
|
||||
try { new carto.dataview.Category(source); } catch (err) { error = err; } // eslint-disable-line no-new
|
||||
|
||||
expect(error).toEqual(jasmine.objectContaining({
|
||||
message: 'Column property is required.',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:column-required'
|
||||
}));
|
||||
});
|
||||
|
||||
it('options set to default if not provided', function () {
|
||||
var column = 'population';
|
||||
|
||||
var dataview = new carto.dataview.Category(source, column);
|
||||
|
||||
expect(dataview._limit).toEqual(6);
|
||||
expect(dataview._operation).toEqual(carto.operation.COUNT);
|
||||
expect(dataview._operationColumn).toEqual('population');
|
||||
});
|
||||
|
||||
it('options set to the provided value', function () {
|
||||
var dataview = new carto.dataview.Category(source, 'population', {
|
||||
limit: 10,
|
||||
operation: carto.operation.AVG,
|
||||
operationColumn: 'column-test'
|
||||
});
|
||||
|
||||
expect(dataview._limit).toEqual(10);
|
||||
expect(dataview._operation).toEqual(carto.operation.AVG);
|
||||
expect(dataview._operationColumn).toEqual('column-test');
|
||||
});
|
||||
|
||||
it('throw error if no correct operation is provided', function () {
|
||||
var error;
|
||||
var test = function () {
|
||||
new carto.dataview.Category(source, 'population', { // eslint-disable-line no-new
|
||||
operation: 'exponential'
|
||||
});
|
||||
};
|
||||
|
||||
try { test(); } catch (err) { error = err; }
|
||||
|
||||
expect(error).toEqual(jasmine.objectContaining({
|
||||
message: 'Operation for category dataview is not valid. Use carto.operation',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:category-invalid-operation'
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setLimit', function () {
|
||||
var dataview;
|
||||
|
||||
beforeEach(function () {
|
||||
dataview = new carto.dataview.Category(source, 'population');
|
||||
});
|
||||
|
||||
it('checks if limit is valid', function () {
|
||||
var requiredError;
|
||||
var numberError;
|
||||
var positiveError;
|
||||
|
||||
try { dataview.setLimit(); } catch (err) { requiredError = err; }
|
||||
try { dataview.setLimit('12'); } catch (err) { numberError = err; }
|
||||
try { dataview.setLimit(0); } catch (err) { positiveError = err; }
|
||||
|
||||
expect(requiredError).toEqual(jasmine.objectContaining({
|
||||
message: 'Limit for category dataview is required.',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:category-limit-required'
|
||||
}));
|
||||
expect(numberError).toEqual(jasmine.objectContaining({
|
||||
message: 'Limit for category dataview must be a number.',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:category-limit-number'
|
||||
}));
|
||||
expect(positiveError).toEqual(jasmine.objectContaining({
|
||||
message: 'Limit for category dataview must be greater than 0.',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:category-limit-positive'
|
||||
}));
|
||||
});
|
||||
|
||||
it('if limit is valid, it assigns it to property, returns this and nothing else if there is no internaModel', function () {
|
||||
var returnedObject = dataview.setLimit(10);
|
||||
|
||||
expect(dataview.getLimit()).toEqual(10);
|
||||
expect(returnedObject).toBe(dataview);
|
||||
});
|
||||
|
||||
it('sets limit in internal model if exists', function () {
|
||||
var internalModelMock = createInternalModelMock();
|
||||
dataview._internalModel = internalModelMock;
|
||||
|
||||
dataview.setLimit(1);
|
||||
|
||||
var operationArgs = internalModelMock.set.calls.mostRecent().args;
|
||||
expect(operationArgs[0]).toEqual('categories');
|
||||
expect(operationArgs[1]).toEqual(1);
|
||||
});
|
||||
|
||||
it('should trigger a limitChanged event', function () {
|
||||
var limitChangedSpy = jasmine.createSpy('operationaChangedSpy');
|
||||
dataview.on('limitChanged', limitChangedSpy);
|
||||
|
||||
expect(limitChangedSpy).not.toHaveBeenCalled();
|
||||
dataview.$setEngine(createEngine());
|
||||
dataview.setLimit(7);
|
||||
|
||||
expect(limitChangedSpy).toHaveBeenCalledWith(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setOperation', function () {
|
||||
var dataview;
|
||||
|
||||
beforeEach(function () {
|
||||
dataview = new carto.dataview.Category(source, 'population');
|
||||
});
|
||||
|
||||
it('checks if operation is valid', function () {
|
||||
var error;
|
||||
var test = function () {
|
||||
dataview.setOperation('swordfish');
|
||||
};
|
||||
|
||||
try { test(); } catch (err) { error = err; }
|
||||
|
||||
expect(error).toEqual(jasmine.objectContaining({
|
||||
message: 'Operation for category dataview is not valid. Use carto.operation',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:category-invalid-operation'
|
||||
}));
|
||||
});
|
||||
|
||||
it('if operation is valid, it assigns it to property, returns this and nothing else if there is no internaModel', function () {
|
||||
var returnedObject = dataview.setOperation(carto.operation.AVG);
|
||||
|
||||
expect(dataview.getOperation()).toEqual(carto.operation.AVG);
|
||||
expect(returnedObject).toBe(dataview);
|
||||
});
|
||||
|
||||
it('sets operation in internal model if exists', function () {
|
||||
var internalModelMock = createInternalModelMock();
|
||||
dataview._internalModel = internalModelMock;
|
||||
|
||||
dataview.setOperation(carto.operation.AVG);
|
||||
|
||||
var operationArgs = internalModelMock.set.calls.mostRecent().args;
|
||||
expect(operationArgs[0]).toEqual('aggregation');
|
||||
expect(operationArgs[1]).toEqual(carto.operation.AVG);
|
||||
});
|
||||
|
||||
it('should trigger a operationChanged event', function () {
|
||||
var operationChangedSpy = jasmine.createSpy('operationaChangedSpy');
|
||||
dataview.on('operationChanged', operationChangedSpy);
|
||||
|
||||
expect(operationChangedSpy).not.toHaveBeenCalled();
|
||||
dataview.$setEngine(createEngine());
|
||||
dataview.setOperation(carto.operation.AVG);
|
||||
|
||||
expect(operationChangedSpy).toHaveBeenCalledWith(carto.operation.AVG);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setOperationColumn', function () {
|
||||
var dataview;
|
||||
|
||||
beforeEach(function () {
|
||||
dataview = new carto.dataview.Category(source, 'population');
|
||||
});
|
||||
|
||||
it('checks if operation is valid', function () {
|
||||
var requiredError;
|
||||
var numberError;
|
||||
var emptyError;
|
||||
|
||||
try { dataview.setOperationColumn(); } catch (err) { requiredError = err; }
|
||||
try { dataview.setOperationColumn(12); } catch (err) { numberError = err; }
|
||||
try { dataview.setOperationColumn(''); } catch (err) { emptyError = err; }
|
||||
|
||||
expect(requiredError).toEqual(jasmine.objectContaining({
|
||||
message: 'Operation column for category dataview is required.',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:category-operation-required'
|
||||
}));
|
||||
expect(numberError).toEqual(jasmine.objectContaining({
|
||||
message: 'Operation column for category dataview must be a string.',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:category-operation-string'
|
||||
}));
|
||||
expect(emptyError).toEqual(jasmine.objectContaining({
|
||||
message: 'Operation column for category dataview must be not empty.',
|
||||
type: 'dataview',
|
||||
errorCode: 'validation:dataview:category-operation-empty'
|
||||
}));
|
||||
});
|
||||
|
||||
it('if operation is valid, it assigns it to property, returns this and nothing else if there is no internaModel', function () {
|
||||
var returnedObject = dataview.setOperationColumn('columnA');
|
||||
|
||||
expect(dataview.getOperationColumn()).toEqual('columnA');
|
||||
expect(returnedObject).toBe(dataview);
|
||||
});
|
||||
|
||||
it('sets operation in internal model if exists', function () {
|
||||
var internalModelMock = createInternalModelMock();
|
||||
dataview._internalModel = internalModelMock;
|
||||
|
||||
dataview.setOperationColumn('columnB');
|
||||
|
||||
var operationArgs = internalModelMock.set.calls.mostRecent().args;
|
||||
expect(operationArgs[0]).toEqual('aggregation_column');
|
||||
expect(operationArgs[1]).toEqual('columnB');
|
||||
});
|
||||
|
||||
it('should trigger a operationColumnChanged event', function () {
|
||||
var operationColumnChangedSpy = jasmine.createSpy('operationaChangedSpy');
|
||||
dataview.on('operationColumnChanged', operationColumnChangedSpy);
|
||||
|
||||
expect(operationColumnChangedSpy).not.toHaveBeenCalled();
|
||||
dataview.$setEngine(createEngine());
|
||||
dataview.setOperationColumn('column2');
|
||||
|
||||
expect(operationColumnChangedSpy).toHaveBeenCalledWith('column2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getData', function () {
|
||||
var dataview;
|
||||
|
||||
beforeEach(function () {
|
||||
dataview = new carto.dataview.Category(source, 'population', {
|
||||
operation: carto.operation.SUM,
|
||||
operationColumn: 'column-test'
|
||||
});
|
||||
});
|
||||
|
||||
it('returns null if there is no internalModel', function () {
|
||||
var data = dataview.getData();
|
||||
|
||||
expect(data).toBeNull();
|
||||
});
|
||||
|
||||
it('returns data from internalModel', function () {
|
||||
var internalModelMock = createInternalModelMock();
|
||||
dataview._internalModel = internalModelMock;
|
||||
|
||||
var data = dataview.getData();
|
||||
|
||||
expect(data).toEqual({
|
||||
count: 42,
|
||||
max: 9,
|
||||
min: 1,
|
||||
nulls: 0,
|
||||
operation: carto.operation.SUM,
|
||||
categories: [
|
||||
{
|
||||
name: 'cat1',
|
||||
value: 1,
|
||||
group: false
|
||||
},
|
||||
{
|
||||
name: 'others',
|
||||
value: 9,
|
||||
group: true
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.$setEngine', function () {
|
||||
var engine;
|
||||
var dataview;
|
||||
|
||||
beforeEach(function () {
|
||||
dataview = new carto.dataview.Category(source, 'population', {
|
||||
operation: carto.operation.MIN,
|
||||
operationColumn: 'column-test'
|
||||
});
|
||||
engine = createEngine();
|
||||
});
|
||||
|
||||
it('creates the internal model', function () {
|
||||
dataview.disable(); // To test that it passes the ._enabled property to the internal model
|
||||
dataview.$setEngine(engine);
|
||||
|
||||
var internalModel = dataview.$getInternalModel();
|
||||
expect(internalModel.get('source')).toBe(dataview._source.$getInternalModel());
|
||||
expect(internalModel.get('column')).toEqual(dataview._column);
|
||||
expect(internalModel.get('categories')).toEqual(dataview._limit);
|
||||
expect(internalModel.get('aggregation')).toEqual(dataview._operation);
|
||||
expect(internalModel.get('aggregation_column')).toEqual(dataview._operationColumn);
|
||||
expect(internalModel.isEnabled()).toBe(false);
|
||||
expect(internalModel._engine).toBe(engine);
|
||||
});
|
||||
|
||||
it('calling twice to $setEngine does not create another internalModel', function () {
|
||||
spyOn(dataview, '_createInternalModel').and.callThrough();
|
||||
|
||||
dataview.$setEngine(engine);
|
||||
dataview.$setEngine(engine);
|
||||
|
||||
expect(dataview._createInternalModel.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
describe('spatial filters', function () {
|
||||
it('creates the internal model with BoundingBox filter if provided', function () {
|
||||
var filter = new carto.filter.BoundingBox();
|
||||
dataview.addFilter(filter);
|
||||
dataview.$setEngine(engine);
|
||||
|
||||
var internalModel = dataview.$getInternalModel();
|
||||
expect(internalModel._bboxFilter).toBeDefined();
|
||||
expect(internalModel.syncsOnBoundingBoxChanges()).toBe(true);
|
||||
});
|
||||
|
||||
it('allows removing a BoundingBox filter', function () {
|
||||
var filter = new carto.filter.BoundingBox();
|
||||
dataview.addFilter(filter);
|
||||
dataview.$setEngine(engine);
|
||||
expect(dataview.hasFilter(filter)).toBe(true);
|
||||
|
||||
dataview.removeFilter(filter);
|
||||
|
||||
expect(dataview.hasFilter(filter)).toBe(false);
|
||||
var internalModel = dataview.$getInternalModel();
|
||||
expect(internalModel._bboxFilter).toBeNull();
|
||||
expect(internalModel.syncsOnBoundingBoxChanges()).toBe(false);
|
||||
});
|
||||
|
||||
it('creates the internal model with Circle filter if provided', function () {
|
||||
var filter = new carto.filter.Circle();
|
||||
dataview.addFilter(filter);
|
||||
dataview.$setEngine(engine);
|
||||
|
||||
var internalModel = dataview.$getInternalModel();
|
||||
expect(internalModel._circleFilter).toBeDefined();
|
||||
expect(internalModel.syncsOnCircleChanges()).toBe(true);
|
||||
});
|
||||
|
||||
it('allows removing a Circle filter', function () {
|
||||
var filter = new carto.filter.Circle();
|
||||
dataview.addFilter(filter);
|
||||
dataview.$setEngine(engine);
|
||||
expect(dataview.hasFilter(filter)).toBe(true);
|
||||
|
||||
dataview.removeFilter(filter);
|
||||
|
||||
expect(dataview.hasFilter(filter)).toBe(false);
|
||||
var internalModel = dataview.$getInternalModel();
|
||||
expect(internalModel._circleFilter).toBeNull();
|
||||
expect(internalModel.syncsOnCircleChanges()).toBe(false);
|
||||
});
|
||||
|
||||
it('creates the internal model with Polygon filter if provided', function () {
|
||||
var filter = new carto.filter.Polygon();
|
||||
dataview.addFilter(filter);
|
||||
dataview.$setEngine(engine);
|
||||
|
||||
var internalModel = dataview.$getInternalModel();
|
||||
expect(internalModel._polygonFilter).toBeDefined();
|
||||
expect(internalModel.syncsOnPolygonChanges()).toBe(true);
|
||||
});
|
||||
|
||||
it('allows removing a Polygon filter', function () {
|
||||
var filter = new carto.filter.Polygon();
|
||||
dataview.addFilter(filter);
|
||||
dataview.$setEngine(engine);
|
||||
expect(dataview.hasFilter(filter)).toBe(true);
|
||||
|
||||
dataview.removeFilter(filter);
|
||||
|
||||
expect(dataview.hasFilter(filter)).toBe(false);
|
||||
var internalModel = dataview.$getInternalModel();
|
||||
expect(internalModel._polygonFilter).toBeNull();
|
||||
expect(internalModel.syncsOnPolygonChanges()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user