Skip to content

Commit

Permalink
add tests for replacement logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Regaddi committed Dec 20, 2022
1 parent 4bc0e6f commit 010bbb9
Show file tree
Hide file tree
Showing 2 changed files with 250 additions and 38 deletions.
10 changes: 9 additions & 1 deletion test/.test-utils/event-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,12 @@ export const emitParticipantLeft = (callObject: DailyCall, participant: Partial<
action: 'participant-left',
participant,
});
};
};

export const emitParticipantUpdated = (callObject: DailyCall, participant: Partial<DailyParticipant>) => {
// @ts-ignore
callObject.emit('participant-updated', {
action: 'participant-updated',
participant,
});
}
278 changes: 241 additions & 37 deletions test/components/DailyAudio.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="@types/jest" />

import DailyIframe, { DailyCall } from '@daily-co/daily-js';
import DailyIframe, { DailyCall, DailyParticipant } from '@daily-co/daily-js';
import { act, render, waitFor } from '@testing-library/react';
import faker from 'faker';
import React from 'react';
Expand All @@ -10,6 +10,7 @@ import { DailyProvider } from '../../src/DailyProvider';
import {
emitActiveSpeakerChange,
emitParticipantLeft,
emitParticipantUpdated,
emitStartedCamera,
emitTrackStarted,
} from '../.test-utils/event-emitter';
Expand Down Expand Up @@ -40,6 +41,14 @@ const emitAudioTrackStarted = (callObject: DailyCall, peerId: string) =>
}
);

const queryAudioById = (
peerId: string,
container: HTMLElement = document.body
) =>
container.querySelector(
`audio[data-session-id="${peerId}"][data-audio-type="audio"]`
);

