Last active
August 25, 2021 01:47
-
-
Save ironblock/48d1cb677ea02460a307111e11f75293 to your computer and use it in GitHub Desktop.
Fill out forms with random junk data when testing or developing things with long annoying forms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* FILL OUT FORM WITH RANDOM DATA | |
* | |
* This bookmarklet makes a best effort to fill out a form with random junk data | |
* that probably can pass some pretty permissive validation. Not everything is | |
* currently implemented. | |
* | |
* It follows the these rules: | |
* <input> | |
* === "TEXT-LIKE" TYPES === | |
* type="text" | |
* type="search" | |
* Fill with a random word | |
* | |
* type="password" | |
* Fill with a random string following the format: | |
* [four letters]-[three numbers]-[four letters] | |
* | |
* type="color" | |
* Fill with a random hex color between #000000 and #FFFFFF | |
* | |
* type="email" | |
* Fill with an email following the format: | |
* [word][numbers]@[word].[domain] | |
* | |
* type="url" | |
* Fill with a random URL following the format: | |
* https://[word].[domain]/[word] | |
* | |
* === "NUMBER-LIKE" TYPES === | |
* NOTE: If the element has a "min" or "max" attribute, it will always be | |
* used, regardless of the outcome of other checks. | |
* | |
* type="range": | |
* type="number": | |
* Does its name contain something indicating that it might be used for | |
* human height? | |
* Yes: Fill with a random number between 4 and 6 (4-6 ft, 4-6 in) | |
* No: Fill with a random number between 1960 and 1999, works for years | |
* | |
* type="tel" | |
* Fill with a random fictitious North American phone number in the format: | |
* 1[100-199]555[ | |
* | |
* | |
* === "CLICK ON" TYPES === | |
* type="checkbox" | |
* type="radio" | |
* For the first element with a given name, always select it. | |
* When the name is observed any additional times, randomly select the | |
* element with 50:50 odds. | |
* | |
* === DATETIME TYPES === | |
* type="date": | |
* Does the name contain something indicating that it might be used for a | |
* birthday? | |
* Yes: Fill with a random date between 20 and 40 years in the past. | |
* No: Fill with a random date between 10 and 50 days in the future. | |
* type="datetime": | |
* Do the same as above, but add `T[00-23]:[00-59]` to the end. | |
* type="month": | |
* Fill with a random year between 1960 and 1999 and a random month: | |
* [1960-1999]-[01-12] | |
* | |
* type="time": | |
* Fill with a random time between 00:00 and 23:59: | |
* [00-23]:[00-59] | |
* | |
* type="week": | |
* Fill with a random year between 1960 and 1999 and a random week: | |
* [1960-1999]-W[00-52] | |
* | |
* === BLOB TYPES === | |
* type="file": NOT YET IMPLEMENTED | |
* | |
* <textarea> | |
* Fill with 10-20 random words | |
* | |
* <select> | |
* Find the first <option> with a defined value and select it | |
* | |
* | |
* ================== MINIFICATION BY https://jscompress.com/ ================== | |
* 76.26% compression, saving 7.79 kb | |
*/ | |
// COPY THIS CODE TO YOUR BOOKMARKLET: | |
javascript:(function(){const a=new Date(Date.now()-630720000000),b=new Date(Date.now()-1261440000000),c=["feet","feet","ft","in","height"],d=["lorem","ipsum","dolor","sit","amet","consectetur","adipiscing","elit"],e=["com","edu","xyz","horse"],f=(a,b)=>b.dispatchEvent(new Event(a,{bubbles:!0})),g=(a,b)=>Math.floor(Math.random()*(b-a+1)+a),h=a=>a[g(0,a.length-1)],j=()=>h(d),k=()=>h(e),l=()=>btoa(j().substring(0,3)),m=a=>{const b=[];for(let c=0;c<a;c++)b.push(j());return b},n=()=>`#${g(0,Math.pow(256,3)-1).toString(16).toUpperCase()}`,o=()=>`${j()}.${k()}`,p=()=>`${j()}${g(10,99)}@${o()}`,q=()=>`${g(0,23)}:${g(0,59)}`,r=()=>`19${getRadomNumberBetween(60,99)}`,s=(a,b)=>{const[c,d]=[a,b].map(a=>Date.UTC(a.getFullYear(),a.getMonth(),a.getDate()));return Math.floor((c-d)/86400000)},t=(a,b)=>{const c=new Date(a);return c.setDate(c.getDate()+b),c},u=(a,b)=>t(g(0,s(a,b))),v=a=>!isNaN(a)&&!isNaN(parseFloat(a)),w=a=>a.name&&c.some(b=>a.name.toLowerCase().includes(b)),x=(a,b,c,d)=>b(v(a.min)?+a.min:c,v(a.max)?+a.max:d),y=(a,b)=>(c,d)=>Object.getOwnPropertyDescriptor(window[a].prototype,b).set.call(c,d),z=y("HTMLInputElement","value"),A=y("HTMLInputElement","checked"),B=y("HTMLSelectElement","value"),C=y("HTMLTextAreaElement","value"),D="checkbox",E="color",F="date",G="datetime",H="email",I="month",J="number",K="password",L="radio",M="range",N="search",O="tel",P="text",Q="time",R="url",S="week",T="select",U="textarea",V=[D,E,F,G,H,"file",I,J,K,L,M,N,O,P,Q,R,S],W=V.map(a=>`input[type="${a}"]`),X=new Set;W.concat([T,U]).forEach((c,d)=>document.querySelectorAll(`:not(nav):not(footer) form ${c}`).forEach(e=>{const h=V[d]??c;let i,o,s,v=z,y="change";switch(h){case T:v=B,i=Array.from(e.options).find(a=>!!a.value)?.value??0;break;case U:v=C,i=m(g(10,20));break;case D:case L:v=A,y="click",i=!(!!X.has(e.name)&&!g(0,1)),X.add(e.name);break;case O:i=`1${g(100,999)}5550${g(100,199)}`;break;case J:case M:[o,s]=w(e)?[4,6]:[1960,1999],i=x(e,g,o,s);break;case G:i=`T${q()}`;case F:[o,s]=e.name.includes("birth")?[a,b]:[t(new Date,10),t(new Date,50)],i=`${x(e,u,a,b).toISOString().substring(0,10)}${i??""}`;break;case I:i=`${r()}-${g(1,12)}`;break;case Q:i=q();break;case S:i=`${r()}-W${x(e,u,0,52)}`;break;case E:i=n();break;case H:i=p();break;case K:i=[l(),g(10,99),l()].join("-");break;case R:i=`https://${k()}/${j()}`;break;case N:case P:i=j();break;default:console.warn(`Missing handler! Tell Corey he forgot the case for "${h}!"`);}e.focus(),v(e,i),f(y,e),e.blur()}))})(); | |
// SOURCE CODE SO YOU CAN SEE I'M NOT DOING ANYTHING SHADY | |
javascript: (function () { | |
const millisecondsPerDay = 1000 * 60 * 60 * 24; | |
const twentyYearsAgo = new Date(Date.now() - millisecondsPerDay * 365 * 20); | |
const fortyYearsAgo = new Date(Date.now() - millisecondsPerDay * 365 * 40); | |
const heightTerms = ["feet", "feet", "ft", "in", "height"]; | |
const loremIpsum = [ | |
"lorem", | |
"ipsum", | |
"dolor", | |
"sit", | |
"amet", | |
"consectetur", | |
"adipiscing", | |
"elit", | |
]; | |
const domains = ["com", "edu", "xyz", "horse"]; | |
const simulate = (type, element) => | |
element.dispatchEvent(new Event(type, { bubbles: true })); | |
const getRandomNumberBetween = (min, max) => | |
Math.floor(Math.random() * (max - min + 1) + min); | |
const getRandomFromArray = (values) => | |
values[getRandomNumberBetween(0, values.length - 1)]; | |
const getRandomWord = () => getRandomFromArray(loremIpsum); | |
const getRandomDomain = () => getRandomFromArray(domains); | |
const getRandomHash = () => btoa(getRandomWord().substring(0, 3)); | |
const getRandomWords = (count) => { | |
const words = []; | |
for (let i = 0; i < count; i++) { | |
words.push(getRandomWord()); | |
} | |
return words; | |
}; | |
const getRandomHexColor = () => | |
`#${getRandomNumberBetween(0, Math.pow(256, 3) - 1) | |
.toString(16) | |
.toUpperCase()}`; | |
const getRandomURL = () => `${getRandomWord()}.${getRandomDomain()}`; | |
const getRandomEmail = () => | |
`${getRandomWord()}${getRandomNumberBetween(10, 99)}@${getRandomURL()}`; | |
const getRandomTime = () => | |
`${getRandomNumberBetween(0, 23)}:${getRandomNumberBetween(0, 59)}`; | |
const getRandomYear = () => `19${getRadomNumberBetween(60, 99)}`; | |
const getNumberOfDaysBetween = (start, end) => { | |
const [startUTC, endUTC] = [start, end].map((targetDate) => | |
Date.UTC( | |
targetDate.getFullYear(), | |
targetDate.getMonth(), | |
targetDate.getDate() | |
) | |
); | |
return Math.floor((startUTC - endUTC) / millisecondsPerDay); | |
}; | |
const getDateShiftedByDays = (date, days) => { | |
const result = new Date(date); | |
result.setDate(result.getDate() + days); | |
return result; | |
}; | |
const getRandomDateBetween = (start, end) => | |
getDateShiftedByDays( | |
getRandomNumberBetween(0, getNumberOfDaysBetween(start, end)) | |
); | |
const isNumber = (target) => !isNaN(target) && !isNaN(parseFloat(target)); | |
const isHeight = (target) => | |
target.name && | |
heightTerms.some((term) => target.name.toLowerCase().includes(term)); | |
const preferDeclaredMinMax = (element, method, min, max) => | |
method( | |
isNumber(element.min) ? +element.min : min, | |
isNumber(element.max) ? +element.max : max | |
); | |
const getNativeSetterFor = (element, property) => (target, value) => | |
Object.getOwnPropertyDescriptor( | |
window[element].prototype, | |
property | |
).set.call(target, value); | |
const setInputValue = getNativeSetterFor("HTMLInputElement", "value"); | |
const setInputChecked = getNativeSetterFor("HTMLInputElement", "checked"); | |
const setSelectValue = getNativeSetterFor("HTMLSelectElement", "value"); | |
const setTextAreaValue = getNativeSetterFor("HTMLTextAreaElement", "value"); | |
const checkbox = "checkbox"; | |
const color = "color"; | |
const date = "date"; | |
const datetime = "datetime"; | |
const email = "email"; | |
const file = "file"; | |
const month = "month"; | |
const number = "number"; | |
const password = "password"; | |
const radio = "radio"; | |
const range = "range"; | |
const search = "search"; | |
const tel = "tel"; | |
const text = "text"; | |
const time = "time"; | |
const url = "url"; | |
const week = "week"; | |
const select = "select"; | |
const textarea = "textarea"; | |
const inputTypes = [ | |
checkbox, | |
color, | |
date, | |
datetime, | |
email, | |
file, | |
month, | |
number, | |
password, | |
radio, | |
range, | |
search, | |
tel, | |
text, | |
time, | |
url, | |
week, | |
]; | |
const inputTypesForSelector = inputTypes.map( | |
(type) => `input[type="${type}"]` | |
); | |
const otherTypes = [select, textarea]; | |
const seenNames = new Set(); | |
inputTypesForSelector.concat(otherTypes).forEach((formattedSelector, index) => | |
document | |
.querySelectorAll(`:not(nav):not(footer) form ${formattedSelector}`) | |
.forEach((element) => { | |
const selector = inputTypes[index] ?? formattedSelector; | |
let setter = setInputValue; | |
let event = "change"; | |
let value; | |
let min, max; | |
switch (selector) { | |
// NON-<INPUT> TYPES | |
case select: | |
setter = setSelectValue; | |
value = | |
Array.from(element.options).find((option) => !!option.value) | |
?.value ?? 0; | |
break; | |
case textarea: | |
setter = setTextAreaValue; | |
value = getRandomWords(getRandomNumberBetween(10, 20)); | |
break; | |
// "CLICK ON" TYPES | |
case checkbox: | |
case radio: | |
setter = setInputChecked; | |
event = "click"; | |
value = !!(seenNames.has(element.name) | |
? getRandomNumberBetween(0, 1) | |
: 1); | |
seenNames.add(element.name); | |
break; | |
// "NUMBER-LIKE" TYPES | |
case tel: | |
// https://en.wikipedia.org/wiki/555_(telephone_number)#Real_usage | |
value = `1${getRandomNumberBetween( | |
100, | |
999 | |
)}5550${getRandomNumberBetween(100, 199)}`; | |
break; | |
case number: | |
case range: | |
[min, max] = isHeight(element) ? [4, 6] : [1960, 1999]; | |
value = preferDeclaredMinMax( | |
element, | |
getRandomNumberBetween, | |
min, | |
max | |
); | |
break; | |
// DATETIME TYPES | |
case datetime: | |
value = `T${getRandomTime()}`; | |
case date: | |
[min, max] = element.name.includes("birth") | |
? [twentyYearsAgo, fortyYearsAgo] | |
: [ | |
getDateShiftedByDays(new Date(), 10), | |
getDateShiftedByDays(new Date(), 50), | |
]; | |
value = `${preferDeclaredMinMax( | |
element, | |
getRandomDateBetween, | |
twentyYearsAgo, | |
fortyYearsAgo | |
) | |
.toISOString() | |
.substring(0, 10)}${value ?? ""}`; | |
break; | |
case month: | |
value = `${getRandomYear()}-${getRandomNumberBetween(1, 12)}`; | |
break; | |
case time: | |
value = getRandomTime(); | |
break; | |
case week: | |
value = `${getRandomYear()}-W${preferDeclaredMinMax( | |
element, | |
getRandomDateBetween, | |
0, | |
52 | |
)}`; | |
break; | |
// "TEXT-LIKE" TYPES | |
case color: | |
value = getRandomHexColor(); | |
break; | |
case email: | |
value = getRandomEmail(); | |
break; | |
case password: | |
value = [ | |
getRandomHash(), | |
getRandomNumberBetween(10, 99), | |
getRandomHash(), | |
].join("-"); | |
break; | |
case url: | |
value = `https://${getRandomDomain()}/${getRandomWord()}`; | |
break; | |
case search: | |
case text: | |
value = getRandomWord(); | |
break; | |
default: | |
console.warn( | |
`Missing handler! Tell Corey he forgot the case for "${selector}!"` | |
); | |
} | |
element.focus(); | |
setter(element, value); | |
simulate(event, element); | |
element.blur(); | |
}) | |
); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment