def test_interact():
    interactor = Interactor(runOpts=RunOpts.ON_ACTION)
    value = None

    def retain(func):
        """Retain result for post-call analysis"""
        @wraps(func)
        def wrapper(*args, **kwargs):
            nonlocal value
            value = func(*args, **kwargs)
            return value

        return wrapper

    @retain
    def a(x, y=5):
        return x, y

    with pytest.raises(ValueError):
        interactor(a)

    host = interactor(a, x=10)
    for child in "x", "y":
        assert child in host.names

    host = interactor(a, x=10, y={"type": "list", "limits": [5, 10]})
    testParam = host.child("y")
    assert testParam.type() == "list"
    assert testParam.opts["limits"] == [5, 10]

    myval = 5
    a_interact = InteractiveFunction(a, closures=dict(x=lambda: myval))
    host = interactor(a_interact)
    assert "x" not in host.names
    host.child("Run").activate()
    assert value == (5, 5)
    myval = 10
    host.child("Run").activate()
    assert value == (10, 5)

    host = interactor(a,
                      x=10,
                      y=50,
                      ignores=["x"],
                      runOpts=(RunOpts.ON_CHANGED, RunOpts.ON_CHANGING))
    for child in "x", "Run":
        assert child not in host.names

    host["y"] = 20
    assert value == (10, 20)
    host.child("y").sigValueChanging.emit(host.child("y"), 100)
    assert value == (10, 100)

    with interactor.optsContext(title=str.upper):
        host = interactor(a, x={"title": "different", "value": 5})
        titles = [p.title() for p in host]
        for ch in "different", "Y":
            assert ch in titles

    with interactor.optsContext(title="Group only"):
        host = interactor(a, x=1)
        assert host.title() == "Group only"
        assert [p.title() is None for p in host]

    with interactor.optsContext(runOpts=RunOpts.ON_CHANGED):
        host = interactor(a, x=5)
        host["y"] = 20
        assert value == (5, 20)
        assert "Run" not in host.names

    @retain
    def kwargTest(a, b=5, **c):
        return a + b - c.get("test", None)

    host = interactor(kwargTest, a=10, test=3)
    for ch in "a", "b", "test":
        assert ch in host.names
    host.child("Run").activate()
    assert value == 12

    host = GP.create(name="test deco", type="group")
    interactor.setOpts(parent=host)

    @interactor.decorate()
    @retain
    def a(x=5):
        return x

    assert "a" in host.names
    assert "x" in host.child("a").names
    host.child("a", "Run").activate()
    assert value == 5

    @interactor.decorate(nest=False, runOpts=RunOpts.ON_CHANGED)
    @retain
    def b(y=6):
        return y

    assert "b" not in host.names
    assert "y" in host.names
    host["y"] = 7
    assert value == 7

    def raw(x=5):
        return x

    @retain
    def override(**kwargs):
        return raw(**kwargs)

    host = interactor(wraps(raw)(override), runOpts=RunOpts.ON_CHANGED)
    assert "x" in host.names
    host["x"] = 100
    assert value == 100