This repository has been archived by the owner on Mar 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 260
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add unit test coverage reports to gitignore * add jest dependencies * add jest config * add Config unit tests * add AFKController unit tests * mock video codecs list * test for PixelStreaming SettingsChangedEvent * mock/unmock functions for RTCRtpReceiver * mock WebSocket * test for PixelStreaming.connect() * unit test for disconnect * unit tests for reconnect * added eventemitter events in tests * test that listStreamers is sent on WS connect * mock RTCPeerConnection and RTCIceCandidate * test webRtcConnected event * test RTCPeerConnect close * fixed variable name for consistency * check for navigator.getGamepads before calling it * mock addTransceiver, createAnswer, getTransceivers, setRemoteDescription * test for receiving a connection offer * add null checks for peerConnection since it might be null if connectiong closed * mock addIceCandidate * test for receiving ICE candidate message * mock setLocalDescription, getStats * test for statistics * test webRtcDisconnected event * mock RTCDataChannel and RTCDataChannelEvent * test for dataChannelOpen event * mock RTCTrackEvent * mock MediaStream and MediaStreamTrack * mock video element play() * test playStream and playStreamRejected events * mock video readyState * mock WebRTC data channel send() * test emitCommand * test emitUIInteraction * test emitConsoleCommand * Jest mock for HTMLMediaElement.play() * check boolean return value of all emit* commands * test dataChannelClose event * added TextEncoder and TextDecoder to Jest globals * mock datachannel onmessage * test UE -> browser data channel message * clarified in test description that we are using a Response message * extracted commonly used setup steps as util functions * triggerSdpOffer -> triggerSdpOfferMessage for consistency * run unit tests as a Github action * Revert "break one of the tests to test the GH action" This reverts commit 05f5742. * run tests only if files changed under Frontend/library * added unit test run instructions to README.md
- Loading branch information
Showing
17 changed files
with
9,985 additions
and
2,457 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
name: Run library unit tests | ||
|
||
on: | ||
push: | ||
branches: ['master'] | ||
paths: ['Frontend/library/**'] | ||
pull_request: | ||
branches: ['master'] | ||
paths: ['Frontend/library/**'] | ||
|
||
jobs: | ||
|
||
build: | ||
runs-on: ubuntu-latest | ||
defaults: | ||
run: | ||
working-directory: ./ | ||
|
||
permissions: | ||
contents: write | ||
steps: | ||
- name: "Checkout source code" | ||
uses: actions/checkout@v3 | ||
|
||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: '16.x' | ||
registry-url: 'https://registry.npmjs.org' | ||
|
||
- name: Install library deps | ||
working-directory: ./Frontend/library | ||
run: npm ci | ||
|
||
- name: Run frontend lib tests | ||
working-directory: ./Frontend/library | ||
run: npm run test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,5 @@ node_modules/ | |
node.zip | ||
SignallingWebServer/Public/ | ||
SignallingWebServer/certificates | ||
.vscode | ||
.vscode | ||
coverage/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module.exports = { | ||
preset: "ts-jest/presets/js-with-ts", | ||
testEnvironment: "jsdom", | ||
transform: { | ||
"^.+\\.tsx?$": [ | ||
"ts-jest", | ||
{ | ||
tsconfig: "tsconfig.jest.json", | ||
}, | ||
], | ||
}, | ||
modulePathIgnorePatterns: ["<rootDir>/build/"], | ||
testPathIgnorePatterns: ["<rootDir>/build/", "/node_modules/"], | ||
globals: { | ||
TextDecoder: TextDecoder, | ||
TextEncoder: TextEncoder, | ||
} | ||
}; |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import { Config, Flags, NumericParameters } from '../Config/Config'; | ||
import { PixelStreaming } from '../PixelStreaming/PixelStreaming'; | ||
import { AfkTimedOutEvent, AfkWarningActivateEvent, AfkWarningUpdateEvent, AfkWarningDeactivateEvent } from '../Util/EventEmitter'; | ||
import { mockRTCRtpReceiver, unmockRTCRtpReceiver } from '../__test__/mockRTCRtpReceiver'; | ||
import { | ||
AFKController | ||
} from './AFKController'; | ||
|
||
describe('AFKController', () => { | ||
let mockPixelStreaming: PixelStreaming; | ||
|
||
beforeEach(() => { | ||
mockRTCRtpReceiver(); | ||
jest.useFakeTimers(); | ||
mockPixelStreaming = { | ||
dispatchEvent: jest.fn() | ||
} as any as PixelStreaming; | ||
}); | ||
|
||
afterEach(() => { | ||
unmockRTCRtpReceiver(); | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
it('should not activate AFK timer if it has been disabled from settings', () => { | ||
const config = new Config({ initialSettings: { [Flags.AFKDetection]: false } }); | ||
const onDismissAfk = jest.fn(); | ||
const afkController = new AFKController(config, mockPixelStreaming, onDismissAfk); | ||
|
||
afkController.startAfkWarningTimer(); | ||
expect(afkController.active).toBe(false); | ||
|
||
jest.advanceTimersByTime(1000000 * 1000); | ||
expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should activate AFK timer and trigger it after specified delay if it has been enabled from settings', () => { | ||
const timeoutSeconds = 100; | ||
|
||
const config = new Config({ initialSettings: { [Flags.AFKDetection]: true, [NumericParameters.AFKTimeoutSecs]: timeoutSeconds} }); | ||
const onDismissAfk = jest.fn(); | ||
const afkController = new AFKController(config, mockPixelStreaming, onDismissAfk); | ||
|
||
afkController.startAfkWarningTimer(); | ||
expect(afkController.active).toBe(true); | ||
|
||
// Advance to 1 second before AFK event: | ||
jest.advanceTimersByTime((timeoutSeconds - 1) * 1000); | ||
expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled(); | ||
|
||
// advance 1 more second to trigger AFK warning | ||
jest.advanceTimersByTime(1000); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningActivateEvent({ | ||
countDown: 0, | ||
dismissAfk: expect.anything() | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 10, | ||
})); | ||
|
||
// advance 10 more seconds to trigger AFK countdown updates and eventually timeout | ||
jest.advanceTimersByTime(10 * 1000); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 9, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 8, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 7, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 6, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 5, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 4, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 3, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 2, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 1, | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkTimedOutEvent()); | ||
}); | ||
|
||
it('should postpone AFK activation each time resetAfkWarningTimer is called', () => { | ||
const timeoutSeconds = 100; | ||
|
||
const config = new Config({ initialSettings: { [Flags.AFKDetection]: true, [NumericParameters.AFKTimeoutSecs]: timeoutSeconds} }); | ||
const onDismissAfk = jest.fn(); | ||
const afkController = new AFKController(config, mockPixelStreaming, onDismissAfk); | ||
|
||
afkController.startAfkWarningTimer(); | ||
|
||
// Advance to 1 second before AFK event: | ||
jest.advanceTimersByTime((timeoutSeconds - 1) * 1000); | ||
expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled(); | ||
|
||
afkController.resetAfkWarningTimer(); | ||
|
||
// advance 1 more second and ensure that AFK warning is not triggered since reset was called | ||
jest.advanceTimersByTime(1000); | ||
expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled(); | ||
|
||
// reset AFK timer once more and ensure it is triggered exactly after timeoutSeconds | ||
afkController.resetAfkWarningTimer(); | ||
|
||
// Advance to 1 second before AFK event: | ||
jest.advanceTimersByTime((timeoutSeconds - 1) * 1000); | ||
expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled(); | ||
|
||
// advance 1 more second to trigger AFK warning | ||
jest.advanceTimersByTime(1000); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningActivateEvent({ | ||
countDown: 0, | ||
dismissAfk: expect.anything() | ||
})); | ||
}); | ||
|
||
it('should dismiss AFK warning countdown if onAfkClick is called', () => { | ||
const timeoutSeconds = 100; | ||
|
||
const config = new Config({ initialSettings: { [Flags.AFKDetection]: true, [NumericParameters.AFKTimeoutSecs]: timeoutSeconds} }); | ||
const onDismissAfk = jest.fn(); | ||
const afkController = new AFKController(config, mockPixelStreaming, onDismissAfk); | ||
|
||
afkController.startAfkWarningTimer(); | ||
|
||
// Advance to AFK event: | ||
jest.advanceTimersByTime(timeoutSeconds * 1000); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningActivateEvent({ | ||
countDown: 0, | ||
dismissAfk: expect.anything() | ||
})); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 10, | ||
})); | ||
|
||
// Advance one more second and call onAfkClick | ||
jest.advanceTimersByTime(1000); | ||
|
||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({ | ||
countDown: 9, | ||
})); | ||
|
||
afkController.onAfkClick(); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningDeactivateEvent()); | ||
|
||
// advance 10 more seconds and ensure there are no more countdown/timeout events emitted | ||
jest.advanceTimersByTime(10 * 1000); | ||
expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledTimes(4); | ||
}); | ||
|
||
|
||
}); |
Oops, something went wrong.