carto.js/test/spec/windshaft/client.spec.js
2020-06-13 18:34:34 +08:00

293 lines
10 KiB
JavaScript

var $ = require('jquery');
var _ = require('underscore');
var util = require('cdb.core.util');
var WindshaftClient = require('../../../src/windshaft/client');
var Request = require('../../../src/windshaft/request');
var LZMA = require('../../../vendor/lzma');
describe('windshaft/client', function () {
describe('instantiateMap', function () {
var ajaxSpy;
function getRecentCall () {
const args = ajaxSpy.calls.mostRecent().args[0];
const url = args.url;
return {
url,
method: args.method,
path: url.split('?')[0],
params: url.split('?')[1].split('&'),
dataType: args.dataType,
contentType: args.contentType,
jsonpCallback: args.jsonpCallback,
cache: args.cache,
crossOrigin: args.crossOrigin,
success: args.success,
error: args.error
};
}
beforeEach(function () {
ajaxSpy = spyOn($, 'ajax');
spyOn(util, 'uniqueCallbackName').and.callFake(function () { return 'callbackName'; });
this.client = new WindshaftClient({
urlTemplate: 'https://{user}.carto.com:443',
userName: 'cartojs-test'
});
});
it('should trigger a GET request to instantiate a map', function () {
var request = new Request({ some: 'json that must be encoded' }, {}, {});
this.client.instantiateMap(request);
const { path, method, dataType, jsonpCallback, cache } = getRecentCall();
expect(path).toEqual('https://cartojs-test.carto.com:443/api/v1/map');
expect(method).toEqual('GET');
expect(dataType).toEqual('jsonp');
expect(jsonpCallback).toMatch('_cdbc_callbackName');
expect(cache).toEqual(true);
});
it('should use the endpoint for named maps', function () {
var request = new Request({ some: 'json that must be encoded' }, {}, {});
this.client = new WindshaftClient({
urlTemplate: 'https://{user}.carto.com:443',
userName: 'cartojs-test',
templateName: 'tpl123456789'
});
this.client.instantiateMap(request);
const { path } = getRecentCall();
expect(path).toEqual('https://cartojs-test.carto.com:443/api/v1/map/named/tpl123456789/jsonp');
});
it('should include the given params and handle JSON objects correctly', function () {
var request = new Request({ some: 'json that must be encoded' }, {
client: 'client_version',
filters: { some: 'filters that will be applied' }
}, {});
this.client.instantiateMap(request);
const { path, params, method, dataType, jsonpCallback, cache } = getRecentCall();
expect(path).toEqual('https://cartojs-test.carto.com:443/api/v1/map');
expect(params[0]).toEqual('config=%7B%22some%22%3A%22json%20that%20must%20be%20encoded%22%7D');
expect(params[1]).toEqual('client=client_version');
expect(params[2]).toEqual('filters=%7B%22some%22%3A%22filters%20that%20will%20be%20applied%22%7D');
expect(method).toEqual('GET');
expect(dataType).toEqual('jsonp');
expect(jsonpCallback).toMatch('_cdbc_callbackName');
expect(cache).toEqual(true);
});
it('should invoke the success callback', function () {
var successCallback = jasmine.createSpy('successCallback');
var request = new Request('mapDefinition', {}, { success: successCallback });
this.client.instantiateMap(request);
const { success } = getRecentCall();
success({ layergroupid: '123456789' });
expect(successCallback).toHaveBeenCalled();
var dasboardInstance = successCallback.calls.mostRecent().args[0];
expect(dasboardInstance).toEqual({ layergroupid: '123456789' });
});
it('should invoke the error callback if Windshaft returns some errors under a success response code', function () {
var errorCallback = jasmine.createSpy('errorCallback');
var request = new Request('mapDefinition', {}, { error: errorCallback });
this.client.instantiateMap(request);
var errors = {
errors: ['the error message'],
errors_with_context: [
{
type: 'unknown',
message: 'the error message'
}
]
};
const { success } = getRecentCall();
success(errors);
var callArgs = errorCallback.calls.mostRecent().args;
expect(callArgs[0][0]).toEqual(jasmine.objectContaining({
message: 'the error message',
origin: 'windshaft'
}));
});
it('should invoke the error callback if ajax request goes wrong. If it is not a windshaft error it returns an empty array', function () {
var errorCallback = jasmine.createSpy('errorCallback');
var request = new Request('mapDefinition', {}, { error: errorCallback });
this.client.instantiateMap(request);
const { error } = getRecentCall();
error({ responseText: JSON.stringify({ something: 'else' }) });
var callArgs = errorCallback.calls.mostRecent().args;
expect(callArgs[0] instanceof Array).toBe(true);
expect(callArgs[0].length).toBe(0);
});
it('should ignore the error callback if request was aborted', function () {
var errorCallback = jasmine.createSpy('errorCallback');
var request = new Request('mapDefinition', {}, { error: errorCallback });
this.client.instantiateMap(request);
$.ajax.calls.argsFor(0)[0].error({ xhr: { responseText: 'something' } }, 'abort');
expect(errorCallback).not.toHaveBeenCalled();
});
describe('request tracking', function () {
var successCallback;
var errorCallback;
var request;
beforeEach(function () {
successCallback = jasmine.createSpy('successCallback');
errorCallback = jasmine.createSpy('errorCallback');
request = new Request('mapDefinition', {}, {
success: successCallback,
error: errorCallback
});
});
it('should make a request only if the request service allows it', function () {
expect($.ajax).not.toHaveBeenCalled();
spyOn(this.client._requestTracker, 'canRequestBePerformed').and.returnValue(true);
this.client.instantiateMap(request);
expect($.ajax).toHaveBeenCalled();
});
it('should not make a request when the request service does not allow it', function () {
expect($.ajax).not.toHaveBeenCalled();
spyOn(this.client._requestTracker, 'canRequestBePerformed').and.returnValue(false);
this.client.instantiateMap(request);
expect($.ajax).not.toHaveBeenCalled();
expect(errorCallback).toHaveBeenCalledWith({});
});
});
xdescribe('HTTP method:', function () {
it('should use GET to URL with encoded config when the payload is small enough', function (done) {
var smallPayload = new Array(1933).join('x');
var request = new Request(smallPayload, { a: 'a sentence' }, {});
this.client.instantiateMap(request);
_.defer(function () {
const { url, method, path, params } = getRecentCall();
expect(url.length).toBeLessThan(2033);
expect(path).toEqual('https://cartojs-test.carto.com:443/api/v1/map');
expect(method).toEqual('GET');
expect(params[0]).toMatch('^config=');
expect(params[0]).not.toMatch('^lzma=');
expect(params[1]).toEqual('a=a%20sentence');
done();
});
});
it('should use GET with compressed payload when payload is too big', function (done) {
var mediumPayload = new Array(2033).join('x');
var request = new Request(mediumPayload, { a: 'a sentence' }, {});
this.client.instantiateMap(request);
_.defer(function () {
const { url, method, path, params } = getRecentCall();
expect(url.length).toBeLessThan(2033);
expect(path).toEqual('https://cartojs-test.carto.com:443/api/v1/map');
expect(method).toEqual('GET');
expect(params[0]).toMatch('^lzma=');
expect(params[0]).not.toMatch('^config=');
expect(params[1]).toEqual('a=a%20sentence');
done();
});
});
it('should use POST when URL even the compressed payload is too big', function (done) {
// simulate a compression that generates something BIG
spyOn(LZMA, 'compress').and.callFake(function (data, level, callback) {
callback(new Array(2500).join('x'));
});
var bigPayload = new Array(2033).join('x');
var request = new Request(bigPayload, { a: 'a sentence' }, {});
this.client.instantiateMap(request);
_.defer(function () {
const { method, path, params, dataType, contentType, crossOrigin } = getRecentCall();
expect(path).toEqual('https://cartojs-test.carto.com:443/api/v1/map');
expect(crossOrigin).toEqual(true);
expect(method).toEqual('POST');
expect(dataType).toEqual('json');
expect(contentType).toEqual('application/json');
expect(params[0]).toEqual('a=a%20sentence');
done();
});
});
});
describe('cancelling previous requests', function () {
beforeEach(function () {
this.fakeXHR = jasmine.createSpyObj('fakeXHR', ['abort']);
$.ajax.and.returnValues(this.fakeXHR, undefined);
});
it('should cancel previous requests when using GET requests', function () {
var errorCallback = jasmine.createSpy('errorCallback');
var request = new Request({ some: 'json that must be encoded' }, {}, { error: errorCallback });
this.client.instantiateMap(request);
expect($.ajax.calls.argsFor(0)[0].method).toEqual('GET');
expect(this.fakeXHR.abort).not.toHaveBeenCalled();
this.client.instantiateMap(request);
expect(this.fakeXHR.abort).toHaveBeenCalled();
expect(errorCallback).not.toHaveBeenCalled();
});
it('should cancel previous requests when using POST requests', function (done) {
// simulate a compression that generates something BIG
spyOn(LZMA, 'compress').and.callFake(function (data, level, callback) {
callback(new Array(2500).join('x'));
});
var request = new Request({ something: new Array(3000).join('x') }, {}, {});
this.client.instantiateMap(request);
_.defer(function () {
expect($.ajax.calls.argsFor(0)[0].method).toEqual('POST');
expect(this.fakeXHR.abort).not.toHaveBeenCalled();
this.client.instantiateMap(request);
expect(this.fakeXHR.abort).toHaveBeenCalled();
done();
}.bind(this));
});
});
});
});