Ghost/ghost/admin/tests/acceptance/subscribers-test.js

257 lines
9.9 KiB
JavaScript
Raw Normal View History

Subscribers: Admin User Interface v1 Initial Subscribers screen - set up mocked api endpoints - basic subscribers screen with data loading, infinite scroll "Add Subscriber" screen - uses modal to display a new subscriber form - validates subscriber e-mail address - moves pagination from route into controller to use filtered/sorted CPs on top of a live-query so that new subscribers are added to the list and the total can be properly managed TODO: - there is currently a pretty serious performance issue where the whole table is re-rendered when the live-query is updated. `ember-light-table` doesn't allow for live-binding and has no options to easily manipulate it's rows using an external interface - it's possible to move the page loading into the component so we only render new rows but that leaves it difficult to react to new subscribers being added through the UI. I believe the number of components used within the table is also adding to the performance problems. - most likely solution is to drop `ember-light-table` in favour of rendering the table directly - glimmer should do a good job of fast updates even though the underlying array will be completely swapped out "Import subscribers" screen - uses modal to display an import subscribers CSV file upload form - displays upload progress - displays import stats and reloads subscribers table once import has completed - adds `gh-file-uploader` component (NB. pared down copy of `gh-image-uploader`, ripe for some refactoring) - fixes subscribers acceptance test failing because fixtures did not have the labs flag enabled Unfortunately this doesn't have 100% test coverage as we're limited in how we can simulate file uploads 😞 Fix performance issues with subscribers table - moves the table definition from the component up to the controller - switches back to manually manipulating table rows instead of using a live-query This is a quick-fix in that it allows us to continue using the `ember-light-table` component but it does mean that we lose some flexibility that the live-query gave us. For now it's not much of an issue and it allows us to defer deeper performance/flexibility work until we have a concrete need and requirements. Hook up Export CSV button - use a hidden iFrame to trigger the browser to hit the CSV export endpoint and download the file Re-order subscribers table by clicking column headers - displays currently sorted column and sort direction - clicking a column header re-fetches the data from the server with the appropriate query params Fix scroll triggers for infinite pagination + icon change - adds a debounce as well as the throttle so that we always get a final scroll trigger once scrolling has stopped - changes the subscribers icon from the temporary team icon to the mail icon
2016-04-15 17:45:50 +03:00
/* jshint expr:true */
import {
describe,
it,
beforeEach,
afterEach
} from 'mocha';
import { expect } from 'chai';
import startApp from '../helpers/start-app';
import destroyApp from '../helpers/destroy-app';
import { invalidateSession, authenticateSession } from 'ghost/tests/helpers/ember-simple-auth';
describe('Acceptance: Subscribers', function() {
let application;
beforeEach(function() {
application = startApp();
});
afterEach(function() {
destroyApp(application);
});
it('redirects to signin when not authenticated', function () {
invalidateSession(application);
visit('/subscribers');
andThen(function () {
expect(currentURL()).to.equal('/signin');
});
});
it('redirects editors to posts', function () {
let role = server.create('role', {name: 'Editor'});
let user = server.create('user', {roles: [role]});
authenticateSession(application);
visit('/subscribers');
andThen(function () {
expect(currentURL()).to.equal('/');
expect(find('.gh-nav-main a:contains("Subscribers")').length, 'sidebar link is visible')
.to.equal(0);
});
});
it('redirects authors to posts', function () {
let role = server.create('role', {name: 'Author'});
let user = server.create('user', {roles: [role]});
authenticateSession(application);
visit('/subscribers');
andThen(function () {
expect(currentURL()).to.equal('/');
expect(find('.gh-nav-main a:contains("Subscribers")').length, 'sidebar link is visible')
.to.equal(0);
});
});
describe('an admin', function () {
beforeEach(function () {
let role = server.create('role', {name: 'Administrator'});
let user = server.create('user', {roles: [role]});
server.loadFixtures();
return authenticateSession(application);
});
it('can manage subscribers', function () {
server.createList('subscriber', 40);
authenticateSession(application);
visit('/');
click('.gh-nav-main a:contains("Subscribers")');
andThen(function() {
// it navigates to the correct page
expect(currentPath()).to.equal('subscribers.index');
// it has correct page title
expect(document.title, 'page title')
.to.equal('Subscribers - Test Blog');
// it loads the first page
expect(find('.subscribers-table .lt-body .lt-row').length, 'number of subscriber rows')
.to.equal(30);
// it shows the total number of subscribers
expect(find('#total-subscribers').text().trim(), 'displayed subscribers total')
.to.equal('40');
// it defaults to sorting by created_at desc
let [lastRequest] = server.pretender.handledRequests.slice(-1);
expect(lastRequest.queryParams.order).to.equal('created_at desc');
let createdAtHeader = find('.subscribers-table th:contains("Subscription Date")');
expect(createdAtHeader.hasClass('is-sorted'), 'createdAt column is sorted')
.to.be.true;
expect(createdAtHeader.find('.icon-descending').length, 'createdAt column has descending icon')
.to.equal(1);
});
// click the column to re-order
click('th:contains("Subscription Date")');
andThen(function () {
// it flips the directions and re-fetches
let [lastRequest] = server.pretender.handledRequests.slice(-1);
expect(lastRequest.queryParams.order).to.equal('created_at asc');
let createdAtHeader = find('.subscribers-table th:contains("Subscription Date")');
expect(createdAtHeader.find('.icon-ascending').length, 'createdAt column has ascending icon')
.to.equal(1);
// scroll to the bottom of the table to simulate infinite scroll
find('.subscribers-table').scrollTop(find('.subscribers-table .ember-light-table').height());
});
// trigger infinite scroll
triggerEvent('.subscribers-table', 'scroll');
andThen(function () {
// it loads the next page
expect(find('.subscribers-table .lt-body .lt-row').length, 'number of subscriber rows after infinite-scroll')
.to.equal(40);
});
// click the add subscriber button
click('.btn:contains("Add Subscriber")');
andThen(function () {
// it displays the add subscriber modal
expect(find('.fullscreen-modal').length, 'add subscriber modal displayed')
.to.equal(1);
});
// cancel the modal
click('.fullscreen-modal .btn:contains("Cancel")');
andThen(function () {
// it closes the add subscriber modal
expect(find('.fullscreen-modal').length, 'add subscriber modal displayed after cancel')
.to.equal(0);
});
// save a new subscriber
click('.btn:contains("Add Subscriber")');
fillIn('.fullscreen-modal input[name="email"]', 'test@example.com');
click('.fullscreen-modal .btn:contains("Add")');
andThen(function () {
// the add subscriber modal is closed
expect(find('.fullscreen-modal').length, 'add subscriber modal displayed after save')
.to.equal(0);
// the subscriber is added to the table
expect(find('.subscribers-table .lt-body .lt-row:first-of-type .lt-cell:first-of-type').text().trim(), 'first email in list after addition')
.to.equal('test@example.com');
// the table is scrolled to the top
// TODO: implement scroll to new record after addition
// expect(find('.subscribers-table').scrollTop(), 'scroll position after addition')
// .to.equal(0);
// the subscriber total is updated
expect(find('#total-subscribers').text().trim(), 'subscribers total after addition')
.to.equal('41');
});
// saving a duplicate subscriber
click('.btn:contains("Add Subscriber")');
fillIn('.fullscreen-modal input[name="email"]', 'test@example.com');
click('.fullscreen-modal .btn:contains("Add")');
andThen(function () {
// the validation error is displayed
expect(find('.fullscreen-modal .error .response').text().trim(), 'duplicate email validation')
.to.equal('Email already exists.');
// the subscriber is not added to the table
expect(find('.lt-cell:contains(test@example.com)').length, 'number of "test@example.com rows"')
.to.equal(1);
// the subscriber total is unchanged
expect(find('#total-subscribers').text().trim(), 'subscribers total after failed add')
.to.equal('41');
});
// deleting a subscriber
click('.fullscreen-modal .btn:contains("Cancel")');
click('.subscribers-table tbody tr:first-of-type button:last-of-type');
andThen(function () {
// it displays the delete subscriber modal
expect(find('.fullscreen-modal').length, 'delete subscriber modal displayed')
.to.equal(1);
});
// cancel the modal
click('.fullscreen-modal .btn:contains("Cancel")');
andThen(function () {
// return pauseTest();
// it closes the add subscriber modal
expect(find('.fullscreen-modal').length, 'delete subscriber modal displayed after cancel')
.to.equal(0);
});
click('.subscribers-table tbody tr:first-of-type button:last-of-type');
click('.fullscreen-modal .btn:contains("Delete")');
andThen(function () {
// the add subscriber modal is closed
expect(find('.fullscreen-modal').length, 'delete subscriber modal displayed after confirm')
.to.equal(0);
// the subscriber is removed from the table
expect(find('.subscribers-table .lt-body .lt-row:first-of-type .lt-cell:first-of-type').text().trim(), 'first email in list after addition')
.to.not.equal('test@example.com');
// the subscriber total is updated
expect(find('#total-subscribers').text().trim(), 'subscribers total after addition')
.to.equal('40');
});
Subscribers: Admin User Interface v1 Initial Subscribers screen - set up mocked api endpoints - basic subscribers screen with data loading, infinite scroll "Add Subscriber" screen - uses modal to display a new subscriber form - validates subscriber e-mail address - moves pagination from route into controller to use filtered/sorted CPs on top of a live-query so that new subscribers are added to the list and the total can be properly managed TODO: - there is currently a pretty serious performance issue where the whole table is re-rendered when the live-query is updated. `ember-light-table` doesn't allow for live-binding and has no options to easily manipulate it's rows using an external interface - it's possible to move the page loading into the component so we only render new rows but that leaves it difficult to react to new subscribers being added through the UI. I believe the number of components used within the table is also adding to the performance problems. - most likely solution is to drop `ember-light-table` in favour of rendering the table directly - glimmer should do a good job of fast updates even though the underlying array will be completely swapped out "Import subscribers" screen - uses modal to display an import subscribers CSV file upload form - displays upload progress - displays import stats and reloads subscribers table once import has completed - adds `gh-file-uploader` component (NB. pared down copy of `gh-image-uploader`, ripe for some refactoring) - fixes subscribers acceptance test failing because fixtures did not have the labs flag enabled Unfortunately this doesn't have 100% test coverage as we're limited in how we can simulate file uploads 😞 Fix performance issues with subscribers table - moves the table definition from the component up to the controller - switches back to manually manipulating table rows instead of using a live-query This is a quick-fix in that it allows us to continue using the `ember-light-table` component but it does mean that we lose some flexibility that the live-query gave us. For now it's not much of an issue and it allows us to defer deeper performance/flexibility work until we have a concrete need and requirements. Hook up Export CSV button - use a hidden iFrame to trigger the browser to hit the CSV export endpoint and download the file Re-order subscribers table by clicking column headers - displays currently sorted column and sort direction - clicking a column header re-fetches the data from the server with the appropriate query params Fix scroll triggers for infinite pagination + icon change - adds a debounce as well as the throttle so that we always get a final scroll trigger once scrolling has stopped - changes the subscribers icon from the temporary team icon to the mail icon
2016-04-15 17:45:50 +03:00
// click the import subscribers button
click('.btn:contains("Import CSV")');
andThen(function () {
// it displays the import subscribers modal
expect(find('.fullscreen-modal').length, 'import subscribers modal displayed')
.to.equal(1);
});
// cancel the modal
click('.fullscreen-modal .btn:contains("Cancel")');
andThen(function () {
// it closes the import subscribers modal
expect(find('.fullscreen-modal').length, 'import subscribers modal displayed after cancel')
.to.equal(0);
});
// TODO: how to simulate file upload?
// re-open import modal
// upload a file
// modal title changes
// modal button changes
// table is reset
// close modal
});
});
});