phantomjs global variables call in page.evaluate - phantomjs

I want to know how to use a varaible globally in phantomjs so that it can be used in the page.evaluate function also.
I have gone through some previous answers but but able to understand well

JSON-serializable arguments can be passed to page.evaluate.
Here is a very basic the following example using this technique :
page.open('http://stackoverflow.com/', function(status) {
var title = page.evaluate(function(s) {
return document.querySelector(s).innerText;
}, 'title');
console.log(title);
phantom.exit();
});

Related

cy.clear() not clearing input field properly - Cypress

When I perform
cy.get('#fsp-name').clear().type('random text');
If the text already has value lets say 'assd asd adsdsd' and I perform above command I get something similar to 'random textassd'
I also tried using
cy.get('#fsp-name').clear().should('have.value', '').type('random text');
It works some time and in other times it complains it does not equal to ' '.
And I am trying to do this in a each loop like below
const data = [
{selector:'#name', newValue: 'John'},
{selector:'#phone', newValue: '1234567'}
];
cy.wrap(data).each(field => {
cy.get(field.selector).clear().should('have.value', '').type(field.newValue);
cy.contains('Save').click();
cy.visit('/abc/sdd');
cy.get(field.selector).invoke('val').should('equal', field.newValue);
});
Tried the solutions provided above, but all did not help.
I've ended up using this:
cy.get('#my-input-element').focus().clear();
If that doesn't work, the not so happy workaround is:
cy.get('#my-input-element').invoke('val', '');
When .type somehow did not finish the given string (rare cases):
cy.get('#my-input-element').invoke('val', 'Some text here');
I had a similar problem and It was related to focused and click related. I can suggest trying the following two option. I DON'T know it is right or wrong.
cy.get('#fsp-name').click().clear().type('random text');
OR
cy.get('#fsp-name').click().focused().clear().type('random text');
I was talking to the developer and according to him we are using MaterialUI and have some default component using focused and click event differently. After having both options resolved my problem
.clear() is an alias of .type('{selectall}{backspace}') however depending upon the input field set up this would not work in all cases.
I solved this by using .type('{selectall}{backspace}{selectall}{backspace}') instead of the .clear()
I'm using Cypress version 3.8.3 and I noticed that I have to invoke clear() sometimes two times in a row:
cy.get('#fsp-name').clear();
cy.get('#fsp-name').clear();
Seems like the cypress test runner is getting ahead of app initialization and some helpful article links below
https://www.cypress.io/blog/2018/02/05/when-can-the-test-start/
https://www.cypress.io/blog/2019/01/22/when-can-the-test-click/
As of now adding wait before clearing makes the test pass. Let me know if anyone has better solutions
I've had the same problem using Mui React with Cypress and when I called clear an ";" was added.
I've applied the same #Steven Vachon solution calling clear() function of cypress first.
Here my solution:
const clearInputElement = (input) => {
const input2Search = input;
cy.get(input2Search).clear();
cy.get(input2Search).then(($elm) => {
const event = new Event(input2Search, { bubbles: true, cancelable: true });
const input = $elm.get(0); // `as HTMLInputElement` for TypeScript
input.value = "";
input.dispatchEvent(event);
});
};
I ended up having to do clear manually via the DOM:
cy.get('input').then($elm => {
const event = new Event('input', { bubbles: true, cancelable: true });
const input = $elm.get(0); // `as HTMLInputElement` for TypeScript
input.value = '';
input.dispatchEvent(event);
});
I, too, faced a similar issue while using with react-ace editor. I wind up with
function typeContentOnSelectingExistingContent(elementId, content) {
return cy.get(`#${elementId}`).type(`{selectAll}{selectAll}${content}`)
}
Try this, it worked for me:
cy.get('#fsp-name').clear({ force: true }).then(() => {
cy.wait(3000)
cy.get('#fsp-name').invoke('val', '').type(`${valueToBeTyped}{enter}`)
})
Official docs states that:
It is unsafe to chain further commands that rely on the subject after .clear().
That's probably why the code in the original question didn't work, it was chaining clear and type commands:
cy.get('#fsp-name').clear().type('random text');
So, a simple alternative would be something like:
cy.get('#fsp-name').clear()
cy.get('#fsp-name').type('some text')
More about the clear command:
https://docs.cypress.io/api/commands/clear

