Add generic paging framework
Authors: - Daniel Friedman - Ben McMorran - Peter Fogg TNL-1892
This commit is contained in:
committed by
Daniel Friedman
parent
65a36a64df
commit
351e491c82
@@ -1,10 +1,10 @@
|
||||
define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset", "js/views/assets",
|
||||
"js/models/asset", "js/collections/asset", "js/spec_helpers/view_helpers"],
|
||||
function ($, AjaxHelpers, URI, AssetView, AssetsView, AssetModel, AssetCollection, ViewHelpers) {
|
||||
define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/assets",
|
||||
"js/collections/asset", "js/spec_helpers/view_helpers"],
|
||||
function ($, AjaxHelpers, URI, AssetsView, AssetCollection, ViewHelpers) {
|
||||
|
||||
describe("Assets", function() {
|
||||
var assetsView, mockEmptyAssetsResponse, mockAssetUploadResponse, mockFileUpload,
|
||||
assetLibraryTpl, assetTpl, pagingFooterTpl, pagingHeaderTpl, uploadModalTpl;
|
||||
assetLibraryTpl, assetTpl, uploadModalTpl;
|
||||
|
||||
assetLibraryTpl = readFixtures('asset-library.underscore');
|
||||
assetTpl = readFixtures('asset.underscore');
|
||||
@@ -357,6 +357,96 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset
|
||||
$(".upload-modal .file-chooser").fileupload('add', mockFileUpload);
|
||||
expect(assetsView.largeFileErrorMsg).toBeNull();
|
||||
});
|
||||
|
||||
describe('Paging footer', function () {
|
||||
var firstPageAssets = {
|
||||
sort: "uploadDate",
|
||||
end: 1,
|
||||
assets: [
|
||||
{
|
||||
"display_name": "test.jpg",
|
||||
"url": "/c4x/A/CS102/asset/test.jpg",
|
||||
"date_added": "Nov 07, 2014 at 17:47 UTC",
|
||||
"id": "/c4x/A/CS102/asset/test.jpg",
|
||||
"portable_url": "/static/test.jpg",
|
||||
"thumbnail": "/c4x/A/CS102/thumbnail/test.jpg",
|
||||
"locked": false,
|
||||
"external_url": "localhost:8000/c4x/A/CS102/asset/test.jpg"
|
||||
},
|
||||
{
|
||||
"display_name": "test.pdf",
|
||||
"url": "/c4x/A/CS102/asset/test.pdf",
|
||||
"date_added": "Oct 20, 2014 at 11:00 UTC",
|
||||
"id": "/c4x/A/CS102/asset/test.pdf",
|
||||
"portable_url": "/static/test.pdf",
|
||||
"thumbnail": null,
|
||||
"locked": false,
|
||||
"external_url": "localhost:8000/c4x/A/CS102/asset/test.pdf"
|
||||
}
|
||||
],
|
||||
pageSize: 2,
|
||||
totalCount: 3,
|
||||
start: 0,
|
||||
page: 0
|
||||
}, secondPageAssets = {
|
||||
sort: "uploadDate",
|
||||
end: 2,
|
||||
assets: [
|
||||
{
|
||||
"display_name": "test.odt",
|
||||
"url": "/c4x/A/CS102/asset/test.odt",
|
||||
"date_added": "Oct 20, 2014 at 11:00 UTC",
|
||||
"id": "/c4x/A/CS102/asset/test.odt",
|
||||
"portable_url": "/static/test.odt",
|
||||
"thumbnail": null,
|
||||
"locked": false,
|
||||
"external_url": "localhost:8000/c4x/A/CS102/asset/test.odt"
|
||||
}
|
||||
],
|
||||
pageSize: 2,
|
||||
totalCount: 3,
|
||||
start: 2,
|
||||
page: 1
|
||||
};
|
||||
|
||||
it('can move forward a page using the next page button', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
assetsView.pagingView.setPage(0);
|
||||
AjaxHelpers.respondWithJson(requests, firstPageAssets);
|
||||
expect(assetsView.pagingView.pagingFooter).toBeDefined();
|
||||
expect(assetsView.pagingView.pagingFooter.$('button.next-page-link'))
|
||||
.not.toHaveClass('is-disabled');
|
||||
assetsView.pagingView.pagingFooter.$('button.next-page-link').click();
|
||||
AjaxHelpers.respondWithJson(requests, secondPageAssets);
|
||||
expect(assetsView.pagingView.pagingFooter.$('button.next-page-link'))
|
||||
.toHaveClass('is-disabled');
|
||||
});
|
||||
|
||||
it('can move back a page using the previous page button', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
assetsView.pagingView.setPage(1);
|
||||
AjaxHelpers.respondWithJson(requests, secondPageAssets);
|
||||
expect(assetsView.pagingView.pagingFooter).toBeDefined();
|
||||
expect(assetsView.pagingView.pagingFooter.$('button.previous-page-link'))
|
||||
.not.toHaveClass('is-disabled');
|
||||
assetsView.pagingView.pagingFooter.$('button.previous-page-link').click();
|
||||
AjaxHelpers.respondWithJson(requests, firstPageAssets);
|
||||
expect(assetsView.pagingView.pagingFooter.$('button.previous-page-link'))
|
||||
.toHaveClass('is-disabled');
|
||||
});
|
||||
|
||||
it('can set the current page using the page number input', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
assetsView.pagingView.setPage(0);
|
||||
AjaxHelpers.respondWithJson(requests, firstPageAssets);
|
||||
assetsView.pagingView.pagingFooter.$('#page-number-input').val('2');
|
||||
assetsView.pagingView.pagingFooter.$('#page-number-input').trigger('change');
|
||||
AjaxHelpers.respondWithJson(requests, secondPageAssets);
|
||||
expect(assetsView.collection.currentPage).toBe(1);
|
||||
expect(assetsView.pagingView.pagingFooter.$('button.previous-page-link'))
|
||||
.not.toHaveClass('is-disabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "js/models/xblock_info",
|
||||
"js/views/paged_container", "common/js/components/views/paging_header",
|
||||
"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) {
|
||||
|
||||
|
||||
393
cms/static/js/spec/views/paging_spec.js
Normal file
393
cms/static/js/spec/views/paging_spec.js
Normal file
@@ -0,0 +1,393 @@
|
||||
define([
|
||||
"jquery",
|
||||
"common/js/spec_helpers/ajax_helpers",
|
||||
"URI",
|
||||
"js/views/paging",
|
||||
"js/views/paging_header",
|
||||
"common/js/components/collections/paging_collection"
|
||||
], function ($, AjaxHelpers, URI, PagingView, PagingHeader, PagingCollection) {
|
||||
|
||||
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,
|
||||
current_page: 0,
|
||||
count: 4,
|
||||
page: 0,
|
||||
start: 0
|
||||
};
|
||||
var mockSecondPage = {
|
||||
results: [
|
||||
createPageableItem(4)
|
||||
],
|
||||
num_pages: 2,
|
||||
page_size: 3,
|
||||
current_page: 1,
|
||||
count: 4,
|
||||
page: 1,
|
||||
start: 3
|
||||
};
|
||||
var mockEmptyPage = {
|
||||
results: [],
|
||||
num_pages: 1,
|
||||
page_size: 3,
|
||||
current_page: 0,
|
||||
count: 0,
|
||||
page: 0,
|
||||
start: 0
|
||||
};
|
||||
|
||||
var respondWithMockItems = function(requests) {
|
||||
var requestIndex = requests.length - 1;
|
||||
var request = requests[requestIndex];
|
||||
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, requestIndex);
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
beforeEach(function () {
|
||||
var collection = new PagingCollection();
|
||||
collection.isZeroIndexed = true;
|
||||
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.currentPage).toBe(0);
|
||||
pagingView.setPage(2);
|
||||
respondWithMockItems(requests);
|
||||
expect(pagingView.collection.currentPage).toBe(1);
|
||||
});
|
||||
|
||||
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);
|
||||
expect(pagingView.collection.currentPage).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
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.currentPage).toBe(0);
|
||||
});
|
||||
|
||||
it('can move to the next page', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
pagingView.setPage(1);
|
||||
respondWithMockItems(requests);
|
||||
pagingView.nextPage();
|
||||
respondWithMockItems(requests);
|
||||
expect(pagingView.collection.currentPage).toBe(1);
|
||||
});
|
||||
|
||||
it('can not move forward from the final page', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
pagingView.setPage(2);
|
||||
respondWithMockItems(requests);
|
||||
pagingView.nextPage();
|
||||
expect(requests.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
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.currentPage).toBe(0);
|
||||
});
|
||||
|
||||
it('can not move back from the first page', function () {
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
pagingView.setPage(1);
|
||||
respondWithMockItems(requests);
|
||||
pagingView.previousPage();
|
||||
expect(requests.length).toBe(1);
|
||||
});
|
||||
|
||||
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.currentPage).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
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.currentPage).toBe(0);
|
||||
});
|
||||
|
||||
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.currentPage).toBe(1);
|
||||
});
|
||||
|
||||
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(0);
|
||||
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.currentPage).toBe(1);
|
||||
});
|
||||
|
||||
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.currentPage).toBe(0);
|
||||
});
|
||||
|
||||
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('<p>Showing <span class="count-current-shown">1-3</span>' +
|
||||
' out of <span class="count-total">4 total</span>, ' +
|
||||
'sorted by <span class="sort-order">Date</span> descending</p>');
|
||||
});
|
||||
|
||||
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('<p>Showing <span class="count-current-shown">1-3</span>' +
|
||||
' out of <span class="count-total">4 total</span>, ' +
|
||||
'sorted by <span class="sort-order">Name</span> ascending</p>');
|
||||
});
|
||||
});
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user