browser_tester 1.5.0

Deterministic lightweight browser runtime for Rust tests
Documentation
use super::*;

#[test]
fn canvas_rendering_context_2d_exposes_core_defaults() -> Result<()> {
    let html = r#"
        <canvas id='canvas' width='100' height='80'></canvas>
        <p id='result'></p>
        <script>
          const canvas = document.getElementById('canvas');
          const ctx = canvas.getContext('2d');
          const attrs = ctx.getContextAttributes();
          const dash = ctx.getLineDash();
          document.getElementById('result').textContent = [
            ctx.canvas === canvas,
            ctx.fillStyle,
            ctx.strokeStyle,
            ctx.lineWidth,
            ctx.lineCap,
            ctx.lineJoin,
            ctx.miterLimit,
            ctx.font,
            ctx.textAlign,
            ctx.textBaseline,
            ctx.direction,
            ctx.globalAlpha,
            ctx.globalCompositeOperation,
            ctx.imageSmoothingEnabled,
            ctx.imageSmoothingQuality,
            ctx.filter,
            attrs.alpha,
            ctx.isContextLost(),
            dash.length,
            typeof ctx.fillRect,
            typeof ctx.createLinearGradient,
            ctx.toString()
          ].join(':');
        </script>
        "#;

    let h = Harness::from_html(html)?;
    h.assert_text(
        "#result",
        "true:#000000:#000000:1:butt:miter:10:10px sans-serif:start:alphabetic:inherit:1:source-over:true:low:none:true:false:0:function:function:[object CanvasRenderingContext2D]",
    )?;
    Ok(())
}

#[test]
fn canvas_rendering_context_2d_tostring_bracket_call_and_raw_getter_parity_work() -> Result<()> {
    let html = r#"
        <canvas id='canvas' width='100' height='80'></canvas>
        <button id='run' type='button'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const ctx = document.getElementById('canvas').getContext('2d');
            const toStringFn = ctx['toString'];
            let bad = 'none';
            try {
              toStringFn.call({});
            } catch (e) {
              bad = String(e);
            }

            document.getElementById('result').textContent = [
              ctx.toString(),
              ctx['toString'](),
              String(ctx),
              toStringFn.call(ctx),
              String(toStringFn.name === 'toString'),
              String(toStringFn.length === 0),
              String(Function.prototype.toString.call(toStringFn) === toStringFn.toString()),
              String(bad.includes('CanvasRenderingContext2D method called on incompatible receiver'))
            ].join('|');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "[object CanvasRenderingContext2D]|[object CanvasRenderingContext2D]|[object CanvasRenderingContext2D]|[object CanvasRenderingContext2D]|true|true|true|true",
    )?;
    Ok(())
}

#[test]
fn canvas_rendering_context_2d_tracks_dash_transform_and_image_data_calls() -> Result<()> {
    let html = r#"
        <canvas id='canvas' width='100' height='80'></canvas>
        <button id='run' type='button'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const canvas = document.getElementById('canvas');
            const ctx = canvas.getContext('2d');

            ctx.setLineDash([5, 2, 1]);
            const dash = ctx.getLineDash().join(',');

            ctx.setTransform(1, 0, 0, 1, 12, 34);
            ctx.transform(2, 0, 0, 2, 1, 1);
            const t1 = ctx.getTransform();

            ctx.setTransform({ a: 3, d: 4, e: 5, f: 6 });
            const t2 = ctx.getTransform();

            const textWidth = ctx.measureText('abcd').width;
            const gradient = ctx.createLinearGradient(0, 0, 10, 10);
            gradient.addColorStop(0, 'red');
            const pattern = ctx.createPattern(canvas, 'repeat');
            pattern.setTransform({});

            const imageA = ctx.createImageData(2, 3);
            const imageB = ctx.getImageData(0, 0, 4, 1);
            const imageC = ctx.createImageData(imageB);

            ctx.putImageData(imageA, 0, 0);
            ctx.fillText('a', 1, 2);
            ctx.strokeText('b', 3, 4, 100);

            ctx.beginPath();
            ctx.moveTo(0, 0);
            ctx.lineTo(10, 10);
            ctx.bezierCurveTo(1, 1, 2, 2, 3, 3);
            ctx.quadraticCurveTo(1, 1, 2, 2);
            ctx.arc(5, 5, 2, 0, 3.14);
            ctx.arcTo(1, 1, 2, 2, 3);
            ctx.ellipse(5, 5, 2, 3, 0, 0, 3.14);
            ctx.rect(0, 0, 4, 4);
            ctx.roundRect(0, 0, 4, 4, 1);
            ctx.fill();
            ctx.stroke();
            ctx.clip();
            ctx.drawImage(canvas, 0, 0);

            document.getElementById('result').textContent = [
              dash,
              t1.a,
              t1.d,
              t1.e,
              t1.f,
              t2.a,
              t2.d,
              t2.e,
              t2.f,
              textWidth,
              typeof gradient.addColorStop,
              pattern !== null,
              imageA.width,
              imageA.height,
              imageA.data.length,
              imageB.data.length,
              imageC.width,
              imageC.height,
              ctx.isPointInPath(1, 1),
              ctx.isPointInStroke(1, 1)
            ].join(':');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "5,2,1,5,2,1:2:2:13:35:3:4:5:6:40:function:true:2:3:24:16:4:1:false:false",
    )?;
    Ok(())
}

