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