mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-22 18:31:57 +03:00
22e13acd65
- All var declarations are now const or let as per ES6 - All comma-separated lists / chained declarations are now one declaration per line - This is for clarity/readability but also made running the var-to-const/let switch smoother - ESLint rules updated to match How this was done: - npm install -g jscodeshift - git clone https://github.com/cpojer/js-codemod.git - git clone git@github.com:TryGhost/Ghost.git shallow-ghost - cd shallow-ghost - jscodeshift -t ../js-codemod/transforms/unchain-variables.js . -v=2 - jscodeshift -t ../js-codemod/transforms/no-vars.js . -v=2 - yarn - yarn test - yarn lint / fix various lint errors (almost all indent) by opening files and saving in vscode - grunt test-regression - sorted!
351 lines
12 KiB
JavaScript
351 lines
12 KiB
JavaScript
const should = require('should');
|
|
const sinon = require('sinon');
|
|
const Promise = require('bluebird');
|
|
const rewire = require('rewire');
|
|
const pagination = rewire('../../../../core/server/models/plugins/pagination');
|
|
|
|
describe('pagination', function () {
|
|
let paginationUtils;
|
|
|
|
afterEach(function () {
|
|
sinon.restore();
|
|
});
|
|
|
|
describe('paginationUtils', function () {
|
|
before(function () {
|
|
paginationUtils = pagination.__get__('paginationUtils');
|
|
});
|
|
|
|
describe('formatResponse', function () {
|
|
let formatResponse;
|
|
|
|
before(function () {
|
|
formatResponse = paginationUtils.formatResponse;
|
|
});
|
|
|
|
it('returns correct pagination object for single page', function () {
|
|
formatResponse(5, {limit: 10, page: 1}).should.eql({
|
|
limit: 10,
|
|
next: null,
|
|
page: 1,
|
|
pages: 1,
|
|
prev: null,
|
|
total: 5
|
|
});
|
|
});
|
|
|
|
it('returns correct pagination object for first page of many', function () {
|
|
formatResponse(44, {limit: 5, page: 1}).should.eql({
|
|
limit: 5,
|
|
next: 2,
|
|
page: 1,
|
|
pages: 9,
|
|
prev: null,
|
|
total: 44
|
|
});
|
|
});
|
|
|
|
it('returns correct pagination object for middle page of many', function () {
|
|
formatResponse(44, {limit: 5, page: 9}).should.eql({
|
|
limit: 5,
|
|
next: null,
|
|
page: 9,
|
|
pages: 9,
|
|
prev: 8,
|
|
total: 44
|
|
});
|
|
});
|
|
|
|
it('returns correct pagination object for last page of many', function () {
|
|
formatResponse(44, {limit: 5, page: 3}).should.eql({
|
|
limit: 5,
|
|
next: 4,
|
|
page: 3,
|
|
pages: 9,
|
|
prev: 2,
|
|
total: 44
|
|
});
|
|
});
|
|
|
|
it('returns correct pagination object when page not set', function () {
|
|
formatResponse(5, {limit: 10}).should.eql({
|
|
limit: 10,
|
|
next: null,
|
|
page: 1,
|
|
pages: 1,
|
|
prev: null,
|
|
total: 5
|
|
});
|
|
});
|
|
|
|
it('returns correct pagination object for limit all', function () {
|
|
formatResponse(5, {limit: 'all'}).should.eql({
|
|
limit: 'all',
|
|
next: null,
|
|
page: 1,
|
|
pages: 1,
|
|
prev: null,
|
|
total: 5
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('parseOptions', function () {
|
|
let parseOptions;
|
|
|
|
before(function () {
|
|
parseOptions = paginationUtils.parseOptions;
|
|
});
|
|
|
|
it('should use defaults if no options are passed', function () {
|
|
parseOptions().should.eql({
|
|
limit: 15,
|
|
page: 1
|
|
});
|
|
});
|
|
|
|
it('should accept numbers for limit and page', function () {
|
|
parseOptions({
|
|
limit: 10,
|
|
page: 2
|
|
}).should.eql({
|
|
limit: 10,
|
|
page: 2
|
|
});
|
|
});
|
|
|
|
it('should use defaults if bad options are passed', function () {
|
|
parseOptions({
|
|
limit: 'thelma',
|
|
page: 'louise'
|
|
}).should.eql({
|
|
limit: 15,
|
|
page: 1
|
|
});
|
|
});
|
|
|
|
it('should permit all for limit', function () {
|
|
parseOptions({
|
|
limit: 'all'
|
|
}).should.eql({
|
|
limit: 'all',
|
|
page: 1
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('addLimitAndOffset', function () {
|
|
let addLimitAndOffset;
|
|
const collection = {};
|
|
|
|
before(function () {
|
|
addLimitAndOffset = paginationUtils.addLimitAndOffset;
|
|
});
|
|
|
|
beforeEach(function () {
|
|
collection.query = sinon.stub().returns(collection);
|
|
});
|
|
|
|
it('should add query options if limit is set', function () {
|
|
addLimitAndOffset(collection, {limit: 5, page: 1});
|
|
|
|
collection.query.calledTwice.should.be.true();
|
|
collection.query.firstCall.calledWith('limit', 5).should.be.true();
|
|
collection.query.secondCall.calledWith('offset', 0).should.be.true();
|
|
});
|
|
|
|
it('should not add query options if limit is not set', function () {
|
|
addLimitAndOffset(collection, {page: 1});
|
|
|
|
collection.query.called.should.be.false();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('fetchPage', function () {
|
|
let model;
|
|
let bookshelf;
|
|
let knex;
|
|
let mockQuery;
|
|
|
|
before(function () {
|
|
paginationUtils = pagination.__get__('paginationUtils');
|
|
});
|
|
|
|
beforeEach(function () {
|
|
// Stub paginationUtils
|
|
paginationUtils.parseOptions = sinon.stub();
|
|
paginationUtils.addLimitAndOffset = sinon.stub();
|
|
paginationUtils.formatResponse = sinon.stub().returns({});
|
|
|
|
// Mock out bookshelf model
|
|
mockQuery = {
|
|
clone: sinon.stub(),
|
|
select: sinon.stub(),
|
|
toQuery: sinon.stub()
|
|
};
|
|
mockQuery.clone.returns(mockQuery);
|
|
mockQuery.select.returns(Promise.resolve([{aggregate: 1}]));
|
|
|
|
model = function () {
|
|
};
|
|
|
|
model.prototype.fetchAll = sinon.stub().returns(Promise.resolve({}));
|
|
model.prototype.query = sinon.stub();
|
|
model.prototype.query.returns(mockQuery);
|
|
|
|
knex = {raw: sinon.stub().returns(Promise.resolve())};
|
|
|
|
bookshelf = {Model: model, knex: knex};
|
|
|
|
pagination(bookshelf);
|
|
});
|
|
|
|
it('extends Model with fetchPage', function () {
|
|
bookshelf.Model.prototype.should.have.ownProperty('fetchPage');
|
|
bookshelf.Model.prototype.fetchPage.should.be.a.Function();
|
|
});
|
|
|
|
it('calls all paginationUtils and methods', function (done) {
|
|
paginationUtils.parseOptions.returns({});
|
|
|
|
bookshelf.Model.prototype.fetchPage().then(function () {
|
|
sinon.assert.callOrder(
|
|
paginationUtils.parseOptions,
|
|
model.prototype.query,
|
|
mockQuery.clone,
|
|
mockQuery.select,
|
|
paginationUtils.addLimitAndOffset,
|
|
model.prototype.fetchAll,
|
|
paginationUtils.formatResponse
|
|
);
|
|
|
|
paginationUtils.parseOptions.calledOnce.should.be.true();
|
|
paginationUtils.parseOptions.calledWith(undefined).should.be.true();
|
|
|
|
paginationUtils.addLimitAndOffset.calledOnce.should.be.true();
|
|
paginationUtils.formatResponse.calledOnce.should.be.true();
|
|
|
|
model.prototype.query.calledOnce.should.be.true();
|
|
model.prototype.query.firstCall.calledWith().should.be.true();
|
|
|
|
mockQuery.clone.calledOnce.should.be.true();
|
|
mockQuery.clone.firstCall.calledWith().should.be.true();
|
|
|
|
mockQuery.select.calledOnce.should.be.true();
|
|
mockQuery.select.calledWith().should.be.true();
|
|
|
|
model.prototype.fetchAll.calledOnce.should.be.true();
|
|
model.prototype.fetchAll.calledWith({}).should.be.true();
|
|
|
|
done();
|
|
}).catch(done);
|
|
});
|
|
|
|
it('calls all paginationUtils and methods when order set', function (done) {
|
|
const orderOptions = {order: {id: 'DESC'}};
|
|
paginationUtils.parseOptions.returns(orderOptions);
|
|
|
|
bookshelf.Model.prototype.fetchPage(orderOptions).then(function () {
|
|
sinon.assert.callOrder(
|
|
paginationUtils.parseOptions,
|
|
model.prototype.query,
|
|
mockQuery.clone,
|
|
mockQuery.select,
|
|
paginationUtils.addLimitAndOffset,
|
|
model.prototype.query,
|
|
model.prototype.fetchAll,
|
|
paginationUtils.formatResponse
|
|
);
|
|
|
|
paginationUtils.parseOptions.calledOnce.should.be.true();
|
|
paginationUtils.parseOptions.calledWith(orderOptions).should.be.true();
|
|
|
|
paginationUtils.addLimitAndOffset.calledOnce.should.be.true();
|
|
paginationUtils.formatResponse.calledOnce.should.be.true();
|
|
|
|
model.prototype.query.calledTwice.should.be.true();
|
|
model.prototype.query.firstCall.calledWith().should.be.true();
|
|
model.prototype.query.secondCall.calledWith('orderBy', 'undefined.id', 'DESC').should.be.true();
|
|
|
|
mockQuery.clone.calledOnce.should.be.true();
|
|
mockQuery.clone.firstCall.calledWith().should.be.true();
|
|
|
|
mockQuery.select.calledOnce.should.be.true();
|
|
mockQuery.select.calledWith().should.be.true();
|
|
|
|
model.prototype.fetchAll.calledOnce.should.be.true();
|
|
model.prototype.fetchAll.calledWith(orderOptions).should.be.true();
|
|
|
|
done();
|
|
}).catch(done);
|
|
});
|
|
|
|
it('calls all paginationUtils and methods when group by set', function (done) {
|
|
const groupOptions = {groups: ['posts.id']};
|
|
paginationUtils.parseOptions.returns(groupOptions);
|
|
|
|
bookshelf.Model.prototype.fetchPage(groupOptions).then(function () {
|
|
sinon.assert.callOrder(
|
|
paginationUtils.parseOptions,
|
|
model.prototype.query,
|
|
mockQuery.clone,
|
|
mockQuery.select,
|
|
paginationUtils.addLimitAndOffset,
|
|
model.prototype.query,
|
|
model.prototype.fetchAll,
|
|
paginationUtils.formatResponse
|
|
);
|
|
|
|
paginationUtils.parseOptions.calledOnce.should.be.true();
|
|
paginationUtils.parseOptions.calledWith(groupOptions).should.be.true();
|
|
|
|
paginationUtils.addLimitAndOffset.calledOnce.should.be.true();
|
|
paginationUtils.formatResponse.calledOnce.should.be.true();
|
|
|
|
model.prototype.query.calledTwice.should.be.true();
|
|
model.prototype.query.firstCall.calledWith().should.be.true();
|
|
model.prototype.query.secondCall.calledWith('groupBy', 'posts.id').should.be.true();
|
|
|
|
mockQuery.clone.calledOnce.should.be.true();
|
|
mockQuery.clone.firstCall.calledWith().should.be.true();
|
|
|
|
mockQuery.select.calledOnce.should.be.true();
|
|
mockQuery.select.calledWith().should.be.true();
|
|
|
|
model.prototype.fetchAll.calledOnce.should.be.true();
|
|
model.prototype.fetchAll.calledWith(groupOptions).should.be.true();
|
|
|
|
done();
|
|
}).catch(done);
|
|
});
|
|
|
|
it('returns expected response', function (done) {
|
|
paginationUtils.parseOptions.returns({});
|
|
bookshelf.Model.prototype.fetchPage().then(function (result) {
|
|
result.should.have.ownProperty('collection');
|
|
result.should.have.ownProperty('pagination');
|
|
result.collection.should.be.an.Object();
|
|
result.pagination.should.be.an.Object();
|
|
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('returns expected response even when aggregate is empty', function (done) {
|
|
// override aggregate response
|
|
mockQuery.select.returns(Promise.resolve([]));
|
|
paginationUtils.parseOptions.returns({});
|
|
|
|
bookshelf.Model.prototype.fetchPage().then(function (result) {
|
|
result.should.have.ownProperty('collection');
|
|
result.should.have.ownProperty('pagination');
|
|
result.collection.should.be.an.Object();
|
|
result.pagination.should.be.an.Object();
|
|
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|