-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
Copy pathwaiters.ts
133 lines (117 loc) · 3.27 KB
/
waiters.ts
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
/**
@module @ember/test
*/
const contexts: unknown[] = [];
const callbacks: Array<() => unknown> = [];
/**
This allows ember-testing to play nicely with other asynchronous
events, such as an application that is waiting for a CSS3
transition or an IndexDB transaction. The waiter runs periodically
after each async helper (i.e. `click`, `andThen`, `visit`, etc) has executed,
until the returning result is truthy. After the waiters finish, the next async helper
is executed and the process repeats.
For example:
```javascript
import { registerWaiter } from '@ember/test';
registerWaiter(function() {
return myPendingTransactions() === 0;
});
```
The `context` argument allows you to optionally specify the `this`
with which your callback will be invoked.
For example:
```javascript
import { registerWaiter } from '@ember/test';
registerWaiter(MyDB, MyDB.hasPendingTransactions);
```
@public
@for @ember/test
@static
@method registerWaiter
@param {Object} context (optional)
@param {Function} callback
@since 1.2.0
*/
export function registerWaiter<T>(context: T, callback: (this: T) => unknown): void;
export function registerWaiter(callback: (this: null) => unknown): void;
export function registerWaiter<T>(
// Formatting makes a pretty big difference in how readable this is.
// prettier-ignore
...args:
| [context: T, callback: (this: T) => unknown]
| [callback: (this: null) => unknown]
): void {
let checkedCallback: () => unknown;
let checkedContext: T | null;
if (args.length === 1) {
checkedContext = null;
checkedCallback = args[0];
} else {
checkedContext = args[0];
checkedCallback = args[1];
}
if (indexOf(checkedContext, checkedCallback) > -1) {
return;
}
contexts.push(checkedContext);
callbacks.push(checkedCallback);
}
/**
`unregisterWaiter` is used to unregister a callback that was
registered with `registerWaiter`.
@public
@for @ember/test
@static
@method unregisterWaiter
@param {Object} context (optional)
@param {Function} callback
@since 1.2.0
*/
export function unregisterWaiter(context: unknown, callback: unknown) {
if (!callbacks.length) {
return;
}
if (arguments.length === 1) {
callback = context;
context = null;
}
let i = indexOf(context, callback);
if (i === -1) {
return;
}
contexts.splice(i, 1);
callbacks.splice(i, 1);
}
/**
Iterates through each registered test waiter, and invokes
its callback. If any waiter returns false, this method will return
true indicating that the waiters have not settled yet.
This is generally used internally from the acceptance/integration test
infrastructure.
@public
@for @ember/test
@static
@method checkWaiters
*/
export function checkWaiters() {
if (!callbacks.length) {
return false;
}
for (let i = 0; i < callbacks.length; i++) {
let context = contexts[i];
let callback = callbacks[i];
// SAFETY: The loop ensures that this exists
if (!callback!.call(context)) {
return true;
}
}
return false;
}
function indexOf(context: unknown, callback: unknown) {
for (let i = 0; i < callbacks.length; i++) {
if (callbacks[i] === callback && contexts[i] === context) {
return i;
}
}
return -1;
}