Jon Gallant

Solution to SignalR error 'Unexpected token in JSON' when parsing event data

2 min read

I’ve been writing some UI automation tests with Playwright and was trying to parse a SignalR event. Like so:

const imageEvent = JSON.parse(event.payload.toString()) as ImageEvent;
```text
And I got this error:
```bash
1) tests/memealyzer.spec.ts:15:1 › Add Meme Test =================================================
webSocket.waitForEvent: Unexpected token  in JSON at position 658
49 | expect(afterCardCount).toEqual(beforeCardCount + 1);
50 |
> 51 | await webSocket.waitForEvent("framereceived", (event) => {
| ^
52 | if (event.payload.indexOf("ReceiveImage") > 0) {
53 | const imageEvent = JSON.parse(event.payload.toString()) as ImageEvent;
```python
As you can see from this screenshot:
![Screenshot](/2021/09/signalr-unexpected-token-in-json/115.png)
It looks like a christmas tree is in my JSON. I assumed it was an invalid char added by my code or playwright’s code, etc.
Here’s what it looks like in the debugger:
![Debugger](/2021/09/signalr-unexpected-token-in-json/114.png)
So, I removed it like so:
```typescript
const payload = event.payload.toString().replace("", ""); // Remove hidden char
```markdown
![Replace](/2021/09/signalr-unexpected-token-in-json/116.png)
Little did I know that character is a record separator! After I tweeted my code, David Fowler pointed me to this:
> You want to split based on that character instead of removing it. A single websocket payload can contain multiple messages [https://t.co/3sHUdjCpoB](https://t.co/3sHUdjCpoB)
> — David Fowler 🇧🇧💉💉 (@davidfowl) [September 1, 2021](https://twitter.com/davidfowl/status/1433139356609351683?ref_src=twsrc%5Etfw)
Here’s the code that SignalR uses to parse and iterate through the results:
[https://github.com/dotnet/aspnetcore/blob/e18394c8a933a5e03c0f5e4d614b622c2cb0a4b7/src/SignalR/clients/ts/signalr/src/TextMessageFormat.ts#L6-L22](https://github.com/dotnet/aspnetcore/blob/e18394c8a933a5e03c0f5e4d614b622c2cb0a4b7/src/SignalR/clients/ts/signalr/src/TextMessageFormat.ts#L6-L22)
So, instead of removing the char, I now split on it and loop through the results.
```typescript
await webSocket.waitForEvent("framereceived", (event) => {
if (event.payload.indexOf("ReceiveImage") > 0) {
const imageEvents = TextMessageFormat.parse(event.payload.toString());
for (let imageEventRaw of imageEvents) {
const imageEvent = JSON.parse(imageEventRaw) as ImageEvent;
actualId = imageEvent.arguments[0].Id;
return true;
}
}
});

Jon

Share:
Share on X