browser_tester 1.5.0

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

#[test]
fn async_generator_function_constructor_builds_async_generator_functions() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='out'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const AsyncGeneratorFunction = (async function* () {}).constructor;
            const byNew = new AsyncGeneratorFunction(`
              yield await Promise.resolve('a');
              yield await Promise.resolve('b');
              yield await Promise.resolve('c');
            `);
            const byCall = AsyncGeneratorFunction(
              'yield await Promise.resolve(1); yield* [2, 3];'
            );
            const empty = AsyncGeneratorFunction();

            const fromNew = byNew();
            const fromCall = byCall();
            const fromEmpty = empty();
            const selfFactory = fromNew[Symbol.asyncIterator];
            const self = selfFactory();
            const tag = AsyncGeneratorFunction.prototype[Symbol.toStringTag];

            Promise.all([
              fromNew.next(),
              fromNew.next(),
              fromNew.next(),
              fromNew.next(),
              fromCall.next(),
              fromCall.next(),
              fromCall.next(),
              fromCall.next(),
              fromEmpty.next(),
            ]).then((results) => {
              const a = results[0];
              const b = results[1];
              const c = results[2];
              const d = results[3];
              const n1 = results[4];
              const n2 = results[5];
              const n3 = results[6];
              const nDone = results[7];
              const emptyDone = results[8];
              const letters = a.value + b.value + c.value;
              const numbers = n1.value + ',' + n2.value + ',' + n3.value;
              const doneFlags =
                d.done + ':' + nDone.done + ':' + emptyDone.done;
              document.getElementById('out').textContent =
                letters + '|' +
                numbers + '|' +
                doneFlags + '|' +
                tag + '|' +
                (self === fromNew) + '|' +
                (typeof fromNew[Symbol.iterator]);
            });
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#out",
        "abc|1,2,3|true:true:true|AsyncGeneratorFunction|true|undefined",
    )?;
    Ok(())
}

#[test]
fn global_async_generator_function_constructor_surface_and_prototype_chain_work() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='out'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const sample = async function* namedAsyncGen() {};
            const byGlobal = AsyncGeneratorFunction(
              'yield await Promise.resolve(1); yield 2;'
            );
            const iter = byGlobal();
            Promise.all([iter.next(), iter.next(), iter.next()]).then((results) => {
              document.getElementById('out').textContent = [
                typeof AsyncGeneratorFunction,
                String(window.AsyncGeneratorFunction === AsyncGeneratorFunction),
                AsyncGeneratorFunction.name,
                String(AsyncGeneratorFunction.length),
                String(Object.getPrototypeOf(AsyncGeneratorFunction) === Function.prototype),
                String(Object.getPrototypeOf(sample) === AsyncGeneratorFunction.prototype),
                byGlobal.name,
                String(byGlobal.length),
                String(byGlobal.constructor === AsyncGeneratorFunction),
                String(byGlobal.toString().includes('__bt_function_ref__(')),
                results[0].value + ',' + results[1].value,
                String(results[2].done)
              ].join('|');
            });
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text(
        "#out",
        "function|true|AsyncGeneratorFunction|1|true|true|anonymous|0|true|true|1,2|true",
    )?;
    Ok(())
}

#[test]
fn async_generator_function_native_source_text_and_hidden_surface_work() -> Result<()> {
    let html = r#"
        <button id='run'>run</button>
        <p id='out'></p>
        <script>
          document.getElementById('run').addEventListener('click', () => {
            const ctorText = AsyncGeneratorFunction.toString();
            const iterProto = AsyncGeneratorFunction.prototype.prototype;

            function forInKeys(value) {
              let out = '';
              for (const key in value) {
                out += key + ',';
              }
              return out || 'empty';
            }

            document.getElementById('out').textContent = [
              String(ctorText.includes('[native code]')),
              String(ctorText.includes('AsyncGeneratorFunction')),
              String(ctorText === Function.prototype.toString.call(AsyncGeneratorFunction)),
              String(ctorText === String(AsyncGeneratorFunction)),
              String(ctorText === new String(AsyncGeneratorFunction).valueOf()),
              String(Object.keys(AsyncGeneratorFunction).length),
              String(Object.keys(AsyncGeneratorFunction.prototype).length),
              String(Object.keys(iterProto).length),
              String(Object.keys({ ...AsyncGeneratorFunction.prototype }).length),
              String(Object.keys({ ...iterProto }).length),
              forInKeys(AsyncGeneratorFunction.prototype),
              forInKeys(iterProto),
              JSON.stringify(iterProto)
            ].join('|');
          });
        </script>
        "#;

    let mut h = Harness::from_html(html)?;
    h.click("#run")?;
    h.assert_text("#out", "true|true|true|true|true|0|0|0|0|0|empty|empty|{}")?;
    Ok(())
}