Rails Capybara not detecting vivsiblity of flex item - ruby-on-rails

I am doing display: flex an element on button click and then display: none to the same element after some ajax calls. I am doing the integration testing for the same using Capybara with Selenium driver. The problem is that capybara detects the visibility of the element and sometimes it does not even though the element is visible. I have tried giving different wait values but still it works sometimes and sometimes it does not. Is there anyway I can rectify this? The code is as below:
ele.addEventListener('change', () => {
showSpinner(true);
ajaxCall().then(() => showSpinner(false));
}
showSpinner = (flag) => {
let spinner = document.getElementById('spinner');
if (!spinner) {
return;
} else if (flag) {
spinner.classList.add('show');
} else {
spinner.classList.remove('show');
}
};
.spinner.show {
display: flex;
}
.spinner {
display: none;
// other properties
}
In test file
choose 'radio_button' // if radio button
select 'some text', from: 'dropdown_element' // if dropdown
assert page.has_css?('.spinner', wait: 0)
This works sometimes and sometimes it does not. The element is selected or clicked. That works. But not has_css. Also I tried using assert_css but I am getting error. So how can I write the testcase for the above problem?

I solved the problem as below. I found the answer from a comment by #Thomas Walpole for this question Check element visibility that is visible for less than a second in Rails Capybara asked by me. The problem was that sometimes the ajax response was very fast and sometimes it was slow. So all I had to was to slow down the network.
// Set the latency time through selenium before the click or select and then check
// for the visibility of the element on page and then again change back the latency
page.driver.browser.network_conditions = { offline: false, latency: 2000, throughput: 789 }
choose 'radio_button' // if radio button
select 'some text', from: 'dropdown_element' // if dropdown
assert page.has_css?('.spinner', wait: 0)
page.driver.browser.network_conditions = { offline: false, latency: 0, throughput: 0 }
// continue with other tests
This worked for my problem. Feel free to improve this solution.

Related

navigator.mediaSession.metadata not updating after page reload

I am currently tying our audio player with mediaSession.
Everything is working as it should, when I hit play and update navigator.mediaSession.metadata, it's properly displayed in the notification on desktop and mobile.
But after I reload the page and hit play, the notification has always default values (website URL as a title and link rel="icon" for the artwork). This only happens after I reload the website. If I close it and open again the notification is working properly again.
Here's how it's done:
//...
initialConfiguration: {
title: 'Initial Title',
artist: 'Initial Artist',
album: '',
artwork: [
{ src: "initial/artwork/url.jpg", sizes: "512x512", type: "image/jpg" },
]
},
currentMetadata: null,
setMediaSessionMetaData: function(){
let self = this;
if ('mediaSession' in navigator) {
if( !self.currentMetadata ){
self.currentMetadata = new MediaMetadata(self.initialConfiguration);
}else{
// Update existing metadata
self.currentMetadata.title = "New Title";
self.currentMetadata.artist = "New Artist";
self.currentMetadata.artwork = [
{ src: "new/artwork/url.jpg", sizes: '512x512', type: "image/jpg" },
];
}
navigator.mediaSession.metadata = self.currentMetadata;
}
},
//...
This function works perfectly fine on first page load, when I hit play for the first time it loads the initialConfiguration and if I call the function again the title and artwork gets updated. But after reload, the notification has always default values ignoring my configuration.
Is there a bug in mediaSession, I didn't find anything regarding this issue on mediaSession github page (https://github.com/w3c/mediasession/issues) and searching this issue gives me zero results.
After Searching for days and not finding anything....
I discovered a workaround. It has to do with the performance.navigation.type when you first open a page it is set to 0 and after a refresh it gets set to 1. I was curious if this had any effect on the mediasession so I figured out how to "Hard Refresh" the page by using window.open(window.location.href, "_self");, because apparently that generates a "Hard Refresh". After that the mediasession works again. so what I did was setup an onload function that checks to see if performance.navigation.type == 1 and if so then do a "Hard Refresh"
window.onload = function() {
if (performance.navigation.type != 0) {
window.open(window.location.href, "_self");
}
};
Now when the user refresh's it will do a "Hard Refresh".
Also make sure to move the window. Onload line to the end of the javascript file or after the initial function

Blank Firefox addon panel page with multiple windows

I've followed MDN's document to create a toggle button addon.
Everything works fine except one problem:
Open a second browser window (cmd+n or ctrl+n) and click on the toggle button there
Click on the toggle button on the original browser window without closing the toggle button on the second window
the toggle button's panel becomes blank with the following error message:
JavaScript error: resource:///modules/WindowsPreviewPerTab.jsm, line 406: NS_ERR
OR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIT
askbarTabPreview.invalidate]
// ./lib/main.js
var { ToggleButton } = require("sdk/ui/button/toggle");
var panels = require("sdk/panel");
var self = require("sdk/self");
var buttonIndex = 0;
var lastKnownButtonIndex = 0;
var button = ToggleButton({
id: "button",
label: "my button",
icon: {
"16": "./icon-16.png"
},
onClick: handleChange,
});
var panel = panels.Panel({
contentURL: self.data.url("menu.html"),
onHide: handleHide
});
function handleChange(state) {
if (state.checked) {
panel.show({
position: button
});
}
}
function handleHide() {
button.state('window', {checked: false});
}
function assignButtonIndex() {
return (buttonIndex++).toString();
}
The complete addon is here: https://goo.gl/9N3jle
To reproduce: Extract the zip file and $ cd testButton; cfx run and follow the above steps.
I really hope someone can help me with this. Thank you in advance!
It's a bug; you're not doing anything wrong. It's a racing condition between the windows' focus events, and the panel's event, that prevent somehow the panel's hidden event to be emitted properly.
You can try to mitigate with a workaround the issue until is properly fixed. I added some explanation in the bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1174425#c2 but in short, you can try to add a setTimeout to delay a bit when the panel is shown, in order to avoid the racing condition with the window's focus. Something like:
const { setTimeout } = require("sdk/timers");
/* ... your code here ... */
function handleChange(state) {
if (state.checked) {
setTimeout(() => panel.show({ position: button }), 100);
}
}
I am currently using a workaround where I dynamically create a new Panel every time the user presses the toolbar button.
It is faster than the 100ms workaround and also handles a scenario where the user outright closes one of the browser windows while the panel is open. (The 100ms workaround fails in this case and a blank panel is still displayed.)
It works like this:
let myPanel = null;
const toolbarButton = ToggleButton({
...,
onChange: function (state) {
if (state.checked) {
createPanel();
}
}
});
function createPanel(){
// Prevent memory leaks
if(myPanel){
myPanel.destroy();
}
// Create a new instance of the panel
myPanel = Panel({
...,
onHide: function(){
// Destroy the panel instead of just hiding it.
myPanel.destroy();
}
});
// Display the panel immediately
myPanel.show();
}

