- Remote browsers now start after tests are compiled (#3219) by @link89
- The TestCafe Docker image now includes version tags (#2315)
- Tests now fail with a meaningful error if no fixture is defined (#2913)
- Tests now resume correctly after a long waiting (#3070)
- TestCafe now throws a meaningful exception when taking screenshots in a browser that does not support it (#2878)
- Events are now simulated in the correct order when focusing an element after another element was focused on the
changed
event (#3098) - The
Invalid calling object
exception is no longer thrown in IE11 (testcafe-hammerhead/#1846) - The JSON parse error is no longer thrown when sending an XHR request (testcafe-hammerhead/#1839)
- Overridden functions now have the right prototype in an
iframe
withoutsrc
(testcafe-hammerhead/#1824) gulp-testcafe
now correctly closes Chrome after tests are finished (testcafe-hammerhead/#1826)- Saving the
window
prototype to a property now works correctly (testcafe-hammerhead/#1828) - Hammerhead is now retained after
document.close
in Firefox (testcafe-hammerhead/#1821)
- TestCafe no longer posts internal messages to the browser console (#3099)
- The TestCafe process no longer terminates before the report is written to a file (#2502)
You can now run only those tests or fixtures whose metadata contains a specific set of values. Use the --test-meta and --fixture-meta flags to specify these values.
testcafe chrome my-tests --test-meta device=mobile,env=production
testcafe chrome my-tests --fixture-meta subsystem=payments,type=regression
In the API, test and fixture metadata is now passed to the runner.filter method in the testMeta
and fixtureMeta
parameters. Use this metadata to build a logic that determines whether to run the current test.
runner.filter((testName, fixtureName, fixturePath, testMeta, fixtureMeta) => {
return testMeta.mobile === 'true' &&
fixtureMeta.env === 'staging';
});
⚙️ Run Dynamically Loaded Tests (#2074)
You can now run tests imported from external libraries or generated dynamically even if the .js
file does not contain any tests.
This was not possible previously because test files should contain the fixture and test directives. However, you can now provide the --disable-test-syntax-validation command line flag to bypass this check.
testcafe safari test.js --disable-test-syntax-validation
In the API, use the disableTestSyntaxValidation option.
runner.run({ disableTestSyntaxValidation: true })
- Touch events are now simulated with correct touch properties (
touches
,targetTouches
,changedTouches
) (#2856) - Google Chrome now closes correctly on macOS after tests are finished (#2860)
- Internal attribute and node changes no longer trigger
MutationObserver
notifications (testcafe-hammerhead/#1769) - The
ECONNABORTED
error is no longer raised (testcafe-hammerhead/#1744) - Websites that use
Location.ancestorOrigins
are now proxied correctly (testcafe-hammerhead/#1342)
⚙️ Stop Test Run After the First Test Fail (#1323)
You can now configure TestCafe to stop the entire test run after the first test fail. This saves your time when you fix problems with your tests one by one.
Specify the --sf flag to enable this feature when you run tests from the command line.
testcafe chrome my-tests --sf
In the API, use the stopOnFirstFail option.
runner.run({ stopOnFirstFail: true })
⚙️ View the JavaScript Errors' Stack Traces in Reports (#2043)
Now when a JavaScript error occurs on the tested webpage, the test run report includes a stack trace for this error (only if the --skip-js-errors option is disabled).
⚙️ Browsers are Automatically Restarted When They Stop Responding (#1815)
If a browser stops responding while it executes tests, TestCafe restarts the browser and reruns the current test in a new browser instance. If the same problem occurs with this test two more times, the test run finishes and an error is thrown.
- An error message about an unawaited call to an async function is no longer displayed when an uncaught error occurs (#2557)
- A request hook is no longer added multiple times when a filter rule is used (#2650)
- Screenshot links in test run reports now contain paths specified by the
--screenshot-pattern
option (#2726) - Assertion chains no longer produce unhandled promise rejections (#2852)
- The
moment
loader now works correctly in the Jest environment (#2500) - TestCafe no longer hangs if the screenshot directory contains forbidden symbols (#681)
- The
--ssl
option's parameters are now parsed correctly (#2924) - TestCafe now throws a meaningful error if an assertion method is missing (#1063)
- TestCafe no longer hangs when it clicks a custom element (#2861)
- TestCafe now performs keyboard navigation between radio buttons/groups in a way that matches the native browser behavior (#2067, #2045)
- The
fetch
method can now be used with data URLs (#2865) - The
switchToIframe
function no longer throws an error (#2956) - TestCafe can now scroll through fixed elements when the action has custom offsets (#2978)
- You can now specify the current directory or its parent directories as the base path to store screenshots (#2975)
- Tests no longer hang up when you try to debug in headless browsers (#2846)
- The
removeEventListener
function now works correctly when an object is passed as its third argument (testcafe-hammerhead/#1737) - Hammerhead no longer adds the
event
property to a nullcontentWindow
in IE11 (testcafe-hammerhead/#1684) - The browser no longer resets connection with the server for no reason (testcafe-hammerhead/#1647)
- Hammerhead now stringifies values correctly before outputting them to the console (testcafe-hammerhead/#1750)
- A document fragment from the top window can now be correctly appended to an iframe (testcafe-hammerhead/#912)
- Lifecycle callbacks that result from the
document.registerElement
method are no longer called twice (testcafe-hammerhead/#695)
⚙️ CoffeeScript Support (#1556) by @GeoffreyBooth
TestCafe now allows you to write tests in CoffeeScript. You do not need to compile CoffeeScript manually or make any customizations - everything works out of the box.
import { Selector } from 'testcafe'
fixture 'CoffeeScript Example'
.page 'https://devexpress.github.io/testcafe/example/'
nameInput = Selector '#developer-name'
test 'Test', (t) =>
await t
.typeText(nameInput, 'Peter')
.typeText(nameInput, 'Paker', { replace: true })
.typeText(nameInput, 'r', { caretPos: 2 })
.expect(nameInput.value).eql 'Parker';
⚙️ Failed Selector Method Pinpointed in the Report (#2568)
Now the test run report can identify which selector's method does not match any DOM element.
⚙️ Fail on Uncaught Server Errors (#2546)
Previously, TestCafe ignored uncaught errors and unhandled promise rejections that occurred on the server. Whenever an error or a promise rejection happened, test execution continued.
Starting from v0.22.0, tests fail if a server error or promise rejection is unhandled. To return to the previous behavior, we have introduced the skipUncaughtErrors
option. Use the --skip-uncaught-errors flag in the command line or the skipUncaughtErrors option in the API.
testcafe chrome tests/fixture.js --skipUncaughtErrors
runner.run({skipUncaughtErrors:true})
⚙️ Use Glob Patterns in runner.src
(#980)
You can now use glob patterns in the runner.src method to specify a set of test files.
runner.src(['/home/user/tests/**/*.js', '!/home/user/tests/foo.js']);
RequestLogger
no longer fails when it tries to stringify a null request body (#2718)- Temporary directories are now correctly removed when the test run is finished (#2735)
- TestCafe no longer throws
ECONNRESET
when run against a Webpack project (#2711) - An error is no longer thrown when TestCafe tests Sencha ExtJS applications in IE11 (#2639)
- Firefox no longer waits for page elements to appear without necessity (#2080)
${BROWSER}
in the screenshot pattern now correctly resolves to the browser name (#2742)- The
toString
function now returns a native string for overridden descriptor ancestors (testcafe-hammerhead/#1713) - The
iframe
flag is no longer added when a form withtarget="_parent"
is submitted (testcafe-hammerhead/#1680) - Hammerhead no longer sends request headers in lower case (testcafe-hammerhead/#1380)
- The overridden
createHTMLDocument
method has the right context now (testcafe-hammerhead/#1722) - Tests no longer lose connection (testcafe-hammerhead/#1647)
- The case when both the
X-Frame-Options
header and a CSP withframe-ancestors
are set is now handled correctly (testcafe-hammerhead/#1666) - The mechanism that resolves URLs on the client now works correctly (testcafe-hammerhead/#1701)
LiveNodeListWrapper
now imitates the native behavior correctly (testcafe-hammerhead/#1376)
- The
RequestLogger.clear
method no longer raises an error if it is called during a long running request (#2688) - TestCafe now uses native methods to work with the
fetch
request (#2686) - A URL now resolves correctly for elements in a
document.implementation
instance (testcafe-hammerhead/#1673) - Response header names specified via the
respond
function are lower-cased now (testcafe-hammerhead/#1704) - The cookie domain validation rule on the client side has been fixed (testcafe-hammerhead/#1702)
⚙️ Test Web Pages Served Over HTTPS (#1985)
Some browser features (like Service Workers, Geolocation API, ApplePaySession, or SubtleCrypto) require a secure origin. This means that the website should use the HTTPS protocol.
Starting with v0.21.0, TestCafe can serve proxied web pages over HTTPS. This allows you to test pages that require a secure origin.
To enable HTTPS when you use TestCafe through the command line, specify the --ssl flag followed by the HTTPS server options. The most commonly used options are described in the TLS topic in the Node.js documentation.
testcafe --ssl pfx=path/to/file.pfx;rejectUnauthorized=true;...
When you use a programming API, pass the HTTPS server options to the createTestCafe method.
'use strict';
const createTestCafe = require('testcafe');
const selfSignedSertificate = require('openssl-self-signed-certificate');
let runner = null;
const sslOptions = {
key: selfSignedSertificate.key,
cert: selfSignedSertificate.cert
};
createTestCafe('localhost', 1337, 1338, sslOptions)
.then(testcafe => {
runner = testcafe.createRunner();
})
.then(() => {
return runner
.src('test.js')
// Browsers restrict self-signed certificate usage unless you
// explicitly set a flag specific to each browser.
// For Chrome, this is '--allow-insecure-localhost'.
.browsers('chrome --allow-insecure-localhost')
.run();
});
See Connect to TestCafe Server over HTTPS for more information.
⚙️ Construct Screenshot Paths with Patterns (#2152)
You can now use patterns to construct paths to screenshots. TestCafe provides a number of placeholders you can include in the path, for example, ${DATE}
, ${TIME}
, ${USERAGENT}
, etc. For a complete list, refer to the command line --screenshot-path-pattern flag description.
You specify a screenshot path pattern when you run tests. Each time TestCafe takes a screenshot, it substitutes the placeholders with actual values and saves the screenshot to the resulting path.
The following example shows how to specify a screenshot path pattern through the command line:
testcafe all test.js -s screenshots -p '${DATE}_${TIME}/test-${TEST_INDEX}/${USERAGENT}/${FILE_INDEX}.png'
When you use a programming API, pass the screenshot path pattern to the runner.screenshots method.
runner.screenshots('reports/screenshots/', true, '${TEST_INDEX}/${OS}/${BROWSER}-v${BROWSER_VERSION}/${FILE_INDEX}.png');
⚙️ Add Info About Screenshots and Quarantine Attempts to Custom Reports (#2216)
Custom reporters can now access screenshots' data and the history of quarantine attempts (if the test run in the quarantine mode).
The following information about screenshots is now available:
- the path to the screenshot file,
- the path to the thumbnail image,
- the browser's user agent,
- the quarantine attempt number (if the screenshot was taken in the quarantine mode),
- whether the screenshot was taken because the test failed.
If the test was run in the quarantine mode, you can also determine which attempts failed and passed.
Refer to the reportTestDone method description for details on how to access this information.
- HTML5 drag events are no longer simulated if
event.preventDefault
is called for themousedown
event (#2529) - File upload no longer causes an exception when there are several file inputs on the page (#2642)
- File upload now works with inputs that have the
required
attribute (#2509) - The
load
event listener is no longer triggered when added to an image (testcafe-hammerhead/#1688)
- The
buttons
property was added to theMouseEvent
instance (#2056) - Response headers were converted to lowercase (#2534)
- Updated flow definitions (#2053)
- An
AttributesWrapper
instance is now updated when the the element's property specifies thedisabled
attribute (#2539) - TestCafe no longer hangs when it redirects from a tested page to the 'about:error' page with a hash (#2371)
- TestCafe now reports a warning for a mocked request if CORS validation failed (#2482)
- Prevented situations when a request logger tries to stringify a body that is not logged (#2555)
- The Selector API now reports
NaN
instead ofinteger
when type validation fails (#2470) - Enabled
noImplicitAny
and disabledskipLibCheck
in the TypeScript compiler (#2497) - Pages with
rel=prefetch
links no longer hang during test execution (#2528) - Fixed the
TypeError: this.res.setHeader is not a function
error in Firefox (#2438) - The
formtarget
attribute was overridden (testcafe-hammerhead/#1513) fetch.toString()
now equalsfunction fetch() { [native code] }
(testcafe-hammerhead/#1662)
TestCafe now takes screenshots using browsers' debug protocols (#2492)
fetch
requests now correctly proxied in a specific case (testcafe-hammerhead/#1613)- Resources responding with
304
HTTP status code and with the 'content-length: ' header are proxied correctly now (testcafe-hammerhead/#1602) - The
transfer
argument ofwindow.postMessage
is passed correctly now (testcafe-hammerhead/#1535) - Incorrect focus events order in IE has been fixed (#2072)
⚙️ Add TS definitions to the Docker image (#2481)
- Selection in a
contenteditable
div
now works properly in a specific scenario (#2365) - A collision related to several
moment-duration-format
package versions is now fixed (#1750) - TestCafe now reports a warning when saving several screenshots at the same path (#2213)
- A regression related to wrongly processed
document.write
in IE11 is now fixed (#2469) - An out of memory crash on calling console methods is now fixed (testcafe-hammerhead/#1546)
Click
action for an element with 1px height or width works properly now (#2020)- Touch emulation for the latest Google Chrome was fixed (#2448)
- Enabled the screenshot and window resizing functionalities in the concurrency mode for Firefox and Chrome on macOS #2095
⚙️ Typescript definitions for new features from v0.20.0 have been added (#2428)
- Now sites with the overridden
Element.prototype.matches
method work properly #2241 window.Blob
now returns a correct result when Array ofArrayBuffer
is passed as a parameter (testcafe-hammerhead/#1599)- Firefox Shield popup is not shown during test execution now (#2421)
Request Hooks: Intercepting HTTP requests (#1341)
TestCafe now allows you to record HTTP request data or mock responses. You can also create a custom HTTP request hook to emulate authentications like Kerberos or Client Certificate Authentication.
See Intercepting HTTP Requests for more information.
⚙️ Specifying resources accessed by bypassing a proxy server (#1791)
TestCafe now allows you to bypass the proxy server when accessing specific resources.
To specify resources that require direct access, use the --proxy-bypass flag in the command line or the useProxy API method's parameters.
testcafe chrome my-tests/**/*.js --proxy proxy.corp.mycompany.com --proxy-bypass localhost:8080,internal-resource.corp.mycompany.com
runner.useProxy('172.0.10.10:8080', ['localhost:8080', 'internal-resource.corp.mycompany.com']);
⚙️ Specifying testing metadata (#2242)
TestCafe allows you to specify additional information for tests in the form of key-value metadata and use it in reports.
You can define metadata for a fixture or a test using the meta method:
fixture `My Fixture`
.meta('fixtureID', 'f-0001')
.meta({ author: 'John', creationDate: '05/03/2018' });
test
.meta('testID', 't-0005')
.meta({ severity: 'critical', testedAPIVersion: '1.0' })
('MyTest', async t => { /* ... */});
To include testing metadata to reports, use the custom reporter methods.
⚙️ Passing a regular promise to t.expect
is deprecated now (#2207)
TestCafe now throws an error if you pass a regular promise to the assertion's expect
method.
If you need to assert a regular promise, set the allowUnawaitedPromise option to true
.
await t.expect(doSomethingAsync()).ok('check that a promise is returned', { allowUnawaitedPromise: true });
- The session recovery bubble in Firefox is disabled (#2341)
- TestCafe works properly if a
body
element has thepointer-events: none;
css style rule (#2251) - Resizing Chrome in the emulation mode works correctly (#2154)
- The location port is used for service messages (#2308)
- A browser instance shuts down correctly on Unix systems (#2226)
- An
Integrity
attribute is removed fromscript
andlink
tags (testcafe-hammerhead/#235) - The
event.preventDefault()
method call changes theevent.defaultPrevented
property value (testcafe-hammerhead/#1588) - It is possible to set the
meta
element'scontent
attribute (testcafe-hammerhead/#1586) - TestCafe no longer overrides attributes used in a non-standard way with
null
(testcafe-hammerhead/#1583) - The
Change
event fires correctly if thetarget.value
changes (#2319) MouseEvent.screenX
andMouseEvent.screenY
are added to the emulated events (#2325)- Cookies on
localhost
are processed correctly (testcafe-hammerhead/#1491) - Setting the
//
url for an image works correctly (#2312) shadowUI
internal elements are no longer processed (#2281)typeInput
event is raised correctly (#1956)- Selecting text in contenteditable elements works properly (#2301)
Added support for browser providers from private repositories (#2221)
- Restored the screenshot functionality in legacy tests (#2235)
- Updated the list of emulation devices in Google Chrome (#2257)
- Fixed touch events emulation (#2268)
- The
event.relatedTarget
property is set correctly for the emulated focus and drag events (#2197) - The
event.detail
property is set correctly for the emulated mouse events (#2232) - The
Element.innerHTML
property is processed correctly in certain cases (testcafe-hammerhead/#1538) - The iframe location has the correct value when it is not initialized (testcafe-hammerhead/#1531)
- A trailing slash is added to test page URL when necessary (#2005)
- The
focus
event is not called for a disabled input (#2123)
Backward compatibility with the legacy test syntax has been restored (#2210)
- The
document.all
property is overridden (testcafe-hammerhead/#1046) - Proxying properties in
async
class methods are supported (testcafe-hammerhead/#1510) - Fixed wrongly proxying a
localStorage
check-in WebWorkers (testcafe-hammerhead/#1496)
TestCafe Live: See instant feedback when working on tests (#1624)
We have prepared a new tool for rapid test development.
TestCafe Live provides a service that keeps the TestCafe process and browsers opened while you are working on tests. Changes you make in code immediately restart the tests. That is, TestCafe Live allows you to see test results instantly.
See TestCafe Live for more information.
⚙️ Taking Screenshots of Individual Page Elements (#1496)
We have added the t.takeElementScreenshot action that allows you to take a screenshot of an individual page element.
import { Selector } from 'testcafe';
fixture `My fixture`
.page `http://devexpress.github.io/testcafe/example/`;
test('Take a screenshot of a fieldset', async t => {
await t
.click('#reusing-js-code')
.click('#continuous-integration-embedding')
.takeElementScreenshot(Selector('fieldset').nth(1), 'my-fixture/important-features.png');
});
This action provides additional customization that allows you to adjust the screenshot's center or crop it. Refer to the documentation for more information.
Note that if the screenshot directory is not specified in the runner.screenshots API method or screenshots command line option, the t.takeElementScreenshot
action is ignored.
⚙️ Filtering Elements by Their Visibility (#1018)
You can now filter the selector's matching set to display only visible or hidden elements using the filterVisible and filterHidden methods.
import { Selector } from 'testcafe';
fixture `My fixture`
.page `http://devexpress.github.io/testcafe/example/`;
test('Filter visible and hidden elements', async t => {
const inputs = Selector('input');
const hiddenInput = inputs.filterHidden();
const visibleInputs = inputs.filterVisible();
await t
.expect(hiddenInput.count).eql(1)
.expect(visibleInputs.count).eql(11);
});
⚙️ Finding Elements by the Exact Matching Text (#1292)
The current selector's withText method looks for elements whose text content contains the specified string. With this release, we have added the withExactText method that searches by strict match.
import { Selector } from 'testcafe';
fixture `My fixture`
.page `http://devexpress.github.io/testcafe/example/`;
test('Search by exact text', async t => {
const labels = Selector('label');
const winLabel = labels.withExactText('Windows');
const reusingLabel = labels.withText('JavaScript');
await t
.expect(winLabel.exists).ok()
.expect(reusingLabel.exists).ok();
});
⚙️ Using Decorators in TypeScript Code (#2117) by @pietrovich
TestCafe now allows you to use decorators when writing tests in TypeScript.
Note that decorators are still an experimental feature in TypeScript.
- TestCafe can scroll a webpage when the
body
has a scroll bar (#1940) - Firefox no longer hangs with a dialog asking to set it as the default browser (#1926)
- Legacy APIs no longer freeze because of an unexpected error (#1790)
- Clicking an element that was hidden and then recreated on timeout works correctly (#1994)
- TestCafe finds browsers in headless mode on macOS when tests are executing concurrently (#2035)
- The local storage is restored correctly (#2015) when roles are switched using the
preserverUrl
flag - TestCafe progress bar is no longer visible on screenshots (#2076)
- Window manipulations wait for pages to load (#2000)
- All toolbars are hidden when taking screenshots (#1445)
- TestCafe works with the latest CucumberJS version (#2107)
- Fixed an error connected to file permissions on Ubuntu (#2144)
- Browser manipulations can be executed step-by-step (#2150)
- Fixed a bug where a page does not load because of an error in
generateCallExpression
(testcafe-hammerhead/#1389) - The overridden Blob constructor does not process data unnecessarily (testcafe-hammerhead/#1359)
- The
target
attribute is not set for a button after clicking on it (testcafe-hammerhead/#1437) - The
sandbox
,target
andstyle
attributes are cleaned up (testcafe-hammerhead/#1448) - A
RangeError
with the messageMaximum call stack size exceeded
is no longer raised (testcafe-hammerhead/#1452) - A script error is no longer raised on pages that contain a
beforeunload
handler (testcafe-hammerhead/#1419) - Fixed wrongly overridding an event object (testcafe-hammerhead/#1445)
- An illegal invocation error is no longer raised when calling the
FileListWrapper.item
method (testcafe-hammerhead/#1446) by @javiercbk - A script error is no longer raised when
Node.nextSibling
isnull
(testcafe-hammerhead/#1469) - The
isShadowUIElement
check is performed forNode.nextSibling
when a node is not an element (testcafe-hammerhead/#1465) - The
toString
function is overridden for anchor elements (testcafe-hammerhead/#1483)
Chrome DevTools are opened in a separate window during test execution (#1964)
- In Chrome, disabled showing the 'Save password' prompt after typing text in the
password
input (#1913) - TestCafe correctly scrolls a page to an element when this page has scrollbars (#1955)
- Fixed the 'Cannot redefine property %testCafeCore%' script error (#1996)
- TestCafe rounds off dimension values when it calculates scrolling (#2004)
- In Chrome, the 'Download multiple files' dialog no longer prevents the test execution process (#2017)
- TestCafe closes a connection to the specified resource if the destination server hangs (testcafe-hammerhead/#1384)
- Proxying the
location's
href
property works correctly (testcafe-hammerhead/#1362) - The proxy supports
https
requests for node 8.6 and higher (testcafe-hammerhead/#1401) - Added support for pages with the
super
keyword (testcafe-hammerhead/#1390) - The proxy emulates native browser behavior for non-success status codes (testcafe-hammerhead/#1397)
- The proxied
ServiceWorker.register
method returns a rejected Promise for unsecure URLs (testcafe-hammerhead/#1411) - Added support for
javascript
protocol expressions applied to the location's properties (testcafe-hammerhead/#1274)
Vulnerability Fix (testcafe-legacy-api/#26)
We have fixed a vulnerability related to the dependency on uglify-js v1.x. We used it in our testcafe-legacy-api module that provides backward compatibility with older APIs from the paid TestCafe version.
This vulnerability affected only those who run tests created with the commercial version of TestCafe in the new open-source TestCafe.
⚙️ WebSockets support (testcafe-hammerhead/#911)
TestCafe provides full-featured WebSocket support (wss
and ws
protocols, request authentication, etc.).
- You can click on elements under the Status bar and specify the
transition
css property (#1934) - Added support for pages with the
rest
anddefault parameter
instructions (testcafe-hammerhead/#1336) - Pages with several
base
tags are supported (testcafe-hammerhead/#1349) - Redirects from cross-domain to same-domain pages are processed (#1922)
- Contenteditable custom elements are correctly recognized (testcafe-hammerhead/#1366)
- Internal headers for
fetch
requests are set correctly (testcafe-hammerhead/#1360)
- Readonly instrumented DOM properties are now set correctly for plain objects (testcafe-hammerhead/#1351).
- The
HTMLElement.style
property is proxied on the client side now (testcafe-hammerhead/#1348). - The
Refresh
response header is proxied now (testcafe-hammerhead/#1354).
- Screenshots are captured correctly when using High DPI monitor configurations on Windows (#1896)
- Fixed the
Cannot read property 'getItem' of null
error which is raised when a console message was printed in an iframe before it is completely loaded (#1875) - Fixed the
Content iframe did not load
error which is raised if an iframe reloaded during theswitchToIframe
command execution (#1842) - Selector options are passed to all derivative selectors (#1907)
- Fixed a memory leak in IE related to live node collection proxying (testcafe-hammerhead/#1262)
DocumentFragment
nodes are correctly processed (testcafe-hammerhead/#1334)
--reporter flag name fixed (#1881)
In v0.18.0, we accidentally changed the --reporter CLI flag to --reporters
. In this recovery release, we roll back to the previous flag name.
Compatibility with RequireJS restored (#1874)
Changes in v0.18.0 made TestCafe incompatible with RequireJS. It is fixed in this recovery release.
We apologize for any inconvenience.
We have added support for headless testing in Firefox (version 56+) and Chrome.
testcafe firefox:headless tests/sample-fixture.js
runner
.src('tests/sample-fixture.js')
.browsers('firefox:headless')
.run()
.then(failedCount => {
// ...
});
⚙️ Outputting test results to multiple channels (#1412)
You can now print a report in the console and saved it to a .json
file by specifying multiple reporters when running tests.
testcafe all tests/sample-fixture.js -r spec,json:report.json
const stream = fs.createWriteStream('report.json');
runner
.src('tests/sample-fixture.js')
.browsers('chrome')
.reporter('spec')
.reporter('json', stream)
.run()
.then(failedCount => {
stream.end();
});
⚙️ Entering the debug mode when a test fails (#1608)
TestCafe can now automatically switch to the debug mode when a test fails. Test execution is paused so that you can explore the tested page to determine the failure's cause.
To enable this behavior, use the --debug-on-fail
flag in the command line or the debugOnFail
option in the API.
testcafe chrome tests/fixture.js --debug-on-fail
runner.run({ debugOnFail: true });
⚙️ Interacting with the tested page in debug mode (#1848)
When debugging your tests, you can now interact with the tested page. Click the Unlock page button in the page footer to enable interaction.
Click Resume to continue running the test or click Next Step to skip to the next step.
⚙️ Chrome and Firefox are opened with clean profiles by default (#1623)
TestCafe now opens Chrome and Firefox with empty profiles to eliminate profile settings' and extensions' influence on tests.
However, you can return to the previous behavior using the :userProfile
browser option.
testcafe firefox:userProfile tests/test.js
runner
.src('tests/fixture1.js')
.browsers('firefox:userProfile')
.run();
⚙️ Customizable timeout to wait for the window.load
event (#1645)
Previously, TestCafe started a test when the DOMContentLoaded
event was raised. However, there are many pages that execute initialization code on the window.load
event (which is raised after DOMContentLoaded
because it waits for all stylesheets, images and subframes to load). In this case, you need to wait for the window.load
event to fire before running tests.
With this release, TestCafe waits 3
seconds for the window.load
event.
We have also added a pageLoadTimeout
setting that allows you to customize this interval.
You can set it to 0
to skip waiting for window.load
.
The following examples show how to use the pageLoadTimeout
setting from the command line and API:
testcafe chrome test.js --page-load-timeout 0
runner.run({
pageLoadTimeout: 0
});
You can also use the setPageLoadTimeout
method in the test API to set the timeout for an individual test.
fixture `Page load timeout`
.page `http://devexpress.github.io/testcafe/example/`;
test(`Page load timeout`, async t => {
await t
.setPageLoadTimeout(0)
.navigateTo('http://devexpress.github.io/testcafe/');
});
⚙️ Access messages output by the tested app to the browser console (#1738)
You can now obtain messages that the tested app outputs to the browser console. This is useful if your application or the framework it uses posts errors, warnings or other informative messages to the console.
Use the t.getBrowserConsoleMessages
method that returns the following object:
{
error: ["Cannot access the 'db' database. Wrong credentials.", '...'], // error messages
warn: ['The setTimeout property is deprecated', '...'], // warning messages
log: ['[09:12:08] Logged in', '[09:25:43] Changes saved', '...'], // log messages
info: ['The application was updated since your last visit.', '...'] // info messages
}
Note that this method returns only messages posted via the console.error
, console.warn
, console.log
and console.info
methods. Messages the browser outputs (like when an unhandled exception occurs on the page) are not returned.
For instance, you can use React's typechecking feature, PropTypes, to check that you assigned valid values to the component's props. If a PropTypes
rule is violated, React posts an error to the JavaScript console.
The following example shows how to check the React prop types for errors using the t.getBrowserConsoleMessages
method:
// check-prop-types.js
import { t } from 'testcafe';
export default async function () {
const { error } = await t.getBrowserConsoleMessages();
await t.expect(error[0]).notOk();
}
// test.js
import { Selector } from 'testcafe';
import checkPropTypes from './check-prop-types';
fixture `react example`
.page `http://localhost:8080/` // https://github.com/mzabriskie/react-example
.afterEach(() => checkPropTypes());
test('test', async t => {
await t
.typeText(Selector('.form-control'), 'devexpress')
.click(Selector('button').withText('Go'))
.click(Selector('h4').withText('Organizations'));
});
⚙️ Defining drag end point on the destination element (#982)
The t.dragToElement
action can now drop a dragged element at any point inside the destination element.
You can specify the target point using the destinationOffsetX
and destinationOffsetY
options.
import { Selector } from 'testcafe';
const fileIcon = Selector('.file-icon');
const directoryPane = Selector('.directory');
fixture `My Fixture`
.page `https://example.com/`;
test('My Test', async t => {
await t
.dragToElement(fileIcon, directoryPane, {
offsetX: 10,
offsetY: 10,
destinationOffsetX: 100,
destinationOffsetY: 50,
modifiers: {
shift: true
}
});
});
⚙️ TestCafe exits gracefully when the process is interrupted (#1378)
Previously, TestCafe left browsers open when you exited the process by pressing Ctrl+C
in the terminal.
Now TestCafe exits gracefully closing all browsers opened for testing.
- Tests no longer hang in Nightmare (#1493)
- The
focus
event is raised when clicking links withtabIndex="0"
(#1803) - Headless Chrome processes no longer hang after test runs (#1826)
setFilesToUpload
no longer throws aRangeError
on websites that use Angular (#1731)- Fixed a bug where an
iframe
got a wrong origin (#1753) document.open
does not throw an error ifdocument.defaultView
isnull
(testcafe-hammerhead/#1272)- No error is thrown when the handler passed to
addEventListener
isundefined
(testcafe-hammerhead/#1251) - An error is no longer raised if the processed element is not extendible (testcafe-hammerhead/#1300)
- Fixed a bug where an
onclick
handler did not work after click on aSubmit
button (testcafe-hammerhead/#1291) - Images with
style = background-image: url("img.png");
are loaded correctly (testcafe-hammerhead/#1212) - Documents can contain two
ShadowUI
roots (testcafe-hammerhead/#1246) - HTML in an overridden
document.write
function is processed correctly (testcafe-hammerhead/#1311) - Elements processing works for a
documentFragment
as it is added to the DOM (testcafe-hammerhead/#1334)
- Taking a screenshot on teamcity agent works correctly (#1625)
- It is possible to run tests on remote devices from a docker container (#1728)
- TestCafe compiles TypeScript tests correctly if Mocha or Jest typedefs are included in the project (#1537)
- Running on remote devices works correctly on MacOS (#1732)
- A target directory is checked before creating a screenshot (#1551)
- TypeScript definitions allow you to send any objects as
dependencies
forClientFunctions
(#1713) - The second
MutationObserver
callback argument is not missed (testcafe-hammerhead/#1268) - Link's
href
property with an unsupported protocol is set correctly (testcafe-hammerhead/#1276) - The
document.documentURI
property is processed correctly in IE (testcafe-hammerhead/#1270) JSON.stringify
andObject.keys
functions work properly for aMessageEvent
instance (testcafe-hammerhead/#1277)
- The
hover
action no longer fails for elements that hide on mouseover (#1679) - SelectText and SelectTextAreaContent TypeScript definitions match the documentation (#1697)
- TestCafe finds browsers installed for the current user on Windows (#1688)
- TestCafe can resize MS Edge 15 window (#1517)
- Google Chrome Canary has a dedicated
chrome-canary
alias (#1711) - Test no longer hangs when
takeScreenshot
is called in headless Chrome Canary on Windows (#1685) - Tests fail if the
uncaughtRejection
exception is raised (#1473) - TypeScript tests run on macOS with no errors (#1696)
- The test duration is reported accurately (#1674)
- XHR requests with an overridden
setRequestHeader
function returned by theXhrSandbox.openNativeXhr
method are now handled properly (testcafe-hammerhead/#1252) - HTML in an overridden
document.write
function is now processed correctly (testcafe-hammerhead/#1218) Object.assign
is overridden (testcafe-hammerhead/#1208)- Scripts with
async
functions are processed correctly (testcafe-hammerhead/#1260)
⚙️ Testing Electron applications (testcafe-browser-provider-electron)
We have created a browser provider that allows you to test Electron applications with TestCafe.
To do this, install the browser provider plugin from npm:
npm install testcafe-browser-provider-electron
Create a .testcafe-electron-rc
file that contains the Electron plugin's configurations.
The only required setting here is mainWindowUrl
. It is a URL (or path) to the main window page that relates to the application's directory.
{
"mainWindowUrl": "./index.html"
}
Place this file in the application root directory.
Next, install the Electron module.
npm install electron@latest
You can now run tests. Specify the electron
browser name and the application path
when the test launches.
testcafe "electron:/home/user/electron-app" "path/to/test/file.js"
testCafe
.createRunner()
.src('path/to/test/file.js')
.browsers('electron:/home/user/electron-app')
.run();
Nota that you can also test the Electron app's executable files. See the plugin readme to learn more about the Electron browser provider.
⚙️ Concurrent test execution (#1165)
We have added concurrent test launch. This makes a test batch complete faster.
TestCafe launches one instance of each specified browser by default. Tests are run one by one in each of them.
Enable concurrency and TestCafe launches multiple instances of each browser. It distributes the test batch among them. The tests are run in parallel.
To enable concurrency, add -c
in the command line or use the runner.concurrency()
API method.
Specify the number of instances for each browser.
testcafe -c 3 chrome tests/test.js
var testRunPromise = runner
.src('tests/test.js')
.browsers('chrome')
.concurrency(3)
.run();
See Concurrent Test Execution for more details.
⚙️ Further improvements in automatic waiting mechanism (#1521)
We have enhanced the waiting mechanism behavior in certain scenarios which required wait
actions.
⚙️ User roles preserve the local storage (#1454)
TestCafe now saves the local storage state when switching between roles. You get the same local storage content you left when you switch back.
This is useful for testing websites that perform authentication via local storage instead of cookies.
- Selector's
withAttribute
method supports searching by strict match (#1548) - Description for the
path
parameter of thet.takeScreenshot
action has been corrected (#1515) - Local storage is now cleaned appropriately after the test run.(#1546)
- TestCafe now checks element visibility with a timeout when the target element's
style.top
is negative (#1185) - Fetching an absolute CORS URL now works correctly. (#1629)
- Add partial support for proxying live node collections (the
GetElementsByTagName
method) (#1442) - TypeScript performance has been enhanced. (#1591)
- The right port is now applied to a cross-domain iframe location after redirect. (testcafe-hammerhead/#1191)
- All internal properties are marked as non-enumerable. (testcafe-hammerhead/#1182)
- Support proxying pages with defined referrer policy. (testcafe-hammerhead/#1195)
- WebWorker content is now correctly proxied in FireFox 54. (testcafe-hammerhead/#1216)
- Code instrumentation for the
document.activeElement
property works properly if it isnull
. (testcafe-hammerhead/#1226) length
,item
andnamedItem
are no longer own properties ofLiveNodeListWrapper
. (testcafe-hammerhead/#1222)- The
scope
option in theserviceWorker.register
function is processed correctly. (testcafe-hammerhead/#1233) - Promises from a fetch request are now processed correctly. (testcafe-hammerhead/#1234)
- Fix transpiling for the
for..of
loop to support browsers withoutwindow.Iterator
. (testcafe-hammerhead/#1231)
- Typing text now raises the
onChange
event in latest React versions. (#1558) - Screenshots can now be taken when TestCafe runs from the Docker image. (#1540)
- The native
value
property setters ofHTMLInputElement
andHTMLTextAreaElement
prototypes are now saved. (testcafe-hammerhead/#1185) - The
name
andnamedItem
methods of anHTMLCollection
are now marked as non-enumerable. (testcafe-hammerhead/#1172) - Code instrumentation of the
length
property runs faster. (testcafe-hammerhead/#979)
- A typo in RoleOptions typedefs was fixed (#1541)
- TestCafe no longer crashes on node 4 with an unmet dependency (#1547)
- Markup imported via
meta[rel="import"]
is now processed. (testcafe-hammerhead/#1161) - The correct context is passed to
MutationObserver
. (testcafe-hammerhead/#1178) - The
innerHtml
property is no longer processed for elements that don't have this property. (testcafe-hammerhead/#1164)
TypeScript support, seamless testing in headless Chrome and device emulator, and numerous bug fixes.
⚙️ TypeScript support (#408)
In this release, we have added the capability to write tests in TypeScript. By using TypeScript to write your TestCafe tests, you get the advantages of strongly-typed languages such as: rich coding assistance, painless scalability, check-as-you-type code verification, and much more.
TestCafe bundles TypeScript declaration file with the npm package, so you have no need to install any additional packages.
Just create a .ts
file with the
import { Selector } from 'testcafe';
and write your test.
For details, see TypeScript Support
⚙️ Support running in Chrome in headless mode and in device emulator (#1417)
Now TestCafe allows you to run your tests in Google Chrome in headless and device emulation modes.
Headless mode allows you to run tests in Chrome without any visible UI shell. To run tests in headless mode, use the :headless
postfix:
testcafe "chrome:headless" tests/sample-fixture.js
Device emulation mode allows you to check how your tests works on mobile devices via Chrome's built-in device emulator. To run tests in device emulation mode, specify emulation:
and device parameters:
testcafe "chrome:emulation:device=iphone 6" tests/sample-fixture.js
For details, see Using Chrome-specific Features.
⚙️ Support HTML5 Drag and Drop (#897)
Starting with this release, TestCafe supports HTML5 drag and drop, so you can test elements with the draggable
attribute.
⚙️ Fixed URL for opening remote browsers (#1476)
We have simplified the format of links that TestCafe generates when you run tests on remote browsers.
Now, you have no need to type a unique link for each test run, all the links became constant. So, it is easier now to run tests on a remote device repeatedly: you can run them by navigating a link from your browser history.
- No TestCafe UI on screenshots created during testing (#1357)
mouseenter
andmouseleave
events are not triggered during cursor moving (#1426)- The runner's speed option affects the speed of
doubleClick
action (#1486) - Press action shortcuts work wrong if input's value ends with '.' or starts with '-.' (#1499)
- A test report has too small line length on Travis (#1469)
- Service messages with cookies do not have enough time to come to server before a new page is loaded (testcafe-hammerhead/#1086)
- The
window.history.replaceState
function is overridden incorrectly (testcafe-hammerhead/#1146) - Hammerhead crashes if a script file contains a sourcemap comment (testcafe-hammerhead/#1052)
- The proxy should override the
DOMParser.parseFromString
method (testcafe-hammerhead/#1133) - The
fetch
method should emulate the native behaviour on merging headers (testcafe-hammerhead/#1116) - The
EventSource
requests are broken when used via proxy (testcafe-hammerhead/#1106) - The code processing may cause syntax errors in some cases because of wrong
location
property wrapping (testcafe-hammerhead/#1101) - When calling the
fetch
function without parameters, we should return its native result instead ofwindow.Promise.reject
(testcafe-hammerhead/#1099) - The
querySelector
function is overridden incorrectly (testcafe-hammerhead/#1131)
Plugins for React and Vue.js, TestCafe Docker image, support for Internet access proxies and lots of bug fixes.
We have changed the way the withText method behaves when it is called in a chain.
const el = Selector('div').withText('This is').withText('my element');
In previous versions, this selector searched for a div
with text my element
because the second call to withText
overrode the first one.
Now this code returns an element whose text contains both This is
and my element
as the second call compounds with the first one.
In this release cycle, we have created a plugin for testing React applications. This plugin allows you to select React components by their names.
import ReactSelector from 'testcafe-react-selector';
const TodoList = ReactSelector('TodoApp TodoList');
const itemsCountStatus = ReactSelector('TodoApp div');
const itemsCount = ReactSelector('TodoApp div span');
And it enables you to get React component's state
and props
.
import ReactSelector from 'testcafe-react-selector';
fixture `TODO list test`
.page('http://localhost:1337');
test('Check list item', async t => {
const el = ReactSelector('TodoList');
await t.expect(el.getReact().props.priority).eql('High');
await t.expect(el.getReact().state.isActive).eql(false);
});
To learn more, see the testcafe-react-selectors repository.
In addition to the React plugin, we have released a plugin that facilitates testing Vue.js applications.
In the same manner, it allows you to select Vue.js components with VueSelector
selectors.
import VueSelector from 'testcafe-vue-selectors';
const rootVue = VueSelector();
const todoInput = VueSelector('todo-input');
const todoItem = VueSelector('todo-list todo-item');
These selectors allow you to get Vue component's props
, state
and computed
properties.
import VueSelector from 'testcafe-vue-selector';
fixture `TODO list test`
.page('http://localhost:1337');
test('Check list item', async t => {
const todoItem = VueSelector('todo-item');
await t
.expect(todoItem.getVue().props.priority).eql('High')
.expect(todoItem.getVue().state.isActive).eql(false)
.expect(todoItem.getVue().computed.text).eql('Item 1');
});
To learn more, see the testcafe-vue-selectors repository.
⚙️ TestCafe Docker image (#1141)
We have created a Docker image with TestCafe, Chromium and Firefox preinstalled.
You no longer need to manually install browsers or the testing framework on your server. Pull the Docker image from the repository and run TestCafe immediately.
docker pull testcafe/testcafe
docker run -v //user/tests:/tests -it testcafe/testcafe firefox tests/**/*.js
To learn more, see Using TestCafe Docker Image
⚙️ Support for Internet access proxies (#1206)
If your local network uses a proxy server to access the Internet, TestCafe can use it reach the external webpages.
To specify the proxy server, use a command line option
testcafe chrome my-tests/**/*.js --proxy 172.0.10.10:8080
or a method in the API.
runner.useProxy('username:[email protected]');
Note that you can pass the credentials with the proxy server host.
⚙️ Debugging mode option (#1347)
As an alternative to calling the t.debug method
in test code, you can now specify the --debug-mode
command line option to pause the test before the first action or assertion.
When the test is paused, you can debug in the browser developer tools as well as continue test execution step by step.
testcafe chrome my-tests/**/*.js --debug-mode
If you use TestCafe API, provide the debugMode
option to the runner.run
method.
runner.run({ debugMode: true });
⚙️ Filtering selector's matching set by attribute (#1346)
You can now use the withAttribute
method to select elements that have a particular attribute set to a specific value.
You can omit the attribute value to select elements that simply have the specified attribute.
const el = Selector('div').withAttribute('attributeName', 'value').nth(2);
⚙️ hasAttribute method added to DOM node state (#1045)
For you convenience, the DOM node state object now provides the hasAttribute
method that allows you to determine if an element has a particular attribute.
const el = Selector('div.button');
t.expect(el.hasAttribute('disabled')).ok();
⚙️ Redirection when switching between roles (#1339)
User roles now provide a preserveUrl
option
that allows you to save the webpage URL to which the browser was redirected after logging in. If you enable this option when creating a role,
the browser will be redirected to the saved URL every time you switch to this role.
const regularUser = Role(url, async t => {
/* authentication code */
}, { preserveUrl: true })
- Fixed a bug where incorrect call site and callstack were generated for an assertion that failed in a class method (#1267)
- Incorrect validation result no longer appears when a test controller is used inside an async function (#1285)
- Click on the status panel no longer affects the page state (#1389)
- The
input
event is now raised with a correct selection value when input value was changed (#1388) - Inline source maps are now placed in transpiled files so that breakpoints work correctly (#1375)
value
andselectedIndex
in theinput
event handler for the dropdown element are now valid (#1366)- A
presskey('enter')
call now raises theclick
event on a button element (#1424) - The cursor position in Monaco editor is now set correctly on the click action (#1385)
hasScroll
now works correctly if thebody
has absolute positioning (#1353)- Text can now be typed into HTML5 input elements (#1327)
focusin
andfocusout
events are now raised when the browser window is in the background (testcafe-hammerhead/#1044)caretPositionFromPoint
andcaretRangeFromPoint
now ignore TestCafe UI elements on the page (testcafe-hammerhead/#1084)- Images created with the
Image
constructor are now loaded through the proxy (testcafe-hammerhead/#1087) - The
innerText
return value is now clear of script and style code (testcafe-hammerhead/#1079) - Non-string values for element's text properties are now converted to
String
(testcafe-hammerhead/#1091) - SVG elements are now processed correctly in IE (testcafe-hammerhead/#1083)
Authentication via user roles, client-side debugging and numerous bug fixes.
⚙️ Authentication via user roles (#243)
Many test scenarios involve the activity of more than one user. TestCafe addresses these scenarios by providing a convenient way to isolate authentication test actions and apply them easily whenever you need to switch the user account.
A piece of logic that logs in a particular user is called a role. It is a good practice to create a role for each user account participating in your test.
Create roles via the Role
constructor. You can keep them in a separate helper file.
helper.js
import { Role } from 'testcafe';
export var regularAccUser = Role('http://example.com/login', async t => {
await t
.typeText('#login', 'TestUser')
.typeText('#password', 'testpass')
.click('#sign-in');
});
export var facebookAccUser = Role('http://example.com/login', async t => {
await t
.click('#sign-in-with-facebook')
.typeText('#email', '[email protected]')
.typeText('#pass', 'testpass')
.click('#submit');
});
export var admin = Role('http://example.com/login', async t => {
await t
.typeText('#login', 'Admin')
.typeText('#password', 'adminpass')
.click('#sign-in');
});
In test code, use the t.useRole
method to switch between roles.
test.js
import { regularAccUser, admin } from './helper';
import { Selector } from 'testcafe';
const entry = Selector('#entry');
const removeButton = Selector('#remove-entry');
fixture `My Fixture`
.page `http://example.com`;
test('test that involves two users', async t => {
await t
.useRole(regularAccUser)
.expect(entry.exists).ok()
.expect(removeButton.visible).notOk()
.useRole(admin)
.expect(removeButton.visible).ok()
.click(removeButton)
.expect(entry.exists).notOk()
});
To learn more, see User Roles.
We have released the BrowserStack browser provider plugin.
Install this plugin from npm
.
npm install testcafe-browser-provider-browserstack
And save the BrowserStack username and access key to environment variables BROWSERSTACK_USERNAME
and BROWSERSTACK_ACCESS_KEY
.
Now you can run tests on any virtual machine available on BrowserStack.
testcafe "browserstack:[email protected]:Windows 10" "path/to/test/file.js"
⚙️ Client-side debugging (#918)
We have added a new t.debug
method to debug test behavior on the client.
When test execution reaches t.debug
, it pauses so that you can open browser's developer tools
and check the web page state, DOM elements location, their CSS styles.
fixture `My fixture`
.page `https://devexpress.github.io/testcafe/example`;
test('My test', async t => {
await t
.debug()
.setNativeDialogHandler(() => true)
.click('#populate')
.click('#submit-button');
});
In the footer, you'll find buttons that allow you to continue test execution or step to the next test action.
TestCafe logs points in code where the debugger stopped.
⚙️ Testing local webpages (#1286)
You can now run tests against local webpages. To do this, specify a URL with the file://
scheme or a relative path when calling the page function.
fixture `MyFixture`
.page `file:///user/my-website/index.html`;
fixture `MyFixture`
.page `../my-project/index.html`;
You can also navigate to local pages with the t.navigateTo action.
fixture `My fixture`
.page `http://www.example.com/`;
test('Navigate to local pages', async t => {
await t
.navigateTo('file:///user/my-website/index.html')
.navigateTo('../my-project/index.html');
});
⚙️ Adding custom methods to the selector (#1212)
You can now extend selectors with custom methods executed on the client. Use the addCustomMethods method to provide custom methods.
const myTable = Selector('.my-table').addCustomMethods({
getCellText: (table, rowIndex, columnIndex) =>
table.rows[rowIndex].cells[columnIndex].innerText
});
await t.expect(myTable.getCellText(1, 1)).contains('hey!');
Use this feature to build selectors that reflect the specifics of your web app.
⚙️ Removing the native dialog handler (#243)
We have added the capability to remove a native dialog handler by passing null
to the t.setNativeDialogHandler
method.
fixture `My fixture`
.page `https://devexpress.github.io/testcafe/example`;
test('My test', async t => {
await t
.setNativeDialogHandler(() => true)
.click('#populate')
.setNativeDialogHandler(null)
.click('#submit-button');
});
- Fixed a bug that led to an incorrect callstack in test run report (#1226)
- Cursor is now hidden on screenshots created using the
t.takeScreenshot
action (#1245) - Error no longer appears when selecting a non-existent child by index (#1240)
- The blur event is now raised on time when an input is hidden in IE (#1275)
- TestCafe no longer fails if a client function argument contains ES6 class method syntax (#1279)
- TestCafe now reports errors that occur during browser provider initialization (#1282)
- Click on the debugger panel no longer affects the tested page (#1200)
- An unhandled error no longer occurs when running a fixture without tests (#1302)
- The
input
event is now raised when the value of aselect
element is changed (#1311) - You can now perform actions with ShadowDOM elements (#1312)
- Server no longer responds with status 222 when window.fetch() is called in Chrome (#1134)
- The JSON reporter no longer returns
screenshotPath: null
if a screenshot path is not specified (#1269) - The
navigateTo
action no longer fails silently with schemes likehttp*string*://
(#965) - The SVG
use
tag is no longer broken when the parent page has afile://
URL (testcafe-hammerhead/#1051) - Fixed a bug where
toString
was used instead ofinstanceToString
from DOM utils (testcafe-hammerhead/#1055) - File download is no longer raised if the resource is fetched by setting the script src (testcafe-hammerhead/#1062)
- Fixed wrong CORS emulation for
fetch
requests (testcafe-hammerhead/#1059) Navigator.sendBeacon
function is now overridden (testcafe-hammerhead/#1035)
IDE plugins, fixture hooks, speed
option for test actions, a couple of API enhancements and lots of bug fixes.
With this release, we have prepared test runner plugins for VSCode and SublimeText. These plugins allow you to
- Run a particular test, fixture, all tests in a file or directory via the context menu or built-in commands,
- Automatically detect browsers installed on the local machine,
- Repeat last test run,
- Debug tests,
- View test results in the
Debug Console
panel.
⚙️ Fixture hooks (#903)
You can now specify fixture hooks that will be executed before the first test in a fixture is started and after the last test is finished.
fixture `My fixture`
.page `http://example.com`
.before( async ctx => {
/* fixture initialization code */
})
.after( async ctx => {
/* fixture finalization code */
});
Unlike test hooks, fixture hooks are executed between test runs and do not have access to the tested page. Use them to perform server-side operations like preparing the server that hosts the tested app.
Use the ctx
parameter passed to fixture.before
and fixture.after
methods (fixture context) to share values and objects with test code.
You can assign to ctx
parameter's properties or add new properties.
In test code, use the t.fixtureCtx
property to access the fixture context.
fixture `Fixture1`
.before(async ctx => {
ctx.someProp = 123;
})
.after(async ctx => {
console.log(ctx.newProp); // > abc
});
test('Test1', async t => {
console.log(t.fixtureCtx.someProp); // > 123
});
test('Test2', async t => {
t.fixtureCtx.newProp = 'abc';
});
⚙️ Speed option for test actions (#865)
You can now specify speed for individual test actions using the speed
option.
import { Selector } from 'testcafe';
const nameInput = Selector('#developer-name');
fixture `My Fixture`
.page `http://devexpress.github.io/testcafe/example/`
test('My Test', async t => {
await t
.typeText(nameInput, 'Peter')
.typeText(nameInput, ' Parker', { speed: 0.1 });
});
If speed is also specified for the whole test, the action speed setting overrides test speed.
⚙️ Setting test speed from test code (#865)
You can now specify test speed from code using the t.setTestSpeed
method.
import { Selector } from 'testcafe';
fixture `Test Speed`
.page `http://devexpress.github.io/testcafe/example/`;
const nameInput = Selector('#developer-name');
test(`Test Speed`, async t => {
await t
.typeText(nameInput, 'Peter')
.setTestSpeed(0.1)
.typeText(nameInput, ' Parker');
});
⚙️ Using test controller outside of test code (#1166)
You may sometimes need to call test API from outside of test code. For instance, your page model can contain methods that perform common operations used in many tests, like authentication.
import { Selector } from 'testcafe';
export default class Page {
constructor () {
this.loginInput = Selector('#login');
this.passwordInput = Selector('#password');
this.signInButton = Selector('#sign-in-button');
}
async login (t) {
await t
.typeText(this.loginInput, 'MyLogin')
.typeText(this.passwordInput, 'Pa$$word')
.click(this.signInButton);
}
}
In this instance, you need to access the test controller from the page model's login
method.
TestCafe allows you to avoid passing the test controller to the method explicitly.
Instead, you can simply import t
to the page model file.
import { Selector, t } from 'testcafe';
export default class Page {
constructor () {
this.loginInput = Selector('#login');
this.passwordInput = Selector('#password');
this.signInButton = Selector('#sign-in-button');
}
async login () {
await t
.typeText(this.loginInput, 'MyLogin')
.typeText(this.passwordInput, 'Pa$$word')
.click(this.signInButton);
}
}
TestCafe will implicitly resolve test context and provide the right test controller.
The new paste
option allows you to insert a portion of text with one keystroke, similar to the paste operation.
import { Selector } from 'testcafe';
fixture `My fixture`
.page `http://devexpress.github.io/testcafe/example/`;
const nameInput = Selector('#developer-name');
test(`My test`, async t => {
await t
.typeText(nameInput, 'Peter')
.typeText(nameInput, ' Parker', { paste: true });
});
⚙️ prevSibling and nextSibling selector's DOM search methods (#1218)
The new prevSibling
and nextSibling
methods allow you to search among sibling elements that reside before and after the selector's matching elements in the DOM tree.
Selector('li .active').prevSibling(2);
Selector('li').nextSibling('.checked');
⚙️ Deprecated functionality removed (#1167)
The following deprecated members have been removed from the API.
t.select
method - useSelector
instead:
const id = await t.select('.someClass').id;
// can be replaced with
const id = await Selector('.someClass').id;
selectorOptions.index
- use selector.nth() instead.selectorOptions.text
- use selector.withText() instead.selectorOptions.dependencies
- use filtering and hierarchical methods to build combined selectors instead.
- Fixed a bug where tests failed with a script error (#1188)
- Text can now be typed to an input field with type "email" in Firefox (#1187)
npm install
no longer displays warnings (#769)- Dev Tools can now be opened with a keyboard shortcut or right click on macOS (#1193)
- A warning no longer appears when using ClientFunction with dependencies (#1168)
- Tests can now run against React Storybook (#1147)
- Script error is no longer thrown in iOS webviews (Firefox, Chrome of iOS) (#1189)
- XhrSandbox.createNativeXHR now works correctly (testcafe-hammerhead/#1042)
- Window.prototype is no longer used for NativeMethods initialization (testcafe-hammerhead/#1040)
- Functions from the 'vm' module are now overridden on the client (testcafe-hammerhead/#1029)
- Input type is now changed while setting the selection range in Firefox (testcafe-hammerhead/#1025)
- An iframe with the
about:blank
src can now sendpostMessage
(testcafe-hammerhead/#1026) - The
formaction
attribute is now overridden correctly after it is appended in DOM (testcafe-hammerhead/#1021) - Fixed a bug where the Authorization Header was wrongly removed (testcafe-hammerhead/#1016)
- The
file://
protocol is now supported (testcafe-hammerhead/#908)
🏎️ A recovery release following v0.12.0 with an important fix. 🏎️
- Fixed a bug when the cursor was not visible while running tests (#1156).
HTTP authentication support, a CI-friendly way to start and stop the tested app and lots of API enhancements.
TestCafe now supports testing webpages protected with HTTP Basic and NTLM authentication.
Use the httpAuth function in fixture or test declaration to specify the credentials.
fixture `My fixture`
.page `http://example.com`
.httpAuth({
username: 'username',
password: 'Pa$$word',
// Optional parameters, can be required for the NTLM authentication.
domain: 'CORP-DOMAIN',
workstation: 'machine-win10'
});
test('Test1', async t => {}); // Logs in as username
test // Logs in as differentUserName
.httpAuth({
username: 'differentUserName',
password: 'differentPa$$word'
})
('Test2', async t => {});
⚙️ Built-in CI-friendly way to start and stop the tested web app (#1047)
When launching tests, you can now specify a command that starts the tested application. TestCafe will automatically execute this command before running tests and stop the process when tests are finished.
testcafe chrome tests/ --app "node server.js"
runner
.startApp('node server.js')
.run();
You can also specify how long TestCafe should wait until the tested application initializes (the default is 1 sec).
testcafe chrome tests/ --app "node server.js" --app-init-delay 4000
runner
.startApp('node server.js', 4000)
.run();
⚙️ Screenshot and window resize actions now work on Linux (#1117)
The t.takeScreenshot
, t.resizeWindow
, t.resizeWindowToFitDevice
and t.maximizeWindow
actions can now be executed on Linux machines.
⚙️ Adding custom properties to the element state (#749)
The state of webpage elements can now be extended with custom properties.
We have added the addCustomDOMProperties method to the selector, so that you can add properties to the element state like in the following example.
import { Selector } from 'testcafe'
fixture `My fixture`
.page `https://devexpress.github.io/testcafe/example/`;
test('Check Label HTML', async t => {
const label = Selector('label').addCustomDOMProperties({
innerHTML: el => el.innerHTML
});
await t.expect(label.innerHTML).contains('input type="checkbox" name="remote"');
});
⚙️ Skipping tests (#246)
TestCafe now allows you to specify that a particular test or fixture should be skipped when running tests.
Use the fixture.skip
and test.skip
methods for this.
fixture.skip `Fixture1`; // All tests in this fixture will be skipped
test('Fixture1Test1', () => {});
test('Fixture1Test2', () => {});
fixture `Fixture2`;
test('Fixture2Test1', () => {});
test.skip('Fixture2Test2', () => {}); // This test will be skipped
test('Fixture2Test3', () => {});
You can also use the only
method to specify that only a particular test or fixture should run while all others should be skipped.
fixture.only `Fixture1`;
test('Fixture1Test1', () => {});
test('Fixture1Test2', () => {});
fixture `Fixture2`;
test('Fixture2Test1', () => {});
test.only('Fixture2Test2', () => {});
test('Fixture2Test3', () => {});
// Only tests in Fixture1 and the Fixture2Test2 test will run
⚙️ Specifying the start webpage for a test (#501)
An individual test can now override the fixture's page
setting and start on a different page.
fixture `MyFixture`
.page `http://devexpress.github.io/testcafe/example`;
test('Test1', async t => {
// Starts at http://devexpress.github.io/testcafe/example
});
test
.page `http://devexpress.github.io/testcafe/blog/`
('Test2', async t => {
// Starts at http://devexpress.github.io/testcafe/blog/
});
⚙️ Initialization and finalization methods for a test (#1108)
We have added the before and after methods to the test declaration. Use them to provide code that will be executed before a test is started and after it is finished.
test
.before( async t => {
/* test initialization code */
})
('My Test', async t => {
/* test code */
})
.after( async t => {
/* test finalization code */
});
⚙️ Sharing variables between hooks and test code (#841)
You can now share variables between fixture.beforeEach
, fixture.afterEach
, test.before
, test.after
functions and test code
by using the test context object.
Test context is available through the t.ctx
property.
Instead of using a global variable, assign the object you want to share directly to t.ctx
or create a property like in the following example.
fixture `Fixture1`
.beforeEach(async t => {
t.ctx.someProp = 123;
});
test
('Test1', async t => {
console.log(t.ctx.someProp); // > 123
})
.after(async t => {
console.log(t.ctx.someProp); // > 123
});
⚙️ Assertion methods to check for regexp match (#1038)
We have added match
and notMatch
methods to check if a string matches a particular regular expression.
await t.expect('foobar').match(/^f/, 'this assertion passes');
await t.expect('foobar').notMatch(/^b/, 'this assertion passes');
Selector's filter predicates now receive more information about the current node, which enables you to implement more advanced filtering logic.
The filter
, find
, parent
, child
and sibling
methods now pass the node's index to the predicate.
The find
, parent
, child
and sibling
methods now also pass a node from the preceding selector.
Selector('ul').find((node, idx, originNode) => {
// node === the <ul>'s descendant node
// idx === index of the current <ul>'s descendant node
// originNode === the <ul> element
});
In addition, all these methods now allow you to pass objects to the predicate's scope on the client. To this end, we have added
an optional dependencies
parameter.
const isNodeOk = ClientFunction(node => { /*...*/ });
const flag = getFlag();
Selector('ul').child(node => {
return isNodeOk(node) && flag;
}, { isNodeOk, flag });
⚙️ Filtering by negative index in selectors (#738)
You can now pass negative index
values to selector methods. In this instance, index is counted from the end of the matching set.
const lastChild = Selector('.someClass').child(-1);
⚙️ Improved cursor positioning in test actions (#981)
In action options, X and Y offsets that define the point where action is performed can now be negative. In this instance, the cursor position is calculated from the bottom-right corner of the target element.
await t.click('#element', { offsetX: -10, offsetY: -30 });
⚙️ Client functions as an assertion's actual value (#1009)
You can now pass client functions to assertion's expect
method. In this instance, the
Smart Assertion Query Mechanism
will run this client function and use the return value as the assertion's actual value.
import { ClientFunction } from 'testcafe';
const windowLocation = ClientFunction(() => window.location.toString());
fixture `My Fixture`
.page `http://www.example.com`;
test('My Test', async t => {
await t.expect(windowLocation()).eql('http://www.example.com');
});
⚙️ Automatic waiting for scripts added during a test action (#1072)
If a test action adds scripts on a page, TestCafe now automatically waits for them to finish before proceeding to the next test action.
⚙️ New ESLint plugin (#1083)
We have prepared an ESLint plugin. Get it to ensure that ESLint does not fail on TestCafe test code.
- Remote browser connection timeout has been increased (#1078)
- You can now run tests located in directories with a large number of files (#1090)
- Key identifiers for all keys are now passed to key events (#1079)
- Touch events are no longer emulated for touch monitors (#984)
- v8 flags can now be passed to Node.js when using TestCafe from the command line (#1006)
- ShadowUI root is now hidden for
elementFromPoint
in an iframe in IE (#1029) - Preventing the form submit event no longer leads to additional delay between actions (#1115)
- TestCafe no longer hangs when a cursor is moved out of a reloading iframe (#1140)
- Onclick event handler is now executed correctly during click automation in specific cases (#1138)
- The
application/pdf
mime type is no longer recognized as a page (testcafe-hammerhead#1014) - Limited support for the
frameset
tag is implemented (testcafe-hammerhead#1009) Function.prototype.toString
is now proxied correctly when it is overriden in a user script (testcafe-hammerhead#999)- Script processing no longer hangs on chained assignments (testcafe-hammerhead#866)
formaction
attribute is now processed (testcafe-hammerhead#988)document.styleSheets
is now overrided (testcafe-hammerhead#1000)href
attribute is now processed correctly in an iframe without src when it is set from the main window (testcafe-hammerhead#620)- Cookies without a key are now set correctly (testcafe-hammerhead#899)
- The
noscript
tag is now processed correctly when it was added viainnerHTML
(testcafe-hammerhead#987) Element.insertAdjacentHTML
function is now overrided in IE (testcafe-hammerhead#954)- Browser behaviour is now emulated correctly when the cookie size is bigger than the browser limit (testcafe-hammerhead#767)
🏎️ A quick follow-up for the v0.11.0 with important fix for Firefox users. 🏎️
- Firefox now launches successfully if TestCafe installation directory contains whitespaces (#1042).
⚙️ Redesigned selector system. (#798)
Multiple filtering and hierarchical methods were introduced for selectors. Now you can build flexible, lazily-evaluated functional-style selector chains.
Here are some examples:
Selector('ul').find('label').parent('div.someClass')
Finds all ul
elements on page. Then, in each found ul
element finds label
elements.
Then, for each label
element finds a parent that matches the div.someClass
selector.
Like in jQuery, if you request a property of the matching set or try evaluate a snapshot, the selector returns values for the first element in the set.
// Returns id of the first element in the set
const id = await Selector('ul').find('label').parent('div.someClass').id;
// Returns snapshot for the first element in the set
const snapshot = await Selector('ul').find('label').parent('div.someClass')();
However, you can obtain data for any element in the set by using nth
filter.
// Returns id of the third element in the set
const id = await Selector('ul').find('label').parent('div.someClass').nth(2).id;
// Returns snapshot for the fourth element in the set
const snapshot = await Selector('ul').find('label').parent('div.someClass').nth(4)();
Note that you can add text and index filters in the selector chain.
Selector('.container').parent(1).nth(0).find('.content').withText('yo!').child('span');
In this example the selector:
- finds the second parent (parent of parent) of
.container
elements; - peeks the first element in the matching set;
- in that element, finds elements that match the
.content
selector; - filters them by text
yo!
; - in each filtered element, searches for a child with tag name
span
.
Also, now you can get selector matching set length and check matching elements existence by using selector count
and exists
properties.
Previously selector call outside of text context thrown an error:
const selector = Selector(arg => /* selector code */);
selector('someArg'); // <-- throws
test ('Some test', async t=> {
...
});
Now it's not a case if selector is not awaited. It's useful when you need to build a page model outside the test context:
const selector = Selector(arg => /* selector code */);
const selector2 = selector('someArg').find('span'); // <-- doesn't throw anymore
test ('Some test', async t=> {
...
});
However, once you'll try to obtain element property outside of test context it will throw:
const selector = Selector(arg => /* selector code */);
async getId() {
return await selector('someArg').id; // throws
}
getId();
test ('Some test', async t=> {
...
});
Previously if selector returned single node index
was ignored:
Selector('#someId', { index: 2 } ); // index is ignored and selector returns element with id `someId`
however it's not a case now:
Selector('#someId').nth(2); // returns `null`, since there is only one element in matching set with id `someId`
t.select
method - useSelector
instead:
const id = await t.select('.someClass').id;
// can be replaced with
const id = await Selector('.someClass').id;
- selectorOptions.index - use selector.nth() instead.
- selectorOptions.text - use selector.withText() instead.
- selectorOptions.dependencies - use filtering and hierarchical methods to build combined selectors instead.
⚙️ Built-in assertions. (#998)
TestCafe now ships with numerous built-in BDD-style assertions. If the TestCafe assertion receives a Selector's property as an actual value, TestCafe uses the smart assertion query mechanism: if an assertion did not passed, the test does not fail immediately. The assertion retries to pass multiple times and each time it re-requests the actual shorthand value. The test fails if the assertion could not complete successfully within a timeout. This approach allows you to create stable tests that lack random errors and decrease the amount of time required to run all your tests due to the lack of extra waitings.
Example page markup:
<div id="btn"></div>
<script>
var btn = document.getElementById('btn');
btn.addEventListener(function() {
window.setTimeout(function() {
btn.innerText = 'Loading...';
}, 100);
});
</script>
Example test code:
test('Button click', async t => {
const btn = Selector('#btn');
await t
.click(btn)
// Regular assertion will fail immediately, but TestCafe retries to run DOM state
// assertions many times until this assertion pass successfully within the timeout.
// The default timeout is 3000 ms.
.expect(btn.textContent).contains('Loading...');
});
⚙️ It's now possible to start browser with arguments. (#905)
If you need to pass arguments for the specified browser, write them right after browser alias. Surround the browser call and its arguments with quotation marks:
testcafe "chrome --start-fullscreen",firefox tests/test.js
See Starting browser with arguments.
- Action keyboard events now have
event.key
andevent.keyIdentifier
properties set (#993). document.body.nextSibling
, that was broken is some cases previously, now operates properly (#958).- Now it's possible to use
t.setFilesToUpload
andt.clearUpload
methods with the hidden inputs (#963). - Now test not hangs if object
toString
method usesthis.location
getter (#953). - Touch events now correctly dispatched in latest Chrome versions with touch monitor (#944).
- Now test compilation doesn't fail if imported helper contains module re-export (e.g.
export * from './mod'
) (#969). - Actions now scroll to element to make it completely visible (there possible) (#987, #973).
- Dispatched key events now successfully pass
instanceof
check (#964). - Ember elements doesn't throw
Uncaught TypeError: e.getAttribute is not a function
anymore (#966). - First run wizards now automatically disabled in Chrome in Firefox (testcafe-browser-tools#102).
<td>
now correctly focused on actions (testcafe-hammerhead#901).document.baseURI
now returns correct value (testcafe-hammerhead#920).Function.constructor
now returns correct value (testcafe-hammerhead#913).- Setting
location
to the URL hash value doesn't lead to JavaScript error anymore (testcafe-hammerhead#917). - Fixed corruption of
<template>
content (testcafe-hammerhead#912). - Fixed
querySelector
forhref
attribute if value contains URL hash (testcafe-hammerhead#922). - HTTP responses with Brotli encoding now processed correctly (testcafe-hammerhead#900).
Element.attributes
now behaves as a live collection (testcafe-hammerhead#924).- TestCafe doesn't fail with
Error: Can't set headers after they are sent.
error on network errors (testcafe-hammerhead#937). - Element property value setters now return correct value (testcafe-hammerhead#907).
window.fetch
without parameters now returns rejected promise as expected (testcafe-hammerhead#939).- Hyperlinks created in iframe and added to the top window now have correct URL (testcafe-hammerhead#564).
autocomplete
attribute now not forced on all elements (testcafe-hammerhead#955).- Cookies set via XHR response now available from client code (testcafe-hammerhead#905).
- Fixed client rendering problems caused by incorrect DOM element determination (testcafe-hammerhead#953).
⚙️ Snapshot API shorthands. (#771)
Previously, if you needed to use a single property from the snapshot, you had to introduce two assignments
const snapshot = await selector();
const nodeType = snapshot.nodeType;
or additional parentheses.
const nodeType = (await selector()).nodeType;
Now snapshot methods and property getters are exposed by selectors (and selector promises as well) so that you can write more compact code.
const nodeType = await selector.nodeType;
// or
const nodeType = await selector('someParam').nodeType;
However, shorthand properties do not allow you to omit parentheses when working with dictionary properties
like style
, attributes
or boundingClientRect
.
const width = (await selector.style)['width'];
That is why we have also introduced shorthand methods for these dictionaries: getStyleProperty
, getAttribute
and getBoundingClientRectProperty
.
const width = await selector.getStyleProperty('width');
const id = await selector.getAttribute('id');
const left = await selector.getBoundingClientRectProperty('left');
Finally, we have added the hasClass
method.
if (await selector.hasClass('foo')) {
//...
}
⚙️ Improved automatic wait mechanism. (#245)
We got rid of unnecessary waiting so that tests now run almost two times faster.
⚙️ Test execution speed control. (#938)
We have introduced an option that allows you to specify how fast tests run.
By default, tests run at the maximum speed. However, if you need to watch a test running to understand what happens in it,
this speed may seem too fast. In this instance, use the new speed
option to slow the test down.
This option is available from the command line
testcafe chrome my-tests --speed 0.1
and from the API.
await runner.run({
speed: 0.1
})
You can use factor values between 1
(the fastest, used by default) and 0.01
(the slowest).
⚙️ t.maximizeWindow
test action. (#812)
We have added a test action that maximizes the browser window.
import { expect } from 'chai';
import { Selector } from 'testcafe';
const menu = Selector('#side-menu');
fixture `My fixture`
.page `http://www.example.com/`;
test('Side menu is displayed in full screen', async t => {
await t.maximizeWindow();
expect(await menu.visible).to.be.ok;
});
- The
t.resizeWindow
andt.resizeWindowToFitDevice
actions now work correctly on macOS (#816) - Browser aliases are now case insensitive in the command line (#890)
- Tests no longer hang if target scrolling coordinates are fractional (#882)
- The 'Element is not visible' error is no longer raised when scrolling a document in Quirks mode (#883)
<table>
child elements are now focused correctly (#889)- The page is no longer scrolled to the parent element when focusing on a non-focusable child during click automation (#913)
- Browser auto-detection now works with all the Linux distributions (#104, #915)
🎉 Initial release 🎉