-
Notifications
You must be signed in to change notification settings - Fork 91
/
fillable.js
151 lines (142 loc) · 4.24 KB
/
fillable.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { assign, buildSelector, findClosestValue } from '../helpers';
import { getExecutionContext } from '../execution_context';
/**
* Alias for `fillable`, which works for inputs, HTML select menus, and
* contenteditable elements.
*
* [See `fillable` for usage examples.](#fillable)
*
* @name selectable
* @function
*
* @public
*
* @param {string} selector - CSS selector of the element to look for text
* @param {Object} options - Additional options
* @param {string} options.scope - Nests provided scope within parent's scope
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index
* @param {boolean} options.resetScope - Override parent's scope
* @param {string} options.testContainer - Context where to search elements in the DOM
* @return {Descriptor}
*/
/**
* Fills in an input matched by a selector.
*
* @example
*
* // <input value="">
*
* const page = PageObject.create({
* fillIn: PageObject.fillable('input')
* });
*
* // result: <input value="John Doe">
* page.fillIn('John Doe');
*
* @example
*
* // <div class="name">
* // <input value="">
* // </div>
* // <div class="last-name">
* // <input value= "">
* // </div>
*
* const page = PageObject.create({
* fillInName: PageObject.fillable('input', { scope: '.name' })
* });
*
* page.fillInName('John Doe');
*
* // result
* // <div class="name">
* // <input value="John Doe">
* // </div>
*
* @example
*
* // <div class="name">
* // <input value="">
* // </div>
* // <div class="last-name">
* // <input value= "">
* // </div>
*
* const page = PageObject.create({
* scope: 'name',
* fillInName: PageObject.fillable('input')
* });
*
* page.fillInName('John Doe');
*
* // result
* // <div class="name">
* // <input value="John Doe">
* // </div>
*
* @example <caption>Filling different inputs with the same property</caption>
*
* // <input id="name">
* // <input name="lastname">
* // <input data-test="email">
* // <textarea aria-label="address"></textarea>
* // <input placeholder="phone">
* // <div contenteditable="true" id="bio"></div>
*
* const page = create({
* fillIn: fillable('input, textarea, [contenteditable]')
* });
*
* page
* .fillIn('name', 'Doe')
* .fillIn('lastname', 'Doe')
* .fillIn('email', 'john@doe')
* .fillIn('address', 'A street')
* .fillIn('phone', '555-000')
* .fillIn('bio', 'The story of <b>John Doe</b>');
*
* @public
*
* @param {string} selector - CSS selector of the element to look for text
* @param {Object} options - Additional options
* @param {string} options.scope - Nests provided scope within parent's scope
* @param {number} options.at - Reduce the set of matched elements to the one at the specified index
* @param {boolean} options.resetScope - Override parent's scope
* @param {string} options.testContainer - Context where to search elements in the DOM
* @return {Descriptor}
*/
export function fillable(selector, userOptions = {}) {
return {
isDescriptor: true,
get(key) {
return function(contentOrClue, content) {
let clue;
if (content === undefined) {
content = contentOrClue;
} else {
clue = contentOrClue;
}
let executionContext = getExecutionContext(this);
let options = assign({ pageObjectKey: `${key}()` }, userOptions);
return executionContext.runAsync((context) => {
let fullSelector = buildSelector(this, selector, options);
let container = options.testContainer || findClosestValue(this, 'testContainer');
if (clue) {
fullSelector = ['input', 'textarea', 'select', '[contenteditable]']
.map((tag) => [
`${fullSelector} ${tag}[data-test="${clue}"]`,
`${fullSelector} ${tag}[aria-label="${clue}"]`,
`${fullSelector} ${tag}[placeholder="${clue}"]`,
`${fullSelector} ${tag}[name="${clue}"]`,
`${fullSelector} ${tag}#${clue}`
])
.reduce((total, other) => total.concat(other), [])
.join(',');
}
context.assertElementExists(fullSelector, options);
context.fillIn(fullSelector, container, options, content);
});
};
}
};
}