browser_tester 1.5.0

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

#[test]
fn before_unload_event_constructor_exposes_legacy_return_value() -> Result<()> {
    let html = r#"
        <p id='result'></p>
        <script>
          const ev = new BeforeUnloadEvent('beforeunload');
          document.getElementById('result').textContent = [
            ev.type,
            ev.returnValue === '',
            ev.defaultPrevented,
            ev.cancelable
          ].join(':');
        </script>
        "#;

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

#[test]
fn before_unload_event_constructor_return_value_can_mark_default_prevented() -> Result<()> {
    let html = r#"
        <p id='result'></p>
        <script>
          const ev = new BeforeUnloadEvent('beforeunload', {
            cancelable: true,
            returnValue: 'leave?'
          });
          document.getElementById('result').textContent = [
            ev.returnValue,
            ev.defaultPrevented,
            ev.cancelable
          ].join(':');
        </script>
        "#;

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

#[test]
fn before_unload_event_return_value_assignment_cancels_dispatch() -> Result<()> {
    let html = r#"
        <div id='target'></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          const target = document.getElementById('target');
          target.addEventListener('beforeunload', (event) => {
            event.returnValue = 'stay';
            document.getElementById('result').textContent = [
              event.returnValue,
              event.defaultPrevented
            ].join(':');
          });

          document.getElementById('run').addEventListener('click', () => {
            const ok = target.dispatchEvent(
              new BeforeUnloadEvent('beforeunload', { cancelable: true })
            );
            document.getElementById('result').textContent =
              document.getElementById('result').textContent + ':' + String(ok);
          });
        </script>
        "#;

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

#[test]
fn before_unload_event_return_value_propagates_to_later_listeners() -> Result<()> {
    let html = r#"
        <div id='target'></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          const target = document.getElementById('target');
          target.addEventListener('beforeunload', (event) => {
            const alias = event;
            alias.returnValue = 'stay';
          });
          target.addEventListener('beforeunload', (event) => {
            document.getElementById('result').textContent = [
              event.returnValue,
              event.defaultPrevented
            ].join(':');
          });

          document.getElementById('run').addEventListener('click', () => {
            const ok = target.dispatchEvent(
              new BeforeUnloadEvent('beforeunload', { cancelable: true })
            );
            document.getElementById('result').textContent =
              document.getElementById('result').textContent + ':' + String(ok);
          });
        </script>
        "#;

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

#[test]
fn before_unload_return_value_define_property_and_delete_work() -> Result<()> {
    let html = r#"
        <div id='target'></div>
        <button id='btn'>run</button>
        <p id='result'></p>
        <script>
          const target = document.getElementById('target');
          target.addEventListener('beforeunload', (event) => {
            Object.defineProperty(event, 'returnValue', {
              value: 'stay',
              configurable: true
            });
            const descriptor = Object.getOwnPropertyDescriptor(event, 'returnValue').value;
            const before = event.returnValue;
            const deleted = delete event.returnValue;
            const afterDelete = event.returnValue === undefined;
            Object.defineProperty(event, 'returnValue', {
              value: 'next',
              configurable: true
            });
            document.getElementById('result').textContent = [
              descriptor,
              before,
              deleted,
              afterDelete,
              event.returnValue
            ].join('|');
          });
          document.getElementById('btn').addEventListener('click', () => {
            target.dispatchEvent(
              new BeforeUnloadEvent('beforeunload', { cancelable: true })
            );
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#btn")?;
    h.assert_text("#result", "stay|stay|true|true|next")?;
    Ok(())
}

#[test]
fn before_unload_event_constructor_rejects_non_object_options() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            let threw = false;
            try {
              new BeforeUnloadEvent('beforeunload', 123);
            } catch (error) {
              threw = String(error).includes('options argument must be an object');
            }
            document.getElementById('result').textContent = String(threw);
          });
        </script>
        "#;

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