Skip to content

Commit df9c497

Browse files
authored
Multiple windows support (#2988)
* [wip] preparations for multiple windows * multiple windows
1 parent ae88ef6 commit df9c497

File tree

5 files changed

+23
-15
lines changed

5 files changed

+23
-15
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "testcafe-hammerhead",
33
"description": "A powerful web-proxy used as a core for the TestCafe testing framework (https://github.com/DevExpress/testcafe).",
4-
"version": "31.6.4",
4+
"version": "31.7.0",
55
"homepage": "https://github.com/DevExpress/testcafe-hammerhead",
66
"bugs": {
77
"url": "https://github.com/DevExpress/testcafe-hammerhead/issues"

src/client/sandbox/child-window/index.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import getTopOpenerWindow from '../../utils/get-top-opener-window';
1616
import nextTick from '../../utils/next-tick';
1717
import { version, isSafari } from '../../utils/browser';
1818
import getCorrectedTargetForSinglePageMode from '../../utils/get-corrected-target-for-single-page-mode';
19-
19+
import isTargetBlank from '../../../utils/is-target-blank';
2020

2121
const DEFAULT_WINDOW_PARAMETERS = 'width=500px, height=500px';
2222
const STORE_CHILD_WINDOW_CMD = 'hammerhead|command|store-child-window';
@@ -48,18 +48,18 @@ export default class ChildWindowSandbox extends SandboxBase {
4848
target = target.toLowerCase();
4949

5050
if (isKeywordTarget(target))
51-
return target === '_blank';
51+
return isTargetBlank(target);
5252

5353
return !windowsStorage.findByName(target);
5454
}
5555

56-
private _openUrlInNewWindow (url: string, windowName?: string, windowParams?: string, window?: Window): OpenedWindowInfo | null {
56+
private _openUrlInNewWindow (url: string, windowName?: string, windowParams?: string, window?: Window, form?: HTMLFormElement): OpenedWindowInfo | null {
5757
const windowId = getRandomInt16Value().toString();
5858

5959
windowParams = windowParams || DEFAULT_WINDOW_PARAMETERS;
6060
windowName = windowName || windowId;
6161

62-
const newPageUrl = settings.get().nativeAutomation ? url : urlUtils.getPageProxyUrl(url, windowId);
62+
const newPageUrl = urlUtils.getPageProxyUrl(url, windowId, settings.get().nativeAutomation);
6363
const targetWindow = window || this.window;
6464
const beforeWindowOpenedEventArgs = { isPrevented: false };
6565

@@ -68,11 +68,12 @@ export default class ChildWindowSandbox extends SandboxBase {
6868
if (beforeWindowOpenedEventArgs.isPrevented)
6969
return null;
7070

71-
const openedWindow = nativeMethods.windowOpen.call(targetWindow, newPageUrl, windowName, windowParams);
71+
const startPageUrl = settings.get().nativeAutomation ? SPECIAL_BLANK_PAGE : newPageUrl;
72+
const openedWindow = nativeMethods.windowOpen.call(targetWindow, startPageUrl, windowName, windowParams);
7273

7374
this._tryToStoreChildWindow(openedWindow, getTopOpenerWindow());
7475

75-
this.emit(this.WINDOW_OPENED_EVENT, { windowId, window: openedWindow });
76+
this.emit(this.WINDOW_OPENED_EVENT, { windowId, window: openedWindow, windowName, pageUrl: newPageUrl, form });
7677

7778
return { windowId, wnd: openedWindow };
7879
}
@@ -160,7 +161,7 @@ export default class ChildWindowSandbox extends SandboxBase {
160161
const [url, target, parameters] = args;
161162

162163
if (settings.get().allowMultipleWindows && ChildWindowSandbox._shouldOpenInNewWindow(target, DefaultTarget.windowOpen)) {
163-
const openedWindowInfo = this._openUrlInNewWindow(url, target, parameters, window);
164+
const openedWindowInfo = this._openUrlInNewWindow(url, isTargetBlank(target) ? void 0 : target, parameters, window);
164165

165166
return openedWindowInfo?.wnd;
166167
}
@@ -204,18 +205,22 @@ export default class ChildWindowSandbox extends SandboxBase {
204205
!ChildWindowSandbox._shouldOpenInNewWindowOnElementAction(form, DefaultTarget.form))
205206
return;
206207

207-
const aboutBlankUrl = urlUtils.getProxyUrl(SPECIAL_BLANK_PAGE);
208-
const openedInfo = this._openUrlInNewWindow(aboutBlankUrl);
208+
const isNativeAutomation = settings.get().nativeAutomation;
209+
const aboutBlankUrl = urlUtils.getProxyUrl(SPECIAL_BLANK_PAGE, void 0, isNativeAutomation);
210+
const openedInfo = this._openUrlInNewWindow(aboutBlankUrl, void 0, void 0, void 0, form);
209211

210212
if (!openedInfo)
211213
return;
212214

213215
const formAction = nativeMethods.formActionGetter.call(form);
214-
const newWindowUrl = urlUtils.getPageProxyUrl(formAction, openedInfo.windowId);
216+
const newWindowUrl = urlUtils.getPageProxyUrl(formAction, openedInfo.windowId, isNativeAutomation);
215217

216218
nativeMethods.formActionSetter.call(form, newWindowUrl);
217219
nativeMethods.formTargetSetter.call(form, openedInfo.windowId);
218220

221+
if (isNativeAutomation)
222+
e.preventDefault();
223+
219224
// TODO: On hammerhead start we need to clean up the window.name
220225
// It's necessary for form submit.
221226
// Also we need clean up the form target to the original value.

src/client/utils/url.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ export function overrideGetCrossDomainIframeProxyUrl (func: typeof getCrossDomai
209209
getCrossDomainIframeProxyUrl = func;
210210
}
211211

212-
export function getPageProxyUrl (url: string, windowId: string): string {
212+
export function getPageProxyUrl (url: string, windowId: string, nativeAutomation?: boolean): string {
213213
const parsedProxyUrl = parseProxyUrl(url);
214214
let resourceType = null;
215215

@@ -228,7 +228,7 @@ export function getPageProxyUrl (url: string, windowId: string): string {
228228
const isCrossDomainUrl = !destLocation.sameOriginCheck(destLocation.getLocation(), url);
229229
const proxyPort = isCrossDomainUrl ? settings.get().crossDomainProxyPort : location.port.toString(); // eslint-disable-line no-restricted-properties
230230

231-
return getProxyUrl(url, { windowId, proxyPort, resourceType });
231+
return getProxyUrl(url, { windowId, proxyPort, resourceType }, nativeAutomation);
232232
}
233233

234234
export function getCrossDomainProxyPort (proxyPort: string) {

src/session/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export default abstract class Session extends EventEmitter {
200200
let payloadScript = '';
201201

202202
if (withPayload)
203-
payloadScript = isIframe ? await this.getIframePayloadScript(false) : await this.getPayloadScript();
203+
payloadScript = isIframe ? await this.getIframePayloadScript(false) : await this.getPayloadScript(windowId);
204204

205205
const taskScript = this._fillTaskScriptTemplate({
206206
serverInfo,
@@ -329,7 +329,7 @@ export default abstract class Session extends EventEmitter {
329329
}
330330

331331
abstract getIframePayloadScript (iframeWithoutSrc: boolean): Promise<string>;
332-
abstract getPayloadScript (): Promise<string>;
332+
abstract getPayloadScript (windowId?: string): Promise<string>;
333333
abstract handleFileDownload (): void;
334334
abstract handleAttachment ({ isOpenedInNewWindow }: { isOpenedInNewWindow: boolean }): void;
335335
abstract handlePageError (ctx: RequestPipelineContext, err: string): void;

src/utils/is-target-blank.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function (value = ''): boolean {
2+
return value === '_blank';
3+
}

0 commit comments

Comments
 (0)