chromium/third_party/blink/web_tests/media/video-source-moved.html

<!DOCTYPE html>
<title>Test to make sure a "source" moved after the media element begins processing is handled correctly.</title>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="media-file.js"></script>
<script>
for(var i = 0; i < 7; i++) {
    async_test(function(t) {
        var testInfo = [
            { func : moveToEnd, errorCount : 0, moved : null, elementToMove: function(video, current) {
                // Moving previous "source" element to end of list, it should be processed again.
                return video.removeChild(current.previousSibling);
            } },
            { func : moveToEnd, errorCount : 0, moved : null, elementToMove: function(video, current) {
                // Moving current "source" element, it should be processed again.
                return video.removeChild(current);
            } },
            { func : moveToEnd, errorCount : 0, moved : null, elementToMove: function(video, current) {
                // Moving next "source" element, it should be processed again.
                return video.removeChild(current.nextSibling);
            } },
            { func : moveEarlier, errorCount : 0, moved : null, elementToMove: function(video, current) {
                // Moving current "source" element to beginning of list, it should not be processed again.
                return video.removeChild(current);
            } },
            { func : moveEarlier, errorCount : 0, moved : null, elementToMove: function(video, current) {
                // Moving next "source" element to beginning of list, it should never processed.
                return video.removeChild(current.nextSibling);
            } },
            { func : moveEarlier, errorCount : 0, moved : null, elementToMove: function(video, current) {
                // span inserted after current "source" element before it is removed, processing should proceed normally.
                var span = document.createElement("span")
                span.appendChild(document.createTextNode("Your browser doesn't support HTML5 video!"));
                video.insertBefore(span, current.nextSibling);
                return video.removeChild(current);
            } },
            { func : moveEarlier, errorCount : 0, moved : null, elementToMove: function(video, current) {
                // span inserted after next "source" element before it is removed, processing should proceed normally.
                var span = document.createElement("span")
                span.appendChild(document.createTextNode("Your browser doesn't support HTML5 video!"));
                video.insertBefore(span, current.nextSibling.nextSibling);
                return video.removeChild(current.nextSibling);
            } }
        ];

        var test = testInfo[i];
        var video = document.createElement("video");

        // Add a bunch of source elements with bogus urls because we want to rearrange
        // elements after the media engine begins processing sources, and we can't predict
        // the delay between when the media element fires an "error" event and our handler
        // is called, but we need to guarantee that there are <source> elements that
        // haven't been processed when we run the test.
        for (var index = 1; index <= 10; index++)
            addSource(index);

        function addSource(index) {
            var source = document.createElement("source");
            source.src = index + "-" + Date.now() + ".ogv";
            source.type = mimeTypeForExtension(source.src.split(".").pop());
            video.appendChild(source);

            source.onerror = t.step_func(function(event) {
                test.func(event);
            });
        }

        function findCurrentSourceElement() {
            var sources = video.childNodes;
            var currentSrc = video.currentSrc;
            var index;
            for (index = 0; index < sources.length; ++index) {
                if (sources[index].src == currentSrc)
                    break;
            }

            assert_less_than(index, sources.length, currentSrc + " not found in <source> list");
            return sources[index];
        }

        function moveEarlier(event) {
            switch (++test.errorCount) {
            case 1:
                // Do nothing on the first error event
                break;

            case 2:
                var current = findCurrentSourceElement();
                test.moved = test.elementToMove(video, current);
                assert_not_equals(test.moved, null);
                video.insertBefore(test.moved, video.firstChild);
                break;

            default:
                // We should never get an error for the element we moved.
                assert_not_equals(event.target, test.moved);
                if (event.target.nextSibling == null)
                    t.done();
                break;
            }
        }

        function moveToEnd(event) {
            switch (++test.errorCount) {
            case 1:
                // Do nothing on the first error event
                break;

            case 2:
                var current = findCurrentSourceElement();
                test.moved = test.elementToMove(video, current);
                assert_not_equals(test.moved, null);
                video.appendChild(test.moved);
                break;

            default:
                assert_true(event.target == test.moved || event.target.nextSibling != null);
                if (event.target == test.moved)
                    t.done();
                break;
            }
        }
    });
}
</script>