Integration with proxyquireify #2

Closed
loicplaire opened this Issue Apr 16, 2015 · 13 comments

Projects

None yet

3 participants

@loicplaire

I use browserify/react/proxyquireify on my project. I got the first two working but whenever I use proxyquire in my specs, i get errors like the one below:

Error: Cannot find module '../../../../app/components/Ads/PolarNativeAdTeaser'
    at app-test/specs/components/Ads/PolarNativeAdTeaserSpec.js:17

I believe I call the proxyquireify plugin correct in wallaby.js is:

'use strict';

var wallabify = require('wallabify');
var proxyquireify = require('proxyquireify');

var wallabyPostprocessor = wallabify({},
    function(b){
        return b.plugin(proxyquireify.plugin);
    }
);

module.exports = function () {
    return {
        files: [
            'node_modules/react-tools/src/test/phantomjs-shims.js',
            {
                pattern: 'app/**/*.js',
                load: false
            },
            {
                pattern: 'app-mock/**/*.js',
                load: false,
                instrument: false
            }
        ],

        tests: [
            {
                pattern: 'app-test/**/*Spec.js',
                load: false
            }
        ],

        testFramework: 'mocha@2.0.1',

        preprocessors: {
            'app*/**/*.js': function(file) {
                return require('babel').transform(file.content, {sourceMap: true});
            }
        },

        postprocessor: wallabyPostprocessor,

        bootstrap: function () {
            window.__moduleBundler.loadTests();
        }
    };
};

My spec is:

var proxyquire = require('proxyquireify')(require);
var PolarAdSlotTeaser = proxyquire('../../../../app/components/Ads/PolarNativeAdTeaser', {
    'react': Context.React,
    '../../utils/mixins/PolarNativeAdMixin': {}
});

A similar karma config using the proxyquireify plugin works without any issue with the exact same specs.

Am I doing something wrong?

@ArtemGovorov ArtemGovorov added the bug label Apr 16, 2015
@ArtemGovorov
Member

Confirmed, reproduced it, thanks for the sample code. Looks like proxyquireify is replacing browserify default prelude script, investigating why wallabify doesn't work with it.

@ArtemGovorov
Member

So proxyquireify works by replacing default browserify prelude code during pack phase and adding a transform to add normal require for everything that was proxyquireify-ed.

First, wallaby.js removes the pack phase of browserify as it doesn't serve bundles, so no need to pack anything. To address this issue I have added an option to pass a prelude code via options. Please make sure to update to wallabify@0.0.6.

Second, wallaby.js changes the original code (instruments it) and proxyquireify transform dependency search only works for simple cases, like

var proxy = require('proxyquireify')
var proxy = require('proxyquireify')(require)

In case of wallaby instrumentation, they become something like

var proxy = (w(...), require('proxyquireify'))
var proxy = (w(...), require('proxyquireify')(require))

and that makes proxyquireify not find these vars anymore.

To address this issue I have patched proxyquireify below. Ideally, I should send a PR to https://github.com/thlorenz/proxyquireify/blob/master/lib/find-dependencies.js to handle more complex scenarios, such as in wallaby case. But for now, all you need to do is to list variables that you assign to require('proxyquireify')(require), it is proxyquire in you example code, in one place in the patch. If you are using the same proxyquire name everywhere, then it's even easier.

So the config file that should work for you is:

'use strict';

var wallabify = require('wallabify');
var proxyquireify = require('proxyquireify');

// proxyquireify patch
var proxyquireifyPrelude = require('fs').readFileSync(require('path').join(__dirname, 'node_modules/proxyquireify/lib/prelude.js')).toString();
require('proxyquireify/lib/find-dependencies');
require.cache[require.resolve('proxyquireify/lib/find-dependencies')].exports = function (src) {
  if (!/require\(.+proxyquireify.+\)/.test(src)) return [];
  // IMPORTANT: list all variables that you assign like var proxyquire = require('proxyquireify')(require);
  var hash = ['proxyquire']
    .map(function (name) {
      return require('proxyquireify/node_modules/detective')(src, {word: name});
    })
    .reduce(function (acc, arr) {
      arr.forEach(function (x) {
        acc[x] = true;
      });
      return acc;
    }, {});

  return Object.keys(hash);
};

var wallabyPostprocessor = wallabify({
        // passing proxyquireify prelude code
        prelude: proxyquireifyPrelude
    },
    function(b){
        // we don't need anything but proxyquireify transform
        return b.transform(require('proxyquireify/lib/transform'));
    }
);

// the rest of your config didn't change

Please let me know if it works for you.

@loicplaire

Thanks for the quick feedback and update! That works perfectly.

@ArtemGovorov
Member

Awesome, thanks.

@Almenit
Almenit commented Dec 4, 2015

Any idés how to be able to use it with typescript? Is this the way to go?

import proxy from "proxyquireify";
var proxyquireify = proxy(require);
@ArtemGovorov
Member

@Almenit As mentioned it my comment, you need to list variables that you assign. My patch is using proxyquire variable, your is using proxyquireify variable, so you may need:

...
var hash = ['proxyquire', 'proxyquireify']
...
@Almenit
Almenit commented Dec 4, 2015

Yes I know that and I tried that. And It maybe right, but when I use proxyquireify() it can find my module. It is a bit hard to debug and find the error.

@ArtemGovorov
Member

Does it work without wallaby? Try looking into the compiled files in wallaby cache, perhaps it could shed some light.

@Almenit
Almenit commented Dec 4, 2015

I will try that on monday. I will let you know :-)

@ArtemGovorov
Member

@Almenit Cool, let me know how it goes. If it doesn't work for you, please try reproducing it on the repo I have created for you earlier - https://github.com/wallabyjs/typescript-es6-babel and I'll have a look how to make it work.

@Almenit
Almenit commented Dec 5, 2015

I will do that. Thanks @ArtemGovorov for your help.

@Almenit
Almenit commented Dec 7, 2015

Now it works! I had to fake a require in typescript and do a

var proxyquireify = require("proxyquireify")(require);
@ArtemGovorov
Member

@Almenit Awesome, thanks for the update! I'm guessing it's because proxyquireify expects certain code structures, but with separate import proxy from "proxyquireify"; TypeScript compiler generates the code that proxyquireify doesn't expect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment