Acceptance Test for Markdown Extension?


I’m currently working on a Markdown Extension/plugin that adds quite a number of BBCode tags, and I am looking to write QUnit Acceptance tests for them (I got really tired of constantly checking them manually, and there’s a lot of them).

The tags in question are a mix between simple tags that just apply HTML and complex tags that have event handlers attached to them. As such, I need to test both the HTML of the cooked and the event handlers.

I’ve come across quite a few acceptance tests for markdown extensions (namely local-dates-composer-test.js.es6, spoiler-button-test.js-es6, checklist-test.js.es6, and pretty-text-test.js), which I have used as references. These can broadly be separated into two ways to perform the test:

  1. Simulate opening the site, creating a new topic, and filling in text inside the editor, while getting the output via a selector on the DOM. (local-dates-composer-test.js.es6, spoiler-button-test.js-es6)
  2. Create an instance of Pretty Text to cook the text on the spot and compare the HTML there. (checklist-test.js.es6, pretty-text-test.js) (checklist seems to also create an instance of the Post model to test event handling, and overall really seems to be testing the initializer).

I’ve tried both methods and have more or less succeeded. The first method is quite straight forward and I was able to get what I wanted at the cost of a longer time than the second. The second method I was able to successfully do with a much faster testing time, but I’m getting a weird error.

Here are my codes and results:

Method 1: Simulate opening the site
import { acceptance, queryAll } from "discourse/tests/helpers/qunit-helpers";

QUnit.assert.cooked = async function (input, expected, message) {
  await fillIn(".d-editor-input", input);
  const actual = queryAll(".d-editor-preview")[0].innerHTML;
    result: actual === expected.replace(/\/>/g, ">"),

acceptance("Method 1", function (needs) {
  test("cooking via site", async function (assert) {
    await visit("/");
    await click("#create-topic");

    assert.cooked("hello world", "<p>hello world</p>", "this test works");

Method 2: Create a Pretty Text Instance
import { acceptance} from "discourse/tests/helpers/qunit-helpers";
import { cookAsync } from "discourse/lib/text";

acceptance("Method 2", function (needs) {
  test("cooking using cookAsync", async function (assert) {
    const cooked = await cookAsync("hello world", {});
    assert.equal(cooked, "<p>hello world</p>", "this test also works");

Right now, I have them just testing a simple cook of the text “hello world”. I have tested this against my own custom tags, and they do work.

I think I’m missing something for method 2, as the error afterEach failed ....: this.keyTrapper is null. Regardless, both methods work, and I can see that for simple tests of the HTML, I should use method 2 and for tests that will involve event handling, I should use method 1.

Since a lot of my tags are just simple HTML, I want to use method 2 alongside method 1 during testing, to save time. I would like to know what I’m missing that’s creating that error, or if there’s an even better way to write these tests altogether.


You can see how its done in a similar official plugin


But that’s not using QUnit.

The reason is I believe the cooking is done in the back end btw.

It would be nice to simulate that on the front end.

Btw I’ve personally migrated the BBCode plugin to a Theme Component. But not published it exactly because you lose all the tests.