Vue Component Lifecycle Hooks Not Being Called - vuejs2

See and example of this issue here.
I have a <count-down> component that simply displays an timer (that updates every second, of course). If I have three such timers on the page all at the same time, they work as expected. However, if I have three that are displayed on the pages at different times (i.e. using v-if statements), the timers don't work as expected. The first timer works just fine, but the lifecycle hooks for subsequent timers never fire. I have a sneaky suspicion that Vue is trying to be clever and reuse my first component, since it's no longer on the page any more. What can I do to work around this behavior?

Use a key.
The key special attribute is primarily used as a hint for Vue’s virtual DOM algorithm to identify VNodes when diffing the new list of nodes against the old list. Without keys, Vue uses an algorithm that minimizes element movement and tries to patch/reuse elements of the same type in-place as much as possible.
From your codepen:
<count-down :description="'Timer 1: '" :seconds="3" v-if="sync" :key="1"></count-down>
<count-down :description="'Timer 2: '" :seconds="5" v-if="sync" :key="2"></count-down>
<count-down :description="'Timer 3: '" :seconds="7" v-if="sync" :key="3"></count-down>
<count-down :description="'Timer 4: '" :seconds="3" v-if="async === 4" :key="4"></count-down>
<count-down :description="'Timer 5: '" :seconds="5" v-if="async === 5" :key="5"></count-down>
<count-down :description="'Timer 3: '" :seconds="7" v-if="async === 6" :key="6"></count-down>

Related

"v-on with no argument expects an object value" facing this error in quasar selector when focus into the field

here is my code, options array updated in created hook based on api response and response of api is array of object and v-model value is also updated in created hook. this selector is of input type and also filter the data based on input type from options array.
hope so this chunk of code is enough to explain.
<q-select
ref="registeredCountry"
for="registeredCountry"
color="olab-brand-blue"
v-model="registeredAddress.country"
use-input
fill-input
hide-selected
:options="countryOptions"
#filter="filterCountryList"
emit-value
option-label="countryName"
option-value="countryName"
#update:model-value="resetStateAndCityFields('registeredAddress')"
map-options
>
</q-select>
I got exactly the same Vue warning with one of my q-selects, after migrating it (unchanged) from Vue 2/Quasar 1 to Vue 3/Quasar 2. The same q-select code worked without warnings on the older levels. The warning is very unspecific from a Quasar point of view.
However, I found a hint on https://github.com/quasarframework/quasar/issues/8898 to eliminate this warning, which helped to resolve the issue in my case.
The reason for the warning was in my case due to the use of q-chips with q-items for the options in the q-select. Those q-items for the q-select options used "v-on='scope.itemEvents'", together with "v-bind='scope.itemProps'", which was the recommended combination in Quasar 1/Vue 2.
In Quasar 2/Vue 3 the "v-on='scope.itemEvents' is no longer necessary (if used, it causes this Vue warning). Just search for all "v-on='scope.itemEvents'" in your template code, then drop (i.e. delete) those "v-on=...", but keep the "v-bind=...".
This eliminates the above Vue warnings (which otherwise come up for every selectable option in your q-select).

How to avoid v-text-field to emit input events?

I'm trying to simulate the v-model.lazy for my v-text-field due to performance constraints.
I tried this:
<v-text-field :value="p.name" #change="v => p.name = v" :data-vv-name="'name'+p.id" v-validate="'required|max:255'" :error-messages="errors.collect('form'+p.id+'.'+'name'+p.id)" :counter="255" :label="$t('property.name')" required maxlength="255" :data-vv-as="' '" v-else></v-text-field>
But I keep getting all the keydowns and input emits, which is provoking a big lag:
If I use an input with a v-model.lazy it works as expected, but I'm not able to achieve the same thing using the v-text-field.
Should I use a prevent.default for those events?
Adding data-vv-delay="1000" and :value="p.name" #change="v => p.name = v" instead of v-model improved a lot the lag. This will delay de validation of the field.
The real solution would require v-model.lazy to work on Vuetify's v-text-field, but it is not the case yet.

