Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -0,0 +1,306 @@
var Backbone = require('backbone');
var AddLayerModel = require('builder/components/modals/add-layer/add-layer-model');
var TableModel = require('builder/data/table-model');
var UserModel = require('builder/data/user-model');
var ConfigModel = require('builder/data/config-model');
var sharedForCreateListingViewModel = require('./shared-for-create-listing-view-model.spec.js');
var sharedForCreateListingImportViewModel = require('./shared-for-import-view-model.spec.js');
var UserActions = require('builder/data/user-actions');
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
describe('components/modals/add-layer/add-layer-model', function () {
beforeEach(function () {
jasmine.Ajax.install();
spyOn(MetricsTracker, 'track');
var configModel = new ConfigModel({
base_url: '/u/pepe'
});
var vizUrl = 'http(s)?://(.)+' + configModel.get('base_url') + '/api/v1/viz.*';
jasmine.Ajax.stubRequest(new RegExp(vizUrl)).andReturn({
status: 200
});
this.pollingModel = new Backbone.Model();
this.userModel = new UserModel({
username: 'pepe'
}, {
configModel: configModel
});
this.userActions = UserActions({
userModel: this.userModel,
analysisDefinitionNodesCollection: {},
analysisDefinitionsCollection: {},
layerDefinitionsCollection: {},
widgetDefinitionsCollection: {}
});
spyOn(this.userActions, 'createLayerFromTable');
this.model = new AddLayerModel(null, {
pollingModel: this.pollingModel,
configModel: configModel,
userModel: this.userModel,
userActions: this.userActions
});
});
afterEach(function () {
jasmine.Ajax.uninstall();
});
sharedForCreateListingViewModel.call(this);
sharedForCreateListingImportViewModel.call(this);
it('should have listing as default content pane', function () {
expect(this.model.get('contentPane')).toEqual('listing');
});
describe('.canFinish', function () {
describe('when listing is import', function () {
beforeEach(function () {
spyOn(this.model._uploadModel, 'isValidToUpload');
this.model.set('listing', 'import');
});
it('should return true only if upload is valid', function () {
expect(this.model.canFinish()).toBeFalsy();
this.model._uploadModel.isValidToUpload = function () { return true; };
expect(this.model.canFinish()).toBeTruthy();
});
});
describe('when listing is datasets', function () {
beforeEach(function () {
this.model.set('listing', 'datasets');
});
it('should return true if there is at least one dataset selected', function () {
expect(this.model.canFinish()).toBeFalsy();
this.model._selectedDatasetsCollection.add({});
expect(this.model.canFinish()).toBeTruthy();
});
});
});
describe('.canSelect', function () {
beforeEach(function () {
this.dataset = new Backbone.Model({
selected: false
});
});
it('should return true only if there is dataset selected or if wanting to deselect', function () {
expect(this.model.canSelect(this.dataset)).toBeTruthy();
this.model._selectedDatasetsCollection.add({ selected: true });
expect(this.model.canSelect(this.dataset)).toBeFalsy();
this.dataset.set('selected', true);
expect(this.model.canSelect(this.dataset)).toBeTruthy();
});
});
describe('.finish', function () {
describe('when an dataset is selected', function () {
describe('when dataset is a remote one (from library)', function () {
beforeEach(function () {
this.pollingModel.bind('importByUploadData', function (data) {
this.importByUploadData = data;
}, this);
this.model._tablesCollection.reset([{
id: 'abc-123',
type: 'remote',
name: 'foobar',
external_source: {
size: 1024
}
}]);
this.model._tablesCollection.at(0).set('selected', true);
this.model.finish();
});
it('should trigger a importByUploadData event', function () {
expect(this.importByUploadData).toBeTruthy();
});
it('should pass a metadata object with necessary data to import dataset', function () {
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ type: 'remote' }));
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ value: 'foobar' }));
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ remote_visualization_id: 'abc-123' }));
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ size: 1024 }));
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ create_vis: false }));
});
});
describe('when dataset is not a remote one', function () {
beforeEach(function () {
this.model.bind('addLayerDone', function () {
this.addLayerDoneCalled = true;
}, this);
this.model._tablesCollection.reset([{
id: 'abc',
type: 'table',
name: 'paco',
table: {
name: 'tableName'
}
}]);
this.model._tablesCollection.at(0).set('selected', true);
this.model.finish();
});
it('should create layer from dataset', function () {
expect(this.userActions.createLayerFromTable).toHaveBeenCalled();
});
it('should create layer with expected params', function () {
var tableModel = this.userActions.createLayerFromTable.calls.argsFor(0)[0];
expect(tableModel.get('name')).toBe('tableName');
});
it('should change the content view setting', function () {
expect(this.model.get('contentPane')).toEqual('addingNewLayer');
});
describe('when adding layer succeeds', function () {
beforeEach(function () {
var createdModel = new Backbone.Model({ id: 'test' });
expect(this.addLayerDoneCalled).toBeFalsy();
this.userActions.createLayerFromTable.calls.argsFor(0)[1].success(createdModel);
});
it('should trigger addLayerDone', function () {
expect(this.addLayerDoneCalled).toBeTruthy();
});
});
describe('when adding layer fails', function () {
beforeEach(function () {
this.userActions.createLayerFromTable.calls.argsFor(0)[1].error({}, {
responseText: '{"error": ["meh"]}'
});
});
it('should change contentPane to addLayerFail', function () {
expect(this.model.get('contentPane')).toEqual('addLayerFailed');
});
});
describe('when table quota exceeded', function () {
beforeEach(function () {
this.userActions.createLayerFromTable.calls.argsFor(0)[1].error({}, {
responseText: '{"errors": ["You have reached your table quota"]}'
});
});
it('should change contentPane to datasetQuotaExceeded', function () {
expect(this.model.get('contentPane')).toEqual('datasetQuotaExceeded');
});
});
});
});
describe('.createFromScratch', function () {
beforeEach(function () {
spyOn(TableModel.prototype, 'save').and.callFake(function () {
this.set('name', 'name-just-for-testing-purposes', { silent: true });
return this;
});
});
it('should change to loading state', function () {
this.model.createFromScratch();
expect(this.model.get('contentPane')).toEqual('creatingFromScratch');
});
it('should save a new dataset table', function () {
this.model.createFromScratch();
expect(TableModel.prototype.save).toHaveBeenCalled();
});
describe('when table is successfully created', function () {
it('should add the table as new layer', function () {
this.model.createFromScratch();
TableModel.prototype.save.calls.argsFor(0)[1].success();
expect(this.userActions.createLayerFromTable).toHaveBeenCalled();
var tableModel = this.userActions.createLayerFromTable.calls.argsFor(0)[0];
expect(tableModel.get('name')).toBe('name-just-for-testing-purposes');
});
});
});
describe('when an upload is set', function () {
beforeEach(function () {
this.pollingModel.bind('importByUploadData', function (d) {
this.importByUploadData = d;
}, this);
this.model.set('listing', 'import');
this.model.finish();
});
it('should call pollingModel importByUploadData with expected data', function () {
expect(this.importByUploadData).toBeTruthy();
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ state: 'idle' }));
});
});
});
describe('when listing', function () {
it('should detect which', function () {
this.model.set('listing', 'import');
expect(this.model._atImportPane()).toBe(true);
this.model.set('listing', 'datasets');
expect(this.model._atImportPane()).toBe(false);
expect(this.model._atDatasetsPane()).toBe(true);
this.model.set('listing', 'scratch');
expect(this.model._atDatasetsPane()).toBe(false);
expect(this.model._atScratchPane()).toBe(true);
});
it('should detect "twitter import pane"', function () {
this.model.set('listing', 'import');
this.model.set('activeImportPane', 'twitter');
expect(this.model._atTwitterImportPane()).toBe(true);
this.model.set('activeImportPane', '*whatever-else*');
expect(this.model._atTwitterImportPane()).toBe(false);
});
describe('and deciding on togglers', function () {
it('should decide to show "guessing toggler" if at import', function () {
this.model.set('listing', 'import');
expect(this.model.showGuessingToggler()).toBe(true);
this.model.set('listing', 'datasets');
expect(this.model.showGuessingToggler()).toBe(false);
});
it('should decide to show "privacy toggler" if at import (unless deprecated twitter)', function () {
this.model.set('listing', 'import');
this.model.set('activeImportPane', '*whatever-but-twitter*');
expect(this.model.showPrivacyToggler()).toBe(true);
this.model.set('activeImportPane', 'twitter');
var spy = spyOn(this.userModel, 'hasOwnTwitterCredentials');
spy.and.returnValue(true);
expect(this.model.showPrivacyToggler()).toBe(true);
spy.and.returnValue(false);
expect(this.model.showPrivacyToggler()).toBe(false);
});
});
});
});
@@ -0,0 +1,60 @@
var $ = require('jquery');
var _ = require('underscore');
var CreditsUsageView = require('builder/components/modals/add-layer/content/imports/import-twitter/credits-usage-view');
var getUserModelFixture = require('fixtures/builder/user-model.fixture.js');
/** Note: More behaviour is tested on its parent view (import-twitter.view.spec.js) */
describe('components/modals/add-layer/content/imports/imports-twitter/credits-usage-view', function () {
beforeEach(function () {
this.userModel = getUserModelFixture();
// extracted from `import-twitter.tpl`
this.tplForView =
'<div class="Form-rowData Form-rowData--longer CreditsUsage">' +
' <div class="UISlider CreditsUsage-slider js-slider"></div>' +
' <div class="CreditsUsage-info CDB-Text CDB-Size-medium js-info"></div>' +
'</div>';
this.createView = function (opts) {
var custom = opts || {};
var defaults = {
userModel: this.userModel,
el: $(this.tplForView)
};
return new CreditsUsageView(_.extend(defaults, custom));
};
this.view = this.createView();
});
it('should be enabled by default', function () {
expect(this.view._disabled).toBe(false);
});
it('can be created disabled or enabled', function () {
var v = this.createView({disabled: true});
expect(v._disabled).toBe(true);
v = this.createView({disabled: false});
expect(v._disabled).toBe(false);
});
describe('render', function () {
beforeEach(function () {
this.view.render();
});
it('should render properly', function () {
expect(this.view.$('.js-slider').length).toBe(1);
expect(this.view.$('.js-info').length).toBe(1);
});
it('can be rendered with a disabled or enabled slider', function () {
expect(this.view._disabled).toBe(false);
expect(this.view.$('.js-slider').slider('option', 'disabled')).toBe(false);
this.view._disabled = true;
this.view.render();
expect(this.view.$('.js-slider').slider('option', 'disabled')).toBe(true);
});
});
});
@@ -0,0 +1,176 @@
var _ = require('underscore');
var ImportTwitterView = require('builder/components/modals/add-layer/content/imports/import-twitter/import-twitter-view');
var getUserModelFixture = require('fixtures/builder/user-model.fixture.js');
var getConfigModelFixture = require('fixtures/builder/config-model.fixture.js');
describe('components/modals/add-layer/content/imports/imports-twitter/import-twitter-view', function () {
beforeEach(function () {
this.userModel = getUserModelFixture();
this.view = new ImportTwitterView({
userModel: this.userModel,
configModel: getConfigModelFixture()
});
this.view.render();
});
describe('render', function () {
it('should be rendered properly', function () {
expect(this.view.$('.ImportTwitterPanel-categories').length).toBe(1);
expect(this.view.$('.ImportTwitterPanel-datePicker').length).toBe(1);
expect(this.view.$('.ImportTwitterPanel-creditsUsage').length).toBe(1);
});
describe('twitter categories', function () {
beforeEach(function () {
this.categories = this.view.categories;
});
it('should render properly', function () {
expect(this.categories.$('.TwitterCategory').length).toBe(1);
expect(this.categories.$('.TwitterCategory label').text()).toBe(
'components.modals.add-layer.imports.twitter.category 1');
});
it('should create a new category when the before one has any character', function () {
this.categories.$('.TwitterCategory .js-terms').val('test');
this.categories.$('.TwitterCategory .js-terms').trigger('keydown');
expect(this.categories.$('.TwitterCategory').length).toBe(2);
});
it('should delete the category when it is empty and it is not the first one', function () {
this.categories.$('.TwitterCategory .js-terms').val('test');
this.categories.$('.TwitterCategory .js-terms').trigger('keydown');
expect(this.categories.$('.TwitterCategory').length).toBe(2);
this.categories.$('.TwitterCategory:eq(0) .js-terms').val('');
this.categories.$('.TwitterCategory:eq(0) .js-terms').trigger('keydown');
expect(this.categories.$('.TwitterCategory').length).toBe(1);
});
it('should render 4 categories as max', function () {
for (var i = 0, l = 10; i < l; i++) {
this.categories.$('.TwitterCategory:eq(' + i + ') .js-terms').val('test');
this.categories.$('.TwitterCategory:eq(' + i + ') .js-terms').trigger('keydown');
}
expect(this.categories.$('.TwitterCategory').length).toBe(4);
});
it('should return categories as JSON format', function () {
this.categories.$('.TwitterCategory .js-terms').val('test');
this.categories.$('.TwitterCategory .js-terms').trigger('keydown');
var categories = this.categories.getCategories();
expect(categories.length).toBe(2);
expect(categories[0].category).toBe('1');
expect(categories[0].terms.length).toBe(1);
expect(categories[0].terms[0]).toBe('test');
expect(categories[1].category).toBe('2');
expect(categories[1].terms.length).toBe(0);
});
});
describe('twitter credits', function () {
beforeEach(function () {
this.creditsUsage = this.view.creditsUsage;
var creditsInfoKey = _.keys(this.creditsUsage._subviews)[0];
this.creditsInfo = this.creditsUsage._subviews[creditsInfoKey];
});
it('should render properly', function () {
expect(this.creditsUsage.$('.CreditsUsage-slider').length).toBe(1);
expect(this.creditsUsage.$('.CreditsUsage-info').length).toBe(1);
});
it('should set as min value 1%, not 0%', function () {
this.creditsUsage.$('.js-slider').slider('value', 0);
expect(this.creditsUsage.model.get('value')).toBe(1);
});
it('should start around 80% of quota', function () {
var perValue = (this.creditsUsage.model.get('value') * 100) / this.userModel.get('twitter').quota;
expect(perValue).toBe(80);
});
it("should let choose 'no limits' when user doesn't have hard limits", function () {
this.creditsUsage.$('.js-slider').slider('value', 101);
expect(this.creditsUsage.$('.js-info').text()).toContain(
'components.modals.add-layer.imports.twitter.credits-no-limit');
});
it("shouldn't let choose 'no limits' when user has hard limits", function () {
var twitterData = this.userModel.get('twitter');
twitterData.hard_limit = true;
this.userModel.set('twitter', twitterData);
this.creditsUsage.render();
this.creditsUsage.$('.js-slider').slider('value', 101);
expect(this.creditsUsage.$('.js-info').text()).not.toContain(
'components.modals.add-layer.imports.twitter.credits-no-limit');
});
it('should disable slider when user has reached his/her limits', function () {
var twitterData = this.userModel.get('twitter');
twitterData.monthly_use = 110;
this.userModel.set('twitter', twitterData);
this.view.render();
expect(this.view.$('.js-slider').slider('option', 'disabled')).toBeTruthy();
expect(this.view.$('.js-info').text()).toContain(
'components.modals.add-layer.imports.twitter.credits-consumed');
});
it('should change credits info when credits value has changed', function () {
expect(this.creditsInfo.model.get('value')).toBe(80);
this.creditsUsage.model.set('value', 30);
expect(this.creditsInfo.model.get('value')).toBe(30);
});
it('should update model when value has changed', function (done) {
expect(this.creditsUsage.model.get('value')).toBe(80);
spyOn(this.view.model, 'validate').and.callThrough();
this.creditsUsage.model.set('value', 1);
var that = this;
_.defer(function () {
var lastCall = that.view.model.validate.calls.mostRecent();
var lastArg = lastCall.args[0].user_defined_limits.twitter_credits_limit;
expect(lastArg).toEqual(1);
done();
});
});
});
describe('enabled or disabled according to user\'s own credentials', function () {
beforeEach(function () {
this.spyOnHasOwnTwitterCredentials = spyOn(this.userModel, 'hasOwnTwitterCredentials');
this.formIsEnabled = function () {
var categories = !this.view.categories._disabled;
var datepicker = !this.view.datepicker._disabled;
var creditsUsage = !this.view.creditsUsage._disabled;
var allInputsEnabled = categories && datepicker && creditsUsage;
return allInputsEnabled;
};
});
it('should be enabled if user has his own credentials', function () {
this.spyOnHasOwnTwitterCredentials.and.returnValue(true);
this.view._initViews();
expect(this.formIsEnabled()).toBe(true);
});
it('should not be enabled if uses don\'t have his own', function () {
this.spyOnHasOwnTwitterCredentials.and.returnValue(false);
this.view._initViews();
expect(this.formIsEnabled()).toBe(false);
});
});
});
it('should not have leaks', function () {
expect(this.view).toHaveNoLeaks();
});
afterEach(function () {
this.view.clean();
});
});
@@ -0,0 +1,38 @@
var _ = require('underscore');
var TwitterCategoriesView = require('builder/components/modals/add-layer/content/imports/import-twitter/twitter-categories/twitter-categories-view');
/** Note: More behaviour, specially 'render', is tested on its parent view (import-twitter.view.spec.js) */
describe('components/modals/add-layer/content/imports/import-twitter/twitter-categories/twitter-categories-view', function () {
beforeEach(function () {
this.createView = function (opts) {
var custom = opts || {};
var defaults = {};
var view = new TwitterCategoriesView(_.extend(defaults, custom));
view.categoriesAreDisabled = function () {
var allDisabled = this.collection.every(function (category) {
return category.get('disabled');
});
return allDisabled;
};
return view;
};
this.view = this.createView();
});
it('should be enabled by default', function () {
expect(this.view._disabled).toBe(false);
expect(this.view.categoriesAreDisabled()).toBe(false);
});
it('can be created disabled or enabled', function () {
var v = this.createView({disabled: true});
expect(v._disabled).toBe(true);
expect(v.categoriesAreDisabled()).toBe(true);
v = this.createView({disabled: false});
expect(v._disabled).toBe(false);
expect(v.categoriesAreDisabled()).toBe(false);
});
});
@@ -0,0 +1,37 @@
var Backbone = require('backbone');
var TwitterCategoryView = require('builder/components/modals/add-layer/content/imports/import-twitter/twitter-categories/twitter-category-view');
/** Note: More behaviour is tested on its parent view (import-twitter.view.spec.js) */
describe('components/modals/add-layer/content/imports/import-twitter/twitter-categories/twitter-category-view', function () {
beforeEach(function () {
this.createView = function () {
var m = new Backbone.Model({
terms: [],
category: '1',
counter: 1014
});
return new TwitterCategoryView({model: m});
};
this.view = this.createView();
});
describe('render', function () {
beforeEach(function () {
this.view.render();
});
it('should render properly', function () {
expect(this.view.$('input').length).toBe(1);
});
it('can be rendered disabled or enabled', function () {
this.view.model.set('disabled', false);
this.view.render();
expect(this.view.$('input').prop('disabled')).toBe(false);
this.view.model.set('disabled', true);
this.view.render();
expect(this.view.$('input').prop('disabled')).toBe(true);
});
});
});
@@ -0,0 +1,55 @@
var Backbone = require('backbone');
var ImportsView = require('builder/components/modals/add-layer/content/imports/imports-view');
var AddLayerModel = require('builder/components/modals/add-layer/add-layer-model');
var userModel = require('fixtures/builder/user-model.fixture');
var configModel = require('fixtures/builder/config-model.fixture');
describe('components/modals/add-layer/content/imports/imports-view', function () {
var privacyModel = new Backbone.Model();
var guessingModel = new Backbone.Model();
var _userModel = userModel({
mailchimp: {
enabled: true
}
});
var _configModel = configModel({
oauth_gdrive: true
});
var createModel = new AddLayerModel({}, {
userModel: _userModel,
configModel: _configModel,
userActions: {},
pollingModel: new Backbone.Model()
});
beforeEach(function () {
this.view = new ImportsView({
userModel: _userModel,
configModel: _configModel,
createModel: createModel,
privacyModel: privacyModel,
guessingModel: guessingModel
});
spyOn(this.view, '_setUploadModel');
this.view.render();
});
it('should call _setUploadModel on change events', function () {
// Switch tabs back and forth, this used to break because backbone drops events
this.view.$('.js-gdriveTab').click();
this.view.$('.js-fileTab').click();
var selectedTab = this.view._tabPaneCollection.filter(function (e) {
return e.get('selected') === true;
})[0];
selectedTab.attributes.createContentView().trigger('change');
expect(this.view._setUploadModel).toHaveBeenCalled();
this.view.clean();
});
afterEach(function () {
// Remove dropzone leaftover elements
document.querySelector('input.dz-hidden-input').remove();
});
});
@@ -0,0 +1,110 @@
var Backbone = require('backbone');
var GuessingTogglerView = require('builder/components/modals/add-layer/footer/guessing-toggler-view');
var CreateModel = require('builder/components/modals/add-layer/add-layer-model');
var getUserModelFixture = require('fixtures/builder/user-model.fixture.js');
var getConfigModelFixture = require('fixtures/builder/config-model.fixture.js');
describe('components/modals/add-layer/footer/guessing-toggler-view', function () {
beforeEach(function () {
jasmine.Ajax.install();
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
.andReturn({ status: 200 });
this.upgradeUrl = window.upgrade_url;
window.upgrade_url = 'paco_upgrade';
this.userModel = getUserModelFixture();
this.createModel = new CreateModel({
type: 'map',
contentPane: 'listing',
listing: 'import'
}, {
configModel: getConfigModelFixture(),
userModel: this.userModel,
userActions: {},
pollingModel: new Backbone.Model()
});
this.guessingModel = new Backbone.Model({ guessing: true });
this.view = new GuessingTogglerView({
userModel: this.userModel,
guessingModel: this.guessingModel,
createModel: this.createModel,
configModel: jasmine.createSpyObj('configModel', ['get'])
});
spyOn(this.createModel, 'bind').and.callThrough();
this.spyOnHasOwnTwitterCredentials = spyOn(this.userModel, 'hasOwnTwitterCredentials');
this.view.render();
});
afterEach(function () {
jasmine.Ajax.uninstall();
});
it('should render properly', function () {
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.guessing-desc');
expect(this.view.$('.js-toggle').length).toBe(1);
expect(this.view.$('.js-toggle input').is(':checked')).toBeTruthy();
});
describe('when twitter import is active', function () {
beforeEach(function () {
this.createModel.set('activeImportPane', 'twitter');
});
it('should not render guessing button', function () {
expect(this.view.$el.text()).not.toContain('components.modals.add-layer.footer.guessing-desc');
expect(this.view.$('button').length).toBe(0);
});
it('should display how to get historical data when user has his own credentials', function () {
this.spyOnHasOwnTwitterCredentials.and.returnValue(true);
this.view.render();
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.twitter-how-to-historical');
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.contact-team');
});
it('should display a deprecated warning if user does not have his own credentials', function () {
this.spyOnHasOwnTwitterCredentials.and.returnValue(false);
this.view.render();
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.deprecated-connector');
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.twitter-contact-support');
});
});
it('should not change type and content guessing attributes when button is clicked', function () {
// Valid "upload"
var uploadModel = this.createModel.getUploadModel();
uploadModel.setUpload({
type: 'url',
value: 'https://carto.com'
});
expect(uploadModel.get('content_guessing')).toBeTruthy();
expect(uploadModel.get('type_guessing')).toBeTruthy();
expect(this.guessingModel.get('guessing')).toBeTruthy();
this.view.$('.js-toggle').click();
expect(this.guessingModel.get('guessing')).toBeFalsy();
expect(uploadModel.get('content_guessing')).toBeTruthy();
expect(uploadModel.get('type_guessing')).toBeTruthy();
});
it('should not change type and content guessing attributes when upload isn\'t valid', function () {
// Non valid "upload"
var uploadModel = this.createModel.getUploadModel();
uploadModel.setUpload({
type: 'url',
value: 'hello'
});
this.view.$('.js-toggle').click();
expect(this.guessingModel.get('guessing')).toBeFalsy();
expect(uploadModel.get('content_guessing')).toBeTruthy();
expect(uploadModel.get('type_guessing')).toBeTruthy();
});
it('should have no leaks', function () {
expect(this.view).toHaveNoLeaks();
});
});
@@ -0,0 +1,104 @@
var Backbone = require('backbone');
var PrivacyTogglerView = require('builder/components/modals/add-layer/footer/privacy-toggler-view');
var CreateModel = require('builder/components/modals/add-layer/add-layer-model');
var getUserModelFixture = require('fixtures/builder/user-model.fixture.js');
var getConfigModelFixture = require('fixtures/builder/config-model.fixture.js');
describe('components/modals/add-layer/footer/privacy-toggler-view', function () {
beforeEach(function () {
jasmine.Ajax.install();
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
.andReturn({ status: 200 });
this.upgradeUrl = window.upgrade_url;
window.upgrade_url = 'paco_upgrade';
this.userModel = getUserModelFixture();
var configModel = getConfigModelFixture();
this.model = new CreateModel({
option: 'listing',
listing: 'import'
}, {
configModel: configModel,
userModel: this.userModel,
userActions: {},
pollingModel: new Backbone.Model()
});
this.privacyModel = new Backbone.Model({ privacy: 'PUBLIC' });
this.view = new PrivacyTogglerView({
userModel: this.userModel,
privacyModel: this.privacyModel,
createModel: this.model,
configModel: configModel
});
spyOn(this.model, 'bind').and.callThrough();
this.spyOnHasOwnTwitterCredentials = spyOn(this.userModel, 'hasOwnTwitterCredentials');
this.view.render();
});
afterEach(function () {
jasmine.Ajax.uninstall();
});
it('should render properly', function () {
expect(this.view.$('.PrivacyToggler').length).toBe(1);
expect(this.view.$('.PrivacyToggler--PUBLIC').length).toBe(1);
expect(this.view.$('.PrivacyToggler').hasClass('is-disabled')).toBeFalsy();
});
it('should change privacy when it is clicked', function () {
expect(this.privacyModel.get('privacy')).toBe('PUBLIC');
expect(this.view.$('.PrivacyToggler--PUBLIC').length).toBe(1);
this.view.$('.PrivacyToggler').click();
expect(this.privacyModel.get('privacy')).toBe('PRIVATE');
expect(this.view.$('.PrivacyToggler--PRIVATE').length).toBe(1);
});
it('should point to upgrade when user can\'t change privacy', function () {
var actions = { private_tables: false };
this.userModel.set('actions', actions);
this.view.render();
expect(this.view.$('a.PrivacyToggler').length).toBe(1);
expect(this.view.$('a.PrivacyToggler').attr('href')).toBe('paco_upgrade');
expect(this.view.$('.PrivacyToggler').hasClass('is-disabled')).toBeTruthy();
});
it('should not point to upgrade if user can\'t change privacy and there is no upgrade url', function () {
window.upgrade_url = '';
var actions = { private_tables: false };
this.userModel.set('actions', actions);
this.view.render();
expect(this.view.$('a.PrivacyToggler').length).toBe(0);
expect(this.view.$('button.PrivacyToggler').length).toBe(1);
expect(this.view.$('.PrivacyToggler').hasClass('is-disabled')).toBeTruthy();
});
it('should have no leaks', function () {
expect(this.view).toHaveNoLeaks();
});
describe('when twitter import is active', function () {
beforeEach(function () {
this.model.set('activeImportPane', 'twitter');
});
it('should be displayed if user has his own credentials', function () {
this.spyOnHasOwnTwitterCredentials.and.returnValue(true);
this.view.render();
expect(this.view.$('.PrivacyToggler').length).toBe(1);
});
it('it should not be displayed if user does not have his own credentials', function () {
this.spyOnHasOwnTwitterCredentials.and.returnValue(false);
this.view.render();
expect(this.view.$('.PrivacyToggler').length).toBe(0);
});
});
afterEach(function () {
window.upgrade_url = this.upgradeUrl;
});
});
@@ -0,0 +1,65 @@
var _ = require('underscore');
var Backbone = require('backbone');
var ListingView = require('builder/components/modals/add-layer/content/listing-view');
var CreateModel = require('builder/components/modals/add-layer/add-layer-model');
var UserModel = require('builder/data/user-model');
describe('components/modals/add-layer/listing-view', function () {
beforeEach(function () {
jasmine.Ajax.install();
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
.andReturn({ status: 200 });
var configModel = jasmine.createSpyObj('configModel', ['get', 'urlVersion']);
this.userModel = new UserModel({
username: 'pepe',
actions: {
private_tables: true
}
}, {
configModel: configModel
});
this.createModel = new CreateModel({
type: 'map',
contentPane: 'listing',
listing: 'import'
}, {
configModel: configModel,
userModel: this.userModel,
userActions: {},
pollingModel: new Backbone.Model()
});
this.view = new ListingView({
userModel: this.userModel,
createModel: this.createModel,
configModel: configModel,
privacyModel: new Backbone.Model({
privacy: 'PRIVATE'
}),
guessingModel: new Backbone.Model({
guessing: true
})
});
spyOn(this.createModel._tablesCollection, 'fetch');
spyOn(this.createModel, 'bind').and.callThrough();
spyOn(this.createModel._visualizationFetchModel, 'bind').and.callThrough();
this.view.render();
});
afterEach(function () {
jasmine.Ajax.uninstall();
});
it('should render correctly', function () {
this.createModel.set('option', 'listing');
expect(_.size(this.view._subviews)).toBe(1);
});
it('should have no leaks', function () {
expect(this.view).toHaveNoLeaks();
});
});
@@ -0,0 +1,226 @@
var Backbone = require('backbone');
var CreateModel = require('builder/components/modals/add-layer/add-layer-model');
var VisualizationsFetchModel = require('builder/data/visualizations-fetch-model');
var TablesCollection = require('builder/data/tables-collection');
var UserModel = require('builder/data/user-model');
var ConfigModel = require('builder/data/config-model');
var NavigationView = require('builder/components/modals/add-layer/content/navigation-view');
var _ = require('underscore');
describe('components/modals/add-layer/navigation-view', function () {
beforeEach(function () {
jasmine.Ajax.install();
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
.andReturn({ status: 200 });
this.configModel = new ConfigModel({
base_url: '/u/pepe'
});
this.userModel = new UserModel({
username: 'pepe',
remaining_byte_quota: 10
}, {
configModel: this.configModel
});
this.createModel = new CreateModel(
{},
{
configModel: this.configModel,
userModel: this.userModel,
userActions: {},
pollingModel: new Backbone.Model()
}
);
this.visFetchModel = new VisualizationsFetchModel({
content_type: 'datasets'
});
this.tablesCollection = new TablesCollection([], {
configModel: this.configModel
});
this.createView = function () {
this.view = new NavigationView({
configModel: this.configModel,
userModel: this.userModel,
routerModel: this.visFetchModel,
createModel: this.createModel,
tablesCollection: this.tablesCollection
});
};
this.createView();
this.createModel.set('type', 'dataset');
spyOn(this.createModel, 'bind').and.callThrough();
spyOn(this.visFetchModel, 'bind').and.callThrough();
spyOn(this.tablesCollection, 'bind').and.callThrough();
this.view.render();
});
afterEach(function () {
jasmine.Ajax.uninstall();
this.view.remove();
});
it('should render correctly', function () {
expect(this.view.$('.Filters-searchLink').length).toBe(1);
expect(this.view.$('.js-typeItem').length).toBe(3);
});
// TBD: create dataset dialog still not implemented
// it('should not render several links when create dialog type is dataset', function () {
// this.createModel = new CreateDatasetModel({},
// {js-typeItem
// visMap: {},
// configModel: this.configModel,
// userModel: this.userModel
// });
// this.createView();
// this.view.render();
// expect(this.view.$('.Filters-searchLink').length).toBe(1);
// expect(this.view.$('.Filters-typeLink').length).toBe(3);
// });
describe('when data library is enabled', function () {
describe('.render', function () {
it('should render correctly', function () {
spyOn(this.view._configModel, 'dataLibraryEnabled').and.returnValue(true);
this.view.render();
expect(this.view.$('.js-typeItem').length).toBe(4);
expect(this.innerHTML()).toContain('components.modals.add-layer.navigation.data-library');
});
});
});
describe('.initBinds', function () {
it('should render when listing state changes', function () {
spyOn(this.view, 'render');
this.view._initBinds();
this.createModel.trigger('change:listing');
expect(this.view.render).toHaveBeenCalled();
});
it('should render when router model changes', function () {
spyOn(this.view, 'render');
this.view._initBinds();
this.visFetchModel.trigger('change');
expect(this.view.render).toHaveBeenCalled();
});
it('should render when collection changes', function () {
spyOn(this.view, 'render');
this.view._initBinds();
this.tablesCollection.trigger('sync');
expect(this.view.render).toHaveBeenCalled();
});
it('should call _onChangeIsSearchEnabled when model isSearchEnabled changes', function () {
spyOn(this.view, '_onChangeIsSearchEnabled');
this.view._initBinds();
this.view.model.trigger('change:isSearchEnabled');
expect(this.view._onChangeIsSearchEnabled).toHaveBeenCalled();
});
});
it('should create from scratch when create empty button is clicked', function () {
spyOn(this.createModel, 'createFromScratch');
this.userModel.set('account_type', 'ACCOUNT');
this.view.render();
this.view.$('.js-create-empty').click();
expect(this.createModel.createFromScratch).toHaveBeenCalled();
});
it('should disable connect-dataset option when user is out of bytes quota', function () {
this.createModel.set('listing', 'datasets');
this.userModel.set('remaining_byte_quota', 0);
this.view.render();
expect(this.view.$('.js-connect').hasClass('is-disabled')).toBeTruthy();
this.view.$('.js-connect').click();
expect(this.createModel.get('listing')).not.toBe('import');
});
it('should disable connect-dataset option when user Individual and is out of datasets quota', function () {
this.createModel.set('listing', 'datasets');
this.userModel.set('account_type', 'Individual');
this.userModel.set('table_quota', 40);
this.userModel.set('table_count', 40);
this.view.render();
expect(this.view.$('.js-connect').hasClass('is-disabled')).toBeTruthy();
this.view.$('.js-connect').click();
expect(this.createModel.get('listing')).not.toBe('import');
});
it('should disable create empty dataset option when user is out of bytes quota', function () {
spyOn(this.createModel, 'createFromScratch');
this.createModel.set('listing', 'datasets');
this.userModel.set('remaining_byte_quota', 0);
this.view.render();
expect(this.view.$('.js-create-empty').hasClass('is-disabled')).toBeTruthy();
this.view.$('.js-create-empty').click();
expect(this.createModel.createFromScratch).not.toHaveBeenCalled();
});
it('should disable create empty dataset option when user Individual and is out of datasets quota', function () {
spyOn(this.createModel, 'createFromScratch');
this.createModel.set('listing', 'datasets');
this.userModel.set('account_type', 'Individual');
this.userModel.set('table_quota', 40);
this.userModel.set('table_count', 40);
this.view.render();
expect(this.view.$('.js-create-empty').hasClass('is-disabled')).toBeTruthy();
this.view.$('.js-create-empty').click();
expect(this.createModel.createFromScratch).not.toHaveBeenCalled();
});
it('should search starting for the first page', function () {
this.visFetchModel.set('page', 2);
this.view.$('.js-search-input').val('test');
this.view.$('.js-search-form').submit();
expect(this.visFetchModel.get('page')).toBe(1);
});
it('should change router model and listing model when a link is clicked', function () {
spyOn(this.view._configModel, 'dataLibraryEnabled').and.returnValue(true);
this.view.render();
var routerChanged = false;
var stateChanged = false;
function resetFlags () {
routerChanged = false;
stateChanged = false;
}
this.visFetchModel.bind('change', function (m, c) {
if (!_.isEmpty(m.changed)) routerChanged = true;
});
this.createModel.bind('change', function (m, c) {
if (!_.isEmpty(m.changed)) stateChanged = true;
});
resetFlags();
this.view.$('.js-connect').click();
expect(routerChanged).toBeFalsy();
expect(stateChanged).toBeTruthy();
resetFlags();
this.view.$('.js-library').click();
expect(routerChanged).toBeTruthy();
expect(stateChanged).toBeTruthy();
});
it('should have no leaks', function () {
expect(this.view).toHaveNoLeaks();
});
});
@@ -0,0 +1,36 @@
var Backbone = require('backbone');
/**
* Common test cases for a create listing view model.
* Expected to be called in the context of the top-describe closure of an option model, e.g.:
* describe('...', function() {
* beforeEach(function() {
* this.model = new Model({});
* });
* sharedForCreateListingViewModel.call(this);
*/
module.exports = function () {
it('should have listing attr representing current listing view', function () {
expect(this.model.get('listing')).toEqual(jasmine.any(String));
expect(this.model.get('listing')).not.toEqual(''); // should have an initial value
});
describe('.showLibrary', function () {
it('should return a boolean for if data library should be loaded', function () {
expect(this.model.showLibrary()).toEqual(jasmine.any(Boolean));
});
});
describe('.canSelect', function () {
it('should return a boolean for if user can select an item (more)', function () {
var datasetModel = new Backbone.Model();
expect(this.model.canSelect(datasetModel)).toEqual(jasmine.any(Boolean));
});
});
describe('.showDatasets', function () {
it('should return a boolean for whether to show datasets or not', function () {
expect(this.model.showDatasets()).toEqual(jasmine.any(Boolean));
});
});
};
@@ -0,0 +1,16 @@
/**
* Common test cases for a import view model in a create listing.
* Expected to be called in the context of the top-describe closure of an option model, e.g.:
* describe('...', function() {
* beforeEach(function() {
* this.model = new Model({});
* });
* sharedForImportViewModel.call(this);
*/
module.exports = function () {
describe('.setActiveImportPane', function () {
it('should be a function to set which pane is currently active', function () {
expect(this.model.setActiveImportPane).toEqual(jasmine.any(Function));
});
});
};