summaryrefslogtreecommitdiffstats
path: root/toolkit/components/translations/tests/browser/translations-test.mjs
blob: 3ff107a6990a3a369165e0c029648c1f3f28ebf2 (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
135
136
137
138
139
140
141
142
143
144
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

// eslint-disable-next-line no-unused-vars
let ok;
let is;
// eslint-disable-next-line no-unused-vars
let isnot;
let ContentTaskUtils;

/** @type {{ document: Document, window: Window }} */
let content;

/**
 * Inject the global variables from the test scope into the ES module scope.
 */
export function setup(config) {
  // When a function is provided to `ContentTask.spawn`, that function is provided the
  // Assert library through variable capture. In this case, this code is an ESM module,
  // and does not have access to that scope. To work around this issue, pass any any
  // relevant variables to that can be bound to the module scope.
  //
  // See: https://searchfox.org/mozilla-central/rev/cdddec7fd690700efa4d6b48532cf70155e0386b/testing/mochitest/BrowserTestUtils/content/content-task.js#78
  const { Assert } = config;
  ok = Assert.ok.bind(Assert);
  is = Assert.equal.bind(Assert);
  isnot = Assert.notEqual.bind(Assert);

  ContentTaskUtils = config.ContentTaskUtils;
  content = config.content;
}

export function getSelectors() {
  return {
    getH1() {
      return content.document.querySelector("h1");
    },
    getHeader() {
      return content.document.querySelector("header");
    },
    getLastParagraph() {
      return content.document.querySelector("p:last-of-type");
    },
    getFrenchSection() {
      return content.document.getElementById("french-section");
    },
    getEnglishSection() {
      return content.document.getElementById("english-section");
    },
    getSpanishSection() {
      return content.document.getElementById("spanish-section");
    },
    getFrenchSentence() {
      return content.document.getElementById("french-sentence");
    },
    getEnglishSentence() {
      return content.document.getElementById("english-sentence");
    },
    getSpanishSentence() {
      return content.document.getElementById("spanish-sentence");
    },
    getEnglishHyperlink() {
      return content.document.getElementById("english-hyperlink");
    },
    getFrenchHyperlink() {
      return content.document.getElementById("french-hyperlink");
    },
    getSpanishHyperlink() {
      return content.document.getElementById("spanish-hyperlink");
    },
  };
}

/**
 * Provide longer defaults for the waitForCondition.
 *
 * @param {Function} callback
 * @param {string} message
 */
function waitForCondition(callback, message) {
  const interval = 100;
  // Use 4 times the defaults to guard against intermittents. Many of the tests rely on
  // communication between the parent and child process, which is inherently async.
  const maxTries = 50 * 4;
  return ContentTaskUtils.waitForCondition(
    callback,
    message,
    interval,
    maxTries
  );
}

/**
 * Asserts that a page was translated with a specific result.
 *
 * @param {string} message The assertion message.
 * @param {Function} getNode A function to get the node.
 * @param {string} translation The translated message.
 */
export async function assertTranslationResult(message, getNode, translation) {
  try {
    await waitForCondition(
      () => translation === getNode()?.innerText,
      `Waiting for: "${translation}"`
    );
  } catch (error) {
    // The result wasn't found, but the assertion below will report the error.
    console.error(error);
  }

  is(translation, getNode()?.innerText, message);
}

/**
 * Simulates right-clicking an element with the mouse.
 *
 * @param {element} element - The element to right-click.
 */
export function rightClickContentElement(element) {
  return new Promise(resolve => {
    element.addEventListener(
      "contextmenu",
      function () {
        resolve();
      },
      { once: true }
    );

    const EventUtils = ContentTaskUtils.getEventUtils(content);
    EventUtils.sendMouseEvent({ type: "contextmenu" }, element, content.window);
  });
}

/**
 * Selects all the content within a specified element.
 *
 * @param {Element} element - The element containing the content to be selected.
 * @returns {string} - The text content of the selection.
 */
export function selectContentElement(element) {
  content.focus();
  content.getSelection().selectAllChildren(element);
  return element.textContent;
}