diff --git a/test/javascripts/wizard/test_helper.js b/test/javascripts/wizard/test_helper.js new file mode 100644 index 00000000..7d851f1b --- /dev/null +++ b/test/javascripts/wizard/test_helper.js @@ -0,0 +1,74 @@ +// discourse-skip-module +/*global document, Logster, QUnit */ + +window.Discourse = {}; +window.Wizard = {}; +Wizard.SiteSettings = {}; +Discourse.__widget_helpers = {}; +Discourse.SiteSettings = Wizard.SiteSettings; + +//= require env +//= require jquery.debug +//= require ember.debug +//= require locales/i18n +//= require locales/en +//= require route-recognizer +//= require fake_xml_http_request +//= require pretender +//= require qunit +//= require ember-qunit +//= require discourse-loader +//= require jquery.debug +//= require handlebars +//= require ember-template-compiler +//= require wizard-application +//= require wizard-vendor +//= require_tree ./helpers +//= require_tree ./acceptance +//= require_tree ./models +//= require_tree ./components +//= require ./wizard-pretender +//= require test-shims + +document.addEventListener("DOMContentLoaded", function () { + document.body.insertAdjacentHTML( + "afterbegin", + ` +
+ + ` + ); +}); + +if (window.Logster) { + Logster.enabled = false; +} else { + window.Logster = { enabled: false }; +} +Ember.Test.adapter = window.QUnitAdapter.create(); + +let createPretendServer = requirejs( + "wizard/test/wizard-pretender", + null, + null, + false +).default; + +let server; +QUnit.testStart(function () { + server = createPretendServer(); +}); + +QUnit.testDone(function () { + server.shutdown(); +}); + +let _testApp = requirejs("wizard/test/helpers/start-app").default(); +let _buildResolver = requirejs("discourse-common/resolver").buildResolver; +window.setResolver(_buildResolver("wizard").create({ namespace: _testApp })); + +Object.keys(requirejs.entries).forEach(function (entry) { + if (/\-test/.test(entry)) { + requirejs(entry, null, null, true); + } +}); diff --git a/test/javascripts/wizard/wizard-pretender.js b/test/javascripts/wizard/wizard-pretender.js new file mode 100644 index 00000000..e9dccfb3 --- /dev/null +++ b/test/javascripts/wizard/wizard-pretender.js @@ -0,0 +1,106 @@ +import Pretender from "pretender"; + +// TODO: This file has some copied and pasted functions from `create-pretender` - would be good +// to centralize that code at some point. + +function parsePostData(query) { + const result = {}; + query.split("&").forEach(function (part) { + const item = part.split("="); + const firstSeg = decodeURIComponent(item[0]); + const m = /^([^\[]+)\[([^\]]+)\]/.exec(firstSeg); + + const val = decodeURIComponent(item[1]).replace(/\+/g, " "); + if (m) { + result[m[1]] = result[m[1]] || {}; + result[m[1]][m[2]] = val; + } else { + result[firstSeg] = val; + } + }); + return result; +} + +function response(code, obj) { + if (typeof code === "object") { + obj = code; + code = 200; + } + return [code, { "Content-Type": "application/json" }, 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.put("/wizard/steps/:id", (request) => { + const body = parsePostData(request.requestBody); + + if (body.fields.full_name === "Server Fail") { + return response(422, { + errors: [{ field: "full_name", description: "Invalid name" }], + }); + } else { + return response(200, { success: true }); + } + }); + }); + + server.prepareBody = function (body) { + if (body && typeof body === "object") { + return JSON.stringify(body); + } + return body; + }; + + server.unhandledRequest = function (verb, path) { + const error = + "Unhandled request in test environment: " + path + " (" + verb + ")"; + window.console.error(error); + throw error; + }; + + return server; +} diff --git a/test/javascripts/wizard/wizard-test.js b/test/javascripts/wizard/wizard-test.js new file mode 100644 index 00000000..ea550cf2 --- /dev/null +++ b/test/javascripts/wizard/wizard-test.js @@ -0,0 +1,78 @@ +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")); +});