import { it, beforeEach, describe, expect } from 'vitest';
import { provideSdkInstance } from "../AblyReactHooks";
import { usePresence } from "./usePresence";
import { render, screen, act } from '@testing-library/react';
import { FakeAblySdk, FakeAblyChannels } from "../fakes/ably";
const testChannelName = "testChannel";
describe("usePresence", () => {
let channels: FakeAblyChannels;
let ablyClient: FakeAblySdk;
let otherClient: FakeAblySdk;
beforeEach(() => {
channels = new FakeAblyChannels([testChannelName]);
ablyClient = new FakeAblySdk().connectTo(channels);
otherClient = new FakeAblySdk().connectTo(channels);
provideSdkInstance(ablyClient as any);
});
it("presence data is not visible on first render as it runs in an effect", async () => {
render();
const values = screen.getByRole("presence").innerHTML;
expect(values).toBe("");
await act(async () => {
await wait(2);
// To let react run its updates so we don't see warnings in the test output
});
});
it("presence data available after effect runs", async () => {
render();
await act(async () => {
await wait(2);
});
const values = screen.getByRole("presence").innerHTML;
expect(values).toContain(`"bar"`);
});
it("presence data updates when update function is triggered", async () => {
render();
await act(async () => {
const button = screen.getByText(/Update/i);
button.click();
});
const values = screen.getByRole("presence").innerHTML;
expect(values).toContain(`"baz"`);
});
it("presence data respects updates made by other clients", async () => {
render();
await act(async () => {
otherClient.channels.get(testChannelName).presence.enter("boop");
});
const presenceElement = screen.getByRole("presence");
const values = presenceElement.innerHTML;
expect(presenceElement.children.length).toBe(2);
expect(values).toContain(`"bar"`);
expect(values).toContain(`"boop"`);
});
it("presence API works with type information provided", async () => {
render();
await act(async () => {
await wait(2);
});
const values = screen.getByRole("presence").innerHTML;
expect(values).toContain(`"data":{"foo":"bar"}`);
});
it("usePresence works with multiple clients", async () => {
render();
await act(async () => {
const button = screen.getByText(/Update/i);
button.click();
await wait(2);
});
const values = screen.getByRole("presence").innerHTML;
expect(values).toContain(`"data":"baz1"`);
expect(values).toContain(`"data":"baz2"`);
});
});
const UsePresenceComponent = () => {
const [val, update] = usePresence(testChannelName, "bar");
const presentUsers = val.map((presence, index) => {
return (
{presence.clientId} - {JSON.stringify(presence)})
});
return (
<>
>
);
}
const UsePresenceComponentMultipleClients = ({client1, client2}) => {
const [val1, update1] = usePresence({channelName: testChannelName, realtime: client1}, "foo");
const [val2, update2] = usePresence({channelName: testChannelName, realtime: client2}, "bar");
const presentUsers = val1.map((presence, index) => {
return ({presence.clientId} - {JSON.stringify(presence)})
});
return (
<>
>
);
}
interface MyPresenceType {
foo: string;
}
const TypedUsePresenceComponent = () => {
const [val] = usePresence("testChannelName", { foo: "bar" });
return (
{JSON.stringify(val)}
);
}
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));