Асинхронный код в пользовательских правилах ESLint
История и мотивация:
У нас есть довольно обширная сквозная тестовая кодовая страница Protractor. Иногда бывает, что тест ждет конкретного исправления, которое будет реализовано - как правило, в рамках подхода TDD и для демонстрации того, как проблема воспроизводится и каково предполагаемое поведение. В настоящее время мы используем Jasmine pending()
с номером проблемы Jira внутри. Пример:
pending("Missing functionality (AP-1234)", function () {
// some testing is done here
});
Теперь мы хотели бы знать, когда мы можем переименовать pending()
обратно в it()
и запустить тест. Или, другими словами, когда проблема AP-1234
разрешена или отправляется на тестирование.
Текущий подход:
В настоящий момент я пытаюсь решить его с помощью пользовательского правила ESLint
, jira
Модуль NodeJS и Q
. Пользовательское правило ESLint
выполняет поиск вызовов pending()
с хотя бы одним аргументом. Извлекает номера билетов в формате AP-
, а затем 4 цифры и использует jira.findIssue()
, чтобы проверить его статус в Jira. Если статус Resolved
- сообщить об ошибке.
Вот что я получил до сих пор:
"use strict";
var JiraApi = require("jira").JiraApi,
Q = require('q');
var jira = new JiraApi("https",
"jira.url.com",
"443",
"user",
"password",
"2");
module.exports = function (context) {
var jiraTicketRegex = /AP\-\d+/g;
return {
CallExpression: function (node) {
if (node.callee.name === "pending" && node.arguments.length > 0) {
var match = node.arguments[0].value.match(jiraTicketRegex);
if (match) {
match.forEach(function(ticket) {
console.log(ticket); // I see the ticket numbers printed
getTicket(ticket).then(function (status) {
console.log(status); // I don't see statuses printed
if (status === "Resolved") {
context.report(node, 'Ticket {{ticket}} is already resolved.', {
ticket: ticket
})
}
});
});
}
}
}
}
};
Где getTicket()
определяется как:
function getTicket(ticket) {
var deferred = Q.defer();
jira.findIssue(ticket, function(error, issue) {
if (error) {
deferred.reject(new Error(error));
} else {
deferred.resolve(issue.fields.status.name);
}
});
return deferred.promise;
}
Проблема: в настоящее время она успешно извлекает номера билетов из вызовов pending()
, но не печатает статусы билетов. Ошибок нет.
Вопрос:
Общим вопросом является, я думаю, следующее: могу ли я использовать асинхронные блоки кода, ждать ответных запросов, разрешать promises в пользовательских правилах ESLint
? И, если нет, каковы мои варианты?
Более конкретный вопрос: что я делаю неправильно и как я могу использовать модуль Node.js jira
с ESLint
?
Поблагодарили бы любые идеи или альтернативные подходы.
Ответы
Ответ 1
Короткий ответ - нет, вы не можете использовать асинхронный код внутри правил. ESLint является синхронным и в значительной степени полагается на EventEmitter
, когда он ходит по AST. Было бы очень сложно изменить код ESLint, чтобы быть асинхронным, но в то же время гарантировать, что события будут выбрасываться в правильном порядке.
Я думаю, что ваш единственный выбор состоит в том, чтобы написать правило синхронизации, которое выводит достаточное количество информации в сообщение об ошибке, затем используйте один из синтаксических форматов, например JSON
или UNIX
, а затем создайте другое приложение, которое вы можете подключить к выходу ESLint и сделать асинхронный поиск в Jira на основе сообщения об ошибке.
Ответ 2
Примечание: он не отвечает на оригинальный вопрос о поддержке асинхронного кода в пользовательских правилах ESLint, но предоставляет альтернативное решение проблемы.
В этом случае я лично не использовал бы ESLint, он должен использоваться для проверки правильности написания кода и последующего руководства стилями; с моей точки зрения, пропущенные тесты не являются частью проверки кода, это больше похоже на внутренние процессы вашей команды. Кроме того, такие запросы могут значительно замедлить выполнение ESLint, если кто-либо запускает его в режиме реального времени в своем редакторе, вызовы будут выполняться очень часто и будут замедлять весь чек. Я бы сделал эту JIRA-проверку частью потока Contractor, поэтому, если билет будет разрешен, вы получите неудачную спецификацию Protractor. (скопирован из comment, чтобы завершить ответ)
Жасмин позволяет отмечать спецификации как ожидающие использования xit()
. Я не уверен в pending()
, хотя он работает странно в Protractor. Кроме того, Jasmine позволяет вызывать pending()
внутри спецификации, поэтому он будет помечен как ожидающий, но еще не реализован для Protractor (см. Проблему). Зная это, я бы использовал специальный помощник для определения "ожидающих спецификаций", который должен быть проверен для статуса проблемы JIRA. Я думаю, вы все еще можете использовать Q для работы с promises, я просто отправлю альтернативу с помощью WebDriver promises без внешних зависимостей. Ниже приведена измененная версия getTicket()
:
function getTicketStatus(ticket) {
// Using WebDriver promises
var deferred = protractor.promise.defer();
jira.findIssue(ticket, function(error, issue) {
if (error) {
deferred.reject(new Error(error));
} else {
deferred.fulfill(issue.fields.status.name);
}
});
return deferred.promise;
}
Тогда существует пользовательская вспомогательная функция:
function jira(name) {
// Display as pending in reporter results, remove when pending() is supported
xit(name);
// Using Jasmine Async API because Jira request is not a part of Control Flow
it(name, function (done) {
getTicketStatus().then(function (status) {
if (status === 'Resolved') {
done.fail('Ticket "' + name + '" is already resolved.');
} else {
done();
// pending() is not supported yet https://github.com/angular/protractor/issues/2454
// pending();
}
}, function (error) {
done.fail(error);
});
});
}
Пример использования:
jira('Missing functionality (AP-1234)', function () {
//
});
jira('Missing functionality (AP-1235)');
Если запрос JIRA не удался или проблема имеет статус "Разрешено", вы получите неудачную спецификацию (используя Jasmine асинхронный API). Во всех ситуациях вы все равно будете дублировать эту спецификацию в ожидании результатов репортера. Я надеюсь, что это можно улучшить, когда pending()
функциональность внутри спецификации реализована.