define(['jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers', 'URI', 'js/models/xblock_info', 'js/views/paged_container', 'js/views/paging_header', 'common/js/components/views/paging_footer', 'js/views/xblock'], function($, _, AjaxHelpers, URI, XBlockInfo, PagedContainer, PagingHeader, PagingFooter, XBlockView) { var htmlResponseTpl = _.template('' + '
' ); function getResponseHtml(override_options) { var default_options = { start: 0, displayed: PAGE_SIZE, total: PAGE_SIZE + 1, previews: true }; var options = _.extend(default_options, override_options); return '
' + '
' + htmlResponseTpl(options) + '' + '
'; } var makePage = function(html_parameters) { return { resources: [], html: getResponseHtml(html_parameters) }; }; var PAGE_SIZE = 3; var mockFirstPage = makePage({ start: 0, displayed: PAGE_SIZE, total: PAGE_SIZE + 1 }); var mockSecondPage = makePage({ start: PAGE_SIZE, displayed: 1, total: PAGE_SIZE + 1 }); var mockEmptyPage = makePage({ start: 0, displayed: 0, total: 0 }); var respondWithMockPage = function(requests, mockPage) { var request = AjaxHelpers.currentRequest(requests); if (typeof mockPage === 'undefined') { 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_number; mockPage = page === '0' ? mockFirstPage : mockSecondPage; } AjaxHelpers.respondWithJson(requests, mockPage); }; var MockPagingView = PagedContainer.extend({ view: 'container_preview', el: $("
"), model: new XBlockInfo({}, {parse: true}) }); describe('Paging Container', function() { var pagingContainer; beforeEach(function() { pagingContainer = new MockPagingView({ page_size: PAGE_SIZE, page: jasmine.createSpyObj('page', ['updatePreviewButton', 'renderAddXBlockComponents']) }); }); describe('Container', function() { describe('rendering', function() { it('should set show_previews', function() { var requests = AjaxHelpers.requests(this); expect(pagingContainer.collection.showChildrenPreviews).toBe(true); // precondition check pagingContainer.setPage(0); respondWithMockPage(requests, makePage({previews: false})); expect(pagingContainer.collection.showChildrenPreviews).toBe(false); pagingContainer.setPage(0); respondWithMockPage(requests, makePage({previews: true})); expect(pagingContainer.collection.showChildrenPreviews).toBe(true); }); }); describe('setPage', function() { it('can set the current page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.collection.currentPage).toBe(0); pagingContainer.setPage(1); respondWithMockPage(requests); expect(pagingContainer.collection.currentPage).toBe(1); }); it('should not change page after a server error', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.setPage(1); requests[1].respond(500); expect(pagingContainer.collection.currentPage).toBe(0); }); }); describe('nextPage', function() { it('does not move forward after a server error', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.nextPage(); requests[1].respond(500); expect(pagingContainer.collection.currentPage).toBe(0); }); it('can move to the next page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.nextPage(); respondWithMockPage(requests); expect(pagingContainer.collection.currentPage).toBe(1); }); it('can not move forward from the final page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); pagingContainer.nextPage(); AjaxHelpers.expectNoRequests(requests); }); }); describe('previousPage', function() { it('can move back a page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); pagingContainer.previousPage(); respondWithMockPage(requests); expect(pagingContainer.collection.currentPage).toBe(0); }); it('can not move back from the first page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.previousPage(); AjaxHelpers.expectNoRequests(requests); }); it('does not move back after a server error', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); pagingContainer.previousPage(); requests[1].respond(500); expect(pagingContainer.collection.currentPage).toBe(1); }); }); }); describe('PagingHeader', function() { describe('Next page button', function() { beforeEach(function() { pagingContainer.render(); }); it('does not move forward if a server error occurs', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.pagingHeader.$('.next-page-link').click(); requests[1].respond(500); expect(pagingContainer.collection.currentPage).toBe(0); }); it('can move to the next page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.pagingHeader.$('.next-page-link').click(); respondWithMockPage(requests); expect(pagingContainer.collection.currentPage).toBe(1); }); it('should be enabled when there is at least one more page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingHeader.$('.next-page-link')).not.toHaveClass('is-disabled'); }); it('should be disabled on the final page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); expect(pagingContainer.pagingHeader.$('.next-page-link')).toHaveClass('is-disabled'); }); it('should be disabled on an empty page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingContainer.pagingHeader.$('.next-page-link')).toHaveClass('is-disabled'); }); }); describe('Previous page button', function() { beforeEach(function() { pagingContainer.render(); }); it('does not move back if a server error occurs', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); pagingContainer.pagingHeader.$('.previous-page-link').click(); requests[1].respond(500); expect(pagingContainer.collection.currentPage).toBe(1); }); it('can go back a page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); pagingContainer.pagingHeader.$('.previous-page-link').click(); respondWithMockPage(requests); expect(pagingContainer.collection.currentPage).toBe(0); }); it('should be disabled on the first page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingHeader.$('.previous-page-link')).toHaveClass('is-disabled'); }); it('should be enabled on the second page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); expect(pagingContainer.pagingHeader.$('.previous-page-link')).not.toHaveClass('is-disabled'); }); it('should be disabled for an empty page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingContainer.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; pagingContainer.setPage(0); respondWithMockPage(requests); message = pagingContainer.pagingHeader.$('.meta').html().trim(); expect(message).toBe('

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

'); }); }); describe('Children count label', function() { it('should show correct count on first page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingHeader.$('.count-current-shown')).toHaveHtml('1-3'); }); it('should show correct count on second page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); expect(pagingContainer.pagingHeader.$('.count-current-shown')).toHaveHtml('4-4'); }); it('should show correct count for an empty collection', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingContainer.pagingHeader.$('.count-current-shown')).toHaveHtml('0-0'); }); }); describe('Children total label', function() { it('should show correct total on the first page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingHeader.$('.count-total')).toHaveText('4 total'); }); it('should show correct total on the second page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); expect(pagingContainer.pagingHeader.$('.count-total')).toHaveText('4 total'); }); it('should show zero total for an empty collection', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingContainer.pagingHeader.$('.count-total')).toHaveText('0 total'); }); }); }); describe('PagingFooter', function() { describe('Next page button', function() { beforeEach(function() { // Render the page and header so that they can react to events pagingContainer.render(); }); it('does not move forward if a server error occurs', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.pagingFooter.$('.next-page-link').click(); requests[1].respond(500); expect(pagingContainer.collection.currentPage).toBe(0); }); it('can move to the next page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.pagingFooter.$('.next-page-link').click(); respondWithMockPage(requests); expect(pagingContainer.collection.currentPage).toBe(1); }); it('should be enabled when there is at least one more page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingFooter.$('.next-page-link')).not.toHaveClass('is-disabled'); }); it('should be disabled on the final page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); expect(pagingContainer.pagingFooter.$('.next-page-link')).toHaveClass('is-disabled'); }); it('should be disabled on an empty page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingContainer.pagingFooter.$('.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 pagingContainer.render(); }); it('does not move back if a server error occurs', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); pagingContainer.pagingFooter.$('.previous-page-link').click(); requests[1].respond(500); expect(pagingContainer.collection.currentPage).toBe(1); }); it('can go back a page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); pagingContainer.pagingFooter.$('.previous-page-link').click(); respondWithMockPage(requests); expect(pagingContainer.collection.currentPage).toBe(0); }); it('should be disabled on the first page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingFooter.$('.previous-page-link')).toHaveClass('is-disabled'); }); it('should be enabled on the second page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); expect(pagingContainer.pagingFooter.$('.previous-page-link')).not.toHaveClass('is-disabled'); }); it('should be disabled for an empty page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingContainer.pagingFooter.$('.previous-page-link')).toHaveClass('is-disabled'); }); }); describe('Current page label', function() { it('should show 1 on the first page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingFooter.$('.current-page')).toHaveText('1'); }); it('should show 2 on the second page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(1); respondWithMockPage(requests); expect(pagingContainer.pagingFooter.$('.current-page')).toHaveText('2'); }); it('should show 1 for an empty collection', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingContainer.pagingFooter.$('.current-page')).toHaveText('1'); }); }); describe('Page total label', function() { it('should show the correct value with more than one page', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingFooter.$('.total-pages')).toHaveText('2'); }); it('should show page 1 when there are no assets', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); AjaxHelpers.respondWithJson(requests, mockEmptyPage); expect(pagingContainer.pagingFooter.$('.total-pages')).toHaveText('1'); }); }); describe('Page input field', function() { var input; it('should initially have a blank page input', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); expect(pagingContainer.pagingFooter.$('.page-number-input')).toHaveValue(''); }); it('should handle invalid page requests', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.pagingFooter.$('.page-number-input').val('abc'); pagingContainer.pagingFooter.$('.page-number-input').trigger('change'); expect(pagingContainer.collection.currentPage).toBe(0); expect(pagingContainer.pagingFooter.$('.page-number-input')).toHaveValue(''); }); it('should switch pages via the input field', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.pagingFooter.$('.page-number-input').val('2'); pagingContainer.pagingFooter.$('.page-number-input').trigger('change'); AjaxHelpers.respondWithJson(requests, mockSecondPage); expect(pagingContainer.collection.currentPage).toBe(1); expect(pagingContainer.pagingFooter.$('.page-number-input')).toHaveValue(''); }); it('should handle AJAX failures when switching pages via the input field', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.pagingFooter.$('.page-number-input').val('2'); pagingContainer.pagingFooter.$('.page-number-input').trigger('change'); requests[1].respond(500); expect(pagingContainer.collection.currentPage).toBe(0); expect(pagingContainer.pagingFooter.$('.page-number-input')).toHaveValue(''); }); }); }); describe('Previews', function() { describe('Toggle Previews', function() { var testSendsAjax, defaultUrl = '/preview/xblock/handler/trigger_previews'; testSendsAjax = function(show_previews) { it('should send ' + (!show_previews) + ' when showChildrenPreviews was ' + show_previews, function() { var requests = AjaxHelpers.requests(this); pagingContainer.collection.showChildrenPreviews = show_previews; pagingContainer.togglePreviews(); AjaxHelpers.expectJsonRequest(requests, 'POST', defaultUrl, {showChildrenPreviews: !show_previews}); AjaxHelpers.respondWithJson(requests, {showChildrenPreviews: !show_previews}); }); }; testSendsAjax(true); testSendsAjax(false); it('should trigger render on success', function() { spyOn(pagingContainer, 'render'); var requests = AjaxHelpers.requests(this); pagingContainer.togglePreviews(); AjaxHelpers.respondWithJson(requests, {showChildrenPreviews: true}); expect(pagingContainer.render).toHaveBeenCalled(); }); it('should not trigger render on failure', function() { spyOn(pagingContainer, 'render'); var requests = AjaxHelpers.requests(this); pagingContainer.togglePreviews(); AjaxHelpers.respondWithError(requests); expect(pagingContainer.render).not.toHaveBeenCalled(); }); it('should send force_render when new block causes page change', function() { var requests = AjaxHelpers.requests(this); pagingContainer.setPage(0); respondWithMockPage(requests); spyOn(pagingContainer, 'render'); var mockXBlockInfo = new XBlockInfo({id: 'mock-location'}); var mockXBlockView = new XBlockView({model: mockXBlockInfo}); mockXBlockView.model.id = 'mock-location'; pagingContainer.refresh(mockXBlockView, true); expect(pagingContainer.render).toHaveBeenCalled(); expect(pagingContainer.render.calls.mostRecent().args[0].force_render).toEqual('mock-location'); }); }); }); }); });