summaryrefslogtreecommitdiffstats
path: root/dom/promise/tests/file_promise_argument_tests.js
blob: 2a3b4e78c944b392c2c5e2eddcaf5031f80fa8a9 (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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * This file is meant to provide common infrastructure for several consumers.
 * The consumer is expected to define the following things:
 *
 * 1) An verifyPromiseGlobal function which does whatever test the consumer
 *    wants.
 * 2) An isXrayArgumentTest global boolean, because some of these tests act
 *    differenly based on that boolean.
 * 3) A function named getPromise.  This function is given a global object and a
 *    single argument to use for getting the promise.  The getPromise function
 *    is expected to trigger the canonical Promise.resolve for the given global
 *    with the given argument in some way that depends on the test, and return
 *    the result.
 * 4) A subframe (frames[0]) which can be used as a second global for creating
 *    promises.
 */

/* global verifyPromiseGlobal, getPromise, isXrayArgumentTest */

var label = "parent";

function passBasicPromise() {
  var p1 = Promise.resolve();
  verifyPromiseGlobal(p1, window, "Promise.resolve return value 1");
  var p2 = getPromise(window, p1);
  is(p1, p2, "Basic promise should just pass on through");
  return p2;
}

function passPrimitive(global) {
  var p = getPromise(global, 5);
  verifyPromiseGlobal(p, global, "Promise wrapping primitive");
  return p.then(function (arg) {
    is(arg, 5, "Should have the arg we passed in");
  });
}

function passThenable(global) {
  var called = false;
  var thenable = {
    then(f) {
      called = true;
      f(7);
    },
  };
  var p = getPromise(global, thenable);
  verifyPromiseGlobal(p, global, "Promise wrapping thenable");
  return p.then(function (arg) {
    ok(called, "Thenable should have been called");
    is(arg, 7, "Should have the arg our thenable passed in");
  });
}

function passWrongPromiseWithMatchingConstructor() {
  var p1 = Promise.resolve();
  verifyPromiseGlobal(p1, window, "Promise.resolve() return value 2");
  p1.constructor = frames[0].Promise;
  var p2 = getPromise(frames[0], p1);
  // The behavior here will depend on whether we're touching frames[0] via Xrays
  // or not.  If we are not, the current compartment while getting our promise
  // will be that of frames[0].  If we are, it will be our window's compartment.
  if (isXrayArgumentTest) {
    isnot(
      p1,
      p2,
      "Should have wrapped the Promise in a new promise, because its constructor is not matching the current-compartment Promise constructor"
    );
    verifyPromiseGlobal(
      p2,
      window,
      "Promise wrapping xrayed promise with therefore non-matching constructor"
    );
  } else {
    is(
      p1,
      p2,
      "Should have left the Promise alone because its constructor matched"
    );
  }
  return p2;
}

function passCorrectPromiseWithMismatchedConstructor() {
  var p1 = Promise.resolve(9);
  verifyPromiseGlobal(p1, window, "Promise.resolve() return value 3");
  p1.constructor = frames[0].Promise;
  var p2 = getPromise(window, p1);
  isnot(
    p1,
    p2,
    "Should have wrapped promise in a new promise, since its .constructor was wrong"
  );
  verifyPromiseGlobal(
    p2,
    window,
    "Promise wrapping passed-in promise with mismatched constructor"
  );
  return p2.then(function (arg) {
    is(arg, 9, "Should have propagated along our resolution value");
  });
}

function passPromiseToOtherGlobal() {
  var p1 = Promise.resolve();
  verifyPromiseGlobal(p1, window, "Promise.resolve() return value 4");
  var p2 = getPromise(frames[0], p1);
  // The behavior here will depend on whether we're touching frames[0] via Xrays
  // or not.  If we are not, the current compartment while getting our promise
  // will be that of frames[0].  If we are, it will be our window's compartment.
  if (isXrayArgumentTest) {
    is(
      p1,
      p2,
      "Should have left the Promise alone, because its constructor matches the current compartment's constructor"
    );
  } else {
    isnot(
      p1,
      p2,
      "Should have wrapped promise in a promise from the other global"
    );
    verifyPromiseGlobal(
      p2,
      frames[0],
      "Promise wrapping passed-in basic promise"
    );
  }
  return p2;
}

function passPromiseSubclass() {
  class PromiseSubclass extends Promise {
    constructor(func) {
      super(func);
    }
  }

  var p1 = PromiseSubclass.resolve(11);
  verifyPromiseGlobal(p1, window, "PromiseSubclass.resolve() return value");
  var p2 = getPromise(window, p1);
  isnot(p1, p2, "Should have wrapped promise subclass in a new promise");
  verifyPromiseGlobal(
    p2,
    window,
    "Promise wrapping passed-in promise subclass"
  );
  return p2.then(function (arg) {
    is(
      arg,
      11,
      "Should have propagated along our resolution value from subclass"
    );
  });
}

function runPromiseArgumentTests(finishFunc) {
  Promise.resolve()
    .then(passBasicPromise)
    .then(passPrimitive.bind(undefined, window))
    .then(passPrimitive.bind(undefined, frames[0]))
    .then(passThenable.bind(undefined, window))
    .then(passThenable.bind(undefined, frames[0]))
    .then(passWrongPromiseWithMatchingConstructor)
    .then(passCorrectPromiseWithMismatchedConstructor)
    .then(passPromiseToOtherGlobal)
    .then(passPromiseSubclass)
    .then(finishFunc)
    .catch(function (e) {
      ok(
        false,
        `Exception thrown: ${e}@${location.pathname}:${e.lineNumber}:${e.columnNumber}`
      );
      finishFunc();
    });
}