-->

“TypeError: deps.map is not a function” in resolve

2019-03-01 02:50发布

问题:

I've been changing my org's underlying infrastructure to switch our automated tests from running in browser client using a separate web server to running in the test runner (intern-runner). In the test runner environment, things had been going swell--I'd gotten past a ton of issues, but then boom! Someone drops a new unittest, that runs just fine in the browser client, but then when I run it with test runner, I get this error:

! TypeError: deps.map is not a function at http://9.77.140.51:9000/__intern/node_modules/dojo/dojo.js:678

Line 678 in dojo.js is this:

resolveDeps = function (deps, module, referenceModule) {
    // resolve deps with respect to this module
    return deps.map(function (dep, i) {   // <-- Line 678!
        var result = getModule(dep, referenceModule);
        if (result.fix) {
            result.fix = function (m) {
                module.deps[i] = m;
            };
        }
        return result;
    });
},

I have not changed this file at all. I have no idea what that resolveDeps() function does or what a "deps" is.

I don't see anything unusual that this new test is doing, nothing really extraordinary from the hundreds of other tests that pass just fine (however, I did not write it). Browser client reports no errors. When running with test runner, bringing up the developer tool to look at the console provides no meaningful info, as the TypeError seems to kill the HTTP proxy server and the browser console just shows a bunch of 404s, which seems like red herrings because the server was stopped.

Anyone have any clues?

回答1:

This is likely due to an improperly formatted test module, although it's hard to say without more information. The error is occurring in the loader's dependency resolution code, which comes into play for define and require statements. Dojo's define function understands 4 argument configurations:

  1. define(id, deps, callback)
  2. define(deps, callback)
  3. define(callback)
  4. define(object)

(id is a string and deps is an array.) If for some reason you had a module that used the format define(id, callback), you'd get the error you're seeing because the dependency resolution code in the loader expects either the first or second parameter to be an array.



回答2:

This seems to be caused by the dojo.js

This gives tests a slightly different module loading path than non-test files.

node_modules/dojo/dojo.js

  if (has('host-browser')) {
injectUrl = function (url, callback, module, parent) {
    // insert a script element to the insert-point element with src=url;
    // apply callback upon detecting the script has loaded.
    var node = document.createElement('script'),
        handler = function (event) {
            document.head.removeChild(node);

            if (event.type === 'load') {
                has('loader-ie9-compat') ? callback(node) : callback();
            }

When Dojo sets up the define global call, it is doing a check on the number of arguments passed to the define call. So, if you pass a single object to define, similar to what nls is doing for the i18n files, it will hit the following piece of logic.

node_modules/dojo/dojo.js:844

var define = mix(function (deps, factory) {
    if (has('loader-explicit-mid') && arguments.length === 3) {
        var id = deps;
        deps = factory;
        factory = arguments[2];
        var module = getModule(id);
        module.injected = true;
        defineModule(module, deps, factory);
    }

    if (arguments.length === 1) {
        if (has('loader-cjs-wrapping') && typeof deps === 'function') {
            factory = deps;
            deps = [ 'require', 'exports', 'module' ];

            // Scan factory for require() calls and add them to the
            // list of dependencies
            factory.toString()
                .replace(comments, '')
                .replace(requireCall, function () {
                    deps.push(/* mid */ arguments[2]);
                });
        }
        else if (/* define(value) */ !Array.isArray(deps)) {
            var value = deps;
            deps = [];
            factory = function () {
                return value;
            };
        }
    }

    if (has('loader-ie9-compat')) {
        for (var i = document.scripts.length - 1, script; (script = document.scripts[i]); --i) {
            if (script.readyState === 'interactive') {
                script.defArgs = [ deps, factory ];
                break;
            }
        }
    }
    else {
        defArgs = [ deps, factory ];
    }
}, {
    amd: { vendor: 'dojotoolkit.org' }
});

This defines that if it is not a function, then it will go into the second check to see if the dependencies are not an array, and then sets up a structure to return the value back in the factory.



标签: dojo intern