Mocha: this.timeout () не работает при использовании стрелочных функций ES6

Созданный на 21 дек. 2015  ·  59Комментарии  ·  Источник: mochajs/mocha

При использовании Node> = 4 с синтаксисом use strict и ES6 для стрелочных функций mocha не работает:

describe('foo', () => {
  this.timeout(100);
});

# => TypeError: this.timeout is not a function

Использование синтаксиса ES5 действительно работает:

describe('foo', function() {
  this.timeout(100);
});

Итак, какой уродливый трюк делает мокко с this ?

Самый полезный комментарий

Спасибо.

Почему так много «магии», которая, в конце концов, порождает проблемы? Почему не это ?:

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

Никаких глобалов, никакой проблемной магии ... только JavaScript.

Все 59 Комментарий

Он связывает функцию с тестовым контекстом, чего нельзя сделать при использовании стрелочных функций. С http://mochajs.org/

screen shot 2015-12-21 at 8 06 34 am

Прости за это!

Спасибо.

Почему так много «магии», которая, в конце концов, порождает проблемы? Почему не это ?:

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

Никаких глобалов, никакой проблемной магии ... только JavaScript.

То, что вы предлагаете, является серьезным критическим изменением и тем, что обсуждается в https://github.com/mochajs/mocha/issues/1969#issuecomment-160925915 Переписывание может ввести эти типы семантики :)

Приятно знать. Спасибо.

@ibc ну, это должно быть

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', (suite) => ... );  
});

но являются ли два разных аргумента набора одним и тем же типом? вероятно, нет, поэтому у вас есть разные имена переменных, чтобы отразить разные типы, например

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', (test) => ... );  
});

в любом случае оператор стрелки нельзя использовать в функциях, ожидающих контекстов.

Я не собираюсь ломать интерфейс BDD для # 1969 - во всяком случае, сразу же - хотя меня можно убедить. Я надеялся, что мы сохраним существующий API и представим отдельный пакет, содержащий пользовательский интерфейс BDD. Mocha будет поставляться с версией пользовательского интерфейса BDD, которая использует существующий API, но затем мы можем выпустить новую версию пакета пользовательского интерфейса BDD с использованием лямбда-выражений после этого - пользователи могут выбрать, следует ли явно обновлять этот пакет.

Возможно, альтернативный синтаксис ES6 для оболочки describe или suite может решить эту проблему:

describe({ feature: 'create stuff' , do () {
    it('abc', () => {
    }); 
}})

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

Есть новости по этому поводу? у меня есть это

mocha = require('mocha');

mocha.describe('test', (suite) => {

suite.timeout(500);

suite.it('test', (done)=>
          )
    }
)

И получение TypeError: невозможно прочитать свойство «тайм-аут» неопределенного

@mroien, это не ошибка Mocha. синтаксис стрелки не является заменой 1: 1 для function . пожалуйста, прочтите о его ограничениях

Из этого что-нибудь вышло? Предлагаемое решение мне нравится, хотя бы из-за моей любви к стрелочным функциям и отвращения к "этому", когда это не требуется.

Поскольку таймаут актуален только для done , почему бы просто не присоединить функцию тайм-аута к функции done.

it('makes sense', done => {
    done.timeout(100);
});

@nomilous это все еще не работает. У меня была похожая проблема. В моем случае работает вызов setTimeout внутри блока it . например

it('description', done => {
     const func = () => {
          // assertions
     };
     setTimeout(func, 10000);
});

@nomilous synchronous или случаи, возвращающие обещание, также могут иметь тайм-аут.

@ andela-engmkwalusimbi, это не должно работать. Как написал @boneskull :

@mroien, это не ошибка Mocha. синтаксис стрелки не является заменой функции 1: 1. пожалуйста, прочтите о его ограничениях

Для всех, кто все еще задается вопросом об этом, убедитесь, что вы понимаете, что подразумевает стрелочная функция, а затем вернитесь сюда и прочитайте (есть множество ресурсов, которые могут объяснить это намного лучше, чем я).

Единственный способ, которым эти стрелочные функции будут работать в этом случае, - это если мы изменим bdd API для передачи объекта context каждому обратному вызову Runnable (хуки, тесты) вместо использования this . Это неплохая идея, но это серьезное изменение, поэтому этого никогда не произойдет. Вместо этого:

it('should do something', function (done) {
  this.timeout(9000);
  // stuff
  done();
});

это выглядело бы так:

it('should do something', (context, done) => {
  context.timeout(9000);
  done();
});

Это нарушило бы каждый существующий асинхронный тест Mocha, независимо от того, был ли он обратно совместим в противном случае:

it('should do something', function (context, done) {
  // context is unused, but 'done' is now the second parameter
  this.timeout(9000);
  done();
});

Мы могли бы предоставить альтернативную реализацию bdd которая делает это, однако - это просто не будет по умолчанию.

Это самое подробное объяснение того, «где находится эта проблема». :улыбка:

Может быть, это будет учтено в следующей основной версии? Я не думаю, что это достаточно важное изменение для создания альтернативной реализации bdd. Названные аргументы также могут помочь в будущей разработке и, возможно, создать простой способ добавить какое-то промежуточное ПО для тестирования, например:

