cybernetlab / karma-polymer

Karma adapter for Polymer framewrok
2 stars 6 forks source link

Uncaught TypeError: window.wrap is not a function #2

Closed haxpor closed 7 years ago

haxpor commented 7 years ago

Hi I wrote a test case of polymer in jasmine using polymer.create('stock-ticker', done) inside beforeAll(function(done)) as seen on README.md of this repository.

But then it gives me error as follows

Uncaught TypeError: window.wrap is not a function
  at node_modules/karma-polymer/lib/adapter.js:41

Below is version of related packages I use

"babel": "^5.8.21",
    "babel-preset-es2015": "^6.16.0",
    "browserify": "^13.3.0",
    "jasmine-core": "^2.5.2",
    "karma": "^1.4.0",
    "karma-browserify": "^5.1.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-jasmine": "^1.1.0",
    "karma-polymer": "^0.1.4",
    "karma-spec-reporter": "0.0.26",
    "watchify": "^3.9.0"
cybernetlab commented 7 years ago

Hi! looks like your HTML includes element with id wrap. Isn't it? If yes - try to change it to another value

haxpor commented 7 years ago

@cybernetlab thanks for prompt reply! I checked and I had no element with id wrap. I tested printing window.wrap out in adapter.js file at that line, and it's undefined. If you need more information, please tell me.

cybernetlab commented 7 years ago

Did you include webcomponents polyfill like it noted here?

<!-- Polyfill Web Components for older browsers -->
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>

I found wrap declaration in wscomponentsjs

haxpor commented 7 years ago

Yes, I included it. I checked I also included it in karma's configuration file too.

Here in index.html

...
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1">
<script src="node_modules/webcomponents.js/webcomponents-lite.min.js" async></script>

<!-- Import your component here -->
<link rel="import" href="dist/test-component.v.html" async>

<style>
...

Here in karma's configuration file

// list of files / patterns to load in the browser
    files: [
        { pattern: 'node_modules/**', included: false, served: true, watched: true },
        './node_modules/webcomponents.js/webcomponents.min.js',
        './src/**/*.js',
        './test/**/*.js'
    ],

    polymer: {
      src: [
        './node_modules/@polymer/polymer/polymer.html',
        './node_modules/webcomponents.js/webcomponents.min.js',
        './src/**/*.js',
        './src/**/*.html'
      ]
    },

Updated: I tried not to include it in Jasmine test, it gives out the same error.

cybernetlab commented 7 years ago

I think that the key of problem is async attribute of script and link elements. It forces browser to execute script asynchronousely without waiting for full page load. As you have async on both webcomponents and test-component you can't be sure that window.wrap will be defined when test-component will be executed. Try to remove both. If it helps, and you want to improve page loading, try to set async on webcomponents only.

UPD Also try to change async to defer because last one guaranties loading order

haxpor commented 7 years ago

I can render page normally without problem with async but I do agree removing it is better. Thanks for that.

For Jasmine, So I believe this means I need to ensure that webcomponentsjs is loaded first before custom component when test suite starts. But how can I ensure it via karma? Please allow me to include karma.conf.js as follows.