Protractor how to wait until browser.get to a url

await browser.wait(function() {
return browser.getCurrentUrl().then(function(url) {
return `cars/detail.aspx${browser.baseUrl}`;
});
}, 5000, "url err");
How do I make protractor wait until cars/detail.aspx${browser.baseUrl} is loaded?
I think you can use the urlContains expected condition in protractor to wait until the url contains something specific. You can refer to the documentation here.
I'm using this method, maybe it will be helpful
export function waitForUrlContains(url: string, customTimeout: number = E2E_TIMEOUT) {
return browser.getCurrentUrl().then(myUrl => {
return browser.wait(protractor.ExpectedConditions.urlContains(url), customTimeout, `URL do not contain: ${url}, and is: ${myUrl}`);
});
}
You can read the Protractor's API documentation for further information on different ways of waiting for an element (url in this case) https://www.protractortest.org/#/api
You have 2 ways actually:
const EC = protractor.ExpectedConditions;
const myUrl = 'cars/detail.aspx${browser.baseUrl}';
then:
return browser.wait(EC.urlIs(myUrl));
OR
return browser.wait(EC.urlContains(myUrl));

dojo JsonRest call not working

I'm trying to call my RESTful service from dojo. All I can see from debugger is, it tries to call the service but it doen't reach there. There are no errors. I can see the 'hello' alert.
define(["dojo/store/JsonRest","dojo/domReady!"],
function(JsonRest){
alert("Hello");
var rest = new JsonRest({
target: "/my/rest/call"
});
}
);
I's following this page from dojotoolkit.
But if i call using a declare then it works.
define(["dojo/store/JsonRest","dojo/_base/declare","dojo/domReady!"],
function(JsonRest, declare){
var rest = declare(JsonRest);
var restResult = new rest({
target: "/my/rest/call"
});
}
);
What am I doing wrong here?
error messages in console:
You're not following that tutorial to the letter. The difference is that you're using define and not require. Dojo's define is used in combination with declare to create new Dojo classes. Dojo's require is used to load and use existing classes. The link below is a recommended read and in your case pay special attention to the 'Requiring modules' and 'Defining modules' parts:
https://dojotoolkit.org/documentation/tutorials/1.8/modules/
If you use require like in that tutorial, it works perfectly:
require([
'dojo/store/JsonRest',
], function(
JsonRest
) {
new JsonRest({
target: 'some/resource/'
}).get(1).then(function (item) {
alert(JSON.stringify(item));
});
});
Here's a working example on Plunker: http://plnkr.co/edit/ZhsO67BFpWB5Txqy0Zl9?p=preview

Passing variable into page.evaluate - PhantomJS

Is it possible to pass variables in a page.evaluate in my case below?
function myFunction(webpage, arg1, arg2){
var page = require('webpage').create();
page.viewportSize = { width: 1920, height: 1080 };
page.open(webpage, function (status){
if (status == 'success') {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js", function(){
page.evaluate(function(){
arg = arg1 + arg2;
console.log(arg);
});
});
}
else { phantom.exit(); }
});
}
I tried several methods found on the internet but nothing actually impossible to get to its variables.
Thank you in advance for your help :)
As usual, the answer is clearly stated in the documentation of evaluate function:
As of PhantomJS 1.6, JSON-serializable arguments can be passed to the function. In the following example, the text value of a DOM element is extracted. The following example achieves the same end goal as the previous example but the element is chosen based on a selector which is passed to the evaluate call:
The example that follows demonstrates the usage:
var title = page.evaluate(function(s) {
return document.querySelector(s).innerText;
}, 'title');
console.log(title);
I have phantomjs 1.5.0, so instead of compiling 1.6 or higher version I went for an alternative solution:
So I've saved arguments to selectors.js file
-------------selectors.js starts----------------
var selectors = "div.nice"
-------------selectors.js ends----------------
and then injected them into the page:
page.injectJs("selectors.js");
More details can be found here: http://phantomjs.org/api/webpage/method/inject-js.html
I use phantom 4.0.4, below works for me, https://www.npmjs.com/package/phantom
var arg = 'test'
page.evaluate(function(arg) {
console.log(arg)
}, arg);

