I want to run a function (to render flash messages) after a backbone.navigate call. Is it possible? I currently hooked into the all event and check if eventname starts with "route:". But that triggers too early, before my messages are added... so I was thinking of running after the route completes
# intercept all router navigate and render flash messages if any
renderFlashMessengesOnNavigate = (evt) =>
if evt.indexOf("route:") is 0
console.log "rendering messages after route ..."
#flashMessenger.render()
window.appRouter.bind "all", renderFlashMessengesOnNavigate
window.authRouter.bind "all", renderFlashMessengesOnNavigate
window.userRouter.bind "all", renderFlashMessengesOnNavigate
Try this:
var originalNavigate = Backbone.history.navigate;
Backbone.history.navigate = function(fragment, options){
originalNavigate.apply(this, arguments);
//your code here
}
Related
After updating testinglibrary/userEvent from version 13 to 14, it is not waiting for dynamically rendered.
My dialog is lazily loaded as well as the content inside the dialog.
An example code is below.
it('updates the channel information after edit channel request succeeds', async () => {
render();
await userEvent.click(await screen.findByTestId('TestId'));
const myDialog = await screen.findByRole('dialog');
// This is problematic.
const nameField = within(myDialog).getByLabelText(/name/i);
})
Dialog shows spinner until it finishes fully loading the content.
And the content will be rendered as long as query waits. But it doesn't wait for the content to be rendered but quits waiting as soon as it finds the spinner, saying it couldn't find the content but only spinner.
What I tried
Using find query instead of get, some tests are resolved only doing this but others aren't.
Using screen instead of within(dialog).findBy. This resolves some breaking test as well.
I looked over the document and changelog if there were effective change that possibly breaks the test code, but had no luck :(
What should I do with it?
This might be because you haven't ran setup yet. userEvent's API have changed in 14, and now, per the documentation:
We recommend invoking userEvent.setup() before the component is rendered.
So in your case, you need to try something like this.
it('updates the channel information after edit channel request succeeds', async () => {
const user = userEvent.setup()
render();
await user.click(await screen.findByTestId('TestId'));
const myDialog = await screen.findByRole('dialog');
// This is problematic.
const nameField = within(myDialog).getByLabelText(/name/i);
})
I am working on a project which produces a Chrome extension. In a background page I have a function named checkingProcess. This function is executed when a new tab is opened or a tab is updated. (I tried to catch the change of URL here.)
chrome.tabs.onActivated.addListener((activeInfo) => {
checkingProcess(activeInfo.tabId)
})
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
checkingProcess(tab.id)
})
Then, in the checkingProcess function, I have some functions for the data handling and API calls. Then I tried to receive a message that comes from popup. This message represents that the popup was opened by the user.
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.msg === 'popup_opened') {
sendResponse({
matches_length: response['matches'].length,
hostname: host,
})
}
chrome.runtime.lastError
})
After that, it sends a response to the popup. In the popup, I listen to the message and use the response in the popup.
useEffect(() => {
chrome.runtime.sendMessage({ msg: 'popup_opened' }, (res) => {
setHostname(res['hostname'])
setMatchesLength(res['matches_length'])
console.log(res['hostname'], 'burası')
console.log(res['matches_length'], 'burası')
})
}, [])
However, I realize that this message process is only executed once, but I need to run it multiple times to access the data in background simultaneously. How can I do that?
Your message is only sent once because it's currently setup in a React.useEffect with an empty list of dependencies. This means this code will only be run once when your component is mounted. If you want to run it "multiple times" you first need to define what this means? Examples are:
Executing sendMessage after a user performs some action, like clicking a button. In that case you don't need useEffect. Instead, wire an event handler to that button and perform the sendMessage there.
Executing sendMessage after re-render of your component. Simply remove the empty list of dependencies ([]) from your useEffect method. Note: use this with caution. If you setup your component in a way that it re-renders often, this can quickly turn into a situation where many API calls are made.
Executing sendMessage after some state within your component changes. Add this variable to the list of dependencies: [loaded]
Executing sendMessage every 10 seconds. You'll want to use setInterval within your useEffect, like this:
useEffect(() => {
const interval = setInterval(() => {
chrome.runtime.sendMessage({ msg: 'popup_opened' }, (res) => {
setHostname(res['hostname'])
setMatchesLength(res['matches_length'])
console.log(res['hostname'], 'burası')
console.log(res['matches_length'], 'burası')
})
}, 10000);
return () => clearInterval(interval);
}, []);
I'm trying to create a plugin for Figma, which has been going fine until now. It's based on the react example they provide on their github page: https://github.com/figma/plugin-samples/tree/master/react
In this example I've created a button, that on click will call this function:
(file: ui.tsx)
onClick = () => {
parent.postMessage({pluginMessage: {type: 'GetData'}}, '*');
};
This is parent.postMessage is a function figma provides to communicate with another file in the project, code.ts. This file will receive the postMessage with the pluginMessage as parameter, which works as expected. The code.ts that receives this looks like this:
(file: code.ts)
figma.ui.onmessage = msg => {
if (msg.type === 'GetData') {
figma.ui.postMessage({"title": figma.currentPage.selection[0].name});
}
};
This file receives the message, and it gets in the if statement since GetData has been set. Up until here, everything is good and well. The issue I'm walking into is the figma.ui.postMessage({}), which should do a callback to the onmessage function in ui.tsx:
(file: ui.tsx)
onmessage = (selection) => {
console.log(selection);
};
This onmessage function should, according to Figma's documentation, receive the object from the postMessage in code.ts. This does however never happen; it will never be called at all. I can't access the current selection in ui.tsx, so I need data from code.ts. Is there any way to pass this data to ui.tsx, or does anyone know why this doesn't work?
I encountered the same issue. Within your ui.tsx file, try adding the following:
window.onmessage = selection => {
let message = selection.data.pluginMessage;
console.log(message);
}
or try this ->
window.addEventListener("message", (selection) => {
console.log(selection);
});
this will add another message event handler to the window. if you use onmessage it might overwrite the previous handler!
put first of script
onmessage = event => {
console.log("got this from the plugin code", event, event.data.pluginMessage)
}
I'm creating a chatboard and I'm using signalR to let users know when new comment is added on some status/post.
I'm using React and I've tried to add event listeners for the hub function in different components, in some components it works, not others.
This is the hub:
public class CommentHub : Hub
{
public void UpdateComments(int postId)
{
try
{
var context = GlobalHost.ConnectionManager.GetHubContext<CommentHub>();
context.Clients.All.updateNewComments(postId);
}
catch (Exception ex)
{
Log.Error(ex.Message);
}
}
}
I call the event listener in the componentDidMound function:
componentDidMount: function() {
this.commentUpdateListener();
},
And this is the event listener:
commentUpdateListener: function () {
console.log("in the comment update listener!");
var commentHub = $.connection.commentHub;
commentHub.client.updateNewComments = function (postId) {
console.log("updateNewComments called!");
};
$.connection.hub.start();
},
I have a react component for a post/status, a component for the "wall/newsfeed" and then I have a component for the "comment box" for each status on the wall, where the comments are rendered.
When I place the event listener in the wall component or the post component it works, and the 'updateNewComponent' function gets called, but not when I place it in the "comment box" component.
Still "in the comment update listener!" gets logged no matter where I place the event listener, but the hub function is not always called, and it seems to matter in what react component the event listener is placed.
Is the $.connection.commentHub not staying alive? Is it closing?
Is there some reason the function is not always being called?
You can enable logging before starting the hub connection like this :
$.connection.hub.logging = true;
$.connection.hub.start();
If you see some disconnections you can try to restart the connection when it closes :
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
Further reading : Understanding and Handling Connection Lifetime Events in SignalR
I have a test that clicks a button and redirects to a user dashboard. When this happens Webdriver returns:
javascript error: document unloaded while waiting for result.
To fix this I insert browser.sleep(2000) at the point where redirection occurs and assuming my CPU usage is low, this solves the issue. However, 2000 ms is arbitrary and slow. Is there something like browser.waitForAngular() that will wait for the angular to load on the redirected page before the expect(..)?
it('should create a new user', () => {
$signUp.click();
$email.sendKeys((new Date().getTime()) + '#.com');
$password.sendKeys('12345');
$submit.click();
browser.sleep(2000); // Need alternative to sleep...
// This doesn't do it...
// browser.sleep(1);
// browser.waitForAngular();
$body.evaluate('user')
.then((user) => {
expect(user).toBe(true);
});
});
do you think something like this could work for you? This will wait up to 10 seconds for the url to include the text 'pageTwo', or whatever you put in.
var nextPageButton = $('#nextPage');
nextPageButton.click().then(function(){
return browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
return /pageTwo/.test(url);
});
}, 10000);
};
Just stick in the regex of the url you are expecting.
Alternatively, you could wait for an element from the next page to appear as well:
var nextPageButton = $('#nextPage');
nextPageButton.click();
var elementFromSecondPage = $('#coolElement');
browser.wait(protractor.until.elementIsVisible(elementFromSecondPage), 5000, 'Error: Element did not display within 5 seconds');
When using .click, protractor will naturally wait for angular to finish the action attached to the click, such as changing the page. But, while the page change, you may still be needing something specific to be loaded, so the test fails before that part is available. Using this, it should wait for the click part to finish, then wait for the element to appear.
To expand on user2020347's answer:
Thanks that solved my issue. I wonder why this isn't a built in function. I'll be using this in many places to wait for browser navigation.
To make it more concise, I made a little helper:
Object.assign(global, {
waitUntilURLContains: string => {
let fn = () => {
return browser.driver.wait(() => {
return browser.driver.getCurrentUrl().then((url) => {
return url.includes(string);
});
}, waitDelay);
}
return fn.bind(null, string);
}
});
In my test:
$button.click().then(waitUntilURLContains('dashboard'));
keeping it very simple. I was also running into the same problem but was able to solve it using the following code :
page.setUsername(objectrepository.userdetails.useremail);
page.setPassword(objectrepository.userdetails.userpassword);
page.login().click();
**browser.wait(EC.visibilityOf(page.greetingMessageElement()), 5000);**
page.greetingMessageElement().getText()
.then(function (value){
expect(browser.getCurrentUrl()).toContain("#/mytickets");
});