define([ 'jquery', 'URI', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers', 'edx-ui-toolkit/js/pagination/paging-collection', 'js/views/paging', 'js/views/paging_header' ], function($, URI, AjaxHelpers, PagingCollection, PagingView, PagingHeader) { 'use strict'; var createPageableItem = function(index) { var id = 'item_' + index; return { id: id, display_name: id, url: id }; }; var mockFirstPage = { results: [ createPageableItem(1), createPageableItem(2), createPageableItem(3) ], num_pages: 2, page_size: 3, count: 4, page: 0, start: 0 }; var mockSecondPage = { results: [ createPageableItem(4) ], num_pages: 2, page_size: 3, page: 1, count: 4, start: 3 }; var mockEmptyPage = { results: [], num_pages: 1, page_size: 3, count: 0, page: 0, start: 0 }; var respondWithMockItems = function(requests) { var request = AjaxHelpers.currentRequest(requests); var url = new URI(request.url); var queryParameters = url.query(true); // Returns an object with each query parameter stored as a value var page = queryParameters.page; var response = page === '0' ? mockFirstPage : mockSecondPage; AjaxHelpers.respondWithJson(requests, response); }; var MockPagingView = PagingView.extend({ renderPageItems: function() {}, initialize: function() { this.registerSortableColumn('name-col', 'Name', 'name', 'asc'); this.registerSortableColumn('date-col', 'Date', 'date', 'desc'); this.setInitialSortColumn('date-col'); } }); describe('Paging', function() { var pagingView, TestPagingCollection = PagingCollection.extend({ state: { firstPage: 0, currentPage: null, pageSize: 3 } }); beforeEach(function() { var collection = new TestPagingCollection(); collection.url = '/dummy/'; pagingView = new MockPagingView({collection: collection}); }); describe('PagingView', function() { describe('setPage', function() { it('can set the current page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); expect(pagingView.collection.getPageNumber()).toBe(1); pagingView.setPage(2); respondWithMockItems(requests); expect(pagingView.collection.getPageNumber()).toBe(2); }); it('should not change page after a server error', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); pagingView.setPage(2); requests[1].respond(500); /* PagingCollection sets the currentPage to the old page in case of failure */ expect(pagingView.collection.getPageNumber()).toBe(1); }); }); describe('nextPage', function() { it('does not move forward after a server error', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); pagingView.nextPage(); requests[1].respond(500); expect(pagingView.collection.getPageNumber()).toBe(1); }); it('can move to the next page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); pagingView.nextPage(); respondWithMockItems(requests); /* PagingCollection now returns the normalized page number; adds one if zero indexed */ expect(pagingView.collection.getPageNumber()).toBe(2); }); it('can not move forward from the final page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); pagingView.nextPage(); AjaxHelpers.expectNoRequests(requests); }); }); describe('previousPage', function() { it('can move back a page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); pagingView.previousPage(); respondWithMockItems(requests); expect(pagingView.collection.getPageNumber()).toBe(1); }); it('can not move back from the first page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); pagingView.previousPage(); AjaxHelpers.expectNoRequests(requests); }); it('does not move back after a server error', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); pagingView.previousPage(); requests[1].respond(500); expect(pagingView.collection.getPageNumber()).toBe(2); }); }); describe('toggleSortOrder', function() { it('can toggle direction of the current sort', function() { var requests = AjaxHelpers.requests(this); expect(pagingView.collection.sortDirection).toBe('desc'); pagingView.toggleSortOrder('date-col'); respondWithMockItems(requests); expect(pagingView.collection.sortDirection).toBe('asc'); pagingView.toggleSortOrder('date-col'); respondWithMockItems(requests); expect(pagingView.collection.sortDirection).toBe('desc'); }); it('sets the correct default sort direction for a column', function() { var requests = AjaxHelpers.requests(this); pagingView.toggleSortOrder('name-col'); respondWithMockItems(requests); expect(pagingView.sortDisplayName()).toBe('Name'); expect(pagingView.collection.sortDirection).toBe('asc'); pagingView.toggleSortOrder('date-col'); respondWithMockItems(requests); expect(pagingView.sortDisplayName()).toBe('Date'); expect(pagingView.collection.sortDirection).toBe('desc'); }); }); describe('sortableColumnInfo', function() { it('returns the registered info for a column', function() { pagingView.registerSortableColumn('test-col', 'Test Column', 'testField', 'asc'); var sortInfo = pagingView.sortableColumnInfo('test-col'); expect(sortInfo.displayName).toBe('Test Column'); expect(sortInfo.fieldName).toBe('testField'); expect(sortInfo.defaultSortDirection).toBe('asc'); }); it('throws an exception for an unregistered column', function() { expect(function() { pagingView.sortableColumnInfo('no-such-column'); }).toThrow(); }); }); }); describe('PagingHeader', function() { var pagingHeader; beforeEach(function() { pagingHeader = new PagingHeader({view: pagingView}); }); describe('Next page button', function() { beforeEach(function() { // Render the page and header so that they can react to events pagingView.render(); pagingHeader.render(); }); it('does not move forward if a server error occurs', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); pagingHeader.$('.next-page-link').click(); requests[1].respond(500); expect(pagingView.collection.state.currentPage).toBe(0); expect(pagingView.collection.getPageNumber()).toBe(1); }); it('can move to the next page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); pagingHeader.$('.next-page-link').click(); respondWithMockItems(requests); expect(pagingView.collection.getPageNumber()).toBe(2); }); it('should be enabled when there is at least one more page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); expect(pagingHeader.$('.next-page-link')).not.toHaveClass('is-disabled'); }); it('should be disabled on the final page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); expect(pagingHeader.$('.next-page-link')).toHaveClass('is-disabled'); }); it('should be disabled on an empty page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingHeader.$('.next-page-link')).toHaveClass('is-disabled'); }); }); describe('Previous page button', function() { beforeEach(function() { // Render the page and header so that they can react to events pagingView.render(); pagingHeader.render(); }); it('does not move back if a server error occurs', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); pagingHeader.$('.previous-page-link').click(); requests[1].respond(500); expect(pagingView.collection.getPageNumber()).toBe(2); }); it('can go back a page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); pagingHeader.$('.previous-page-link').click(); respondWithMockItems(requests); expect(pagingView.collection.getPageNumber()).toBe(1); }); it('should be disabled on the first page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); expect(pagingHeader.$('.previous-page-link')).toHaveClass('is-disabled'); }); it('should be enabled on the second page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); expect(pagingHeader.$('.previous-page-link')).not.toHaveClass('is-disabled'); }); it('should be disabled for an empty page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingHeader.$('.previous-page-link')).toHaveClass('is-disabled'); }); }); describe('Page metadata section', function() { it('shows the correct metadata for the current page', function() { var requests = AjaxHelpers.requests(this), message; pagingView.setPage(1); respondWithMockItems(requests); message = pagingHeader.$('.meta').html().trim(); expect(message).toBe('

Showing 1-3' + ' out of 4 total, ' + 'sorted by Date descending

'); }); it('shows the correct metadata when sorted ascending', function() { var requests = AjaxHelpers.requests(this), message; pagingView.setPage(1); pagingView.toggleSortOrder('name-col'); respondWithMockItems(requests); message = pagingHeader.$('.meta').html().trim(); expect(message).toBe('

Showing 1-3' + ' out of 4 total, ' + 'sorted by Name ascending

'); }); }); describe('Item count label', function() { it('should show correct count on first page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); expect(pagingHeader.$('.count-current-shown')).toHaveHtml('1-3'); }); it('should show correct count on second page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); expect(pagingHeader.$('.count-current-shown')).toHaveHtml('4-4'); }); it('should show correct count for an empty collection', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingHeader.$('.count-current-shown')).toHaveHtml('0-0'); }); }); describe('Item total label', function() { it('should show correct total on the first page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); expect(pagingHeader.$('.count-total')).toHaveText('4 total'); }); it('should show correct total on the second page', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(2); respondWithMockItems(requests); expect(pagingHeader.$('.count-total')).toHaveText('4 total'); }); it('should show zero total for an empty collection', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingHeader.$('.count-total')).toHaveText('0 total'); }); }); describe('Sort order label', function() { it('should show correct initial sort order', function() { var requests = AjaxHelpers.requests(this); pagingView.setPage(1); respondWithMockItems(requests); expect(pagingHeader.$('.sort-order')).toHaveText('Date'); }); it('should show updated sort order', function() { var requests = AjaxHelpers.requests(this); pagingView.toggleSortOrder('name-col'); respondWithMockItems(requests); expect(pagingHeader.$('.sort-order')).toHaveText('Name'); }); }); }); }); });