I’m writing an EditorGUI field for my custom serialized field, so I’m trying to mimic that API.
Here’s an example of what I’m trying to do:
public static Rect MyField(Rect position)
{
var evt = Event.current;
if (evt.type == EventType.MouseDown)
Debug.Log("MyField clicked!");
}
I’m trying to test it, with a TestEditorWindow
and onGui callbacks:
public class TestEditorWindow : EditorWindow
{
public Action onGui;
void OnGUI() => onGui?.Invoke();
}
[UnityTest]
public IEnumerator TestMyField()
{
bool onGuiCalled = false;
var position = new Rect(x: 0, y: 0, width: 150, height: 30);
void OnGUI()
{
var evt = new Event() { type = EventType.MouseDown, clickCount = 1, mousePosition = position.center };
Event.current = evt;
MyField(position);
onGuiCalled = true;
}
var testWindow = EditorWindow.GetWindow<TestEditorWindow>();
testWindow.onGui = OnGUI;
yield return new WaitUntil(() => onGuiCalled);
// Assert for MyField behavior here...
}
The issue I run into is that the EventType
is changed to EventType.Ignored
. I realize this is probably pretty poor testing behavior because the Layout and Repaint current events are overwritten.
I was thinking there was some behavior in Event.current
that was validating the set event, so I tried changing my custom field to look like
public static Rect MyField(Rect position, Event customEvent = null)
{
var evt = customEvent ?? Event.current;
if (evt.type == EventType.MouseDown)
Debug.Log("MyField clicked!");
}
And I changed the OnGUI
method in my test to look like:
void OnGUI()
{
var evt = new Event() { type = EventType.MouseDown, clickCount = 1, mousePosition = position.center };
MyField(position, evt);
onGuiCalled = true;
}
But somehow, the event type is still changed to EventType.Ignored
. I tried debugging the creation of the event, and the event type is changed when it’s passed to MyField
. I have no clue how this is happening.
After this, I was thinking that I probably shouldn’t be trying to set the current event while the OnGUI
method is being called. I reverted the changes I made earlier, and tried the following:
[UnityTest]
public IEnumerator TestMyField()
{
bool onGuiCalled = false;
var position = new Rect(x: 0, y: 0, width: 150, height: 30);
void OnGUI()
{
Event.current = evt;
MyField(position);
onGuiCalled = true;
}
var testWindow = EditorWindow.GetWindow<TestEditorWindow>();
testWindow.onGui = OnGUI;
var evt = new Event() { type = EventType.MouseDown, clickCount = 1, mousePosition = position.center };
Event.current = evt;
yield return new WaitUntil(() => onGuiCalled);
// Assert for MyField behavior here...
}
However, the OnGUI
method never received the set Event.current
. No amount of yield return null
and combinations of WaitUntil
could get the OnGUI
method to receive the event.
So I tried digging through the API one more time, and stumbled upon a method, EditorWindow.SendEvent
. It looked promising–perhaps this was the way I could invoke an event in an editor window.
[UnityTest]
public IEnumerator TestMyField()
{
bool onGuiCalled = false;
var position = new Rect(x: 0, y: 0, width: 150, height: 30);
void OnGUI()
{
Event.current = evt;
MyField(position);
onGuiCalled = true;
}
var testWindow = EditorWindow.GetWindow<TestEditorWindow>();
testWindow.onGui = OnGUI;
var evt = new Event() { type = EventType.MouseDown, clickCount = 1, mousePosition = position.center };
testWindow.SendEvent(evt);
yield return new WaitUntil(() => onGuiCalled);
// Assert for MyField behavior here...
}
Nope! Somehow, EditorWindow.SendEvent
automatically sets the EventType
to EventType.Used
.
I’ve been bashing my head at this problem for a couple hours now, and I need some help.
- How the heck am I supposed to mock a simple MouseDownEvent at a position in IMGUI?
- What’s causing my mouse down events set to
Event.current
to become ignored? - What magical being is causing the mouse down events passed to
MyField
to become ignored when they’re of type MouseDown after creation, and I don’t touch them in my editor script?
Sincerely, a Unity Dev with hopes of 100% Code Coverage.