summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/popovers/resources/popover-top-layer-nesting.js
blob: ace10b3f7bc47f32c04ad1435e1d2eb28f3ec3a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
function createTopLayerElement(t,topLayerType) {
  let element, show, showing;
  switch (topLayerType) {
    case 'dialog':
      element = document.createElement('dialog');
      show = () => element.showModal();
      showing = () => element.matches(':modal');
      break;
    case 'fullscreen':
      element = document.createElement('div');
      show = async (topmostElement) => {
        // Be sure to add user activation to the topmost visible target:
        await blessTopLayer(topmostElement);
        await element.requestFullscreen();
      };
      showing = () => document.fullscreenElement === element;
      break;
    default:
      assert_unreached('Invalid top layer type');
  }
  t.add_cleanup(() => element.remove());
  return {element,show,showing};
}
function runTopLayerTests(testCases, testAnchorAttribute) {
  testAnchorAttribute = testAnchorAttribute || false;
  testCases.forEach(test => {
    const description = test.firstChild.data.trim();
    assert_equals(test.querySelectorAll('.target').length,1,'There should be exactly one target');
    const target = test.querySelector('.target');
    assert_true(!!target,'Invalid test case');
    const popovers = Array.from(test.querySelectorAll('[popover]'));
    assert_true(popovers.length > 0,'No popovers found');
    ['dialog','fullscreen'].forEach(topLayerType => {
      promise_test(async t => {
        const {element,show,showing} = createTopLayerElement(t,topLayerType);
        target.appendChild(element);

        // Show the popovers.
        t.add_cleanup(() => popovers.forEach(popover => popover.hidePopover()));
        popovers.forEach(popover => popover.showPopover());
        popovers.forEach(popover => assert_true(popover.matches(':popover-open'),'All popovers should be open'));

        // Activate the top layer element.
        await show(popovers[popovers.length-1]);
        assert_true(showing());
        popovers.forEach(popover => assert_equals(popover.matches(':popover-open'),popover.dataset.stayOpen==='true','Incorrect behavior'));

        // Add another popover within the top layer element and make sure entire stack stays open.
        const newPopover = document.createElement('div');
        t.add_cleanup(() => newPopover.remove());
        newPopover.popover = popoverHintSupported() ? 'hint' : 'auto';
        element.appendChild(newPopover);
        popovers.forEach(popover => assert_equals(popover.matches(':popover-open'),popover.dataset.stayOpen==='true','Adding another popover shouldn\'t change anything'));
        assert_true(showing(),'top layer element should still be top layer');
        newPopover.showPopover();
        assert_true(newPopover.matches(':popover-open'));
        popovers.forEach(popover => assert_equals(popover.matches(':popover-open'),popover.dataset.stayOpen==='true','Showing the popover shouldn\'t change anything'));
        assert_true(showing(),'top layer element should still be top layer');
      },`${description} with ${topLayerType}`);

      promise_test(async t => {
        const {element,show,showing} = createTopLayerElement(t,topLayerType);
        element.popover = popoverHintSupported() ? 'hint' : 'auto';
        target.appendChild(element);

        // Show the popovers.
        t.add_cleanup(() => popovers.forEach(popover => popover.hidePopover()));
        popovers.forEach(popover => popover.showPopover());
        popovers.forEach(popover => assert_true(popover.matches(':popover-open'),'All popovers should be open'));
        const targetWasOpenPopover = target.matches(':popover-open');

        // Show the top layer element as a popover first.
        element.showPopover();
        assert_true(element.matches(':popover-open'),'element should be open as a popover');
        assert_equals(target.matches(':popover-open'),targetWasOpenPopover,'target shouldn\'t change popover state');

        try {
          await show(element);
          assert_unreached('It is an error to activate a top layer element that is already a showing popover');
        } catch (e) {
          // We expect an InvalidStateError for dialogs, and a TypeError for fullscreens.
          // Anything else should fall through to the test harness.
          if (e.name !== 'InvalidStateError' && e.name !== 'TypeError') {
            throw e;
          }
        }
      },`${description} with ${topLayerType}, top layer element *is* a popover`);

      if (testAnchorAttribute) {
        promise_test(async t => {
          const {element,show,showing} = createTopLayerElement(t,topLayerType);
          element.anchorElement = target;
          document.body.appendChild(element);

          // Show the popovers.
          t.add_cleanup(() => popovers.forEach(popover => popover.hidePopover()));
          popovers.forEach(popover => popover.showPopover());
          popovers.forEach(popover => assert_true(popover.matches(':popover-open'),'All popovers should be open'));

          // Activate the top layer element.
          await show(popovers[popovers.length-1]);
          assert_true(showing());
          popovers.forEach(popover => assert_equals(popover.matches(':popover-open'),popover.dataset.stayOpen==='true','Incorrect behavior'));
        },`${description} with ${topLayerType}, anchor attribute`);
      }
    });
  });
}