In the discussion on #328 the consensus seems to be that people like type definitions. This moves toward generating types using jsdoc as suggested by @bollwyvl in that thread.

I don't have much Typescript experience so I would very much appreciate it if people could test them out. The types are available as CircleCI artifacts here:
https://3914-322074228-gh.circle-artifacts.com/0/root/repo/build/pyodide.d.ts

@bollwyvl said that

> types that aren't tested are probably worse than no types at all

If anyone could contribute tests, that would be very helpful (I don't know what they should look like). 

The main limitation I ran into with this approach is that Typescript supports Typescript types in jsdoc annotations but jsdoc does not. This means that if we want to automatically generate docs, we have to stick to the much more limited syntax that jsdoc supports. For example, `isPyProxy` should be typed `obj is PyProxy` but this approach does not allow that as far as I can tell. 
Some basic types. In the discussion on #328 the consensus seems to be that people like type definitions. This moves toward generating types using jsdoc as suggested by @bollwyvl in that thread.

I don't have much Typescript experience so I would very much appreciate it if people could test them out. The types are available as CircleCI artifacts here:
https://3914-322074228-gh.circle-artifacts.com/0/root/repo/build/pyodide.d.ts

@bollwyvl said that

> types that aren't tested are probably worse than no types at all

If anyone could contribute tests, that would be very helpful (I don't know what they should look like). 

The main limitation I ran into with this approach is that Typescript supports Typescript types in jsdoc annotations but jsdoc does not. This means that if we want to automatically generate docs, we have to stick to the much more limited syntax that jsdoc supports. For example, `isPyProxy` should be typed `obj is PyProxy` but this approach does not allow that as far as I can tell. 
from pathlib import Path

import pytest

from pyodide_build.common import UNVENDORED_STDLIB_MODULES


def test_cpython_core(python_test, selenium, request):

    name, error_flags = python_test

    # keep only flags related to the current browser
    flags_to_remove = ["firefox", "chrome"]
    flags_to_remove.remove(selenium.browser)
    for flag in flags_to_remove:
        if "crash-" + flag in error_flags:
            error_flags.remove("crash-" + flag)

    if any(flag.startswith("segfault") for flag in error_flags):
        pytest.skip('known segfault with code: "{}"'.format(",".join(error_flags)))

    if error_flags:
        if request.config.option.run_xfail:
            request.applymarker(
                pytest.mark.xfail(
                    run=False,
                    reason='known failure with code "{}"'.format(",".join(error_flags)),
                )
            )
        else:
            pytest.xfail('known failure with code "{}"'.format(",".join(error_flags)))

    selenium.load_package(UNVENDORED_STDLIB_MODULES)
    try:
        selenium.run(
            """
            from test.libregrtest import main
            try:
                main(['{}'], verbose=True, verbose3=True)
            except SystemExit as e:
                if e.code != 0:
                    raise RuntimeError(f'Failed with code: {{e.code}}')
            """.format(
                name
            )
        )
    except selenium.JavascriptException:
        print(selenium.logs)
        raise


def pytest_generate_tests(metafunc):
    if "python_test" in metafunc.fixturenames:
        test_modules = []
        test_modules_ids = []
        with open(Path(__file__).parent / "python_tests.txt") as fp:
            for line in fp:
                line = line.strip()
                if line.startswith("#") or not line:
                    continue
                error_flags = line.split()
                name = error_flags.pop(0)
                test_modules.append((name, error_flags))
                # explicitly define test ids to keep
                # a human readable test name in pytest
                test_modules_ids.append(name)
        metafunc.parametrize("python_test", test_modules, ids=test_modules_ids)

from pathlib import Path

import pytest

from pyodide_build.common import UNVENDORED_STDLIB_MODULES


def test_cpython_core(python_test, selenium, request):

    name, error_flags = python_test

    # keep only flags related to the current browser
    flags_to_remove = ["firefox", "chrome"]
    flags_to_remove.remove(selenium.browser)
    for flag in flags_to_remove:
        if "crash-" + flag in error_flags:
            error_flags.remove("crash-" + flag)

    if any(flag.startswith("segfault") for flag in error_flags):
        pytest.skip('known segfault with code: "{}"'.format(",".join(error_flags)))

    if error_flags:
        if request.config.option.run_xfail:
            request.applymarker(
                pytest.mark.xfail(
                    run=False,
                    reason='known failure with code "{}"'.format(",".join(error_flags)),
                )
            )
        else:
            pytest.xfail('known failure with code "{}"'.format(",".join(error_flags)))

    selenium.load_package(UNVENDORED_STDLIB_MODULES)
    try:
        selenium.run(
            """
            from test.libregrtest import main
            try:
                main(['{}'], verbose=True, verbose3=True)
            except SystemExit as e:
                if e.code != 0:
                    raise RuntimeError(f'Failed with code: {{e.code}}')
            """.format(
                name
            )
        )
    except selenium.JavascriptException:
        print(selenium.logs)
        raise


def pytest_generate_tests(metafunc):
    if "python_test" in metafunc.fixturenames:
        test_modules = []
        test_modules_ids = []
        with open(Path(__file__).parent / "python_tests.txt") as fp:
            for line in fp:
                line = line.strip()
                if line.startswith("#") or not line:
                    continue
                error_flags = line.split()
                name = error_flags.pop(0)
                test_modules.append((name, error_flags))
                # explicitly define test ids to keep
                # a human readable test name in pytest
                test_modules_ids.append(name)
        metafunc.parametrize("python_test", test_modules, ids=test_modules_ids)
