diff --git a/assets/javascripts/discourse/routes/admin-wizards-api-show.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-api-show.js.es6 index 6c0ed7a8..bfe90f72 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-api-show.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-api-show.js.es6 @@ -10,6 +10,12 @@ export default DiscourseRoute.extend({ } }, + afterModel(model) { + if (model === null) { + return this.transitionTo("adminWizardsApi"); + } + }, + setupController(controller, model) { controller.set("api", model); }, diff --git a/assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6 index 474360ec..e1f53c8f 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-logs-show.js.es6 @@ -7,6 +7,12 @@ export default DiscourseRoute.extend({ return CustomWizardLogs.list(params.wizardId); }, + afterModel(model) { + if (model === null) { + return this.transitionTo("adminWizardsLogs"); + } + }, + setupController(controller, model) { controller.setProperties({ wizard: model.wizard, diff --git a/assets/javascripts/discourse/routes/admin-wizards-submissions-show.js.es6 b/assets/javascripts/discourse/routes/admin-wizards-submissions-show.js.es6 index b616b5be..b9dbd90f 100644 --- a/assets/javascripts/discourse/routes/admin-wizards-submissions-show.js.es6 +++ b/assets/javascripts/discourse/routes/admin-wizards-submissions-show.js.es6 @@ -8,6 +8,12 @@ export default DiscourseRoute.extend({ return CustomWizardAdmin.submissions(params.wizardId); }, + afterModel(model) { + if (model === null) { + return this.transitionTo("adminWizardsSubmissions"); + } + }, + setupController(controller, model) { const { fields, submissions } = formatModel(model); diff --git a/assets/javascripts/discourse/templates/admin-wizards-api-show.hbs b/assets/javascripts/discourse/templates/admin-wizards-api-show.hbs index 7fe0fd21..89387446 100644 --- a/assets/javascripts/discourse/templates/admin-wizards-api-show.hbs +++ b/assets/javascripts/discourse/templates/admin-wizards-api-show.hbs @@ -260,11 +260,11 @@
diff --git a/plugin.rb b/plugin.rb index 955063f4..64d0dc6d 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.4.3 +# version: 2.4.4 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech diff --git a/test/javascripts/acceptance/admin-custom-fields-unsuscribed-test.js b/test/javascripts/acceptance/admin-custom-fields-unsuscribed-test.js new file mode 100644 index 00000000..fa3b5f75 --- /dev/null +++ b/test/javascripts/acceptance/admin-custom-fields-unsuscribed-test.js @@ -0,0 +1,357 @@ +import { + acceptance, + query, + visible, +} from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, findAll, visit, waitUntil } from "@ember/test-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; +import { + getCustomFields, + getUnsubscribedAdminWizards, + getWizard, +} from "../helpers/admin-wizard"; + +acceptance("Admin | Custom Fields Unsuscribed", function (needs) { + needs.user(); + needs.settings({ + custom_wizard_enabled: true, + available_locales: JSON.stringify([{ name: "English", value: "en" }]), + }); + + needs.pretender((server, helper) => { + server.get("/admin/wizards/wizard", () => { + return helper.response(getWizard); + }); + server.get("/admin/wizards", () => { + return helper.response(getUnsubscribedAdminWizards); + }); + server.get("/admin/wizards/custom-fields", () => { + return helper.response(getCustomFields); + }); + server.put("/admin/wizards/custom-fields", () => { + return helper.response({ success: "OK" }); + }); + server.delete("/admin/wizards/custom-fields/topic_custom_field", () => { + return helper.response({ success: "OK" }); + }); + }); + + async function selectTypeAndSerializerAndFillInName( + type, + serializer, + name, + summaryName + ) { + const typeDropdown = selectKit( + `.admin-wizard-container details:has(summary[name="${summaryName}"])` + ); + await typeDropdown.expand(); + await click( + `.select-kit-collection li[data-value="${type.toLowerCase()}"]` + ); + + const serializerDropdown = selectKit( + ".admin-wizard-container details.multi-select" + ); + await serializerDropdown.expand(); + await click( + `.select-kit-collection li[data-value="${serializer + .toLowerCase() + .replace(/ /g, "_")}"]` + ); + + await fillIn( + ".admin-wizard-container input", + name.toLowerCase().replace(/ /g, "_") + ); + } + + async function waitForSaveMessage() { + // Wait for the "Saved custom field" message to appear + await waitUntil( + () => + document.querySelector(".message-content")?.innerText === + "Saved custom field", + { timeout: 5000 } + ); + + // Wait for the message to change back to the original text + await waitUntil( + () => + document.querySelector(".message-content")?.innerText === + "View, create, edit and destroy custom fields", + { timeout: 15000 } + ); + await new Ember.RSVP.Promise((resolve) => setTimeout(resolve, 1000)); + } + + test("Navigate to custom fields tab", async (assert) => { + await visit("/admin/wizards/custom-fields"); + assert.ok(find("table")); + assert.ok( + findAll("table tbody tr").length === 4, + "Display loaded custom fields" + ); + assert.ok( + query(".message-content").innerText.includes( + "View, create, edit and destroy custom fields" + ), + "it displays wizard message" + ); + }); + test("view available custom fields for unsubscribed plan", async (assert) => { + await visit("/admin/wizards/custom-fields"); + await click(".admin-wizard-controls .btn-icon-text"); + assert.ok( + visible(".wizard-subscription-selector"), + "custom field class is present" + ); + assert.ok( + visible(".wizard-subscription-selector-header"), + "custom field type is present" + ); + assert.ok(visible(".input"), "custom field name is present"); + assert.ok(visible(".multi-select"), "custom field serializer is present"); + assert.ok(visible(".actions"), "custom field action buttons are present"); + + const dropdown1 = selectKit( + '.admin-wizard-container details:has(summary[name="Filter by: Select a class"])' + ); + await dropdown1.expand(); + let enabledOptions1 = findAll( + '.admin-wizard-container details:has(summary[name="Filter by: Select a class"]) ul li:not(.disabled)' + ); + let disabledOptions1 = findAll( + '.admin-wizard-container details:has(summary[name="Filter by: Select a class"]) ul li.disabled' + ); + assert.equal( + enabledOptions1.length, + 2, + "There are two enabled options for class fields" + ); + assert.equal( + disabledOptions1.length, + 2, + "There are two disabled options for class fields" + ); + const dropdown2 = selectKit( + '.admin-wizard-container details:has(summary[name="Filter by: Select a type"])' + ); + await dropdown2.expand(); + let enabledOptions2 = findAll( + '.admin-wizard-container details:has(summary[name="Filter by: Select a type"]) ul li:not(.disabled)' + ); + let disabledOptions2 = findAll( + '.admin-wizard-container details:has(summary[name="Filter by: Select a type"]) ul li.disabled' + ); + assert.equal( + enabledOptions2.length, + 3, + "There are three enabled options for type" + ); + assert.equal( + disabledOptions2.length, + 1, + "There is one disabled option for type" + ); + }); + test("change custom fields for unsubscribed plan", async (assert) => { + await visit("/admin/wizards/custom-fields"); + await click(".admin-wizard-controls .btn-icon-text"); + + const dropdown1 = selectKit( + '.admin-wizard-container details:has(summary[name="Filter by: Select a class"])' + ); + await dropdown1.expand(); + await click('.select-kit-collection li[data-value="topic"]'); + const serializerDropdown = selectKit( + ".admin-wizard-container details.multi-select" + ); + await serializerDropdown.expand(); + let enabledOptions1 = findAll( + ".admin-wizard-container details.multi-select ul li" + ); + assert.equal( + enabledOptions1.length, + 2, + "There are two enabled options in the serializer dropdown for Topic" + ); + await serializerDropdown.collapse(); + const dropdown2 = selectKit( + '.admin-wizard-container details:has(summary[name="Filter by: Topic"])' + ); + await dropdown2.expand(); + await click('.select-kit-collection li[data-value="post"]'); + await serializerDropdown.expand(); + let enabledOptions2 = findAll( + ".admin-wizard-container details.multi-select ul li" + ); + assert.equal( + enabledOptions2.length, + 1, + "There is one enabled option in the serializer dropdown for Post" + ); + }); + + test("Create Topic and Post custom fields", async (assert) => { + await visit("/admin/wizards/custom-fields"); + assert.ok( + findAll("table tbody tr").length === 4, + "Display loaded custom fields" + ); + await click(".admin-wizard-controls .btn-icon-text"); + + const dropdownTopic = selectKit( + '.admin-wizard-container details:has(summary[name="Filter by: Select a class"])' + ); + await dropdownTopic.expand(); + await click('.select-kit-collection li[data-value="topic"]'); + + await selectTypeAndSerializerAndFillInName( + "String", + "Topic View", + "Topic Custom Field", + "Filter by: Select a type" + ); + + await click(".actions .save"); + // Wait for the "Saved custom field" message to appear + await waitForSaveMessage(); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(1) label" + ).innerText.includes("topic"), + "Topic custom field is displayed" + ); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(3) label" + ).innerText.includes("topic_custom_field"), + "Topic custom field name is displayed" + ); + + await click(".admin-wizard-controls .btn-icon-text"); + + const dropdownPost = selectKit( + '.admin-wizard-container details:has(summary[name="Filter by: Select a class"])' + ); + await dropdownPost.expand(); + await click('.select-kit-collection li[data-value="post"]'); + + await selectTypeAndSerializerAndFillInName( + "Boolean", + "Post", + "Post Custom Field", + "Filter by: Select a type" + ); + + await click(".actions .save"); + // Wait for the "Saved custom field" message to appear + await waitForSaveMessage(); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(1) label" + ).innerText.includes("post"), + "Post custom field is displayed" + ); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(3) label" + ).innerText.includes("post_custom_field"), + "Post custom field name is displayed" + ); + assert.ok( + findAll("table tbody tr").length === 6, + "Display added custom fields" + ); + }); + test("Update Topic custom field", async (assert) => { + await visit("/admin/wizards/custom-fields"); + await click(".admin-wizard-controls .btn-icon-text"); + const dropdownTopic = selectKit( + '.admin-wizard-container details:has(summary[name="Filter by: Select a class"])' + ); + await dropdownTopic.expand(); + await click('.select-kit-collection li[data-value="topic"]'); + await selectTypeAndSerializerAndFillInName( + "String", + "Topic View", + "Topic Custom Field", + "Filter by: Select a type" + ); + await click(".actions .save"); + await waitForSaveMessage(); + await click(".admin-wizard-container tbody tr:first-child button"); + await selectTypeAndSerializerAndFillInName( + "Boolean", + "Topic List Item", + "Updated Topic Custom Field", + "Filter by: String" + ); + await click(".admin-wizard-container tbody tr:first-child .save"); + await waitForSaveMessage(); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(1) label" + ).innerText.includes("topic"), + "Topic custom field is displayed" + ); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(2) label" + ).innerText.includes("boolean"), + "Updated Type is displayed" + ); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(3) label" + ).innerText.includes("updated_topic_custom_field"), + "Updated Topic custom field name is displayed" + ); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(4)" + ).innerText.includes("topic_view"), + "Original Serializer is displayed" + ); + assert.ok( + query( + ".admin-wizard-container tbody tr:first-child td:nth-child(4)" + ).innerText.includes("topic_list_item"), + "Updated Serializer is displayed" + ); + }); + test("Delete Topic custom field", async (assert) => { + await visit("/admin/wizards/custom-fields"); + assert.ok( + findAll("table tbody tr").length === 4, + "Display loaded custom fields" + ); + await click(".admin-wizard-controls .btn-icon-text"); + + const dropdownTopic = selectKit( + '.admin-wizard-container details:has(summary[name="Filter by: Select a class"])' + ); + await dropdownTopic.expand(); + await click('.select-kit-collection li[data-value="topic"]'); + await selectTypeAndSerializerAndFillInName( + "String", + "Topic View", + "Topic Custom Field", + "Filter by: Select a type" + ); + await click(".actions .save"); + await waitForSaveMessage(); + assert.ok( + findAll("table tbody tr").length === 5, + "Display added custom fields" + ); + await click(".admin-wizard-container tbody tr:first-child button"); + await click(".actions .destroy"); + assert.ok( + findAll("table tbody tr").length === 4, + "Display custom fields without deleted fields" + ); + }); +}); diff --git a/test/javascripts/acceptance/admin-logs-test.js b/test/javascripts/acceptance/admin-logs-test.js new file mode 100644 index 00000000..c888a55a --- /dev/null +++ b/test/javascripts/acceptance/admin-logs-test.js @@ -0,0 +1,69 @@ +import { acceptance, query } from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, findAll, visit } from "@ember/test-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; +import { + getUnsubscribedAdminWizards, + getWizard, + getWizardTestingLog, +} from "../helpers/admin-wizard"; + +acceptance("Admin | Logs", function (needs) { + needs.user(); + needs.settings({ + custom_wizard_enabled: true, + available_locales: JSON.stringify([{ name: "English", value: "en" }]), + }); + needs.pretender((server, helper) => { + server.get("/admin/wizards/logs", () => { + return helper.response([ + { id: "this_is_testing_wizard", name: "This is testing wizard" }, + ]); + }); + server.get("/admin/wizards/logs/this_is_testing_wizard", () => { + return helper.response(getWizardTestingLog); + }); + server.get("/admin/wizards", () => { + return helper.response(getUnsubscribedAdminWizards); + }); + server.get("/admin/wizards/wizard", () => { + return helper.response(getWizard); + }); + }); + test("viewing logs fields tab", async (assert) => { + await visit("/admin/wizards/logs"); + const wizards = selectKit(".select-kit"); + assert.ok( + query(".message-content").innerText.includes( + "Select a wizard to see its logs" + ), + "it displays logs message" + ); + assert.ok( + query(".message-content").innerText.includes("Select a wizard"), + "it displays list of logs" + ); + await wizards.expand(); + await wizards.selectRowByValue("this_is_testing_wizard"); + assert.ok( + query(".message-content").innerText.includes( + "View recent logs for wizards on the forum" + ), + "it displays logs for a selected wizard" + ); + assert.ok(find("table")); + assert.ok(findAll("table tbody tr").length === 2, "Displays logs list"); + + await click(".refresh.btn"); + assert.ok(find("table")); + assert.ok( + findAll("table tbody tr").length === 2, + "Refresh button works correctly" + ); + + await wizards.expand(); + await click('[data-name="Select a wizard"]'); + const wizardContainerDiv = find(".admin-wizard-container"); + assert.ok(wizardContainerDiv.children().length === 0, "the div is empty"); + }); +}); diff --git a/test/javascripts/acceptance/admin-manager-test.js b/test/javascripts/acceptance/admin-manager-test.js new file mode 100644 index 00000000..afa1b006 --- /dev/null +++ b/test/javascripts/acceptance/admin-manager-test.js @@ -0,0 +1,111 @@ +import { acceptance, query } from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, find, findAll, visit, waitUntil } from "@ember/test-helpers"; +import { + getUnsubscribedAdminWizards, + getWizard, + getWizardTestingLog, +} from "../helpers/admin-wizard"; + +acceptance("Admin | Manager", function (needs) { + needs.user(); + needs.settings({ + custom_wizard_enabled: true, + available_locales: JSON.stringify([{ name: "English", value: "en" }]), + }); + needs.pretender((server, helper) => { + server.get("/admin/wizards/manager/this_is_testing_wizard", () => { + return helper.response(getWizardTestingLog); + }); + server.get("/admin/wizards", () => { + return helper.response(getUnsubscribedAdminWizards); + }); + server.get("/admin/wizards/wizard", () => { + return helper.response(getWizard); + }); + server.delete("/admin/wizards/manager/destroy", () => { + return helper.response({ + success: "OK", + destroyed: [ + { id: "this_is_testing_wizard", name: "This is testing wizard" }, + ], + failures: [], + }); + }); + }); + async function waitForDestructionAndResetMessage() { + await waitUntil( + () => + document.querySelector(".message-content")?.innerText === + "Destruction complete", + { timeout: 5000 } + ); + + await waitUntil( + () => + document.querySelector(".message-content")?.innerText === + "Export, import or destroy wizards" && + !document.querySelector(".message-block.primary ul") && + !find(".message-block.primary svg").classList.contains( + "d-icon-check-circle" + ), + { timeout: 15000 } + ); + // Wait an additional second after the conditions are met + await new Ember.RSVP.Promise((resolve) => setTimeout(resolve, 1000)); + } + + test("viewing manager fields content", async (assert) => { + await visit("/admin/wizards/manager"); + assert.ok( + query(".message-content").innerText.includes( + "Export, import or destroy wizards" + ), + "it displays manager message" + ); + assert.ok( + find('table tr[data-wizard-id="this-is-testing-wizard"]'), + "table shows the wizard content list" + ); + + const checkbox = findAll( + 'table tr[data-wizard-id="this-is-testing-wizard"] input[type="checkbox"]' + ); + const exportCheck = checkbox[0]; + const destroyCheck = checkbox[1]; + + const exportButton = find("#export-button"); + assert.ok( + exportButton.hasAttribute("disabled"), + "the export button is disabled when export checkbox is unchecked" + ); + + await click(exportCheck); + assert.ok( + !exportButton.hasAttribute("disabled"), + "the export button is enabled when export checkbox is clicked" + ); + await click(exportCheck); + assert.ok( + exportButton.hasAttribute("disabled"), + "the export button is disabled when export checkbox is unchecked" + ); + const destroyButton = find("#destroy-button"); + assert.ok( + destroyButton.hasAttribute("disabled"), + "the destroy button is disabled when destroy checkbox is unchecked" + ); + await click(destroyCheck); + assert.ok( + !destroyButton.hasAttribute("disabled"), + "the destroy button is enabled when destroy checkbox is clicked" + ); + await click("#destroy-button"); + + assert.notOk( + find('table tr[data-wizard-id="this-is-testing-wizard"]'), + "the wizard row is removed after destroy button is clicked" + ); + await waitForDestructionAndResetMessage(); + }); +}); diff --git a/test/javascripts/acceptance/admin-submissions-test.js b/test/javascripts/acceptance/admin-submissions-test.js new file mode 100644 index 00000000..50635a37 --- /dev/null +++ b/test/javascripts/acceptance/admin-submissions-test.js @@ -0,0 +1,229 @@ +import { acceptance, query } from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, findAll, visit } from "@ember/test-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; +import { + getAnotherWizardSubmission, + getUnsubscribedAdminWizards, + getWizard, + getWizardSubmissions, +} from "../helpers/admin-wizard"; + +acceptance("Admin | Submissions", function (needs) { + needs.user(); + needs.settings({ + custom_wizard_enabled: true, + available_locales: JSON.stringify([{ name: "English", value: "en" }]), + }); + needs.pretender((server, helper) => { + server.get("/admin/wizards/submissions", () => { + return helper.response([ + { id: "this_is_testing_wizard", name: "This is testing wizard" }, + { id: "another_wizard", name: "another wizard" }, + ]); + }); + server.get("/admin/wizards/submissions/this_is_testing_wizard", () => { + return helper.response(getWizardSubmissions); + }); + server.get("/admin/wizards/submissions/another_wizard", () => { + return helper.response(getAnotherWizardSubmission); + }); + server.get("/admin/wizards", () => { + return helper.response(getUnsubscribedAdminWizards); + }); + server.get("/admin/wizards/wizard", () => { + return helper.response(getWizard); + }); + }); + test("View submissions fields tab and content", async (assert) => { + await visit("/admin/wizards/submissions"); + const wizards = selectKit(".select-kit"); + assert.ok( + query(".message-content").innerText.includes( + "Select a wizard to see its submissions" + ), + "it displays submissions message" + ); + assert.ok( + query(".message-content").innerText.includes("Select a wizard"), + "it displays list of wizards" + ); + await wizards.expand(); + await wizards.selectRowByValue("this_is_testing_wizard"); + assert.ok( + query(".message-content").innerText.includes( + "You're viewing the submissions of the This is testing wizard" + ), + "it displays submissions for a selected wizard" + ); + const submissions = getWizardSubmissions.submissions; // Get submissions data from your JSON file + const rows = findAll("table tbody tr"); + + for (let i = 0; i < submissions.length; i++) { + const dateCell = rows[i].querySelector("td:nth-child(1)"); + const userCell = rows[i].querySelector("td:nth-child(2)"); + const stepCell = rows[i].querySelector("td:nth-child(3)"); + const expectedDate = moment(submissions[i].submitted_at).format( + "MMM D, YYYY h:mm a" + ); + + assert.equal( + dateCell.innerText, + expectedDate, + `Date is displayed correctly for submission ${i + 1}` + ); + assert.equal( + userCell.innerText.trim(), + submissions[i].user.username, + `User is displayed correctly for submission ${i + 1}` + ); + assert.equal( + stepCell.innerText.trim().split("\n")[0], + submissions[i].fields.step_1_field_1.value, + `Step is displayed correctly for submission ${i + 1}` + ); + } + assert.ok( + findAll("table tbody tr").length >= 1, + "Displays submissions list" + ); + + await wizards.expand(); + await click('[data-name="Select a wizard"]'); + const wizardContainerDiv = find(".admin-wizard-container"); + assert.ok(wizardContainerDiv.children().length === 0, "the div is empty"); + }); + test("View submissions tab for another wizard with more steps", async (assert) => { + await visit("/admin/wizards/submissions"); + const wizards = selectKit(".select-kit"); + + await wizards.expand(); + await wizards.selectRowByValue("another_wizard"); + + assert.ok( + query(".message-content").innerText.includes( + "You're viewing the submissions of the another wizard" + ), + "it displays submissions for another wizard" + ); + + const submissions = getAnotherWizardSubmission.submissions; // Get submissions data from your JSON file + const rows = findAll("table tbody tr"); + + for (let i = 0; i < submissions.length; i++) { + const dateCell = rows[i].querySelector("td:nth-child(1)"); + const userCell = rows[i].querySelector("td:nth-child(2)"); + const step1Cell = rows[i].querySelector("td:nth-child(3)"); + const step2Cell = rows[i].querySelector("td:nth-child(4)"); + const submission = submissions[i]; + const expectedDate = moment(submission.submitted_at).format( + "MMM D, YYYY h:mm a" + ); + + assert.equal( + dateCell.innerText, + expectedDate, + `Date is displayed correctly for submission ${i + 1}` + ); + assert.equal( + userCell.innerText.trim(), + submissions[i].user.username, + `User is displayed correctly for submission ${i + 1}` + ); + assert.equal( + step1Cell.innerText.trim().split("\n")[0], + submissions[i].fields.step_1_field_1.value, + `Step 1 is displayed correctly for submission ${i + 1}` + ); + assert.equal( + step2Cell.innerText.trim().split("\n")[0], + submissions[i].fields.step_2_field_1.value, + `Step 2 is displayed correctly for submission ${i + 1}` + ); + } + + assert.ok( + findAll("table tbody tr").length >= 1, + "Displays submissions list for another wizard" + ); + }); + test("Modal actions for submissions", async (assert) => { + await visit("/admin/wizards/submissions"); + const wizards = await selectKit(".select-kit"); + await wizards.expand(); + await wizards.selectRowByValue("this_is_testing_wizard"); + + await click(".open-edit-columns-btn"); + assert.dom(".modal-inner-container").exists("Modal is displayed"); + + const userCheckbox = find( + ".edit-directory-columns-container .edit-directory-column:nth-child(2) .left-content .column-name input" + ); + assert.ok(userCheckbox, "User checkbox is present"); + assert.ok(userCheckbox[0].checked, "User checkbox is checked by default"); + await click(userCheckbox[0]); + assert.notOk( + userCheckbox[0].checked, + "User checkbox is unchecked after clicking" + ); + + await click(".modal-footer .btn-primary"); + assert + .dom("table thead th") + .doesNotIncludeText("User", "User column is not displayed"); + + await click(".open-edit-columns-btn"); + const submittedAtCheckbox = find( + ".edit-directory-columns-container .edit-directory-column:nth-child(1) .left-content .column-name input" + ); + assert.ok(submittedAtCheckbox, "Submitted At checkbox is present"); + assert.ok( + submittedAtCheckbox[0].checked, + "Submitted At checkbox is checked by default" + ); + await click(submittedAtCheckbox[0]); + + await click(".modal-footer .btn-primary"); + assert.notOk( + submittedAtCheckbox[0].checked, + "Submitted At checkbox is unchecked after clicking" + ); + assert + .dom("table thead th") + .doesNotIncludeText( + "Submitted At", + "Submitted At column is not displayed" + ); + + await click(".open-edit-columns-btn"); + await click(".modal-footer .btn-secondary"); + + assert + .dom("table thead th:nth-child(1)") + .hasText("Submitted At", "Submitted At column is displayed after reset"); + assert + .dom("table thead th:nth-child(2)") + .hasText("User", "User column is displayed after reset"); + }); + test("Download submissions", async (assert) => { + await visit("/admin/wizards/submissions"); + const wizards = await selectKit(".select-kit"); + await wizards.expand(); + await wizards.selectRowByValue("this_is_testing_wizard"); + + const downloadLinks = findAll(".download-link"); + assert.ok(downloadLinks.length > 1, "Download links are present"); + + const downloadLink = downloadLinks[1]; + await click(downloadLink); + + const expectedURL = + "/admin/wizards/submissions/this_is_testing_wizard/download"; + const actualURL = new URL(downloadLink.href); + assert.equal( + actualURL.pathname, + expectedURL, + "Download link has correct URL" + ); + }); +}); diff --git a/test/javascripts/acceptance/admin-wizards-api-test.js b/test/javascripts/acceptance/admin-wizards-api-test.js new file mode 100644 index 00000000..0bc61895 --- /dev/null +++ b/test/javascripts/acceptance/admin-wizards-api-test.js @@ -0,0 +1,123 @@ +import { acceptance, query } from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, visit } from "@ember/test-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; +import { + getBusinessAdminWizard, + getCustomFields, + getNewApi, + getWizard, + putNewApi, +} from "../helpers/admin-wizard"; + +acceptance("Admin | API tab", function (needs) { + needs.user(); + needs.settings({ + custom_wizard_enabled: true, + available_locales: JSON.stringify([{ name: "English", value: "en" }]), + }); + + needs.pretender((server, helper) => { + server.get("/admin/wizards/wizard", () => { + return helper.response(getWizard); + }); + server.get("/admin/wizards", () => { + return helper.response(getBusinessAdminWizard); + }); + server.get("/admin/wizards/custom-fields", () => { + return helper.response(getCustomFields); + }); + server.get("/admin/wizards/api", () => { + return helper.response([ + { + name: "new_api", + title: "new API", + endpoints: [{ id: "59e3b6", name: "ag" }], + }, + ]); + }); + server.get("/admin/customize/user_fields", () => { + return helper.response({ user_fields: [] }); + }); + server.put("/admin/wizards/api/new_api", () => { + return helper.response(putNewApi); + }); + server.get("/admin/wizards/api/new_api", () => { + return helper.response(getNewApi); + }); + }); + + test("Visit API tab and fill data", async function (assert) { + await visit("/admin/wizards/api"); + const list = find(".admin-controls li"); + const count = list.length; + assert.equal(count, 6, "There should be 6 admin tabs"); + + // create new api + await click(".admin-wizard-controls button"); + assert.ok( + query(".wizard-header.large").innerText.includes("New API"), + "it displays API creation message" + ); + assert.equal( + currentURL(), + "/admin/wizards/api/create", + "clicking the button navigates to the correct URL" + ); + // fill data + await fillIn('.metadata input[placeholder="Display name"]', "new API"); + await fillIn('.metadata input[placeholder="Underscored"]', "new_api"); + const fieldTypeDropdown = selectKit( + ".wizard-api-authentication .settings .control-group.auth-type .select-kit" + ); + await fieldTypeDropdown.expand(); + await fieldTypeDropdown.selectRowByValue("basic"); + await fillIn( + ".wizard-api-authentication .settings .control-group:eq(1) .controls input", + "some_username" + ); + await fillIn( + ".wizard-api-authentication .settings .control-group:eq(2) .controls input", + "some_password" + ); + await click(".wizard-api-endpoints button"); + await fillIn( + '.wizard-api-endpoints .endpoint .top input[placeholder="Endpoint name"]', + "endpoint_name" + ); + await fillIn( + '.wizard-api-endpoints .endpoint .top input[placeholder="Enter a url"]', + "https://test.api.com" + ); + const endpointMethodDropdown = await selectKit( + '.wizard-api-endpoints .endpoint .bottom details:has(summary[name="Filter by: Select a method"])' + ); + await endpointMethodDropdown.expand(); + await endpointMethodDropdown.selectRowByValue("POST"); + + const contentTypeDropdown = await selectKit( + '.wizard-api-endpoints .endpoint .bottom details:has(summary[name="Filter by: Select a content type"])' + ); + await contentTypeDropdown.expand(); + await contentTypeDropdown.selectRowByValue("application/json"); + + const successCodesDropdown = await selectKit( + ".wizard-api-endpoints .endpoint .bottom details.multi-select" + ); + await successCodesDropdown.expand(); + await successCodesDropdown.selectRowByValue(200); + await successCodesDropdown.selectRowByValue(100); + + assert.strictEqual( + successCodesDropdown.header().value(), + "200,100", + "group should be set" + ); + await click(".wizard-api-header.page button.btn-primary"); + assert.equal( + currentURL(), + "/admin/wizards/api/new_api", + "clicking the button navigates to the correct URL" + ); + }); +}); diff --git a/test/javascripts/acceptance/admin-wizards-business-subscription-test.js b/test/javascripts/acceptance/admin-wizards-business-subscription-test.js new file mode 100644 index 00000000..4ba326d9 --- /dev/null +++ b/test/javascripts/acceptance/admin-wizards-business-subscription-test.js @@ -0,0 +1,252 @@ +import { + acceptance, + query, + visible, +} from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, findAll, visit } from "@ember/test-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; +import { + getAdminTestingWizard, + getBusinessAdminWizard, + getCreatedWizard, + getCustomFields, + getWizard, +} from "../helpers/admin-wizard"; + +acceptance("Admin | Custom Wizard Business Subscription", function (needs) { + needs.user(); + needs.settings({ + custom_wizard_enabled: true, + available_locales: JSON.stringify([{ name: "English", value: "en" }]), + }); + + needs.pretender((server, helper) => { + server.get("/admin/wizards/wizard", () => { + return helper.response(getWizard); + }); + server.get("/admin/wizards/custom-fields", () => { + return helper.response(getCustomFields); + }); + server.get("/admin/wizards", () => { + return helper.response(getBusinessAdminWizard); + }); + server.get("/admin/wizards/api", () => { + return helper.response([]); + }); + server.get("/admin/customize/user_fields", () => { + return helper.response({ user_fields: [] }); + }); + server.get("/admin/wizards/wizard/this_is_testing_wizard", () => { + return helper.response(getAdminTestingWizard); + }); + server.put("/admin/wizards/wizard/new_wizard_for_testing", () => { + return helper.response({ + success: "OK", + wizard_id: "new_wizard_for_testing", + }); + }); + server.get("/admin/wizards/wizard/new_wizard_for_testing", () => { + return helper.response(getCreatedWizard); + }); + }); + + test("Displaying all tabs including API", async (assert) => { + await visit("/admin/wizards"); + const list = find(".admin-controls li"); + const count = list.length; + assert.equal(count, 6, "There should be 6 admin tabs"); + }); + + test("creating a new wizard", async (assert) => { + await visit("/admin/wizards/wizard"); + await click(".admin-wizard-controls button"); + assert.ok( + query(".message-content").innerText.includes( + "You're creating a new wizard" + ), + "it displays wizard creation message" + ); + // "Step 1: Inserting a title + const wizardTitle = "New wizard for testing"; + await fillIn(".wizard-header input", wizardTitle); + assert.equal( + $(".wizard-header input").val(), + wizardTitle, + "The title input is inserted" + ); + const wizardLink = find("div.wizard-url a"); + assert.equal(wizardLink.length, 1, "Wizard link was created"); + assert.equal( + find(".wizard-subscription-container a:contains('Subscribed')").length, + 1, + "Wizard subscription features are accesible" + ); + await click( + '.wizard-subscription-container .subscription-settings .setting-value input[type="checkbox"]' + ); + assert.ok( + find( + '.wizard-subscription-container .subscription-settings .setting-value input[type="checkbox"]' + ).is(":checked"), + "subscription feature available" + ); + + // Step 2: Creating a step section + await click(".step .link-list button"); + const stepOneText = "step_1 (step_1)"; + const stepOneBtn = find(`.step button:contains(${stepOneText})`); + assert.equal(stepOneBtn.length, 1, "Creating a step"); + const stepTitle = "step title"; + await fillIn(".wizard-custom-step input[name='title']", stepTitle); + const stepButtonText = $.trim( + $(".step div[data-id='step_1'] button").text() + ); + assert.ok( + stepButtonText.includes(stepTitle), + "The step button changes according to title" + ); + assert.equal( + find(".wizard-subscription-container a:contains('Subscribed')").length, + 2, + "Steps subscription features are accesible" + ); + // Step 3: Creating a field section + await click(".field .link-list button"); + + assert.ok( + !visible(".wizard-custom-field button.undo-changes"), + "clear button is not rendered" + ); + const fieldOneText = "step_1_field_1 (step_1_field_1)"; + const fieldOneBtn = find(`.field button:contains(${fieldOneText})`); + assert.equal(fieldOneBtn.length, 1, "Creating a field"); + const fieldTitle = "field title"; + await fillIn(".wizard-custom-field input[name='label']", fieldTitle); + assert.ok( + visible(".wizard-custom-field button.undo-changes"), + "clear button is rendered after filling content" + ); + let fieldButtonText = $.trim( + $(".field div[data-id='step_1_field_1'] button").text() + ); + assert.ok( + fieldButtonText.includes(fieldTitle), + "The step button changes according to title" + ); + await click(`.wizard-custom-field button.undo-changes`); + fieldButtonText = $(".field div[data-id='step_1_field_1'] button") + .text() + .trim(); + assert.ok( + fieldButtonText.includes("step_1_field_1 (step_1_field_1)"), + "The field button changes to default title after clear button is clicked" + ); + const fieldTypeDropdown = selectKit( + ".wizard-custom-field .setting-value .select-kit" + ); + await fieldTypeDropdown.expand(); + await fieldTypeDropdown.selectRowByValue("text"); + assert.ok( + query(".wizard-custom-field .message-content").innerText.includes( + "You're editing a field" + ), + "Text tipe for field correctly selected" + ); + assert.equal( + find(".wizard-subscription-container a:contains('Subscribed')").length, + 3, + "Field subscription features are accesible" + ); + + // Step 4: Creating a action section + await click(".action .link-list button"); + + const actionOneText = "action_1 (action_1)"; + const actionOneBtn = find(`.action button:contains(${actionOneText})`); + assert.equal(actionOneBtn.length, 1, "Creating an action"); + assert.ok( + query( + ".wizard-custom-action .wizard-message .message-content" + ).innerText.includes("Select an action type"), + "it displays wizard select action message" + ); + const actionTypeDropdown = selectKit( + ".wizard-custom-action .setting-value .select-kit" + ); + await actionTypeDropdown.expand(); + const listEnabled = findAll( + ".wizard-custom-action .setting .setting-value ul li:not(.disabled)" + ); + const listDisabled = findAll( + ".wizard-custom-action .setting .setting-value ul li.disabled" + ); + assert.ok( + listDisabled.length === 0, + "Disabled items displayed correctly in action dropdown" + ); + assert.ok( + listEnabled.length === 11, + "Enabled items displayed correctly in action dropdown" + ); + await actionTypeDropdown.selectRowByValue("create_topic"); + assert.ok( + query(".wizard-custom-action .message-content").innerText.includes( + "You're editing an action" + ), + "Create type action correctly selected" + ); + let listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 10, + "Display all settings of create topic" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("send_to_api"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 5, + "Display all settings of send to api" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("create_category"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 9, + "Display all settings of create categories" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("create_group"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 14, + "Display all settings of create group" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("create_topic"); + assert.ok( + !visible('.admin-wizard-buttons button:contains("Delete Wizard")'), + "delete wizard button not displayed" + ); + //Step 5: Save wizard + await click(".admin-wizard-buttons button"); + + assert.equal( + currentURL(), + "/admin/wizards/wizard/new_wizard_for_testing", + "clicking the button navigates to the correct URL" + ); + assert.ok( + visible('.admin-wizard-buttons button:contains("Delete Wizard")'), + "delete wizard button visible" + ); + }); +}); diff --git a/test/javascripts/acceptance/admin-wizards-standard-subscription-test.js b/test/javascripts/acceptance/admin-wizards-standard-subscription-test.js new file mode 100644 index 00000000..b3debf77 --- /dev/null +++ b/test/javascripts/acceptance/admin-wizards-standard-subscription-test.js @@ -0,0 +1,245 @@ +import { + acceptance, + query, + visible, +} from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, findAll, visit } from "@ember/test-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; +import { + getAdminTestingWizard, + getCreatedWizard, + getCustomFields, + getStandardAdminWizard, + getWizard, +} from "../helpers/admin-wizard"; + +acceptance("Admin | Custom Wizard Standard Subscription", function (needs) { + needs.user(); + needs.settings({ + custom_wizard_enabled: true, + available_locales: JSON.stringify([{ name: "English", value: "en" }]), + }); + + needs.pretender((server, helper) => { + server.get("/admin/wizards/wizard", () => { + return helper.response(getWizard); + }); + server.get("/admin/wizards/custom-fields", () => { + return helper.response(getCustomFields); + }); + server.get("/admin/wizards", () => { + return helper.response(getStandardAdminWizard); + }); + server.get("/admin/wizards/api", () => { + return helper.response({ success: "OK" }); + }); + server.get("/admin/customize/user_fields", () => { + return helper.response({ user_fields: [] }); + }); + server.get("/admin/wizards/wizard/this_is_testing_wizard", () => { + return helper.response(getAdminTestingWizard); + }); + server.put("/admin/wizards/wizard/new_wizard_for_testing", () => { + return helper.response({ + success: "OK", + wizard_id: "new_wizard_for_testing", + }); + }); + server.get("/admin/wizards/wizard/new_wizard_for_testing", () => { + return helper.response(getCreatedWizard); + }); + }); + + test("Displaying all tabs except API", async (assert) => { + await visit("/admin/wizards"); + const list = find(".admin-controls li"); + const count = list.length; + assert.equal(count, 5, "There should be 5 admin tabs"); + }); + + test("creting a new wizard", async (assert) => { + await visit("/admin/wizards/wizard"); + await click(".admin-wizard-controls button"); + assert.ok( + query(".message-content").innerText.includes( + "You're creating a new wizard" + ), + "it displays wizard creation message" + ); + // ("Step 1: Inserting a title") + const wizardTitle = "New wizard for testing"; + await fillIn(".wizard-header input", wizardTitle); + assert.equal( + $(".wizard-header input").val(), + wizardTitle, + "The title input is inserted" + ); + const wizardLink = find("div.wizard-url a"); + assert.equal(wizardLink.length, 1, "Wizard link was created"); + assert.equal( + find(".wizard-subscription-container a:contains('Subscribed')").length, + 1, + "Wizard subscription features are accesible" + ); + const subsFeature = find( + ".wizard-subscription-container .subscription-settings .setting-value input" + ); + await click( + ".wizard-subscription-container .subscription-settings .setting-value input" + ); + assert.ok(subsFeature.is(":checked"), "subscription feature available"); + // ("Step 2: Creating a step section") + await click(".step .link-list button"); + const stepOneText = "step_1 (step_1)"; + const stepOneBtn = find(`.step button:contains(${stepOneText})`); + assert.equal(stepOneBtn.length, 1, "Creating a step"); + const stepTitle = "step title"; + await fillIn(".wizard-custom-step input[name='title']", stepTitle); + const stepButtonText = $.trim( + $(".step div[data-id='step_1'] button").text() + ); + assert.ok( + stepButtonText.includes(stepTitle), + "The step button changes according to title" + ); + assert.equal( + find(".wizard-subscription-container a:contains('Subscribed')").length, + 2, + "Steps subscription features are accesible" + ); + // step("Step 3: Creating a field section") + await click(".field .link-list button"); + assert.ok( + !visible(".wizard-custom-field button.undo-changes"), + "clear button is not rendered" + ); + const fieldOneText = "step_1_field_1 (step_1_field_1)"; + const fieldOneBtn = find(`.field button:contains(${fieldOneText})`); + assert.equal(fieldOneBtn.length, 1, "Creating a field"); + const fieldTitle = "field title"; + await fillIn(".wizard-custom-field input[name='label']", fieldTitle); + assert.ok( + visible(".wizard-custom-field button.undo-changes"), + "clear button is rendered after filling content" + ); + let fieldButtonText = $.trim( + $(".field div[data-id='step_1_field_1'] button").text() + ); + assert.ok( + fieldButtonText.includes(fieldTitle), + "The step button changes according to title" + ); + await click(`.wizard-custom-field button.undo-changes`); + fieldButtonText = $(".field div[data-id='step_1_field_1'] button") + .text() + .trim(); + assert.ok( + fieldButtonText.includes("step_1_field_1 (step_1_field_1)"), + "The field button changes to default title after clear button is clicked" + ); + const fieldTypeDropdown = selectKit( + ".wizard-custom-field .setting-value .select-kit" + ); + await fieldTypeDropdown.expand(); + await fieldTypeDropdown.selectRowByValue("text"); + assert.ok( + query(".wizard-custom-field .message-content").innerText.includes( + "You're editing a field" + ), + "Text tipe for field correctly selected" + ); + assert.equal( + find(".wizard-subscription-container a:contains('Subscribed')").length, + 3, + "Field subscription features are accesible" + ); + // ("Step 4: Creating a action section") + await click(".action .link-list button"); + const actionOneText = "action_1 (action_1)"; + const actionOneBtn = find(`.action button:contains(${actionOneText})`); + assert.equal(actionOneBtn.length, 1, "Creating an action"); + assert.ok( + query( + ".wizard-custom-action .wizard-message .message-content" + ).innerText.includes("Select an action type"), + "it displays wizard select action message" + ); + const actionTypeDropdown = selectKit( + ".wizard-custom-action .setting-value .select-kit" + ); + await actionTypeDropdown.expand(); + const listEnabled = findAll( + ".wizard-custom-action .setting .setting-value ul li:not(.disabled)" + ); + const listDisabled = findAll( + ".wizard-custom-action .setting .setting-value ul li.disabled" + ); + assert.ok( + listDisabled.length === 4, + "Disabled items displayed correctly in action dropdown" + ); + assert.ok( + listEnabled.length === 7, + "Enabled items displayed correctly in action dropdown" + ); + await actionTypeDropdown.selectRowByValue("create_topic"); + assert.ok( + query(".wizard-custom-action .message-content").innerText.includes( + "You're editing an action" + ), + "Create type action correctly selected" + ); + let listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 10, + "Display all settings of create topic" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("send_message"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 9, + "Display all settings of send message" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("watch_categories"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 7, + "Display all settings of watch categories" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("add_to_group"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 3, + "Display all settings of add to group" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("create_topic"); + // step("Step 5: Save wizard"); + assert.ok( + !visible('.admin-wizard-buttons button:contains("Delete Wizard")'), + "delete wizard button not displayed" + ); + await click(".admin-wizard-buttons button"); + assert.equal( + currentURL(), + "/admin/wizards/wizard/new_wizard_for_testing", + "clicking the button navigates to the correct URL" + ); + assert.ok( + visible('.admin-wizard-buttons button:contains("Delete Wizard")'), + "delete wizard button visible" + ); + }); +}); diff --git a/test/javascripts/acceptance/admin-wizards-unsuscribed-test.js b/test/javascripts/acceptance/admin-wizards-unsuscribed-test.js new file mode 100644 index 00000000..cc2f8bdb --- /dev/null +++ b/test/javascripts/acceptance/admin-wizards-unsuscribed-test.js @@ -0,0 +1,587 @@ +import { + acceptance, + query, + visible, +} from "discourse/tests/helpers/qunit-helpers"; +import { test } from "qunit"; +import { click, findAll, visit } from "@ember/test-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; +import { + getAdminTestingWizard, + getCreatedWizard, + getCustomFields, + getUniqueWizard, + getUnsubscribedAdminWizards, + getWizard, +} from "../helpers/admin-wizard"; + +acceptance("Admin | Custom Wizard Unsuscribed", function (needs) { + needs.user(); + needs.settings({ + custom_wizard_enabled: true, + available_locales: JSON.stringify([{ name: "English", value: "en" }]), + }); + + needs.pretender((server, helper) => { + server.get("/admin/wizards/wizard", () => { + return helper.response(getWizard); + }); + server.get("/admin/wizards/custom-fields", () => { + return helper.response(getCustomFields); + }); + server.get("/admin/wizards", () => { + return helper.response(getUnsubscribedAdminWizards); + }); + server.get("/admin/wizards/api", () => { + return helper.response({ success: "OK" }); + }); + server.get("/admin/customize/user_fields", () => { + return helper.response({ user_fields: [] }); + }); + server.get("/admin/wizards/wizard/this_is_testing_wizard", () => { + return helper.response(getAdminTestingWizard); + }); + server.put("/admin/wizards/wizard/new_wizard_for_testing", () => { + return helper.response({ + success: "OK", + wizard_id: "new_wizard_for_testing", + }); + }); + server.get("/admin/wizards/wizard/new_wizard_for_testing", () => { + return helper.response(getCreatedWizard); + }); + server.get("/admin/wizards/wizard/unique_wizard", () => { + return helper.response(getUniqueWizard); + }); + }); + + async function appendText(selector, text) { + let element = document.querySelector(selector); + if (element) { + let currentValue = element.value; + let newValue = currentValue + text; + await fillIn(selector, newValue); + } + } + + test("Displaying all tabs except API", async (assert) => { + await visit("/admin/wizards"); + const list = find(".admin-controls li"); + const count = list.length; + assert.equal(count, 5, "There should be 5 admin tabs"); + }); + + test("creting a new wizard", async (assert) => { + await visit("/admin/wizards/wizard"); + await click(".admin-wizard-controls button"); + assert.ok( + query(".message-content").innerText.includes( + "You're creating a new wizard" + ), + "it displays wizard creation message" + ); + const wizardTitle = "New wizard for testing"; + await fillIn(".wizard-header input", wizardTitle); + assert.equal( + $(".wizard-header input").val(), + wizardTitle, + "The title input is inserted" + ); + const wizardLink = find("div.wizard-url a"); + assert.equal(wizardLink.length, 1, "Wizard link was created"); + assert.equal( + $.trim($("a[title='Subscribe to use these features']").text()), + "Not Subscribed", + "Show messsage and link of user not subscribed" + ); + assert.equal( + find(".wizard-subscription-container").length, + 1, + "Wizard subscription features are not accesible" + ); + await click(".step .link-list button"); + const stepOneText = "step_1 (step_1)"; + const stepOneBtn = find(`.step button:contains(${stepOneText})`); + assert.equal(stepOneBtn.length, 1, "Creating a step"); + const stepTitle = "step title"; + await fillIn(".wizard-custom-step input[name='title']", stepTitle); + const stepButtonText = $.trim( + $(".step div[data-id='step_1'] button").text() + ); + assert.ok( + stepButtonText.includes(stepTitle), + "The step button changes according to title" + ); + assert.equal( + find(".wizard-subscription-container").length, + 2, + "Steps subscription features are not accesible" + ); + await appendText( + ".wizard-custom-step .wizard-text-editor textarea", + "Input in step description composer" + ); + await click(".wizard-custom-step .wizard-editor-gutter button:first-child"); + assert.strictEqual( + query( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper p" + ).textContent.trim(), + "Input in step description composer" + ); + await appendText( + ".wizard-custom-step .wizard-text-editor textarea", + "\n\n**Bold text**" + ); + let boldText = await query( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper strong" + ).innerHTML.trim(); + assert.strictEqual( + boldText, + "Bold text", + "The bold text in the preview wrapper should be 'Bold Text'" + ); + await appendText( + ".wizard-custom-step .wizard-text-editor textarea", + "\n\n*emphasized text*" + ); + let empText = await query( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper em" + ).innerHTML.trim(); + assert.strictEqual( + empText, + "emphasized text", + "The emphasized text in the preview wrapper should be 'emphasized text'" + ); + await appendText( + ".wizard-custom-step .wizard-text-editor textarea", + "\n\n> Blockqoute text" + ); + let blockquoteText = await query( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper blockquote p" + ).innerHTML.trim(); + assert.strictEqual( + blockquoteText, + "Blockqoute text", + "The emphasized text in the preview wrapper should be 'Blockqoute text'" + ); + await appendText( + ".wizard-custom-step .wizard-text-editor textarea", + `\n\n\`\`\` + \code text + \n\`\`\`` + ); + let codeText = await query( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper code" + ).innerHTML.trim(); + assert.strictEqual( + codeText, + "code text", + "The emphasized text in the preview wrapper should be 'code text'" + ); + await appendText( + ".wizard-custom-step .wizard-text-editor textarea", + `\n\n* List item\n* List item` + ); + let listItems = findAll( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper ul li" + ); + assert.strictEqual( + listItems.length, + 2, + "There should be two list items in the unordered list in the preview wrapper" + ); + assert.strictEqual( + listItems[0].textContent.trim(), + "List item", + "The first list item should be 'List item'" + ); + assert.strictEqual( + listItems[1].textContent.trim(), + "List item", + "The second list item should be 'List item'" + ); + await appendText( + ".wizard-custom-step .wizard-text-editor textarea", + `\n\n1. List item\n1. List item` + ); + let orderedListItems = findAll( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper ol li" + ); + assert.strictEqual( + orderedListItems.length, + 2, + "There should be two list items in the ordered list in the preview wrapper" + ); + assert.strictEqual( + orderedListItems[0].textContent.trim(), + "List item", + "The first list item should be 'List item'" + ); + assert.strictEqual( + orderedListItems[1].textContent.trim(), + "List item", + "The second list item should be 'List item'" + ); + await appendText( + ".wizard-custom-step .wizard-text-editor textarea", + `\n\n` + ); + await click( + ".wizard-custom-step .wizard-text-editor .d-editor button.link" + ); + assert.ok(exists(".insert-link.modal-body"), "hyperlink modal visible"); + + await fillIn(".modal-body .link-url", "google.com"); + await fillIn(".modal-body .link-text", "Google"); + await click(".modal-footer button.btn-primary"); + let urlText = await query( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper a" + ).innerHTML.trim(); + assert.strictEqual( + urlText, + "Google", + "The link text in the preview wrapper should be 'Google'" + ); + await click( + ".wizard-custom-step .wizard-text-editor .d-editor button.local-dates" + ); + assert.ok( + exists(".discourse-local-dates-create-modal.modal-body"), + "Insert date-time modal visible" + ); + assert.ok( + !exists( + ".discourse-local-dates-create-modal.modal-body .advanced-options" + ), + "Advanced mode not visible" + ); + await click(".modal-footer button.advanced-mode-btn"); + assert.ok( + exists( + ".discourse-local-dates-create-modal.modal-body .advanced-options" + ), + "Advanced mode is visible" + ); + await click(".modal-footer button.btn-primary"); + assert.ok( + exists( + ".wizard-custom-step .wizard-text-editor .d-editor-preview-wrapper span.discourse-local-date" + ), + "Date inserted" + ); + + await click(".field .link-list button"); + assert.ok( + !visible(".wizard-custom-field button.undo-changes"), + "clear button is not rendered" + ); + const fieldOneText = "step_1_field_1 (step_1_field_1)"; + const fieldOneBtn = find(`.field button:contains(${fieldOneText})`); + assert.equal(fieldOneBtn.length, 1, "Creating a field"); + const fieldTitle = "field title"; + await fillIn(".wizard-custom-field input[name='label']", fieldTitle); + assert.ok( + visible(".wizard-custom-field button.undo-changes"), + "clear button is rendered after filling content" + ); + let fieldButtonText = $.trim( + $(".field div[data-id='step_1_field_1'] button").text() + ); + assert.ok( + fieldButtonText.includes(fieldTitle), + "The step button changes according to title" + ); + await fillIn( + ".wizard-custom-field textarea[name='description']", + "First step field description" + ); + await click(`.wizard-custom-field button.undo-changes`); + fieldButtonText = $(".field div[data-id='step_1_field_1'] button") + .text() + .trim(); + assert.ok( + fieldButtonText.includes("step_1_field_1 (step_1_field_1)"), + "The field button changes to default title after clear button is clicked" + ); + await fillIn(".wizard-custom-field input[name='label']", fieldTitle); + await fillIn( + ".wizard-custom-field textarea[name='description']", + "First step field description" + ); + const fieldTypeDropdown = selectKit( + ".wizard-custom-field .setting-value .select-kit" + ); + await fieldTypeDropdown.expand(); + await fieldTypeDropdown.selectRowByValue("text"); + assert.ok( + query(".wizard-custom-field .message-content").innerText.includes( + "You're editing a field" + ), + "Text tipe for field correctly selected" + ); + assert.equal( + find(".wizard-subscription-container").length, + 3, + "Field subscription features are not accesible" + ); + await click(".action .link-list button"); + const actionOneText = "action_1 (action_1)"; + const actionOneBtn = find(`.action button:contains(${actionOneText})`); + assert.equal(actionOneBtn.length, 1, "Creating an action"); + assert.ok( + query( + ".wizard-custom-action .wizard-message .message-content" + ).innerText.includes("Select an action type"), + "it displays wizard select action message" + ); + const actionTypeDropdown = selectKit( + ".wizard-custom-action .setting-value .select-kit" + ); + await actionTypeDropdown.expand(); + const listEnabled = findAll( + ".wizard-custom-action .setting .setting-value ul li:not(.disabled)" + ); + const listDisabled = findAll( + ".wizard-custom-action .setting .setting-value ul li.disabled" + ); + assert.ok( + listDisabled.length === 7, + "disabled items displayed correctly in action dropdown" + ); + assert.ok( + listEnabled.length === 4, + "Enabled items displayed correctly in action dropdown" + ); + await actionTypeDropdown.selectRowByValue("create_topic"); + assert.ok( + query(".wizard-custom-action .message-content").innerText.includes( + "You're editing an action" + ), + "Create type action correctly selected" + ); + let listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 10, + "Display all settings of create topic" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("open_composer"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 8, + "Display all settings of open composer" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("update_profile"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 4, + "Display all settings of update profile" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("route_to"); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 4, + "Display all settings of route to" + ); + await actionTypeDropdown.expand(); + await click('[data-name="Select a type"]'); + listTopicSettings = findAll( + ".admin-wizard-container .wizard-custom-action .setting" + ); + assert.ok( + listTopicSettings.length === 2, + "the settings options is empty when no action is selected" + ); + await actionTypeDropdown.expand(); + await actionTypeDropdown.selectRowByValue("create_topic"); + const fieldsContentIf = [4, 8]; + for (let i = 0; i < fieldsContentIf.length; i++) { + await click( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldsContentIf[i]}) button` + ); + let selectKitInsideThirdSetting = await selectKit( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldsContentIf[i]}) .select-kit` + ); + await selectKitInsideThirdSetting.expand(); + await selectKitInsideThirdSetting.selectRowByIndex(1); + await fillIn( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldsContentIf[i]}) .key input`, + "Action title" + ); + await fillIn( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldsContentIf[i]}) .value input`, + "Some value" + ); + await fillIn( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldsContentIf[i]}) .output input`, + "Result text" + ); + const actualTitle = query( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldsContentIf[i]}) .key input` + ).value; + const actualValue = query( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldsContentIf[i]}) .value input` + ).value; + const actualResultText = query( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldsContentIf[i]}) .output input` + ).value; + + assert.strictEqual(actualTitle, "Action title", "Title is correct"); + assert.strictEqual(actualValue, "Some value", "Value is correct"); + assert.strictEqual(actualResultText, "Result text", "Text is correct"); + } + const fieldsContentSet = [ + [6, "howto", "10"], + [7, "gazelle", "gazelle"], + ]; + for (let [ + fieldIndex, + expectedDataName, + expectedDataValue, + ] of fieldsContentSet) { + await click( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldIndex}) button` + ); + let selectKitInsideThirdSetting = await selectKit( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldIndex}) .output .select-kit` + ); + await selectKitInsideThirdSetting.expand(); + await selectKitInsideThirdSetting.selectRowByIndex(1); + let selectKitElement = document.querySelector( + `.admin-wizard-container .wizard-custom-action .setting:nth-of-type(${fieldIndex}) .output .select-kit` + ); + let summaryElement = selectKitElement.querySelector("summary"); + assert.equal( + summaryElement.getAttribute("data-name"), + expectedDataName, + "The correct data-name is selected" + ); + assert.equal( + summaryElement.getAttribute("data-value"), + expectedDataValue, + "The correct data-value is selected" + ); + } + assert.ok( + !visible('.admin-wizard-buttons button:contains("Delete Wizard")'), + "delete wizard button not displayed" + ); + await click(".admin-wizard-buttons button"); + assert.equal( + currentURL(), + "/admin/wizards/wizard/new_wizard_for_testing", + "Wizard saved successfully" + ); + assert.ok( + visible('.admin-wizard-buttons button:contains("Delete Wizard")'), + "delete wizard button visible" + ); + }); + test("viewing content for a selected wizard", async (assert) => { + await visit("/admin/wizards/wizard"); + assert.ok( + query(".message-content").innerText.includes( + "Select a wizard, or create a new one" + ), + "it displays wizard message" + ); + const wizards = selectKit(".select-kit"); + await wizards.expand(); + + await wizards.selectRowByValue("unique_wizard"); + assert.ok( + query(".message-content").innerText.includes("You're editing a wizard"), + "it displays wizard message for a selected wizard" + ); + assert.equal( + query(".admin-wizard-container .wizard-header input").value, + getUniqueWizard.name, + "The wizard name is correctly displayed" + ); + // Save wizard Submissions + assert.equal( + query(".wizard-settings .setting:nth-of-type(1) input").checked, + getUniqueWizard.save_submissions, + "The save submissions flag is correctly set" + ); + + // Multiple Submissions + assert.equal( + query(".wizard-settings .setting:nth-of-type(2) input").checked, + getUniqueWizard.multiple_submissions, + "The multiple submissions flag is correctly set" + ); + + // After Signup + assert.equal( + query(".wizard-settings .setting:nth-of-type(3) input").checked, + getUniqueWizard.after_signup, + "The after signup flag is correctly set" + ); + + // Prompt Completion + assert.equal( + query(".wizard-settings .setting:nth-of-type(4) input").checked, + getUniqueWizard.prompt_completion, + "The prompt completion flag is correctly set" + ); + // step content + for (let i = 0; i < getUniqueWizard.steps.length; i++) { + // click on the step that is needed + await click( + `.wizard-links.step .link-list div:nth-of-type(${ + i + 1 + }) button.btn-text` + ); + assert.equal( + query(".wizard-custom-step input[name='title']").value, + getUniqueWizard.steps[i].title, + "Step title is correct" + ); + assert.equal( + query(".wizard-custom-step .wizard-text-editor textarea").value, + getUniqueWizard.steps[i].description, + "Step description is correct" + ); + // field content + for (let j = 0; j < getUniqueWizard.steps[i].fields.length; j++) { + await click( + `.wizard-links.field .link-list div:nth-of-type(${ + j + 1 + }) button.btn-text` + ); + assert.equal( + query(".wizard-custom-field.visible .setting:nth-of-type(1) input") + .value, + getUniqueWizard.steps[i].fields[j].label, + "Field title is correct" + ); + assert.equal( + query(".wizard-custom-field.visible .setting:nth-of-type(3) textarea") + .value, + getUniqueWizard.steps[i].fields[j].description, + "Field description is correct" + ); + let selectTypeElement = document.querySelector( + `.admin-wizard-container .wizard-custom-field.visible .setting:nth-of-type(5) .select-kit` + ); + let summaryElement = selectTypeElement.querySelector("summary"); + assert.equal( + summaryElement.getAttribute("data-value"), + getUniqueWizard.steps[i].fields[j].type, + "The correct data-value is selected" + ); + } + } + }); +}); diff --git a/test/javascripts/helpers/admin-wizard.js b/test/javascripts/helpers/admin-wizard.js new file mode 100644 index 00000000..6c5dd84c --- /dev/null +++ b/test/javascripts/helpers/admin-wizard.js @@ -0,0 +1,934 @@ +const getWizard = { + wizard_list: [ + { id: "this_is_testing_wizard", name: "This is testing wizard" }, + { id: "another_wizard", name: "another wizard" }, + { id: "unique_wizard", name: "Unique wizard for testing" }, + ], + field_types: { + text: { + min_length: null, + max_length: null, + prefill: null, + char_counter: null, + validations: null, + placeholder: null, + }, + textarea: { + min_length: null, + max_length: null, + prefill: null, + char_counter: null, + placeholder: null, + }, + composer: { + min_length: null, + max_length: null, + char_counter: null, + placeholder: null, + }, + text_only: {}, + composer_preview: { preview_template: null }, + date: { format: "YYYY-MM-DD" }, + time: { format: "HH:mm" }, + date_time: { format: "" }, + number: {}, + checkbox: {}, + url: { min_length: null }, + upload: { file_types: ".jpg,.jpeg,.png" }, + dropdown: { prefill: null, content: null }, + tag: { limit: null, prefill: null, content: null, tag_groups: null }, + category: { limit: 1, property: "id", prefill: null, content: null }, + group: { prefill: null, content: null }, + user_selector: {}, + }, + realtime_validations: { + similar_topics: { + types: ["text"], + component: "similar-topics-validator", + backend: true, + required_params: [], + }, + }, + custom_fields: [ + { + id: "external", + klass: "category", + name: "require_topic_approval", + type: "boolean", + serializers: null, + }, + { + id: "external", + klass: "category", + name: "require_reply_approval", + type: "boolean", + serializers: null, + }, + { + id: "external", + klass: "category", + name: "num_auto_bump_daily", + type: "integer", + serializers: null, + }, + { + id: "external", + klass: "category", + name: "has_chat_enabled", + type: "boolean", + serializers: null, + }, + { + id: "external", + klass: "post", + name: "missing uploads", + type: "json", + serializers: null, + }, + { + id: "external", + klass: "post", + name: "missing uploads ignored", + type: "boolean", + serializers: null, + }, + { + id: "external", + klass: "post", + name: "notice", + type: "json", + serializers: null, + }, + { + id: "external", + klass: "post", + name: "local_dates", + type: "json", + serializers: null, + }, + { + id: "external", + klass: "post", + name: "has_polls", + type: "boolean", + serializers: null, + }, + ], +}; +const getUnsubscribedAdminWizards = { + subscribed: false, + subscription_type: "none", + subscription_attributes: { + wizard: { + required: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + permitted: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + restart_on_revisit: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + step: { + condition: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + required_data: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + permitted_params: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + field: { + condition: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + type: { + none: [ + "text", + "textarea", + "text_only", + "date", + "time", + "date_time", + "number", + "checkbox", + "dropdown", + "upload", + ], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + realtime_validations: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + action: { + type: { + none: ["create_topic", "update_profile", "open_composer", "route_to"], + standard: [ + "create_topic", + "update_profile", + "open_composer", + "route_to", + "send_message", + "watch_categories", + "add_to_group", + ], + business: ["*"], + community: ["*"], + }, + }, + custom_field: { + klass: { + none: ["topic", "post"], + standard: ["topic", "post"], + business: ["*"], + community: ["*"], + }, + type: { + none: ["string", "boolean", "integer"], + standard: ["string", "boolean", "integer"], + business: ["*"], + community: ["*"], + }, + }, + api: { + all: { none: [], standard: [], business: ["*"], community: ["*"] }, + }, + }, + subscription_client_installed: false, +}; +const getCustomFields = { + custom_fields: [ + { + id: "external", + klass: "category", + name: "require_topic_approval", + type: "boolean", + serializers: null, + }, + { + id: "external", + klass: "category", + name: "require_reply_approval", + type: "boolean", + serializers: null, + }, + { + id: "external", + klass: "category", + name: "num_auto_bump_daily", + type: "integer", + serializers: null, + }, + { + id: "external", + klass: "category", + name: "has_chat_enabled", + type: "boolean", + serializers: null, + }, + ], +}; +const getWizardTestingLog = { + wizard: { + id: "this_is_testing_wizard", + name: "This is testing wizard", + }, + logs: [ + { + date: "2022-12-13T05:32:38.906-04:00", + action: "create_topic", + username: "christin", + message: "success: created topic - id: 119", + user: { + id: 55, + username: "christin", + name: "Sybil Ratke", + avatar_template: "", + }, + }, + { + date: "2022-12-12T09:41:57.888-04:00", + action: "create_topic", + username: "someuser", + message: + "error: invalid topic params - title: ; post: creating a text for this text area that is being displayed here.", + user: { + id: 1, + username: "someuser", + name: null, + avatar_template: "", + }, + }, + ], + total: 2, +}; +const getWizardSubmissions = { + wizard: { + id: "this_is_testing_wizard", + name: "This is testing wizard", + }, + submissions: [ + { + id: "1", + fields: { + step_1_field_1: { + value: + "creating a text for this text area that is being displayed here.", + type: "textarea", + label: "label field", + }, + }, + submitted_at: "2022-12-12T09:41:57-04:00", + user: { + id: 1, + username: "someuser", + name: null, + avatar_template: "", + }, + }, + ], + total: 1, +}; +const getAnotherWizardSubmission = { + wizard: { id: "another_wizard", name: "another wizard" }, + submissions: [ + { + id: "00925bcd58366d07fb698dc5", + fields: { + step_1_field_1: { + value: "More content here by user", + type: "text", + label: "Content to be inserted", + }, + step_2_field_1: { + value: "body of the content created by the user", + type: "textarea", + label: "Step 2 content", + }, + }, + submitted_at: "2023-05-10T20:58:11-04:00", + user: { + id: 29, + username: "anotheruser", + name: null, + avatar_template: "", + }, + }, + { + id: "dc094efcd4873d6da4666c1a", + fields: { + step_1_field_1: { + value: "Title for the content being created", + type: "text", + label: "Content to be inserted", + }, + step_2_field_1: { + value: "THis is the body of the content that will be created", + type: "textarea", + label: "Step 2 content", + }, + }, + submitted_at: "2023-05-10T20:56:14-04:00", + user: { + id: 1, + username: "someuser", + name: null, + avatar_template: "", + }, + }, + ], + total: 2, +}; +const getBusinessAdminWizard = { + subscribed: true, + subscription_type: "business", + subscription_attributes: { + wizard: { + required: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + permitted: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + restart_on_revisit: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + step: { + condition: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + required_data: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + permitted_params: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + field: { + condition: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + type: { + none: [ + "text", + "textarea", + "text_only", + "date", + "time", + "date_time", + "number", + "checkbox", + "dropdown", + "upload", + ], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + realtime_validations: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + action: { + type: { + none: ["create_topic", "update_profile", "open_composer", "route_to"], + standard: [ + "create_topic", + "update_profile", + "open_composer", + "route_to", + "send_message", + "watch_categories", + "add_to_group", + ], + business: ["*"], + community: ["*"], + }, + }, + custom_field: { + klass: { + none: ["topic", "post"], + standard: ["topic", "post"], + business: ["*"], + community: ["*"], + }, + type: { + none: ["string", "boolean", "integer"], + standard: ["string", "boolean", "integer"], + business: ["*"], + community: ["*"], + }, + }, + api: { + all: { none: [], standard: [], business: ["*"], community: ["*"] }, + }, + }, + subscription_client_installed: false, +}; +const getStandardAdminWizard = { + subscribed: true, + subscription_type: "standard", + subscription_attributes: { + wizard: { + required: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + permitted: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + restart_on_revisit: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + step: { + condition: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + required_data: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + permitted_params: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + field: { + condition: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + type: { + none: [ + "text", + "textarea", + "text_only", + "date", + "time", + "date_time", + "number", + "checkbox", + "dropdown", + "upload", + ], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + realtime_validations: { + none: [], + standard: ["*"], + business: ["*"], + community: ["*"], + }, + }, + action: { + type: { + none: ["create_topic", "update_profile", "open_composer", "route_to"], + standard: [ + "create_topic", + "update_profile", + "open_composer", + "route_to", + "send_message", + "watch_categories", + "add_to_group", + ], + business: ["*"], + community: ["*"], + }, + }, + custom_field: { + klass: { + none: ["topic", "post"], + standard: ["topic", "post"], + business: ["*"], + community: ["*"], + }, + type: { + none: ["string", "boolean", "integer"], + standard: ["string", "boolean", "integer"], + business: ["*"], + community: ["*"], + }, + }, + api: { + all: { none: [], standard: [], business: ["*"], community: ["*"] }, + }, + }, + subscription_client_installed: false, +}; +const getAdminTestingWizard = { + id: "this_is_testing_wizard", + name: "This is testing wizard", + save_submissions: true, + after_time: false, + after_time_scheduled: "2022-12-12T13:45:00.000Z", + prompt_completion: true, + steps: [ + { + id: "step_1", + title: "step 1", + raw_description: "This is a description for step 1 sads", + fields: [ + { + id: "step_1_field_1", + label: "label field", + description: "this is the label description", + type: "textarea", + placeholder: "insert a textarea text here.", + }, + ], + description: "This is a description for step 1 sads", + }, + ], + actions: [ + { + id: "action_1", + run_after: "wizard_completion", + type: "create_topic", + skip_redirect: false, + post: "step_1_field_1", + post_builder: false, + title: [ + { + type: "assignment", + output: "Testing title", + output_type: "text", + output_connector: "set", + pairs: [], + }, + ], + category: [ + { + type: "assignment", + output_type: "category", + output_connector: "set", + output: [30], + }, + ], + }, + ], +}; +const getCreatedWizard = { + id: "new_wizard_for_testing", + name: "New wizard for testing", + save_submissions: true, + multiple_submissions: false, + after_signup: false, + prompt_completion: false, + steps: [ + { + id: "step_1", + title: "step title", + raw_description: + 'Input in step description composer\n\n**Bold text**\n\n*emphasized text*\n\n\u003e Blockqoute text\n\n```\n code text\n \n```\n\n* List item\n* List item\n\n1. List item\n1. List item\n\n[Google](https://google.com)[date=2023-05-25 timezone="America/La_Paz"]', + fields: [ + { + id: "step_1_field_1", + label: "field title", + description: "First step field description", + type: "text", + min_length: "1", + placeholder: "Insert text here", + validations: { similar_topics: {} }, + }, + ], + description: + 'Input in step description composer\n\n**Bold text**\n\n*emphasized text*\n\n\u003e Blockqoute text\n\n```\n code text\n \n```\n\n* List item\n* List item\n\n1. List item\n1. List item\n\n[Google](https://google.com)[date=2023-05-25 timezone="America/La_Paz"]', + }, + ], + actions: [ + { + id: "action_1", + run_after: "wizard_completion", + type: "create_topic", + post_builder: false, + post_template: "Wizard Fields w{step_1_field_1}", + title: [ + { + type: "conditional", + output: "Result text", + output_type: "text", + output_connector: "then", + pairs: [ + { + index: 0, + key: "Action title", + key_type: "text", + value: "Some value", + value_type: "text", + connector: "equal", + }, + ], + }, + ], + category: [ + { + type: "assignment", + output_type: "category", + output_connector: "set", + output: [10], + }, + ], + tags: [ + { + type: "assignment", + output_type: "tag", + output_connector: "set", + pairs: [], + output: ["gazelle"], + }, + ], + visible: [ + { + type: "conditional", + output: "Result text", + output_type: "text", + output_connector: "then", + pairs: [ + { + index: 0, + key: "Action title", + key_type: "text", + value: "Some value", + value_type: "text", + connector: "equal", + }, + ], + }, + ], + }, + ], +}; +const getUniqueWizard = { + id: "unique_wizard", + name: "Unique wizard for testing", + save_submissions: true, + multiple_submissions: false, + after_signup: false, + prompt_completion: false, + steps: [ + { + id: "step_1", + title: "step title", + raw_description: + 'Input in step description composer\n\n**Bold text**\n\n*emphasized text*\n\n\u003e Blockqoute text\n\n```\n code text\n \n```\n\n* List item\n* List item\n\n1. List item\n1. List item\n\n[Google](https://google.com)[date=2023-05-25 timezone="America/La_Paz"]', + fields: [ + { + id: "step_1_field_1", + label: "field title", + description: "First step field description", + type: "text", + min_length: "1", + placeholder: "Insert text here", + validations: { similar_topics: {} }, + }, + ], + description: + 'Input in step description composer\n\n**Bold text**\n\n*emphasized text*\n\n\u003e Blockqoute text\n\n```\n code text\n \n```\n\n* List item\n* List item\n\n1. List item\n1. List item\n\n[Google](https://google.com)[date=2023-05-25 timezone="America/La_Paz"]', + }, + { + id: "step_2", + title: "step title two", + raw_description: "Input in step description composer", + fields: [ + { + id: "step_2_field_1", + label: "step 2 field title", + description: "First step field description", + type: "textarea", + min_length: "1", + placeholder: "Insert text here", + validations: { similar_topics: {} }, + }, + { + id: "step_2_field_2", + label: "step 2 field two title", + description: "Second Step field two field description", + type: "text", + min_length: "1", + placeholder: "Insert more text here", + validations: { similar_topics: {} }, + }, + ], + description: "Input in step description composer", + }, + ], + actions: [ + { + id: "action_1", + run_after: "wizard_completion", + type: "create_topic", + post_builder: false, + post_template: "Wizard Fields w{step_1_field_1}", + title: [ + { + type: "conditional", + output: "Result text", + output_type: "text", + output_connector: "then", + pairs: [ + { + index: 0, + key: "Action title", + key_type: "text", + value: "Some value", + value_type: "text", + connector: "equal", + }, + ], + }, + ], + category: [ + { + type: "assignment", + output_type: "category", + output_connector: "set", + output: [10], + }, + ], + tags: [ + { + type: "assignment", + output_type: "tag", + output_connector: "set", + pairs: [], + output: ["gazelle"], + }, + ], + visible: [ + { + type: "conditional", + output: "Result text", + output_type: "text", + output_connector: "then", + pairs: [ + { + index: 0, + key: "Action title", + key_type: "text", + value: "Some value", + value_type: "text", + connector: "equal", + }, + ], + }, + ], + }, + ], +}; + +const getNewApi = { + name: "new_api", + title: "new API", + authorization: { + auth_type: "basic", + auth_url: null, + token_url: null, + client_id: null, + client_secret: null, + authorized: null, + auth_params: [], + access_token: null, + refresh_token: null, + token_expires_at: null, + token_refresh_at: null, + code: null, + username: "some_username", + password: "some_password", + }, + endpoints: [ + { + id: "8371de", + name: "endpoint_name", + method: "POST", + url: "https://test.api.com", + content_type: "application/json", + success_codes: [200, 100], + }, + ], + log: [], +}; +const putNewApi = { + success: "OK", + api: { + name: "new_api", + title: "new API", + authorization: { + auth_type: "basic", + auth_url: null, + token_url: null, + client_id: null, + client_secret: null, + authorized: null, + auth_params: [], + access_token: null, + refresh_token: null, + token_expires_at: null, + token_refresh_at: null, + code: null, + username: "some_username", + password: "some_password", + }, + endpoints: [ + { + id: "8371de", + name: "endpoint_name", + method: "POST", + url: "https://test.api.com", + content_type: "application/json", + success_codes: [200, 100], + }, + ], + log: [], + }, +}; +export { + getWizard, + getUnsubscribedAdminWizards, + getCustomFields, + getWizardTestingLog, + getWizardSubmissions, + getBusinessAdminWizard, + getStandardAdminWizard, + getAdminTestingWizard, + getCreatedWizard, + getNewApi, + putNewApi, + getAnotherWizardSubmission, + getUniqueWizard, +};