it('should do something', function ({ context, done }) { ...

Однако мы могли бы предоставить альтернативную реализацию bdd, которая делает это - это просто не будет по умолчанию.

@boneskull Новый интерфейс bdd-es6 было бы здорово :)

Хотя мне нравятся стрелочные функции, которые действительно полезны, например, для функций массива, таких как .filter(i => i.val) , в чем проблема с использованием обычных функций? Я думаю, что было бы полезно иметь описание, и это глобально, поэтому мне не нужно требовать их каждый раз. Кроме того, с каких это пор магия this только потому, что вы не понимаете (стрелочные) функции? Я определенно не хочу предоставлять переменную каждый раз, когда могу возвращать обещания, иначе я бы давно переключился на что-то вроде ava. Что касается простоты мокко, я думаю, что не должно быть больших изменений в обычных / стрелочных функциях, описанных в # 1969. И, пожалуйста, не говорите мне, что стрелочные функции набираются быстрее, поскольку ваш редактор может преобразовать один f в function () {\n\t\n} .

Я не понимаю, есть ли решение для тайм-аута вызова before() который использует стрелочные функции?

    before( async function () {
      data = await provider.getData();
      console.log(data);
      this.timeout(30*1000);
    });

Не имеет никакого эффекта. по-прежнему получается 4-секундный тайм-аут. Это единственная медленная вещь в моем наборе тестов. Я могу установить тайм-аут до 30 секунд в mocha.opts чтобы решить проблему, но мне действительно не нужно, чтобы все тесты тайм-аут после 30 секунд, только один вызов api, когда 4 секунды подходит для 99% из них.

Вот как я решил это за это время (обратите внимание, что первый describe() использует function вместо синтаксиса жирной стрелки:

describe('Search API', function () {
    this.timeout(30*1000);

    context('search', () => {
        let data;

        before( async () => {
          data = await provider.getSearch();
        });

        it('returns results', () => {
          expect(data).to.exist;
          expect(data.results).to.be.instanceOf(Array);
          expect(data.results.length).to.be.above(0);
        });
    })
});

@chovy Вы устанавливаете тайм-аут после того, как тайм-аут наступает в await provider.getData() .
Попробуйте использовать вместо этого:

before(async function () {
  this.timeout(30*1000); // set timeout first, then run the function
  data = await provider.getData();
  console.log(data);
});

Я не понимаю, есть ли решение для тайм-аута вызова before (), который использует стрелочные функции?

Чтобы прояснить это: в настоящее время нет возможности вызвать timeout Mocha с помощью стрелочных функций. Любое обсуждение альтернатив (каким бы похвальным оно ни было) - это обсуждение возможных новых (или, по крайней мере, модифицированных) интерфейсов.

То, что я думал какое-то время, могло сделать:

it('...', (done) => {
  ...
  done()
})

а также

it('...', (t) => {
  t.timeout(500)
  t.tag('integration', 'api')
  ...
  t.done()
})

используя тот же интерфейс по умолчанию.

Поддержка обоих в одном интерфейсе по умолчанию позволяет вам начать использовать стрелочные функции в существующей кодовой базе. Стоит отметить, что синтаксис (done) найти во многих онлайн-уроках, по-прежнему будет работать без флагов или чего-то еще.

Таким образом, в этой реализации вы получаете в качестве параметра традиционную функцию done , но с дополнительными функциями, добавленными как свойства этого объекта done function.

при использовании this.timeout() истекшее время исчезает в отчете.

@dasilvacontin понятия не имею, почему мы не думали об этом раньше. это отличная идея.

@dasilvacontin о, я помню. потому что вы должны это назвать. возможно, вы этого не захотите.

Извините, не могли бы вы уточнить «надо называть это», @boneskull? Вы говорите о проблемах, при которых Mocha будет думать, что тест асинхронный?

29 января 2017 года в 05:54 Кристофер Хиллер [email protected] написал:

@dasilvacontin о, я помню. потому что вы должны это назвать. возможно, вы этого не захотите.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите чат.

Кроме того, как вы заявляете о своем намерении провести асинхронный тест при использовании 't'?

На ленте вы всегда должны вызывать t.done (t.end в их API) или устанавливать ожидаемое количество утверждений (t.plan).

Можно ли добавить к нему третий аргумент () с параметрами? Это не сломает API.

it ('accepts lambda', (done)=>{ doWork();  done(); }, {timeout:60000});

@boneskull

Что, если вместо того, чтобы ставить контекст первым, это было необязательным вторым?

Вместо этого:

it('should do something', function (done) {
  this.timeout(9000);
  // stuff
  done();
});

это выглядело бы так:

it('should do something', (done, context) => {
  context.timeout(9000);
  done();
});
it('should do something', function (done, context) {
  // context is unused, but 'done' is now the second parameter
  this.timeout(9000);
  done();
});

Однако мы могли бы предоставить альтернативную реализацию bdd, которая делает это - это просто не будет по умолчанию.

Это самое подробное объяснение того, «где находится эта проблема». 😄

или если контекст должен быть определенным параметром

it('should do something', function (done, override) {
  // context is unused, but 'done' is now the second parameter
  override.timeout(9000);
  done();
});

Но я бы тоже взял нестандартный интерфейс :)

Обратной стороной любого решения, требующего done является то, что вам нужно использовать done даже если возврат обещания будет проще. Говоря за себя, я знаю, что лучше наберу function и return чем .then(()=>{done()}, done) !

@Flamenco Это интересная идея, хотя я мог бы предпочесть, чтобы функция

@ScottFreeCode Я определенно согласен с done Я тоже не люблю его использовать, я просто комментировал необходимость ставить контекст первым и последним и использовал вышеупомянутый пример, предоставленный bonekull.

Мне просто понравилась бы возможность передать контекст или установить какой-нибудь переключатель на мокко для выполнения es6.

А пока я просто завершаю те несколько описаний тестов, которые требуют различий в тайм-аутах при вызове функции (), выглядящей как дурацкая.

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

Добавив следующую функцию when определенную ниже, в тестовое объявление, например: it('does something', when(() => someFunctionReturningAPromise, customTimeout)) можно установить тайм-аут мокко, не отказываясь от стрелочных функций.

Точно так же, поскольку мы работаем только с обещаниями, мы можем повторно передать первый параметр в тест и передать контекст вместо выполненного обратного вызова: it('can access the mocha test context', when(testContext => someFunctionThatNeedsContext(testContext))

const when = (lambda, timeout) =>
  function() { // return a plain function for mocha to bind this to
    this.timeout(timeout || this.timeout() || 1000)
    return lambda(this)
  }

Некоторые тестовые примеры для иллюстрации:

const delay = timeout =>
  new Promise((resolve, reject) => setTimeout(resolve, timeout))

const deject = timeout => // similar to above, but a delayed reject
  new Promise((resolve, reject) => setTimeout(reject, timeout))

describe('mocha testing', () => {
  context('with only arrow functions', () => {
    context('tests that do not time out', () => {
      it('passes fast', when(() => delay(10), 100))
      it('does not usually time out', when(() => delay(2000), 2010))
    })
    context('tests that will time out', () => { // these should fail if the 'when' function works properly
      it('times out fast', when(() => delay(1000), 10)) // will fail in 10ms
      it('times out', when(() => delay(1000), 1000)) // will fail in about 1000ms
    })
    context('tests that will reject', () => { // this shows the when function works as expected when a test rejects
      it('fails fast', when(() => deject(10), 100))
    })
  })
})

@ astitt-ripple ага, или вы просто пишете function () {} ... Wtf?

Ладно, Лука, укус плохой. :-)

Разница со стрелочной функцией в том, что возврат можно пропустить. В
Настройка типа es6, это уже может быть обычным шаблоном для обещания 'then'
цепи.

С функциональным блоком, как вы предлагаете, и, насколько я знаю, возврат для
обещание должно быть явным. Минимум для тестовой функции на основе обещаний
{...} неверен, тест всегда должен возвращать свое обещание, поэтому минимальный
действительная тривиализация на самом деле: function {return ...}. В противном случае
test возвращает undefined в mocha, а не отправленное обещание ... и
у автора теста плохие времена.

Если большая часть кода в базе кода уже является стрелочными функциями из обещания. Тогда
и / или стиль функционального программирования, добавление функции return может выглядеть
непоследовательный. Предлагаемая форма «когда» доступна для тех, кто
предпочитаю стрелки и более функциональный стиль, чем традиционные функции
обратный вызов или стили возврата функции. Это более лаконично и соответствует
описать контекст это dsl мы все согласны, что нам нравится писать тесты, принимая во внимание
учетная запись обещания абстракции асинхронного программирования, которую обрабатывает javascript, поэтому
хорошо. Кроме того, это короче, чем функция + возврат, даже без нашего приятеля curly:
когда (() => ...).

Возможно, это не лучший стиль этого проекта, я это понимаю, и
Я не предлагаю это как изменение проекта. Может быть, это даже
предосудительно, как предполагает ваш wtf. Хорошо. Мокко должен работать с
pre-fp friendly js. Обратная совместимость - первоочередная задача. Что
тоже имеет смысл.

Это длинная и тупиковая нить, и это один из выходов. Один хороший
вещь о javascript, не обязательно должен быть один способ или один стиль для
добиться цели. Нам совсем не обязательно договариваться о стиле. Функционально
говоря, мой предыдущий пост дает людям возможность использовать стрелки и обещания
последовательно и с тестовой dsl, не отказываясь от доступа к мокко
контекст, чистый и удобный способ программирования, который не
было предложено ранее.

Спасибо.

Если большая часть кода в базе кода уже ... стиль функционального программирования ...

... тогда использование this.mutatingMethod(currentConfiguration) для настройки поведения, особенно функции (или, скорее, подпрограммы), которая уже выполняется, является более непоследовательным, чем необходимость писать return (что является просто синтаксисом) , и непоследовательная внешность сделает эту реальность более очевидной, а не внесет несогласованность.

(Не поймите меня неправильно, я вполне доволен ростом популярности идей функционального программирования на JS; но синтаксис function / return vs => : на самом деле это не важно для функционального программирования, просто вопрос того, что выглядит более понятным в этой парадигме, в то время как другие концепции, такие как чистота и декларативное против императивного, на самом деле важны. Было бы неплохо иметь средство выполнения тестов, которое вместо этого было бы более функциональным в его поведение / семантика , в этот момент переключение на стрелочные функции, вероятно, будет тривиальным ...)

Я согласен с вами, что this.timeout является мутационным и выходит за рамки парадигмы функционального программирования. Конечно, это совершенно непоследовательно. В настоящее время есть ли другой способ объявить настраиваемый тайм-аут для каждого теста, кроме this.timeout?

В текущей реализации мокко кажется необходимым вернуться к императивной / мутационной парадигме или отказаться от настройки на время ожидания теста. Один или другой.

В приведенной выше абстракции when тайм-аут является вторым параметром, позволяющим функциональному стилю оставаться на уровне теста. Он скрывает этот неизбежный выход из режима FP обратно к императивному программированию, но делает это в одном месте. Кроме того, он предоставляет стрелочным функциям доступ к контексту мокко, что невозможно без нарушения соглашения о параметрах тестовой функции. Таким образом, он потенциально решает несколько проблем для некоторых пользователей этого проекта (судя по истории этой проблемы) до тех пор, пока кто-то не исследует вашу идею тест-раннера.

И, пожалуйста, не поймите меня неправильно. Я не думаю, что функциональное программирование когда-либо или должно когда-либо полностью заменить императивное / мутационное программирование, производное от машины Тьюринга. Например, почти в каждом случае в среде выполнения JS код, функциональный или нет, в конечном итоге интерпретируется программой, написанной в этом более традиционном императивном стиле (возможно, C ++, но не обязательно), работающей в операционной системе, также написанной на основе мутационных и императивные идеи (вероятно, C). Память - это фиксированный ресурс, неизменяемые структуры данных - ложь, о которой нам говорит среда выполнения. Эта принципиально императивная модель используется в вычислениях по умолчанию и никуда не денется. Но это не значит, что функциональное программирование не может сосуществовать поверх него. И если это так, то неизбежно, что код FP время от времени должен опускаться до базовой модели. Я не думаю, что это должно означать, что мы опускаем руки и говорим весь синтаксис, и давайте просто использовать функцию / возврат.

На самом деле мы можем выполнять функциональное программирование на C, учитывая определенную терпимость к деталям, точно так же, как вы можете выполнять функциональное программирование с помощью функции / возврата вместо => функций. Только не забудьте вернуть свое обещание. FP в C требует немного большего набора текста, что, в конце концов, всего лишь синтаксис ... / s

В конце концов, стрелочные функции постепенно приближают нас к работоспособному и практичному способу работы в модели лямбда-исчисления на популярном языке. Удаление этих лишних символов имеет небольшое, но важное отличие. Есть еще много практических ограничений, но многие из них разрешимы, и рассматриваемая тема является одним из них.

В любом случае. Я буду использовать предложенную мной вспомогательную функцию, и другие теперь тоже могут ее использовать. Я с нетерпением жду вашего решения для запуска тестов, но пока я не знаю, будет ли оно особенно продуктивным, если продолжать попытки убедить друг друга в нашем собственном мнении о том, какой синтаксис важен или нет, как будто там это в одну сторону. Мне нравятся стрелки, а вам нравятся функции. Я не видел убедительного аргумента, который бы изменил мою точку зрения. Я открыт для одного, но он должен быть более продуманным, чем коленные рефлексы вроде: «просто используйте функцию, wtf» или «вы все еще можете делать fp с более подробным синтаксисом».

Решите проблему другим способом, и тогда никому не нужно будет использовать when . Достаточно. :-)

