最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Asynchronous code in custom ESLint rules - Stack Overflow

programmeradmin5浏览0评论

The Story and Motivation:

We have a rather huge end-to-end Protractor test codebase. Sometimes it happens that a test waits for a specific fix to be implemented - usually as a part of a TDD approach and to demonstrate how a problem is reproduced and what is the intended behavior. What we are currently doing is using Jasmine's pending() with a Jira issue number inside. Example:

pending("Missing functionality (AP-1234)", function () {
    // some testing is done here
});

Now, we'd like to know when we can rename the pending() back to it() and run the test. Or, in other words, when the issue AP-1234 is resolved or sent to testing.

The Current Approach:

At the moment, I'm trying to solve it with a custom ESLint rule, jira NodeJS module, and Q. The custom ESLint rule searches for pending() calls with at least one argument. Extracts the ticket numbers in format of AP- followed by 4 digits and uses jira.findIssue() to check its status in Jira. If status is Resolved - report an error.

Here is what I've got so far:

"use strict";

var JiraApi = require("jira").JiraApi,
    Q = require('q');
var jira = new JiraApi("https",
    "jira.url",
    "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
                                })
                            }
                        });
                    });

                }
            }
        }
    }
};

Where getTicket() is defined as:

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;
}

The problem is: currently, it successfully extracts the ticket numbers from the pending() calls, but doesn't print ticket statuses. No errors though.

The Question:

The general question is, I guess, would be: can I use asynchronous code blocks, wait for callbacks, resolve promises in custom ESLint rules? And, if not, what are my options?

A more specific question would be: what am I doing wrong and how can I use Node.js jira module with ESLint?

Would appreciate any insights or alternative approaches.

The Story and Motivation:

We have a rather huge end-to-end Protractor test codebase. Sometimes it happens that a test waits for a specific fix to be implemented - usually as a part of a TDD approach and to demonstrate how a problem is reproduced and what is the intended behavior. What we are currently doing is using Jasmine's pending() with a Jira issue number inside. Example:

pending("Missing functionality (AP-1234)", function () {
    // some testing is done here
});

Now, we'd like to know when we can rename the pending() back to it() and run the test. Or, in other words, when the issue AP-1234 is resolved or sent to testing.

The Current Approach:

At the moment, I'm trying to solve it with a custom ESLint rule, jira NodeJS module, and Q. The custom ESLint rule searches for pending() calls with at least one argument. Extracts the ticket numbers in format of AP- followed by 4 digits and uses jira.findIssue() to check its status in Jira. If status is Resolved - report an error.

Here is what I've got so far:

"use strict";

var JiraApi = require("jira").JiraApi,
    Q = require('q');
var jira = new JiraApi("https",
    "jira.url.",
    "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
                                })
                            }
                        });
                    });

                }
            }
        }
    }
};

Where getTicket() is defined as:

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;
}

The problem is: currently, it successfully extracts the ticket numbers from the pending() calls, but doesn't print ticket statuses. No errors though.

The Question:

The general question is, I guess, would be: can I use asynchronous code blocks, wait for callbacks, resolve promises in custom ESLint rules? And, if not, what are my options?

A more specific question would be: what am I doing wrong and how can I use Node.js jira module with ESLint?

Would appreciate any insights or alternative approaches.

Share Improve this question edited Jan 3, 2016 at 3:15 user4639281 asked Nov 23, 2015 at 22:17 alecxealecxe 474k127 gold badges1.1k silver badges1.2k bronze badges 7
  • Does response from Jira e at all? Could you check it inside getTicket function? I personally would not use ESLint in this case, it is supposed to be used to check if your code is written correctly and if you follow style guides; from my point of view missing tests is not the part of code check, it's more like your team internal processes. Also, this kind of requests may slow your ESLint executions significantly, if anyone runs it in real-time in their editor, calls will be made very often and will slow down the entire check. I am not sure about async support in ESLint though. – Michael Radionov Commented Nov 24, 2015 at 9:16
  • @MichaelRadionov if I put the exact same code outside of the rule - I see the responses ing from Jira - I can check the status for every requested ticket - this part works like a clockwork. Overall, I agree with you that eslint is probably not a good tool to use for this kind of task. It's probably more my curiosity driving it :) How would you automate this? Thank you! – alecxe Commented Nov 24, 2015 at 14:46
  • Should these checks for missing tests fail your actual Protractor tests? – Michael Radionov Commented Nov 24, 2015 at 16:41
  • @MichaelRadionov yup, I think it's okay to fail a test in this case (I already like where you are going with this - make this a part of a test run?..) – alecxe Commented Nov 24, 2015 at 16:43
  • Yeah, kinda. I suppose it also would be nice to keep pending, because it shows in the report that there are some unfinished parts. – Michael Radionov Commented Nov 24, 2015 at 16:44
 |  Show 2 more ments

3 Answers 3

Reset to default 10

The short answer is - no, you can't use asynchronous code inside of the rules. ESLint is synchronous and heavily relies on EventEmitter when it walks AST. It would be very hard to modify ESLint code to be async, but at the same time guarantee that events will be emitted in the right order. I think your only choice might be to write a sync rule that outputs enough information into the error message, then use one of the parsable formatters like JSON or UNIX and then create another application that you can pipe ESLint output to and do a async lookup in Jira based on the error message.

These answers remain valid in 2018.

For some insights from the eslint devs, see this conversation we had on their mailing list.

For a working example, in my "pseudo eslint plugin" I opted to use expensive but synchronous APIs and warn users about how best to use the "plugin" in their CI process.

Note: it does not answer original question about support of async code in ESLint custom rules, but provides an alternative solution to the issue.

I personally would not use ESLint in this case, it is supposed to be used to check if your code is written correctly and if you follow style guides; from my point of view missing tests is not the part of code check, it's more like your team internal processes. Also, this kind of requests may slow your ESLint executions significantly, if anyone runs it in real-time in their editor, calls will be made very often and will slow down the entire check. I would make this JIRA check a part of Protractor flow, so if the ticket is resolved, you will get a failed Protractor spec. (copied from the ment to make the answer plete)

Jasmine allows to mark specs as pending using xit(). I am not sure about pending() though, it works weird in Protractor. Also, Jasmine allows to call pending() inside a spec, so it will be marked as pending, but it is not implemented for Protractor yet (see issue). Knowing that, I would use a custom helper to define "pending specs", which should be checked for JIRA issue status. I guess you can still use Q to work with promises, I'll just post an alternative using WebDriver promises without external dependencies. Here is a modified version of 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;
}

Then there is a custom helper function:

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./angular/protractor/issues/2454
                // pending();
            }
        }, function (error) {
            done.fail(error);
        });
    });

}

Usage example:

jira('Missing functionality (AP-1234)', function () {
    //
});

jira('Missing functionality (AP-1235)');

In case if request to JIRA fails or issue has a status Resolved, you will get a failed spec (using Jasmine async API). In all situations you will still have this spec duplicated as pending in reporter results. I hope it can be improved, when pending() functionality inside a spec is implemented.

发布评论

评论列表(0)

  1. 暂无评论