browser_tester 1.5.0

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

#[test]
fn element_client_width_includes_padding_and_excludes_border() -> Result<()> {
    let html = r#"
        <div id='box' style='width: 100px; padding: 20px; padding-right: 10px; border: 5px solid black;'></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const box = document.getElementById('box');
            document.getElementById('result').textContent = String(box.clientWidth);
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text("#result", "130")?;
    Ok(())
}

#[test]
fn element_client_width_is_zero_for_inline_or_no_layout_box_elements() -> Result<()> {
    let html = r#"
        <span id='inline' style='display:inline; width: 100px; padding: 20px;'></span>
        <div id='hidden' style='display:none; width: 100px; padding: 20px;'></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const inline = document.getElementById('inline');
            const hidden = document.getElementById('hidden');
            const detached = document.createElement('div');
            detached.style.width = '40px';
            detached.style.padding = '10px';
            document.getElementById('result').textContent = [
              inline.clientWidth,
              hidden.clientWidth,
              detached.clientWidth
            ].join(':');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text("#result", "0:0:0")?;
    Ok(())
}

#[test]
fn document_element_client_width_uses_window_inner_width() -> Result<()> {
    let html = r#"
        <html>
          <body>
            <button id='run'>run</button>
            <p id='result'></p>
            <script>
              document.getElementById('run').addEventListener('click', () => {
                window.innerWidth = 845.9;
                document.getElementById('result').textContent =
                  String(document.documentElement.clientWidth);
              });
            </script>
          </body>
        </html>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text("#result", "845")?;
    Ok(())
}

#[test]
fn layout_derived_properties_shadow_define_property_delete_and_fast_path_parity_work() -> Result<()>
{
    let html = r#"
        <div
          id='box'
          style='width: 100px; height: 80px; padding-left: 7px; padding-right: 15px; padding-top: 10px; padding-bottom: 5px; border-left: 4px solid black; border-top: 6px solid black;'
        ></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const box = document.getElementById('box');

            Object.defineProperty(box, 'clientWidth', { value: 'cw', configurable: true });
            Object.defineProperty(box, 'clientHeight', { get() { return 'ch'; }, configurable: true });
            Object.defineProperty(box, 'clientLeft', { value: 'cl', configurable: true });
            Object.defineProperty(box, 'clientTop', { value: 'ct', configurable: true });
            Object.defineProperty(box, 'currentCSSZoom', { value: 'zoom', configurable: true });
            Object.defineProperty(box, 'offsetWidth', { value: 'ow', configurable: true });
            Object.defineProperty(box, 'offsetHeight', { value: 'oh', configurable: true });
            Object.defineProperty(box, 'offsetLeft', { value: 'ol', configurable: true });
            Object.defineProperty(box, 'offsetTop', { value: 'ot', configurable: true });
            Object.defineProperty(box, 'scrollWidth', { value: 'sw', configurable: true });
            Object.defineProperty(box, 'scrollHeight', { value: 'sh', configurable: true });
            Object.defineProperty(box, 'scrollLeft', { value: 'sl', configurable: true });
            Object.defineProperty(box, 'scrollTop', { value: 'st', configurable: true });
            Object.defineProperty(box, 'scrollLeftMax', { value: 'slm', configurable: true });
            Object.defineProperty(box, 'scrollTopMax', { value: 'stm', configurable: true });

            const shadow = [
              box.clientWidth,
              box.clientHeight,
              box.clientLeft,
              box.clientTop,
              box.currentCSSZoom,
              box.offsetWidth,
              box.offsetHeight,
              box.offsetLeft,
              box.offsetTop,
              box.scrollWidth,
              box.scrollHeight,
              box.scrollLeft,
              box.scrollTop,
              box.scrollLeftMax,
              box.scrollTopMax
            ].join(':');

            delete box.clientWidth;
            delete box.clientHeight;
            delete box.clientLeft;
            delete box.clientTop;
            delete box.currentCSSZoom;
            delete box.offsetWidth;
            delete box.offsetHeight;
            delete box.offsetLeft;
            delete box.offsetTop;
            delete box.scrollWidth;
            delete box.scrollHeight;
            delete box.scrollLeft;
            delete box.scrollTop;
            delete box.scrollLeftMax;
            delete box.scrollTopMax;

            const restored = [
              box.clientWidth,
              box.clientHeight,
              box.clientLeft,
              box.clientTop,
              box.currentCSSZoom,
              box.offsetWidth,
              box.offsetHeight,
              box.offsetLeft,
              box.offsetTop,
              box.scrollWidth,
              box.scrollHeight,
              box.scrollLeft,
              box.scrollTop,
              box.scrollLeftMax,
              box.scrollTopMax
            ].join(':');

            document.getElementById('result').textContent = [shadow, restored].join('|');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "cw:ch:cl:ct:zoom:ow:oh:ol:ot:sw:sh:sl:st:slm:stm|122:95:4:6:1:0:0:0:0:0:0:0:0:0:0",
    )?;
    Ok(())
}

#[test]
fn reduced_layout_derived_metrics_stay_off_instance_copy_surface_until_shadowed_work() -> Result<()>
{
    let html = r#"
        <div id='box' style='width: 100px; height: 80px; padding-left: 7px; padding-right: 15px; border-left: 4px solid black;'></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const box = document.getElementById('box');

            const before = [
              String(Object.getOwnPropertyDescriptor(box, 'clientWidth') === undefined),
              String(Object.getOwnPropertyDescriptor(box, 'offsetWidth') === undefined),
              String(Object.keys(Object.assign({}, box)).includes('clientWidth')),
              String(Object.keys({ ...box }).includes('offsetWidth'))
            ].join(':');

            Object.defineProperty(box, 'clientWidth', {
              value: 'cw',
              enumerable: true,
              configurable: true
            });

            const shadowed = [
              box.clientWidth,
              String(Object.keys(Object.assign({}, box)).includes('clientWidth')),
              String(Object.keys({ ...box }).includes('clientWidth'))
            ].join(':');

            delete box.clientWidth;

            const restored = [
              String(Object.getOwnPropertyDescriptor(box, 'clientWidth') === undefined),
              String(Object.keys(Object.assign({}, box)).includes('clientWidth')),
              String(Object.keys({ ...box }).includes('clientWidth')),
              String(box.clientWidth)
            ].join(':');

            document.getElementById('result').textContent =
              [before, shadowed, restored].join('|');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "true:true:false:false|cw:true:true|true:false:false:122",
    )?;
    Ok(())
}