added support for key modifiers to Casper#sendKeys()
Showing
7 changed files
with
114 additions
and
14 deletions
... | @@ -3,7 +3,7 @@ branches: | ... | @@ -3,7 +3,7 @@ branches: |
3 | - "master" | 3 | - "master" |
4 | - "1.0" | 4 | - "1.0" |
5 | before_script: | 5 | before_script: |
6 | - "npm install -g jshint@1.0.0" | 6 | - "npm install -g jshint@1.1.0" |
7 | - "phantomjs --version" | 7 | - "phantomjs --version" |
8 | - "export PHANTOMJS_EXECUTABLE='phantomjs --local-to-remote-url-access=yes --ignore-ssl-errors=yes'" | 8 | - "export PHANTOMJS_EXECUTABLE='phantomjs --local-to-remote-url-access=yes --ignore-ssl-errors=yes'" |
9 | script: | 9 | script: | ... | ... |
... | @@ -116,6 +116,7 @@ Last, all the casper test suites have been upgraded to use the new testing featu | ... | @@ -116,6 +116,7 @@ Last, all the casper test suites have been upgraded to use the new testing featu |
116 | - fixed [#441](https://github.com/n1k0/casperjs/issues/441) - added `--ssl-protocol` option support to the `casperjs` executable | 116 | - fixed [#441](https://github.com/n1k0/casperjs/issues/441) - added `--ssl-protocol` option support to the `casperjs` executable |
117 | - Added [`Casper#fillSelectors()`](http://docs.casperjs.org/en/latest/modules/casper.html#fillselectors) and [`Casper#fillXPath()`](http://docs.casperjs.org/en/latest/modules/casper.html#fillxpath) | 117 | - Added [`Casper#fillSelectors()`](http://docs.casperjs.org/en/latest/modules/casper.html#fillselectors) and [`Casper#fillXPath()`](http://docs.casperjs.org/en/latest/modules/casper.html#fillxpath) |
118 | - Added [`Casper#getElementsAttribute()`](http://docs.casperjs.org/en/latest/modules/casper.html#getelementsattribute) and [`Casper#getElementsInfo()`](http://docs.casperjs.org/en/latest/modules/casper.html#getelementsinfo) | 118 | - Added [`Casper#getElementsAttribute()`](http://docs.casperjs.org/en/latest/modules/casper.html#getelementsattribute) and [`Casper#getElementsInfo()`](http://docs.casperjs.org/en/latest/modules/casper.html#getelementsinfo) |
119 | - Added support for key modifiers to `Casper#sendKeys()` | ||
119 | - `cli`: Now dropping an arg or an option will be reflected in their *raw* equivalent | 120 | - `cli`: Now dropping an arg or an option will be reflected in their *raw* equivalent |
120 | - `cli.get()` now supports fallback values | 121 | - `cli.get()` now supports fallback values |
121 | 122 | ... | ... |
... | @@ -1419,12 +1419,37 @@ Sends native keyboard events to the element matching the provided :doc:`selector | ... | @@ -1419,12 +1419,37 @@ Sends native keyboard events to the element matching the provided :doc:`selector |
1419 | this.click('form.contact input[type="submit"]'); | 1419 | this.click('form.contact input[type="submit"]'); |
1420 | }); | 1420 | }); |
1421 | 1421 | ||
1422 | Note that ``sendKeys()`` by default will remove the focus on text input fields, which will typically close autocomplete widgets. If you want to maintain focus, use the ``keepFocus`` option. For example, if using jQuery-UI, you can click on the first autocomplete suggestion using:: | 1422 | .. versionadded:: 1.1 |
1423 | |||
1424 | Options | ||
1425 | ~~~~~~~ | ||
1426 | |||
1427 | - ``(Boolean) keepFocus``: | ||
1428 | |||
1429 | |||
1430 | ``sendKeys()`` by default will remove the focus on text input fields, which will typically close autocomplete widgets. If you want to maintain focus, us e the ``keepFocus`` option. For example, if using jQuery-UI, you can click on the first autocomplete suggestion using:: | ||
1431 | |||
1432 | casper.then(function() { | ||
1433 | this.sendKeys('form.contact input#name', 'action', {keepFocus: true}); | ||
1434 | this.click('form.contact ul.ui-autocomplete li.ui-menu-item:first- child a'); | ||
1435 | }); | ||
1436 | |||
1437 | - ``(String) modifiers``: | ||
1438 | |||
1439 | ``sendKeys()`` accepts a ``modifiers`` option to support key modifiers. The options is a string representing the composition of modifiers to use, separated by the ``+`` character:: | ||
1440 | |||
1441 | casper.then(function() { | ||
1442 | this.sendKeys('document', 's', {modifiers: 'ctrl+alt+shift'}); | ||
1443 | }); | ||
1444 | |||
1445 | Available modifiers are: | ||
1446 | |||
1447 | - ``ctrl`` | ||
1448 | - ``alt`` | ||
1449 | - ``shift`` | ||
1450 | - ``meta`` | ||
1451 | - ``keypad`` | ||
1423 | 1452 | ||
1424 | casper.then(function() { | ||
1425 | this.sendKeys('form.contact input#name', 'action', {keepFocus: true}); | ||
1426 | this.click('form.contact ul.ui-autocomplete li.ui-menu-item:first-child a'); | ||
1427 | }); | ||
1428 | 1453 | ||
1429 | .. index:: auth | 1454 | .. index:: auth |
1430 | 1455 | ... | ... |
... | @@ -965,7 +965,7 @@ Casper.prototype.getElementAttr = function getElementAttr(selector, attribute) { | ... | @@ -965,7 +965,7 @@ Casper.prototype.getElementAttr = function getElementAttr(selector, attribute) { |
965 | /** | 965 | /** |
966 | * Retrieves the value of an attribute for each element matching the provided | 966 | * Retrieves the value of an attribute for each element matching the provided |
967 | * DOM CSS3/XPath selector. | 967 | * DOM CSS3/XPath selector. |
968 | * | 968 | * |
969 | * @param String selector A DOM CSS3/XPath selector | 969 | * @param String selector A DOM CSS3/XPath selector |
970 | * @param String attribute The attribute name to lookup | 970 | * @param String attribute The attribute name to lookup |
971 | * @return Array | 971 | * @return Array |
... | @@ -1531,6 +1531,11 @@ Casper.prototype.runStep = function runStep(step) { | ... | @@ -1531,6 +1531,11 @@ Casper.prototype.runStep = function runStep(step) { |
1531 | /** | 1531 | /** |
1532 | * Sends keys to given element. | 1532 | * Sends keys to given element. |
1533 | * | 1533 | * |
1534 | * Options: | ||
1535 | * | ||
1536 | * - eventType: "keypress", "keyup" or "keydown" (default: "keypress") | ||
1537 | * - modifiers: a string defining the key modifiers, eg. "alt", "alt+shift" | ||
1538 | * | ||
1534 | * @param String selector A DOM CSS3 compatible selector | 1539 | * @param String selector A DOM CSS3 compatible selector |
1535 | * @param String keys A string representing the sequence of char codes to send | 1540 | * @param String keys A string representing the sequence of char codes to send |
1536 | * @param Object options Options | 1541 | * @param Object options Options |
... | @@ -1543,18 +1548,20 @@ Casper.prototype.sendKeys = function(selector, keys, options) { | ... | @@ -1543,18 +1548,20 @@ Casper.prototype.sendKeys = function(selector, keys, options) { |
1543 | eventType: 'keypress' | 1548 | eventType: 'keypress' |
1544 | }, options || {}); | 1549 | }, options || {}); |
1545 | var elemInfos = this.getElementInfo(selector), | 1550 | var elemInfos = this.getElementInfo(selector), |
1546 | tag = elemInfos.nodeName.toLowerCase(), | 1551 | tag = elemInfos.nodeName.toLowerCase(), |
1547 | type = utils.getPropertyPath(elemInfos, 'attributes.type'), | 1552 | type = utils.getPropertyPath(elemInfos, 'attributes.type'), |
1548 | supported = ["color", "date", "datetime", "datetime-local", "email", | 1553 | supported = ["color", "date", "datetime", "datetime-local", "email", |
1549 | "hidden", "month", "number", "password", "range", "search", | 1554 | "hidden", "month", "number", "password", "range", "search", |
1550 | "tel", "text", "time", "url", "week"]; | 1555 | "tel", "text", "time", "url", "week"], |
1551 | var isTextInput = false; | 1556 | isTextInput = false; |
1552 | if (tag === 'textarea' || (tag === 'input' && supported.indexOf(type) !== -1)) { | 1557 | if (tag === 'textarea' || (tag === 'input' && supported.indexOf(type) !== -1)) { |
1553 | // clicking on the input element brings it focus | 1558 | // clicking on the input element brings it focus |
1554 | isTextInput = true; | 1559 | isTextInput = true; |
1555 | this.click(selector); | 1560 | this.click(selector); |
1556 | } | 1561 | } |
1557 | this.page.sendEvent(options.eventType, keys); | 1562 | var modifiers = utils.computeModifier(options && options.modifiers, |
1563 | this.page.event.modifier) | ||
1564 | this.page.sendEvent(options.eventType, keys, null, null, modifiers); | ||
1558 | if (isTextInput && !options.keepFocus) { | 1565 | if (isTextInput && !options.keepFocus) { |
1559 | // remove the focus | 1566 | // remove the focus |
1560 | this.evaluate(function(selector) { | 1567 | this.evaluate(function(selector) { | ... | ... |
... | @@ -90,6 +90,30 @@ function clone(o) { | ... | @@ -90,6 +90,30 @@ function clone(o) { |
90 | exports.clone = clone; | 90 | exports.clone = clone; |
91 | 91 | ||
92 | /** | 92 | /** |
93 | * Computes a modifier string to its PhantomJS equivalent. A modifier string is | ||
94 | * in the form "ctrl+alt+shift". | ||
95 | * | ||
96 | * @param String modifierString Modifier string, eg. "ctrl+alt+shift" | ||
97 | * @param Object modifiers Modifiers definitions | ||
98 | * @return Number | ||
99 | */ | ||
100 | function computeModifier(modifierString, modifiers) { | ||
101 | "use strict"; | ||
102 | var modifier = 0, | ||
103 | checkKey = function(key) { | ||
104 | if (key in modifiers) return; | ||
105 | throw new CasperError(format('%s is not a supported key modifier', key)); | ||
106 | }; | ||
107 | if (!modifierString) return modifier; | ||
108 | var keys = modifierString.split('+'); | ||
109 | keys.forEach(checkKey); | ||
110 | return keys.reduce(function(acc, key) { | ||
111 | return acc | modifiers[key]; | ||
112 | }, modifier); | ||
113 | } | ||
114 | exports.computeModifier = computeModifier; | ||
115 | |||
116 | /** | ||
93 | * Dumps a JSON representation of passed value to the console. Used for | 117 | * Dumps a JSON representation of passed value to the console. Used for |
94 | * debugging purpose only. | 118 | * debugging purpose only. |
95 | * | 119 | * | ... | ... |
... | @@ -17,3 +17,25 @@ casper.test.begin('sendKeys() tests', 3, function(test) { | ... | @@ -17,3 +17,25 @@ casper.test.begin('sendKeys() tests', 3, function(test) { |
17 | test.done(); | 17 | test.done(); |
18 | }); | 18 | }); |
19 | }); | 19 | }); |
20 | |||
21 | casper.test.begin('sendKeys() key modifiers tests', 1, function(test) { | ||
22 | casper.start().then(function() { | ||
23 | this.setContent([ | ||
24 | '<input>', | ||
25 | '<script>var keys = []; window.addEventListener("keypress", function(e) {', | ||
26 | ' keys.push({code: e.which, alt: e.altKey, ctrl: e.ctrlKey});', | ||
27 | '})</script>' | ||
28 | ].join('')); | ||
29 | this.sendKeys('input', 'k'); | ||
30 | this.sendKeys('input', 'k', {modifiers: "ctrl"}); | ||
31 | this.sendKeys('input', 'k', {modifiers: "ctrl+alt"}); | ||
32 | test.assertEquals(this.getGlobal('keys'), | ||
33 | [ | ||
34 | {code: 107, alt: false, ctrl: false}, | ||
35 | {code: 107, alt: false, ctrl: true}, | ||
36 | {code: 107, alt: true, ctrl: true} | ||
37 | ], 'sendKeys() uses key modifiers'); | ||
38 | }).run(function() { | ||
39 | test.done(); | ||
40 | }); | ||
41 | }); | ... | ... |
... | @@ -52,6 +52,27 @@ casper.test.begin('utils.clone() tests', 2, function(test) { | ... | @@ -52,6 +52,27 @@ casper.test.begin('utils.clone() tests', 2, function(test) { |
52 | test.done(); | 52 | test.done(); |
53 | }); | 53 | }); |
54 | 54 | ||
55 | casper.test.begin('utils.computeModifier() tests', 7, function(test) { | ||
56 | var modifiers = require('webpage').create().event.modifier; | ||
57 | test.assertType(modifiers, "object"); | ||
58 | test.assertEquals(utils.computeModifier("", modifiers), 0, | ||
59 | 'computeModifier() computes a "none" modifier'); | ||
60 | test.assertEquals(utils.computeModifier("alt", modifiers), | ||
61 | modifiers.alt, | ||
62 | 'computeModifier() computes an "alt" modifier'); | ||
63 | test.assertEquals(utils.computeModifier("ctrl+alt", modifiers), | ||
64 | modifiers.ctrl | modifiers.alt, | ||
65 | 'computeModifier() computes a "ctrl+alt" modifier'); | ||
66 | test.assertEquals(utils.computeModifier("ctrl+alt+shift", modifiers), | ||
67 | modifiers.ctrl | modifiers.alt | modifiers.shift, | ||
68 | 'computeModifier() computes a "ctrl+alt+shift" modifier'); | ||
69 | test.assertThrows(utils.computeModifier, ["chucknorris", modifiers], | ||
70 | 'computeModifier() checks for a valid modifier'); | ||
71 | test.assertThrows(utils.computeModifier, ["chuck+norris", modifiers], | ||
72 | 'computeModifier() checks for a valid complex modifier'); | ||
73 | test.done(); | ||
74 | }); | ||
75 | |||
55 | casper.test.begin('equals() tests', 23, function(test) { | 76 | casper.test.begin('equals() tests', 23, function(test) { |
56 | test.assert(utils.equals(null, null), 'equals() null equality'); | 77 | test.assert(utils.equals(null, null), 'equals() null equality'); |
57 | test.assertNot(utils.equals(null, undefined), 'equals() null vs. undefined inequality'); | 78 | test.assertNot(utils.equals(null, undefined), 'equals() null vs. undefined inequality'); | ... | ... |
-
Please register or sign in to post a comment