Home Reference Source Test Repository

test/ElectroPhone.js

import { expect } from 'chai';
import ElectroPhone from '../lib/ElectroPhone'

/** @test {ElectroPhone} */
describe('ElectroPhone', () => {
    let synth;

    it('should have a ElectroPhone function', () => {
        expect(ElectroPhone).to.be.a('function');
    });

    /** @test {ElectroPhone#constructor} */
    it('should create a ElectroPhone instance', () => {
        synth = new ElectroPhone();
        expect(synth).to.be.a('object');
    });

    /** @test {ElectroPhone#isPlaying} */
    it('should have a isPlaying property', () => {
        expect(synth.isPlaying).to.be.defined;
        expect(synth.isPlaying).to.be.equal(false);
    });

    /** @test {ElectroPhone#getModules} */
    it('should have a method to get modules', () => {
        synth = new ElectroPhone();
        expect(synth.getModules).to.be.a('function');
        expect(synth.getModules()).to.be.a('object');
    });

    /** @test {ElectroPhone#defaultModules} */
    it('should have master and adsr modules created', () => {
        const modules = synth.getModules();
        expect(modules[ElectroPhone.CONST.MASTER]).to.be.a('object');
        expect(modules[ElectroPhone.CONST.ADSR]).to.be.a('object');
    });

    /** @test {ElectroPhone#create} */
    it('should have a create method to add new module', () => {
        let modules;
        const nodeProps = { level: 100, link: null, wave: 'sine' };

        expect(synth.create).to.be.a('function');
        synth.create('node1', ElectroPhone.TYPES.OSCILLATOR, nodeProps);

        modules = synth.getModules();
        expect(modules['node1']).to.be.a('object');
        expect(modules['node1'].type).to.equal(ElectroPhone.TYPES.OSCILLATOR);
        expect(modules['node1'].props).to.deep.equal(nodeProps);
    });

    /** @test {ElectroPhone#create} */
    it('should fail if try to create an existing module', () => {
        expect(synth.create.bind(synth, 'node1', ElectroPhone.TYPES.OSCILLATOR, {})).to.throw(Error);
    });

    /** @test {ElectroPhone#update} */
    it('should have a update method to update a module', () => {
        let modules;

        expect(synth.update).to.be.a('function');
        synth.update('node1', { level: 50 });

        modules = synth.getModules();
        expect(modules['node1']).to.be.a('object');
        expect(modules['node1'].props).to.be.a('object');
        expect(modules['node1'].props.level).to.equal(50);
    });

    /** @test {ElectroPhone#update} */
    it('should fail if try to update a module that doesn\'t exist', () => {
        expect(synth.update.bind(synth, 'nodeX', {})).to.throw(Error);
    });

    /** @test {ElectroPhone#master} */
    it('should have a master method to update the master module', () => {
        let modules;

        expect(synth.master).to.be.a('function');
        synth.master({ level: 50 });

        modules = synth.getModules();
        expect(modules[ElectroPhone.CONST.MASTER].props).to.be.a('object');
        expect(modules[ElectroPhone.CONST.MASTER].props.level).to.equal(50);
    });

    /** @test {ElectroPhone#adsr} */
    it('should have a adsr method to update the adsr module', () => {
        let modules;

        expect(synth.adsr).to.be.a('function');
        synth.adsr({ attack: 10 });

        modules = synth.getModules();
        expect(modules[ElectroPhone.CONST.ADSR].props).to.be.a('object');
        expect(modules[ElectroPhone.CONST.ADSR].props.attack).to.equal(10);
    });

    /** @test {ElectroPhone#destroy} */
    it('should have a destroy method to destroy a module', () => {
        let modules;

        expect(synth.destroy).to.be.a('function');
        synth.destroy('node1');

        modules = synth.getModules();
        expect(modules['node1']).to.be.undefined;
    });

    /** @test {ElectroPhone#destroy} */
    it('should fail if try to destroy a module that doesn\'t exist', () => {
        expect(synth.destroy.bind(synth, 'nodeX')).to.throw(Error);
    });

    /** @test {ElectroPhone#play} */
    it('should have a play method that doesn\'t start if no frequency given', () => {
        synth.play();
        expect(synth.isPlaying).to.be.equal(false);
    });

    /** @test {ElectroPhone#play} */
    it('should have a play method that start playing given frequency', () => {
        synth.play(440);
        expect(synth.isPlaying).to.be.equal(true);
    });


    /** @test {ElectroPhone#stop} */
    it('should have a stop method that doesn\'t stop if no frequency given', () => {
        synth.stop();
        expect(synth.isPlaying).to.be.equal(true);
    });

    /** @test {ElectroPhone#stop} */
    it('should have a stop method that stop playing given frequency', () => {
        synth.stop(440);
        expect(synth.isPlaying).to.be.equal(false);
    });

    /** @test {ElectroPhone#link} */
    it('should have a link method to link two modules', () => {
        const nodeProps = { level: 100, link: null, wave: 'sine' };
        let modules;

        synth.create('node1', ElectroPhone.TYPES.OSCILLATOR, nodeProps);

        expect(synth.link).to.be.a('function');
        synth.link('node1', ElectroPhone.CONST.MASTER);

        modules = synth.getModules();
        expect(modules['node1']).to.be.a('object');
        expect(modules['node1'].props).to.be.a('object');
        expect(modules['node1'].props.link).to.equal(ElectroPhone.CONST.MASTER);
    });

    /** @test {ElectroPhone#link} */
    it('should fail if try to link the master module to anything', () => {
        expect(synth.link.bind(synth, ElectroPhone.CONST.MASTER, 'node1')).to.throw(Error);
    });

    /** @test {ElectroPhone#link} */
    it('should fail if try to link a source that doesn\'t exist', () => {
        expect(synth.link.bind(synth, 'nodeX', ElectroPhone.CONST.MASTER)).to.throw(Error);
    });

    /** @test {ElectroPhone#link} */
    it('should fail if try to link a source to a target that doesn\'t exist', () => {
        expect(synth.link.bind(synth, 'node1', 'nodeX')).to.throw(Error);
    });

    /** @test {ElectroPhone#getModuleProperties} */
    it('should have a static getModuleProperties method to get module properties by type', () => {
        const
            props = ElectroPhone.getModuleProperties(),
            oscProps = ElectroPhone.getModuleProperties(ElectroPhone.TYPES.OSCILLATOR);

        expect(props).is.an('array');
        expect(props.length).to.be.above(0);
        expect(props.filter(e => e.name === 'level').pop().defaultValue).to.be.equal(100);

        expect(oscProps).is.an('array');
        expect(oscProps.length).to.be.above(0);
        expect(oscProps.filter(e => e.name === 'wave').pop().defaultValue).to.be.equal(ElectroPhone.CONST.WAVE_SINE);
    });

    /** @test {ElectroPhone#describeModules} */
    it('should have a static describeModules method to describe all ElectroPhone modules with properties', () => {
        const modules = ElectroPhone.describeModules();

        expect(modules).is.an('array');
        expect(modules.length).to.be.above(0);
        expect(modules.filter(e => e.type === ElectroPhone.TYPES.MASTER).pop().properties).is.an('array');
        expect(
            modules
                .filter(e => e.type === ElectroPhone.TYPES.MASTER)
                .pop()
                .properties
                .filter(p => p.name === 'level')
                .pop()
                .defaultValue
        ).to.be.equal(100);

        expect(modules.filter(e => e.type === ElectroPhone.TYPES.OSCILLATOR).pop().properties).is.an('array');
        expect(
            modules
                .filter(e => e.type === ElectroPhone.TYPES.OSCILLATOR)
                .pop()
                .properties
                .filter(p => p.name === 'wave')
                .pop()
                .defaultValue
        ).to.be.equal(ElectroPhone.CONST.WAVE_SINE);
    });

    /** @test {ElectroPhone#getFrequency} */
    it('should have a static getFrequency method to calculate frequency value from note and octave', () => {
        const
            freq = ElectroPhone.getFrequency(),
            freqA4 = ElectroPhone.getFrequency('A', 4);

        expect(freq).to.be.a('number');
        expect(freq).to.be.equal(0);
        expect(freqA4).to.be.a('number');
        expect(freqA4).to.be.equal(440);
    });

    /** @test {ElectroPhone#getFrequency} */
    it('should have a static getNotes method to get notes list', () => {
        const notes = ElectroPhone.getNotes();

        expect(notes).is.an('array');
        expect(notes.length).to.be.equal(12);
        expect(notes.indexOf('C')).to.be.equal(0);
        expect(notes.indexOf('A')).to.be.equal(9);
    });
});