Ghost/ghost/admin/tests/acceptance/members-test.js
Kevin Ansfield 3817f583fa 🐛 Fixed unexpected "unsaved changes" modal when deleting a member
closes https://github.com/TryGhost/Team/issues/2275

When deleting a member, after confirming deletion another "unsaved changes" modal popped up. From that point, if you clicked to stay you remained on the member screen with stale data (the member was still deleted) resulting in further errors when any attempt to make changes was made.

- prevented the unsaved changes check running for a deleted member because it would always return `true` in that case
- ensured the data setup for the unsaved changes check still occurs when a member is accessed directly via the URL
  - previously it was skipped because the data setup only occurred inside `fetchMemberTask` but that isn't called when the route already loaded the model via it's `model()` hook
2022-12-05 11:48:37 +00:00

268 lines
11 KiB
JavaScript

import moment from 'moment-timezone';
import {authenticateSession, invalidateSession} from 'ember-simple-auth/test-support';
import {beforeEach, describe, it} from 'mocha';
import {blur, click, currentURL, fillIn, find, findAll} from '@ember/test-helpers';
import {expect} from 'chai';
import {setupApplicationTest} from 'ember-mocha';
import {setupMirage} from 'ember-cli-mirage/test-support';
import {visit} from '../helpers/visit';
describe('Acceptance: Members', function () {
let hooks = setupApplicationTest();
setupMirage(hooks);
it('redirects to signin when not authenticated', async function () {
await invalidateSession();
await visit('/members');
expect(currentURL()).to.equal('/signin');
});
it('redirects non-admins to site', async function () {
let role = this.server.create('role', {name: 'Editor'});
this.server.create('user', {roles: [role]});
await authenticateSession();
await visit('/members');
expect(currentURL()).to.equal('/site');
expect(find('[data-test-nav="members"]'), 'sidebar link')
.to.not.exist;
});
describe('as owner', function () {
beforeEach(async function () {
this.server.loadFixtures('configs');
let role = this.server.create('role', {name: 'Owner'});
this.server.create('user', {roles: [role]});
return await authenticateSession();
});
it('it renders, can be navigated, can edit member', async function () {
let member1 = this.server.create('member', {createdAt: moment.utc().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss')});
this.server.create('member', {createdAt: moment.utc().subtract(2, 'day').format('YYYY-MM-DD HH:mm:ss')});
await visit('/members');
// lands on correct page
expect(currentURL(), 'currentURL').to.equal('/members');
// it has correct page title
expect(document.title, 'page title').to.equal('Members - Test Blog');
// it lists all members
expect(findAll('[data-test-list="members-list-item"]').length, 'members list count')
.to.equal(2);
// it highlights active state in nav menu
expect(
find('[data-test-nav="members"]'),
'highlights nav menu item'
).to.have.class('active');
let member = find('[data-test-list="members-list-item"]');
expect(member.querySelector('.gh-members-list-name').textContent, 'member list item title')
.to.equal(member1.name);
// it does not add ?include=email_recipients
const membersRequests = this.server.pretender.handledRequests.filter(r => r.url.match(/\/members\/(\?|$)/));
expect(membersRequests[0].url).to.not.have.string('email_recipients');
await visit(`/members/${member1.id}`);
// it shows selected member form
expect(find('[data-test-input="member-name"]').value, 'loads correct member into form')
.to.equal(member1.name);
expect(find('[data-test-input="member-email"]').value, 'loads correct email into form')
.to.equal(member1.email);
// it maintains active state in nav menu
expect(
find('[data-test-nav="members"]'),
'highlights nav menu item'
).to.have.class('active');
// trigger save
await fillIn('[data-test-input="member-name"]', 'New Name');
await blur('[data-test-input="member-name"]');
await click('[data-test-button="save"]');
await click('[data-test-link="members-back"]');
// lands on correct page
expect(currentURL(), 'currentURL').to.equal('/members');
});
it('can create a new member', async function () {
this.server.create('member', {createdAt: moment.utc().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss')});
await visit('/members');
// lands on correct page
expect(currentURL(), 'currentURL').to.equal('/members');
// it has correct page title
expect(document.title, 'page title').to.equal('Members - Test Blog');
// it lists all members
expect(findAll('[data-test-list="members-list-item"]').length, 'members list count')
.to.equal(1);
// start new member
await click('[data-test-new-member-button="true"]');
// it navigates to the new member route
expect(currentURL(), 'new member URL').to.equal('/members/new');
// it displays the new member form
expect(find('.gh-canvas-header h2').textContent, 'settings pane title')
.to.contain('New');
// it highlights active state in nav menu
expect(
find('[data-test-nav="members"]'),
'highlights nav menu item'
).to.have.class('active');
// all fields start blank
findAll('.gh-member-settings-primary .gh-input').forEach(function (elem) {
expect(elem.value, `input field for ${elem.getAttribute('name')}`)
.to.be.empty;
});
// save new member
await fillIn('[data-test-input="member-name"]', 'New Name');
await blur('[data-test-input="member-name"]');
await fillIn('[data-test-input="member-email"]', 'example@domain.com');
await blur('[data-test-input="member-email"]');
await click('[data-test-button="save"]');
expect(find('[data-test-input="member-name"]').value, 'name has been preserved')
.to.equal('New Name');
expect(find('[data-test-input="member-email"]').value, 'email has been preserved')
.to.equal('example@domain.com');
});
it('can bulk delete members', async function () {
// members to be kept
this.server.createList('member', 6);
// imported members to be deleted
const label = this.server.create('label');
this.server.createList('member', 5, {labels: [label]});
await visit('/members');
expect(findAll('[data-test-member]').length).to.equal(11);
await click('[data-test-button="members-actions"]');
expect(find('[data-test-button="delete-selected"]')).to.not.exist;
// a filter is needed for the delete-selected button to show
await click('[data-test-button="members-filter-actions"]');
await fillIn('[data-test-members-filter="0"] [data-test-select="members-filter"]', 'label');
await click('.gh-member-label-input input');
await click(`[data-test-label-filter="${label.name}"]`);
await click(`[data-test-button="members-apply-filter"]`);
expect(findAll('[data-test-member]').length).to.equal(5);
expect(currentURL()).to.equal('/members?filter=label%3A%5Blabel-0%5D');
await click('[data-test-button="members-actions"]');
expect(find('[data-test-button="delete-selected"]')).to.exist;
await click('[data-test-button="delete-selected"]');
expect(find('[data-test-modal="delete-members"]')).to.exist;
expect(find('[data-test-text="delete-count"]')).to.have.text('5 members');
// ensure export endpoint gets hit with correct query params when deleting
let exportQueryParams;
this.server.get('/members/upload', (schema, request) => {
exportQueryParams = request.queryParams;
});
await click('[data-test-button="confirm"]');
expect(exportQueryParams).to.deep.equal({filter: 'label:[label-0]', limit: 'all'});
expect(find('[data-test-text="deleted-count"]')).to.have.text('5 members');
expect(find('[data-test-button="confirm"]')).to.not.exist;
// members filter is reset
expect(currentURL()).to.equal('/members');
expect(findAll('[data-test-member]').length).to.equal(6);
await click('[data-test-button="close-modal"]');
expect(find('[data-test-modal="delete-members"]')).to.not.exist;
});
it('can delete a member (via list)', async function () {
const newsletter = this.server.create('newsletter');
const label = this.server.create('label');
this.server.createList('member', 2, {newsletters: [newsletter], labels: [label]});
await visit('/members');
expect(findAll('[data-test-member]').length).to.equal(2);
await click('[data-test-member] a');
expect(currentURL()).to.match(/members\/\d+/);
await click('[data-test-button="member-actions"]');
await click('[data-test-button="delete-member"]');
expect(find('[data-test-modal="delete-member"]')).to.exist;
await click('[data-test-modal="delete-member"] [data-test-button="cancel"]');
expect(currentURL()).to.match(/members\/\d+/);
expect(find('[data-test-modal="delete-member"]')).to.not.exist;
await click('[data-test-button="member-actions"]');
await click('[data-test-button="delete-member"]');
await click('[data-test-modal="delete-member"] [data-test-button="confirm"]');
expect(currentURL()).to.equal('/members');
expect(findAll('[data-test-modal]')).to.have.length(0);
expect(findAll('[data-test-member]')).to.have.length(1);
});
it('can delete a member (via url)', async function () {
const newsletter = this.server.create('newsletter');
const label = this.server.create('label');
const [memberOne] = this.server.createList('member', 2, {newsletters: [newsletter], labels: [label]});
await visit(`/members/${memberOne.id}`);
await click('[data-test-button="member-actions"]');
await click('[data-test-button="delete-member"]');
expect(find('[data-test-modal="delete-member"]')).to.exist;
await click('[data-test-modal="delete-member"] [data-test-button="cancel"]');
expect(currentURL()).to.match(/members\/\d+/);
expect(find('[data-test-modal="delete-member"]')).to.not.exist;
await click('[data-test-button="member-actions"]');
await click('[data-test-button="delete-member"]');
await click('[data-test-modal="delete-member"] [data-test-button="confirm"]');
expect(currentURL()).to.equal('/members');
expect(findAll('[data-test-modal]')).to.have.length(0);
expect(findAll('[data-test-member]')).to.have.length(1);
});
});
});