browser_tester 1.5.0

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

#[test]
fn text_decoder_default_utf8_decodes_multibyte_text() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const decoder = new TextDecoder();
            const encoded = new Uint8Array([240, 160, 174, 183]);
            document.getElementById('result').textContent = decoder.decode(encoded);
          });
        </script>
        "#;

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

#[test]
fn text_decoder_windows_1251_decodes_russian_text() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const decoder = new TextDecoder('windows-1251');
            const encoded = new Uint8Array([
              207, 240, 232, 226, 229, 242, 44, 32, 236, 232, 240, 33
            ]);
            document.getElementById('result').textContent = decoder.decode(encoded);
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text("#result", "Привет, мир!")?;
    Ok(())
}

#[test]
fn text_decoder_properties_reflect_options_and_are_read_only() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const decoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
            const before = [decoder.encoding, decoder.fatal, decoder.ignoreBOM].join(':');
            decoder.encoding = 'windows-1251';
            decoder.fatal = false;
            decoder.ignoreBOM = false;
            const after = [decoder.encoding, decoder.fatal, decoder.ignoreBOM].join(':');
            document.getElementById('result').textContent = before + '|' + after;
          });
        </script>
        "#;

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

#[test]
fn text_decoder_decode_supports_array_buffer_and_default_empty_input() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const decoder = new TextDecoder();
            const bytes = new Uint8Array([65, 66, 67]);
            const fromBuffer = decoder.decode(bytes.buffer);
            const fromEmpty = decoder.decode();
            document.getElementById('result').textContent = fromBuffer + ':' + fromEmpty.length;
          });
        </script>
        "#;

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

#[test]
fn text_decoder_fatal_and_ignore_bom_options_work() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const fatal = new TextDecoder('utf-8', { fatal: true });
            let fatalError = false;
            try {
              fatal.decode(new Uint8Array([0xFF]));
            } catch (e) {
              fatalError = String(e).includes('invalid UTF-8');
            }

            const keepBom = new TextDecoder('utf-8', { ignoreBOM: true });
            const stripBom = new TextDecoder('utf-8');
            const payload = new Uint8Array([0xEF, 0xBB, 0xBF, 0x41]);
            const kept = keepBom.decode(payload);
            const stripped = stripBom.decode(payload);

            document.getElementById('result').textContent = [
              fatalError,
              kept.length,
              kept.codePointAt(0),
              kept.codePointAt(1),
              stripped.length,
              stripped.codePointAt(0)
            ].join(':');
          });
        </script>
        "#;

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

#[test]
fn text_decoder_has_branded_prototype_surface_and_validates_receiver() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='result'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const decoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
            const encodingGetter = Object.getOwnPropertyDescriptor(TextDecoder.prototype, 'encoding').get;
            let receiverError = false;
            try {
              TextDecoder.prototype.decode.call({}, new Uint8Array([65]));
            } catch (e) {
              receiverError = String(e).includes('incompatible receiver');
            }
            document.getElementById('result').textContent = [
              Object.prototype.toString.call(decoder),
              TextDecoder.prototype[Symbol.toStringTag],
              String(Object.getPrototypeOf(decoder) === TextDecoder.prototype),
              String(decoder.constructor === TextDecoder),
              String(encodingGetter.call(decoder)),
              String(TextDecoder.prototype.decode.call(decoder, new Uint8Array([65]))),
              String(receiverError)
            ].join('|');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#result",
        "[object TextDecoder]|TextDecoder|true|true|utf-8|A|true",
    )?;
    Ok(())
}