<!doctype html>
<html>
    <head>
        <title>Pointer Events coalesced events count and properties<</title>
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
        <script src="/resources/testharness.js"></script>
        <script src="/resources/testharnessreport.js"></script>
        <!-- Additional helper script for common checks across event types -->
        <script type="text/javascript" src="../pointerevent_support.js"></script>
        <script>
            var eventList = All_Pointer_Events;
            PhaseEnum = {
              WaitingForCancel:   0,
              WaitingForOver:     1,
              WaitingForEnter:    2,
              WaitingForDown:     3,
              WaitingForMove:     4,
              WaitingForUp:       5,
              WaitingForOut:      6,
              WaitingForLeave:    7,
              Done:               8,
            };
            var phase = PhaseEnum.WaitingForCancel;

            function resetTestState() {
                phase = PhaseEnum.WaitingForCancel;
            }
            function expect_no_coalesced_events(event, eventName) {
                test(function () {
                    assert_equals(event.getCoalescedEvents().length, 0, eventName + ' should not have any coalesced events');
                }, expectedPointerType + ' ' + eventName + ' should not have any coalesced events'); 
            }
            function run() {
                var test_pointerEvent = setup_pointerevent_test("coalesced events attributes in pointerevents", ['touch']);
                var target0 = document.getElementById("target0");
                var target1 = document.getElementById("target1");

                on_event(target0, 'pointercancel', function (event) {
                    if (phase == PhaseEnum.WaitingForCancel) {
                        expect_no_coalesced_events(event, 'pointercancel');
                        phase++;
                    }
                });
                eventList.forEach(function(eventName) {
                    on_event(target1, eventName, function (event) {
                        switch (phase) {
                          case PhaseEnum.WaitingForOver:
                            if (eventName == 'pointerover') {
                              expect_no_coalesced_events(event, eventName);
                              phase++;
                            }
                            break;
                          case PhaseEnum.WaitingForEnter:
                            if (eventName == 'pointerenter') {
                              expect_no_coalesced_events(event, eventName);
                              phase++;
                            }
                            break;
                          case PhaseEnum.WaitingForDown:
                            if (eventName == 'pointerdown') {
                              expect_no_coalesced_events(event, eventName);
                              phase++;
                              setTimeout(function(){
                                // This is just a way to block the main thread.
                                var current = new Date().getTime();
                                for (; new Date().getTime() - current < 500;);
                              }, 0);
                            }
                            break;
                          case PhaseEnum.WaitingForMove:
                            if (eventName == 'pointermove') {
                              var coalescedEvents = event.getCoalescedEvents();
                              test (function() {
                                assert_greater_than(event.getCoalescedEvents().length, 1, 'pointermove should have at least 2 coalesced events.');
                              }, expectedPointerType + ' pointermove should have >2 coalesced events as main thread is busy.');
                              test (function() {
                                for (var i=0; i<coalescedEvents.length; i++) {
                                  assert_equals(coalescedEvents[i].isTrusted, true, 'isTrusted flag should be true for coalesced events.');
                                  if (i > 0)
                                    assert_greater_than_equal(coalescedEvents[i].timeStamp, coalescedEvents[i-1].timeStamp, 'Time stamps of coalesced events must be ascending.');
                                }
                              }, expectedPointerType + ' pointermove coalesced events should all be marked as trusted.');
                              test (function() {
                                for (var i=1; i<coalescedEvents.length; i++)
                                  assert_greater_than_equal(coalescedEvents[i].timeStamp, coalescedEvents[i-1].timeStamp, 'Time stamps of coalesced events must be ascending.');
                              }, expectedPointerType + ' time stamps of coalesced events must be ascending.');
                              test (function() {
                                for (var i=0; i<coalescedEvents.length; i++) {
                                  assert_equals(coalescedEvents[i].bubbles, false, 'Bubbles attribute should be false for coalesced events.');
                                  assert_equals(coalescedEvents[i].cancelable, false, 'Cancelable attribute should be false for coalesced events.');
                                }
                              }, expectedPointerType + ' pointermove coalesced events should all bubbles and cancelable as false.');
                              phase++;
                            }
                            break;
                          case PhaseEnum.WaitingForUp:
                            if (eventName == 'pointerup') {
                              expect_no_coalesced_events(event, eventName);
                              phase++;
                            }
                            break;
                          case PhaseEnum.WaitingForOut:
                            if (eventName == 'pointerout') {
                              expect_no_coalesced_events(event, eventName);
                              phase++;
                            }
                            break;
                          case PhaseEnum.WaitingForLeave:
                            if (eventName == 'pointerleave') {
                              expect_no_coalesced_events(event, eventName);
                              phase++;
                              test_pointerEvent.done();
                            }
                            break;
                        }
                    });
                });
            }
        </script>
    </head>
    <body onload="run()">
        <h1>Pointer Events coalesced events count and properties</h1>
        <h2 id="pointerTypeDescription"></h2>
        <h4>
            Test Description: This test checks the coalesced events of all types of pointer events.
            <ol>
                 <li>Pointer down in the black square and drag inside the black square immediately</li>
                 <li>Release the pointer.</li>
                 <li>Pointer down in the purple square and drag inside the purple square immediately</li>
                 <li>Release the pointer and move out of the purple square</li>
            </ol>

            Test passes if the proper behavior of the events is observed.
        </h4>
        <div id="target0"></div>
        <div id="target1" class="touchActionNone"></div>
        <div id="complete-notice">
            <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
            <p>Refresh the page to run the tests again with a different pointer type.</p>
        </div>
    </body>
</html>

