
function dispatchEventWithLog(shadow, target, event) {
    var eventPath = [];
    var relatedTargets = [];
    var pathAtTargets = [];

    var attachedNodes = [];
    for (var nodeKey in shadow) {
        var startingNode = shadow[nodeKey];
        for (var node = startingNode; node; node = node.parentNode) {
            if (attachedNodes.indexOf(node) >= 0)
                continue;
            attachedNodes.push(node);
            node.addEventListener(event.type, (function (event) {
                eventPath.push(this.label);
                relatedTargets.push(event.relatedTarget ? event.relatedTarget.label : null);

                if (!event.composedPath) // Don't fail all tests just for the lack of composedPath.
                    return;

                pathAtTargets.push(event.composedPath().map(function (node) { return node.label; }));
            }).bind(node));
        }
    }

    target.dispatchEvent(event);

    return {eventPath: eventPath, relatedTargets: relatedTargets, pathAtTargets: pathAtTargets};
}

/*
-SR: ShadowRoot  -S: Slot
A ------------------------------- A-SR
+ B ------------ B-SR             + A1 --- A1-SR
  + C            + B1 --- B1-SR   + A2-S   + A1a
  + D --- D-SR     + B1a  + B1b --- B1b-SR
          + D1            + B1c-S   + B1b1
                                    + B1b2
*/
function createTestTree(mode) {
    var namedNodes = {};

    function element(name) {
        var element = document.createElement(name.indexOf('-S') > 0 ? 'slot' : 'div');
        element.label = name;
        namedNodes[name] = element;
        for (var i = 1; i < arguments.length; i++) {
            var item = arguments[i];
            if (typeof(item) == 'function')
                item(element);
            else
                element.appendChild(item);
        }
        return element;
    }

    function shadow(name) {
        var children = [];
        for (var i = 1; i < arguments.length; i++)
            children.push(arguments[i]);
        return function (element) {
            var shadowRoot = element.attachShadow({mode: mode});
            shadowRoot.label = name;
            namedNodes[name] = shadowRoot;
            for (var child of children)
                shadowRoot.appendChild(child);
        }
    }

    var host = element('A',
        shadow('A-SR',
            element('A1',
                shadow('A1-SR',
                    element('A1a'))),
            element('A2-S')
        ),
        element('B',
            shadow('B-SR',
                element('B1',
                    shadow('B1-SR',
                        element('B1b',
                            shadow('B1b-SR',
                                element('B1b1'),
                                element('B1b2'))),
                        element('B1c-S')),
                    element('B1a'))),
            element('C'),
            element('D',
                shadow('D-SR',
                    element('D1')))));

    return namedNodes;
}
