Initial commit
This commit is contained in:
+178
@@ -0,0 +1,178 @@
|
||||
const $ = require('jquery');
|
||||
const AddOrRemoveGroupUsersFiltersExtraView = require('dashboard/views/organization/groups-admin/filters/add-or-remove-group-users-filters-extra-view');
|
||||
const PasswordValidatedForm = require('dashboard/helpers/password-validated-form');
|
||||
const AddGroupUsersView = require('dashboard/views/organization/groups-admin/add-group-users/add-group-users-view');
|
||||
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
const UserModel = require('dashboard/data/user-model');
|
||||
const GroupModel = require('dashboard/data/group-model');
|
||||
const OrganizationModel = require('dashboard/data/organization-model');
|
||||
|
||||
const PASSWORD = 'password';
|
||||
|
||||
describe('organization/groups-admin/add-or-remove-group-users-filters-extra-view', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(PasswordValidatedForm, 'showPasswordModal').and.callFake(
|
||||
function (options) {
|
||||
options.onPasswordTyped && options.onPasswordTyped(PASSWORD);
|
||||
}
|
||||
);
|
||||
|
||||
this.user = new UserModel({
|
||||
id: 'user-id',
|
||||
username: 'pepe',
|
||||
actions: {},
|
||||
needs_password_confirmation: true
|
||||
}, {});
|
||||
|
||||
this.organization = new OrganizationModel({
|
||||
id: 'org-id',
|
||||
users: [{
|
||||
id: 'abc-123',
|
||||
username: 'paco'
|
||||
},
|
||||
{
|
||||
id: 'abc-456',
|
||||
username: 'pepe'
|
||||
}]
|
||||
}, { configModel });
|
||||
|
||||
this.user.setOrganization(this.organization);
|
||||
|
||||
this.group = new GroupModel({
|
||||
id: 'g1',
|
||||
organization: this.user.organization,
|
||||
users: [{
|
||||
id: 'u1',
|
||||
username: 'pachi'
|
||||
}]
|
||||
}, { configModel });
|
||||
|
||||
spyOn(AddGroupUsersView.prototype, 'initialize').and.callThrough();
|
||||
|
||||
this.view = new AddOrRemoveGroupUsersFiltersExtraView({
|
||||
group: this.group,
|
||||
orgUsers: this.user.organization.users,
|
||||
userModel: this.user
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
// The Dialog closing action occurs within a 120ms delay, so we
|
||||
// remove it manually instead of waiting for the dialog to close
|
||||
const dialog = document.querySelector('.Dialog');
|
||||
|
||||
if (dialog) {
|
||||
dialog.remove();
|
||||
}
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should not open dialog to add users just yet', function () {
|
||||
expect(AddGroupUsersView.prototype.initialize).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should show the add users button', function () {
|
||||
expect(this.view.$('.js-add-users').attr('style')).toBeUndefined();
|
||||
expect(this.view.$('.js-rm-users').attr('style')).toContain('display: none');
|
||||
});
|
||||
|
||||
describe('when click add', function () {
|
||||
beforeEach(function () {
|
||||
this.view.$('.js-add-users').click();
|
||||
});
|
||||
|
||||
it('should open dialog to add users', function () {
|
||||
expect(AddGroupUsersView.prototype.initialize).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when at least one user is selected', function () {
|
||||
beforeEach(function () {
|
||||
this.group.users.first().set('selected', true);
|
||||
});
|
||||
|
||||
it('should change the subheader to show remove button', function () {
|
||||
expect(this.view.$('.js-add-users').attr('style')).toContain('display: none');
|
||||
expect(this.view.$('.js-rm-users').attr('style')).not.toContain('none');
|
||||
});
|
||||
|
||||
describe('when click remove', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.clock().install(); // due to modal animations
|
||||
this.jqXHR = $.Deferred();
|
||||
spyOn(this.group.users, 'removeInBatch').and.returnValue(this.jqXHR);
|
||||
this.view.$('.js-rm-users').click();
|
||||
jasmine.clock().tick(1000);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
it('should require password confirmation if needed', function () {
|
||||
expect(PasswordValidatedForm.showPasswordModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should bypass password confirmation when needs_password_validation is false', function () {
|
||||
PasswordValidatedForm.showPasswordModal.calls.reset();
|
||||
|
||||
const userModel = new UserModel({
|
||||
needs_password_confirmation: false
|
||||
});
|
||||
|
||||
this.view = new AddOrRemoveGroupUsersFiltersExtraView({
|
||||
group: this.group,
|
||||
orgUsers: this.user.organization.users,
|
||||
userModel
|
||||
});
|
||||
|
||||
expect(PasswordValidatedForm.showPasswordModal).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call group users collection to remove them in batch', function () {
|
||||
expect(this.group.users.removeInBatch).toHaveBeenCalled();
|
||||
expect(this.group.users.removeInBatch).toHaveBeenCalledWith(jasmine.any(Array), jasmine.any(String));
|
||||
expect(this.group.users.removeInBatch).toHaveBeenCalledWith(['u1'], PASSWORD);
|
||||
});
|
||||
|
||||
it('should show removing users loader in a modal', function () {
|
||||
expect($('.Dialog').text()).toContain('Removing users');
|
||||
});
|
||||
|
||||
describe('when users are removed', function () {
|
||||
beforeEach(function () {
|
||||
this.jqXHR.resolve();
|
||||
jasmine.clock().tick(1000);
|
||||
});
|
||||
|
||||
it('should close loading modal', function () {
|
||||
expect($('.Dialog').length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fails to remove users', function () {
|
||||
beforeEach(function () {
|
||||
this.jqXHR.reject();
|
||||
jasmine.clock().tick(1000);
|
||||
});
|
||||
|
||||
it('should close loading modal', function () {
|
||||
expect($('.Dialog').text()).not.toContain('Removing users');
|
||||
});
|
||||
|
||||
it('should show error modal', function () {
|
||||
expect($('.Dialog').text()).toContain('error');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
const FlashMessageModel = require('dashboard/data/flash-message-model');
|
||||
const CreateGroupView = require('dashboard/views/organization/groups-admin/create-group/create-group-view');
|
||||
const GroupModel = require('dashboard/data/group-model');
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
|
||||
describe('organization/groups-admin/create-group-view', function () {
|
||||
beforeEach(function () {
|
||||
this.group = new GroupModel({}, { configModel });
|
||||
|
||||
spyOn(this.group, 'save');
|
||||
|
||||
this.onCreatedSpy = jasmine.createSpy('onCreated callback');
|
||||
this.flashMessageModel = new FlashMessageModel();
|
||||
this.view = new CreateGroupView({
|
||||
configModel,
|
||||
group: this.group,
|
||||
onCreated: this.onCreatedSpy,
|
||||
flashMessageModel: this.flashMessageModel
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render input', function () {
|
||||
expect(this.view.$('input').length > 0).toBe(true);
|
||||
});
|
||||
|
||||
describe('when click create group', function () {
|
||||
it('should not try to save group if has no name', function () {
|
||||
this.view.$('.js-create').click();
|
||||
expect(this.group.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when has written a name', function () {
|
||||
beforeEach(function () {
|
||||
this.view.$('.js-name').val('foobar');
|
||||
this.view.$('.js-create').click();
|
||||
});
|
||||
|
||||
it('should try to create group', function () {
|
||||
expect(this.group.save).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should show loading meanwhile', function () {
|
||||
expect(this.innerHTML()).toContain('Creating group');
|
||||
});
|
||||
|
||||
it('should not add to collection until got response', function () {
|
||||
expect(this.group.save.calls.argsFor(0)[1].wait).toBe(true);
|
||||
});
|
||||
|
||||
describe('when create succeeds', function () {
|
||||
beforeEach(function () {
|
||||
this.group.save.calls.argsFor(0)[1].success();
|
||||
});
|
||||
|
||||
it('should call onCreated callback', function () {
|
||||
expect(this.onCreatedSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when create fails', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.flashMessageModel, 'show');
|
||||
this.group.save.calls.argsFor(0)[1].error(this.group, {responseText: '{"errors": ["ERR!"]}'});
|
||||
});
|
||||
|
||||
it('should show form again', function () {
|
||||
expect(this.innerHTML()).not.toContain('Creating group');
|
||||
});
|
||||
|
||||
it('should show error', function () {
|
||||
expect(this.flashMessageModel.show).toHaveBeenCalledWith('ERR!', 'error');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
const FlashMessageModel = require('dashboard/data/flash-message-model');
|
||||
const GroupModel = require('dashboard/data/group-model');
|
||||
const PasswordValidatedForm = require('dashboard/helpers/password-validated-form');
|
||||
const ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
const EditGroupView = require('dashboard/views/organization/groups-admin/edit-group/edit-group-view');
|
||||
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
const UserModel = require('fixtures/dashboard/user-model.fixture');
|
||||
|
||||
describe('organization/groups-admin/edit-group-view', function () {
|
||||
beforeEach(function () {
|
||||
this.group = new GroupModel({
|
||||
id: 'g1',
|
||||
display_name: 'my group'
|
||||
}, { configModel });
|
||||
spyOn(this.group, 'save');
|
||||
|
||||
spyOn(PasswordValidatedForm, 'showPasswordModal').and.callFake(
|
||||
function (options) {
|
||||
options.onPasswordTyped && options.onPasswordTyped();
|
||||
}
|
||||
);
|
||||
|
||||
this.onSavedSpy = jasmine.createSpy('onSaved callback');
|
||||
this.onDeletedSpy = jasmine.createSpy('onDeleted callback');
|
||||
|
||||
this.flashMessageModel = new FlashMessageModel();
|
||||
|
||||
this.view = new EditGroupView({
|
||||
flashMessageModel: this.flashMessageModel,
|
||||
group: this.group,
|
||||
userModel: new UserModel(),
|
||||
modals: new ModalsServiceModel(),
|
||||
onSaved: this.onSavedSpy,
|
||||
onDeleted: this.onDeletedSpy
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
describe('when click save', function () {
|
||||
it('should not try to save group if has no name', function () {
|
||||
this.view.$('.js-name').val('');
|
||||
this.view.$('.js-save').click();
|
||||
expect(this.group.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when has changed name', function () {
|
||||
beforeEach(function () {
|
||||
this.view.$('.js-name').val('new name');
|
||||
this.view.$('.js-save').click();
|
||||
});
|
||||
|
||||
it('should try to save group', function () {
|
||||
expect(this.group.save).toHaveBeenCalled();
|
||||
expect(this.group.save).toHaveBeenCalledWith({
|
||||
display_name: 'new name'
|
||||
}, jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('should show loading meanwhile', function () {
|
||||
expect(this.innerHTML()).toContain('Saving');
|
||||
});
|
||||
|
||||
it('should not update model until got response back', function () {
|
||||
expect(this.group.save.calls.argsFor(0)[1].wait).toBe(true);
|
||||
});
|
||||
|
||||
describe('when save succeeds', function () {
|
||||
beforeEach(function () {
|
||||
this.group.set({
|
||||
id: 'g1'
|
||||
});
|
||||
this.group.save.calls.argsFor(0)[1].success();
|
||||
});
|
||||
|
||||
it('should call onSaved callback', function () {
|
||||
expect(this.onSavedSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when save fails', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.flashMessageModel, 'show');
|
||||
this.group.save.calls.argsFor(0)[1].error(this.group, {responseText: '{"errors": ["ERR!"]}'});
|
||||
});
|
||||
|
||||
it('should show form again', function () {
|
||||
expect(this.view.$('input').length > 0).toBe(true);
|
||||
});
|
||||
|
||||
it('should show error', function () {
|
||||
expect(this.flashMessageModel.show).toHaveBeenCalledWith('ERR!', 'error');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when click delete group', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.group, 'destroy');
|
||||
this.view.$('.js-delete').click();
|
||||
});
|
||||
|
||||
it('should require password confirmation if needed', function () {
|
||||
expect(PasswordValidatedForm.showPasswordModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should bypass password confirmation when needs_password_validation is false', function () {
|
||||
PasswordValidatedForm.showPasswordModal.calls.reset();
|
||||
|
||||
this.view = new EditGroupView({
|
||||
flashMessageModel: this.flashMessageModel,
|
||||
group: this.group,
|
||||
userModel: new UserModel({ needs_password_validation: false }),
|
||||
modals: new ModalsServiceModel(),
|
||||
onSaved: this.onSavedSpy,
|
||||
onDeleted: this.onDeletedSpy
|
||||
});
|
||||
|
||||
expect(PasswordValidatedForm.showPasswordModal).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should change to loading while destroying', function () {
|
||||
expect(this.innerHTML()).toContain('Deleting');
|
||||
});
|
||||
|
||||
it('should not remove from collection until response confirms it deleteted', function () {
|
||||
expect(this.group.destroy.calls.argsFor(0)[0].wait).toBe(true);
|
||||
});
|
||||
|
||||
describe('when deleted', function () {
|
||||
beforeEach(function () {
|
||||
this.group.destroy.calls.argsFor(0)[0].success();
|
||||
});
|
||||
|
||||
it('should call onDeleted callback', function () {
|
||||
expect(this.onDeletedSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when deletion fails', function () {
|
||||
beforeEach(function () {
|
||||
this.group.destroy.calls.argsFor(0)[0].error();
|
||||
});
|
||||
|
||||
it('should show form again', function () {
|
||||
expect(this.view.$('input').length > 0).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
const $ = require('jquery');
|
||||
const EmptyGroupFiltersExtraView = require('dashboard/views/organization/groups-admin/filters/empty-group-filters-extra-view');
|
||||
const UserModel = require('dashboard/data/user-model');
|
||||
const GroupModel = require('dashboard/data/group-model');
|
||||
const OrganizationModel = require('dashboard/data/organization-model');
|
||||
const PasswordValidatedForm = require('dashboard/helpers/password-validated-form');
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
|
||||
const PASSWORD = 'password';
|
||||
|
||||
describe('organization/groups_admin/empty_group_filters_extra_view', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(PasswordValidatedForm, 'showPasswordModal').and.callFake(
|
||||
function (options) {
|
||||
options.onPasswordTyped && options.onPasswordTyped(PASSWORD);
|
||||
}
|
||||
);
|
||||
|
||||
this.organization = new OrganizationModel({
|
||||
id: 'org-id',
|
||||
users: [{
|
||||
id: 'ou-1',
|
||||
username: 'paco'
|
||||
},
|
||||
{
|
||||
id: 'ou-2',
|
||||
username: 'pepe'
|
||||
}]
|
||||
}, { configModel });
|
||||
|
||||
this.user = new UserModel({
|
||||
id: 'user-id',
|
||||
username: 'pepe',
|
||||
actions: {},
|
||||
needs_password_confirmation: true
|
||||
});
|
||||
this.user.setOrganization(this.organization);
|
||||
|
||||
this.group = new GroupModel({
|
||||
id: 'g1',
|
||||
organization: this.user.organization,
|
||||
users: [{
|
||||
id: 'gu-1',
|
||||
username: 'pachi'
|
||||
}]
|
||||
}, { configModel });
|
||||
|
||||
this.groupUsers = this.group.users;
|
||||
spyOn(this.groupUsers, 'addInBatch');
|
||||
|
||||
this.orgUsers = this.user.organization.users;
|
||||
|
||||
this.view = new EmptyGroupFiltersExtraView({
|
||||
groupUsers: this.groupUsers,
|
||||
orgUsers: this.orgUsers,
|
||||
userModel: this.user
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
// The Dialog closing action occurs within a 120ms delay, so we
|
||||
// remove it manually instead of waiting for the dialog to close
|
||||
var dialog = document.querySelector('.Dialog');
|
||||
|
||||
if (dialog) {
|
||||
dialog.remove();
|
||||
}
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should show the add-users button disabled', function () {
|
||||
expect(this.view.$('.js-add-users').hasClass('is-disabled')).toBe(true);
|
||||
});
|
||||
|
||||
it('should do nothing on click add-button', function () {
|
||||
this.view.$('.js-add-users').click();
|
||||
expect(this.groupUsers.addInBatch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when at least one user is selected', function () {
|
||||
beforeEach(function () {
|
||||
this.orgUsers.first().set('selected', true);
|
||||
});
|
||||
|
||||
it('should change the subheader to show add button', function () {
|
||||
expect(this.view.$('.js-add-users').hasClass('is-disabled')).toBe(false);
|
||||
});
|
||||
|
||||
describe('when click add', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.clock().install(); // due to modal animations
|
||||
this.jqXHR = $.Deferred();
|
||||
this.groupUsers.addInBatch.and.returnValue(this.jqXHR);
|
||||
this.view.$('.js-add-users').click();
|
||||
jasmine.clock().tick(1000);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
it('should require password confirmation if needed', function () {
|
||||
expect(PasswordValidatedForm.showPasswordModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should bypass password confirmation when needs_password_validation is false', function () {
|
||||
PasswordValidatedForm.showPasswordModal.calls.reset();
|
||||
|
||||
const userModel = new UserModel({
|
||||
needs_password_confirmation: false
|
||||
});
|
||||
|
||||
this.view = new EmptyGroupFiltersExtraView({
|
||||
groupUsers: this.groupUsers,
|
||||
orgUsers: this.orgUsers,
|
||||
userModel
|
||||
});
|
||||
|
||||
expect(PasswordValidatedForm.showPasswordModal).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call group users collection to add them in batch', function () {
|
||||
expect(this.group.users.addInBatch).toHaveBeenCalled();
|
||||
expect(this.group.users.addInBatch).toHaveBeenCalledWith(jasmine.any(Array), jasmine.any(String));
|
||||
expect(this.group.users.addInBatch).toHaveBeenCalledWith(['ou-1'], PASSWORD);
|
||||
});
|
||||
|
||||
it('should show removing users loader in a modal', function () {
|
||||
expect($('.Dialog').text()).toContain('Adding');
|
||||
});
|
||||
|
||||
describe('when users are added', function () {
|
||||
beforeEach(function () {
|
||||
this.jqXHR.resolve();
|
||||
jasmine.clock().tick(1000);
|
||||
});
|
||||
|
||||
it('should close loading modal', function () {
|
||||
expect($('.Dialog').length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fails to add users', function () {
|
||||
beforeEach(function () {
|
||||
this.jqXHR.reject();
|
||||
jasmine.clock().tick(1000);
|
||||
});
|
||||
|
||||
it('should close loading modal', function () {
|
||||
expect($('.Dialog').text()).not.toContain('Adding');
|
||||
});
|
||||
|
||||
it('should show error modal', function () {
|
||||
expect($('.Dialog').text()).toContain('error');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
const GroupHeaderView = require('dashboard/views/organization/groups-admin/group-header/group-header-view');
|
||||
const GroupModel = require('dashboard/data/group-model');
|
||||
const UrlModel = require('dashboard/data/url-model');
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
|
||||
describe('dashboard/views/organization/groups-admin/group-header-view', function () {
|
||||
beforeEach(function () {
|
||||
this.setupView = function () {
|
||||
this.group = new GroupModel({}, { configModel });
|
||||
|
||||
this.urls = {
|
||||
root: new UrlModel({ base_url: 'fake-root-url' }),
|
||||
users: new UrlModel({ base_url: 'fake-users-url' }),
|
||||
edit: new UrlModel({ base_url: 'fake-edit-url' })
|
||||
};
|
||||
this.urls.users.isCurrent = true;
|
||||
|
||||
spyOn(GroupHeaderView.prototype, 'initialize').and.callThrough();
|
||||
this.view = new GroupHeaderView({
|
||||
group: this.group,
|
||||
urls: this.urls
|
||||
});
|
||||
this.view.render();
|
||||
};
|
||||
});
|
||||
|
||||
describe('when group is new', function () {
|
||||
beforeEach(function () {
|
||||
this.setupView();
|
||||
});
|
||||
|
||||
it('should render the fallback text as title', function () {
|
||||
expect(this.innerHTML()).toContain('Create new group');
|
||||
});
|
||||
|
||||
it('should render back button to root', function () {
|
||||
expect(this.view.$('.Filters-group a.u-actionTextColor').attr('href')).toEqual('fake-root-url');
|
||||
});
|
||||
|
||||
it('should not render the users tab', function () {
|
||||
expect(this.innerHTML()).not.toMatch('\sUser');
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when group already exist', function () {
|
||||
beforeEach(function () {
|
||||
this.setupView();
|
||||
this.group.set({
|
||||
id: 'g1',
|
||||
display_name: 'my group'
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the group display name as title', function () {
|
||||
expect(this.innerHTML()).toContain('my group');
|
||||
});
|
||||
|
||||
it('should render back button to root', function () {
|
||||
expect(this.view.$('.Filters-group a.u-actionTextColor').attr('href')).toEqual('fake-root-url');
|
||||
});
|
||||
|
||||
it('should render back button to users if is not on users url', function () {
|
||||
this.urls.users.isCurrent = false;
|
||||
this.view.render();
|
||||
expect(this.view.$('.Filters-group a.u-actionTextColor').attr('href')).toEqual('fake-users-url');
|
||||
});
|
||||
|
||||
it('should render the menu', function () {
|
||||
expect(this.innerHTML()).toContain('User');
|
||||
});
|
||||
|
||||
it('should only render users count if has any', function () {
|
||||
expect(this.innerHTML()).not.toContain('0 Users');
|
||||
this.group.users.reset([{}]);
|
||||
expect(this.innerHTML()).toContain('1 User');
|
||||
this.group.users.reset([{}, {}, {}]);
|
||||
expect(this.innerHTML()).toContain('3 Users');
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
const Backbone = require('backbone');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const GroupsMainView = require('dashboard/views/organization/groups-admin/groups-main-view');
|
||||
|
||||
describe('dashboard/views/organization/groups-admin/groups-main-view', function () {
|
||||
beforeEach(function () {
|
||||
this.contentView = new CoreView();
|
||||
spyOn(this.contentView, 'render').and.callThrough();
|
||||
|
||||
this.routerModel = new Backbone.Model({
|
||||
view: this.contentView
|
||||
});
|
||||
this.router = new Backbone.Model();
|
||||
this.router.model = this.routerModel;
|
||||
|
||||
this.view = new GroupsMainView({
|
||||
routerModel: this.router,
|
||||
groups: this.groups
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render the view given by router model', function () {
|
||||
expect(this.contentView.render).toHaveBeenCalled();
|
||||
expect(this.view.el).toEqual(this.contentView.el.parentNode);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
const GroupUsersView = require('dashboard/views/organization/groups-admin/group-users/group-users-view');
|
||||
const GroupModel = require('dashboard/data/group-model');
|
||||
const UserModel = require('dashboard/data/user-model');
|
||||
const OrganizationModel = require('dashboard/data/organization-model');
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
|
||||
describe('dashboard/organization/views/groups-admin/group-users/group-users-view', function () {
|
||||
beforeEach(function () {
|
||||
this.organization = new OrganizationModel({
|
||||
id: 'org-id',
|
||||
users: [{
|
||||
id: 'abc-123',
|
||||
username: 'paco'
|
||||
},
|
||||
{
|
||||
id: 'abc-456',
|
||||
username: 'pepe'
|
||||
}]
|
||||
}, { configModel, currentUserId: 'user-id' });
|
||||
|
||||
this.user = new UserModel({
|
||||
id: 'user-id',
|
||||
username: 'pepe',
|
||||
actions: {}
|
||||
});
|
||||
this.user.setOrganization(this.organization);
|
||||
|
||||
this.group = new GroupModel({
|
||||
id: 'g1',
|
||||
organization: this.user.organization,
|
||||
users: [{
|
||||
id: 'u1',
|
||||
username: 'pachi'
|
||||
}]
|
||||
}, { configModel });
|
||||
this.groupUsers = this.group.users;
|
||||
this.groupUsers.sync = (a, b, opts) => {
|
||||
this.syncOpts = opts;
|
||||
};
|
||||
|
||||
this.view = new GroupUsersView({
|
||||
group: this.group,
|
||||
orgUsers: this.user.organization.users,
|
||||
userModel: new UserModel()
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render a loading view initially', function () {
|
||||
expect(this.innerHTML()).toContain('Getting users');
|
||||
});
|
||||
|
||||
describe('when group users are fetched', function () {
|
||||
describe('when there are no group users', function () {
|
||||
beforeEach(function () {
|
||||
this.syncOpts.success({
|
||||
users: [],
|
||||
total_user_entries: 0,
|
||||
total_entries: 0
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the empty view', function () {
|
||||
expect(this.innerHTML()).not.toContain('Remove'); // btn
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
describe('when group users are added', function () {
|
||||
beforeEach(function () {
|
||||
this.syncOpts.success({
|
||||
users: [{
|
||||
id: 'gu-1',
|
||||
username: 'pepito'
|
||||
}],
|
||||
total_user_entries: 1,
|
||||
total_entries: 1
|
||||
});
|
||||
this.groupUsers.fetch();
|
||||
});
|
||||
|
||||
it('should render the group users', function () {
|
||||
expect(this.innerHTML()).toContain('pepito');
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there are at least one group user', function () {
|
||||
beforeEach(function () {
|
||||
this.syncOpts.success({
|
||||
users: [{
|
||||
id: 'gu-2',
|
||||
username: 'bollibompa'
|
||||
}],
|
||||
total_user_entries: 1,
|
||||
total_entries: 1
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the group users', function () {
|
||||
expect(this.innerHTML()).toContain('bollibompa');
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
describe('when group is emptied', function () {
|
||||
beforeEach(function () {
|
||||
this.syncOpts.success({
|
||||
users: [],
|
||||
total_user_entries: 0,
|
||||
total_entries: 0
|
||||
});
|
||||
this.groupUsers.fetch();
|
||||
});
|
||||
|
||||
it('should render the empty view', function () {
|
||||
expect(this.innerHTML()).not.toContain('Remove'); // btn
|
||||
expect(this.innerHTML()).not.toContain('bollibompa');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
const GroupView = require('dashboard/views/organization/groups-admin/group-view/group-view');
|
||||
const GroupModel = require('dashboard/data/group-model');
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
|
||||
describe('organization/groups_admin/group_view', function () {
|
||||
beforeEach(function () {
|
||||
this.group = new GroupModel({
|
||||
display_name: 'foobar',
|
||||
shared_tables_count: 42,
|
||||
shared_maps_count: 37,
|
||||
users: [{
|
||||
id: 'u1',
|
||||
name: 'pepe'
|
||||
}]
|
||||
}, { configModel });
|
||||
|
||||
this.view = new GroupView({
|
||||
model: this.group,
|
||||
url: 'group-url'
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render the title', function () {
|
||||
expect(this.innerHTML()).toContain('foobar');
|
||||
});
|
||||
|
||||
it('should render the URL', function () {
|
||||
expect(this.innerHTML()).toContain('href="group-url"');
|
||||
});
|
||||
|
||||
it('should render the shared maps/datasets counts', function () {
|
||||
expect(this.innerHTML()).toContain('42 shared datasets');
|
||||
expect(this.innerHTML()).toContain('37 shared maps');
|
||||
});
|
||||
|
||||
it('should render a preview of the users', function () {
|
||||
expect(this.innerHTML()).toContain('pepe');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
const RouterModel = require('dashboard/views/organization/groups-admin/router-model');
|
||||
const OrganizationGroupsCollection = require('dashboard/data/organization-groups-collection');
|
||||
const OrganizationModel = require('dashboard/data/organization-model');
|
||||
const GroupModel = require('dashboard/data/group-model');
|
||||
const UserModel = require('dashboard/data/user-model');
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
|
||||
describe('dashboard/data/router-model', function () {
|
||||
beforeEach(function () {
|
||||
const organization = new OrganizationModel({
|
||||
owner: {
|
||||
id: 123
|
||||
}
|
||||
}, { configModel });
|
||||
|
||||
const user = new UserModel({
|
||||
id: 123,
|
||||
base_url: 'https://carto.com/user/paco',
|
||||
username: 'paco'
|
||||
});
|
||||
user.setOrganization(organization);
|
||||
|
||||
this.groups = new OrganizationGroupsCollection([], {
|
||||
organization: user.organization,
|
||||
configModel
|
||||
});
|
||||
|
||||
this.model = new RouterModel();
|
||||
});
|
||||
|
||||
describe('.createGroupView', function () {
|
||||
beforeEach(function () {
|
||||
this.groups.add({
|
||||
id: 'g1',
|
||||
display_name: 'group that i already fetched'
|
||||
});
|
||||
this.fetchedCallbackSpy = jasmine.createSpy('fetchedCallback');
|
||||
});
|
||||
|
||||
describe('when given a id of a group that already is fetched', function () {
|
||||
beforeEach(function () {
|
||||
this.model.createGroupView(this.groups, 'g1', this.fetchedCallbackSpy);
|
||||
});
|
||||
|
||||
it('should call the fetched callback right away with the corresponding group', function () {
|
||||
expect(this.fetchedCallbackSpy).toHaveBeenCalled();
|
||||
expect(this.fetchedCallbackSpy).toHaveBeenCalledWith(this.groups.first());
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a id of a group that is not yet fetched', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(GroupModel.prototype, 'fetch');
|
||||
this.model.createGroupView(this.groups, 'other', this.fetchedCallbackSpy);
|
||||
});
|
||||
|
||||
it('should fetch the group first', function () {
|
||||
expect(GroupModel.prototype.fetch).toHaveBeenCalled();
|
||||
expect(this.fetchedCallbackSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fetch w/ users', function () {
|
||||
expect(GroupModel.prototype.fetch.calls.argsFor(0)[0].data.fetch_users).toBe(true);
|
||||
});
|
||||
|
||||
describe('when fetch succeeds', function () {
|
||||
beforeEach(function () {
|
||||
GroupModel.prototype.fetch.calls.argsFor(0)[0].success();
|
||||
});
|
||||
|
||||
it('should add the group to the collection', function () {
|
||||
expect(this.groups.get('other')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call the fetched callback with the new group', function () {
|
||||
expect(this.fetchedCallbackSpy).toHaveBeenCalled();
|
||||
expect(this.fetchedCallbackSpy).toHaveBeenCalledWith(this.groups.get('other'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fetch fails', function () {
|
||||
beforeEach(function () {
|
||||
GroupModel.prototype.fetch.calls.argsFor(0)[0].error();
|
||||
});
|
||||
|
||||
it('should create a generic error view', function () {
|
||||
var view = this.model.get('view');
|
||||
view.render();
|
||||
expect(this.innerHTML(view)).toContain('error');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.createLoadingView', function () {
|
||||
beforeEach(function () {
|
||||
this.model.createLoadingView('Loading something');
|
||||
});
|
||||
|
||||
it('should create a loading view', function () {
|
||||
var view = this.model.get('view');
|
||||
view.render();
|
||||
expect(this.innerHTML(view)).toContain('Loading something');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
const Router = require('dashboard/common/router-organization-groups');
|
||||
const UserModel = require('dashboard/data/user-model');
|
||||
const OrganizationGroupsCollection = require('dashboard/data/organization-groups-collection');
|
||||
const OrganizationModel = require('dashboard/data/organization-model');
|
||||
const FlashMessageModel = require('dashboard/data/flash-message-model');
|
||||
const ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
const configModel = require('fixtures/dashboard/config-model.fixture');
|
||||
|
||||
describe('dashboard/common/router-organization-groups', function () {
|
||||
beforeEach(function () {
|
||||
const organization = new OrganizationModel({
|
||||
owner: {
|
||||
id: 123
|
||||
}
|
||||
}, { configModel });
|
||||
|
||||
const userModel = new UserModel({
|
||||
id: 123,
|
||||
base_url: 'https://carto.com/user/paco',
|
||||
username: 'paco',
|
||||
org_admin: true
|
||||
});
|
||||
userModel.setOrganization(organization);
|
||||
|
||||
this.groups = new OrganizationGroupsCollection([], {
|
||||
organization: userModel.organization,
|
||||
configModel
|
||||
});
|
||||
|
||||
this.flashMessageModel = new FlashMessageModel();
|
||||
|
||||
this.router = new Router({
|
||||
userModel,
|
||||
flashMessageModel: this.flashMessageModel,
|
||||
rootUrl: userModel.viewUrl().organization().groups(),
|
||||
groups: this.groups,
|
||||
modals: new ModalsServiceModel()
|
||||
});
|
||||
});
|
||||
|
||||
describe('.normalizeFragmentOrUrl', function () {
|
||||
it('should return the normalized pathname for URLs matching current scope', function () {
|
||||
expect(this.router.normalizeFragmentOrUrl('https://carto.com/user/paco/organization/groups/new')).toEqual('/new');
|
||||
expect(this.router.normalizeFragmentOrUrl('https://carto.com/user/paco/organization/groups/edit/123')).toEqual('/edit/123');
|
||||
});
|
||||
|
||||
it('should return full URL for non-matching URLs', function () {
|
||||
expect(this.router.normalizeFragmentOrUrl('https://carto.com/user/paco/somewhere/else')).toEqual('https://carto.com/user/paco/somewhere/else');
|
||||
});
|
||||
});
|
||||
|
||||
it('should render a generic loading view for starters', function () {
|
||||
var view = this.router.model.get('view');
|
||||
view.render();
|
||||
expect(this.innerHTML(view)).toContain('Loading view');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user