BorisMoore / jsviews

Interactive data-driven views, MVVM and MVP, built on top of JsRender templates
http://www.jsviews.com/#jsviews
MIT License
856 stars 130 forks source link

losting last symbol #386

Closed Mytia closed 7 years ago

Mytia commented 7 years ago

Hi again:)

I'm using selenium for test web gui writing on jsviews. After some updates of jsviews I start to get error in tests with losting last symbol from input. For example my test is like this: ... .setValue('#name', 'test value') .click('#save')

and my test send and save to db only 'test valu'

I try to emulate such scenario in fiddle:

https://jsfiddle.net/nq4372t8/14/

So as I understand, I can fix tests for adding .pause(1) after setValue but it is not best practice for me, Moreover, the tests worked before without it...

BorisMoore commented 7 years ago

Yes, that's because the default trigger setting is 'true', so text box triggers updates on each character entry. But that update is asynchronous, not synchronous.

It changed in commit 77: See https://github.com/BorisMoore/jsviews.com/commit/e6a1582c39ff15c0f6ae0bce050965b70f975f12

So for testing frameworks you either have to make your test async, or you need to switch the trigger setting back to false, like it was before commit 77:

Examples: https://github.com/BorisMoore/jsviews.com/blob/gh-pages/test/unit-tests/tests-jsviews.js#L1235-L1238 https://github.com/BorisMoore/jsviews.com/blob/gh-pages/test/unit-tests/tests-jsviews.js#L7780-L7805

So you can write:

$.views.settings.trigger(false);
var data = {
    item: { name: '1111' },
  save: function(event, data) {
    console.log(data.view.data.name);
  }
};

$.templates("#tmpl").link("#main", data);

$('#name').val('2222');
$('#name').change();
$('#save').click();
Mytia commented 7 years ago

Well, thanks for fast answer. I see in my live databases cut text, so as I undestood, users can reproduce "fast input" throught GUI and my selenium test works fine on 83 version with default value of trigger setting. Is it possible that after the 83 version jsviews started working a little slower, which was enough to allow the users and tests of the selenium to press the save button before data is updated in the object or is it most likely a problems in my code?

BorisMoore commented 7 years ago

I don't think commit 83 had changes that would have noticeably impacted perf. But I would be curious to understand better, if you do see a significant change after that specific commit. Can you switch back to 82, and compare...?

If you have a lot of code running after each key entry (and therefore observable update to the value, if you have trigger set to true) then it may be possible to create a race condition. I have not seen that, though. If you are able to reproduce such a scenario, I would be interested to look more closely and analyse what is happening.

Of course you can either change the way you bind observably to that value, so as to reduce code running on each character update, or you can switch to trigger = false, either globally or for that particular input...

Mytia commented 7 years ago

You can see this feature better in this fiddles... 83 version https://jsfiddle.net/nq4372t8/16/ 84 version https://jsfiddle.net/nq4372t8/18/

BorisMoore commented 7 years ago

They both seem to work correctly for me. What is the difference in behavior that you are seeing with those two samples?

Mytia commented 7 years ago

In chrome 59, 83 showing in concole two times 2222, but 84 - 1111

BorisMoore commented 7 years ago

The difference between 83 and 84 is:

In 83 if you have an input with trigger=true, it listens to keydown events and then triggers observable updates for each character entry, and ALSO (redundantly) it listens to the change event (bubbled up to the 'activeBody' element) and again triggers observable updates. That meant that you could have code that triggered the change event on the input using .change() (like in your jsfiddle) or .blur() and that would trigger the observable update.

In 84 the redundant triggering of the change event is removed (for better perf and to reduce confusion for developers who would probably not understand why certain code was running twice): https://github.com/BorisMoore/jsviews/blob/master/jsviews.js#L3769. So now if you have trigger set to true, it listens only to keydown (async), but if you set to false it will only listen to change (sync) - for triggering observable updates...

With 84 in the default situation (trigger=true) you can still programmatically trigger updates by writing

$('#name').val('2222');
$('#name').keydown();

but using change() will not work...

Mytia commented 7 years ago

Ok, thanks for the detailed explanation. Use $.views.settings.trigger(false); in tests and all works fine.

BorisMoore commented 7 years ago

See also https://github.com/BorisMoore/jsviews/issues/381