Testing a vuetify on rails project with capybara selenium - ruby-on-rails

I often use this site but it had never happened to me to ask a question. Now I am blocked and so it is time to ask the first one.
I need to test a sign up form created with vue 2 and vuetify, server side rendered with ruby on rails, webpack 5.
I configured capybara with selenium chrome headless driver, it works when it comes to interacting with text fields and buttons but when I try to check the checkbox:
(byebug) check('Accept')
*** Capybara::ElementNotFound Exception: Unable to find visible checkbox "Accept" that is not disabled
Vuetify hides the input and replaces it with beautiful div but, what is the best approach to check a v-checkbox?
Signup form
If I add the visible attribute, the input is found but nothing happens. I think I need to interact with some other element?
(byebug) check('Accept', visible: false)
#<Capybara::Node::Element tag="input" path="/HTML/BODY[1]/DIV[1]/DIV[1]/DIV[1]/MAIN[1]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/FORM[1]/DIV[2]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/INPUT[1]">
I also tried this but still nothing happen:
(byebug) page.find('input[type=checkbox]', visible: false).set(true)
#<Capybara::Node::Element tag="input" path="/HTML/BODY[1]/DIV[1]/DIV[1]/DIV[1]/MAIN[1]/DIV[1]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/FORM[1]/DIV[2]/DIV[2]/DIV[1]/DIV[1]/DIV[1]/INPUT[1]">
So I also tried the click way but getting this error:
(byebug) page.find('input[type=checkbox]', visible: false).click
*** Selenium::WebDriver::Error::ElementClickInterceptedError Exception: element click intercepted: Element <input aria-checked="false" id="input-96" role="checkbox" type="checkbox" value=""> is not clickable at point (234, 531). Other element would receive the click: <div class="v-input--selection-controls__ripple"></div>
(Session info: headless chrome=85.0.4183.121)
I tried also executing the raw script:
page.execute_script("window.uiApp.$data.terms_and_conditions = true")
The vue app is mounted in this way:
window.uiApp = new Vue({
i18n,
vuetify,
store,
router,
el: id,
render: h => h(App, {
props
})
})
But window.uiApp.$data is empty, so this attempt also seems to fail :( How to access vue component data (without vue web tool)?
I don't know what else to try, thanks in advance

Looking at the HTML shown in your linked image (in the future when asking questions it would be helpful if you included the relevant HTML directly in your question) it looks like you have a label associated with the hidden checkbox that the user can click. In that case you can use
check('Accept', allow_label_click: true)
which, when the actual checkbox is hidden, will click on the associated label instead. If you want that behavior to be on by default you can set Capybara.automatic_label_click = true.
Your other option is to determine exactly which element is actually being shown as the 'checkbox' and use find(...).click to locate that element and click on it.

I changed the checkbox in this way:
<v-checkbox v-model="terms_and_conditions"
#input='$v.terms_and_conditions.$touch()'
#blur='$v.terms_and_conditions.$touch()'
:label="$t('commons.accept')">
</v-checkbox>
<div class="ml-2">
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<a
target="_blank"
href="/users/terms_and_conditions"
#click.stop
v-on="on"
>
{{ $t('session.sign_up.terms') }}
</a>
</template>
{{ $t('session.sign_up.terms_hint') }}
</v-tooltip>
</div>
Thank you

Related

Node Red textarea with template node" No msg.payload input possible after changing content of textarea"

The attached Node Red Flow with the attached HTML and Javascript Code is working as follows:
msg.payload sending from the buttons is displayed in the textarea and can also be send out correct to the debug node
I also can change the content of the textarea and then send out correct to the debug node
But after I have changed the content of the textarea, all further msg.payload inputs from the Buttons are ignored until I make re deployment of Node Red.
<textarea name="textentered" id="textentered" rows="8" cols="25">{{msg.payload}}</textarea>
<input type="submit" value="Save Comments" ng-click="send({payload:test()})">
<script>
(function(scope) {
scope.test = function() {
var text = document.getElementById("textentered").value;
alert(text);
return "E:"+text;
}
})(scope)
</script>
I have made several modification but never could fix this problem. So I hope somebody in this community can help me.
I now alone have found the solution. Problem: HTML code for Dashboard already had the new msg.payload, but Dashboard was not refreshed.
With Dashboard refresh nodes at each msg.input it works fine !!!
New Node Red Flow

Playwright: Two elements with the same name, how to fill the one that is visible?

I have an Ionic React app that uses react-router 5 to display various pages.
The app defaults to a login form, but if users go to the support page, there is a contact form.
I'm trying to test the contact form in Playwright with code like this:
await page.fill('input[name=mail]', 'playwright#example.com');
However, I'm getting an error:
=========================== logs ===========================
waiting for selector "input[name=mail]"
selector resolved to 2 elements. Proceeding with the first one.
selector resolved to hidden <input name="mail" type="email" placeholder="" autocorr…/>
elementHandle.fill("playwright#example.com")
waiting for element to be visible, enabled and editable
element is not visible - waiting...
The problem is that Playwright is seeing the first email address input on the login form, which is not visible, and then trying to fill that in instead of the visible email address input on the contact page.
Obviously, I never want to fill in an element that isn't visible, so how can I force playwright to only try to fill in visible elements?
You can use page.locator to check for visibility first and then fill in the value.
await page.locator('input[name=mail] >> visible=true').fill('playwright#example.com');
To make tests easier to write, wrap this in a helper function:
async fillFormElement(
inputType: 'input' | 'textarea',
name: string,
value: string,
) {
await this.page
.locator(`${inputType}[name=${name}] >> visible=true`)
.fill(value);
}
It can be done in this way, if you are trying to check is element visible. Even you have two same elements with one selector one hidden one visible.
const element = await page.waitForSelector(selector, {state:visible});
await element.fill(yourString);

I got jquery-ui sortable working with meteor templates, but is it a bad hack?

I'm trying to use jquery-ui sortable with nested templates in Meteor, as follows. Here are the two templates in question:
<template name="activityEditor">
{{! the main activity editor view }}
<div class="activity-editor">
<input type="text" name="title" class="input-xxlarge" value="{{info.title}}" placeholder="Type a title here...">
<div class="activity-steps">
{{#each info.steps}}
{{>activityStepEditor}}
{{/each}}
</div>
</div>
</template>
<template name="activityStepEditor">
{{! the container view for each step editor }}
<div class="activity-step" data-id="{{_id}}">
<div class="order">{{order}}</div>
{{!....stuff...}}
</div>
</template>
and the template code (using coffeescript):
_.extend Template.activityEditor, {
# ...stuff...
rendered: ->
$(".activity-steps").sortable {
items: '.activity-step'
handle: '.order'
update: ->
stepIds = ($(el).attr('data-id') for el in $('.activity-step'))
$('.activity-steps').empty() #this must be done in order to steps to re-render properly
Lab.Activity.reorderSteps stepIds
}
$(".activity-steps").disableSelection()
}
The only way I can get this code to work and properly rerender the order is by emptying the container of my sortable elements right after they update with $('.activity-steps').empty(). I've tried cancelling the update event and forcing a rerender by changing another variable watched in the context, but any change causes Exception from Meteor.flush(): undefined after which I can't rerender anything until page reload.
This seems to work, and everything rerenders great. So my question is: is there any reason why I shouldn't do this? Is there a better, standard practice way to handle the sortable that I'm not seeing?
In the near future there'll be a better way to do it, as Meteor team is developing its new rendering engine: http://youtube.com/watch?v=ISNEhPG0wnA
(in this video, Avital Oliver shows exactly a way to do it without redrawing the screen: the object in the list is actually moved on all clients)
See this Meteor's Github Wiki entry for more technical info:
http://github.com/meteor/meteor/wiki/New-Template-Engine-Preview
While that's not officially published, if you need it right now, you could try Nazar Leush's approach:
http://github.com/nleush/meteor-todos-sortable-animation
He also published a working example here: http://todos-dnd-animated.meteor.com

Configure xforms:select element for 'view' mode

I have next problem, when user looks to the filled form element xforms:select shown as it should be readonly and displays the label of selected item, below is html represenation of the element as it comes to browser
...
<span
id="control-8-control"
class="xforms-control xforms-select xforms-incremental xforms-select-appearance-full xforms-static xforms-readonly"
>
some value1
</span>
...
, but when user clicks on the text "some value", this texts turns to value of selected item, and looks next way
...
<span
id="control-8-control"
class="xforms-control xforms-select xforms-incremental xforms-select-appearance-full xforms-static xforms-readonly"
>
2WPbzcoW3eoH/1rDCyejaA==
</span>
...
Obviously some listener is hanging on that element, and changes it's inner-html.
Moreover this behavior can be observed only for xforms:select elements with appearance="full"
Where can I reconfigure this element behavior?
This is a bug. I didn't reproduce exactly the same problem you had, as I have been testing this on a nightly build, but most likely, the source of the problem is the same: the client sends a value change to the server when you click on the label, while it shouldn't. I fixed this, and the fix will be in the next nightly build. For reference, this is the bug and commit.

Trying to understand - HTML replacements and scripts having access to replaced elements on the page

I have a page with a ticket list. In it, there is a <td> that is either a grab or release link. That link inside the '' is wrapped in a '' for an ajax html replacement. Like:
<td>
<div id="ticket_grab_release_<%= ticket.id %>">
*---- either a grab or release link here ----*
<div>
</td>
So, the user clicks on 'grab': They are assigned the ticket, the worklist is updated with their info on the page via HTML replacements, and the grab link is replaced with a 'release' link.
Next to this is a 'complete' link. When the user clicks on that, a small complete form opens in a jQuery UI-Dialog window. I ran into a problem though because along with the grab/replace link changing I also had to toggle this 'complete' link with a grey non-link 'complete' or an actual 'complete' link (if ticket released - disable complete link or visa versa).
The problem is that if this 'complete' link was greyed out and I replaced that with a 'complete' link, the UI Dialog window would not open. Like (no idea what I'm saying) the link wasn't in the DOM.
I got frustrated for a bit and then tried wrapping the script in a <div> and doing an html page replacement on the whole script. I HTML replaced the greyed out 'complete' with a 'complete' link and then HTML replaced the script right after. Interestingly that worked, but I'm really curious as to why it worked. When you ajax insert a script through an HTML replacement, does that inserted script have access to the modified DOM where the original script only has access to the what was the original DOM from the page load?
<div id="html_replace_sript">
<script type="text/javascript">
$('.complete_ticket_link' ).click(function(){
var url = $(this).attr("href");
$("#form_load").load(url,
function() {
$(this).dialog({
modal:true,
draggable: true,
resizable: false,
width:'auto',
height:'auto',
title: ' Complete Ticket ',
position: [125, 50]
});
});
return false;
});
</script>
</div>
Thanks - much apprecaited!
Check out live()'s much less recource-demanding counterpart: delegate()
Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.
That means that instead of having to look through the entire window for an element, it starts at the specified root, significantly reducing overhead. This is the best solution for your issue.
The answer is YES.
But if you want to bind events to elements that match the selector now and in the future, you can use .live()
So you'd do:
$('.complete_ticket_link' ).live('click' function(){
...
});
Using this, your code can be on your main page and it will work.
Hope this helps. Cheers

Resources