feat: introduce puppeteer-firefox (#3628)
This adds a proof-of-concept of `puppeteer-firefox`. This consists of two parts: - `//experimental/juggler` - patches to apply to Firefox. - `//experimental/puppeteer-firefox` - front-end code to be merged with Puppeteer. As things become more stable, we'll gradually move it out of the experimental folder.
1
experimental/puppeteer-firefox/test/assets/csp.html
Normal file
@@ -0,0 +1 @@
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
|
||||
12
experimental/puppeteer-firefox/test/assets/detect-touch.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Detect Touch Test</title>
|
||||
<script src='modernizr.js'></script>
|
||||
</head>
|
||||
<body style="font-size:30vmin">
|
||||
<script>
|
||||
document.body.textContent = Modernizr.touchevents ? 'YES' : 'NO';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
experimental/puppeteer-firefox/test/assets/digits/0.png
Normal file
|
After Width: | Height: | Size: 434 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/1.png
Normal file
|
After Width: | Height: | Size: 346 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/2.png
Normal file
|
After Width: | Height: | Size: 413 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/3.png
Normal file
|
After Width: | Height: | Size: 434 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/4.png
Normal file
|
After Width: | Height: | Size: 403 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/5.png
Normal file
|
After Width: | Height: | Size: 422 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/6.png
Normal file
|
After Width: | Height: | Size: 445 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/7.png
Normal file
|
After Width: | Height: | Size: 387 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/8.png
Normal file
|
After Width: | Height: | Size: 447 B |
BIN
experimental/puppeteer-firefox/test/assets/digits/9.png
Normal file
|
After Width: | Height: | Size: 437 B |
15
experimental/puppeteer-firefox/test/assets/error.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<script>
|
||||
a();
|
||||
|
||||
function a() {
|
||||
b();
|
||||
}
|
||||
|
||||
function b() {
|
||||
c();
|
||||
}
|
||||
|
||||
function c() {
|
||||
throw new Error('Fancy error!');
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,2 @@
|
||||
import num from './es6module.js';
|
||||
window.__es6injected = num;
|
||||
@@ -0,0 +1 @@
|
||||
export default 42;
|
||||
@@ -0,0 +1,2 @@
|
||||
import num from './es6/es6module.js';
|
||||
window.__es6injected = num;
|
||||
@@ -0,0 +1,8 @@
|
||||
<link rel='stylesheet' href='./style.css'>
|
||||
<script src='./script.js' type='text/javascript'></script>
|
||||
<style>
|
||||
div {
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
<div>Hi, I'm frame</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<frameset>
|
||||
<frameset>
|
||||
<frame src='./frame.html'></frame>
|
||||
<frame src='about:blank'></frame>
|
||||
</frameset>
|
||||
<frame src='/empty.html'></frame>
|
||||
<frame></frame>
|
||||
</frameset>
|
||||
@@ -0,0 +1,25 @@
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
body iframe {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
::-webkit-scrollbar{
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
async function attachFrame(frameId, url) {
|
||||
var frame = document.createElement('iframe');
|
||||
frame.src = url;
|
||||
frame.id = frameId;
|
||||
document.body.appendChild(frame);
|
||||
await new Promise(x => frame.onload = x);
|
||||
return 'kazakh';
|
||||
}
|
||||
</script>
|
||||
<iframe src='./two-frames.html' name='2frames'></iframe>
|
||||
<iframe src='./frame.html' name='aframe'></iframe>
|
||||
@@ -0,0 +1 @@
|
||||
<iframe src='./frame.html'></iframe>
|
||||
@@ -0,0 +1 @@
|
||||
console.log('Cheers!');
|
||||
@@ -0,0 +1,3 @@
|
||||
div {
|
||||
color: blue;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body iframe {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
</style>
|
||||
<iframe src='./frame.html' name='uno'></iframe>
|
||||
<iframe src='./frame.html' name='dos'></iframe>
|
||||
@@ -0,0 +1,3 @@
|
||||
<script>
|
||||
var globalVar = 123;
|
||||
</script>
|
||||
52
experimental/puppeteer-firefox/test/assets/grid.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
function generatePalette(amount) {
|
||||
var result = [];
|
||||
var hueStep = 360 / amount;
|
||||
for (var i = 0; i < amount; ++i)
|
||||
result.push('hsl(' + (hueStep * i) + ', 100%, 90%)');
|
||||
return result;
|
||||
}
|
||||
|
||||
var palette = generatePalette(100);
|
||||
for (var i = 0; i < 200; ++i) {
|
||||
var box = document.createElement('div');
|
||||
box.classList.add('box');
|
||||
box.style.setProperty('background-color', palette[i % palette.length]);
|
||||
var x = i;
|
||||
do {
|
||||
var digit = x % 10;
|
||||
x = (x / 10)|0;
|
||||
var img = document.createElement('img');
|
||||
img.src = `./digits/${digit}.png`;
|
||||
box.insertBefore(img, box.firstChild);
|
||||
} while (x);
|
||||
document.body.appendChild(box);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.box {
|
||||
font-family: arial;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid darkgray;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,2 @@
|
||||
window.__injected = 42;
|
||||
window.__injectedError = new Error('hi');
|
||||
@@ -0,0 +1,3 @@
|
||||
body {
|
||||
background-color: red;
|
||||
}
|
||||
16
experimental/puppeteer-firefox/test/assets/input/button.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Button test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="mouse-helper.js"></script>
|
||||
<button onclick="clicked();">Click target</button>
|
||||
<script>
|
||||
window.result = 'Was not clicked';
|
||||
function clicked() {
|
||||
result = 'Clicked';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Selection Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<label for="agree">Remember Me</label>
|
||||
<input id="agree" type="checkbox">
|
||||
<script>
|
||||
window.result = {
|
||||
check: null,
|
||||
events: [],
|
||||
};
|
||||
|
||||
let checkbox = document.querySelector('input');
|
||||
|
||||
const events = [
|
||||
'change',
|
||||
'click',
|
||||
'dblclick',
|
||||
'input',
|
||||
'mousedown',
|
||||
'mouseenter',
|
||||
'mouseleave',
|
||||
'mousemove',
|
||||
'mouseout',
|
||||
'mouseover',
|
||||
'mouseup',
|
||||
];
|
||||
|
||||
for (let event of events) {
|
||||
checkbox.addEventListener(event, () => {
|
||||
if (['change', 'click', 'dblclick', 'input'].includes(event) === true) {
|
||||
result.check = checkbox.checked;
|
||||
}
|
||||
|
||||
result.events.push(event);
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Keyboard test</title>
|
||||
</head>
|
||||
<body>
|
||||
<textarea></textarea>
|
||||
<script>
|
||||
window.result = "";
|
||||
let textarea = document.querySelector('textarea');
|
||||
textarea.focus();
|
||||
textarea.addEventListener('keydown', event => {
|
||||
log('Keydown:', event.key, event.code, event.which, modifiers(event));
|
||||
});
|
||||
textarea.addEventListener('keypress', event => {
|
||||
log('Keypress:', event.key, event.code, event.which, event.charCode, modifiers(event));
|
||||
});
|
||||
textarea.addEventListener('keyup', event => {
|
||||
log('Keyup:', event.key, event.code, event.which, modifiers(event));
|
||||
});
|
||||
function modifiers(event) {
|
||||
let m = [];
|
||||
if (event.altKey)
|
||||
m.push('Alt')
|
||||
if (event.ctrlKey)
|
||||
m.push('Control');
|
||||
if (event.metaKey)
|
||||
m.push('Meta')
|
||||
if (event.shiftKey)
|
||||
m.push('Shift')
|
||||
return '[' + m.join(' ') + ']';
|
||||
}
|
||||
function log(...args) {
|
||||
console.log.apply(console, args);
|
||||
result += args.join(' ') + '\n';
|
||||
}
|
||||
function getResult() {
|
||||
let temp = result.trim();
|
||||
result = "";
|
||||
return temp;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Scrollable test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src='mouse-helper.js'></script>
|
||||
<script>
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let button = document.createElement('button');
|
||||
button.textContent = i + ': not clicked';
|
||||
button.id = 'button-' + i;
|
||||
button.onclick = () => button.textContent = 'clicked';
|
||||
button.oncontextmenu = event => {
|
||||
event.preventDefault();
|
||||
button.textContent = 'context menu';
|
||||
}
|
||||
document.body.appendChild(button);
|
||||
document.body.appendChild(document.createElement('br'));
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
69
experimental/puppeteer-firefox/test/assets/input/select.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Selection Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<select>
|
||||
<option value="black">Black</option>
|
||||
<option value="blue">Blue</option>
|
||||
<option value="brown">Brown</option>
|
||||
<option value="cyan">Cyan</option>
|
||||
<option value="gray">Gray</option>
|
||||
<option value="green">Green</option>
|
||||
<option value="indigo">Indigo</option>
|
||||
<option value="magenta">Magenta</option>
|
||||
<option value="orange">Orange</option>
|
||||
<option value="pink">Pink</option>
|
||||
<option value="purple">Purple</option>
|
||||
<option value="red">Red</option>
|
||||
<option value="violet">Violet</option>
|
||||
<option value="white">White</option>
|
||||
<option value="yellow">Yellow</option>
|
||||
</select>
|
||||
<script>
|
||||
window.result = {
|
||||
onInput: null,
|
||||
onChange: null,
|
||||
onBubblingChange: null,
|
||||
onBubblingInput: null,
|
||||
};
|
||||
|
||||
let select = document.querySelector('select');
|
||||
|
||||
function makeEmpty() {
|
||||
for (let i = select.options.length - 1; i >= 0; --i) {
|
||||
select.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
function makeMultiple() {
|
||||
select.setAttribute('multiple', true);
|
||||
}
|
||||
|
||||
select.addEventListener('input', () => {
|
||||
result.onInput = Array.from(select.querySelectorAll('option:checked')).map((option) => {
|
||||
return option.value;
|
||||
});
|
||||
}, false);
|
||||
|
||||
select.addEventListener('change', () => {
|
||||
result.onChange = Array.from(select.querySelectorAll('option:checked')).map((option) => {
|
||||
return option.value;
|
||||
});
|
||||
}, false);
|
||||
|
||||
document.body.addEventListener('input', () => {
|
||||
result.onBubblingInput = Array.from(select.querySelectorAll('option:checked')).map((option) => {
|
||||
return option.value;
|
||||
});
|
||||
}, false);
|
||||
|
||||
document.body.addEventListener('change', () => {
|
||||
result.onBubblingChange = Array.from(select.querySelectorAll('option:checked')).map((option) => {
|
||||
return option.value;
|
||||
});
|
||||
}, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Textarea test</title>
|
||||
</head>
|
||||
<body>
|
||||
<textarea></textarea>
|
||||
<script src='mouse-helper.js'></script>
|
||||
<script>
|
||||
window.result = '';
|
||||
let textarea = document.querySelector('textarea');
|
||||
textarea.addEventListener('input', () => result = textarea.value, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1
experimental/puppeteer-firefox/test/assets/mobile.html
Normal file
@@ -0,0 +1 @@
|
||||
<meta name = "viewport" content = "initial-scale = 1, user-scalable = no">
|
||||
3
experimental/puppeteer-firefox/test/assets/modernizr.js
Normal file
@@ -0,0 +1,3 @@
|
||||
/*! modernizr 3.5.0 (Custom Build) | MIT *
|
||||
* https://modernizr.com/download/?-touchevents-setclasses !*/
|
||||
!function(e,n,t){function o(e,n){return typeof e===n}function s(){var e,n,t,s,a,i,r;for(var l in c)if(c.hasOwnProperty(l)){if(e=[],n=c[l],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t<n.options.aliases.length;t++)e.push(n.options.aliases[t].toLowerCase());for(s=o(n.fn,"function")?n.fn():n.fn,a=0;a<e.length;a++)i=e[a],r=i.split("."),1===r.length?Modernizr[r[0]]=s:(!Modernizr[r[0]]||Modernizr[r[0]]instanceof Boolean||(Modernizr[r[0]]=new Boolean(Modernizr[r[0]])),Modernizr[r[0]][r[1]]=s),f.push((s?"":"no-")+r.join("-"))}}function a(e){var n=u.className,t=Modernizr._config.classPrefix||"";if(p&&(n=n.baseVal),Modernizr._config.enableJSClass){var o=new RegExp("(^|\\s)"+t+"no-js(\\s|$)");n=n.replace(o,"$1"+t+"js$2")}Modernizr._config.enableClasses&&(n+=" "+t+e.join(" "+t),p?u.className.baseVal=n:u.className=n)}function i(){return"function"!=typeof n.createElement?n.createElement(arguments[0]):p?n.createElementNS.call(n,"http://www.w3.org/2000/svg",arguments[0]):n.createElement.apply(n,arguments)}function r(){var e=n.body;return e||(e=i(p?"svg":"body"),e.fake=!0),e}function l(e,t,o,s){var a,l,f,c,d="modernizr",p=i("div"),h=r();if(parseInt(o,10))for(;o--;)f=i("div"),f.id=s?s[o]:d+(o+1),p.appendChild(f);return a=i("style"),a.type="text/css",a.id="s"+d,(h.fake?h:p).appendChild(a),h.appendChild(p),a.styleSheet?a.styleSheet.cssText=e:a.appendChild(n.createTextNode(e)),p.id=d,h.fake&&(h.style.background="",h.style.overflow="hidden",c=u.style.overflow,u.style.overflow="hidden",u.appendChild(h)),l=t(p,e),h.fake?(h.parentNode.removeChild(h),u.style.overflow=c,u.offsetHeight):p.parentNode.removeChild(p),!!l}var f=[],c=[],d={_version:"3.5.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,n){var t=this;setTimeout(function(){n(t[e])},0)},addTest:function(e,n,t){c.push({name:e,fn:n,options:t})},addAsyncTest:function(e){c.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=d,Modernizr=new Modernizr;var u=n.documentElement,p="svg"===u.nodeName.toLowerCase(),h=d._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):["",""];d._prefixes=h;var m=d.testStyles=l;Modernizr.addTest("touchevents",function(){var t;if("ontouchstart"in e||e.DocumentTouch&&n instanceof DocumentTouch)t=!0;else{var o=["@media (",h.join("touch-enabled),("),"heartz",")","{#modernizr{top:9px;position:absolute}}"].join("");m(o,function(e){t=9===e.offsetTop})}return t}),s(),a(f),delete d.addTest,delete d.addAsyncTest;for(var v=0;v<Modernizr._q.length;v++)Modernizr._q[v]();e.Modernizr=Modernizr}(window,document);
|
||||
@@ -0,0 +1,36 @@
|
||||
<style>
|
||||
button {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#btn0 { right: 0px; top: 0; }
|
||||
#btn1 { right: -10px; top: 25px; }
|
||||
#btn2 { right: -20px; top: 50px; }
|
||||
#btn3 { right: -30px; top: 75px; }
|
||||
#btn4 { right: -40px; top: 100px; }
|
||||
#btn5 { right: -50px; top: 125px; }
|
||||
#btn6 { right: -60px; top: 150px; }
|
||||
#btn7 { right: -70px; top: 175px; }
|
||||
#btn8 { right: -80px; top: 200px; }
|
||||
#btn9 { right: -90px; top: 225px; }
|
||||
#btn10 { right: -100px; top: 250px; }
|
||||
</style>
|
||||
<button id=btn0>0</button>
|
||||
<button id=btn1>1</button>
|
||||
<button id=btn2>2</button>
|
||||
<button id=btn3>3</button>
|
||||
<button id=btn4>4</button>
|
||||
<button id=btn5>5</button>
|
||||
<button id=btn6>6</button>
|
||||
<button id=btn7>7</button>
|
||||
<button id=btn8>8</button>
|
||||
<button id=btn9>9</button>
|
||||
<button id=btn10>10</button>
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
for (const button of Array.from(document.querySelectorAll('button')))
|
||||
button.addEventListener('click', () => console.log('button #' + button.textContent + ' clicked'), false);
|
||||
}, false);
|
||||
</script>
|
||||
3
experimental/puppeteer-firefox/test/assets/one-style.css
Normal file
@@ -0,0 +1,3 @@
|
||||
body {
|
||||
background-color: pink;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<link rel='stylesheet' href='./one-style.css'>
|
||||
<div>hello, world!</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<script>
|
||||
window.result = window.injected;
|
||||
</script>
|
||||
1
experimental/puppeteer-firefox/test/assets/title.html
Normal file
@@ -0,0 +1 @@
|
||||
<title>Woof-Woof</title>
|
||||
32
experimental/puppeteer-firefox/test/assets/wrappedlink.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<style>
|
||||
:root {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div {
|
||||
width: 10ch;
|
||||
word-wrap: break-word;
|
||||
border: 1px solid blue;
|
||||
transform: rotate(33deg);
|
||||
line-height: 8ch;
|
||||
padding: 2ch;
|
||||
}
|
||||
|
||||
a {
|
||||
margin-left: 7ch;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
<a href='#clicked'>123321</a>
|
||||
</div>
|
||||
<script>
|
||||
document.querySelector('a').addEventListener('click', () => {
|
||||
window.__clicked = true;
|
||||
});
|
||||
</script>
|
||||