RolandJansen/intermix.js

View on GitHub
src/plugins/__tests__/Synth.test.ts

Summary

Maintainability
B
5 hrs
Test Coverage
/// <reference path="../../../typings/web-audio-test-api.d.ts" />
import "web-audio-test-api";
import Synth from "../Synth";
import { IntermixNote, IntermixCtrl } from "../../interfaces/interfaces";
import { IPlugin } from "../../interfaces/IRegistryItems";

describe("DemoSynth", () => {
    let ac: AudioContext;
    let synth: IPlugin;

    beforeEach(() => {
        ac = new AudioContext();
        synth = new Synth("abcd", ac);
    });

    test("ensure that we're testing against the WebAudioTestAPI", () => {
        expect(ac.$name).toEqual("AudioContext");
    });

    test("has a metadata section (static)", () => {
        expect(Synth.METADATA.type).toEqual("instrument");
        expect(Synth.METADATA.name).toEqual("Intermix Synth");
    });

    test("has action definitions", () => {
        expect(synth.actionDefs[0].typeTag).toEqual(",sff");
    });

    test("has zero inputs", () => {
        expect(synth.inputs.length).toEqual(0);
    });

    test("has one output", () => {
        expect(synth.outputs.length).toEqual(1);
    });

    test("output type is GainNode", () => {
        expect(synth.outputs[0]).toBeInstanceOf(GainNode);
    });

    describe("onChange", () => {
        let testNote: IntermixNote;
        let testCtrl: IntermixCtrl;

        beforeEach(() => {
            testNote = ["note", 23, 1, 1, 1];
            testCtrl = ["testCtrl", 0.23, 0];
            // {
            //     value: 23,
            //     velocity: 1,
            //     steps: 1,
            //     duration: 1,
            //     startTime: 1,
            // };
            synth["ac"].$processTo("00:00.000");
        });

        test("should return false with an uncovered parameter", () => {
            const falsyValue = synth.onChange(["FANTASY_PARAMETER", 23]);
            expect(falsyValue).toBeFalsy();
        });

        test("should add and delete OscillatorNodes from the queue", () => {
            synth.onChange(["note", testNote]);
            synth.onChange(["note", testNote]);
            expect(synth["queue"].length).toEqual(2);
            synth.onChange(["stop", true]);
            expect(synth["queue"].length).toEqual(0);
        });

        test("should start and stop an OscillatorNode at given times", () => {
            synth.onChange(["note", testNote]);

            const node = synth["queue"][0];
            expect(node.$stateAtTime("00:00.000")).toBe("SCHEDULED");
            expect(node.$stateAtTime("00:00.999")).toBe("SCHEDULED");
            expect(node.$stateAtTime("00:01.000")).toBe("PLAYING");
            expect(node.$stateAtTime("00:01.999")).toBe("PLAYING");
            expect(node.$stateAtTime("00:02.000")).toBe("FINISHED");
        });

        test("should disconnect nodes on stop", () => {
            synth.onChange(["note", testNote]);
            const oscNode = synth["queue"][0];
            oscNode.disconnect = jest.fn(); // fake disconnect call
            synth.onChange(["stop", true]);
            expect(oscNode.disconnect).toHaveBeenCalledTimes(1);
        });

        test("should remove nodes from queue on stop", () => {
            synth.onChange(["note", testNote]);
            expect(synth["queue"].length).toEqual(1);
            synth.onChange(["stop", true]);
            expect(synth["queue"].length).toEqual(0);
        });

        test("should handle envelope attack", () => {
            // there's no check if value is within range (covered by actionDef)
            synth.onChange(["envAttack", testCtrl]);
            expect(synth["attack"]).toEqual(0.23);
        });

        test("should handle envelope decay", () => {
            // there's no check if value is within range (covered by actionDef)
            synth.onChange(["envDecay", testCtrl]);
            expect(synth["decay"]).toEqual(0.23);
        });
    });
});