Repository: lo1tuma/eslint-plugin-mocha (ts)

Issue:
Crash in no-identical-titles: "Cannot read property 'testTitles' of undefined"
Cannot read property 'testTitles' of undefined
TypeError: Cannot read property 'testTitles' of undefined
    at EventEmitter.CallExpression (/Users/wstamper/github/BBUI/SetupAssistantUI/node_modules/eslint-plugin-mocha/lib/rules/no-identical-title.js:51:54)
    at emitOne (events.js:101:20)
    at EventEmitter.emit (events.js:188:7)
    at NodeEventGenerator.enterNode (/Users/wstamper/github/BBUI/SetupAssistantUI/node_modules/eslint/lib/util/node-event-generator.js:40:22)
    at CodePathAnalyzer.enterNode (/Users/wstamper/github/BBUI/SetupAssistantUI/node_modules/eslint/lib/code-path-analysis/code-path-analyzer.js:608:23)
    at CommentEventGenerator.enterNode (/Users/wstamper/github/BBUI/SetupAssistantUI/node_modules/eslint/lib/util/comment-event-generator.js:97:23)
    at Controller.enter (/Users/wstamper/github/BBUI/SetupAssistantUI/node_modules/eslint/lib/eslint.js:915:36)
    at Controller.__execute (/Users/wstamper/github/BBUI/SetupAssistantUI/node_modules/estraverse/estraverse.js:397:31)
    at Controller.traverse (/Users/wstamper/github/BBUI/SetupAssistantUI/node_modules/estraverse/estraverse.js:501:28)
    at Controller.Traverser.controller.traverse (/Users/wstamper/github/BBUI/SetupAssistantUI/node_modules/eslint/lib/util/traverser.js:36:33)

Pull request:
Fix crash in no-identical-title (fixes #98)
Fix crash in no-identical-title (fixes #98)

The problem was no new test suite "layer" was added if the test suite had a non-string literal title, but the layers were popped regardless of the title, which resulted in an empty stack.

cc @epmatsw

Patch:
diff --git a/lib/rules/no-identical-title.js b/lib/rules/no-identical-title.js
index cd5ce13..10137ab 100644
--- a/lib/rules/no-identical-title.js
+++ b/lib/rules/no-identical-title.js
@@ -21,18 +21,21 @@ function handlTestCaseTitles(context, titles, node, title) {
     }
 }
 
-function handlTestSuiteTitles(context, layers, node, title) {
-    var currentLayer = layers[layers.length - 1];
-    if (astUtil.isDescribe(node)) {
-        if (currentLayer.describeTitles.indexOf(title) !== -1) {
-            context.report({
-                node: node,
-                message: 'Test suite title is used multiple times.'
-            });
-        }
-        currentLayer.describeTitles.push(title);
-        layers.push(newLayer());
+function handlTestSuiteTitles(context, titles, node, title) {
+    if (!astUtil.isDescribe(node)) {
+        return;
+    }
+    if (titles.indexOf(title) !== -1) {
+        context.report({
+            node: node,
+            message: 'Test suite title is used multiple times.'
+        });
     }
+    titles.push(title);
+}
+
+function isFirstArgLiteral(node) {
+    return node.arguments && node.arguments[0] && node.arguments[0].type === 'Literal';
 }
 
 module.exports = function (context) {
@@ -43,13 +46,16 @@ module.exports = function (context) {
         CallExpression: function (node) {
             var currentLayer = titleLayers[titleLayers.length - 1],
                 title;
-            if (!node.arguments || !node.arguments[0] || node.arguments[0].type !== 'Literal') {
+            if (astUtil.isDescribe(node)) {
+                titleLayers.push(newLayer());
+            }
+            if (!isFirstArgLiteral(node)) {
                 return;
             }
 
             title = node.arguments[0].value;
             handlTestCaseTitles(context, currentLayer.testTitles, node, title);
-            handlTestSuiteTitles(context, titleLayers, node, title);
+            handlTestSuiteTitles(context, currentLayer.describeTitles, node, title);
         },
         'CallExpression:exit': function (node) {
             if (astUtil.isDescribe(node)) {


Test patch:
diff --git a/test/rules/no-identical-title.js b/test/rules/no-identical-title.js
index 2ae9ded..9b956b9 100644
--- a/test/rules/no-identical-title.js
+++ b/test/rules/no-identical-title.js
@@ -77,7 +77,21 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], {
             env: {
                 es6: true
             }
-        }
+        },
+        [
+            'describe("title " + foo, function() {',
+            '    describe("describe1", function() {});',
+            '});',
+            'describe("describe1", function() {});'
+        ].join('\n'),
+        [
+            'describe("describe1", function() {',
+            '    describe("describe2", function() {});',
+            '    describe("title " + foo, function() {',
+            '        describe("describe2", function() {});',
+            '    });',
+            '});'
+        ].join('\n')
     ],
 
     invalid: [
@@ -125,6 +139,13 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], {
             ].join('\n'),
             errors: [ { message: 'Test suite title is used multiple times.', column: 1, line: 2 } ]
         },
+        {
+            code: [
+                'describe("describe1", function() {});',
+                'xdescribe("describe1", function() {});'
+            ].join('\n'),
+            errors: [ { message: 'Test suite title is used multiple times.', column: 1, line: 2 } ]
+        },
         {
             code: [
                 'describe("describe1", function() {',