Я не думаю, что это должно означать, что мы опускаем руки и говорим весь синтаксис, и давайте просто использовать функцию / возврат.

Мне нравятся стрелки, а вам нравятся функции.

... это лучше было бы более продуманным, чем коленные рефлексы вроде: ... "вы все еще можете делать fp с более подробным синтаксисом".

Однако это в значительной степени противоположное тому, что я сказал - я стремился к тому, что стрелочные функции, которые все еще используют this , в первую очередь не будут FP, они будут объектно-ориентированными функциями со стрелками ( инверсия FP с традиционными функциями JS). Другими словами, это далеко не просто другой синтаксис, настоящая проблема в том, что существует более глубокая несовместимость парадигм, чем просто несовместимость синтаксиса (поскольку Mocha в любом случае разрабатывается в настоящее время).

Я почти уверен, что можно создать альтернативный интерфейс поверх Mocha, чтобы полностью заменить this параметрами. Я просто хочу прояснить, что если вы хотите использовать FP при написании тестов, вам нужно будет сделать больше, чем просто придумать способ передать Mocha this в стрелочные функции. Я очень много для подъема к такого рода вызов, однако. ; ^)

(Есть также несколько других вариантов поведения Mocha, которые связаны с состоянием, глобальным или, что еще хуже, и тем, и другим, но в данный момент у меня нет времени придумать краткий способ их перечисления. Если вы когда-нибудь видели проблемы, связанные с запуском Mocha более одного раза, однако это их пример.)

