Skip to content

Instantly share code, notes, and snippets.

@ironblock
Last active August 25, 2021 01:47
Show Gist options
  • Save ironblock/48d1cb677ea02460a307111e11f75293 to your computer and use it in GitHub Desktop.
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
/**
* 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