browser_tester 1.5.0

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

#[test]
fn hash_change_event_constructor_populates_properties() -> Result<()> {
    let html = r#"
        <p id='result'></p>
        <script>
          const ev = new HashChangeEvent('hashchange', {
            oldURL: 'https://a.test/path#old',
            newURL: 'https://a.test/path#new',
            bubbles: true,
            cancelable: true
          });
          document.getElementById('result').textContent = [
            ev.type,
            ev.oldURL,
            ev.newURL,
            ev.bubbles,
            ev.cancelable,
            ev.isTrusted
          ].join('~');
        </script>
        "#;

    let h = Harness::from_html(html)?;
    h.assert_text(
        "#result",
        "hashchange~https://a.test/path#old~https://a.test/path#new~true~true~false",
    )?;
    Ok(())
}

#[test]
fn dispatch_event_with_hash_change_event_payload_preserves_fields() -> 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('hashchange', (event) => {
            document.getElementById('result').textContent = [
              event.oldURL,
              event.newURL,
              event.isTrusted
            ].join('~');
          });

          document.getElementById('run').addEventListener('click', () => {
            const ev = new HashChangeEvent('hashchange', {
              oldURL: 'https://old.test/app#before',
              newURL: 'https://old.test/app#after'
            });
            target.dispatchEvent(ev);
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "https://old.test/app#before~https://old.test/app#after~false",
    )?;
    Ok(())
}

#[test]
fn hash_change_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 HashChangeEvent('hashchange', 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(())
}

#[test]
fn location_hash_navigation_dispatches_hashchange_event_with_old_and_new_urls() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          const logs = [];
          window.addEventListener('hashchange', (event) => {
            logs.push([
              event.type,
              event.oldURL,
              event.newURL,
              event.bubbles,
              event.cancelable,
              event.isTrusted
            ].join('~'));
          });

          document.getElementById('run').addEventListener('click', () => {
            location.href = 'https://app.local/path';
            location.hash = 'frag';
            document.getElementById('result').textContent = logs.join('||');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "hashchange~https://app.local/path~https://app.local/path#frag~false~false~true",
    )?;
    Ok(())
}

#[test]
fn location_hash_navigation_uses_normalized_urls_after_default_port_navigation() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          const logs = [];
          window.addEventListener('hashchange', (event) => {
            logs.push(event.oldURL + '~' + event.newURL);
          });

          document.getElementById('run').addEventListener('click', () => {
            location.href = 'http://example.com:80/path';
            location.hash = 'frag';
            document.getElementById('result').textContent = [
              location.href,
              logs.join('||')
            ].join('|');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "http://example.com/path#frag|http://example.com/path~http://example.com/path#frag",
    )?;
    assert_eq!(
        h.take_location_navigations(),
        vec![
            LocationNavigation {
                kind: LocationNavigationKind::HrefSet,
                from: "about:blank".to_string(),
                to: "http://example.com/path".to_string(),
            },
            LocationNavigation {
                kind: LocationNavigationKind::HrefSet,
                from: "http://example.com/path".to_string(),
                to: "http://example.com/path#frag".to_string(),
            },
        ]
    );
    Ok(())
}

#[test]
fn location_same_url_setters_do_not_dispatch_hashchange_or_record_navigation_work() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          const logs = [];
          window.addEventListener('hashchange', (event) => {
            logs.push(event.oldURL + '~' + event.newURL);
          });

          document.getElementById('run').addEventListener('click', () => {
            location.href = 'https://app.local/path#frag';
            location.hash = 'frag';
            location.hash = '#frag';
            location.port = '443';
            location.hostname = 'app.local';
            location.pathname = '/path';
            location.search = '';
            location.protocol = 'https:';
            document.getElementById('result').textContent = [
              location.href,
              logs.length
            ].join('|');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text("#result", "https://app.local/path#frag|0")?;
    assert_eq!(
        h.take_location_navigations(),
        vec![LocationNavigation {
            kind: LocationNavigationKind::HrefSet,
            from: "about:blank".to_string(),
            to: "https://app.local/path#frag".to_string(),
        }]
    );
    Ok(())
}