Text input inside jQuery UI sortable doesn't work on touch devices

I made a simple page with some divs being sortable by the jQuery UI Sortable, with a little help from Touch Punch to get it working on an iPad running iOS 7.1.2.
Inside each of these divs, I included a text input tag. On desktop browsers the inputs work fine, but the iPad doesn't recognize the click on the input component. The keyboard isn't launched and I can't type into it. Any lights?
My page is here: https://www.dropbox.com/s/5crp55r9jw98var/sortableTest.zip?dl=0
Well, here's what worked for me.
I edited the jquery.js. On jQuery.Event.prototype, inside the preventDefault function, there is:
if ( e.preventDefault ) {
e.preventDefault();
} else {
e.returnValue = false;
}
Basically, I changed the if condition to e.preventDefault && e.target.tagName != "INPUT". It solved the example, but in the real life I needed to add some more conditions to ensure that other input fields won't get caught by this.
Change in jquery.ui.touch-punch.js worked for me.
JS: jquery.ui.touch-punch.js
Method to modify:
//line: 31
function simulateMouseEvent(event, simulatedType) {
//...
}
//changes to add ++
if ($(event.target).is("input") || $(event.target).is("textarea")) {
return;
} else {
event.preventDefault();
}
I know this is an old question but got the following to work for me without modifying the JS files:
let detectTap = false;
$('body').on('touchstart', '#sortableMenu input', () => {
detectTap = true;
});
$('body').on('touchmove', '#sortableMenu input', () => {
detectTap = false;
});
$('body').on('touchend', '#sortableMenu input', (e) => {
if (detectTap) $(e.target).focus();
});
Basically just adding a tap listener on the inputs, and when it gets the tap, focus on that input.

