Skip to content

Commit

Permalink
Merge pull request #7 from khdkhd/acr/travis
Browse files Browse the repository at this point in the history
Chore: Unit tests
  • Loading branch information
a-cordier committed Nov 5, 2017
2 parents f190313 + 597d1e1 commit f5baf06
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 2 deletions.
9 changes: 8 additions & 1 deletion package.json
Expand Up @@ -36,6 +36,13 @@
]
}
},
"nyc": {
"exclude": [
"**/*.spec.js",
"**/*.mock.js",
"build"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/khdkhd/wasa"
Expand Down Expand Up @@ -84,4 +91,4 @@
"rxjs": "^5.4.3",
"worker-timer": "^1.1.0"
}
}
}
56 changes: 56 additions & 0 deletions src/blocks/hat.spec.js
@@ -0,0 +1,56 @@
import test from 'ava'
import sinon from 'sinon'
import { Hat } from './hat'
import { AudioContextMock } from '../mock/audio-context.mock'

test('Hat factory returns object', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const hat = Hat(audioContext)
t.true(typeof hat === 'object')
})

test('Hat factory returns object with a duration getter and setter', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const hat = Hat(audioContext)
hat.setDuration(1)
t.is(1, hat.getDuration())
})

test('Hat connect method returns an object with a connect method', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const hat = Hat(audioContext)
const nextInChain = {
input: audioContext.createGain(),
connect() {},
}
t.true(typeof hat.connect(nextInChain).connect === 'function')
})

test('Hat noteOn method call create oscillators in the audio context', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const hat = Hat(audioContext)
hat.noteOn()
t.true(audioContext.createOscillator.called)
})

test('Hat noteOff method call stop on oscillator nodes', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const hat = Hat(audioContext)
hat.noteOn()
hat.noteOff()
audioContext.getOscillatorNodes()
.forEach((osc) => {
t.true(osc.stop.called)
})
})

test('Hat noteOff method cancel scheduled values on gain nodes', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const hat = Hat(audioContext)
hat.noteOn()
hat.noteOff()
audioContext.getGainNodes()
.forEach((gain) => {
t.true(gain.gain.cancelScheduledValues.called)
})
})
72 changes: 72 additions & 0 deletions src/blocks/kick.spec.js
@@ -0,0 +1,72 @@
import test from 'ava'
import sinon from 'sinon'
import { Kick } from './kick'
import { AudioContextMock } from '../mock/audio-context.mock'

test('Kick factory returns object', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const kick = Kick(audioContext)
t.true(typeof kick === 'object')
})

test('Kick factory returns object with a duration getter and setter', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const kick = Kick(audioContext)
kick.setDuration(1)
t.is(1, kick.getDuration())
})

test('Kick factory returns object with a frequency getter and setter', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const kick = Kick(audioContext)
kick.setFrequency(440)
t.is(440, kick.getFrequency())
})

test('Kick factory returns object with a finalFrequency getter and setter', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const kick = Kick(audioContext)
kick.setFinalFrequency(220)
t.is(220, kick.getFinalFrequency())
})

test('Kick connect method returns an object with a connect method', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const kick = Kick(audioContext)
const nextInChain = {
input: audioContext.createGain(),
connect() {},
}
t.true(typeof kick.connect(nextInChain).connect === 'function')
})

test('Kick noteOn method call create oscillators in the audio context', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const kick = Kick(audioContext)
kick.noteOn()
t.true(audioContext.createOscillator.called)
})

test('Kick noteOff method call stop on oscillator nodes', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const kick = Kick(audioContext)
kick.noteOn()
kick.noteOff()
audioContext.getOscillatorNodes()
.forEach((osc) => {
t.true(osc.stop.called)
})
})

test('Kick noteOff method cancel scheduled values on osc gain nodes', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const kick = Kick(audioContext)
kick.noteOn()
kick.noteOff()
let nG = 0 // number of gain nodes
audioContext.getGainNodes()
.forEach((gain) => {
nG += gain.gain.cancelScheduledValues.called ? 1 : 0
})
t.is(audioContext.getGainNodes().length - 1, nG)
})
13 changes: 13 additions & 0 deletions src/common/range.spec.js
Expand Up @@ -10,6 +10,12 @@ test('Normalizes value from [min,max] to [0,1]', (t) => {
t.is(0.5, value)
})

