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,
+};