chromium/third_party/blink/web_tests/fast/events/touch/multi-touch-partial-sequence.html

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../../resources/js-test.js"></script>
</head>
<body>
<p id="description"></p>
<div id="target" style="padding: 10px; background-color: blue;"></div>
<div id="console"></div>
<script>
description("Tests that events are received properly even when we never saw the touchstart for the first finger (eg. was skipped by cc touch hit testing) - crbug.com/363321");

var event;
var expectingStart = false;
var expectingEnd = false;

var target = document.getElementById('target');
var rect = target.getBoundingClientRect();
var targetX = rect.left + rect.width / 2;
var targetY = rect.top + rect.height / 2;

window.addEventListener('touchstart', function(e) {
    if (!expectingStart) {
      testFailed('Got unexpected touchstart event');
      return;
    }
    expectingStart = false;
    event = e;

    shouldBe('event.target', 'target');

    // Touch ID 0 is the one we never got a touchstart for, so it should
    // be targeted at the document.
    shouldBe('event.touches.length', '2');
    shouldBe('event.touches[0].identifier', '0');
    shouldBe('event.touches[0].pageX', '12');
    shouldBe('event.touches[0].pageY', '0');
    shouldBe('event.touches[0].target', 'document');

    // Touch ID 1 should be the new touch.
    shouldBe('event.touches[1].identifier', '1');
    shouldBe('event.touches[1].pageX', 'targetX');
    shouldBe('event.touches[1].pageY', 'targetY');
    shouldBe('event.touches[1].target', 'target');
    
    shouldBe('event.changedTouches.length', '1');
    shouldBe('event.changedTouches[0].identifier', '1');

    shouldBe('event.targetTouches.length', '1');
    shouldBe('event.targetTouches[0].identifier', '1');
});

window.addEventListener('touchmove', function(e) {
    testFailed('Got unexpected touchmove event');
});

window.addEventListener('touchend', function(e) {
    if (!expectingEnd) {
      testFailed('Got unexpected touchstart event');
      return;
    }
    expectingEnd = false;
    event = e;

    shouldBe('event.target', 'target');

    shouldBe('event.touches.length', '0');
    
    shouldBe('event.changedTouches.length', '1');
    shouldBe('event.changedTouches[0].identifier', '1');
    shouldBe('event.changedTouches[0].pageX', 'targetX');
    shouldBe('event.changedTouches[0].pageY', 'targetY');
    shouldBe('event.changedTouches[0].target', 'target');

    shouldBe('event.targetTouches.length', '0');
});

if (document.elementFromPoint(targetX, targetY) != target) {
    testFailed('Failed to hit expected target at ' + targetX + ',' + targetY);
} else if (!window.eventSender) {
    testFailed('This test requires eventSender');
} else {
    eventSender.clearTouchPoints();

    // First touch point is outside our target, but we never actually
    // get a touchstart event sent to the renderer for it.
    eventSender.addTouchPoint(10, 0);
    eventSender.updateTouchPoint(0, 12, 0);

    // Second point is on our target and we expect touchstart
    eventSender.addTouchPoint(targetX, targetY);
    debug('Sending touchstart event.');
    expectingStart = true;
    eventSender.touchStart();
    if (expectingStart)
      testFailed("Didn't receive expected touchstart event");
    debug('');

    // Make sure we don't get any events (or crash) if we receive a move or
    // end for just the first touch point.
    debug('Sending touchmove and touchend for unrelated touch point.');
    eventSender.updateTouchPoint(0, 13, 0);
    eventSender.touchMove();
    eventSender.releaseTouchPoint(0);
    eventSender.touchEnd();
    debug('');

    // If the 2nd touch point lifts, we get an event showing just that change.
    debug('Sending touchend.');
    eventSender.releaseTouchPoint(0);
    expectingEnd = true;
    eventSender.touchEnd();
    if (expectingEnd)
      testFailed("Didn't receive expected touchend event");
    debug('');
}
</script>
</body>
</html>