test('Returns value unchanged if range is undefined', (t) => {
const range = undefined
const value = scale(range, 10)
t.is(value, value)
})

test('Unormalizes value from [0,1] to [min,max]', (t) => {
const range = {
min: 5,
Expand All @@ -18,3 +24,10 @@ test('Unormalizes value from [0,1] to [min,max]', (t) => {
const value = unscale(range, 0.5)
t.is(10, value)
})


test('Returns value unchanged if range is undefined', (t) => {
const range = undefined
const value = unscale(range, 10)
t.is(value, value)
})
37 changes: 36 additions & 1 deletion src/core/note.spec.js
@@ -1,6 +1,41 @@
import test from 'ava'
import { getFrequency } from '.'
import { Note, getFrequency, DURATIONS } from '.'

test('Note factory creates an object', (t) => {
const note = Note({
note: 'A4',
octave: 3,
duration: DURATIONS.WHOLE,
})
t.true(typeof note === 'object')
})

test('Note factory creates an object with a note getter', (t) => {
const note = Note({
note: 'A4',
octave: 3,
duration: DURATIONS.WHOLE,
})
t.is('A4', note.getNote())
})

test('Note factory creates an object with an octave getter', (t) => {
const note = Note({
note: 'A4',
octave: 3,
duration: DURATIONS.WHOLE,
})
t.is(3, note.getOctave())
})

test('Note factory creates an object with a duration getter', (t) => {
const note = Note({
note: 'A4',
octave: 3,
duration: DURATIONS.WHOLE,
})
t.is(DURATIONS.WHOLE, note.getDuration())
})
test('Note C3 converts to 130.81 Hz', (t) => {
const frequency = getFrequency('C', 3)
t.is(130.81, Number(frequency.toFixed(2)))
Expand Down
44 changes: 44 additions & 0 deletions src/core/sequencer.spec.js
Expand Up @@ -3,6 +3,12 @@ import sinon from 'sinon'
import { Sequencer } from '.'
import { AudioContextMock } from '../mock/audio-context.mock'

test('Sequencer factory creates a sequencer object', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const sequencer = Sequencer(audioContext)
t.true(typeof sequencer === 'object')
})

test('Calling start triggers onPlay handler', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
Sequencer(audioContext)
Expand All @@ -11,3 +17,41 @@ test('Calling start triggers onPlay handler', (t) => {
})
.start()
})

test('Calling stop triggers onStop handler', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
Sequencer(audioContext)
.onStop(() => {
t.pass()
})
.start()
.stop()
})

test('Sequencer factory returns object with a loopMode getter and setter', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const sequencer = Sequencer(audioContext)
sequencer.setLoopMode(true)
t.is(true, sequencer.getLoopMode())
})

test('Sequencer factory returns object with a length getter and setter', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const sequencer = Sequencer(audioContext)
sequencer.setLength(16)
t.is(16, sequencer.getLength())
})

test('Sequencer factory returns object with a division getter and setter', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const sequencer = Sequencer(audioContext)
sequencer.setDivision(4)
t.is(4, sequencer.getDivision())
})

test('Sequencer factory returns object with a tempo getter and setter', (t) => {
const audioContext = AudioContextMock(sinon.sandbox.create())
const sequencer = Sequencer(audioContext)
sequencer.setTempo(120)
t.is(120, sequencer.getTempo())
})
2 changes: 2 additions & 0 deletions src/mock/audio-context.mock.js
Expand Up @@ -14,6 +14,7 @@ export const AudioContextMock = (sandbox) => {
setValueAtTime: sandbox.spy(),
cancelScheduledValues: sandbox.spy(),
linearRampToValueAtTime: sandbox.spy(),
exponentialRampToValueAtTime: sandbox.spy(),
value: undefined,
})

Expand All @@ -26,6 +27,7 @@ export const AudioContextMock = (sandbox) => {
frequency: AudioParam(),
connect: sandbox.spy(),
start: sandbox.spy(),
stop: sandbox.spy(),
})

const createChannelMerger = () => ({
Expand Down

0 comments on commit f5baf06

Please sign in to comment.