campaigns.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. const apiUrl = Cypress.env('apiUrl');
  2. describe('Campaigns', () => {
  3. it('Opens campaigns page', () => {
  4. cy.resetDB();
  5. cy.loginAndVisit('/campaigns');
  6. });
  7. it('Counts campaigns', () => {
  8. cy.get('tbody td[data-label=Status]').should('have.length', 1);
  9. });
  10. it('Edits campaign', () => {
  11. cy.get('td[data-label=Status] a').click();
  12. // Fill fields.
  13. cy.get('input[name=name]').clear().type('new-name');
  14. cy.get('input[name=subject]').clear().type('new-subject');
  15. cy.get('input[name=from_email]').clear().type('new <from@email>');
  16. // Change the list.
  17. cy.get('.list-selector a.delete').click();
  18. cy.get('.list-selector input').click();
  19. cy.get('.list-selector .autocomplete a').eq(0).click();
  20. // Clear and redo tags.
  21. cy.get('input[name=tags]').type('{backspace}new-tag{enter}');
  22. // Enable schedule.
  23. cy.get('[data-cy=btn-send-later] .check').click();
  24. cy.get('.datepicker input').click();
  25. cy.get('.datepicker-header .control:nth-child(2) select').select((new Date().getFullYear() + 1).toString());
  26. cy.get('.datepicker-body a.is-selectable:first').click();
  27. cy.get('body').click(1, 1);
  28. // Switch to content tab.
  29. cy.get('.b-tabs nav a').eq(1).click();
  30. // Switch format to plain text.
  31. cy.get('label[data-cy=check-plain]').click();
  32. cy.get('.modal button.is-primary').click();
  33. // Enter body value.
  34. cy.get('textarea[name=content]').clear().type('new-content');
  35. cy.get('button[data-cy=btn-save]').click();
  36. // Schedule.
  37. cy.get('button[data-cy=btn-schedule]').click();
  38. cy.get('.modal button.is-primary').click();
  39. cy.wait(250);
  40. // Verify the changes.
  41. cy.request(`${apiUrl}/api/campaigns/1`).should((response) => {
  42. const { data } = response.body;
  43. expect(data.status).to.equal('scheduled');
  44. expect(data.name).to.equal('new-name');
  45. expect(data.subject).to.equal('new-subject');
  46. expect(data.content_type).to.equal('plain');
  47. expect(data.altbody).to.equal(null);
  48. expect(data.send_at).to.not.equal(null);
  49. expect(data.body).to.equal('new-content');
  50. expect(data.lists.length).to.equal(1);
  51. expect(data.lists[0].id).to.equal(1);
  52. expect(data.tags.length).to.equal(1);
  53. expect(data.tags[0]).to.equal('new-tag');
  54. });
  55. cy.get('tbody td[data-label=Status] .tag.scheduled');
  56. });
  57. it('Clones campaign', () => {
  58. for (let n = 0; n < 3; n++) {
  59. // Clone the campaign.
  60. cy.get('[data-cy=btn-clone]').first().click();
  61. cy.get('.modal input').clear().type(`clone${n}`).click();
  62. cy.get('.modal button.is-primary').click();
  63. cy.wait(250);
  64. cy.clickMenu('all-campaigns');
  65. cy.wait(100);
  66. // Verify the newly created row.
  67. cy.get('tbody td[data-label="Name"]').first().contains(`clone${n}`);
  68. }
  69. });
  70. it('Searches campaigns', () => {
  71. cy.get('input[name=query]').clear().type('clone2{enter}');
  72. cy.get('tbody tr').its('length').should('eq', 1);
  73. cy.get('tbody td[data-label="Name"]').first().contains('clone2');
  74. cy.get('input[name=query]').clear().type('{enter}');
  75. });
  76. it('Deletes campaign', () => {
  77. // Delete all visible lists.
  78. cy.get('tbody tr').each(() => {
  79. cy.get('tbody a[data-cy=btn-delete]').first().click();
  80. cy.get('.modal button.is-primary').click();
  81. });
  82. // Confirm deletion.
  83. cy.get('table tr.is-empty');
  84. });
  85. it('Adds new campaigns', () => {
  86. const lists = [[1], [1, 2]];
  87. const cTypes = ['richtext', 'html', 'plain'];
  88. let n = 0;
  89. cTypes.forEach((c) => {
  90. lists.forEach((l) => {
  91. // Click the 'new button'
  92. cy.get('[data-cy=btn-new]').click();
  93. cy.wait(100);
  94. // Fill fields.
  95. cy.get('input[name=name]').clear().type(`name${n}`);
  96. cy.get('input[name=subject]').clear().type(`subject${n}`);
  97. l.forEach(() => {
  98. cy.get('.list-selector input').click();
  99. cy.get('.list-selector .autocomplete a').first().click();
  100. });
  101. // Add tags.
  102. for (let i = 0; i < 3; i++) {
  103. cy.get('input[name=tags]').type(`tag${i}{enter}`);
  104. }
  105. // Hit 'Continue'.
  106. cy.get('button[data-cy=btn-continue]').click();
  107. cy.wait(250);
  108. // Insert content.
  109. cy.window().then((win) => {
  110. win.tinymce.editors[0].setContent(`hello${n} \{\{ .Subscriber.Name \}\}\n\{\{ .Subscriber.Attribs.city \}\}`);
  111. });
  112. cy.wait(200);
  113. // Select content type.
  114. cy.get(`label[data-cy=check-${c}]`).click();
  115. // If it's not richtext, there's a "you'll lose formatting" prompt.
  116. if (c !== 'richtext') {
  117. cy.get('.modal button.is-primary').click();
  118. }
  119. // Save.
  120. cy.get('button[data-cy=btn-save]').click();
  121. cy.clickMenu('all-campaigns');
  122. cy.wait(250);
  123. // Verify the newly created campaign in the table.
  124. cy.get('tbody td[data-label="Name"]').first().contains(`name${n}`);
  125. cy.get('tbody td[data-label="Name"]').first().contains(`subject${n}`);
  126. cy.get('tbody td[data-label="Lists"]').first().then(($el) => {
  127. cy.wrap($el).find('li').should('have.length', l.length);
  128. });
  129. n++;
  130. });
  131. });
  132. // Fetch the campaigns API and verfiy the values that couldn't be verified on the table UI.
  133. cy.request(`${apiUrl}/api/campaigns?order=asc&order_by=created_at`).should((response) => {
  134. const { data } = response.body;
  135. expect(data.total).to.equal(lists.length * cTypes.length);
  136. let n = 0;
  137. cTypes.forEach((c) => {
  138. lists.forEach((l) => {
  139. expect(data.results[n].content_type).to.equal(c);
  140. expect(data.results[n].lists.map((ls) => ls.id)).to.deep.equal(l);
  141. n++;
  142. });
  143. });
  144. });
  145. });
  146. it('Starts and cancels campaigns', () => {
  147. for (let n = 1; n <= 2; n++) {
  148. cy.get(`tbody tr:nth-child(${n}) [data-cy=btn-start]`).click();
  149. cy.get('.modal button.is-primary').click();
  150. cy.wait(250);
  151. cy.get(`tbody tr:nth-child(${n}) td[data-label=Status] .tag.running`);
  152. if (n > 1) {
  153. cy.get(`tbody tr:nth-child(${n}) [data-cy=btn-cancel]`).click();
  154. cy.get('.modal button.is-primary').click();
  155. cy.wait(250);
  156. cy.get(`tbody tr:nth-child(${n}) td[data-label=Status] .tag.cancelled`);
  157. }
  158. }
  159. });
  160. it('Sorts campaigns', () => {
  161. const asc = [5, 6, 7, 8, 9, 10];
  162. const desc = [10, 9, 8, 7, 6, 5];
  163. const cases = ['cy-name', 'cy-timestamp'];
  164. cases.forEach((c) => {
  165. cy.sortTable(`thead th.${c}`, asc);
  166. cy.wait(250);
  167. cy.sortTable(`thead th.${c}`, desc);
  168. cy.wait(250);
  169. });
  170. });
  171. });