browser_tester 1.5.0

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

#[test]
fn element_shadow_root_is_null_without_attached_open_shadow_root() -> Result<()> {
    let html = r#"
        <div id='host'></div>
        <img id='pic' alt='logo'>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const host = document.getElementById('host');
            const pic = document.getElementById('pic');

            let readOnly = false;
            try {
              host.shadowRoot = document.createElement('div');
            } catch (e) {
              readOnly = String(e).includes('shadowRoot is read-only');
            }

            document.getElementById('result').textContent = [
              host.shadowRoot === null,
              pic.shadowRoot === null,
              readOnly
            ].join(':');
          });
        </script>
        "#;

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

#[test]
fn element_shadow_root_returns_open_shadow_root_and_updates_style_node_like_mdn_example()
-> Result<()> {
    let html = r#"
        <div id='host' l='120' c='tomato'></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          function updateStyle(elem) {
            const shadow = elem.shadowRoot;
            const childNodes = Array.from(shadow.childNodes);

            childNodes.forEach((childNode) => {
              if (childNode.nodeName === 'STYLE') {
                childNode.textContent =
                  'div{width:' + elem.getAttribute('l') + 'px;height:' +
                  elem.getAttribute('l') + 'px;background-color:' +
                  elem.getAttribute('c') + ';}';
              }
            });
          }

          document.getElementById('run').addEventListener('click', () => {
            const host = document.getElementById('host');
            const root = host.attachShadow({ mode: 'open' });
            root.innerHTML = '<style></style><div id="square"></div>';
            updateStyle(host);

            const styleText = root.querySelector('style').textContent;
            document.getElementById('result').textContent = [
              host.shadowRoot === root,
              host.shadowRoot.childNodes.length,
              styleText.includes('width:120px'),
              styleText.includes('background-color:tomato'),
              host.childNodes.length
            ].join(':');
          });
        </script>
        "#;

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

#[test]
fn element_shadow_root_returns_null_for_closed_mode_but_attach_shadow_returns_root() -> Result<()> {
    let html = r#"
        <div id='host'></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const host = document.getElementById('host');
            const root = host.attachShadow({ mode: 'closed' });
            root.innerHTML = '<span id="inside">inside</span>';

            document.getElementById('result').textContent = [
              host.shadowRoot === null,
              root.childNodes.length,
              root.querySelector('#inside').textContent
            ].join(':');
          });
        </script>
        "#;

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

#[test]
fn element_attach_shadow_validates_options_and_rejects_second_attachment() -> Result<()> {
    let html = r#"
        <div id='a'></div>
        <div id='b'></div>
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const a = document.getElementById('a');
            const b = document.getElementById('b');

            let missingMode = false;
            try {
              a.attachShadow({});
            } catch (e) {
              missingMode = String(e).includes('mode is required');
            }

            let invalidMode = false;
            try {
              a.attachShadow({ mode: 'OPEN' });
            } catch (e) {
              invalidMode = String(e).includes("must be 'open' or 'closed'");
            }

            b.attachShadow({ mode: 'open' });
            let secondAttachThrows = false;
            try {
              b.attachShadow({ mode: 'open' });
            } catch (e) {
              secondAttachThrows = String(e).includes('NotSupportedError');
            }

            document.getElementById('result').textContent = [
              missingMode,
              invalidMode,
              secondAttachThrows
            ].join(':');
          });
        </script>
        "#;

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