#[test]
fn canvas_rendering_context_2d_reset_and_property_normalization_work() -> Result<()> {
    let html = r#"
        <canvas id='canvas' width='100' height='80'></canvas>
        <button id='run' type='button'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const canvas = document.getElementById('canvas');
            const ctx = canvas.getContext('2d');

            ctx.globalAlpha = 2;
            ctx.lineWidth = -1;
            ctx.lineCap = 'invalid';
            ctx.imageSmoothingEnabled = 0;
            ctx.imageSmoothingQuality = 'high';

            const normalized = [
              ctx.globalAlpha,
              ctx.lineWidth,
              ctx.lineCap,
              ctx.imageSmoothingEnabled,
              ctx.imageSmoothingQuality
            ].join(',');

            ctx.lineWidth = 9;
            ctx.lineCap = 'round';
            ctx.fillStyle = 'green';
            ctx.globalAlpha = 0.3;
            ctx.filter = 'blur(1px)';
            ctx.setLineDash([4, 1]);
            ctx.setTransform(2, 0, 0, 2, 9, 9);
            ctx.reset();

            const t = ctx.getTransform();
            document.getElementById('result').textContent = [
              normalized,
              ctx.lineWidth,
              ctx.lineCap,
              ctx.fillStyle,
              ctx.globalAlpha,
              ctx.filter,
              ctx.getLineDash().length,
              t.a,
              t.d,
              t.e,
              t.f
            ].join(':');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "1,1,butt,false,high:1:butt:#000000:1:none:0:1:1:0:0",
    )?;
    Ok(())
}

#[test]
fn canvas_rendering_context_2d_draw_image_accepts_image_bitmap_sources() -> Result<()> {
    let html = r#"
      <input id='file' type='file' accept='image/png'>
      <p id='out'></p>
      <script>
        const input = document.getElementById('file');
        input.addEventListener('change', async () => {
          try {
            const file = input.files[0];
            const bmp = await createImageBitmap(file);
            const canvas = document.createElement('canvas');
            canvas.width = bmp.width;
            canvas.height = bmp.height;
            const ctx = canvas.getContext('2d');
            if (!ctx) {
              document.getElementById('out').textContent = 'noctx';
              return;
            }
            ctx.drawImage(bmp, 0, 0);
            document.getElementById('out').textContent =
              `${typeof ctx.drawImage}:${canvas.width}x${canvas.height}`;
          } catch (e) {
            document.getElementById('out').textContent = 'error:' + String(e);
          }
        });
      </script>
    "#;

    let mut h = Harness::from_html(html)?;
    let png_with_2x3_ihdr = [
        137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 2, 0, 0, 0, 3, 8, 2,
        0, 0, 0,
    ];
    let mut file = MockFile::new("shape.png").with_bytes(&png_with_2x3_ihdr);
    file.mime_type = "image/png".to_string();
    h.set_input_files("#file", &[file])?;
    h.assert_text("#out", "function:2x3")?;
    Ok(())
}