describe('NgTableParams', function () { var scope, NgTableParams, $rootScope; beforeEach(module("ngTable")); beforeEach(function(){ module(function($provide){ $provide.decorator('ngTableDefaultGetData', createSpy); createSpy.$inject = ['$delegate']; function createSpy(ngTableDefaultGetData){ return jasmine.createSpy('ngTableDefaultGetDataSpy',ngTableDefaultGetData).and.callThrough(); } }); }); beforeEach(inject(function ($controller, _$rootScope_, _NgTableParams_) { $rootScope = _$rootScope_; scope = $rootScope.$new(); NgTableParams = _NgTableParams_; })); function createNgTableParams(settings) { var initialParams; if (arguments.length === 2){ initialParams = arguments[0]; settings = arguments[1]; } settings = angular.extend({}, settings); settings.filterOptions = angular.extend({}, { filterDelay: 0 }, settings.filterOptions); var tableParams = new NgTableParams(initialParams, settings); spyOn(tableParams.settings(), 'getData').and.callThrough(); return tableParams; } it('NgTableParams should be defined', function () { expect(NgTableParams).toBeDefined(); }); describe('generatePagesArray', function(){ it('should generate pages array using arguments supplied', function(){ var params = new NgTableParams(); expect(params.generatePagesArray(1, 30, 10)).toEqual([ { type: 'prev', number: 1, active: false }, { type: 'first', number: 1, active: false, current: true }, { type: 'page', number: 2, active: true, current: false }, { type: 'last', number: 3, active: true, current: false }, { type: 'next', number: 2, active: true } ]); expect(params.generatePagesArray(2, 30, 10)).toEqual([ { type: 'prev', number: 1, active: true }, { type: 'first', number: 1, active: true, current: false }, { type: 'page', number: 2, active: false, current: true }, { type: 'last', number: 3, active: true, current: false }, { type: 'next', number: 3, active: true } ]); expect(params.generatePagesArray(2, 100, 10)).toEqual([ { type: 'prev', number: 1, active: true }, { type: 'first', number: 1, active: true, current: false }, { type: 'page', number: 2, active: false, current: true }, { type: 'page', number: 3, active: true, current: false }, { type: 'page', number: 4, active: true, current: false }, { type: 'page', number: 5, active: true, current: false }, { type: 'page', number: 6, active: true, current: false }, { type: 'page', number: 7, active: true, current: false }, { type: 'more', active: false }, { type: 'last', number: 10, active: true, current: false }, { type: 'next', number: 3, active: true } ]); }); it('should use own parameter values to generate pages when no arguments supplied', function(){ var params = new NgTableParams({ page: 2, count: 10 }, { total: 30 }); expect(params.generatePagesArray()).toEqual([ { type: 'prev', number: 1, active: true }, { type: 'first', number: 1, active: true, current: false }, { type: 'page', number: 2, active: false, current: true }, { type: 'last', number: 3, active: true, current: false }, { type: 'next', number: 3, active: true } ]); }); }); it('NgTableParams `page` parameter', function () { var params = new NgTableParams(); expect(params.page()).toBe(1); expect(params.page(2)).toEqual(params); expect(params.page()).toBe(2); params = new NgTableParams({ page: 3 }); expect(params.page()).toBe(3); }); it('NgTableParams parse url parameters', function () { var params = new NgTableParams({ 'sorting[name]': 'asc', 'sorting[age]': 'desc', 'filter[name]': 'test', 'filter[age]': '20', 'group[name]' : 'asc', 'group[age]' : 'desc', 'group[surname]' : undefined }); expect(params.filter()).toEqual({ 'name': 'test', 'age': 20 }); expect(params.sorting()).toEqual({ 'age': 'desc' }); // sorting only by one column - todo: remove restriction expect(params.group()).toEqual({ 'name' : 'asc', 'age': 'desc', 'surname': undefined }); }); it('NgTableParams return url parameters', function () { var params = new NgTableParams({ 'sorting[name]': 'asc', 'sorting[age]': 'desc', 'filter[name]': 'test', 'filter[age]': '20', 'group[name]' : 'asc', 'group[age]' : 'desc', 'group[surname]' : '' }); expect(params.url()).toEqual({ 'page': '1', 'count': '10', 'filter[name]': 'test', 'filter[age]': '20', 'sorting[age]': 'desc', // sorting only by one column - todo: remove restriction 'group[name]' : 'asc', 'group[age]' : 'desc', 'group[surname]' : '' }); expect(params.url(true)).toEqual([ 'page=1', 'count=10', 'filter[name]=test', 'filter[age]=20', 'sorting[age]=desc', // sorting only by one column - todo: remove restriction 'group[name]=asc', 'group[age]=desc', 'group[surname]=' ]); }); it('orderBy', function () { var params = new NgTableParams({ 'sorting[name]': 'asc' }); expect(params.orderBy()).toEqual([ '+name' ]); // for angular sorting function params.sorting({ name: 'desc', age: 'asc' }); expect(params.orderBy()).toEqual([ '-name', '+age' ]); }); describe('group', function(){ it('one group', function () { var params = new NgTableParams({ group: 'role' }, { groupOptions: { defaultSort: 'desc' } }); expect(params.hasGroup()).toBe(true); expect(params.hasGroup('role')).toBe(true); expect(params.hasGroup('role', 'desc')).toBe(true); expect(params.group()).toEqual({ role: 'desc' }); params.group('age'); expect(params.hasGroup('age', 'desc')).toBe(true); expect(params.group()).toEqual({ age: 'desc' }); params.group('age', 'asc'); expect(params.hasGroup('age', 'asc')).toBe(true); expect(params.group()).toEqual({ age: 'asc' }); }); it('one group (nested property)', function () { var params = new NgTableParams({ group: 'details.personal.age' }, { groupOptions: { defaultSort: 'desc' } }); expect(params.hasGroup()).toBe(true); expect(params.hasGroup('details.personal.age')).toBe(true); expect(params.hasGroup('details.personal.age', 'desc')).toBe(true); expect(params.group()).toEqual({ 'details.personal.age': 'desc' }); params.group('details.country'); expect(params.hasGroup('details.country', 'desc')).toBe(true); expect(params.group()).toEqual({ 'details.country': 'desc' }); params.group('details.country', 'asc'); expect(params.hasGroup('details.country', 'asc')).toBe(true); expect(params.group()).toEqual({ 'details.country': 'asc' }); }); it('one group function', function () { var params = new NgTableParams({ group: angular.identity }); expect(params.hasGroup()).toBe(true); expect(params.hasGroup(angular.identity)).toBe(true); expect(params.hasGroup(angular.identity, params.settings().groupOptions.defaultSort)).toBe(true); expect(params.group()).toEqual(angular.identity); var fn = function(){ }; fn.sortDirection = 'desc'; params.group(fn); expect(params.hasGroup(fn)).toBe(true); expect(params.hasGroup(fn, 'desc')).toBe(true); expect(params.group()).toEqual(fn); }); it('can clear group', function () { var params = new NgTableParams({ group: 'role' }); expect(params.hasGroup()).toBe(true); // checking assumptions params.group({}); expect(params.hasGroup()).toBe(false); expect(params.group()).toEqual({}); }); it('multiple groups', function () { var params = new NgTableParams({ group: 'role' }, { groupOptions: { defaultSort: 'desc' } }); var newGroups = _.extend({}, params.group(), { age: 'desc'}); params.group(newGroups); expect(params.hasGroup()).toBe(true); expect(params.hasGroup('role')).toBe(true); expect(params.hasGroup('role', 'desc')).toBe(true); expect(params.hasGroup('age')).toBe(true); expect(params.hasGroup('age', 'desc')).toBe(true); expect(params.group()).toEqual({ role: 'desc', age: 'desc' }); params.group({ role: 'asc', age: 'asc'}); expect(params.hasGroup('age', 'desc')).toBe(false); expect(params.hasGroup('age', 'asc')).toBe(true); expect(params.group()).toEqual({ role: 'asc', age: 'asc' }); }); it('should apply current defaultSort from groupOptions', function(){ var params = new NgTableParams({ group: 'role' }, { groupOptions: { defaultSort: 'desc' } }); params.settings({ groupOptions: { defaultSort: 'asc' }}); params.group('age'); expect(params.group()).toEqual({ age: 'asc' }); }); it('should not apply defaultSort from groupOptions when explicitly set to empty string', function(){ var params = new NgTableParams({ group: 'role' }, { groupOptions: { defaultSort: 'desc' } }); expect(params.group()).toEqual({ role: 'desc' }); // checking assumptions params.group({ role: ''}); expect(params.group()).toEqual({ role: '' }); params.group({ age: undefined}); expect(params.group()).toEqual({ age: 'desc' }); params.group({ role: null}); expect(params.group()).toEqual({ role: 'desc' }); }); }); describe('settings', function(){ it('defaults', function () { var params = new NgTableParams(); var expectedSettings = { $loading: false, dataset: null, total: 0, defaultSort: 'desc', counts: [10, 25, 50, 100], interceptors: [], paginationMaxBlocks: 11, paginationMinBlocks: 5, sortingIndicator: 'span', filterOptions: { filterComparator: undefined, filterDelay: 500, filterDelayThreshold: 10000, filterFilterName: undefined, filterFn: undefined, filterLayout: 'stack' }, groupOptions: { defaultSort: 'asc', isExpanded: true } }; expect(params.settings()).toEqual(jasmine.objectContaining(expectedSettings)); expect(params.settings().getData).toEqual(jasmine.any(Function)); expect(params.settings().getGroups).toEqual(jasmine.any(Function)); params = new NgTableParams({}, { total: 100, counts: [1,2], groupOptions: { isExpanded: false } }); expectedSettings.total = 100; expectedSettings.counts = [1,2]; expectedSettings.groupOptions = { defaultSort: 'asc', isExpanded: false }; expect(params.settings()).toEqual(jasmine.objectContaining(expectedSettings)); }); it('changing settings().dataset should reset page to 1', function(){ // given var tableParams = createNgTableParams({ count: 1, page: 2 }, { dataset: [1,2,3]}); tableParams.reload(); scope.$digest(); expect(tableParams.page()).toBe(2); // checking assumptions // when tableParams.settings({ dataset: [1,2,3, 4]}); // then expect(tableParams.page()).toBe(1); }); it('should not set filterDelay when working with synchronous dataset', function(){ // given var tableParams = new NgTableParams({}, { dataset: [1,2,3]}); expect(tableParams.settings().filterOptions.filterDelay).toBe(0); }); it('should not set filterDelay when working with synchronous dataset (empty dataset)', function(){ // given var tableParams = new NgTableParams({}, { dataset: []}); expect(tableParams.settings().filterOptions.filterDelay).toBe(0); }); it('should set filterDelay when not certain working with synchronous dataset', function(){ // given var tableParams = new NgTableParams({}, { dataset: [1,2], getData: function(){ // am I sync or async? }}); expect(tableParams.settings().filterOptions.filterDelay).toBe(500); }); it('should set filterDelay when dataset exceeds filterDelayThreshold', function(){ // given var tableParams = new NgTableParams({}, { filterOptions: { filterDelayThreshold: 5 }, dataset: [,2,3,4,5,6] }); expect(tableParams.settings().filterOptions.filterDelay).toBe(500); }); it('should allow filterDelay to be set explicitly', function(){ // given var tableParams = new NgTableParams({}, { filterOptions: { filterDelay: 100}, dataset: [1,2] }); expect(tableParams.settings().filterOptions.filterDelay).toBe(100); }); }); describe('reload', function(){ it('should call getData to retrieve data', function(){ var tp = createNgTableParams(); tp.reload(); scope.$digest(); expect(tp.settings().getData.calls.count()).toBe(1); }); it('should add the results returned by getData to the data field', function(){ var tp = createNgTableParams({ getData: function(){ return [1,2,3]; }}); tp.reload(); scope.$digest(); expect(tp.data).toEqual([1,2,3]); }); it('should use ngTableDefaultGetData function when NgTableParams not supplied a getData function', inject(function(ngTableDefaultGetData){ // given var tp = createNgTableParams(); // when tp.reload(); scope.$digest(); // then expect(ngTableDefaultGetData).toHaveBeenCalled(); })); it('should propagate rejection reason from getData', inject(function($q){ // given var tp = createNgTableParams({ getData: function(){ return $q.reject('bad response') }}); // when var actualRejection; tp.reload().catch(function(reason){ actualRejection = reason; }); scope.$digest(); // then expect(actualRejection).toBe('bad response'); })); }); describe('getGroups', function(){ var dataset; beforeEach(function(){ dataset = [ { 'name': 'Hanson', 'role': 'Accounting' }, { 'name': 'Eaton', 'role': 'Customer Service' }, { 'name': 'Perry', 'role': 'Customer Service' }, { 'name': 'George', 'role': 'Accounting' }, { 'name': 'Jennings', 'role': 'Asset Management' }, { 'name': 'Whitney', 'role': 'Accounting' }, { 'name': 'Weaver', 'role': 'Payroll' }, { 'name': 'Gibson', 'role': 'Payroll' }, { 'name': 'Wells', 'role': 'Media Relations' }, { 'name': 'Willis', 'role': 'Finances' }, { 'name': 'Donovan', 'role': 'Customer Relations' }, { 'name': 'Mcdonald', 'role': 'Finances' }, { 'name': 'Young', 'role': 'Asset Management' } ]; }); it('should group data then apply paging to groups', function () { var tp = createNgTableParams({ count: 2, group: { role: '' } }, { dataset: dataset }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Accounting', data: [ { "name": 'Hanson', "role": 'Accounting' }, { "name": 'George', "role": 'Accounting' }, { "name": 'Whitney', "role": 'Accounting' } ] }, { $hideRows: false, value: 'Customer Service', data: [ { "name": 'Eaton', "role": 'Customer Service' }, { "name": 'Perry', "role": 'Customer Service' } ] } ]); }); it('should sort data, then group, then page groups', function () { var tp = createNgTableParams({ count: 2, sorting: { name: 'desc'}, group: { role: '' } }, { dataset: dataset }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Asset Management', data: [ { "name": 'Young', "role": 'Asset Management' }, { "name": 'Jennings', "role": 'Asset Management' } ] }, { $hideRows: false, value: 'Finances', data: [ { "name": 'Willis', "role": 'Finances' }, { "name": 'Mcdonald', "role": 'Finances' } ] } ]); }); it('should use group function to group data', function () { var grouper = function (item) { return item.name[0]; }; grouper.sortDirection = ''; var tp = createNgTableParams({ count: 2, sorting: {name: 'desc'}, group: grouper }, {dataset: dataset}); var actualRoleGroups; tp.reload().then(function (groups) { actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Y', data: [ { "name": "Young", "role": "Asset Management" } ] }, { $hideRows: false, value: 'W', data: [ { "name": "Willis", "role": "Finances" }, { "name": "Whitney", "role": "Accounting" }, { "name": "Wells", "role": "Media Relations" }, { "name": "Weaver", "role": "Payroll" } ] } ]); }); it('should filter and sort data, then group, then page groups', function () { var tp = createNgTableParams({ count: 2, sorting: { name: 'desc' }, filter: { name: 'e' }, group: { role: '' } }, { dataset: dataset }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Accounting', data: [ { 'name': 'Whitney', 'role': 'Accounting' }, { 'name': 'George', 'role': 'Accounting' } ] }, { $hideRows: false, value: 'Media Relations', data: [ { 'name': 'Wells', 'role': 'Media Relations' } ] } ]); }); it('should filter and sort data, then group, then apply group sortDirection, and finally page groups', function () { var tp = createNgTableParams({ count: 3, sorting: { name: 'desc' }, filter: { name: 'e' }, group: { role: 'desc' } }, { dataset: dataset, groupOptions: { // this value will be overridden by group: { role: 'desc' } defaultSort: undefined } }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Payroll', data: [ { 'name': 'Weaver', 'role': 'Payroll' } ] }, { $hideRows: false, value: 'Media Relations', data: [ { 'name': 'Wells', 'role': 'Media Relations' } ] }, { $hideRows: false, value: 'Customer Service', data: [ { 'name': 'Perry', 'role': 'Customer Service' }, { 'name': 'Eaton', 'role': 'Customer Service' } ] } ]); }); it('should use sortDirection defined on group function to sort groups', function () { var groupFn = function(item){ return item.role; }; groupFn.sortDirection = 'desc'; var tp = createNgTableParams({ count: 3, sorting: { name: 'desc' }, filter: { name: 'e' }, group: groupFn }, { dataset: dataset, groupOptions: { // this value will be overridden by groupFn.sortDirection defaultSort: undefined } }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Payroll', data: [ { 'name': 'Weaver', 'role': 'Payroll' } ] }, { $hideRows: false, value: 'Media Relations', data: [ { 'name': 'Wells', 'role': 'Media Relations' } ] }, { $hideRows: false, value: 'Customer Service', data: [ { 'name': 'Perry', 'role': 'Customer Service' }, { 'name': 'Eaton', 'role': 'Customer Service' } ] } ]); }); }); describe('getGroups with nested property', function(){ var dataset; beforeEach(function(){ dataset = [ { 'details': { 'name': 'Hanson', 'role': 'Accounting' } }, { 'details': { 'name': 'Eaton', 'role': 'Customer Service' } }, { 'details': { 'name': 'Perry', 'role': 'Customer Service' } }, { 'details': { 'name': 'George', 'role': 'Accounting' } }, { 'details': { 'name': 'Jennings', 'role': 'Asset Management' } }, { 'details': { 'name': 'Whitney', 'role': 'Accounting' } }, { 'details': { 'name': 'Weaver', 'role': 'Payroll' } }, { 'details': { 'name': 'Gibson', 'role': 'Payroll' } }, { 'details': { 'name': 'Wells', 'role': 'Media Relations' } }, { 'details': { 'name': 'Willis', 'role': 'Finances' } }, { 'details': { 'name': 'Donovan', 'role': 'Customer Relations' } }, { 'details': { 'name': 'Mcdonald', 'role': 'Finances' } }, { 'details': { 'name': 'Young', 'role': 'Asset Management' } } ]; }); it('should group data then apply paging to groups', function () { var tp = createNgTableParams({ count: 2, group: { 'details.role': '' } }, { dataset: dataset }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Accounting', data: [ { 'details': { 'name': 'Hanson', 'role': 'Accounting' } }, { 'details': { 'name': 'George', 'role': 'Accounting' } }, { 'details': { 'name': 'Whitney', 'role': 'Accounting' } } ] }, { $hideRows: false, value: 'Customer Service', data: [ { 'details': { 'name': 'Eaton', 'role': 'Customer Service' } }, { 'details': { 'name': 'Perry', 'role': 'Customer Service' } } ] } ]); }); it('should sort data, then group, then page groups', function () { var tp = createNgTableParams({ count: 2, sorting: { 'details.name': 'desc'}, group: { 'details.role': '' } }, { dataset: dataset }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Asset Management', data: [ { 'details': { 'name': 'Young', 'role': 'Asset Management' } }, { 'details': { 'name': 'Jennings', 'role': 'Asset Management' } } ] }, { $hideRows: false, value: 'Finances', data: [ { 'details': { 'name': 'Willis', 'role': 'Finances' } }, { 'details': { 'name': 'Mcdonald', 'role': 'Finances' } } ] } ]); }); it('should use group function to group data', function () { var grouper = function (item) { return item.details.name[0]; }; grouper.sortDirection = ''; var tp = createNgTableParams({ count: 2, sorting: {'details.name': 'desc'}, group: grouper }, {dataset: dataset}); var actualRoleGroups; tp.reload().then(function (groups) { actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Y', data: [ { 'details': { 'name': 'Young', 'role': 'Asset Management' } } ] }, { $hideRows: false, value: 'W', data: [ { 'details': { 'name': 'Willis', 'role': 'Finances' } }, { 'details': { 'name': 'Whitney', 'role': 'Accounting' } }, { 'details': { 'name': 'Wells', 'role': 'Media Relations' } }, { 'details': { 'name': 'Weaver', 'role': 'Payroll' } } ] } ]); }); it('should filter and sort data, then group, then page groups', function () { var tp = createNgTableParams({ count: 2, sorting: { 'details.name': 'desc' }, filter: { 'details.name': 'e' }, group: { 'details.role': '' } }, { dataset: dataset }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Accounting', data: [ { 'details': { 'name': 'Whitney', 'role': 'Accounting' } }, { 'details': { 'name': 'George', 'role': 'Accounting' } } ] }, { $hideRows: false, value: 'Media Relations', data: [ { 'details': { 'name': 'Wells', 'role': 'Media Relations' } } ] } ]); }); it('should filter and sort data, then group, then apply group sortDirection, and finally page groups', function () { var tp = createNgTableParams({ count: 3, sorting: { 'details.name': 'desc' }, filter: { 'details.name': 'e' }, group: { 'details.role': 'desc' } }, { dataset: dataset, groupOptions: { // this value will be overridden by group: { role: 'desc' } defaultSort: undefined } }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Payroll', data: [ { 'details': { 'name': 'Weaver', 'role': 'Payroll' } } ] }, { $hideRows: false, value: 'Media Relations', data: [ { 'details': { 'name': 'Wells', 'role': 'Media Relations' } } ] }, { $hideRows: false, value: 'Customer Service', data: [ { 'details': { 'name': 'Perry', 'role': 'Customer Service' } }, { 'details': { 'name': 'Eaton', 'role': 'Customer Service' } } ] } ]); }); it('should use sortDirection defined on group function to sort groups', function () { var groupFn = function(item){ return item.details.role; }; groupFn.sortDirection = 'desc'; var tp = createNgTableParams({ count: 3, sorting: { 'details.name': 'desc' }, filter: { 'details.name': 'e' }, group: groupFn }, { dataset: dataset, groupOptions: { // this value will be overridden by groupFn.sortDirection defaultSort: undefined } }); var actualRoleGroups; tp.reload().then(function(groups){ actualRoleGroups = groups; }); $rootScope.$digest(); expect(actualRoleGroups).toEqual([ { $hideRows: false, value: 'Payroll', data: [ { 'details': { 'name': 'Weaver', 'role': 'Payroll' } } ] }, { $hideRows: false, value: 'Media Relations', data: [ { 'details': { 'name': 'Wells', 'role': 'Media Relations' } } ] }, { $hideRows: false, value: 'Customer Service', data: [ { 'details': { 'name': 'Perry', 'role': 'Customer Service' } }, { 'details': { 'name': 'Eaton', 'role': 'Customer Service' } } ] } ]); }); }); it('ngTableParams test defaults', inject(function ($q, ngTableDefaults) { ngTableDefaults.params.count = 2; ngTableDefaults.settings.counts = []; var tp = new NgTableParams(); expect(tp.count()).toEqual(2); expect(tp.page()).toEqual(1); var settings = tp.settings(); expect(settings.counts.length).toEqual(0); expect(settings.interceptors.length).toEqual(0); expect(settings.filterOptions.filterDelay).toEqual(500); ngTableDefaults.settings.interceptors = [ { response: angular.identity }]; tp = new NgTableParams(); expect(tp.settings().interceptors.length).toEqual(1); })); describe('hasFilter', function(){ var tp; beforeEach(inject(function(){ tp = new NgTableParams({}, {}); })); it('should return false for an empty filter object', function(){ tp.filter({}); expect(tp.hasFilter()).toBe(false); }); it('should return true for when filter has a field with a significant value', function(){ tp.filter({ a: 'b' }); expect(tp.hasFilter()).toBe(true); tp.filter({ a: 0 }); expect(tp.hasFilter()).toBe(true); }); it('should return false when filter only has insignificant field values', function(){ tp.filter({ a: '' }); expect(tp.hasFilter()).toBe(false); tp.filter({ a: null }); expect(tp.hasFilter()).toBe(false); tp.filter({ a: undefined }); expect(tp.hasFilter()).toBe(false); tp.filter({ a: undefined, b: '', c: undefined }); expect(tp.hasFilter()).toBe(false); //tp.filter({ a: NaN }); //expect(tp.hasFilter()).toBe(false); }); }); describe('isDataReloadRequired', function(){ var tp; beforeEach(inject(function(){ tp = createNgTableParams(); })); it('should return true after construction', function(){ expect(tp.isDataReloadRequired()).toBe(true); }); it('should return false once reload called after construction', function(){ tp.reload(); // note: we don't have to wait for the getData promise to be resolved before considering reload // to be unnecessary - that's why we're not having to run a $digest expect(tp.isDataReloadRequired()).toBe(false); }); it('should return false when getData fails', inject(function($q){ tp.settings({ getData: function(){ return $q.reject('bad response'); }}); tp.reload(); scope.$digest(); expect(tp.isDataReloadRequired()).toBe(false); })); it('should detect direct changes to parameters', inject(function($q){ // given tp.reload(); scope.$digest(); expect(tp.isDataReloadRequired()).toBe(false); // checking assumptions // when tp.filter().newField = 99; expect(tp.isDataReloadRequired()).toBe(true); })); it('should return true until changed parameters have been reloaded', function(){ // given tp.reload(); scope.$digest(); // when, then... verifyIsDataReloadRequired(function(){ tp.filter({ age: 1}); }); verifyIsDataReloadRequired(function(){ tp.page(55); }); verifyIsDataReloadRequired(function(){ tp.sorting({ age: 'desc'}); }); verifyIsDataReloadRequired(function(){ tp.count(100); }); }); it('should return true when `$` field on `filter` changes', function(){ // given tp.reload(); scope.$digest(); expect(tp.isDataReloadRequired()).toBe(false); // checking assumptions // when tp.filter().$ = 'cc'; expect(tp.isDataReloadRequired()).toBe(true); }); it('should return true when group function sort direction changes', function(){ // given tp.reload(); scope.$digest(); expect(tp.isDataReloadRequired()).toBe(false); // checking assumptions // when, then... var grouper = function(){ }; tp.group(grouper); expect(tp.isDataReloadRequired()).toBe(true); tp.reload(); scope.$digest(); expect(tp.isDataReloadRequired()).toBe(false); grouper.sortDirection = 'desc'; expect(tp.isDataReloadRequired()).toBe(true); }); it('should return false when parameters "touched" but not modified', function(){ // given tp.filter({ age: 1}); tp.reload(); scope.$digest(); // when, then... tp.filter({ age: 1}); expect(tp.isDataReloadRequired()).toBe(false); }); it('should return true when new settings dataset array supplied', function(){ // given tp.reload(); scope.$digest(); verifyIsDataReloadRequired(function(){ tp.settings({ dataset: [11,22,33]}); }); }); it('should return true when existing settings dataset array is unset', function(){ // given tp = createNgTableParams({ dataset: [1,2,3]}); tp.reload(); scope.$digest(); verifyIsDataReloadRequired(function(){ tp.settings({ dataset: null}); }); }); it('status should not change when settings called without a dataset array', function(){ // given tp = createNgTableParams({ dataset: [1,2,3]}); tp.reload(); scope.$digest(); // when, then... tp.settings({ total : 100 }); expect(tp.isDataReloadRequired()).toBe(false); }); function verifyIsDataReloadRequired(modifer){ modifer(); expect(tp.isDataReloadRequired()).toBe(true); tp.reload(); scope.$digest(); expect(tp.isDataReloadRequired()).toBe(false); } }); describe('hasFilterChanges', function(){ var tp; beforeEach(inject(function(){ tp = createNgTableParams(); })); it('should return true after construction', function(){ expect(tp.hasFilterChanges()).toBe(true); }); it('should return false once reload called after construction', function(){ tp.reload(); // note: we don't have to wait for the getData promise to be resolved before considering reload // to be unnecessary - that's why we're not having to run a $digest expect(tp.hasFilterChanges()).toBe(false); }); it('should return true when getData fails', inject(function($q){ tp.settings({ getData: function(){ return $q.reject('bad response'); }}); tp.reload(); scope.$digest(); expect(tp.hasFilterChanges()).toBe(false); })); it('should detect direct changes to filters', inject(function($q){ // given tp.reload(); scope.$digest(); expect(tp.hasFilterChanges()).toBe(false); // checking assumptions // when tp.filter().newField = 99; expect(tp.hasFilterChanges()).toBe(true); })); it('should return true when `$` field on `filter` changes', function(){ // given tp.reload(); scope.$digest(); expect(tp.hasFilterChanges()).toBe(false); // checking assumptions // when tp.filter().$ = 'cc'; expect(tp.hasFilterChanges()).toBe(true); }); it('should return true until changed filters have been reloaded', function(){ // given tp.reload(); scope.$digest(); // when, then... tp.filter({ age: 1}); expect(tp.hasFilterChanges()).toBe(true); tp.reload(); scope.$digest(); expect(tp.hasFilterChanges()).toBe(false); }); it('should return false when filters "touched" but not modified', function(){ // given tp.filter({ age: 1}); tp.reload(); scope.$digest(); // when, then... tp.filter({ age: 1}); expect(tp.hasFilterChanges()).toBe(false); }); it('status should not change just because new settings dataset array supplied', function(){ // given tp.reload(); scope.$digest(); // when, then... tp.settings({ dataset: [11,22,33]}); expect(tp.hasFilterChanges()).toBe(false); }); }); describe('hasErrorState', function(){ var tp; it('should return false until reload fails', inject(function($q){ // given tp = createNgTableParams({ getData: function(){ if (tp.settings().getData.calls.count() > 2){ return $q.reject('bad response'); } return [1,2]; }}); // when, then tp.reload(); scope.$digest(); expect(tp.hasErrorState()).toBe(false); tp.reload(); scope.$digest(); expect(tp.hasErrorState()).toBe(false); tp.reload(); scope.$digest(); expect(tp.hasErrorState()).toBe(true); })); it('should return false once parameter values change', inject(function($q){ // given tp = createNgTableParams({ getData: function(){ return $q.reject('bad response'); }}); // when, then tp.reload(); scope.$digest(); expect(tp.hasErrorState()).toBe(true); tp.filter({ age: 598}); expect(tp.hasErrorState()).toBe(false); })); }); describe('backwards compatibility shim', function(){ it('shim should supply getData original arguments', inject(function(ngTableGetDataBcShim){ // given var callCount = 0; var adaptedFn = ngTableGetDataBcShim(originalGetDataFn); // when var tableParams = new NgTableParams({}, {}); adaptedFn(tableParams); // then expect(callCount).toBe(1); function originalGetDataFn($defer, params){ callCount++; expect($defer).toBeDefined(); expect($defer.resolve).toBeDefined(); expect(params).toBeDefined(); expect(params).toEqual(jasmine.any(NgTableParams)); } })); it('shim should return the getData "$defer" promise', inject(function(ngTableGetDataBcShim){ // given var callCount = 0; var adaptedFn = ngTableGetDataBcShim(originalGetDataFn); // when var tableParams = new NgTableParams({}, {}); var results = adaptedFn(tableParams); // then expect(results).toBeDefined(); expect(results.then).toBeDefined(); results.then(function(data){ expect(data.length).toBe(3); }); scope.$digest(); function originalGetDataFn($defer/*, params*/){ $defer.resolve([1,2,3]); } })); it('shim should return the data', inject(function(ngTableGetDataBcShim){ // given var callCount = 0; var adaptedFn = ngTableGetDataBcShim(originalGetDataFn); // when var tableParams = new NgTableParams({}, {}); var results = adaptedFn(tableParams); // then expect(results).toBeDefined(); expect(results).toEqual([1,2,3]); function originalGetDataFn(/*$defer, params*/){ return [1,2,3]; } })); it('shim should be applied when getData function supplied has more than one parameter', function(){ // given var tp = createNgTableParams({ getData: originalGetDataFn}); // when var dataFetched = tp.reload(); // then var actualData; dataFetched.then(function(data){ actualData = data; }); scope.$digest(); expect(actualData).toEqual([1,2,3]); function originalGetDataFn($defer, params){ params.total(3); $defer.resolve([1,2,3]); } }); it('shim should NOT be applied when getData has new signature', function(){ // given var tp = createNgTableParams({ getData: newGetDataFn}); // when var dataFetched = tp.reload(); // then var actualData; dataFetched.then(function(data){ actualData = data; }); scope.$digest(); expect(actualData).toEqual([1,2,3]); function newGetDataFn(params){ params.total(3); return [1,2,3]; } }); }); describe('interceptors', function(){ it('can register interceptor', function(){ var interceptor = { response: angular.identity }; var tp = createNgTableParams({ interceptors: [interceptor]}); expect(tp.settings().interceptors).toEqual([interceptor]); }); it('can register multiple interceptor', function(){ var interceptors = [{ response: angular.identity }, { response: angular.identity }]; var tp = createNgTableParams({ interceptors: interceptors}); expect(tp.settings().interceptors).toEqual(interceptors); }); it('can register interceptors after NgTableParams created', function(){ var interceptor = { response: angular.identity }; var interceptor2 = { response: angular.identity }; var tp = createNgTableParams({ interceptors: [interceptor]}); var interceptors = tp.settings().interceptors.concat([interceptor2]); tp.settings({ interceptors: interceptors}); expect(tp.settings().interceptors).toEqual(interceptors); }); describe('one response interceptor', function(){ it('should receive response from call to getData', function(){ // given var interceptor = { response: function(/*data, params*/){ this.hasRun = true; } }; var tp = createNgTableParams({ interceptors: [interceptor]}); // when tp.reload(); scope.$digest(); // then expect(interceptor.hasRun).toBeTruthy(); }); it('should be able to modify data returned by getData', function(){ // given var interceptor = { response: function(data/*, params*/){ data.forEach(function(item){ item.modified = true; }); return data; } }; var tp = createNgTableParams({ interceptors: [interceptor], getData: function(){ return [{}, {}]; }}); // when var actualData; tp.reload().then(function(data){ actualData = data; }); scope.$digest(); // then expect(actualData).toEqual([{ modified: true }, { modified: true }]); }); it('should be able to replace data returned by getData', function(){ // given var interceptor = { response: function(data/*, params*/){ return data.map(function(item){ return item * 2; }); } }; var tp = createNgTableParams({ interceptors: [interceptor], getData: function(){ return [2, 3]; }}); // when var actualData; tp.reload().then(function(data){ actualData = data; }); scope.$digest(); // then expect(actualData).toEqual([4, 6]); }); it('should be able to access tableParams supplied to getData', function(){ // given var interceptor = { response: function(data, params){ params.total(data.total); return data.results; } }; var tp = createNgTableParams({ interceptors: [interceptor], getData: function(){ return { results: [1,2,3], total: 3}; }}); // when var actualData; tp.reload().then(function(data){ actualData = data; }); scope.$digest(); // then expect(actualData).toEqual([1,2,3]); expect(tp.total()).toEqual(3); }); }); describe('one responseError interceptor', function(){ it('should receive rejections from getData', inject(function($q){ // given var interceptor = { responseError: function(reason/*, params*/){ this.actualReason = reason; } }; var tp = createNgTableParams({ interceptors: [interceptor], getData: function(/*params*/){ return $q.reject('BANG!'); } }); // when tp.reload(); scope.$digest(); // then expect(interceptor.actualReason).toBe('BANG!'); })); it('should NOT receive errors from getData', function(){ // given var interceptor = { responseError: function(/*reason, params*/){ this.hasRun = true; } }; var tp = createNgTableParams({ interceptors: [interceptor], getData: function(/*params*/){ throw new Error('BANG!'); } }); // when, then expect(tp.reload).toThrow(); expect(interceptor.hasRun).toBeFalsy(); }); it('should be able to modify reason returned by getData', inject(function($q){ // given var interceptor = { responseError: function(reason/*, params*/){ reason.code = 400; return $q.reject(reason); } }; var tp = createNgTableParams({ interceptors: [interceptor], getData: function(/*params*/){ return $q.reject({ description: 'crappy data'}); } }); // when var actualReason; tp.reload().catch(function(reason){ actualReason = reason; }); scope.$digest(); // then expect(actualReason.code).toBe(400); expect(actualReason.description).toBe('crappy data'); })); it('should be able to replace reason returned by getData', inject(function($q){ // given var interceptor = { responseError: function(/*reason, params*/){ return $q.reject('Cancelled by user'); } }; var tp = createNgTableParams({ interceptors: [interceptor], getData: function(/*params*/){ return $q.reject('BANG!'); } }); // when var actualReason; tp.reload().catch(function(reason){ actualReason = reason; }); scope.$digest(); // then expect(actualReason).toBe('Cancelled by user'); })); it('should be able to access tableParams supplied to getData', function(){ // given var interceptor = { response: function(reason, params){ this.actualParams = params; } }; var tp = createNgTableParams({ interceptors: [interceptor]}); // when var actualData; tp.reload(); scope.$digest(); // then expect(interceptor.actualParams).toBe(tp); }); }); describe('one response plus responseError interceptor', function(){ it('should NOT call responseError on same interceptor whose response method fails', inject(function($q){ // given var interceptor = { response: function(/*data, params*/){ return $q.reject('BANG!'); }, responseError: function(reason/*, params*/){ this.hasRun = true; } }; var tp = createNgTableParams({ interceptors: [interceptor], getData: function(/*params*/){ return [1,2,3]; } }); // when tp.reload(); scope.$digest(); // then expect(interceptor.hasRun).toBeFalsy(); })); }); describe('multiple response interceptors', function(){ it('should run interceptors in the order they were registered', function(){ // given var callCount = 0; var interceptor = { response: function(/*data, params*/){ this.sequence = callCount; callCount++; } }; var interceptors = [interceptor, angular.copy(interceptor)]; var tp = createNgTableParams({ interceptors: interceptors}); // when tp.reload(); scope.$digest(); // then expect(interceptors[0].sequence).toBe(0); expect(interceptors[1].sequence).toBe(1); }); it('results of one interceptor should be piped to the next validator', function(){ // given var interceptor = { response: function(data/*, params*/){ return data.map(function(item){ return item * 2; }); } }; var interceptor2 = { response: function(data/*, params*/){ return data.map(function(item){ return item.toString() + '0'; }); } }; var tp = createNgTableParams({ interceptors: [interceptor, interceptor2], getData: function(){ return [2, 3]; }}); // when var actualData; tp.reload().then(function(data){ actualData = data; }); scope.$digest(); // then expect(actualData).toEqual(['40', '60']); }); }); describe('multiple response and responseError interceptors', function(){ it('responseError of next interceptor should receive failures from previous interceptor', inject(function($q){ // given var badInterceptor = { response: function(/*data, params*/){ return $q.reject('BANG!'); } }; var nextInterceptor = { responseError: function(/*reason, params*/){ this.hasRun = true; } }; var tp = createNgTableParams({ interceptors: [badInterceptor, nextInterceptor]}); // when tp.reload(); scope.$digest(); // then expect(nextInterceptor.hasRun).toBe(true); })); it('should call next response interceptor when previous interceptor recovers from failure', inject(function($q){ // given var badInterceptor = { response: function(/*data, params*/){ return $q.reject('BANG!'); } }; var recoveringInterceptor = { responseError: function(/*reason, params*/){ return [8894,58]; } }; var recoveredData; var nextInterceptor = { response: function(data/*, params*/){ this.hasRun = true; recoveredData = data; } }; var tp = createNgTableParams({ interceptors: [badInterceptor, recoveringInterceptor, nextInterceptor]}); // when tp.reload(); scope.$digest(); // then expect(nextInterceptor.hasRun).toBe(true); expect(recoveredData).toEqual([8894,58]); })); }); }); describe('events', function(){ var actualEventArgs, actualPublisher, fakeTableParams, ngTableEventsChannel; beforeEach(inject(function(_ngTableEventsChannel_){ ngTableEventsChannel = _ngTableEventsChannel_; fakeTableParams = {}; actualPublisher = undefined; actualEventArgs = undefined; })); function getSubscriberCount(){ var allEventNames = Object.keys($rootScope.$$listenerCount); var ngTableEvents = allEventNames.filter(function(event){ return event.indexOf('ngTable:') === 0; }); return ngTableEvents.reduce(function(result, event){ result += $rootScope.$$listenerCount[event]; return result; }, 0); } describe('general pub/sub mechanics', function(){ var supportedEvents = ['DatasetChanged', 'AfterReloadData', 'PagesChanged', 'AfterCreated']; it('should be safe to publish event when no subscribers', function () { function test(event) { ngTableEventsChannel['publish' + event](fakeTableParams); } supportedEvents.forEach(test); }); it('publishing event should notify registered subscribers (one)', function(){ function test(event){ // given var cbCount = 0; ngTableEventsChannel['on' + event](function(){ cbCount++; }); // when ngTableEventsChannel['publish' + event](fakeTableParams); // then expect(cbCount).toBe(1); } supportedEvents.forEach(test); }); it('publishing event should notify registered subscribers (multiple)', function(){ function test(event){ // given var cb1Count = 0; ngTableEventsChannel['on' + event](function(){ cb1Count++; }); var cb2Count = 0; ngTableEventsChannel['on' + event](function(){ cb2Count++; }); // when ngTableEventsChannel['publish' + event](fakeTableParams); // then expect(cb1Count).toBe(1); expect(cb2Count).toBe(1); } supportedEvents.forEach(test); }); it('subscriber should be able to unregister their callback', function(){ function test(event){ // given var cbCount = 0; var subscription = ngTableEventsChannel['on' + event](function(){ cbCount++; }); ngTableEventsChannel['publish' + event](fakeTableParams); expect(cbCount).toBe(1); // checking assumptions expect(getSubscriberCount()).toBe(1); // checking assumptions cbCount = 0; // reset // when subscription(); // unsubscribe ngTableEventsChannel['publish' + event](fakeTableParams); // then expect(cbCount).toBe(0); expect(getSubscriberCount()).toBe(0); } supportedEvents.forEach(test); }); it('subscriber should be able specify the scope to receive events', function(){ // this is useful as it allows all subscriptions to be removed by calling $destroy on that scope function test(event){ // given var childScope = $rootScope.$new(); var cbCount = 0; ngTableEventsChannel['on' + event](function(){ cbCount++; }, childScope); // when, then ngTableEventsChannel['publish' + event](fakeTableParams); expect(cbCount).toBe(1); cbCount = 0; // reset // when, then childScope.$destroy(); ngTableEventsChannel['publish' + event](fakeTableParams); // then expect(cbCount).toBe(0); } supportedEvents.forEach(test); }); it('should not notify subscribers who have filter out the publisher', function(){ function test(event){ // given var cbCount = 0; ngTableEventsChannel['on' + event](function(){ cbCount++; }, function(publisher){ return publisher === fakeTableParams; }); // when ngTableEventsChannel['publish' + event](fakeTableParams); var anoParams = {}; ngTableEventsChannel['publish' + event](anoParams); // then expect(cbCount).toBe(1); } supportedEvents.forEach(test); }); it('should not notify subscribers who have filter not to receive event based on arg values', function(){ function test(event){ // given var cbCount = 0; ngTableEventsChannel['on' + event](function(){ cbCount++; }, function(publisher, arg1){ return arg1 === 1; }); // when ngTableEventsChannel['publish' + event](fakeTableParams, 'cc'); ngTableEventsChannel['publish' + event](fakeTableParams, 1); // then expect(cbCount).toBe(1); } supportedEvents.forEach(test); }); it('should support a shorthand for subscribers to receive events from specific NgTableParams instance', function () { function test(event) { // given var cbCount = 0; ngTableEventsChannel['on' + event](function () { cbCount++; }, fakeTableParams); // when ngTableEventsChannel['publish' + event](fakeTableParams); var anoParams = {}; ngTableEventsChannel['publish' + event](anoParams); // then expect(cbCount).toBe(1); } supportedEvents.forEach(test); }); it('publisher should be supplied to subscriber callback', function(){ function test(event){ // given var cbCount = 0; ngTableEventsChannel['on' + event](function(params){ actualPublisher = params; }); // when ngTableEventsChannel['publish' + event](fakeTableParams); // then expect(actualPublisher).toBe(fakeTableParams); } supportedEvents.forEach(test); }); it('remaining event args should be supplied to subscriber callback', function(){ function test(event){ // given ngTableEventsChannel['on' + event](function(params/*, ...args*/){ actualPublisher = params; actualEventArgs = _.rest(arguments); }); // when var arg1 = [1, 2]; var arg2 = [1]; ngTableEventsChannel['publish' + event](fakeTableParams, arg1, arg2); // then expect(actualEventArgs).toEqual([arg1, arg2]); } supportedEvents.forEach(test); }); it('subscribers should never receive events from null instance of tableParams', function(){ function test(event){ // given var cbCount = 0; ngTableEventsChannel['on' + event](function(params/*, ...args*/){ cbCount++; }); // when fakeTableParams.isNullInstance = true; ngTableEventsChannel['publish' + event](fakeTableParams); // then expect(cbCount).toEqual(0); } supportedEvents.forEach(test); }); }); describe('afterCreated', function(){ it('should fire when a new NgTableParams has been constructed', function(){ // given ngTableEventsChannel.onAfterCreated(function(params){ actualPublisher = params; }); // when var params = createNgTableParams(); // then expect(actualPublisher).toBe(params); }); }); describe('afterReloadData', function(){ it('should fire when a reload completes', function(){ // given ngTableEventsChannel.onAfterReloadData(function(params, newVal, oldVal){ actualPublisher = params; actualEventArgs = [newVal, oldVal]; }); var newDatapage = [1, 5, 6]; var params = createNgTableParams({ getData: function(){ return newDatapage; }}); // when params.reload(); scope.$digest(); // then expect(actualPublisher).toBe(params); expect(actualEventArgs).toEqual([newDatapage, []]); }); it('should fire on reload even if datapage remains the same array', function(){ // given var callCount = 0; ngTableEventsChannel.onAfterReloadData(function(/*params, newVal, oldVal*/){ callCount++; }); var dataPage = [1,2,3]; var params = createNgTableParams({ getData: function(){ return dataPage; }}); // when params.reload(); scope.$digest(); params.reload(); scope.$digest(); // then expect(callCount).toBe(2); }); it('should fire after afterCreated event', function(){ // given var events = []; ngTableEventsChannel.onAfterReloadData(function(/*params, newVal, oldVal*/){ events.push('afterReloadData'); }); ngTableEventsChannel.onAfterCreated(function(/*params*/){ events.push('afterCreated'); }); // when var params = createNgTableParams({}, {dataset: [1,2,3,4,5,6]}); params.reload(); scope.$digest(); // then expect(events[0]).toEqual('afterCreated'); expect(events[1]).toEqual('afterReloadData'); }); }); describe('pagesChanged', function(){ it('should fire when a reload completes', function(){ // given ngTableEventsChannel.onPagesChanged(function(params, newVal, oldVal){ actualPublisher = params; actualEventArgs = [newVal, oldVal]; }); var params = createNgTableParams({ count: 5 }, { counts: [5,10], dataset: [1,2,3,4,5,6]}); // when params.reload(); scope.$digest(); // then var expectedPages = params.generatePagesArray(params.page(), params.total(), params.count()); expect(expectedPages.length).toBeGreaterThan(0); // checking assumptions expect(actualEventArgs).toEqual([expectedPages, undefined]); }); it('should fire when a reload completes - no data', function(){ // given ngTableEventsChannel.onPagesChanged(function(params, newVal, oldVal){ actualPublisher = params; actualEventArgs = [newVal, oldVal]; }); var params = createNgTableParams({ count: 5 }, { counts: [5,10], dataset: []}); // when params.reload(); scope.$digest(); // then expect(actualEventArgs).toEqual([[], undefined]); }); it('should fire when a reload completes (multiple)', function(){ // given var callCount = 0; ngTableEventsChannel.onPagesChanged(function(/*params, newVal, oldVal*/){ callCount++; }); var params = createNgTableParams({ count: 5 }, { counts: [5,10], dataset: [1,2,3,4,5,6]}); // when params.reload(); scope.$digest(); params.page(2); // trigger a change to pages data structure params.reload(); scope.$digest(); // then expect(callCount).toBe(2); }); it('should not fire on reload when pages remain the same', function(){ // given var callCount = 0; ngTableEventsChannel.onPagesChanged(function(/*params, newVal, oldVal*/){ callCount++; }); var params = createNgTableParams({ count: 5 }, { counts: [5,10], dataset: [1,2,3,4,5,6]}); params.reload(); scope.$digest(); // when params.reload(); scope.$digest(); // then expect(callCount).toBe(1); }); it('should fire after afterCreated event', function(){ // given var events = []; ngTableEventsChannel.onPagesChanged(function(/*params, newVal, oldVal*/){ events.push('pagesChanged'); }); ngTableEventsChannel.onAfterCreated(function(/*params*/){ events.push('afterCreated'); }); // when var params = createNgTableParams({ count: 5 }, { counts: [5,10], dataset: [1,2,3,4,5,6]}); params.reload(); scope.$digest(); // then expect(events[0]).toEqual('afterCreated'); expect(events[1]).toEqual('pagesChanged'); }); }); describe('datasetChanged', function(){ it('should fire when a initial dataset is supplied as a settings value', function(){ // given ngTableEventsChannel.onDatasetChanged(function(params, newVal, oldVal){ actualPublisher = params; actualEventArgs = [newVal, oldVal]; }); // when var initialDs = [5, 10]; var params = createNgTableParams({ dataset: initialDs}); // then expect(actualPublisher).toBe(params); expect(actualEventArgs).toEqual([initialDs, null]); }); it('should fire when a new dataset is supplied as a settings value', function(){ // given var initialDs = [1, 2]; ngTableEventsChannel.onDatasetChanged(function(params, newVal, oldVal){ actualPublisher = params; actualEventArgs = [newVal, oldVal]; }); var params = createNgTableParams({ dataset: initialDs}); // when var newDs = [5, 10]; params.settings({ dataset: newDs}); // then expect(actualPublisher).toBe(params); expect(actualEventArgs).toEqual([newDs, initialDs]); }); it('should fire when a dataset is removed from settings value', function(){ // given var initialDs = [1, 2]; ngTableEventsChannel.onDatasetChanged(function(params, newVal, oldVal){ actualPublisher = params; actualEventArgs = [newVal, oldVal]; }); var params = createNgTableParams({ dataset: initialDs}); // when var newDs = null; params.settings({ dataset: newDs}); // then expect(actualPublisher).toBe(params); expect(actualEventArgs).toEqual([newDs, initialDs]); }); it('should NOT fire when the same dataset array is supplied as a new settings value', function(){ // given var callCount = 0; var initialDs = [1, 2]; ngTableEventsChannel.onDatasetChanged(function(/*params, newVal, oldVal*/){ callCount++; }); var params = createNgTableParams({ dataset: initialDs}); // when params.settings({ dataset: initialDs}); // then expect(callCount).toBe(1); }); it('settings().dataset on publisher should reference the new dataset', function(){ var initialDs = [1, 2]; var newDs = [1, 2, 3]; var params = createNgTableParams({ dataset: initialDs}); ngTableEventsChannel.onDatasetChanged(function(params, newVal/*, oldVal*/){ expect(params.settings().dataset).toBe(newVal); }); params.settings({ dataset: newDs}); }); it('should fire after afterCreated event', function(){ // given var events = []; var initialDs = [1, 2]; ngTableEventsChannel.onDatasetChanged(function(/*params, newVal, oldVal*/){ events.push('datasetChanged'); }); ngTableEventsChannel.onAfterCreated(function(/*params*/){ events.push('afterCreated'); }); // when var params = createNgTableParams({ dataset: initialDs}); // then expect(events[0]).toEqual('afterCreated'); expect(events[1]).toEqual('datasetChanged'); }); }); }) });