Skip to content
6 changes: 6 additions & 0 deletions .changeset/warm-dots-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@tapsioss/client-socket-manager": minor
---

Add devtool to the client socket manager.

44 changes: 22 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,44 +80,44 @@
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.1",
"@changesets/cli": "^2.29.2",
"@eslint/js": "^9.21.0",
"@changesets/cli": "^2.29.4",
"@eslint/js": "^9.28.0",
"@lit/react": "^1.0.7",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/eslint__js": "^8.42.3",
"@types/express": "^5.0.0",
"@types/node": "^20.17.19",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"@types/express": "^5.0.3",
"@types/node": "^20.19.0",
"@types/react": "^19.1.6",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.5.1",
"@vitest/eslint-plugin": "1.1.32-beta.3",
"eslint": "^9.21.0",
"eslint": "^9.28.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.8.3",
"eslint-import-resolver-typescript": "^3.10.1",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.19",
"eslint-plugin-prettier": "^5.4.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"express": "^4.21.2",
"jsdom": "^26.0.0",
"jsdom": "^26.1.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.5.2",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"shx": "^0.3.4",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"tsx": "^4.19.3",
"typescript": "^5.7.3",
"typescript-eslint": "^8.25.0",
"tsx": "^4.19.4",
"typescript": "^5.8.3",
"typescript-eslint": "^8.33.1",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.0.7",
"vitest": "^3.2.2",
"wireit": "^0.14.12"
}
}
4 changes: 3 additions & 1 deletion packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ socketManager.subscribe('message', (msg) => {
### Constructor

```ts
constructor(uri: string, options?: Partial<ClientSocketManagerOptions>)
constructor(uri: string, options?: ClientSocketManagerOptions)
```

#### Parameters:
Expand All @@ -86,6 +86,8 @@ We have extended [socket-io's options](https://socket.io/docs/v4/client-options/
- `onAnySubscribedMessageReceived`: Fired when any message is received from a subscribed channel.
- `onVisiblePage`: Fired when the page's `visibilityState` changes to `visible`.
- `onHiddenPage`: Fired when the page's `visibilityState` changes to `hidden`.
- `devtool`: Enables the in-browser DevTool panel for socket debugging. This is useful for development and debugging purposes. In production environments, it's recommended to leave this disabled.


### Properties:

Expand Down
88 changes: 88 additions & 0 deletions packages/core/src/ClientSocketManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
expect,
it,
} from "vitest";
import * as devtool from "./devtool/devtool.ts";
import { ClientSocketManager } from "./index.ts";

describe("ClientSocketManager: unit tests", () => {
Expand Down Expand Up @@ -291,4 +292,91 @@ describe("ClientSocketManager: unit tests", () => {
expect(socketManager.connected).toBe(false);
expect(socketManager.disposed).toBe(true);
});

it("should show devtool when the `devtool` option is true", () => {
socketManager = new ClientSocketManager(socketServerUri, {});
expect(devtool.getDevtoolElement()).toBeNull();
socketManager.dispose();

socketManager = new ClientSocketManager(socketServerUri, {
devtool: true,
});
expect(devtool.getDevtoolElement()).not.toBeNull();
});

it("should update devtool ui when socket was updated", async () => {
const connectResolver = createPromiseResolvers();
const initResolver = createPromiseResolvers();
const initMessageResolver = createPromiseResolvers();
const diposeResolver = createPromiseResolvers();

socketManager = new ClientSocketManager(socketServerUri, {
devtool: true,
eventHandlers: {
onSocketConnection() {
connectResolver.resolve();
},
onInit() {
initResolver.resolve();
this.subscribe("test/init", () => {
initMessageResolver.resolve();
});
},
onDispose() {
diposeResolver.resolve();
},
},
});

// at first the devtool should be in the dom but because no we have lo logs or channels, these sections shouldn't exist.
expect(devtool.getDevtoolElement()).not.toBeNull();
expect(devtool.getDevtoolLogSectionElement()).toBeNull();
expect(devtool.getDevtoolChannelsElement()).toBeNull();
expect(devtool.getDevtoolInfoElement()).not.toBeNull();
expect(devtool.getDevtoolStatusElement()?.innerHTML).not.toEqual(
devtool.Status.CONNECTED,
);

await connectResolver.promise;

// now the log should be visible to the user
expect(devtool.getDevtoolLogSectionElement()).not.toBeNull();
expect(devtool.getDevtoolStatusElement()?.innerHTML).toEqual(
devtool.Status.CONNECTED,
);
await initResolver.promise;

// subscribing to a channel...
expect(devtool.getDevtoolLogSectionElement()!.innerHTML).not.toContain(
devtool.LogType.SUBSCRIBED,
);
expect(devtool.getDevtoolChannelsElement()).toBeNull();

socketManager.subscribe("test/init", () => {});

expect(devtool.getDevtoolChannelsElement()).not.toBeNull();
expect(devtool.getDevtoolLogSectionElement()!.innerHTML).toContain(
devtool.LogType.SUBSCRIBED,
);
expect(devtool.getDevtoolChannelsElement()!.innerHTML).contain("test/init");

// unsubscribing a channel...
expect(devtool.getDevtoolLogSectionElement()!.innerHTML).not.toContain(
devtool.LogType.UNSUBSCRIBED,
);

socketManager.unsubscribe("test/init", () => {});

expect(devtool.getDevtoolLogSectionElement()!.innerHTML).toContain(
devtool.LogType.UNSUBSCRIBED,
);
expect(devtool.getDevtoolChannelsElement()).toBeNull();

socketManager.dispose();

await diposeResolver.promise;

expect(socketManager.connected).toBe(false);
expect(socketManager.disposed).toBe(true);
});
});
Loading