@@ -25,12 +25,19 @@ function collectResultsFromFrames(
 
   // Tell each axe running in each frame to collect results
   frames.forEach(frame => {
+    const tabindex = frame.node.getAttribute('tabindex');
+    const focusable = tabindex ? parseInt(tabindex) >= 0 : true;
+
     var params = {
       options: options,
       command: command,
       parameter: parameter,
       context: {
         initiator: false,
+
+        // if any parent iframe is not focusable then the entire
+        // iframe stack is not focusable
+        focusable: context.focusable === false ? false : focusable,
         page: context.page,
         include: frame.include || [],
         exclude: frame.exclude || []
import queue from './queue';
import sendCommandToFrame from './send-command-to-frame';
import mergeResults from './merge-results';
import getSelector from './get-selector';

/**
 * Sends a message to axe running in frames to start analysis and collate results (via `mergeResults`)
 * @private
 * @param  {Context}  context   The resolved Context object
 * @param  {Object}   options   Options object (as passed to `runRules`)
 * @param  {string}   command   Command sent to all frames
 * @param  {Array}    parameter Array of values to be passed along side the command
 * @param  {Function} callback  Function to call when results from all frames have returned
 */
function collectResultsFromFrames(
  context,
  options,
  command,
  parameter,
  resolve,
  reject
) {
  var q = queue();
  var frames = context.frames;

  // Tell each axe running in each frame to collect results
  frames.forEach(frame => {
    var params = {
      options: options,
      command: command,
      parameter: parameter,
      context: {
        initiator: false,
        page: context.page,
        include: frame.include || [],
        exclude: frame.exclude || []
      }
    };

    q.defer((res, rej) => {
      var node = frame.node;
      sendCommandToFrame(
        node,
        params,
        data => {
          if (data) {
            return res({
              results: data,
              frameElement: node,
              frame: getSelector(node)
            });
          }
          res(null);
        },
        rej
      );
    });
  });

  // Combine results from all frames and give it back
  q.then(data => {
    resolve(mergeResults(data, options));
  }).catch(reject);
}

export default collectResultsFromFrames;

This needs to account for invalid tabindex like `tabindex="foo"`.