Repository: microsoft/playwright-python

Issue:
[BUG] WebSocket error is not notified
**Context:**

- Playwright Version: 1.12
- Operating System: macOS
- Python Version: 3.9

**Code Snippet**

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as playwright:
    browser = playwright.chromium.launch(headless=False)
    try:
        page = browser.new_page()

        errors = []

        def on_web_socket(ws):
            ws.on("socketerror", lambda err: errors.append(err))

        page.on("websocket", on_web_socket)
        page.evaluate("new WebSocket('ws://localhost:8080/invalid-ws-url')")        

        print(errors)
    finally:
        browser.close()
```

This code is originated from a spec in the TypeScript version of Playwright.
https://github.com/microsoft/playwright/blob/060f7ffa92865db95fcfd8f3fa77ac38d5e79cfa/tests/web-socket.spec.ts#L116-L128

When I execute the script with `DEBUG=pw:protocol`,  WebSocket error is really notified, however the callback of `ws.on("socketerror", ...` is not called.

```
  pw:protocol ◀ RECV {"method":"Network.webSocketFrameError","params":{"requestId":"21150.1","timestamp":19371.491694,"errorMessage":"Error during WebSocket handshake: Unexpected response code: 404"},"sessionId":"8B511AAB7B27D8597CE51D735E329871"} +1ms
```

---

When I implemented WebSocket in my project (https://github.com/YusukeIwaki/playwright-ruby-client/pull/116) , I just noticed WebSocket should handle `socketError` event instead of `error` event here. 
https://github.com/microsoft/playwright-python/blob/7b920eaad9ca1b53e0bc19876929c7a4d8d9a6e1/playwright/_impl/_network.py#L298

It seems renamed several months ago.
https://github.com/microsoft/playwright/pull/4495


Discussion:

Resolving patch:
diff --git a/playwright/_impl/_network.py b/playwright/_impl/_network.py
--- a/playwright/_impl/_network.py
+++ b/playwright/_impl/_network.py
@@ -295,7 +295,8 @@ def __init__(
             lambda params: self._on_frame_received(params["opcode"], params["data"]),
         )
         self._channel.on(
-            "error", lambda params: self.emit(WebSocket.Events.Error, params["error"])
+            "socketError",
+            lambda params: self.emit(WebSocket.Events.Error, params["error"]),
         )
         self._channel.on("close", lambda params: self._on_close())
 


Test patch:
diff --git a/tests/async/test_websocket.py b/tests/async/test_websocket.py
--- a/tests/async/test_websocket.py
+++ b/tests/async/test_websocket.py
@@ -12,6 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import asyncio
+
 import pytest
 from flaky import flaky
 
@@ -125,3 +127,22 @@ async def test_should_reject_wait_for_event_on_close_and_error(page, ws_server):
         async with ws.expect_event("framesent"):
             await page.evaluate("window.ws.close()")
     assert exc_info.value.message == "Socket closed"
+
+
+async def test_should_emit_error_event(page, server, browser_name):
+    future = asyncio.Future()
+    page.on(
+        "websocket",
+        lambda websocket: websocket.on(
+            "socketerror", lambda err: future.set_result(err)
+        ),
+    )
+    await page.evaluate(
+        """port => new WebSocket(`ws://localhost:${port}/bogus-ws`)""",
+        server.PORT,
+    )
+    err = await future
+    if browser_name == "firefox":
+        assert err == "CLOSE_ABNORMAL"
+    else:
+        assert ": 404" in err