В настоящее время есть ли другой способ объявить настраиваемый тайм-аут для каждого теста, кроме this.timeout?

К сожалению, я почти уверен, что это не так; вне моей головы предложение принять дополнительный параметр для it который был бы картой значения ключа (как объект JS) настроек конфигурации, звучит как достойное будущее решение в Mocha, если кто-то захочет попробуйте реализовать это.

В настоящее время есть ли другой способ объявить настраиваемый тайм-аут для каждого теста, кроме this.timeout?

К сожалению, я почти уверен, что это не так;

Спасибо, что подтвердили эту деталь. Это подтверждает мою мысль.

Сверху моей головы предложение принять к нему дополнительный параметр, который был бы картой значения ключа (как объект JS) настроек конфигурации, звучит как достойное будущее решение в Mocha, если кто-то захочет попробовать его реализовать.

+1 для более общего решения.

Однако из того, что я могу сказать, кажется возможным передать один параметр. Объедините this с обратным вызовом done (так this становится функцией). Затем пусть мокко запускает каждый тест, завернутый в обещание (ну, на самом деле два, один для обработки тайм-аута и один для фактического запуска теста), независимо от количества параметров (отклонение от того, как это работает сегодня). Затем он мог проверить, является ли результат функции обещанием или нет. Если нет, вызовите done после того, как синхронная функция вернется, чтобы завершить тест. Если результатом функции является обещание, дождитесь его разрешения (или отклонения). Если истечет время ожидания, остановите тест (как и раньше). В случае, когда тесту удается вызвать done а также вернуть обещание. Либо done вызывается до разрешения, и в этом случае mocha должен дождаться обещания, а затем не пройти тест на наличие неоднозначной последовательности завершения. Или «готово» вызывается через некоторое время после разрешения, и в этом случае тест должен быть неудачно задним числом или проблема сигнализируется другим разумным способом. Извините, это много общих черт, но это мое постороннее понимание того, что пытается сделать мокко, и причуд, с которыми он сталкивается. Какие еще соображения могут помешать этому решению?

