Importing a model or component from a plugin into a custom plugin: tests fail

Bonjour,
Nous utilisons Discourse version 3.5.0.
Nous avons notre propre plugin dans lequel nous surchargeons divers éléments de discourse et ajoutons nos propres fonctionnalités.

Dans ce plugin, nous souhaitons notamment ajouter l’icône d’ajout d’un événement dans la barre des outils du composer. Pour ce faire, nous avons besoin d’importer :

  • le modèle DiscoursePostEventEvent qui se situe dans plugins/discourse-calendar/assets/javascripts/discourse/models/discourse-post-event-event.js

  • le composant PostEventBuilder qui se situe dans plugins/discourse-calendar/assets/javascripts/discourse/components/modal/post-event-builder.js

Par ailleurs, nous avons écrit des tests d’intégration pour nos fonctionnalités que nous avons mis dans notre plugin sous le répertoire /test.

import { visit } from "@ember/test-helpers";
import { test } from "qunit";
import { acceptance } from "discourse/tests/helpers/qunit-helpers";

acceptance("TOTO", function (needs) {
  test("coopaname integration - composer", async function (assert) {
    await visit("/");
    assert
      .equal(1, 1, "OK")
  });

});

Nous arrivons à faire ce que nous voulons, mais les tests échouent quelque soit le mode d’import.

Import en tête de fichier

Lorsque nous importons nos modèle et composant via la méthode import en entête de fichier:

import DiscoursePostEventEvent from "discourse/plugins/discourse-calendar/discourse/models/discourse-post-event-event";
import PostEventBuilder from "discourse/plugins/discourse-calendar/discourse/components/modal/post-event-builder";

Tout va bien à l’exécution, mais lorsque nous lançons notre test, il n’est pas exécuté

Require en tête de fichier

Lorsque nous importons nos modèle et composant via la méthode require en entête de fichier:

const DiscoursePostEventEvent = require("discourse/plugins/discourse-calendar/discourse/models/discourse-post-event-event").default;
const PostEventBuilder = require("discourse/plugins/discourse-calendar/discourse/components/modal/post-event-builder".default;

Tout va bien à l’exécution, mais lorsque nous lançons notre test, il n’est pas exécuté

Cela produit la même chose qu’avec import.

Require dans le corps du fichier

Lorsque nous importons nos modèle et composant via la méthode require dans le corps de la fonction :

import { withPluginApi } from "discourse/lib/plugin-api";

function initializeEventBuilder(api) {
  const DiscoursePostEventEvent =
     require("discourse/plugins/discourse-calendar/discourse/models/discourse-post-event-event").default;
  const PostEventBuilder =
     require("discourse/plugins/discourse-calendar/discourse/components/modal/post-event-builder").default;

  ... Suite du code
}

export default {
  name: "add-custom-create-event-button",
  initialize(container) {
    withPluginApi(initializeEventBuilder);
  },
};

Tout va bien à l’exécution, mais lorsque nous lançons notre test, il échoue.

Le modèle n’a pas été trouvé.

Bref, nous voudrions savoir comment importer des modèles, composants etc… correctement depuis d’autres plugins pour qu’on puisse exécuter les tests d’intégration.
Merci !

2 Likes

Hello @Marine

It seems the issue lies in the wrong settings being used in the needs.settings block of our code:

acceptance("Some tests", function (needs) {
  needs.settings({
    // This won't enable the right settings, so the calendar plugin won't be loaded, and the files we need won't be available
    // discourse_post_event_enabled: true, 
    // 
    // Enabling the calendar will solve the issue:
    calendar_enabled: true

    our_plugin_enabled: true
  });


  test("The test", async function (assert) {
    await visit("/");
    assert.equal(1, 1);
  });
});

Well, this is not true. As the plugin overrides the event form, we need to set discourse_post_event_enabled to true. Back to initial situation where the import in our plugin fails.

Any idea?

When you test a plugin in qunit, we only load the JS for that specific plugin. That helps to avoid surprise issues when multiple plugins interact with each other. It also helps to ensure that a plugin doesn’t unexpectedly become dependent on another.

In your case, it sounds like the interaction is deliberate, and you always expect your users to have discourse-calendar enabled. In that case, you can add some config to an about.json file which will make the discourse-calendar JS available in the tests of your own plugin. Here’s an example:

^^ in this case it’s adding discourse-assign. For your case, you would make it discourse-calendar

4 Likes

Thanks! I didn’t know about about.json and it solved the issue. Now, it’s up to us to re-create a fully functional context :wink:

Thanks again!

2 Likes

You may also be interested in system specs for end-to-end testing. That way, the test is run against a real Discourse server, so you don’t have to fake all of the network requests for core & both plugins.

The downside is that they’re much slower. So best to keep any unit/component tests in qunit if you can.

2 Likes

Thanks for the tip!

I’m really more comfortable with system specs as I usually use RSpec or Cucumber to test my Rails apps :slight_smile:

I’ll see what’s worth testing with QUnit or RSpec, depending on the test case.

For now, I managed to reproduce the frontend bug we wanted to fix, so I’ll dig a bit more in QUnit tests.

2 Likes