summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/browser/browser_canvasframe_helper_05.js
blob: b542b14221110931bb8cbd5f7564a951e24214ba (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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

// Test some edge cases of the CanvasFrameAnonymousContentHelper event handling
// mechanism.

const TEST_URL =
  "data:text/html;charset=utf-8,CanvasFrameAnonymousContentHelper test";

add_task(async function () {
  const tab = await addTab(TEST_URL);
  await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
    const { require } = ChromeUtils.importESModule(
      "resource://devtools/shared/loader/Loader.sys.mjs"
    );
    const {
      HighlighterEnvironment,
    } = require("resource://devtools/server/actors/highlighters.js");
    const {
      CanvasFrameAnonymousContentHelper,
    } = require("resource://devtools/server/actors/highlighters/utils/markup.js");
    const doc = content.document;

    const nodeBuilder = () => {
      const root = doc.createElement("div");

      const parent = doc.createElement("div");
      parent.style =
        "pointer-events:auto;width:300px;height:300px;background:yellow;";
      parent.id = "parent-element";
      root.appendChild(parent);

      const child = doc.createElement("div");
      child.style =
        "pointer-events:auto;width:200px;height:200px;background:red;";
      child.id = "child-element";
      parent.appendChild(child);

      return root;
    };

    info("Building the helper");
    const env = new HighlighterEnvironment();
    env.initFromWindow(doc.defaultView);
    const helper = new CanvasFrameAnonymousContentHelper(env, nodeBuilder);
    await helper.initialize();

    info("Getting the parent and child elements");
    const parentEl = helper.getElement("parent-element");
    const childEl = helper.getElement("child-element");

    info("Adding an event listener on both elements");
    let mouseDownHandled = [];
    function onMouseDown(e, id) {
      mouseDownHandled.push(id);
    }
    parentEl.addEventListener("mousedown", onMouseDown);
    childEl.addEventListener("mousedown", onMouseDown);

    function once(target, event) {
      return new Promise(done => {
        target.addEventListener(event, done, { once: true });
      });
    }

    info("Synthesizing an event on the child element");
    let onDocMouseDown = once(doc, "mousedown");
    synthesizeMouseDown(100, 100, doc.defaultView);
    await onDocMouseDown;

    is(mouseDownHandled.length, 2, "The mousedown event was handled twice");
    is(
      mouseDownHandled[0],
      "child-element",
      "The mousedown event was handled on the child element"
    );
    is(
      mouseDownHandled[1],
      "parent-element",
      "The mousedown event was handled on the parent element"
    );

    info("Synthesizing an event on the parent, outside of the child element");
    mouseDownHandled = [];
    onDocMouseDown = once(doc, "mousedown");
    synthesizeMouseDown(250, 250, doc.defaultView);
    await onDocMouseDown;

    is(mouseDownHandled.length, 1, "The mousedown event was handled only once");
    is(
      mouseDownHandled[0],
      "parent-element",
      "The mousedown event was handled on the parent element"
    );

    info("Removing the event listener");
    parentEl.removeEventListener("mousedown", onMouseDown);
    childEl.removeEventListener("mousedown", onMouseDown);

    info("Adding an event listener on the parent element only");
    mouseDownHandled = [];
    parentEl.addEventListener("mousedown", onMouseDown);

    info("Synthesizing an event on the child element");
    onDocMouseDown = once(doc, "mousedown");
    synthesizeMouseDown(100, 100, doc.defaultView);
    await onDocMouseDown;

    is(mouseDownHandled.length, 1, "The mousedown event was handled once");
    is(
      mouseDownHandled[0],
      "parent-element",
      "The mousedown event did bubble to the parent element"
    );

    info("Removing the parent listener");
    parentEl.removeEventListener("mousedown", onMouseDown);

    env.destroy();
    helper.destroy();

    function synthesizeMouseDown(x, y, win) {
      // We need to make sure the inserted anonymous content can be targeted by the
      // event right after having been inserted, and so we need to force a sync
      // reflow.
      win.document.documentElement.offsetWidth;
      EventUtils.synthesizeMouseAtPoint(x, y, { type: "mousedown" }, win);
    }
  });

  gBrowser.removeCurrentTab();
});