если вы хотите использовать FP при написании тестов, вам нужно будет сделать больше, чем просто придумать способ передать Mocha this в стрелочные функции

согласовано. есть определенные изменения в переходе к другой вычислительной модели, и, кроме того, javascript представляет собой сложную экосистему, которую следует учитывать. Однако в моем конкретном случае использования время от времени установка тайм-аута (например, для большей точности на основе некоторых вычислений вместо фиксированного значения по умолчанию) - это единственная ощутимая проблема, с которой я столкнулся при написании тестов FP с помощью Mocha (пока по меньшей мере). Что здорово. : +1:

Тем не менее, я хотел бы знать, что еще вы видите как надвигающиеся препятствия, которые конкретно связаны с Mocha (в отличие от того, что может означать написание тестов в FP в целом).

Это в значительной степени противоположное тому, что я сказал, хотя

Прошу прощения, если я неправильно охарактеризовал или неправильно понял. Судя по ответам, я не уверен, что многое из того, что я написал, поступил так, как задумано. И это прискорбно, поскольку я думаю, что если бы мы дошли до этого, мы, вероятно, пришли бы к довольно близкому соглашению о том, как ФП _ должна_ выглядеть _теории_. Однако здесь, похоже, мы не согласны с тем, как может выглядеть работоспособное сокращение до _practice_ в текущих выпусках Mocha сегодня, по крайней мере, для некоторых пользователей / сценариев использования. Так что я не совсем уверен, в чем основная проблема с предложенной мною дополнительной функцией с вашей стороны.

(Цитаты и ответы по порядку, но, возможно, более важные вещи будут позже, чем раньше.)


Однако из того, что я могу сказать, кажется возможным передать один параметр. Объедините это с обратным вызовом done (чтобы он стал функцией). Тогда ... Какие еще соображения могут помешать этому решению?

Если мы нарушим обратную совместимость, мы сможем переключиться на более простые конструкции.

Если мы сохраним обратную совместимость, оба этих теста должны пройти, а не время ожидания:

it("runs immediately", () => {
  // call functions and assert whatever
})
it("runs asynchronously", doneWithSomeOtherName => {
  setTimeout(() => {
    // call functions and assert whatever
    doneWithSomeOtherName()
  }, 100)
})

Вы можете попробовать придумать пример кода, чтобы доказать обратное (хотя я бы предложил вместо этого сосредоточиться на предложении в конце этого комментария), но я почти уверен, что ни один дизайн не сможет этого сделать и также сделайте этот тест пройденным, а не тайм-аутом:

it("looks just like an asynchronous test with a different name for `done`, but never tells Mocha it's done", context => {
  context.configureByMutation("some value")
  // call functions and assert whatever
})

Но также обратите внимание на мутацию. Подробнее об этом ниже.


Однако в моем конкретном случае использования время от времени установка тайм-аута (например, для большей точности на основе некоторых вычислений вместо фиксированного значения по умолчанию) - это единственная ощутимая проблема, с которой я столкнулся при написании тестов FP с помощью Mocha (пока по меньшей мере). Что здорово.

: +1 :!


Тем не менее, я хотел бы знать, что еще вы видите как надвигающиеся препятствия, которые конкретно связаны с Mocha (в отличие от того, что может означать написание тестов в FP в целом).

Я думаю, что, возможно, я не говорил об этом достаточно сконцентрированном ... так что позвольте мне посмотреть, смогу ли я свести это немного дальше. (Также извините, если что-то из этого показалось антагонистическим; это определенно не предназначено, хотя я признаю, что пытаюсь изменить здесь мышление.) Кодовая база Mocha во многом соответствует иерархиям классов и стилю геттеров и сеттеров. «объект ориентация» (и есть несколько вопросов или потенциальные проблемы Mocha имеет , что я считаю , дошедший до его изменчивого состояния), но это обычно не влияет на тестовый код , если все , что вы делаете , это написание тестов и позволяя запускать их мокко . Вы можете делать странные вещи с императивной изменяющейся конфигурацией Mocha:

it("imperatively sets the timeout multiple times", function(done) {
  this.timeout(5000)
  var context = this
  setTimeout(function() {
    context.timeout(1000)
    setTimeout(done, 500)
  }, 4000)
})

... но вам не обязательно. Как и в случае со многими элементами функционального программирования на нефункциональных языках: просто не злоупотребляйте императивными вещами.

(Также можно привести аргумент, что исключения являются нечистыми, но я еще не убежден, что это верно для исключений, которые генерируются на основе ввода, что можно было бы просто рассматривать как другую форму вывода. Так что некоторые скажут, что использование утверждений этот бросок не работает, но я не собираюсь сейчас заниматься этим.)

(Здесь важная часть :) То, что я пытаюсь понять, это то, что мы потенциально смотрим на то, чтобы либо усложнить и без того сложную кодовую базу, либо внести обратно несовместимое изменение. Нам нужно оправдание любой из этих вещей. Если оправдание - «сделать тесты более функциональными», это хорошо (по крайней мере, в моей книге). Дизайн, делающий тесты более функциональными, может стоить хлопот (в зависимости от того, сколько проблем). Но если под «сделать тесты более функциональными» вы имеете в виду «заставить стрелочные функции видоизменять вещи», то есть «сделать стрелочные функции менее функциональными», это сильно ослабит ситуацию (если это не просто внутреннее противоречие). Более полностью (! Как чистые , как стрелка функция делает вид) , я не думаю , что делает тесты выглядят более функциональными, сохраняя при этом один битых мутациях вовлеченных, однако мало , что бит должны был начаться с, почти столь же убедительным оправданием , как на самом деле избавиться от этой части мутации было бы - по крайней мере, если цель состоит в том, чтобы сделать тесты более функциональными.

