Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewiring a module containing DOM manipulation #152

Open
lkaratun opened this issue Nov 10, 2018 · 3 comments
Open

Rewiring a module containing DOM manipulation #152

lkaratun opened this issue Nov 10, 2018 · 3 comments

Comments

@lkaratun
Copy link

Hi,

I'm trying to use rewire from a Jest test. Jest comes with jsdom and document object is defined inside the test. However, when I try to run
const app = rewire("../app.js")
it fails with the error:
TypeError: Cannot read property 'querySelector' of undefined
when it tries to run the line
const myForm = document.querySelector("#myForm");

When I replace the rewire call with require, the file get imported successfully.

Is there a way to solve this? Am I doing something wrong? Any help will be appreciated!

@akuroda
Copy link

akuroda commented Feb 9, 2019

Hi,
It seems methods of document object are lost after rewire. My workaround for similar problem is:

const f = document.getElementById.bind(document);
const mymodule = rewire('...');
options.__set__("document", {
    getElementById: f
});
// access document object inside mymodule

cf: https://stackoverflow.com/questions/10743596/why-are-certain-function-calls-termed-illegal-invocations-in-javascript

@atsepkov
Copy link

The workaround will not work if the imported file performs DOM manipulation at the time it's being loaded rather than inside a function call to be executed later.

Granted, by default Jest's native jsdom fails in that case too, but explicitly loading jsdom via Jest's setupFiles flag easily fixes the issue in case of regular "require" but remains broken when using "rewire".

@garrettwgg
Copy link

It's not foolproof, but I came up with a different way to get around this. Basically I duplicated the file I wanted to test, injecting the jsdom directly into the file. I also used my actual HTML in the jsdom. I make no claims of it being a perfect (or perfectly written) solution, but it seems to work.

const fs = require('fs')
const rewire = require('rewire')
const pug = require('pug')

const rawIndex = fs.readFileSync('./public/javascripts/index.js', 'utf-8')

// this would a a readFileSync if you had a plain HTML file
const indexHTML = pug.compileFile('./views/index.pug')()

const mockDOM = `
'use strict';

const { JSDOM } = require('jsdom')
const dom = new JSDOM(\`${indexHTML}\`)
document = dom.window.document
window = dom.window
`

fs.writeFileSync('./__mocks__/index.jsdom.js', mockDOM + rawIndex, 'utf-8')

const index = rewire('../__mocks__/index.jsdom.js')

afterAll(() => {
    fs.unlinkSync('./__mocks__/index.jsdom.js')
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants