1cb93a386Sopenharmony_ciconst REPORT_URL = 'http://localhost:8081/report_gold_data' 2cb93a386Sopenharmony_ci// Set this to enforce that the gold server must be up. 3cb93a386Sopenharmony_ci// Typically used for debugging. 4cb93a386Sopenharmony_ciconst fail_on_no_gold = false; 5cb93a386Sopenharmony_ci 6cb93a386Sopenharmony_cifunction reportCanvas(canvas, testname, outputType='canvas') { 7cb93a386Sopenharmony_ci let b64 = canvas.toDataURL('image/png'); 8cb93a386Sopenharmony_ci return _report(b64, outputType, testname); 9cb93a386Sopenharmony_ci} 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_cifunction reportSVG(svg, testname) { 12cb93a386Sopenharmony_ci // This converts an SVG to a base64 encoded PNG. It basically creates an 13cb93a386Sopenharmony_ci // <img> element that takes the inlined SVG and draws it on a canvas. 14cb93a386Sopenharmony_ci // The trick is we have to wait until the image is loaded, thus the Promise 15cb93a386Sopenharmony_ci // wrapping below. 16cb93a386Sopenharmony_ci let svgStr = svg.outerHTML; 17cb93a386Sopenharmony_ci let tempImg = document.createElement('img'); 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci let tempCanvas = document.createElement('canvas'); 20cb93a386Sopenharmony_ci let canvasCtx = tempCanvas.getContext('2d'); 21cb93a386Sopenharmony_ci setCanvasSize(canvasCtx, svg.getAttribute('width'), svg.getAttribute('height')); 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci return new Promise(function(resolve, reject) { 24cb93a386Sopenharmony_ci tempImg.onload = () => { 25cb93a386Sopenharmony_ci canvasCtx.drawImage(tempImg, 0, 0); 26cb93a386Sopenharmony_ci let b64 = tempCanvas.toDataURL('image/png'); 27cb93a386Sopenharmony_ci _report(b64, 'svg', testname).then(() => { 28cb93a386Sopenharmony_ci resolve(); 29cb93a386Sopenharmony_ci }).catch((e) => reject(e)); 30cb93a386Sopenharmony_ci }; 31cb93a386Sopenharmony_ci tempImg.setAttribute('src', 'data:image/svg+xml;,' + svgStr); 32cb93a386Sopenharmony_ci }); 33cb93a386Sopenharmony_ci} 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci// For tests that just do a simple path and return it as a string, wrap it in 36cb93a386Sopenharmony_ci// a proper svg and send it off. Supports fill (nofill means just stroke it). 37cb93a386Sopenharmony_ci// This uses the "standard" size of 600x600. 38cb93a386Sopenharmony_cifunction reportSVGString(svgstr, testname, fillRule='nofill') { 39cb93a386Sopenharmony_ci let newPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 40cb93a386Sopenharmony_ci newPath.setAttribute('stroke', 'black'); 41cb93a386Sopenharmony_ci if (fillRule !== 'nofill') { 42cb93a386Sopenharmony_ci newPath.setAttribute('fill', 'orange'); 43cb93a386Sopenharmony_ci newPath.setAttribute('fill-rule', fillRule); 44cb93a386Sopenharmony_ci } else { 45cb93a386Sopenharmony_ci newPath.setAttribute('fill', 'rgba(255,255,255,0.0)'); 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci newPath.setAttribute('d', svgstr); 48cb93a386Sopenharmony_ci let newSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 49cb93a386Sopenharmony_ci newSVG.appendChild(newPath); 50cb93a386Sopenharmony_ci // helps with the conversion to PNG. 51cb93a386Sopenharmony_ci newSVG.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); 52cb93a386Sopenharmony_ci newSVG.setAttribute('width', 600); 53cb93a386Sopenharmony_ci newSVG.setAttribute('height', 600); 54cb93a386Sopenharmony_ci return reportSVG(newSVG, testname); 55cb93a386Sopenharmony_ci} 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ci// Reports a canvas and then an SVG of this path. Puts it on a standard size canvas. 58cb93a386Sopenharmony_cifunction reportPath(path, testname, done) { 59cb93a386Sopenharmony_ci let canvas = document.createElement('canvas'); 60cb93a386Sopenharmony_ci let canvasCtx = canvas.getContext('2d'); 61cb93a386Sopenharmony_ci // Set canvas size and make it a bit bigger to zoom in on the lines 62cb93a386Sopenharmony_ci standardizedCanvasSize(canvasCtx); 63cb93a386Sopenharmony_ci canvasCtx.stroke(path.toPath2D()); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci let svgStr = path.toSVGString(); 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci return reportCanvas(canvas, testname).then(() => { 68cb93a386Sopenharmony_ci reportSVGString(svgStr, testname).then(() => { 69cb93a386Sopenharmony_ci done(); 70cb93a386Sopenharmony_ci }).catch(reportError(done)); 71cb93a386Sopenharmony_ci }).catch(reportError(done)); 72cb93a386Sopenharmony_ci} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci// data is a base64 encoded png, outputType is the value that goes with the 75cb93a386Sopenharmony_ci// key 'config' when reporting. 76cb93a386Sopenharmony_cifunction _report(data, outputType, testname) { 77cb93a386Sopenharmony_ci return fetch(REPORT_URL, { 78cb93a386Sopenharmony_ci method: 'POST', 79cb93a386Sopenharmony_ci mode: 'no-cors', 80cb93a386Sopenharmony_ci headers: { 81cb93a386Sopenharmony_ci 'Content-Type': 'application/json', 82cb93a386Sopenharmony_ci }, 83cb93a386Sopenharmony_ci body: JSON.stringify({ 84cb93a386Sopenharmony_ci 'output_type': outputType, 85cb93a386Sopenharmony_ci 'data': data, 86cb93a386Sopenharmony_ci 'test_name': testname, 87cb93a386Sopenharmony_ci }) 88cb93a386Sopenharmony_ci }).then(() => console.log(`Successfully reported ${testname} to gold aggregator`)); 89cb93a386Sopenharmony_ci} 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_cifunction reportError(done) { 92cb93a386Sopenharmony_ci return (e) => { 93cb93a386Sopenharmony_ci console.log("Error with fetching. Likely could not connect to aggregator server", e.message); 94cb93a386Sopenharmony_ci if (fail_on_no_gold) { 95cb93a386Sopenharmony_ci expect(e).toBeUndefined(); 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci done(); 98cb93a386Sopenharmony_ci }; 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_cifunction setCanvasSize(ctx, width, height) { 102cb93a386Sopenharmony_ci ctx.canvas.width = width; 103cb93a386Sopenharmony_ci ctx.canvas.height = height; 104cb93a386Sopenharmony_ci} 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_cifunction standardizedCanvasSize(ctx) { 107cb93a386Sopenharmony_ci setCanvasSize(ctx, 600, 600); 108cb93a386Sopenharmony_ci} 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci// A wrapper to catch and print a stacktrace to the logs. 111cb93a386Sopenharmony_ci// Exceptions normally shows up in the browser console, 112cb93a386Sopenharmony_ci// but not in the logs that appear on the bots AND a thrown 113cb93a386Sopenharmony_ci// exception will normally cause a test to time out. 114cb93a386Sopenharmony_ci// This wrapper mitigates both those pain points. 115cb93a386Sopenharmony_cifunction catchException(done, fn) { 116cb93a386Sopenharmony_ci return () => { 117cb93a386Sopenharmony_ci try { 118cb93a386Sopenharmony_ci fn() 119cb93a386Sopenharmony_ci } catch (e) { 120cb93a386Sopenharmony_ci console.log('Failed with the following error', e); 121cb93a386Sopenharmony_ci expect(e).toBeFalsy(); 122cb93a386Sopenharmony_ci debugger; 123cb93a386Sopenharmony_ci done(); 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci // We don't call done with finally because 126cb93a386Sopenharmony_ci // that would make the break the asynchronous nature 127cb93a386Sopenharmony_ci // of fn(). 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci} 130