<!DOCTYPE html>
<html>
<head>
<title>Shadow DOM: Extensions to Event Interface</title>
<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
<meta name="assert" content="Event interface must have composedPath() as a method">
<link rel="help" href="http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event-interface">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/event-path-test-helpers.js"></script>
</head>
<body>
<div id="log"></div>
<script>

window.label = 'window';
document.label = 'document';
document.documentElement.label = 'html';
document.body.label = 'body';

// FIXME: Add a test for trimming event path.

/*
-SR: ShadowRoot  -S: Slot  target: (~)  *: indicates start  digit: event path order
A ------------------------------- A-SR
+ B ------------ B-SR             + A1 ------ A1-SR (1)
  + C            + B1 --- B1-SR   + A2-S      + A1a (*; 0)
  + D --- D-SR     + B1a    + B1b --- B1b-SR
          + D1              + B1c-S   + B1b1
                                      + B1b2
*/

function testEventTargetAfterDispatching(mode) {
    test(() => {
        const nodes = createTestTree(mode);
        const log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {composed: false, bubbles: true}));

        const expectedPath = ['A1a', 'A1-SR'];
        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], expectedPath);
        assert_array_equals(log.pathAtTargets[1], expectedPath);

        assert_equals(log.event.target, null);
        assert_equals(log.event.currentTarget, null);
    }, 'The event must propagate out of ' + mode + ' mode shadow boundaries when the composed flag is set 1');
}

testEventTargetAfterDispatching('open');
testEventTargetAfterDispatching('closed');

/*
-SR: ShadowRoot  -S: Slot  target: (~)  *: indicates start  digit: event path order
window (7)
 + document (6)
   + body (5)
     + A (4) --------------------------- A-SR (3)
       + B ------------ B-SR             + A1 (2) --- A1-SR (1)
         + C            + B1 --- B1-SR   + A2-S       + A1a (*; 0)
         + D --- D-SR     + B1a    + B1b --- B1b-SR
                 + D1              + B1c-S   + B1b1
                                             + B1b2
*/

function testComposedEventInDocument(mode) {
    test(() => {
        const nodes = createTestTree(mode);
        document.body.appendChild(nodes.A);

        const log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {composed: true, bubbles: true}));
        let expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR', 'A', 'body', 'html', 'document', 'window'];

        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], expectedPath);
        assert_array_equals(log.pathAtTargets[1], expectedPath);
        if (mode != 'open')
            expectedPath = expectedPath.slice(expectedPath.indexOf('A1'));
        assert_array_equals(log.pathAtTargets[2], expectedPath);
        assert_array_equals(log.pathAtTargets[3], expectedPath);
        if (mode != 'open')
            expectedPath = expectedPath.slice(expectedPath.indexOf('A'));
        assert_array_equals(log.pathAtTargets[4], expectedPath);
        assert_array_equals(log.pathAtTargets[5], expectedPath);
        assert_array_equals(log.pathAtTargets[6], expectedPath);
        assert_array_equals(log.pathAtTargets[7], expectedPath);

        assert_equals(log.event.target, nodes.A);
        assert_equals(log.event.currentTarget, null);
    }, 'The event must propagate out of ' + mode + ' mode shadow boundaries when the composed flag is set 2');
}

testComposedEventInDocument('open');
testComposedEventInDocument('closed');

/*
-SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
window
 + document
   + body
     + A ------------------------------- A-SR (3)
       + B ------------ B-SR             + A1 (2) -------- A1-SR (1)
         + C            + B1 --- B1-SR   + A2-S [*; 0-3]   + A1a (*; 0)
         + D --- D-SR     + B1a    + B1b --- B1b-SR
                 + D1              + B1c-S   + B1b1
                                             + B1b2
*/

function testComposedEventWithRelatedTargetInDocument(mode) {
    test(() => {
        const nodes = createTestTree(mode);
        document.body.appendChild(nodes.A);

        const log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {composed: true, bubbles: true, relatedTarget: nodes['A2-S']}));
        let expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR'];

        assert_array_equals(log.eventPath, expectedPath);
        assert_equals(log.eventPath.length, log.pathAtTargets.length);
        assert_array_equals(log.pathAtTargets[0], expectedPath);
        assert_array_equals(log.pathAtTargets[1], expectedPath);
        if (mode != 'open')
            expectedPath = expectedPath.slice(expectedPath.indexOf('A1'));
        assert_array_equals(log.pathAtTargets[2], expectedPath);
        assert_array_equals(log.pathAtTargets[3], expectedPath);
        assert_array_equals(log.relatedTargets, ['A2-S', 'A2-S', 'A2-S', 'A2-S']);
    }, 'The event must not propagate out of ' + mode + ' mode shadow tree in which the relative target and the relative related target are the same');
}

testComposedEventWithRelatedTargetInDocument('open');
testComposedEventWithRelatedTargetInDocument('closed');

</script>
</body>
</html>