describe('DailyAudio', () => {
it.each([1, 3, 5])('renders maxSpeakers audio tags (%i)', (maxSpeakers) => {
const Wrapper = createWrapper();
Expand Down Expand Up @@ -79,11 +88,7 @@ describe('DailyAudio', () => {
act(() => emitStartedCamera(callObject));
act(() => emitActiveSpeakerChange(callObject, peerId));
await waitFor(() => {
expect(
container.querySelector(
`audio[data-session-id="${peerId}"][data-audio-type="audio"]`
)
).not.toBeNull();
expect(queryAudioById(peerId, container)).not.toBeNull();
});
});
it('ignores unsubscribed speaker', async () => {
Expand Down Expand Up @@ -113,11 +118,7 @@ describe('DailyAudio', () => {
act(() => emitStartedCamera(callObject));
act(() => emitActiveSpeakerChange(callObject, peerId));
await waitFor(() => {
expect(
container.querySelector(
`audio[data-session-id="${peerId}"][data-audio-type="audio"]`
)
).toBeNull();
expect(queryAudioById(peerId, container)).toBeNull();
});
});
it('ignores local participant', async () => {
Expand All @@ -137,11 +138,7 @@ describe('DailyAudio', () => {
act(() => emitStartedCamera(callObject));
act(() => emitActiveSpeakerChange(callObject, localSessionId));
await waitFor(() => {
expect(
container.querySelector(
`audio[data-session-id="${localSessionId}"][data-audio-type="audio"]`
)
).toBeNull();
expect(queryAudioById(localSessionId, container)).toBeNull();
});
});
});
Expand Down Expand Up @@ -173,11 +170,7 @@ describe('DailyAudio', () => {
act(() => emitStartedCamera(callObject));
act(() => emitAudioTrackStarted(callObject, peerId));
await waitFor(() => {
expect(
container.querySelector(
`audio[data-session-id="${peerId}"][data-audio-type="audio"]`
)
).not.toBeNull();
expect(queryAudioById(peerId, container)).not.toBeNull();
});
});
it('ignores local participant', async () => {
Expand All @@ -197,11 +190,7 @@ describe('DailyAudio', () => {
act(() => emitStartedCamera(callObject));
act(() => emitAudioTrackStarted(callObject, localSessionId));
await waitFor(() => {
expect(
container.querySelector(
`audio[data-session-id="${localSessionId}"][data-audio-type="audio"]`
)
).toBeNull();
expect(queryAudioById(localSessionId, container)).toBeNull();
});
});
});
Expand Down Expand Up @@ -233,23 +222,238 @@ describe('DailyAudio', () => {
act(() => emitStartedCamera(callObject));
act(() => emitAudioTrackStarted(callObject, peerId));
await waitFor(() => {
expect(
container.querySelector(
`audio[data-session-id="${peerId}"][data-audio-type="audio"]`
)
).not.toBeNull();
expect(queryAudioById(peerId, container)).not.toBeNull();
});
act(() =>
emitParticipantLeft(callObject, { local: false, session_id: peerId })
);
await waitFor(() => {
expect(
container.querySelector(
`audio[data-session-id="${peerId}"][data-audio-type="audio"]`
)
).toBeNull();
expect(queryAudioById(peerId, container)).toBeNull();
});
});
});
describe('replacement logic', () => {
it('replaces unsubscribed slot', async () => {
/**
* Scenario:
* - Remote participant 1 becomes active speaker (subscribed)
* - Remote participant 2 becomes active speaker (subscribed)
* - Unsubscribe from remote participant 2
* - Remote participant 3 becomes active speaker (subscribed) and replaces slot of participant 2
*/
const callObject = DailyIframe.createCallObject();
const remoteParticipants = [
faker.datatype.uuid(),
faker.datatype.uuid(),
faker.datatype.uuid(),
];
(callObject.participants as jest.Mock).mockImplementation(() => {
const participants: Record<string, Partial<DailyParticipant>> = {
local: {
local: true,
session_id: localSessionId,
},
};
remoteParticipants.forEach((id) => {
participants[id] = {
local: false,
session_id: id,
// @ts-ignore
tracks: {
audio: {
state: 'playable',
subscribed: true,
},
},
};
});
return participants;
});
const Wrapper = createWrapper(callObject);
const { container } = render(
<Wrapper>
<DailyAudio maxSpeakers={2} />
</Wrapper>
);
act(() => emitStartedCamera(callObject));
act(() => emitActiveSpeakerChange(callObject, remoteParticipants[0]));
await waitFor(() =>
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull()
);
act(() => emitActiveSpeakerChange(callObject, remoteParticipants[1]));
await waitFor(() => {
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[1], container)).not.toBeNull();
});
act(() =>
emitParticipantUpdated(callObject, {
local: false,
session_id: remoteParticipants[1],
// @ts-ignore
tracks: {
audio: {
state: 'sendable',
subscribed: false,
},
},
})
);
act(() => emitActiveSpeakerChange(callObject, remoteParticipants[2]));
await waitFor(() => {
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[1], container)).toBeNull();
expect(queryAudioById(remoteParticipants[2], container)).not.toBeNull();
});
});
it('replaces muted slot', async () => {
/**
* Scenario:
* - Remote participant 1 becomes active speaker (subscribed)
* - Remote participant 2 becomes active speaker (subscribed)
* - Remote participant 2 mutes (still subscribed)
* - Remote participant 3 becomes active speaker (subscribed) and replaces slot of participant 2
*/
const callObject = DailyIframe.createCallObject();
const remoteParticipants = [
faker.datatype.uuid(),
faker.datatype.uuid(),
faker.datatype.uuid(),
];
(callObject.participants as jest.Mock).mockImplementation(() => {
const participants: Record<string, Partial<DailyParticipant>> = {
local: {
local: true,
session_id: localSessionId,
},
};
remoteParticipants.forEach((id) => {
participants[id] = {
local: false,
session_id: id,
// @ts-ignore
tracks: {
audio: {
state: 'playable',
subscribed: true,
},
},
};
});
return participants;
});
const Wrapper = createWrapper(callObject);
const { container } = render(
<Wrapper>
<DailyAudio maxSpeakers={2} />
</Wrapper>
);
act(() => emitStartedCamera(callObject));
act(() => emitActiveSpeakerChange(callObject, remoteParticipants[0]));
await waitFor(() =>
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull()
);
act(() => emitActiveSpeakerChange(callObject, remoteParticipants[1]));
await waitFor(() => {
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[1], container)).not.toBeNull();
});
act(() =>
emitParticipantUpdated(callObject, {
local: false,
session_id: remoteParticipants[1],
// @ts-ignore
tracks: {
audio: {
state: 'off',
subscribed: true,
},
},
})
);
act(() => emitActiveSpeakerChange(callObject, remoteParticipants[2]));
await waitFor(() => {
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[1], container)).toBeNull();
expect(queryAudioById(remoteParticipants[2], container)).not.toBeNull();
});
});
it('replaces least recent speaker slot', async () => {
/**
* Scenario: 4 participants to trigger sorting by last_active dates.
* - Remote participant 1 becomes active speaker (subscribed)
* - Remote participant 2 becomes active speaker (subscribed)
* - Remote participant 3 becomes active speaker (subscribed)
* - Remote participant 4 becomes active speaker (subscribed) and replaces slot of participant 1
*/
const callObject = DailyIframe.createCallObject();
const remoteParticipants = [
faker.datatype.uuid(),
faker.datatype.uuid(),
faker.datatype.uuid(),
faker.datatype.uuid(),
];
(callObject.participants as jest.Mock).mockImplementation(() => {
const participants: Record<string, Partial<DailyParticipant>> = {
local: {
local: true,
session_id: localSessionId,
},
};
remoteParticipants.forEach((id) => {
participants[id] = {
local: false,
session_id: id,
// @ts-ignore
tracks: {
audio: {
state: 'playable',
subscribed: true,
},
},
};
});
return participants;
});
const Wrapper = createWrapper(callObject);
const { container } = render(
<Wrapper>
<DailyAudio maxSpeakers={3} />
</Wrapper>
);
jest.useFakeTimers();
act(() => emitStartedCamera(callObject));
act(() => emitActiveSpeakerChange(callObject, remoteParticipants[0]));
await waitFor(() =>
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull()
);
act(() => {
jest.advanceTimersByTime(5000);
emitActiveSpeakerChange(callObject, remoteParticipants[1]);
});
await waitFor(() => {
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[1], container)).not.toBeNull();
});
act(() => {
jest.advanceTimersByTime(5000);
emitActiveSpeakerChange(callObject, remoteParticipants[2]);
});
await waitFor(() => {
expect(queryAudioById(remoteParticipants[0], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[1], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[2], container)).not.toBeNull();
});
act(() => {
jest.advanceTimersByTime(5000);
emitActiveSpeakerChange(callObject, remoteParticipants[3]);
});
await waitFor(() => {
expect(queryAudioById(remoteParticipants[0], container)).toBeNull();
expect(queryAudioById(remoteParticipants[1], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[2], container)).not.toBeNull();
expect(queryAudioById(remoteParticipants[3], container)).not.toBeNull();
});
jest.useRealTimers();
});
});
describe('replacement logic', () => {});
});

0 comments on commit 010bbb9

Please sign in to comment.