Skip to content

Commit

Permalink
tests so far that i didn't pushed earlier
Browse files Browse the repository at this point in the history
  • Loading branch information
shreyas-jadhav committed Oct 2, 2024
1 parent 390453e commit 65e5c13
Show file tree
Hide file tree
Showing 19 changed files with 666 additions and 36 deletions.
Binary file added .DS_Store
Binary file not shown.
Binary file added example/.DS_Store
Binary file not shown.
19 changes: 8 additions & 11 deletions src/TrackStates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,17 @@ export class LoadingState implements ICommonStateProperties {
*/
export class TimedTrackState implements ICommonStateProperties {
track: PlaylistAudiotrack;
windowScope: Window;

trackOptions: TrackOptions;
timerId: null | number;
timerId: null | NodeJS.Timeout;

// for logging purpse;
intervalId: null | number;
intervalId: null | NodeJS.Timeout;
timeRemainingMs?: number;
timerApproximateEndingAtMs?: number;
constructor(track: PlaylistAudiotrack, trackOptions: TrackOptions) {
this.track = track;
this.windowScope = track.windowScope;

this.trackOptions = trackOptions;
this.timerId = null;
this.intervalId = null;
Expand Down Expand Up @@ -146,10 +146,10 @@ export class TimedTrackState implements ICommonStateProperties {

clearTimer() {
const now = new Date().getTime();
const { timerId, timerApproximateEndingAtMs = now, windowScope } = this;
const { timerId, timerApproximateEndingAtMs = now } = this;

if (timerId) {
windowScope.clearTimeout(timerId);
clearTimeout(timerId);
clearInterval(this.intervalId!);
this.timerId = null;
delete this.timerApproximateEndingAtMs;
Expand All @@ -168,11 +168,8 @@ export class TimedTrackState implements ICommonStateProperties {
}

setNextStateTimer(timeMs: number) {
this.timerId = this.windowScope.setTimeout(
() => this.setNextState(),
timeMs
);
this.intervalId = this.windowScope.setInterval(
this.timerId = setTimeout(() => this.setNextState(), timeMs);
this.intervalId = setInterval(
() =>
this.log(
`${(
Expand Down
10 changes: 3 additions & 7 deletions src/assetFilters.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import distance from "@turf/distance";
import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
import distance from "@turf/distance";
import { Coord } from "@turf/helpers";
import { isEmpty } from "./utils";
import { GeoListenMode } from "./mixer";
import { GeoListenModeType, IMixParams } from "./types";
import { IMixParams } from "./types";
import { IDecoratedAsset } from "./types/asset";
import {
InvalidArgumentError,
RoundwareFrameworkError,
} from "./errors/app.errors";
import { isEmpty } from "./utils";

export interface IAssetPriorities {
readonly DISCARD: false;
Expand Down
1 change: 0 additions & 1 deletion src/events.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ApiClient } from "./api-client";
import { IAssetData } from "./types/asset";
import { EventPayload, EventType } from "./types/events";
type ListenEventsTypes = "play";
const LISTEN_EVENTS = "/listenevents/";
const EVENTS_PATH = `/events/`;
/**
Expand Down
4 changes: 2 additions & 2 deletions src/players/SpeakerStreamer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import {
IGainNode,
IMediaElementAudioSourceNode,
} from "standardized-audio-context";
import { silenceAudioBase64 } from "../playlistAudioTrack";

import { SpeakerConfig } from "../types/roundware";
import { ISpeakerPlayer, SpeakerConstructor } from "../types/speaker";
import { cleanAudioURL, speakerLog } from "../utils";
import { cleanAudioURL, silenceAudioBase64, speakerLog } from "../utils";

/**
*
Expand Down
4 changes: 1 addition & 3 deletions src/playlistAudioTrack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getUrlParam,
makeAudioSafeToPlay,
playlistTrackLog,
silenceAudioBase64,
timestamp,
} from "./utils";
/*
Expand Down Expand Up @@ -109,9 +110,6 @@ export const LOGGABLE_HOWL_EVENTS = [
"unlock",
];

export const silenceAudioBase64 =
"data:audio/mpeg;base64,SUQzBAAAAAABEVRYWFgAAAAtAAADY29tbWVudABCaWdTb3VuZEJhbmsuY29tIC8gTGFTb25vdGhlcXVlLm9yZwBURU5DAAAAHQAAA1N3aXRjaCBQbHVzIMKpIE5DSCBTb2Z0d2FyZQBUSVQyAAAABgAAAzIyMzUAVFNTRQAAAA8AAANMYXZmNTcuODMuMTAwAAAAAAAAAAAAAAD/80DEAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQsRbAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQMSkAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV";

const NEARLY_ZERO = 0.0001;
export class PlaylistAudiotrack {
/**
Expand Down
2 changes: 1 addition & 1 deletion src/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class User {
clientType = "web",
}: {
apiClient: ApiClient;
deviceId: string;
deviceId?: string;
clientType?: string;
}) {
// TODO need to try to persist deviceId as a random value that can partially serve as "a unique identifier generated by the client" that can
Expand Down
15 changes: 9 additions & 6 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
const { point } = require("@turf/helpers");
import { Point, Feature } from "@turf/helpers";
import { AudioContext, IAudioContext } from "standardized-audio-context";
import { silenceAudioBase64 } from "./playlistAudioTrack";

const MATCHES_URI_SCHEME = new RegExp(/^https?:\/\//i);
const MATCHES_WAV_FILE = new RegExp(/\.wav$/i);
export const silenceAudioBase64 =
"data:audio/mpeg;base64,SUQzBAAAAAABEVRYWFgAAAAtAAADY29tbWVudABCaWdTb3VuZEJhbmsuY29tIC8gTGFTb25vdGhlcXVlLm9yZwBURU5DAAAAHQAAA1N3aXRjaCBQbHVzIMKpIE5DSCBTb2Z0d2FyZQBUSVQyAAAABgAAAzIyMzUAVFNTRQAAAA8AAANMYXZmNTcuODMuMTAwAAAAAAAAAAAAAAD/80DEAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQsRbAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQMSkAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV";

export const isIos = () => {
return (
[
Expand Down Expand Up @@ -43,8 +46,8 @@ export const cleanAudioURL = (
* Makes sure coordinates are in range of +180 to -180.
* @param {number[]} coordinates
*/
const normalizeCoords = (coordinates: number[]) => {
for (let i = 0; i <= coordinates.length; i++) {
export const normalizeCoords = (coordinates: number[]) => {
for (let i = 0; i < coordinates.length; i++) {
if (coordinates[i] > 180) coordinates[i] = (coordinates[i] % 180) - 180;
else if (coordinates[i] < -180)
coordinates[i] = (coordinates[i] % 180) + 180;
Expand Down Expand Up @@ -106,9 +109,9 @@ export const UNLOCK_AUDIO_EVENTS = [

/** Helps stabilize WebAudio startup
@thanks https://www.mattmontag.com/web/unlock-web-audio-in-safari-for-ios-and-macos */
function unlockAudioContext(
body: Window[`document`][`body`],
audioCtx: AudioContext
export function unlockAudioContext(
body: Pick<Window[`document`][`body`], "addEventListener">,
audioCtx: Pick<AudioContext, "state" | "resume">
) {
if (audioCtx.state !== "suspended") return;

Expand Down
7 changes: 2 additions & 5 deletions tests/__tests__/TrackStates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ jest.mock("standardized-audio-context", () =>
require("standardized-audio-context-mock")
);
describe("LoadingState", () => {
test("should initialize", () => {
const state = new LoadingState(mockPlaylistAudiotrack, mockTrackOptions);
expect(state).toBeTruthy();
expect(state.asset).toBeNull();
});
const state = new LoadingState(mockPlaylistAudiotrack, mockTrackOptions);
expect(state).toBeTruthy();
});
69 changes: 69 additions & 0 deletions tests/__tests__/audioPanner.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { IAudioContext, IStereoPannerNode } from "standardized-audio-context";
import { AudioPanner } from "../../src/audioPanner";
import { random } from "../../src/utils";

jest.mock("../../src/utils");

const mockRandom = random as jest.MockedFunction<typeof random>;

describe("AudioPanner", () => {
afterEach(() => {
jest.clearAllMocks();
});

test("should instantiate AudioPanner", () => {
const audioContext = {} as IAudioContext;
const panNode = {} as IStereoPannerNode<IAudioContext>;

const audioPanner = new AudioPanner(0, 1, 2, 3, panNode, audioContext);

expect(audioPanner).toBeInstanceOf(AudioPanner);
});

test("should update parameters", () => {
const audioContext = {} as IAudioContext;
const panNode = {} as IStereoPannerNode<IAudioContext>;
const audioPanner = new AudioPanner(0, 1, 2, 3, panNode, audioContext);

audioPanner.updateParams();

expect(mockRandom).toHaveBeenCalledTimes(3); // Called for initial, final, and duration
});

test("should start panning", () => {
const audioContext = {
currentTime: 0,
} as IAudioContext;
const panNode = {
pan: {
value: 0,
linearRampToValueAtTime: jest.fn(),
},
} as unknown as IStereoPannerNode<IAudioContext>;

const audioPanner = new AudioPanner(0, 1, 2, 3, panNode, audioContext);

audioPanner.start();

expect(panNode.pan.linearRampToValueAtTime).toHaveBeenCalledWith(
expect.any(Number),
expect.any(Number)
);

// Ensure the timer function is called
jest.runOnlyPendingTimers();
expect(mockRandom).toHaveBeenCalledTimes(3); // Called for initial, final, and duration
});

test("should clear timeout", () => {
const audioContext = {} as IAudioContext;
const panNode = {} as IStereoPannerNode<IAudioContext>;

const audioPanner = new AudioPanner(0, 1, 2, 3, panNode, audioContext);

audioPanner.start();
audioPanner.clear();

expect(clearTimeout).toHaveBeenCalled();
});
});
118 changes: 118 additions & 0 deletions tests/__tests__/events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Import necessary dependencies and the RoundwareEvents class

import { ApiClient } from "../../src/api-client";
import { RoundwareEvents } from "../../src/events";
import { EventType, EventPayload } from "../../src/types/events";

// Mock the ApiClient class
jest.mock("../../src/api-client");

describe("RoundwareEvents", () => {
let roundwareEvents: RoundwareEvents;
let mockApiClient: jest.Mocked<ApiClient>;

beforeEach(() => {
mockApiClient = new ApiClient("") as jest.Mocked<ApiClient>;
roundwareEvents = new RoundwareEvents(123, mockApiClient);
});

afterEach(() => {
jest.clearAllMocks();
});

describe("logAssetStart", () => {
it("should log asset start and update _startedAssets", async () => {
const assetId = 1;
const startTime = new Date();

// Mock the post method of ApiClient
mockApiClient.post.mockResolvedValue({ id: 456 });

await roundwareEvents.logAssetStart(assetId, startTime);

expect(mockApiClient.post).toHaveBeenCalledWith("/listenevents/", {
starttime: startTime,
session: 123,
asset: assetId,
});

expect(roundwareEvents["_startedAssets"]).toHaveProperty(
assetId.toString(),
expect.objectContaining({ startTime, id: 456 })
);
});

it("should log asset start with default startTime if not provided", async () => {
const assetId = 1;

// Mock the post method of ApiClient
mockApiClient.post.mockResolvedValue({ id: 456 });

await roundwareEvents.logAssetStart(assetId);

expect(mockApiClient.post).toHaveBeenCalledWith("/listenevents/", {
starttime: expect.any(Date),
session: 123,
asset: assetId,
});

expect(roundwareEvents["_startedAssets"]).toHaveProperty(
assetId.toString(),
expect.objectContaining({ startTime: expect.any(Date), id: 456 })
);
});
});

describe("logAssetEnd", () => {
it("should log asset end if assetId exists in _startedAssets", async () => {
const assetId = 1;
const startTime = new Date();
roundwareEvents["_startedAssets"][assetId] = { startTime, id: 789 };

// Mock the patch method of ApiClient
mockApiClient.patch.mockResolvedValue({});

await roundwareEvents.logAssetEnd(assetId);

expect(mockApiClient.patch).toHaveBeenCalledWith(
"/listenevents/789",
expect.objectContaining({
duration_in_seconds: expect.any(Number),
})
);
});

it("should not log asset end if assetId does not exist in _startedAssets", async () => {
const assetId = 1;

// Mock the patch method of ApiClient
mockApiClient.patch.mockResolvedValue({});

await roundwareEvents.logAssetEnd(assetId);

expect(mockApiClient.patch).not.toHaveBeenCalled();
});
});

describe("logEvent", () => {
it("should log an event using the post method of ApiClient", async () => {
const eventType: EventType = "start_session";
const payload: EventPayload = {
latitude: 40.7128,
longitude: -74.006,
};

// Mock the post method of ApiClient
mockApiClient.post.mockResolvedValue(payload);

await roundwareEvents.logEvent(eventType, payload);

expect(mockApiClient.post).toHaveBeenCalledWith("/events/", {
session_id: 123,
event_type: eventType,
client_time: expect.any(String),
...payload,
});
});
});
});
Empty file.
Empty file.
Loading

0 comments on commit 65e5c13

Please sign in to comment.