Search code examples
javascriptunit-testingvue.jsonsen-ui

How to determine if OnsenUI component is compiled in unit test


My project is built with vue-cordova-webpack template. I created a vue-component. There is v-ons-input inside the template of my component. I need to change the value of v-ons-input during the unit test of my component. I can do it only after ons-input is compiled, because only after compilation ons-input has input inside (see about OnsenUI component compilation). The problem is a compilation is executed asynchronously and I didn't find any "legit" way to catch the event when OnsenUI component is ready for use.

What do I do? I created a sinon spy for an internal method _compile of the ons-input and wait until it's been called:

it('test', (done) => {
   const wrapper = mount(myVueComponent)

   // here I can't set a value for ons-input

   var spy = sinon.spy(wrapper.find('ons-input').element, '_compile')

   function waitForCall(spy) {
     return new Promise(function (resolve, reject) {
       (function wait() {
         if (spy.called) {
           return resolve()
         }
         setTimeout(wait, 10)
       })()
     })
   }

   waitForCall(spy).then(function () {
     // now ons-input is compiled and I can set a value for ons-input
     wrapper.find('ons-input').element.value = 'foo'
     ...
   }).then(done, done)
 })

Is there more "clean" way to determine that OnsenUI component is ready for use in a unit test (without manipulation with internal methods of the component)?

P.S. I know the way not for test environment - listening for init event for document(see here), but it doesn't work in unit tests.


Solution

  • setTimeout should be as good as anything here.

    setTimeout(() => document.querySelector('ons-input input'));
    

    Internal details (can be skipped)

    The file defining VOnsInput imports ons-input, which registers ons-input as a Custom Element. This happens synchronously so as long as the Vue component's script has been executed, it is guaranteed that ons-input will be registered as a Custom Element.

    During registration of ons-input, Onsen UI uses a function contentReady to wait for compilation to be finished, but that function is not part of the public API. However, contentReady uses setTimeout (technically setImmediate but it amounts to the same thing) as a fallback so by using setTimeout once you are effectively doing the same thing.

    In short, this means that using setTimeout should guarantee that the inner input is attached when setTimeout's callback is run.