forked from DevExpress/testcafe
/
child.js
115 lines (97 loc) · 3.9 KB
/
child.js
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
import {
Promise,
eventSandbox,
nativeMethods,
} from '../../deps/hammerhead';
import {
domUtils,
delay,
waitFor,
positionUtils,
} from '../../deps/testcafe-core';
import {
CurrentIframeIsNotLoadedError,
CurrentIframeNotFoundError,
CurrentIframeIsInvisibleError,
} from '../../../../shared/errors';
import sendMessageToDriver from '../send-message-to-driver';
import { ExecuteCommandMessage, TYPE as MESSAGE_TYPE } from '../messages';
import DriverStatus from '../../status';
import {
CHECK_IFRAME_EXISTENCE_INTERVAL,
CHECK_IFRAME_VISIBLE_INTERVAL,
WAIT_IFRAME_RESPONSE_DELAY,
} from '../timeouts';
import sendConfirmationMessage from '../send-confirmation-message';
export default class ChildIframeDriverLink {
constructor (driverWindow, driverId) {
this.driverWindow = driverWindow;
this.driverIframe = domUtils.findIframeByWindow(driverWindow);
this.driverId = driverId;
this.iframeAvailabilityTimeout = 0;
}
set availabilityTimeout (val) {
this.iframeAvailabilityTimeout = val;
}
_ensureIframe () {
if (!domUtils.isElementInDocument(this.driverIframe))
return Promise.reject(new CurrentIframeNotFoundError());
return waitFor(() => positionUtils.isIframeVisible(this.driverIframe) ? this.driverIframe : null,
CHECK_IFRAME_VISIBLE_INTERVAL, this.iframeAvailabilityTimeout)
.catch(() => {
throw new CurrentIframeIsInvisibleError();
});
}
_waitForIframeRemovedOrHidden () {
// NOTE: If an iframe was removed or became hidden while a
// command was being executed, we consider this command finished.
return new Promise(resolve => {
this.checkIframeInterval = nativeMethods.setInterval.call(window,
() => {
this._ensureIframe()
.catch(() => {
// NOTE: wait for possible delayed iframe message
return delay(WAIT_IFRAME_RESPONSE_DELAY)
.then(() => resolve(new DriverStatus({ isCommandResult: true })));
});
}, CHECK_IFRAME_EXISTENCE_INTERVAL);
});
}
_waitForCommandResult () {
let onMessage = null;
const waitForResultMessage = () => new Promise(resolve => {
onMessage = e => {
if (e.message.type === MESSAGE_TYPE.commandExecuted)
resolve(e.message.driverStatus);
};
eventSandbox.message.on(eventSandbox.message.SERVICE_MSG_RECEIVED_EVENT, onMessage);
});
return Promise.race([this._waitForIframeRemovedOrHidden(), waitForResultMessage()])
.then(status => {
eventSandbox.message.off(eventSandbox.message.SERVICE_MSG_RECEIVED_EVENT, onMessage);
nativeMethods.clearInterval.call(window, this.checkIframeInterval);
return status;
});
}
sendConfirmationMessage (requestMsgId) {
sendConfirmationMessage({
requestMsgId,
result: { id: this.driverId },
window: this.driverWindow,
});
}
executeCommand (command, testSpeed) {
// NOTE: We should check if the iframe is visible and exists before executing the next
// command, because the iframe might be hidden or removed since the previous command.
return this
._ensureIframe()
.then(() => {
const msg = new ExecuteCommandMessage(command, testSpeed);
return Promise.all([
sendMessageToDriver(msg, this.driverWindow, this.iframeAvailabilityTimeout, CurrentIframeIsNotLoadedError),
this._waitForCommandResult(),
]);
})
.then(result => result[1]);
}
}