diff --git a/.github/workflows/plugin-tests.yml b/.github/workflows/plugin-tests.yml index 855bdfec..ef042fbc 100644 --- a/.github/workflows/plugin-tests.yml +++ b/.github/workflows/plugin-tests.yml @@ -31,7 +31,7 @@ jobs: build_type: ["backend", "frontend"] ruby: ["2.7"] postgres: ["12"] - redis: ["4.x"] + redis: ["6.x"] services: postgres: diff --git a/test/javascripts/acceptance/wizard-test.js.es6 b/test/javascripts/acceptance/wizard-test.js.es6 new file mode 100644 index 00000000..d7aa706a --- /dev/null +++ b/test/javascripts/acceptance/wizard-test.js.es6 @@ -0,0 +1,30 @@ +import { click, currentRouteName, fillIn, visit } from "@ember/test-helpers"; +import { module, test } from "qunit"; +import { run } from "@ember/runloop"; +import startApp from "../helpers/start-app"; +console.log("STARTING TEST"); +let wizard; +window.onerror = function (msg, url, lineNo, columnNo, error) { + console.log(error); + return false +} +module("Acceptance: Custom Wizard", { + beforeEach() { + console.log("BEFORE EACH") + wizard = startApp(); + }, + + afterEach() { + run(wizard, "destroy"); + }, +}); + +function exists(selector) { + return document.querySelector(selector) !== null; +} + +test("Wizard starts", async function (assert) { + console.log("TEST") + await visit("/w/wizard"); + assert.ok(exists(".wizard-column")); +}); diff --git a/test/javascripts/fixtures/wizard.js b/test/javascripts/fixtures/wizard.js new file mode 100644 index 00000000..0b3a219c --- /dev/null +++ b/test/javascripts/fixtures/wizard.js @@ -0,0 +1,340 @@ +export default { + "id": "super_mega_fun_wizard", + "name": "Super Mega Fun Wizard", + "background": "#333333", + "save_submissions": true, + "after_signup": false, + "prompt_completion": false, + "theme_id": 2, + "steps": [ + { + "id": "step_1", + "title": "Text", + "raw_description": "Text inputs!", + "fields": [ + { + "id": "step_1_field_1", + "label": "Text", + "description": "Text field description.", + "type": "text", + "min_length": "3", + "prefill": [ + { + "type": "assignment", + "output": "I am prefilled", + "output_type": "text", + "output_connector": "set" + } + ] + }, + { + "id": "step_1_field_2", + "label": "Textarea", + "type": "textarea", + "min_length": "" + }, + { + "id": "step_1_field_3", + "label": "Composer", + "type": "composer" + }, + { + "id": "step_1_field_4", + "label": "I'm only text", + "description": "", + "type": "text_only" + } + ], + "description": "Text inputs!" + }, + { + "id": "step_2", + "title": "Values", + "raw_description": "Because I couldn't think of another name for this step :)", + "fields": [ + { + "id": "step_2_field_1", + "label": "Date", + "type": "date", + "format": "YYYY-MM-DD" + }, + { + "id": "step_2_field_2", + "label": "Time", + "type": "time", + "format": "HH:mm" + }, + { + "id": "step_2_field_3", + "label": "Date & Time", + "type": "date_time", + "format": "" + }, + { + "id": "step_2_field_4", + "label": "Number", + "type": "number" + }, + { + "id": "step_2_field_5", + "label": "Checkbox", + "type": "checkbox" + }, + { + "id": "step_2_field_6", + "label": "Url", + "type": "url" + }, + { + "id": "step_2_field_7", + "label": "Upload", + "type": "upload", + "file_types": ".jpg,.jpeg,.png" + } + ], + "description": "Because I couldn't think of another name for this step :)" + }, + { + "id": "step_3", + "title": "Combo-boxes", + "raw_description": "Unfortunately not the edible type :sushi: ", + "fields": [ + { + "id": "step_3_field_1", + "label": "Custom Dropdown", + "type": "dropdown", + "content": [ + { + "type": "association", + "pairs": [ + { + "index": 0, + "key": "choice1", + "key_type": "text", + "value": "Choice 1", + "value_type": "text", + "connector": "equal" + }, + { + "index": 1, + "key": "choice2", + "key_type": "text", + "value": "Choice 2", + "value_type": "text", + "connector": "association" + }, + { + "index": 2, + "key": "choice3", + "key_type": "text", + "value": "Choice 3", + "value_type": "text", + "connector": "association" + } + ] + } + ] + }, + { + "id": "step_3_field_2", + "label": "Tag", + "type": "tag" + }, + { + "id": "step_3_field_3", + "label": "Category", + "type": "category", + "limit": 1, + "property": "id" + }, + { + "id": "step_3_field_4", + "label": "Group", + "type": "group" + }, + { + "id": "step_3_field_5", + "label": "User Selector", + "description": "", + "type": "user_selector" + }, + { + "id": "step_3_field_6", + "label": "Conditional User Selector", + "description": "Shown when checkbox in step_2_field_5 is true", + "type": "user_selector" + } + ], + "description": "Unfortunately not the edible type :sushi: " + } + ], + "actions": [ + { + "id": "action_1", + "run_after": "step_3", + "type": "create_topic", + "skip_redirect": true, + "post": "step_1_field_2", + "title": [ + { + "type": "assignment", + "output": "step_1_field_1", + "output_type": "wizard_field", + "output_connector": "set" + } + ], + "category": [ + { + "type": "assignment", + "output": "step_3_field_3", + "output_type": "wizard_field", + "output_connector": "set" + } + ], + "tags": [ + { + "type": "assignment", + "output": "step_3_field_2", + "output_type": "wizard_field", + "output_connector": "set" + } + ], + "custom_fields": [ + { + "type": "association", + "pairs": [ + { + "index": 0, + "key": "post_field", + "key_type": "text", + "value": "Post custom field value", + "value_type": "text", + "connector": "association" + }, + { + "index": 1, + "key": "topic.topic_field", + "key_type": "text", + "value": "Topic custom field value", + "value_type": "text", + "connector": "association" + }, + { + "index": 2, + "key": "topic.topic_json_field{}.key_1", + "key_type": "text", + "value": "Key 1 value", + "value_type": "text", + "connector": "association" + }, + { + "index": 3, + "key": "topic.topic_json_field{}.key_2", + "key_type": "text", + "value": "Key 2 value", + "value_type": "text", + "connector": "association" + } + ] + } + ], + "visible": [ + { + "type": "conditional", + "output": "true", + "output_type": "text", + "output_connector": "then", + "pairs": [ + { + "index": 0, + "key": "name", + "key_type": "user_field", + "value": "Angus", + "value_type": "text", + "connector": "equal" + } + ] + } + ] + }, + { + "id": "action_5", + "run_after": "step_1", + "type": "watch_categories", + "notification_level": "tracking", + "wizard_user": true, + "categories": [ + { + "type": "assignment", + "output": "action_8", + "output_type": "wizard_action", + "output_connector": "set" + } + ], + "mute_remainder": [ + { + "type": "assignment", + "output": "true", + "output_type": "text", + "output_connector": "set" + } + ] + }, + { + "id": "action_4", + "run_after": "step_2", + "type": "update_profile", + "profile_updates": [ + { + "type": "association", + "pairs": [ + { + "index": 0, + "key": "profile_background", + "key_type": "user_field", + "value": "step_2_field_7", + "value_type": "wizard_field", + "connector": "association" + } + ] + } + ] + }, + { + "id": "action_3", + "run_after": "step_2", + "type": "open_composer", + "post_builder": true, + "post_template": "I am interpolating some user fields u{name} u{username} u{email}", + "title": [ + { + "type": "assignment", + "output": "Title of the composer topic", + "output_type": "text", + "output_connector": "set" + } + ], + "tags": [ + { + "type": "assignment", + "output": "tag1", + "output_type": "text", + "output_connector": "set" + } + ] + }, + { + "id": "action_10", + "run_after": "step_3", + "type": "route_to", + "url": [ + { + "type": "assignment", + "output": "https://google.com", + "output_type": "text", + "output_connector": "set" + } + ] + } + ] +} diff --git a/test/javascripts/helpers/start-app.js b/test/javascripts/helpers/start-app.js new file mode 100644 index 00000000..6f5dbcc6 --- /dev/null +++ b/test/javascripts/helpers/start-app.js @@ -0,0 +1,23 @@ +import CustomWizard from "discourse/plugins/discourse-custom-wizard/wizard/custom-wizard"; +import wizardInitializer from "discourse/plugins/discourse-custom-wizard/wizard/initializers/custom-wizard"; +import stepInitializer from "discourse/plugins/discourse-custom-wizard/wizard/initializers/custom-wizard-step"; +import fieldInitializer from "discourse/plugins/discourse-custom-wizard/wizard/initializers/custom-wizard-field"; +import { run } from "@ember/runloop"; + +let app; +let started = false; + +export default function () { + run(() => (app = CustomWizard.create({ rootElement: "#ember-testing" }))); + + if (!started) { + wizardInitializer.initialize(app); + stepInitializer.initialize(app); + fieldInitializer.initialize(app); + app.start(); + started = true; + } + app.setupForTesting(); + app.injectTestHelpers(); + return app; +} diff --git a/test/javascripts/wizard/test_helper.js b/test/javascripts/plugin_helper.js similarity index 86% rename from test/javascripts/wizard/test_helper.js rename to test/javascripts/plugin_helper.js index 7d851f1b..9b1558cd 100644 --- a/test/javascripts/wizard/test_helper.js +++ b/test/javascripts/plugin_helper.js @@ -1,6 +1,6 @@ // discourse-skip-module /*global document, Logster, QUnit */ - +console.log('starting test_helper') window.Discourse = {}; window.Wizard = {}; Wizard.SiteSettings = {}; @@ -21,7 +21,7 @@ Discourse.SiteSettings = Wizard.SiteSettings; //= require jquery.debug //= require handlebars //= require ember-template-compiler -//= require wizard-application +//= require wizard-custom //= require wizard-vendor //= require_tree ./helpers //= require_tree ./acceptance @@ -29,7 +29,7 @@ Discourse.SiteSettings = Wizard.SiteSettings; //= require_tree ./components //= require ./wizard-pretender //= require test-shims - +console.log ("end of require") document.addEventListener("DOMContentLoaded", function () { document.body.insertAdjacentHTML( "afterbegin", @@ -47,12 +47,7 @@ if (window.Logster) { } Ember.Test.adapter = window.QUnitAdapter.create(); -let createPretendServer = requirejs( - "wizard/test/wizard-pretender", - null, - null, - false -).default; +/*let createPretendServer = requirejs("./wizard-pretender", null, null, false).default; let server; QUnit.testStart(function () { @@ -61,9 +56,9 @@ QUnit.testStart(function () { QUnit.testDone(function () { server.shutdown(); -}); +});*/ -let _testApp = requirejs("wizard/test/helpers/start-app").default(); +let _testApp = requirejs("./helpers/start-app").default(); let _buildResolver = requirejs("discourse-common/resolver").buildResolver; window.setResolver(_buildResolver("wizard").create({ namespace: _testApp })); @@ -72,3 +67,4 @@ Object.keys(requirejs.entries).forEach(function (entry) { requirejs(entry, null, null, true); } }); +console.log ("end of helper") diff --git a/test/javascripts/wizard/wizard-test.js b/test/javascripts/wizard/wizard-test.js deleted file mode 100644 index ea550cf2..00000000 --- a/test/javascripts/wizard/wizard-test.js +++ /dev/null @@ -1,78 +0,0 @@ -import { click, currentRouteName, fillIn, visit } from "@ember/test-helpers"; -import { module, test } from "qunit"; -import { run } from "@ember/runloop"; -import startApp from "wizard/test/helpers/start-app"; - -let wizard; -module("Acceptance: wizard", { - beforeEach() { - wizard = startApp(); - }, - - afterEach() { - run(wizard, "destroy"); - }, -}); - -function exists(selector) { - return document.querySelector(selector) !== null; -} - -test("Wizard starts", async function (assert) { - await visit("/"); - assert.ok(exists(".wizard-column-contents")); - assert.strictEqual(currentRouteName(), "step"); -}); - -test("Going back and forth in steps", async function (assert) { - await visit("/steps/hello-world"); - assert.ok(exists(".wizard-step")); - assert.ok( - exists(".wizard-step-hello-world"), - "it adds a class for the step id" - ); - assert.ok(!exists(".wizard-btn.finish"), "can’t finish on first step"); - assert.ok(exists(".wizard-progress")); - assert.ok(exists(".wizard-step-title")); - assert.ok(exists(".wizard-step-description")); - assert.ok( - !exists(".invalid .field-full-name"), - "don't show it as invalid until the user does something" - ); - assert.ok(exists(".wizard-field .field-description")); - assert.ok(!exists(".wizard-btn.back")); - assert.ok(!exists(".wizard-field .field-error-description")); - - // invalid data - await click(".wizard-btn.next"); - assert.ok(exists(".invalid .field-full-name")); - - // server validation fail - await fillIn("input.field-full-name", "Server Fail"); - await click(".wizard-btn.next"); - assert.ok(exists(".invalid .field-full-name")); - assert.ok(exists(".wizard-field .field-error-description")); - - // server validation ok - await fillIn("input.field-full-name", "Evil Trout"); - await click(".wizard-btn.next"); - assert.ok(!exists(".wizard-field .field-error-description")); - assert.ok(!exists(".wizard-step-description")); - assert.ok( - exists(".wizard-btn.finish"), - "shows finish on an intermediate step" - ); - - await click(".wizard-btn.next"); - assert.ok(exists(".select-kit.field-snack"), "went to the next step"); - assert.ok(exists(".preview-area"), "renders the component field"); - assert.ok(exists(".wizard-btn.done"), "last step shows a done button"); - assert.ok(exists(".action-link.back"), "shows the back button"); - assert.ok(!exists(".wizard-step-title")); - assert.ok(!exists(".wizard-btn.finish"), "can’t finish on last step"); - - await click(".action-link.back"); - assert.ok(exists(".wizard-step-title")); - assert.ok(exists(".wizard-btn.next")); - assert.ok(!exists(".wizard-prev")); -}); diff --git a/test/javascripts/wizard/wizard-pretender.js b/views/wizard-pretender.js similarity index 57% rename from test/javascripts/wizard/wizard-pretender.js rename to views/wizard-pretender.js index e9dccfb3..ac0ef1e8 100644 --- a/test/javascripts/wizard/wizard-pretender.js +++ b/views/wizard-pretender.js @@ -1,4 +1,5 @@ import Pretender from "pretender"; +import WizardJson from "./fixtures/wizard"; // TODO: This file has some copied and pasted functions from `create-pretender` - would be good // to centralize that code at some point. @@ -31,48 +32,8 @@ function response(code, obj) { export default function () { const server = new Pretender(function () { - this.get("/wizard.json", () => { - return response(200, { - wizard: { - start: "hello-world", - completed: true, - steps: [ - { - id: "hello-world", - title: "hello there", - index: 0, - description: "hello!", - fields: [ - { - id: "full_name", - type: "text", - required: true, - description: "Your name", - }, - ], - next: "second-step", - }, - { - id: "second-step", - title: "Second step", - index: 1, - fields: [{ id: "some-title", type: "text" }], - previous: "hello-world", - next: "last-step", - }, - { - id: "last-step", - index: 2, - fields: [ - { id: "snack", type: "dropdown", required: true }, - { id: "theme-preview", type: "component" }, - { id: "an-image", type: "image" }, - ], - previous: "second-step", - }, - ], - }, - }); + this.get("/w/wizard.json", () => { + return response(200, cloneJSON(WizardJson); }); this.put("/wizard/steps/:id", (request) => {