Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing and Mocking with Jest, AudioContext

I've been having a lot of trouble trying to do some testing on my classes that use AudioContext. I believe a lot of my frustration stems from not having a good understanding of mocking functions and possibly how tests are executed.

I'm trying to test one class that takes AudioContext, however I keep getting this error when I run a test:

When using TypeScript files: TypeError: (window.AudioContext || window.webkitAudioContext) is not a constructor
This error happens inside the app.ts file. When I run a test does it have to resolve or execute all of it's dependencies?

When using JavaScript files this error occurs in the test file: ReferenceError: AudioContext is not defined

Right now, I assume I have to make a mock AudioContext. How do I even go about knowing all the methods on AudioContext to begin to manually mock it?

Here's a simplified version of my sheets. I will provide TS and JS versions of both:

TypeScript File Versions:

// app.ts
import Sampler from './Sampler';
const audioContext: AudioContext = new (window.AudioContext || window.webkitAudioContext)();
const sampler: Sampler = new Sampler(audioContext);


// Sampler.ts
export default class Sampler{
    private audioContext: AudioContext;

    constructor(audioContext: AudioContext){
        this.audioContext = audioContext;      
    }
 }

JS File Versions:

// app.js
const Sampler = require('./Sampler');
const audioContext =  new (window.AudioContext || window.webkitAudioContext)();
const sampler = new Sampler(audioContext);

// Sampler.js
class Sampler{
    constructor(audioContext){
        this.audioContext = audioContext;   
    }
}
module.exports = Sampler;

Test file that brings up the errors in bold that I mentioned earlier:

// sampler.test.ts

import Sampler from './Sampler';
// Uncomment line below if you're using plain JS and not TS
// const Sampler = require('./Sampler');

test('Test test', () => {
  const audioContext = new AudioContext();
  const s = new Sampler(audioContext);
})

Update: I have the code working for plain JS files now. I added an empty AudioContext mock to my tests.

// sampler.test.js
const Sampler = require('./Sampler');
require('./__mocks__/app');


test('Testing Mock AudioContext', () => {
    const audioContext = new AudioContext();
    const s = new Sampler(audioContext);
})


// __mocks__/app.js
window.AudioContext = jest.fn().mockImplementation(() => {
    return {}
});

Since my project is written in TypeScript, I tried adding the mock to my project, but I still get the error from above "TypeError: (window.AudioContext || window.webkitAudioContext) is not a constructor".

Thanks :).

like image 474
tkss Avatar asked Apr 10 '19 15:04

tkss


1 Answers

Old post, but I thought I would share how I handled the typescript error. To keep the leverage of Typescript and types, I just added the webkitAudioContext to the defined Window typing. My code looks like:

declare var window: {
  webkitAudioContext: typeof AudioContext;
} & Window & typeof globalThis;

const audioContext = new (window.AudioContext || window.webkitAudioContext)();

That essentially tells typescript to union Window & typeof globalThis with the new webkitAudioContext property.

As far as the ReferenceError: AudioContext is not defined error, that is most likely because AudioContext is not mocked (like you said – this is also the question I was searching for when I stumbled across your post). I know jest uses jsdom to mock the dom. jsdom currently doesn't support AudioContext mocks

like image 194
DJ House Avatar answered Oct 11 '22 21:10

DJ House