Skip to content

Commit 4a8eff5

Browse files
authoredSep 14, 2017
Implement --page-load-timeout (closes DevExpress#1645) (DevExpress#1648)
* Implement --page-load-timeout (closes DevExpress#1645) * Fix tests * Apply remarks * Fix tests * Get rid of window.self usage (follow up DevExpress#632) * Remove redundant lines * Reduce default page load timeout
1 parent 6bf1ad5 commit 4a8eff5

File tree

27 files changed

+300
-22
lines changed

27 files changed

+300
-22
lines changed
 

‎src/api/test-controller/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
SetNativeDialogHandlerCommand,
2626
GetNativeDialogHistoryCommand,
2727
SetTestSpeedCommand,
28+
SetPageLoadTimeoutCommand,
2829
UseRoleCommand
2930
} from '../../test-run/commands/actions';
3031

@@ -250,6 +251,10 @@ export default class TestController {
250251
return this._enqueueCommand('setTestSpeed', SetTestSpeedCommand, { speed });
251252
}
252253

254+
_setPageLoadTimeout$ (duration) {
255+
return this._enqueueCommand('setPageLoadTimeout', SetPageLoadTimeoutCommand, { duration });
256+
}
257+
253258
_useRole$ (role) {
254259
return this._enqueueCommand('useRole', UseRoleCommand, { role });
255260
}

‎src/cli/argument-parser.js

+10
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export default class CLIArgumentParser {
102102
.option('--app-init-delay <ms>', 'specify how much time it takes for the tested app to initialize')
103103
.option('--selector-timeout <ms>', 'set the amount of time within which selectors make attempts to obtain a node to be returned')
104104
.option('--assertion-timeout <ms>', 'set the amount of time within which assertion should pass')
105+
.option('--page-load-timeout <ms>', 'set the amount of time within which TestCafe waits for the `window.load` event to fire on page load before proceeding to the next test action')
105106
.option('--speed <factor>', 'set the speed of test execution (0.01 ... 1)')
106107
.option('--ports <port1,port2>', 'specify custom port numbers')
107108
.option('--hostname <name>', 'specify the hostname')
@@ -171,6 +172,14 @@ export default class CLIArgumentParser {
171172
}
172173
}
173174

175+
_parsePageLoadTimeout () {
176+
if (this.opts.pageLoadTimeout) {
177+
assertType(is.nonNegativeNumberString, null, 'Page load timeout', this.opts.pageLoadTimeout);
178+
179+
this.opts.pageLoadTimeout = parseInt(this.opts.pageLoadTimeout, 10);
180+
}
181+
}
182+
174183
_parseSpeed () {
175184
if (this.opts.speed)
176185
this.opts.speed = parseFloat(this.opts.speed);
@@ -295,6 +304,7 @@ export default class CLIArgumentParser {
295304
this._parseFilteringOptions();
296305
this._parseSelectorTimeout();
297306
this._parseAssertionTimeout();
307+
this._parsePageLoadTimeout();
298308
this._parseAppInitDelay();
299309
this._parseSpeed();
300310
this._parsePorts();

‎src/client/core/utils/dom.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ export function isIFrameWindowInDOM (win) {
430430

431431
// NOTE: in Firefox and WebKit, frameElement is null for cross-domain iframes even if they are in the DOM.
432432
// But these browsers don't execute scripts in removed iframes, so we suppose that the iframe is in the DOM.
433-
if ((browserUtils.isFirefox || browserUtils.isWebKit) && win.top !== win.self && !frameElement)
433+
if ((browserUtils.isFirefox || browserUtils.isWebKit) && win.top !== win && !frameElement)
434434
return true;
435435

436436
return !!(frameElement && frameElement.contentDocument);
@@ -439,7 +439,7 @@ export function isIFrameWindowInDOM (win) {
439439
export function isTopWindow (win) {
440440
try {
441441
//NOTE: MS Edge throws an exception when trying to access window.top from an iframe removed from DOM
442-
return win.top === win.self;
442+
return win.top === win;
443443
}
444444
catch (e) {
445445
return false;

‎src/client/core/utils/event.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import hammerhead from '../deps/hammerhead';
2+
import delay from './delay';
23
import * as domUtils from './dom';
34

45

56
var Promise = hammerhead.Promise;
67
var nativeMethods = hammerhead.nativeMethods;
8+
var listeners = hammerhead.eventSandbox.listeners;
79

810
export const RECORDING_LISTENED_EVENTS = [
911
'click', 'mousedown', 'mouseup', 'dblclick', 'contextmenu', 'mousemove', 'mouseover', 'mouseout',
@@ -34,7 +36,8 @@ export function unbind (el, event, handler, useCapture) {
3436
}
3537

3638

37-
export function documentReady () {
39+
// Document ready
40+
const waitForDomContentLoaded = () => {
3841
return new Promise(resolve => {
3942
var isReady = false;
4043

@@ -49,8 +52,6 @@ export function documentReady () {
4952

5053
isReady = true;
5154

52-
unbind(window, 'load', ready);
53-
5455
resolve();
5556
}
5657

@@ -65,9 +66,19 @@ export function documentReady () {
6566

6667
if (document.readyState === 'complete')
6768
nativeMethods.setTimeout.call(window, onContentLoaded, 1);
68-
else {
69+
else
6970
bind(document, 'DOMContentLoaded', onContentLoaded);
70-
bind(window, 'load', ready);
71-
}
7271
});
72+
};
73+
74+
const waitForWindowLoad = () => new Promise(resolve => bind(window, 'load', resolve));
75+
76+
export function documentReady (pageLoadTimeout = 0) {
77+
return waitForDomContentLoaded()
78+
.then(() => {
79+
if (!listeners.getEventListeners(window, 'load').length)
80+
return null;
81+
82+
return Promise.race([waitForWindowLoad(), delay(pageLoadTimeout)]);
83+
});
7384
}

‎src/client/driver/driver.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export default class Driver {
8686
this.fixtureName = runInfo.fixtureName;
8787
this.testName = runInfo.testName;
8888
this.selectorTimeout = options.selectorTimeout;
89+
this.pageLoadTimeout = options.pageLoadTimeout;
8990
this.initialSpeed = options.speed;
9091
this.skipJsErrors = options.skipJsErrors;
9192
this.dialogHandler = options.dialogHandler;
@@ -103,7 +104,7 @@ export default class Driver {
103104
this.pageInitialRequestBarrier = new RequestBarrier();
104105

105106
this.readyPromise = eventUtils
106-
.documentReady()
107+
.documentReady(this.pageLoadTimeout)
107108
.then(() => this.pageInitialRequestBarrier.wait(true));
108109

109110
this._initChildDriverListening();

‎src/client/test-run/iframe.js.mustache

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
var IframeDriver = window['%testCafeIframeDriver%'];
33
var driver = new IframeDriver({{{testRunId}}}, {
44
selectorTimeout: {{{selectorTimeout}}},
5+
pageLoadTimeout: {{{pageLoadTimeout}}},
56
dialogHandler: {{{dialogHandler}}},
67
speed: {{{speed}}}
78
});

‎src/client/test-run/index.js.mustache

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
var testRunId = {{{testRunId}}};
66
var browserId = {{{browserId}}};
77
var selectorTimeout = {{{selectorTimeout}}};
8+
var pageLoadTimeout = {{{pageLoadTimeout}}};
89
var speed = {{{speed}}};
910
var browserHeartbeatUrl = {{{browserHeartbeatUrl}}};
1011
var browserStatusUrl = {{{browserStatusUrl}}};
@@ -20,6 +21,7 @@
2021
{ userAgent: userAgent, fixtureName: fixtureName, testName: testName },
2122
{
2223
selectorTimeout: selectorTimeout,
24+
pageLoadTimeout: pageLoadTimeout,
2325
skipJsErrors: skipJsErrors,
2426
dialogHandler: dialogHandler,
2527
speed: speed

‎src/runner/index.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import MESSAGE from '../errors/runtime/message';
1313

1414
const DEFAULT_SELECTOR_TIMEOUT = 10000;
1515
const DEFAULT_ASSERTION_TIMEOUT = 3000;
16+
const DEFAULT_PAGE_LOAD_TIMEOUT = 3000;
1617

1718

1819
export default class Runner extends EventEmitter {
@@ -30,7 +31,8 @@ export default class Runner extends EventEmitter {
3031
skipJsErrors: false,
3132
quarantineMode: false,
3233
debugMode: false,
33-
selectorTimeout: DEFAULT_SELECTOR_TIMEOUT
34+
selectorTimeout: DEFAULT_SELECTOR_TIMEOUT,
35+
pageLoadTimeout: DEFAULT_PAGE_LOAD_TIMEOUT
3436
};
3537
}
3638

@@ -183,12 +185,13 @@ export default class Runner extends EventEmitter {
183185
return this;
184186
}
185187

186-
run ({ skipJsErrors, quarantineMode, debugMode, selectorTimeout, assertionTimeout, speed = 1 } = {}) {
188+
run ({ skipJsErrors, quarantineMode, debugMode, selectorTimeout, assertionTimeout, pageLoadTimeout, speed = 1 } = {}) {
187189
this.opts.skipJsErrors = !!skipJsErrors;
188190
this.opts.quarantineMode = !!quarantineMode;
189191
this.opts.debugMode = !!debugMode;
190192
this.opts.selectorTimeout = selectorTimeout === void 0 ? DEFAULT_SELECTOR_TIMEOUT : selectorTimeout;
191193
this.opts.assertionTimeout = assertionTimeout === void 0 ? DEFAULT_ASSERTION_TIMEOUT : assertionTimeout;
194+
this.opts.pageLoadTimeout = pageLoadTimeout === void 0 ? DEFAULT_PAGE_LOAD_TIMEOUT : pageLoadTimeout;
192195

193196
if (typeof speed !== 'number' || isNaN(speed) || speed < 0.01 || speed > 1)
194197
throw new GeneralError(MESSAGE.invalidSpeedValue);

‎src/test-run/bookmark.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
SwitchToIframeCommand,
77
SetNativeDialogHandlerCommand,
88
SetTestSpeedCommand,
9+
SetPageLoadTimeoutCommand,
910
NavigateToCommand
1011
} from './commands/actions';
1112

@@ -20,12 +21,13 @@ export default class TestRunBookmark {
2021
this.testRun = testRun;
2122
this.role = role;
2223

23-
this.url = 'about:blank';
24-
this.dialogHandler = testRun.activeDialogHandler;
25-
this.iframeSelector = testRun.activeIframeSelector;
26-
this.speed = testRun.speed;
27-
this.ctx = testRun.ctx;
28-
this.fixtureCtx = testRun.fixtureCtx;
24+
this.url = 'about:blank';
25+
this.dialogHandler = testRun.activeDialogHandler;
26+
this.iframeSelector = testRun.activeIframeSelector;
27+
this.speed = testRun.speed;
28+
this.pageLoadTimeout = testRun.pageLoadTimeout;
29+
this.ctx = testRun.ctx;
30+
this.fixtureCtx = testRun.fixtureCtx;
2931
}
3032

3133
async init () {
@@ -52,6 +54,14 @@ export default class TestRunBookmark {
5254
}
5355
}
5456

57+
async _restorePageLoadTimeout () {
58+
if (this.testRun.pageLoadTimeout !== this.pageLoadTimeout) {
59+
var restorePageLoadTimeoutCommand = new SetPageLoadTimeoutCommand({ duration: this.pageLoadTimeout });
60+
61+
await this.testRun.executeCommand(restorePageLoadTimeoutCommand);
62+
}
63+
}
64+
5565
async _restoreWorkingFrame () {
5666
if (this.testRun.activeIframeSelector !== this.iframeSelector) {
5767
var switchWorkingFrameCommand = this.iframeSelector ?
@@ -89,6 +99,7 @@ export default class TestRunBookmark {
8999

90100
try {
91101
await this._restoreSpeed();
102+
await this._restorePageLoadTimeout();
92103
await this._restoreDialogHandler();
93104

94105
if (this.role.opts.preserveUrl)

‎src/test-run/commands/actions.js

+17
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,23 @@ export class SetTestSpeedCommand extends Assignable {
435435
}
436436
}
437437

438+
export class SetPageLoadTimeoutCommand extends Assignable {
439+
constructor (obj) {
440+
super(obj);
441+
442+
this.type = TYPE.setPageLoadTimeout;
443+
this.duration = null;
444+
445+
this._assignFrom(obj, true);
446+
}
447+
448+
_getAssignableProperties () {
449+
return [
450+
{ name: 'duration', type: positiveIntegerArgument, required: true }
451+
];
452+
}
453+
}
454+
438455
export class UseRoleCommand extends Assignable {
439456
constructor (obj) {
440457
super(obj);

‎src/test-run/commands/from-object.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import {
1818
SwitchToIframeCommand,
1919
SwitchToMainWindowCommand,
2020
SetNativeDialogHandlerCommand,
21-
SetTestSpeedCommand
21+
SetTestSpeedCommand,
22+
SetPageLoadTimeoutCommand
2223
} from './actions';
2324

2425
import AssertionCommand from './assertion';
@@ -105,6 +106,9 @@ export default function createCommandFromObject (obj) {
105106
case TYPE.setTestSpeed:
106107
return new SetTestSpeedCommand(obj);
107108

109+
case TYPE.setPageLoadTimeout:
110+
return new SetPageLoadTimeoutCommand(obj);
111+
108112
case TYPE.assertion:
109113
return new AssertionCommand(obj);
110114

‎src/test-run/commands/type.js

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default {
3535
setNativeDialogHandler: 'set-native-dialog-handler',
3636
getNativeDialogHistory: 'get-native-dialog-history',
3737
setTestSpeed: 'set-test-speed',
38+
setPageLoadTimeout: 'set-page-load-timeout',
3839
debug: 'debug',
3940
assertion: 'assertion',
4041
useRole: 'useRole',

‎src/test-run/index.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import ClientFunctionBuilder from '../client-functions/client-function-builder';
2424

2525

2626
import { TakeScreenshotOnFailCommand } from './commands/browser-manipulation';
27-
import { SetNativeDialogHandlerCommand, SetTestSpeedCommand } from './commands/actions';
27+
import { SetNativeDialogHandlerCommand, SetTestSpeedCommand, SetPageLoadTimeoutCommand } from './commands/actions';
2828

2929

3030
import {
@@ -70,6 +70,7 @@ export default class TestRun extends Session {
7070
this.activeDialogHandler = null;
7171
this.activeIframeSelector = null;
7272
this.speed = this.opts.speed;
73+
this.pageLoadTimeout = this.opts.pageLoadTimeout;
7374

7475
this.pendingRequest = null;
7576
this.pendingPageError = null;
@@ -118,6 +119,7 @@ export default class TestRun extends Session {
118119
testName: JSON.stringify(this.test.name),
119120
fixtureName: JSON.stringify(this.test.fixture.name),
120121
selectorTimeout: this.opts.selectorTimeout,
122+
pageLoadTimeout: this.pageLoadTimeout,
121123
skipJsErrors: this.opts.skipJsErrors,
122124
speed: this.speed,
123125
dialogHandler: JSON.stringify(this.activeDialogHandler)
@@ -128,6 +130,7 @@ export default class TestRun extends Session {
128130
return Mustache.render(IFRAME_TEST_RUN_TEMPLATE, {
129131
testRunId: JSON.stringify(this.id),
130132
selectorTimeout: this.opts.selectorTimeout,
133+
pageLoadTimeout: this.pageLoadTimeout,
131134
speed: this.speed,
132135
dialogHandler: JSON.stringify(this.activeDialogHandler)
133136
});
@@ -376,6 +379,9 @@ export default class TestRun extends Session {
376379
else if (command.type === COMMAND_TYPE.setTestSpeed)
377380
this.speed = command.speed;
378381

382+
else if (command.type === COMMAND_TYPE.setPageLoadTimeout)
383+
this.pageLoadTimeout = command.duration;
384+
379385
else if (command.type === COMMAND_TYPE.debug)
380386
this.debugging = true;
381387
}
@@ -402,6 +408,9 @@ export default class TestRun extends Session {
402408
if (command.type === COMMAND_TYPE.wait)
403409
return delay(command.timeout);
404410

411+
if (command.type === COMMAND_TYPE.setPageLoadTimeout)
412+
return null;
413+
405414
if (command.type === COMMAND_TYPE.debug)
406415
return await this._enqueueSetBreakpointCommand(callsite);
407416

@@ -449,6 +458,12 @@ export default class TestRun extends Session {
449458

450459
await this.executeCommand(setSpeedCommand);
451460
}
461+
462+
if (this.pageLoadTimeout !== this.opts.pageLoadTimeout) {
463+
var setPageLoadTimeoutCommand = new SetPageLoadTimeoutCommand({ duration: this.opts.pageLoadTimeout });
464+
465+
await this.executeCommand(setPageLoadTimeoutCommand);
466+
}
452467
}
453468

454469
async _getStateSnapshotFromRole (role) {
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>PageLoadTimeout (window load long)</title>
5+
</head>
6+
<body>
7+
<img src="./img.png?delay=10000" />
8+
<script>
9+
window.pageOpenedTime = Date.now();
10+
</script>
11+
</body>
12+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>PageLoadTimeout (window load long)</title>
5+
</head>
6+
<body>
7+
<img src="./img.png?delay=10000" />
8+
<script>
9+
window.pageOpenedTime = Date.now();
10+
11+
window.addEventListener('load', function () {
12+
window.loadEventRaised = true;
13+
});
14+
</script>
15+
</body>
16+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>PageLoadTimeout (window load)</title>
5+
</head>
6+
<body>
7+
<img src="./img.png?delay=1000" />
8+
<script>
9+
window.addEventListener('load', function () {
10+
window.loadEventRaised = true;
11+
});
12+
</script>
13+
</body>
14+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>PageLoadTimeout (with iframe)</title>
5+
</head>
6+
<body>
7+
<iframe id="iframe" src="window-load.html"></iframe>
8+
</body>
9+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
describe('Should wait for the window.load event if necessary', function () {
2+
it('Should wait for the window.load event if there are user event handlers for it (set timeout via an option)', function () {
3+
return runTests('testcafe-fixtures/index-test.js', 'Wait for window.load (set timeout via an option)', { pageLoadTimeout: 3000 });
4+
});
5+
6+
it('Should wait for the window.load event if there are user event handlers for it (set timeout via `t`)', function () {
7+
return runTests('testcafe-fixtures/index-test.js', 'Wait for window.load (set timeout via `t`)', { pageLoadTimeout: 0 });
8+
});
9+
10+
it('Should wait for the window.load event in iframe', function () {
11+
return runTests('testcafe-fixtures/index-test.js', 'Wait for window.load in iframe', {
12+
pageLoadTimeout: 0,
13+
selectorTimeout: 10000
14+
});
15+
});
16+
17+
it("Shouldn't wait for the window.load event more than timeout", function () {
18+
return runTests('testcafe-fixtures/index-test.js', "Don't wait for window.load more than timeout", { pageLoadTimeout: 0 });
19+
});
20+
21+
it("Shouldn't wait for the window.load event if there are no user event handlers for it", function () {
22+
return runTests('testcafe-fixtures/index-test.js', "Don't wait for window.load", { pageLoadTimeout: 10000 });
23+
});
24+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { ClientFunction } from 'testcafe';
2+
3+
fixture `page-load-timeout`;
4+
5+
test
6+
.page('http://localhost:3000/fixtures/api/es-next/page-load-timeout/pages/window-load.html')
7+
('Wait for window.load (set timeout via an option)', async t => {
8+
await t.expect(ClientFunction(() => window.loadEventRaised)()).ok('Test started before window.load', { timeout: 0 });
9+
});
10+
11+
test
12+
('Wait for window.load (set timeout via `t`)', async t => {
13+
await t
14+
.setPageLoadTimeout(3000)
15+
.navigateTo('http://localhost:3000/fixtures/api/es-next/page-load-timeout/pages/window-load.html')
16+
.expect(ClientFunction(() => window.loadEventRaised)()).ok('Test started before window.load', { timeout: 0 });
17+
});
18+
19+
test
20+
('Wait for window.load in iframe', async t => {
21+
await t
22+
.setPageLoadTimeout(3000)
23+
.navigateTo('http://localhost:3000/fixtures/api/es-next/page-load-timeout/pages/with-iframe.html')
24+
.switchToIframe('#iframe')
25+
.expect(ClientFunction(() => window.loadEventRaised)()).ok('Test started before window.load', { timeout: 0 });
26+
});
27+
28+
test
29+
.page('http://localhost:3000/fixtures/api/es-next/page-load-timeout/pages/window-load-long.html')
30+
("Don't wait for window.load more than timeout", async t => {
31+
const { startTestTime, pageOpenedTime } = await t.eval(() => {
32+
return {
33+
pageOpenedTime: window.pageOpenedTime,
34+
startTestTime: Date.now()
35+
};
36+
});
37+
38+
await t.expect(startTestTime - pageOpenedTime).lt(1000);
39+
});
40+
41+
test
42+
.page('http://localhost:3000/fixtures/api/es-next/page-load-timeout/pages/window-load-long-no-handlers.html')
43+
("Don't wait for window.load", async t => {
44+
const { startTestTime, pageOpenedTime } = await t.eval(() => {
45+
return {
46+
pageOpenedTime: window.pageOpenedTime,
47+
startTestTime: Date.now()
48+
};
49+
});
50+
51+
await t.expect(startTestTime - pageOpenedTime).lt(1000);
52+
});

‎test/functional/fixtures/api/es-next/roles/test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe('[API] t.useRole()', function () {
2323
return runTests('./testcafe-fixtures/configuration-test.js', 'Clear configuration', TEST_WITH_IFRAME_FAILED_RUN_OPTIONS)
2424
.catch(function (errs) {
2525
expect(errs[0]).contains('- Error in Role initializer - A native alert dialog was invoked');
26-
expect(errs[0]).contains('> 31 | await t.click(showAlertBtn);');
26+
expect(errs[0]).contains('> 32 | await t.click(showAlertBtn);');
2727
});
2828
});
2929

‎test/functional/fixtures/api/es-next/roles/testcafe-fixtures/configuration-test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ async function initConfiguration () {
1616
.expect(history[0].text).eql('Hey!')
1717
.switchToIframe('#iframe')
1818
.expect(iframeElement.exists).ok()
19-
.setTestSpeed(0.95);
19+
.setTestSpeed(0.95)
20+
.setPageLoadTimeout(95);
2021

2122
t.ctx.someVal = 'ctxVal';
2223
t.fixtureCtx.someVal = 'fixtureCtxVal';

‎test/functional/fixtures/api/typescript/smoke/testcafe-fixtures/non-trivial-test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ async function initConfiguration() {
1515
.expect(history[0].text).eql('Hey!')
1616
.switchToIframe('#iframe')
1717
.expect(iframeElement.exists).ok()
18-
.setTestSpeed(0.95);
18+
.setTestSpeed(0.95)
19+
.setPageLoadTimeout(95);
1920

2021
t.ctx['someVal'] = 'ctxVal';
2122
t.fixtureCtx['someVal'] = 'fixtureCtxVal';

‎test/functional/setup.js

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const BROWSER_OPENING_TIMEOUT = 90000;
2222

2323
const FUNCTIONAL_TESTS_SELECTOR_TIMEOUT = 200;
2424
const FUNCTIONAL_TESTS_ASSERTION_TIMEOUT = 1000;
25+
const FUNCTIONAL_TESTS_PAGE_LOAD_TIMEOUT = 0;
2526

2627
var envName = process.env.TESTING_ENVIRONMENT || config.testingEnvironmentNames.localBrowsers;
2728
var environment = config.testingEnvironments[envName];
@@ -155,6 +156,7 @@ before(function () {
155156
var quarantineMode = opts && opts.quarantineMode;
156157
var selectorTimeout = opts && opts.selectorTimeout || FUNCTIONAL_TESTS_SELECTOR_TIMEOUT;
157158
var assertionTimeout = opts && opts.assertionTimeout || FUNCTIONAL_TESTS_ASSERTION_TIMEOUT;
159+
var pageLoadTimeout = opts && opts.pageLoadTimeout || FUNCTIONAL_TESTS_PAGE_LOAD_TIMEOUT;
158160
var onlyOption = opts && opts.only;
159161
var skipOption = opts && opts.skip;
160162
var screenshotPath = opts && opts.setScreenshotPath ? '___test-screenshots___' : '';
@@ -219,6 +221,7 @@ before(function () {
219221
quarantineMode: quarantineMode,
220222
selectorTimeout: selectorTimeout,
221223
assertionTimeout: assertionTimeout,
224+
pageLoadTimeout: pageLoadTimeout,
222225
speed: speed
223226
})
224227
.then(function () {

‎test/server/cli-argument-parser-test.js

+13
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,19 @@ describe('CLI argument parser', function () {
117117
});
118118
});
119119

120+
describe('Page load timeout', function () {
121+
it('Should parse "--page-load-timeout" option as integer value', function () {
122+
return parse('--page-load-timeout 1000')
123+
.then(function (parser) {
124+
expect(parser.opts.pageLoadTimeout).eql(1000);
125+
});
126+
});
127+
128+
it('Should raise an error if the "--page-load-timeout" option value is not an integer', function () {
129+
return assertRaisesError('--page-load-timeout yo', 'Page load timeout is expected to be a non-negative number, but it was "yo".');
130+
});
131+
});
132+
120133
describe('Speed', function () {
121134
it('Should parse "--speed" option as a number', function () {
122135
return parse('--speed 0.01')

‎test/server/test-run-commands-test.js

+46
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,19 @@ describe('Test run commands', function () {
959959
});
960960
});
961961

962+
it('Should create SetPageLoadTimeoutCommand from object', function () {
963+
var commandObj = {
964+
type: TYPE.setPageLoadTimeout,
965+
duration: 3
966+
};
967+
var command = createCommand(commandObj);
968+
969+
expect(JSON.parse(JSON.stringify(command))).eql({
970+
type: TYPE.setPageLoadTimeout,
971+
duration: 3
972+
});
973+
});
974+
962975
it('Should create AssertionCommand from object', function () {
963976
var commandObj = {
964977
type: TYPE.assertion,
@@ -2606,6 +2619,39 @@ describe('Test run commands', function () {
26062619
);
26072620
});
26082621

2622+
it('Should validate SetPageLoadTimeoutCommand', function () {
2623+
assertThrow(
2624+
function () {
2625+
return createCommand({
2626+
type: TYPE.setPageLoadTimeout
2627+
});
2628+
},
2629+
{
2630+
isTestCafeError: true,
2631+
type: ERROR_TYPE.actionPositiveIntegerArgumentError,
2632+
argumentName: 'duration',
2633+
actualValue: 'undefined',
2634+
callsite: null
2635+
}
2636+
);
2637+
2638+
assertThrow(
2639+
function () {
2640+
return createCommand({
2641+
type: TYPE.setPageLoadTimeout,
2642+
duration: -1
2643+
});
2644+
},
2645+
{
2646+
isTestCafeError: true,
2647+
type: ERROR_TYPE.actionPositiveIntegerArgumentError,
2648+
argumentName: 'duration',
2649+
actualValue: -1,
2650+
callsite: null
2651+
}
2652+
);
2653+
});
2654+
26092655
it('Should validate AssertionСommand', function () {
26102656
assertThrow(
26112657
function () {

‎ts-defs/index.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,12 @@ interface TestController {
10201020
* @param speed - Specifies the test speed. Must be a number between 1 (the fastest) and 0.01 (the slowest).
10211021
*/
10221022
setTestSpeed(speed: number): TestControllerPromise;
1023+
/**
1024+
* Specifies the amount of time within which TestCafe waits for the `window.load` event to fire before starting the test.
1025+
*
1026+
* @param duration - Specifies the amount of time within which TestCafe waits for the `window.load` event to fire before starting the test.
1027+
*/
1028+
setPageLoadTimeout(duration: number): TestControllerPromise;
10231029
/**
10241030
* Switches user role.
10251031
*

0 commit comments

Comments
 (0)
Please sign in to comment.