TypeError from screenfull library during jest test

I've added screenfull, a wrapper for the Fullscreen API (https://github.com/sindresorhus/screenfull.js) to a Redux-connected React component. The application uses Typescript elsewhere, but not in the components. Screenfull is used as follows in the component:

componentDidUnmount() {
  screenfull.on('change', () => this.props.toggleFullscreen());
}

componentWillUnmount() {
 screenfull.off('change', () => this.props.toggleFullscreen());
}

and I have a test as follows (there are more failing in the component test file, but I thought I'd share the first one)

  it('mounts with initial state', () => {
    const store = configureStore(reducer);
    const container = mount(
      <Provider store={store}>
        <VideoBoundingBoxApp inIframe={false} />
      </Provider>);
    expect(container.find('VideoBoundingBoxApp')).toExist();
  });

The application runs and works as expected, but when running yarn test, I get the following error:

console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
      Error: Uncaught [TypeError: _screenfull2.default.on is not a function]
          at reportException (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
          at invokeEventListeners (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:209:9)
          at HTMLUnknownElementImpl._dispatch (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
          at HTMLUnknownElementImpl.dispatchEvent (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
          at HTMLUnknownElementImpl.dispatchEvent (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
          at HTMLUnknownElement.dispatchEvent (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
          at Object.invokeGuardedCallbackDev (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:944:16)
          at invokeGuardedCallback (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:993:29)
          at commitRoot (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7157:9)
          at completeRoot (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8065:36) TypeError: _screenfull2.default.on is not a function
          at VideoBoundingBoxApp.componentDidMount (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/src/components/VideoBoundingBox/VideoBoundingBoxApp.jsx:122:28)
          at commitLifeCycles (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5347:26)
          at commitAllLifeCycles (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7018:9)
          at HTMLUnknownElement.callCallback (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:906:14)
          at invokeEventListeners (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
          at HTMLUnknownElementImpl._dispatch (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
          at HTMLUnknownElementImpl.dispatchEvent (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
          at HTMLUnknownElementImpl.dispatchEvent (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
          at HTMLUnknownElement.dispatchEvent (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
          at Object.invokeGuardedCallbackDev (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:944:16)
          at invokeGuardedCallback (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:993:29)
          at commitRoot (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7157:9)
          at completeRoot (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8065:36)
          at performWorkOnRoot (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8015:11)
          at performWork (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7933:9)
          at performSyncWork (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7910:5)
          at requestWork (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7810:7)
          at scheduleWorkImpl (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7685:13)
          at scheduleWork (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7645:12)
          at scheduleRootUpdate (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8273:5)
          at updateContainerAtExpirationTime (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8301:12)
          at Object.updateContainer (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8328:14)
          at Object.create (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9009:18)
          at Object.<anonymous> (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/src/test/components/VideoBoundingBox/VideoBoundingBoxApp.test.jsx:42:49)
          at Object.asyncFn (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-jasmine2/build/jasmine_async.js:82:37)
          at resolve (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-jasmine2/build/queue_runner.js:52:12)
          at new Promise (<anonymous>)
          at mapper (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-jasmine2/build/queue_runner.js:39:19)
          at promise.then (/Users/mschoemaker/Desktop/CrowdFlower/projects/image_annotation/node_modules/jest-jasmine2/build/queue_runner.js:73:82)
          at <anonymous>
          at process._tickCallback (internal/process/next_tick.js:188:7)

(similar for screenfull.off...) I am not sure how to parse this. I don't think it's Typescript related. Would anyone have any idea?

I (well, mostly my boss) figured it out. Turns out, the screenfull code has a check for whether document contains methods such as requestFullscreen, otherwise it returns false. I fixed this by adding

// fullscreen library will cause an error in jest tests
// if it  can't find fullscreen methods on document
[
  'requestFullscreen',
  'exitFullscreen',
].forEach(each => (document[each] = () => {})); // eslint-disable-line

to my setupTests.js

TypeError from screenfull library during jest test – Website Information, tyjny tjjnyt Uncategorized 2018-07-01 5 分. TypeError from screenfull library during jest test. I've added screenfull, a wrapper for the Fullscreen API� I'm trying to make a snapshot test with jest and I got this error: TypeError: Cannot read property 'monitorScrollValue' of null and the test fail without making any snapshot. Steps to reproduce: make a snapshot test following jest tutorial, on a component with a modal in it; Expected behavior: Snapshot is created. Additional notes:

For one thing in the unit test you likely want to jest.mock this dependency. And the _screenfull2.default.on is not a function error might be caused by mismatch between commonjs modules and es6 modules. How are you importing screenfull?

TypeError from screenfull library during jest test, I've added screenfull, a wrapper for the Fullscreen API (https://github.com/ sindresorhus/screenfull.js) to a Redux-connected React component. The application� Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question.Provide details and share your research! But avoid …. Asking for help, clarification, or responding to other answers.

@Michel Schoemaker answer is correct, but I wanted to provide more context for those curious souls out there like myself. Thankfully, screenfull's source code is super short and easy to reason about.

Looking at the source, you'll see a self-invoking function right at the top which stores its return value in a variable called fn.

    // This is what I'm talking about right here. See the end of this function
    var fn = (function () {
        var val;
        var fnMap = [
            [
                'requestFullscreen',
                'exitFullscreen',
                'fullscreenElement',
                'fullscreenEnabled',
                'fullscreenchange',
                'fullscreenerror'
            ],
            // New WebKit
            [
                'webkitRequestFullscreen',
                'webkitExitFullscreen',
                'webkitFullscreenElement',
                'webkitFullscreenEnabled',
                'webkitfullscreenchange',
                'webkitfullscreenerror'

            ],
            // Old WebKit
            [
                'webkitRequestFullScreen',
                'webkitCancelFullScreen',
                'webkitCurrentFullScreenElement',
                'webkitCancelFullScreen',
                'webkitfullscreenchange',
                'webkitfullscreenerror'

            ],
            [
                'mozRequestFullScreen',
                'mozCancelFullScreen',
                'mozFullScreenElement',
                'mozFullScreenEnabled',
                'mozfullscreenchange',
                'mozfullscreenerror'
            ],
            [
                'msRequestFullscreen',
                'msExitFullscreen',
                'msFullscreenElement',
                'msFullscreenEnabled',
                'MSFullscreenChange',
                'MSFullscreenError'
            ]
        ];

        var i = 0;
        var l = fnMap.length;
        var ret = {};
        // This for loop essentially checks the current document object for the property/methods above. 
        for (; i < l; i++) {
            val = fnMap[i];
            if (val && val[1] in document) {
                for (i = 0; i < val.length; i++) {
                    ret[fnMap[0][i]] = val[i];
                }
                return ret;
            }
        }
        // If it doesn't find any of them, this whole function returns false
        // and the fn variable is set to this returned value. 
        return false;
    })();

Then further down in the you'll see for a simple conditional check on this fn variable.

    // Sidenote, if you just remove the bang from the conditional, this package
    // works in testing. But obviously we don't want to do that. 
    if (!fn) {
        if (isCommonjs) {
            module.exports = {isEnabled: false};
            // If log out the value of screenfull after importing it 
            // in your test, this is what you'll see -> {isEnabled: false}
            // Thus screenfull sets this object as the exported module and returns early. 
        } else {
            window.screenfull = {isEnabled: false};
        }

        return;
    }

So back to @Michel Schoemaker's answer; The reason that works is because we're basically monkey patching these properties/methods in the document object so Screenfull thinks we have a compatible environment. Once it think's we have a compatible environment, Jest can mock the library as usual.

I did things a little different than @Michel Schoemaker because I was only using screenfull in two methods of my application so I didn't need to set them up for my whole testing environment. Here' my approach:

thing.spec.js

import screenfull from 'screenfull';

jest.mock('screenfull');

    //********* Fullscreen **********//
    describe('Fullscreen', () => {

        beforeEach(() => {
            document.requestFullscreen = jest.fn();
            document.exitFullscreen = jest.fn();
            document.fullscreenElement = jest.fn();
            document.fullscreenEnabled = jest.fn();
            document.fullscreenchange = jest.fn();
            document.fullscreenerror = jest.fn();
        });

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

        test('test name', (done) => {
            // Assemble

            // Act

            // Assert
            expect(screenfull.toggle).toHaveBeenCalled();
            done();
        });
    });

sindresorhus/screenfull.js: Simple wrapper for cross , This is a limitation in the browser, not in Screenfull. Documentation. Examples. Fullscreen the page. document. Jest is a library for testing JavaScript code. It's an open source project maintained by Facebook, and it's especially well suited for React code testing, although not limited to that: it can test any JavaScript code. Jest is very fast and easy to use

jest – Website Information, Sleeping in jest tests (using async await) does not work. Sleeping in jest tests TypeError from screenfull library during jest test. TypeError from� There's a need here, and if you ignore it Jest core library users (and let's be honest, 90% of them will never even hear about jest-extended) will lose out. .to.be.an.instanceOf is not going to be how many users think to check types, so for those users, even if you see it as sugar, you are effectively denying them the ability to check types in

Configuring Jest � Jest, Note: Node modules are automatically mocked when you have a manual mock in place (e.g.: __mocks__/lodash.js ). More info here. Note: Core modules, like fs ,� Jest Tutorial: what is Jest? Jest is a JavaScript test runner, that is, a JavaScript library for creating, running, and structuring tests. Jest ships as an NPM package, you can install it in any JavaScript project. Jest is one of the most popular test runner these days, and the default choice for React projects.

DOM Manipulation � Jest, Let's see how we can test the following snippet of jQuery code that listens to a click event, fetches some Again, we create a test file in the __tests__/ folder: jest my-test #or jest path/to/my-test.js Run tests related to changed files based on hg/git (uncommitted files): jest -o Run tests related to path/to/fileA.js and path/to/fileB.js: jest --findRelatedTests path/to/fileA.js path/to/fileB.js Run tests that match this spec name (match against the name in describe or test, basically). jest -t name

Comments
  • Hello, could you please elaborate your answer? I don't get where exactly place this code. Thanks!
  • Thanks for your response. I am importing it as import screenfull from 'screenfull';, just as all my other dependencies.
  • does it work outside of the unit test, when you manually test?
  • I've also tried import * as screenfull from 'screenfull', and const screenfull = require('screenfull'), but I get the same error
  • if you don't have this error in actual application code, then maybe the problem lies in the way jest loads the module. Checkout jestjs.io/docs/en/getting-started.html#using-babel
  • you might also want to consider ts-jest