// Karma configuration
// 
module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['polymer', 'browserify', 'jasmine'],

    // list of files / patterns to load in the browser
    files: [
        { pattern: 'node_modules/**', included: false, served: true, watched: true },
        './src/**/*.js',
        './test/**/*.js'
    ],

    polymer: {
      src: [
        './node_modules/@polymer/polymer/polymer.html',
        './node_modules/webcomponents.js/webcomponents.min.js',
        './src/**/*.js',
        './src/**/*.html'
      ]
    },

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
        './src/**/*.js': [ 'browserify' ]
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    // update: added karma-spec-reporter, so we can use 'spec' here
    reporters: ['spec'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['ChromeCanary'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
cybernetlab commented 7 years ago

try to update karma-polymer from github master. Does it fixes issue? Fill free to reopen if it doesn't

haxpor commented 7 years ago

Thank you so much for quick fix! This got rid of that error.

Besides it introduces another one, at the time of test executing the code polymer.create('stock-ticker', done) I tried to print out polymer before that call, and found out that its ready: false. Probably polymer is not yet ready, although I'm no longer stuck at that window.wrap now I need to find a way to ensure running Jasmine test after Polymer is ready because I test calling the component's member functions too.

I did something like this in front-end code

<html>
<body>
...
<script>
  window.addEventListener('WebComponentsReady', function(e) {
    console.log("WebComponents is ready");

    var elem = document.querySelector("stock-ticker");

    console.log(elem.dummyStr('test')); // works
    console.log(elem._computePercent('0.07')); // works

    // do something here as webcomponent is ready ...
  });
</script>
...
</body>
</html>

I can't do that in Jasmine code. But I also tried

polymer.platformReady
.then((result) => {
    console.log("ready upper");
    polymer.create('stock-ticker', function(el) {
        console.log("ready");
        done();
    });
});

done() is not executed, "ready upper" is not printed out too.

Do you have any suggestion on this?

I'm not sure I need to create this for another issue yet, but it's following up from the original issue, thus I continue comment on this thread first.

cybernetlab commented 7 years ago

try to edit node_modules/karma-polymer/lib/adapter.js in your local project and add console.log('something') just before line 42. Do you see anything?

UPD Also find this code in your local project and add console.log(window.wrap) before and after if. Do you see output? Does it appears before or after previous console.log?

haxpor commented 7 years ago

Nope, I don't see it.

Updated: Just saw your update, I'm trying that now...

haxpor commented 7 years ago

I didn't see any text output from both location. Weird.

haxpor commented 7 years ago

I stop bumping this thread now, and will continue investigate until I can find something and might open a new issue. Just in case if you need to look at, this block of code from my testing project has testing against functions that it all failed as it doesn't recognize them as functions.

cybernetlab commented 7 years ago

As I pointed here you didn't include webcomponentsjs in your test code. You include it in index.html but it seems like this file not used in tests. How do you configure your tests? Since you config doesn't include any *.html

haxpor commented 7 years ago

I made it works before with different set up that doesn't include browserify in the workflow, or say include using require() in the source code. See here for example project that works but does not include browserify. You can see its Jasmine test code too here. Very similar to what I'm doing right now.

And the same project we're discussing with this line that if I remove it and cut out browserify in the workflow, then it works as expect. Jasmine test case can recognize functions properly.

I'm not 100% understand of what might be the root cause. Do you think browserify might get in the way?

cybernetlab commented 7 years ago

Anyway the fact that console.log in webcomponents doesn't execute means that you have no this file included inside tests.

haxpor commented 7 years ago

Thanks for all your help and suggestion @cybernetlab ! I successfully integrated the test and it was running fine now.

As for my case, my component has separate .js file from .html. I have to specify something like this in karma.conf.js.

    ...
    // list of files / patterns to load in the browser
    files: [
        { pattern: 'bower_components/**', included: false, served: true, watched: true },
        { pattern: 'node_modules/**', included: false, served: true, watched: true },
        'bower_components/webcomponentsjs/webcomponents-lite.min.js',
        './src/**/*.js',
        './test/**/*.js'
    ],

    polymer: {
      src: [
        'bower_components/polymer/polymer.html',
        './src/**/*.html'
      ]
    },
    ...

and in Jasmine, I need to manually listen to WebcomponentsReady and cannot use polymer.create() which it never call the callback. Code as follows.

beforeAll(function(done) {
   window.addEventListener('WebComponentsReady', function(e) {
   console.log("WebComponents is ready");

   stockticker = document.createElement('stock-ticker');
   stockticker.setAttribute('symbols', '["GOOG", "GOOGL"]');
   stockticker.setAttribute('id', id_name);
   document.body.appendChild(stockticker);

   // get element now and use it throughout test case
   //to_check = document.getElementById(id_name);
   to_check = document.getElementById(id_name);

   done();
   });
});

Notice that I need to specify component's js file which is ./src/**/*.js in files:, but not in polymer: to make it works.