How can you avoid redundant call while waiting for element visibility

I currently have a test script using WebdriverIO that clicks on a button and waits for a popup to display. The purpose of the test is to make sure the element is displayed after a click, but since it is asynchronous I must wait till it is displayed.
But if I wait until the element is displayed my assertion will always pass if waitForVisible is successful. If it is not successful it will always throw an exception on the waitForVisible command and the assertion will never execute.
Here is an example of the code:
browser.click(btnElement)
browser.waitForVisible(popupElement)
expect(browser.isVisible(popupElement)).to.be.true
Is there a different way to tell the expect statement to retry/wait until the element is visible so the assertion is not useless?
You seem to be confusing the purpose of assertions, or misusing them, specifically in your example. You should only use assertions when you have the certainty that the thing (WebElement, text, attribute of an element, etc.) you want to verify contains the expected type of value (which you return into your assert, or expect statement for the final validation => the output is the desired one).
Assertions validate a static value, they don't poll the DOM. That's why you have tools like .waitForVisible(), waitForText(), or more importantly .waitUntil() (which offers more flexibility).
Granted, the expect assertion-style provided by ChaiJS might have a confusing lexicon (expect could be taken out of context: it is expecting of the WebElement to be visible). Just use them for validating outputs of different commands, not states of WebElements, or other dynamic/changing elements.
That being said, as a best-practice, you should always wrap your commands (e.g.: .click()) into a .waitUntil() block and assure the WebElement is ready for the action you're about to perform:
is it rendered in the DOM by the front-end logic? (use .isExisting())
is it visible in the DOM? (you *cannot click on elements which aren't visible in the viewport)
is it clickable? (or w/e other action you want to perform on it...)
In the end, a idiomatic action (in our case .click()) should look like this:
browser.waitUntil(() => {
browser.isExisting(locator);
}, timeout, "Oups! An error occured.\nReason: element ('" + locator + "') does not exist");
browser.waitUntil(() => {
browser.isVisible(locator);
}, timeout, "Oups! An error occured.\nReason: element ('" + locator + "') is not visible");
browser.waitUntil(() => {
browser.click(locator);
}, timeout, "Oups! An error occured.\nReason: element ('" + locator + "') could not be clicked");
You can wrap the whole thing into a custom-command and use it w/e you want. Say good-bye to flaky tests! :)
* Selenium is a user-centric web-automation tool, thus all actions are performed as if a user would (a user cannot click on elements that aren't visible, a user cannot click on multiple elements at the same time, or fill in an input field by typing a whole word, or a whole paragraph, etc.)
I don't know WebdriverIO but I would assume that it has something akin to a try-catch. Wrap your wait in a try-catch. If it succeeds, Assert.pass() or the equivalent. If it times out, an exception will be thrown so in your catch for the timeout put an Assert.fail() or the equivalent.
I've never used ChaiJS but I did take a look at the documentation and found a couple things you should be able to use.
assert.isOk(false, 'this will fail');
This is from the documentation and should be the equivalent to what I'm familiar with, Assert.Fail(). One would assume that a slight adjustment the following would be the equivalent to Assert.Pass(),
assert.isOk(true, 'this will pass?');
If that doesn't work for some reason, you can use the below from the documentation.
assert.isNotOk(false, 'this will pass');

How to get the text from an element which disappears quickly using protractor

I need to get the text from element P but protractor keeps returning error
Code:
<div class = "ui-growl-message">
<span class = "ui-growl- title">Sucesso</span>
<p>cargo Cadastrado cm sucesso!</p>
</div>
I've tried this way:
const msgValidacao = element(by.css('ui-growl-message')).all(by.tagName('p')).first().getText().then(() => {
expect(msgValidacao).toContain('Cargo cadastrado com sucesso');
});
and the Error is:
Failed: No element found using locator: By(css selector,
ui-growl-message)
The problem is the element is a warning so it quickly disappears from the screen.
In addition to the css correction, you'll also want to employ some sort of wait strategy to anticipate the message and grab the content as close to the moment of the initial rendering as possible. Automation around very short-lived messages can be challenging due to intricate timing factors.
It might be not the real problem why it returns that element is not found. I thing that the selector is not good. If the element disappears quickly as You say sometimes the test will pass and sometimes it will fail. Try another selector and make sure that You have the correct one.
If you want to select first element use get(0) not first()
element(by.css('ui-growl-message')).all(by.tagName('p')).get(0)

Difference between registry.byId and dom.byId in dojo? What is the advantage of using registry.byId?

What is the difference between registry.byId and dom.byId in dojo? What is the advantage of using registry.byId?
In the code below I'm using dijit/registry and dojo/dom for both my textbox (#myTextBox3) and my textbox node (#textNode3). Only two of them are providing results.
require(["dojo/parser", "dojo/dom", "dijit/registry", "dijit/form/TextBox", "dojo/domReady!"],
function(parser, dom, registry) {
parser.parse();
// Locate the JS object.
var dibiWidget = registry.byId("myTextBox3");
var dobiWidget = dom.byId("myTextBox3");
var dibiDOM = registry.byId("textNode3");
var dobiDOM = dom.byId("textNode3");
dom.byId("textNode3").innerHTML = "registry.byId for widget id returned: " + dibiWidget + "<br>" +
"dom.byId for widget id returned: " + dobiWidget + "<br>" +
"registry.byId for dom id returned: " + dibiDOM + "<br>" +
"dom.byId for dom id returned: " + dobiDOM + "<br>";
});
These modules have a different usage. So there is no advantage of using registry.byId() (or dom.byId()) because they differ in use case.
dijit/registry::byId()
The dijit/registry module main use is retrieving widget instances. Quoting the reference guide:
dijit/registry stores a collection of all the dijit widgets within a
page. It is commonly used to retrieve a reference to a widget from a
related piece of data
dojo/dom::byId()
The dojo/dom module on the other hand is just a module to access DOM nodes. Quoting the information of byId() on the reference guide:
This is a simple alias to document.getElementById, which not only is
shorter to write, but fortunately works in all browsers. It turns a
domNode reference to some Node byId, or the same node reference if
passed a domNode.
What does it mean?
The registry.byId() function will return an instance of your widget. This contains setters/getters and other stuff from the widget. This module should only be used to retrieve widgets, you cannot get a DOM node with it.
The dom.byId() function on the other hand will return the matching DOM node. You can only use it to retrieve a DOM node. A widget obviously also contains DOM nodes, but you should never directly access the DOM nodes of a widget because they're part of the internal structure of the widget (and may change).
When accessing a widget, always use registry.byId(). It provides APIs to access most DOM properties anyways.
Your code
So, your code demonstrates the 4 possibilities here. Assuming #myTextBox3 is a widget (for example of type dijit/form/TextBox) and #textNode3 is a DOM node, the following will happen:
dibiWidget will work because #myTextBox3 is a widget. It will return a reference to that widget
dobiWidget will probably work, because there is a DOM node behind every widget with the same ID (not required though). However, like I just explained, it's not recommended to use it.
dibiDom will not work because there is no widget with ID #textNode3. This is just a simple DOM node.
dobiDom will return a reference to the DOM node and will work.
I also made a small JSFiddle to demonstrate this.
dom.byId() is just short for document.getElementById(...). It returns a reference to the dom node.
registry.byId(...) returns a reference to a dojo widget that is contained in dojo's registry.
For example if you have <div id='myDiv'></div>, You can't call registry.byId('myDiv') here because it isn't a dojo widget (thus isn't in the dojo registry). You can call dom.byId('myDiv').
Now if you had <div id='myDiv' data-dojo-type='dijit/layout/ContentPane'></div>, You can call both dom.byId('myDiv') and registry.byId('myDiv'). One gets you the dom node and the other gets you the dojo widget. Both will have different methods available to them but I generally favor registry.byId(...) if there is an overlap.
There isn't an advantage to using one or the other because they are both different things and used for different things.
https://dojotoolkit.org/reference-guide/1.9/dijit/registry.html
http://dojotoolkit.org/reference-guide/1.9/dojo/dom.html