mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Add tests to tabs and events pagination (#15757)
closes TryGhost/Team#2128
This commit is contained in:
parent
f2c0bff9df
commit
b526c4b719
5 changed files with 209 additions and 7 deletions
|
@ -64,10 +64,13 @@ export default class ActivityFeedFetcher extends Resource {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
loadNextPage() {
|
loadNextPage() {
|
||||||
|
if (this.hasReachedEnd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const lastEvent = this.data[this.data.length - 1];
|
const lastEvent = this.data[this.data.length - 1];
|
||||||
const lastEventDate = moment.utc(lastEvent.data.created_at).format('YYYY-MM-DD HH:mm:ss');
|
const lastEventDate = moment.utc(lastEvent.data.created_at).format('YYYY-MM-DD HH:mm:ss');
|
||||||
const lastEventId = lastEvent.data.id;
|
const lastEventId = lastEvent.data.id;
|
||||||
|
|
||||||
let filter = `(data.created_at:<'${lastEventDate}',(data.created_at:'${lastEventDate}'+id:<'${lastEventId}'))`;
|
let filter = `(data.created_at:<'${lastEventDate}',(data.created_at:'${lastEventDate}'+id:<'${lastEventId}'))`;
|
||||||
this.eventsBookmarks.push(filter);
|
this.eventsBookmarks.push(filter);
|
||||||
|
|
||||||
|
@ -80,6 +83,9 @@ export default class ActivityFeedFetcher extends Resource {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
loadPreviousPage() {
|
loadPreviousPage() {
|
||||||
|
if (this.hasReachedStart) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.eventsBookmarks.pop();
|
this.eventsBookmarks.pop();
|
||||||
let filter = this.eventsBookmarks[this.eventsBookmarks.length - 1];
|
let filter = this.eventsBookmarks[this.eventsBookmarks.length - 1];
|
||||||
|
|
||||||
|
|
|
@ -290,15 +290,45 @@ export default function mockMembers(server) {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
server.get('/members/events/', withPermissionsCheck(ALLOWED_ROLES, function ({memberActivityEvents}, {queryParams}) {
|
server.get('/members/events/', withPermissionsCheck(ALLOWED_ROLES, function ({memberActivityEvents}, {queryParams}) {
|
||||||
let {limit} = queryParams;
|
let {limit, filter, page} = queryParams;
|
||||||
|
|
||||||
limit = +limit || 15;
|
limit = +limit || 15;
|
||||||
|
page = +page || 1;
|
||||||
|
|
||||||
let collection = memberActivityEvents.all().sort((a, b) => {
|
let collection = memberActivityEvents.all();
|
||||||
return (new Date(a.createdAt)) - (new Date(b.createdAt));
|
collection = collection.sort((a, b) => {
|
||||||
}).slice(0, limit);
|
return Number(b.id) - Number(a.id);
|
||||||
|
});
|
||||||
|
|
||||||
return collection;
|
if (filter) {
|
||||||
|
try {
|
||||||
|
const nqlFilter = nql(filter, {
|
||||||
|
expansions: [
|
||||||
|
{
|
||||||
|
key: 'data.created_at',
|
||||||
|
replacement: 'created_at'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
collection = collection.filter((event) => {
|
||||||
|
const serializedEvent = {};
|
||||||
|
|
||||||
|
// mirage model keys match our main model keys, so we need to transform
|
||||||
|
// camelCase to underscore to match the filter format
|
||||||
|
Object.keys(event.attrs).forEach((key) => {
|
||||||
|
serializedEvent[underscore(key)] = event.attrs[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
return nqlFilter.queryJSON(serializedEvent);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err); // eslint-disable-line
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginateModelCollection('members', collection, page, limit);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
mockMembersStats(server);
|
mockMembersStats(server);
|
||||||
|
|
|
@ -37,6 +37,6 @@ export default BaseSerializer.extend({
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return {events};
|
return {events, meta: serialized.meta};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -102,4 +102,31 @@ describe('Integration: Component: tabs/tabs', function () {
|
||||||
await triggerKeyEvent(tabButtons[0], 'keyup', 'End');
|
await triggerKeyEvent(tabButtons[0], 'keyup', 'End');
|
||||||
isTabRenders(2);
|
isTabRenders(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders content for all tabs with forceRender option', async function () {
|
||||||
|
await render(hbs`
|
||||||
|
<Tabs::Tabs class="test-tab" @forceRender={{true}} as |tabs|>
|
||||||
|
<tabs.tab>Tab 1</tabs.tab>
|
||||||
|
<tabs.tab>Tab 2</tabs.tab>
|
||||||
|
|
||||||
|
<tabs.tabPanel>Content 1</tabs.tabPanel>
|
||||||
|
<tabs.tabPanel>Content 2</tabs.tabPanel>
|
||||||
|
</Tabs::Tabs>`);
|
||||||
|
|
||||||
|
const tabButtons = findAll('.tab');
|
||||||
|
const tabPanels = findAll('.tab-panel');
|
||||||
|
|
||||||
|
expect(tabPanels[0]).to.have.trimmed.text('Content 1');
|
||||||
|
expect(tabPanels[1]).to.have.trimmed.text('Content 2');
|
||||||
|
|
||||||
|
await click(tabButtons[1]);
|
||||||
|
|
||||||
|
expect(findAll('.tab-selected').length).to.equal(1);
|
||||||
|
expect(findAll('.tab-panel-selected').length).to.equal(1);
|
||||||
|
expect(tabButtons[1]).to.have.class('tab-selected');
|
||||||
|
expect(tabPanels[1]).to.have.class('tab-panel-selected');
|
||||||
|
|
||||||
|
expect(tabPanels[0]).to.have.trimmed.text('Content 1');
|
||||||
|
expect(tabPanels[1]).to.have.trimmed.text('Content 2');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
import moment from 'moment-timezone';
|
||||||
|
import {click, find, findAll, render} from '@ember/test-helpers';
|
||||||
|
import {describe, it} from 'mocha';
|
||||||
|
import {expect} from 'chai';
|
||||||
|
import {setupMirage} from 'ember-cli-mirage/test-support';
|
||||||
|
import {setupRenderingTest} from 'ember-mocha';
|
||||||
|
|
||||||
|
describe('Integration: Helper: activity-feed-fetcher-test', function () {
|
||||||
|
const hooks = setupRenderingTest();
|
||||||
|
setupMirage(hooks);
|
||||||
|
|
||||||
|
it('can fetch events', async function () {
|
||||||
|
this.server.createList('member-activity-event', 10, {createdAt: moment('2022-11-01 12:00:00').format('YYYY-MM-DD HH:mm:ss')});
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
{{#let (activity-feed-fetcher pageSize="2") as |eventsFetcher|}}
|
||||||
|
<div class="shown-events">{{eventsFetcher.shownEvents}}</div>
|
||||||
|
<div class="total-events">{{eventsFetcher.totalEvents}}</div>
|
||||||
|
{{/let}}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(find('.shown-events')).to.have.trimmed.text('2');
|
||||||
|
expect(find('.total-events')).to.have.trimmed.text('10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can update total/shown amount of events ', async function () {
|
||||||
|
this.server.createList('member-activity-event', 5, {createdAt: moment('2022-11-01 12:00:00').format('YYYY-MM-DD HH:mm:ss')});
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
{{#let (activity-feed-fetcher pageSize="2") as |eventsFetcher|}}
|
||||||
|
<button class="previous" {{on "click" eventsFetcher.loadPreviousPage}}>Previous page</button>
|
||||||
|
<button class="next" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
|
||||||
|
|
||||||
|
<div class="shown-events">{{eventsFetcher.shownEvents}}</div>
|
||||||
|
<div class="total-events">{{eventsFetcher.totalEvents}}</div>
|
||||||
|
{{/let}}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const totalEvents = find('.total-events');
|
||||||
|
const shownEvents = find('.shown-events');
|
||||||
|
|
||||||
|
expect(shownEvents).to.have.trimmed.text('2');
|
||||||
|
expect(totalEvents).to.have.trimmed.text('5');
|
||||||
|
|
||||||
|
// nothing should change if user tries to load previous page on the first one
|
||||||
|
await click('.previous');
|
||||||
|
expect(shownEvents).to.have.trimmed.text('2');
|
||||||
|
expect(totalEvents).to.have.trimmed.text('5');
|
||||||
|
|
||||||
|
// go to the last page
|
||||||
|
await click('.next');
|
||||||
|
await click('.next');
|
||||||
|
expect(shownEvents).to.have.trimmed.text('5');
|
||||||
|
expect(totalEvents).to.have.trimmed.text('5');
|
||||||
|
|
||||||
|
// nothing should change if user tries to load next page on the last one
|
||||||
|
await click('.next');
|
||||||
|
expect(shownEvents).to.have.trimmed.text('5');
|
||||||
|
expect(totalEvents).to.have.trimmed.text('5');
|
||||||
|
|
||||||
|
await click('.previous');
|
||||||
|
expect(shownEvents).to.have.trimmed.text('4');
|
||||||
|
expect(totalEvents).to.have.trimmed.text('5');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can update data for each page', async function () {
|
||||||
|
this.server.createList('member-activity-event', 5, {createdAt: moment('2022-11-01 12:00:00').format('YYYY-MM-DD HH:mm:ss')});
|
||||||
|
// create event in future to make sure that user don't get events after current date
|
||||||
|
this.server.create('member-activity-event', {createdAt: moment().add(1, 'd').format('YYYY-MM-DD HH:mm:ss')});
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
{{#let (activity-feed-fetcher pageSize="2") as |eventsFetcher|}}
|
||||||
|
<button class="previous" {{on "click" eventsFetcher.loadPreviousPage}}>Previous page</button>
|
||||||
|
<button class="next" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
|
||||||
|
|
||||||
|
{{#each eventsFetcher.data as |event|}}
|
||||||
|
<div class="event-id">{{event.data.id}}</div>
|
||||||
|
{{/each}}
|
||||||
|
{{/let}}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(findAll('.event-id').length).to.equal(2);
|
||||||
|
expect(findAll('.event-id')[0]).to.have.trimmed.text('5');
|
||||||
|
|
||||||
|
await click('.next');
|
||||||
|
expect(findAll('.event-id').length).to.equal(2);
|
||||||
|
expect(findAll('.event-id')[0]).to.have.trimmed.text('3');
|
||||||
|
|
||||||
|
await click('.next');
|
||||||
|
expect(findAll('.event-id').length).to.equal(1);
|
||||||
|
expect(findAll('.event-id')[0]).to.have.trimmed.text('1');
|
||||||
|
|
||||||
|
// nothing should change if user tries to load next page on the last one
|
||||||
|
await click('.next');
|
||||||
|
expect(findAll('.event-id').length).to.equal(1);
|
||||||
|
expect(findAll('.event-id')[0]).to.have.trimmed.text('1');
|
||||||
|
|
||||||
|
await click('.previous');
|
||||||
|
expect(findAll('.event-id').length).to.equal(2);
|
||||||
|
expect(findAll('.event-id')[0]).to.have.trimmed.text('3');
|
||||||
|
|
||||||
|
await click('.previous');
|
||||||
|
expect(findAll('.event-id').length).to.equal(2);
|
||||||
|
expect(findAll('.event-id')[0]).to.have.trimmed.text('5');
|
||||||
|
|
||||||
|
// nothing should change if user tries to load previous page on the first one
|
||||||
|
await click('.previous');
|
||||||
|
expect(findAll('.event-id').length).to.equal(2);
|
||||||
|
expect(findAll('.event-id')[0]).to.have.trimmed.text('5');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('change error state and show error message if fetch was unsuccessful ', async function () {
|
||||||
|
this.server.createList('member-activity-event', 10, {createdAt: moment('2022-11-01 12:00:00').format('YYYY-MM-DD HH:mm:ss')});
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
{{#let (activity-feed-fetcher pageSize="2") as |eventsFetcher|}}
|
||||||
|
<button class="next" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
|
||||||
|
|
||||||
|
<div class="error">{{eventsFetcher.isError}}</div>
|
||||||
|
<div class="error-message">{{eventsFetcher.errorMessage}}</div>
|
||||||
|
{{/let}}
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(find('.error')).to.have.trimmed.text('false');
|
||||||
|
expect(find('.error-message')).to.have.trimmed.text('');
|
||||||
|
|
||||||
|
this.server.get(
|
||||||
|
'/members/events',
|
||||||
|
() => ({errors: [{message: 'Error message'}]}),
|
||||||
|
500
|
||||||
|
);
|
||||||
|
|
||||||
|
await click('.next');
|
||||||
|
|
||||||
|
expect(find('.error')).to.have.trimmed.text('true');
|
||||||
|
expect(find('.error-message')).to.have.trimmed.text('Error message');
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Reference in a new issue