Хотя мне, наверное, не следовало даже заходить так далеко по этому поводу; о решениях см. ниже. 😸


Так что я не совсем уверен, в чем основная проблема с предложенной мною дополнительной функцией с вашей стороны.

(Также здесь важная часть :) Мне нравится бит, в котором timeout в качестве параметра вместо вызова метода, на самом деле! Если вы можете придумать способ обобщить это на остальные методы конфигурации Mocha (их много - и некоторые из них применимы к синхронным тестам, если я правильно помню, поэтому мы не можем просто добавить те же методы, что и properties на done и позволить людям писать асинхронные тесты, которые могут вызывать конфигурацию через done , но я отвлекся), тогда я определенно хотел бы взглянуть на это. По крайней мере, мы можем сделать это рекомендацией, и мы можем даже принять реализацию в it при передаче третьего параметра (или чего-то подобного, может быть, it.configured или it(...).configured(...) если мы не хотим больше махинаций с количеством параметров ...) - что, я думаю, было бы обратно совместимым решением, которое решает основную проблему мутации / императива и получает поддержку стрелочной функции "правильное" способ »(то, что я утверждаю, так или иначе): потому что это соответствует новому поведению. Думаю, что я должен был сказать, вместо того, чтобы идти после this в обходном пути, а именно: давайте расширим его параметрическую часть!

Клянусь, я где-то читал, что можно сделать что-то вроде этого:

describe('a slow thing', () => {
 // test code...
}).timeout(5000);

что не изменяет контракт параметров для предоставленной функции. Сейчас я не могу найти ни одной ссылки на такую ​​вещь, так что, возможно, я просто вообразил это.

@ thom-nic это работает! я думаю, это имеет смысл, поскольку все функции мокко возвращают свой контекст

return this;

Это работает со мной при замене формы функции стрелки на обычную функцию

function () {.....}

Привет народ. Прошу прощения за то, что потемнел после того, как в августе началось обсуждение, я был довольно занят и фактически в основном завершил / перешел от этой работы.

Я ценю подробный ответ о различных вариантах использования и о том, как их сложно связать вместе. Это была самая краткая демонстрация различных настроек, поддерживаемых мокко, из всех, что я читал. Так что спасибо за то, что уделили время этому.

Оглядываясь назад, становится ясно, что я, должно быть, переоценил доступ к контексту мокко ( this ), когда этот аспект действительно был более удобной мыслью. Я не понимал, насколько легко это отвлечет внимание от того, что я на самом деле пытался сделать: это было немного весело, добавив временное расширение ( when ) к тестовой dsl для оптимизации одноразовой работы. корректировка тайм-аута (плюс устранение типичной ошибки для определенного стиля тестов, о чем я расскажу ниже). Возвращение this было еще одной забавной вещью, которую я решил добавить, основная идея (отсюда и название when ) заключалась в обработке случаев, для которых требовалось другое время ожидания, чем обычно.

Очевидно, если бы я хотел получить доступ к связанному контексту, я мог бы просто использовать function напрямую, как многие предлагали, вместо того, чтобы поднимать его с помощью оболочки. Не в этом проблема. 😄 Я не потерялся для меня, как это может показаться странным на первый взгляд. Я надеюсь, что, возможно, картина завершится, если я покажу, как я настраивал некоторые тесты, которые с самого начала привели меня на этот путь. Чтобы быть ясным, я не пытаюсь продать здесь какой-то конкретный стиль, используйте то, что работает для вас. Это то, что у меня сработало.

Ok
Во-первых, начните с предположения, что мы тестируем некоторую установку, которая в основном делает одно, но будет делать это для широкого диапазона входных данных, и поэтому мы должны протестировать эту вещь в нескольких сценариях, чтобы убедиться, что выходы верны. . Однако, поскольку соответствующий код приложения «делает одно», основная процедура тестирования почти всегда одинакова. Я также не хочу дублировать / видоизменять тестовое тело без нужды, поскольку это замедляет то, как быстро я могу добавить больше тестовых примеров для новых входных данных, и в конечном итоге обслуживание станет нецелесообразным.

Поэтому вместо этого мы пишем функцию, которая является достаточно общей, чтобы запустить код приложения с любыми потенциально поддерживаемыми входами, выполнить тестовое действие, а затем подтвердить результаты ... Добавьте, что в моем случае я работал с абстракцией Promise (по причинам, которые я опущу), поэтому эта функция обобщенной тестовой процедуры, естественно, должна возвращать эту цепочку обещаний. Хлеб с маслом, вроде того, пока все хорошо.

Теперь перейдем к тестовым сценариям, поскольку мы упаковали все в нашу функцию тестовой процедуры, тестовые примеры эффективно определяют входные данные и вызывают функцию.

Так что, возможно, я напишу кучу подобных тестов, и все _похоже_, что работает:

it('does something', function() {
  testProcedureFunction('something','1')
})

Если вы внимательно следите за происходящим, вы, вероятно, уже заметили, что в этом примере есть ошибка. Ему не хватает return , и поскольку testProcedureFunction построен на обещаниях (каламбур), он всегда будет проходить, независимо от того, проходят ли утверждения в конце или нет. Это ошибка, и иногда она может быть очень тонкой, чтобы ее можно было отследить. Чтобы проиллюстрировать, в зависимости от того, как мы написали testProcedureFunction и как написано приложение, допустим, есть некоторый синхронный код в начале, и он взрывается вместо утверждений о конце теста, тестовый пример может даже потерпеть неудачу, что приводит нас к думать, что все в порядке.

Конечно, с возвратом тест действительно должен выглядеть так:

it('does something', function() {
  return testProcedureFunction('something','1')
})

