внутренняя зависимость пользовательского репортера загружается как другой экземпляр модуля

Я подумал, что опубликую это, так как некоторое время спотыкался, прежде чем заметил, что происходит. У меня есть набор тестов, который использует CouchDB в качестве базы данных ведения журнала/записи. Я обнаружил, что вы можете писать собственные отчеты в стажере, поэтому подумал, что могу переместить много моих ручных вызовов 'recordSuccess()'/'recordFailure()' из моего тестового скрипта в собственный отчет, отвечающий на события теста. .

Мой основной тестовый сценарий по-прежнему требует небольшого взаимодействия с Couchdb, поэтому я выделил соединение Couchdb и функции отчетности в модуль, а затем попытался использовать этот модуль как из основного тестового сценария, так и из пользовательского модуля Reporter.

Я обнаружил, что вспомогательный модуль CouchDB создается дважды. Это противоречит ожиданию того, что AMD/RequireJS require() будет выполнять модуль только один раз и кэшировать результат для использования в следующий раз, когда модуль потребуется. Если я помещу оператор «отладчик» в его основной код, он явно будет выполнен дважды. Результат для меня заключается в том, что ссылка Couchdb не определена при вызове из репортера.

Структура каталога:

runTest.js               # helper script to run intern test from this dir
src/MainTest.js
src/CouchHelper.js
src/CouchDBReporter.js
src/intern.js            # intern config

runTest.js

node node_modules/.bin/intern-client config=src/intern suites=mypackage/WINTest --envConfig=src/test/dev.json 

то есть MainTest.js:

define([ 'CouchHelper' ], function (CouchHelper) {
  .. test startup ..
  CouchHelper.connect(username, password, etc);

CouchDBReporter.js:

define([ 'CouchHelper' ], function (CouchHelper) {
  return {
    '/test/fail': function (test) {
      // Presume the couchdb is connected at this point
      CouchHelper.recordFailure(test);
    }
  }

интерн.js:

... blah blah ..
loader: {
    // Packages that should be registered with the loader in each testing environment
    packages: [
        'node',
        'nedb',
        'nodemailer',
        { 'mypackage', 'src' }
    ],
    reporters: [ 'console', 'src/CouchDBReporter' ]

CouchHelper.js:

define([
    'intern/dojo/node!node-couchdb'
], function (Couchdb) {

    debugger; // this is hit twice
    var instance = 0;

    function CouchHelper() {
        this.couchdb = undefined;
        this.instance = instance++;
        console.log('Created instance ' + this.instance);
    }

    CouchHelper.prototype = {
        connect: function () { this.couchdb = Couchdb.connect(blah); },
        recordFailure: function (test) { this.couchdb.insert(blah); }
    }
}

При запуске консоль пишет:

Created instance 0
Created instance 0

Когда репортер вызывает recordFailure, он вызывает другой экземпляр CouchHelper, а не файл MainTest.js с именем connect() в .., поэтому this.couchdb не определен, и сценарий аварийно завершает работу. Я могу нормально вызывать recordSuccess/recordFailure из MainTest.js, и this.couchdb допустим в CouchHelper, но экземпляр CouchHelper явно отличается от CouchDBReporter.

Ожидается ли такое поведение, и если да, то каков рекомендуемый способ обмена данными и ресурсами между основным тестовым кодом и кодом в пользовательском генераторе отчетов? Я вижу, что в 3.0 конфигурация репортеров может принимать объект, который может помочь смягчить эту проблему, но кажется, что нужно создавать экземпляр репортера программно, а не определять его в конфигурации.

Ник


person Neek    schedule 04.03.2015    source источник
comment
Я знаю, что мой код выше выглядит немного ненадежным, например. CouchHelper.js, похоже, не возвращает значение ... реальный код был правильным, я на самом деле пробовал как «экспорт», возвращая объект, так и используя одноэлементную фабрику, в различных попытках, когда я сузил то, что происходит.   -  person Neek    schedule 04.03.2015
comment
Где ваша конфигурация карты загрузчика? Как у вас дела с интерном? Этот модуль действительно не в упаковке?   -  person C Snover    schedule 04.03.2015
comment
Глядя на свой конфиг загрузчика, я заметил, что, вероятно, ошибка. Я сопоставил свой каталог src с именем «mypackage» и указал репортер клиента как «src/CouchDBReporter», но запустил пакет «mypackage/MainTest». И CouchDBReporter, и MainTest фактически находятся в одном физическом каталоге, но я угадайте, когда MainTest требовал ./CouchHelper, он загружал mypackage/CouchHelper, а когда CouchDBReporter требовал ./CouchHelper, он загружал src/CouchHelper. Таким образом, один и тот же физический модуль AMD загружался дважды под разными именами.   -  person Neek    schedule 05.03.2015
comment
Если это так, вы должны добавить его в качестве ответа и принять свой собственный ответ. :)   -  person C Snover    schedule 05.03.2015


Ответы (1)


Как предположил Колин, путь к ответу лежал в моей конфигурации карты загрузчика. Это означает, что мой файл intern.js, обозначенный в командной строке как config, имеет раздел loader, в котором можно определить сопоставления путей к модулю AMD (см. https://theintern.github.io/intern/#option-loader). Обычно я просто определяю список имен пакетов, например, я знаю, что для моего теста требуются nedb, nodemailer и мой собственный пакет src:

loader: {
    packages: [ 'node', 'nedb', 'nodemailer', 'src' ]
}

По какой-то причине я определил свой пакет src как доступный под именем mypackage:

loader: {
    packages: [ 'node', 'nedb', 'nodemailer',
        { name: 'mypackage', location: 'src' }
    ]
}

У меня не было веских причин делать это. Затем я указал, что мой пользовательский репортер должен быть загружен стажером, используя имя пакета «src»:

интерн.js:

reporters: [ 'console', 'src/CouchDBReporter' ]

И вот хитрый момент: я ссылался на свой вспомогательный модуль CouchHelper двумя разными способами, но оба раза используя относительный путь к модулю ./CouchHelper:

MainTest.js:

require([
    './CouchHelper',
    ...
], ...

CouchDBReporter.js:

require([
    './CouchHelper',
    ...
], ...

А в командной строке, как вы уже догадались, указал тест для запуска как mypackage/MainTest.js. Это противоречит моей спецификации src/CouchDBReporter в разделе reporter intern.js.

В результате mypackage/MainTest.js требовалось ./CouchHelper, которое разрешалось как mypackage/CouchHelper, а src/CouchDBReporter требовалось ./CouchHelper, которое разрешалось как src/CouchHelper. Это загрузило код модуля CouchHelper дважды, обходя обычную гарантию загрузчика в стиле AMD, что модуль загружается только один раз.

Это, безусловно, был хороший урок по путям модулей AMD и одно из следствий использования относительных путей.

person Neek    schedule 09.03.2015