browser_tester 1.5.0

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

#[test]
fn data_transfer_constructor_creates_empty_data_transfer_object() -> Result<()> {
    let html = r#"
      <p id='out'></p>
      <script>
        const dt = new DataTransfer();
        document.getElementById('out').textContent = [
          dt.dropEffect,
          dt.effectAllowed,
          dt['types']['length'],
          dt['items']['length'],
          dt['files']['length'],
          dt.getData('text/plain') === ''
        ].join('|');
      </script>
    "#;

    let h = Harness::from_html(html)?;
    h.assert_text("#out", "none|all|0|0|0|true")?;
    Ok(())
}

#[test]
fn data_transfer_constructor_supports_set_data_get_data_and_clear_data() -> Result<()> {
    let html = r#"
      <p id='out'></p>
      <script>
        const dt = new DataTransfer();
        const setRet = dt.setData('text/plain', 'alpha');
        const beforeClear = dt.getData('text');
        const clearRet = dt.clearData('text/plain');
        document.getElementById('out').textContent = [
          setRet === undefined,
          beforeClear,
          clearRet === undefined,
          dt.getData('text/plain') === '',
          dt['types']['length'],
          dt['items']['length']
        ].join('|');
      </script>
    "#;

    let h = Harness::from_html(html)?;
    h.assert_text("#out", "true|alpha|true|true|0|0")?;
    Ok(())
}

#[test]
fn data_transfer_drop_effect_and_effect_allowed_enforce_allowed_values() -> Result<()> {
    let html = r#"
      <p id='out'></p>
      <script>
        const dt = new DataTransfer();

        dt.dropEffect = 'copy';
        const dropAfterValid = dt.dropEffect;
        dt.dropEffect = 'INVALID';
        const dropAfterInvalid = dt.dropEffect;

        dt.effectAllowed = 'copyLink';
        const effectAfterValid = dt.effectAllowed;
        dt.effectAllowed = 'INVALID';
        const effectAfterInvalid = dt.effectAllowed;
        dt.effectAllowed = 'COPYMOVE';
        const effectAfterUpper = dt.effectAllowed;

        document.getElementById('out').textContent = [
          dropAfterValid,
          dropAfterInvalid,
          effectAfterValid,
          effectAfterInvalid,
          effectAfterUpper
        ].join('|');
      </script>
    "#;

    let h = Harness::from_html(html)?;
    h.assert_text("#out", "copy|none|copyLink|copyLink|copyMove")?;
    Ok(())
}

#[test]
fn data_transfer_types_items_and_files_are_read_only_on_assignment() -> Result<()> {
    let html = r#"
      <p id='out'></p>
      <script>
        const dt = new DataTransfer();
        dt.setData('text/plain', 'alpha');

        dt.types = ['application/json'];
        dt.items = [];
        dt.files = [];

        document.getElementById('out').textContent = [
          dt['types']['length'],
          dt['types'][0],
          dt['items']['length'],
          dt['files']['length'],
          dt.getData('text/plain')
        ].join('|');
      </script>
    "#;

    let h = Harness::from_html(html)?;
    h.assert_text("#out", "1|text/plain|1|0|alpha")?;
    Ok(())
}

#[test]
fn data_transfer_add_element_accepts_element_and_returns_undefined() -> Result<()> {
    let html = r#"
      <div id='source'></div>
      <p id='out'></p>
      <script>
        const dt = new DataTransfer();
        const ret = dt.addElement(document.getElementById('source'));
        document.getElementById('out').textContent = String(ret === undefined);
      </script>
    "#;

    let h = Harness::from_html(html)?;
    h.assert_text("#out", "true")?;
    Ok(())
}

#[test]
fn data_transfer_add_element_rejects_non_element_argument() {
    let html = r#"
      <div id='source'></div>
      <script>
        document.getElementById('source').addEventListener('dragstart', () => {
          const dt = new DataTransfer();
          dt.addElement('not-element');
        });
      </script>
    "#;

    let mut h = Harness::from_html(html).expect("harness should initialize");
    let err = h
        .dispatch("#source", "dragstart")
        .expect_err("addElement should reject non-element argument");
    match err {
        Error::ScriptRuntime(msg) => assert_eq!(
            msg,
            "TypeError: Failed to execute 'addElement': parameter 1 is not of type 'Element'"
        ),
        other => panic!("unexpected error: {other:?}"),
    }
}

#[test]
fn data_transfer_constructor_rejects_arguments() {
    let html = r#"
      <div id='source'></div>
      <script>
        document.getElementById('source').addEventListener('dragstart', () => {
          new DataTransfer('unexpected');
        });
      </script>
    "#;

    let mut h = Harness::from_html(html).expect("harness should initialize");
    let err = h
        .dispatch("#source", "dragstart")
        .expect_err("DataTransfer constructor should reject arguments");
    match err {
        Error::ScriptRuntime(msg) => {
            assert_eq!(msg, "DataTransfer constructor does not take arguments")
        }
        other => panic!("unexpected error: {other:?}"),
    }
}

#[test]
fn data_transfer_constructor_surface_and_prototype_branding_work() -> Result<()> {
    let html = r#"
      <p id='out'></p>
      <script>
        const dt = new DataTransfer();
        const proto = DataTransfer.prototype;
        const getDataDesc = Object.getOwnPropertyDescriptor(proto, 'getData');
        const setDataDesc = Object.getOwnPropertyDescriptor(proto, 'setData');
        const clearDataDesc = Object.getOwnPropertyDescriptor(proto, 'clearData');

        document.getElementById('out').textContent = [
          typeof DataTransfer,
          String(window.DataTransfer === DataTransfer),
          String(dt.constructor === DataTransfer),
          String(Object.getPrototypeOf(dt) === DataTransfer.prototype),
          String(Object.getPrototypeOf(DataTransfer.prototype) === Object.prototype),
          Object.getOwnPropertyNames(DataTransfer.prototype).sort().join(','),
          String(typeof getDataDesc.value),
          String(getDataDesc.value.name),
          String(getDataDesc.value.length),
          String(getDataDesc.enumerable),
          String(setDataDesc.value.length),
          String(clearDataDesc.value.length),
          Object.prototype.toString.call(dt)
        ].join('|');
      </script>
    "#;

    let h = Harness::from_html(html)?;
    h.assert_text(
        "#out",
        "function|true|true|true|true|addElement,clearData,constructor,getData,setData,setDragImage|function|getData|1|false|2|0|[object DataTransfer]",
    )?;
    Ok(())
}