ESLint rule for Jasmine/Protractor
Your naming of variables is good, they're mostly descriptive and easy to follow.

You could use reverse conditional to reduce the cyclomatic code complexity, doing that your code would look something like:

module.exports = {
  meta: {
    schema: []
  },

  create(context) {
    return {
      MemberExpression(node) {
        if (!node.property || !node.property.object || node.property.name !== 'length') {
          return
        }

        const variableName = node.object.name

        const expectAncestors = context.getAncestors(node)
        for (const expectAncestor of expectAncestors) {
          if (!expectAncestor || expectAncestor.type !== 'CallExpression' || !isExpect(expectAncestor)) {
            continue
          }

          const thenAncestors = context.getAncestors(expectAncestor)
          for (const thenAncestor of thenAncestors) {
            if (!thenAncestor || thenAncestor.type !== 'CallExpression') {
              continue
            }

            const thenCallback = isThenCallBack(thenAncestor)
            const hasParams = thenCallback &amp;&amp; thenCallback.params &amp;&amp; thenCallback.params.length &gt; 0

            if (!hasParams) {
              continue
            }

            const [thenCallbackParam] = thenCallback.params
            const paramIsDesiredVariable = thenCallbackParam &amp;&amp; thenCallbackParam.name === variableName

            const isElementArrayFinderResolution = thenAncestor.callee &amp;&amp; thenAncestor.calle.object &amp;&amp; isElementArrayFinder(thenAncestor.callee.object)

            if (!paramIsDesiredVariable || !isElementArrayFinderResolution) {
              continue
            }

            context.report({
              node,
              message: 'Array.length inside promise resolution function detected. Use count() instead.'
            })

            return
          }
        }
      }
    }
  }
}


I've included some extra changes in the above code, such as using some ES6.


Property shorthand: { node: node } -> { node }
Method properties: create: function(context) { -> create(context) {
For-of: for (var i = 0; i &lt; ancestors.length; i++) { expectAncestor = ancestors[i] -> for (const thenAncestor of thenAncestors), which is nice since the index was only used to access the ith element
Constants: Using const to denote variables that cannot be re-assigned
Using param instead of "argument" to be consistent with eslint api
Creating expectAncestors/thenAncestors instead of re-assigning ancestors


We could further refactor using extract method:

const getExpectAncestor = (context, node) =&gt;
  context.getAncestors(node).find(expectAncestor =&gt; expectAncestor &amp;&amp; expectAncestor.type === 'CallExpression' &amp;&amp; isExpect(expectAncestor))

const getThenAncestor = (context, expectAncestor) =&gt;
  context.getAncestors(expectAncestor).find(thenAncestor =&gt; thenAncestor &amp;&amp; thenAncestor.type === 'CallExpression')

const getThenCallbackParam = thenAncestor =&gt; {
  const thenCallback = isThenCallback(thenAncestor)
  const hasParams = thenCallback &amp;&amp; thenCallback.params &amp;&amp; thenCallback.params.length &gt; 0

  if (hasParams) {
    return thenCallback.params[0]
  }
}

// Ideally you'd rename this something even more descriptive
const isDesiredVariable = (thenCallbackParam, variableName) =&gt; {
  const paramIsDesiredVariable = thenCallbackParam &amp;&amp; thenCallbackParam.name === variableName
  const isElementArrayFinderResolution = thenAncestor.callee &amp;&amp; thenAncestor.calle.object &amp;&amp; isElementArrayFinder(thenAncestor.callee.object)

  return paramIsDesiredVariable &amp;&amp; isElementArrayFinder
}

module.exports = {
  meta: {
    schema: []
  },

  create(context) {
    return {
      MemberExpression(node) {
        // You could extract this into a `isLengthVariable` function
        if (!node.property || !node.property.object || node.property.name !== 'length') {
          return
        }

        const expectAncestor = getExpectAncestor(context, node)
        if (!expectAncestor) {
          return
        }

        const thenAncestor = getThenAncestor(context, expectAncestor)
        if (!thenAncestor) {
          return
        }

        const thenCallbackParam = getThenCallbackParam(thenAncestor)
        if (!thenCallbackParam) {
          return
        }

        const variableName = node.object.name

        if (isDesiredVariable(thenCallbackParam, variableName)) {
          context.report({
            node,
            message: 'Array.length inside promise resolution function detected. Use count() instead.'
          })  
        }
      }
    }
  }
}


Here, we have extracted the main logic into seperate methods: getExpectAncestor, getThenAncestor, getThenCallbackParam

These methods are using Array.prototype.find() to find the first element that matches the predicate provided. If no such element is found, it returns undefined and we can exit MemberExpression

Further notes

You could use arrow functions shorthand since you are directly returning:

create = context =&gt; ({
  MemberExpression(node) {
    // ...
  }
}


You could declare MemberExpression outside of module.exports to further reduce the indentation level, though since the function relies on context you would need to pass context as an additional parameter. You could achieve this through a higher-order function: 

const MemberExpression = context =&gt; node =&gt; {
  // ...
}

module.exports = {
  // ...

  create: context =&gt; ({
    MemberExpression: MemberExpression(context)
  }
}


You'd probably want to refactor this further since there are some especially long lines when checking conditionals, you can use a formatter such as prettier

Prettifying the solution with extracted methods gives the following:

const getExpectAncestor = (context, node) =&gt;
  context
    .getAncestors(node)
    .find(
      expectAncestor =&gt;
        expectAncestor &amp;&amp;
        expectAncestor.type === "CallExpression" &amp;&amp;
        isExpect(expectAncestor)
    );

const getThenAncestor = (context, expectAncestor) =&gt;
  context
    .getAncestors(expectAncestor)
    .find(
      thenAncestor =&gt; thenAncestor &amp;&amp; thenAncestor.type === "CallExpression"
    );

const getThenCallbackParam = thenAncestor =&gt; {
  const thenCallback = isThenCallback(thenAncestor);
  const hasParams =
    thenCallback &amp;&amp; thenCallback.params &amp;&amp; thenCallback.params.length &gt; 0;

  if (hasParams) {
    return thenCallback.params[0];
  }
};

// Ideally you'd rename this something even more descriptive
const isDesiredVariable = (thenCallbackParam, variableName) =&gt; {
  const paramIsDesiredVariable =
    thenCallbackParam &amp;&amp; thenCallbackParam.name === variableName;
  const isElementArrayFinderResolution =
    thenAncestor.callee &amp;&amp;
    thenAncestor.calle.object &amp;&amp;
    isElementArrayFinder(thenAncestor.callee.object);

  return paramIsDesiredVariable &amp;&amp; isElementArrayFinder;
};

module.exports = {
  meta: {
    schema: []
  },

  create(context) {
    return {
      MemberExpression(node) {
        // You could extract this into a `isLengthVariable` function
        if (
          !node.property ||
          !node.property.object ||
          node.property.name !== "length"
        ) {
          return;
        }

        const expectAncestor = getExpectAncestor(context, node);
        if (!expectAncestor) {
          return;
        }

        const thenAncestor = getThenAncestor(context, expectAncestor);
        if (!thenAncestor) {
          return;
        }

        const thenCallbackParam = getThenCallbackParam(thenAncestor);
        if (!thenCallbackParam) {
          return;
        }

        const variableName = node.object.name;

        if (isDesiredVariable(thenCallbackParam, variableName)) {
          context.report({
            node,
            message: "Array.length inside promise resolution function detected. Use count() instead."
          });
        }
      }
    };
  }
};