Show confirm dialog before delete node of jstree

I use jstree and jquery-ui v1.10.1 .I use context menu on tree and i want before delete node show confirm dialog(like jquery-ui dialog).
I use dialog in "before.jstree" event, but when show dialog box, before an option is selected(yes or no) ,the selected node is deleted.
How to solve this problem?
.bind("before.jstree", function(e, data) {
if (data.func === "remove") {
if (!confirmRemove()) {
e.stopImmediatePropagation();
return false;
}
}
}
function confirmRemove() {
return $confirmDialog.dialog('open');
}
I'm using the 2.1.0 version and there is another solution for this functionality.
What you have to do is add a function to the check_callback option.
Like this:
$("#your_tree").jstree({
"core": {
"check_callback": function (operation, node, node_parent, node_position, more) {
// operation can be 'create_node', 'rename_node', 'delete_node', 'move_node', 'copy_node' or 'edit'
// in case of 'rename_node' node_position is filled with the new node name
if (operation === 'delete_node') {
if (!confirmRemove()) {
return false;
}
}
return true;
}
}
I know that this is an old question, but i looked for a more recent question/answer and didn't find it.
Hope it helps to other people that will have the same question :)
The JQuery-UI-Dialog is asynchronous; If you call it, your eventhandler does not stop execution and waits, but goes on and deletes the Node.
Try the JavaScript-Dialog confirm() since this is synchronous and stops further execution until the User confirmed or declined the Dialog.

Back button handler in jQuery Mobile (Android) PhoneGap

Is there any way to handle back button (device backbutton) as default functionality to move back page? I need to implement the same functionality on back button goes to previous page. If there is no previous page (first page) it exit the application. Is this possible in PhoneGap?
I also need to pop page before going to push another page is this posible in jQuery?
Checking window.location.length would be the easiest way to determine if you're on the first page, but this isn't available in Phonegap.
But since you're using JQM, you can either use the navigate event as Omar suggests or could manually count the number of pages shown and the number of pages gone back (same thing) and use this to determine if the first page is being shown and whether to exit the app. Something like this would work:
var pageHistoryCount = 0;
var goingBack = false;
$(document).bind("pageshow", function(e, data) {
if (goingBack) {
goingBack = false;
} else {
pageHistoryCount++;
console.log("Showing page #"+pageHistoryCount);
}
});
function exitApp() {
console.log("Exiting app");
navigator.app.exitApp();
}
function onPressBack(e) {
e.preventDefault();
if(pageHistoryCount > 0) pageHistoryCount--;
if (pageHistoryCount == 0) {
navigator.notification.confirm("Are you sure you want to quit?", function(result){
if(result == 2){
exitApp();
}else{
pageHistoryCount++;
}
}, 'Quit My App', 'Cancel,Ok');
} else {
goingBack = true;
console.log("Going back to page #"+pageHistoryCount);
window.history.back();
}
}
function deviceready() {
$(document).bind('backbutton', onPressBack);
}
$(document).bind('deviceready', deviceready);
As for the second part of your question:
Secondly i need to pop page before going to push another page is this
posible in jquery ?
It's not clear what you're asking here. Do you mean you want to show some kind of popup content like a dialog between every page change? Please clarify then I can help you :-)

Resources