-
Notifications
You must be signed in to change notification settings - Fork 427
/
formFiller.js
157 lines (125 loc) · 5.02 KB
/
formFiller.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
152
153
154
155
156
157
const getDefaultConfig = (randomizer, window) => {
const document = window.document;
/**
* Hacky function to trigger react, angular & vue.js onChange on input
*/
const triggerSimulatedOnChange = (element, newValue, prototype) => {
const lastValue = element.value;
element.value = newValue;
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
nativeInputValueSetter.call(element, newValue);
const event = new Event('input', { bubbles: true });
// React 15
event.simulated = true;
// React >= 16
let tracker = element._valueTracker;
if (tracker) {
tracker.setValue(lastValue);
}
element.dispatchEvent(event);
};
const fillTextElement = (element) => {
const character = randomizer.character();
const newValue = element.value + character;
triggerSimulatedOnChange(element, newValue, window.HTMLInputElement.prototype);
return character;
};
const fillTextAreaElement = (element) => {
const character = randomizer.character();
const newValue = element.value + character;
triggerSimulatedOnChange(element, newValue, window.HTMLTextAreaElement.prototype);
return character;
};
const fillNumberElement = (element) => {
const number = randomizer.character({ pool: '0123456789' });
const newValue = element.value + number;
triggerSimulatedOnChange(element, newValue, window.HTMLInputElement.prototype);
return number;
};
const fillSelect = (element) => {
const options = element.querySelectorAll('option');
if (options.length === 0) return;
const randomOption = randomizer.pick(options);
options.forEach((option) => {
option.selected = option.value === randomOption.value;
});
return randomOption.value;
};
const fillRadio = (element) => {
// using mouse events to trigger listeners
const evt = document.createEvent('MouseEvents');
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
element.dispatchEvent(evt);
return element.value;
};
const fillCheckbox = (element) => {
// using mouse events to trigger listeners
const evt = document.createEvent('MouseEvents');
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
element.dispatchEvent(evt);
return element.value;
};
const fillEmail = (element) => {
const email = randomizer.email();
triggerSimulatedOnChange(element, email, window.HTMLInputElement.prototype);
return email;
};
const defaultMapElements = {
textarea: fillTextAreaElement,
'input[type="text"]': fillTextElement,
'input[type="password"]': fillTextElement,
'input[type="number"]': fillNumberElement,
select: fillSelect,
'input[type="radio"]': fillRadio,
'input[type="checkbox"]': fillCheckbox,
'input[type="email"]': fillEmail,
'input:not([type])': fillTextElement,
};
const defaultShowAction = (element) => {
if (typeof element.attributes['data-old-border'] === 'undefined') {
element.attributes['data-old-border'] = element.style.border;
}
const oldBorder = element.attributes['data-old-border'];
element.style.border = '1px solid red';
setTimeout(() => {
element.style.border = oldBorder;
}, 500);
};
const defaultCanFillElement = () => {
return true;
};
return {
elementMapTypes: defaultMapElements,
showAction: defaultShowAction,
canFillElement: defaultCanFillElement,
maxNbTries: 10,
log: false,
};
};
export default (userConfig) => ({ logger, randomizer, window }) => {
const document = window.document;
const config = { ...getDefaultConfig(randomizer, window), ...userConfig };
return () => {
// Retrieve all selectors
const elementTypes = Object.keys(config.elementMapTypes);
let element;
let nbTries = 0;
do {
// Find a random element within all selectors
const elements = document.querySelectorAll(elementTypes.join(','));
if (elements.length === 0) return;
element = randomizer.pick(elements);
nbTries++;
if (nbTries > config.maxNbTries) return;
} while (!element || !config.canFillElement(element));
// Retrieve element type
const elementType = Object.keys(config.elementMapTypes).find((selector) => element.matches(selector));
const value = config.elementMapTypes[elementType](element);
if (typeof config.showAction === 'function') {
config.showAction(element);
}
if (logger && config.log) {
logger.log('gremlin', 'formFiller', 'input', value, 'in', element);
}
};
};