Теперь я знаю, что в большинстве случаев этот тест будет одной строкой. Фактически, каждый случай будет одной строкой, за исключением тех случаев, когда входные данные таковы, что требуется больший тайм-аут. Среди различий между классическими функциями js и стрелками есть особый аспект функций стрелок, который здесь полезен: функция стрелки с одним оператором имеет подразумеваемый возврат, когда фигурные скобки опущены. Если вместо написания function {...} в тесте используется => ... , то я могу легко просканировать эти случаи на наличие стрелки и отсутствия фигурных скобок и быстро сделать вывод, что у них не может быть этого недостающего return , и потребуется несколько дополнительных шагов (добавление фигурных скобок), чтобы кто-то это испортил.

Вот так:

it('does something', () => testProcedureFunction('something','1'))

А что, если в одном из этих случаев потребуется больше времени, чем в других! Конечно, мы можем установить тайм-аут следующим образом:

it('does something slow', function() {
  this.timeout(10000)
  return testProcedureFunction('somethingSlow','2')
})

Или, может быть, кто-то ошибется и сделает это первым (что, конечно, не работает):

it('does something slow', () => {
  this.timeout(10000)
  return testProcedureFunction('somethingSlow','2')
})

Но теперь мы вернулись к тому, с чего начали, в кодовой базе есть шаблон, готовый для повторения, который чувствителен к отсутствующей ошибке возврата (либо будущим мной, либо следующим человеком, который добавит функцию - дело в том, что это простой совершить ошибку, она может остаться незамеченной, и ее может быть трудно отследить). Функция when решает эту проблему и позволяет нам снова последовательно использовать стрелки:

it('does something slow', when(() => testProcedureFunction('somethingSlow','2'), 10000))

(обратите внимание, я не смог заставить работать предложенное выше предложение .timeout(5000) dot-chaining, возможно, из-за версии мокко, которую мне нужно было использовать, я больше не помню, даст это пытаться!)
(note2, обратите внимание, что использование when не использует трюк с поднятием параметра this - это действительно было просто запоздалой мыслью).

Возможно, существуют линтеры, которые могут помечать отсутствующие ошибки возврата в обмен на обещание (или, что более реалистично, принудительное выполнение оператора возврата с rhs для каждой функции). Однако в то время это не было вариантом, к тому же я думаю, что синтаксис стрелок стал короче, и я нахожу его (субъективно / лично) легче читать и работать с ним, что склонило чашу весов в сторону от function .

Вот и все.

Я не знаю, успею ли я ответить снова в ближайшее время, поэтому я надеюсь, что это было по крайней мере информативным и ясным, и, возможно, даже поставило некоторые противоречия вокруг всего «доступа к мокко-контексту от стрелок» до кровать.

Наконец, так как я нашел функцию vs => запутанной в течение долгого времени, я опущу эту ссылку на случай, если кто-нибудь, случайно читающий, не поймет, почему стрелки не могут получить доступ к this . Это было самое ясное объяснение функций и стрелок, которое я нашел, и именно это помогло мне, наконец, понять различия достаточно хорошо, чтобы использовать их с полной уверенностью.

https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/

@ thom-nic Он работает с it , но не с describe .

describe('my test suite', () => {

  it('test case 1', () => {
    // ...
  }).timeout('10s');  // Works on `it`. This test case doesn't timeout

  it('test case 2', () => {
    // ...
  });  // This test case timeouts.

}).timeout('10s');  // Doesn't work on `describe`. Tests are already created when runs to here.

@ thom-nic, вы можете использовать обычную функциональную форму

