Full answer and explanation probably involves a lot of fun time tracking encoding performed internally. And I won't spend it that way again.
You can use PrintDeifinitions or
Trace[ WebExecute["TypeElement" -> {textArea, text_}], _URLFetch]
To see that the call is:
URLFetch["http://localhost:{port}/session/{sessionId}/element/{elementId}/value",
"Method" -> "Post", "BodyData" -> "{
\"value\":[
characters...
]
}"]
Something goes wrong and characters are not encoded correctly nor the response is parsed correctly.
Here is a quick workaround:
typeElementPath // ClearAll
typeElementPath[elem : _WebElementObject, text_] := Module[{url},
url = URLBuild[
<| URLParse @ elem["URL"],
"Path" -> {"session", elem["SessionID"], "element", elem["ElementId"]}|>
];
URLExecute[
HTTPRequest[
url <> "/clear",
<| "Method" -> "Post"|>
]
];
URLExecute[
HTTPRequest[
url <> "/value",
<|
"Method" -> "Post",
"Body" -> ExportString[<|"value" -> Characters@text|>, "RawJSON", "Compact" -> True]
|>,
CharacterEncoding -> None
],
"RawJSON"
]
]
typeElementPath[textArea, "αó"]
<|"sessionId" -> "a0c4c6e971d1506dd115351a76278480", "status" -> 0, "value" -> Null|>

You can skip the first URLExecute to append instead of overwrite the element.
This should work for IE/Chrome/Edge. For Firefox you probably just need to use:
ExportString[<|"text" -> text|>, "RawJSON", "Compact" -> True]
But I have not tested it.