<!DOCTYPE html>
<script src="../../resources/gc.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<body>
<div id='breadBox'>
<div id='bread'></div>
</div>
<div id='toaster'></div>
<div id='fruitBowl'></div>
<script>
'use strict';
(() => {
if (!window.internals) {
// Requires observeGC
return;
}
promise_test((t) => {
// We may not want to land this test, including for now as an example of how
// this interface behaves in a way that is independent of our feature.
var trash_observation = null;
(() => {
// Construct a node which we do not attach or insert in any way.
// This should DEFINITELY be collected.
const trash = document.createElement("div");
trash_observation = internals.observeGC(trash);
})();
return asyncGC().then(() => {
assert_true(trash_observation.wasCollected,
"|trash| really should have been collected");
});
}, 'Testing collection works as expected');
promise_test((t) => {
var toast_observation = null;
(() => {
const toast = document.createElement("div");
// Set |toast| as active descendant of |toaster|.
toaster.ariaActiveDescendantElement = toast;
// Since |toast| is not yet inserted in the document this relationship
// is not observable.
assert_equals(toaster.ariaActiveDescendantElement, null);
// Insert |toast| into the document, this should make the relationship
// visible AND prevent GC.
breadBox.appendChild(toast);
assert_equals(toaster.ariaActiveDescendantElement, toast);
// Since there is another reference to |toast| from the breadBox it should
// not be a candidate for GC.
toast_observation = internals.observeGC(toast);
})();
return asyncGC().then(() => {
assert_false(toast_observation.wasCollected);
});
}, 'Reference to element in a valid scope should not be collectable by GC');
promise_test((t) => {
var toast_observation = null;
(() => {
const toast = document.createElement("div");
// Set |toast| as active descendant of |toaster|.
toaster.ariaActiveDescendantElement = toast;
// Since |toast| is not yet inserted in the document this relationship
// is not observable.
assert_equals(toaster.ariaActiveDescendantElement, null);
// Since there are no other references to |toast| it should be a candidate
// for GC.
toast_observation = internals.observeGC(toast);
})();
return asyncGC().then(() => {
assert_true(toast_observation.wasCollected,
'Invalid ER should not prevent GC');
});
}, 'Reference to element in an invalid scope should not prevent GC');
promise_test((t) => {
var bread_observation = null;
(() => {
const bread = document.getElementById("bread");
// Set |bread| as active descendant of |toaster| and verify this is
// observable as it is a valid scope.
toaster.ariaActiveDescendantElement = bread;
assert_equals(toaster.ariaActiveDescendantElement, bread);
// Now remove |bread| from the document, this should make |bread| a
// candidate for GC.
bread.remove();
assert_equals(toaster.ariaActiveDescendantElement, null);
// Since there are no other references to |toast| it should be a candidate
// for GC.
bread_observation = internals.observeGC(bread);
})();
return asyncGC().then(() => {
assert_true(bread_observation.wasCollected,
'Invalid ER should not prevent GC');
});
}, 'Reference being previously valid but now invalid should not prevent GC');
promise_test((t) => {
var apple_observation = null;
var banana_observation = null;
var pear_observation = null;
(() => {
const apple = document.createElement("div");
apple.setAttribute("id", "apple");
const banana = document.createElement("div");
banana.setAttribute("id", "banana");
const pear = document.createElement("div");
pear.setAttribute("id", "pear");
// Insert all 3 pieces of fruit into fruitBowl.
fruitBowl.appendChild(apple);
fruitBowl.appendChild(banana);
fruitBowl.appendChild(pear);
// Set describedBy based on the order of my fruit preferences.
fruitBowl.ariaDescribedByElements = [pear, apple, banana];
assert_array_equals(fruitBowl.ariaDescribedByElements, [pear, apple, banana]);
assert_equals(fruitBowl.getAttribute("aria-describedby"), "");
// Someone else comes along and eats the apple.
apple.remove();
assert_array_equals(fruitBowl.ariaDescribedByElements, [pear, banana]);
// only |apple| should be collectable by the GC.
apple_observation = internals.observeGC(apple);
banana_observation = internals.observeGC(banana);
pear_observation = internals.observeGC(pear);
})();
return asyncGC().then(() => {
assert_true(apple_observation.wasCollected,
'Invalid ER should not prevent GC');
assert_false(banana_observation.wasCollected,
'Valid ER should prevent GC');
assert_false(pear_observation.wasCollected,
'Valid ER should prevent GC');
});
}, 'Element reflection arrayAttributes garbage collection test');
})();
</script>