describe('my test suite', function() {
this.timeout(n);

...
}

Любой, кто жалуется на это, не понимает функций стрелок.

Стрелочные функции - это НЕ новая причудливая вещь ES6, которая должна заменить классическую function () {} . Единственная цель стрелочных функций состоит в том, что они наследуют this от своего родителя, тогда как классическая function () имеет собственный this .

Да, даже при использовании полного синтаксиса ES6 вы все равно должны использовать function () если хотите использовать this в правильном контексте вашей функции. Вы должны использовать как function () и () => в своем приложении ES6 в зависимости от того, что вы пытаетесь сделать.

this.timeout() не работает с it('....', () => { ... }) потому что обратный вызов наследует this от родительской функции describe() , в которой this.timeout() не работает имеют смысл на этом уровне.

Разве лямбда-функции не позволяют вам автоматически отправлять один аргумент функции, не объявляя его в вызове?

(параметр) => функция
... затем (функция)

function () {} может быть привязан к 'this', но () => 'заблокирован'

Стрелочные функции должны заменить традиционную функцию, когда получатель ожидает заранее определенного 'this' в том же контексте, из которого он вызывается (а также выигрывает от ввода меньшего количества кода).

Я бы пошел еще дальше и сказал, что никогда не используйте function (), если вы не хотите, чтобы 'this' было чем-то отличным от того, что есть 'this' при его вызове.

@Фламенко...

Разве лямбда-функции не позволяют вам автоматически отправлять один аргумент функции, не объявляя его в вызове?

Я не уверен, что понимаю _ точно_, как вы это говорите.
Что касается «отправки аргументов функции», толстые стрелки работают так же, как и обычные функции, за одним исключением: если у вас ровно 1 аргумент, вы можете опустить круглые скобки.

() => console.log("hi"); //zero arguments requires empty parenthesis
a => console.log(a); //you can optionally leave the parenthesis off for 1 argument
(a,b) => console.log(`${a} ${b}`); //2..n arguments requires parenthesis

Возможно, вы пришли к выводу, что толстые стрелки позволяют вам _вернуть_ значение, опуская фигурные скобки и ключевое слово return если ваша функция является одним выражением.
Итак, если бы у вас было ...

setTimeout(function(a,b) { doSomething(); return calculateSomething(a,b); }, 5000);

... и вы хотели преобразовать это в функцию жирной стрелки, вы не сможете встряхнуть фигурные скобки и ключевое слово return, потому что тело функции имеет несколько операторов. Ты бы сделал это вот так ...

setTimeout((a,b) => { doSomething(); return calculateSomething(a,b); }, 5000);

Если, скорее, вы начали с ...

setTimeout(function(a,b) { return calculateSomething(a,b); }, 5000);

... тогда вы имеете дело с функцией, которая настолько проста, что она просто возвращает одно выражение, и вы можете использовать ...

setTimeout((a,b) => calculateSomething(a,b), 5000);

Это стало намного легче читать!
Я написал об этом немного больше на codefoster.com/levelup-arrays .

В JavaScript есть много разных стилей кодирования - от ООП до FP, от строгой типобезопасности до миксин / утиная типизация. Кроме того, в каждом из этих стилей есть расширенные шаблоны (например, внедрение зависимостей в лагере ООП, каррирование / монада в лагере FP).

Если ваш стиль кодирования ближе к FP, где this не используется, а стрелочные функции используются для уменьшения шаблонного кода, необходимость сохранения this - это дополнительные накладные расходы для любого расширенного тестирования (например, параметризованное тестирование, создание DSL).

Любой опытный разработчик может просто предварительно обернуть среду тестирования в соответствии со своим стилем кодирования, но это означает, что структура менее "из коробки". Это означает дополнительную работу по обновлению, внедрению плагинов и адаптации новых инженеров.

Мне нравится идея альтернативного интерфейса bdd который не использует this и вместо этого передает объект контекста в качестве параметра в describe , it и крючки.

Но это не так просто реализовать, IIRC. Хотя было бы здорово увидеть попытку.

Я знаю, что это приводит к серьезным побочным эффектам, но не могли бы вы справиться с параметром done-or-context что-то вроде этого?

it("runs immediately", () => {
  // call functions and assert whatever
})
it("runs asynchronously", doneOrContext => {
  setTimeout(() => {
    // call functions and assert whatever
    doneOrContext();
  }, 100)
})



md5-b1fe6f00c87a2916712cf6a4df16e142



it("runs immediately using the parameter as a context", doneOrContext => {
  doneOrContext.configureByMutation("some value");
  // As well as changing config, also flags to Mocha that this test is treating the
  // parameter as a context object and is therefore not async.
  // Call functions and assert whatever
})



md5-b1fe6f00c87a2916712cf6a4df16e142



it("runs asynchronously using the parameter as a context", doneOrContext => {
  doneOrContext.configureByMutation("some value");
  doneOrContext.setAsync(); // Flags to Mocha that even though the parameter has been used as
  // a context object, the test is in fact asynchronous.
  setTimeout(() => {
    // call functions and assert whatever
    doneOrContext();
    // or doneOrContext.done()
  }, 100)
})

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

Myscript:

описать ("getBillingDetail", async function () {
this.timeout (55000);
it.only ("проверить правильность имени задания", асинхронная функция (выполнено) {
this.timeout (55000);
var result = await url.getBillingDetail ('12254785565647858');
console.log (результат);
assert.equal (результат, истина);
});
});

Ошибка: превышено время ожидания 55000 мс. Для асинхронных тестов и ловушек убедитесь, что вызывается "done ()"; при возврате обещания убедитесь, что оно разрешено.

Не передавайте выполненный обратный вызов асинхронной функции

Я создал прототип решения с обратной совместимостью. На данный момент это отдельный модуль, но функциональность может быть легко объединена в собственно mocha .

https://github.com/papercuptech/mocha-lambda

быстрый способ

require('mocha-lambda')
// now a global '_tst' can be used where 'this' was before

describe('suite', () => {
  beforeEach(() => {
    _tst.answer = 42
  })

  it('provides "this" as "_tst"', function() {
    assert(this === _tst)
  })

  it('works', () => {
    assert(_tst.answer === 42)
    _tst.skip()
  })
})

для явного именования (и работает с TypeScript)

// if you were previously explicitly importing api (describe, it, etc.) from 'mocha',
// you will have to change to importing from 'mocha-lambda', until (or if) this
// gets merged into mocha proper
import ctx, {describe as d, it as i} from 'mocha-lambda'

d('suite', () => {
  // ctx() is a function that returns "this" as appropriate
  i('works using ctx()', () => {
    ctx().skip()
  })
})

import {Context} from 'mocha'
// ctx() can also rename global
ctx('t')
declare var t: Context
d('suite', () => {
  // ctx() is a function that returns "this" as appropriate
  i('works using renamed global', () => {
    t.skip()
  })
})

@papercuptech Ссылка 404 не найдена.

Уупс .. было частным репо. теперь публично

Можно также npm i mocha-lambda

@aleung @linesh-simplicity, заменено на # 3485

Спасибо.

Почему так много «магии», которая, в конце концов, порождает проблемы? Почему не это ?:

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

Никаких глобалов, никакой проблемной магии ... только JavaScript.

см. ответ @ thom-nic, очистил и сделал свое дело

Клянусь, я где-то читал, что можно сделать что-то вроде этого:

describe('a slow thing', () => {
 // test code...
}).timeout(5000);

что не изменяет контракт параметров для предоставленной функции. Сейчас я не могу найти ни одной ссылки на такую ​​вещь, так что, возможно, я просто вообразил это.

Решение @ thom-nic сработало для меня, спасибо!

Была ли эта страница полезной?
0 / 5 - 0 рейтинги