Testing model binding in Backbone JS with Jasmine

I have a view that contains a model. The view listens for an event from the model and will perform an action once the event is triggered. Below is my code
window.Category = Backbone.Model.extend({})
window.notesDialog = Backbone.View.extend({
initialize: function() {
this.model.bind("notesFetched", this.showNotes, this);
},
showNotes: function(notes) {
//do stuffs here
}
})
I want to test this using Jasmine and below is my test (which doesn't work)
it("should show notes", function() {
var category = new Category;
var notes_dialog = new NotesDialog({model: category})
spyOn(notes_dialog, "showNotes");
category.trigger("notesFetched", "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
})
Does anyone know why the above test doesn't work? The error I get is "Expected spy showNotes to have been called with [ '[]' ] but it was never called."
I was doing something similar where I had a view, but I couldn't get the spy to work properly unless I added it to the prototype, and before I created the instance of the view.
Here's what eventually worked for me:
view.js
view = Backbone.View.extend({
initialize: function(){
this.collection.bind("change", this.onChange, this);
},
...
onChange: function(){
console.log("Called...");
}
});
jasmine_spec.js
describe("Test Event", function(){
it("Should spy on change event", function(){
var spy = spyOn(view.prototype, 'onChange').andCallThrough()
var v = new view( {collection: some_collection });
// Trigger the change event
some_collection.set();
expect(spy).toHaveBeenCalled()
});
});
I would test initially with the toHaveBeenCalled() expectation and change to the toHaveBeenCalledWith() after you get that working...
Update 5/6/2013: Changed update() to set()
Try to amend your existing test code as follows:
it("should show notes", function() {
var category = new Category;
spyOn(NotesDialog.prototype, "showNotes");
var notes_dialog = new NotesDialog({model: category})
category.trigger("notesFetched", "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
})
In your original code, the instance of the method you are calling is one defined in the bind closure, whereas the one you are spying on is in the notes_dialog instance. By moving the spy to the prototype, you are replacing it before the bind takes place, and therefore the bind closure encapsulates the spy, not the original method.
Using a spy means to replace the function you spying on. So in your case you replace the bind function with the spy, so the internal logic of the original spy will not call anymore. And thats the right way to go cause you dont wanna test that Backbones bind is work but that you have called bind with the specific paramaters "notesFetched", this.showNotes, this.
So how to test this. As you know every spy has the toHaveBeenCalledWith(arguments) method. In your case it should looks like this:
expect(category.bind).toHaveBeenCalledWith("notesFetched", category. showNotes, showNotes)
So how to test that trigger the "notesFetched" on the model will call your showNotes function.
Every spy saves the all parameters he was called with. You can access the last one with mostRecentCall.args.
category.bind.mostRecentCall.args[1].call(category.bind.mostRecentCall.args[2], "[]");
expect(notes_dialog.showNotes).toHaveBeenCalledWith("[]");
mostRecentCall.args[1] is the the second argument in your bind call (this.showNotes). mostRecentCall.args[2] is the the third argument in your bind call (this).
As we have test that bind was called with your public method showNotes, you can also call the your public method showNotes directly, but sometimes the passed arguments can access from outside so you will use the shown way.
Your code looks fine, except do you have the test wrapped in a describe function, as well as an it function?
describe("show notes", function(){
it("should show notes", function(){
// ... everything you already have here
});
});
Total guess at this point, but since you're not showing the describe function that's all I can think it would be. You must have a describe block for the tests to work, if you don't have one.
You are pretty close ;)
spyOn replaces the function with your spy and returns you the spy.
So if you do:
var dialog_spy = spyOn(notes_dialog, "showNotes");
category.trigger("notesFetched", "[]");
expect(dialog_spy).toHaveBeenCalledWith("[]");
should work just fine!