Jasmine mock window.location.reload(true); - jasmine

I have a constructor of a js object that looks like this:
function SomeThing(window, document) {
var self = this;
self.window = window;
self.document = document;
if (!self.window.sessionStorage.getItem('page-reloaded')) {
self.window.sessionStorage.setItem('page-reloaded', true);
self.window.location.reload(true); // PROBLEM ON THIS LINE
return;
}
}
my mock test looks like this:
beforeEach(function() {
mockWindowObj = {
'location': {
'href': '',
'search': '?hello=world',
'pathname': '/some/path',
'replace': function () {},
'reload': jasmine.createSpy()
}
};
spyOn(mockWindowObj.location, 'reload').and.callFake(function(){}); ;
some = new SomeThing(mockWindowObj, mockDocumentObj);
});
When I run a test I get this error:
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
{
"message": "Some of your tests did a full page reload!",
"str": "Some of your tests did a full page reload!"
}
If I comment out the line window.location.reload(true) all of my test run fine and pass. I'm sort of new to unit tests and I'm not sure how to get around this. Any help would be very much appreciated. Thanks in advance.

Your posted code cannot be what you actually ran. The line containing self.window.sessionStorage.getItem would have to fail since you did not define sessionStorage on your mock.
I guess the SomeThing function is being called with window pointing to the real window object. That explains what you observe.

Related

How do I fix a "browser.elements is not a function" error in Nightwatch.js?

I'm trying to use page objects in Nightwatch js and am creating my own commands in that. For some reason now Nightwatch doesn't seem to recognise standard commands on browser and give me a type error on different commands. What am I doing wrong with my code?
I'm tried different things here already, for example adding 'this' or 'browser' in front of the command, which didn't help. My code has gone through many versions already I am not even sure anymore what all I've tried after Googling the error.
My pageObject:
const homePageCommands = {
deleteAllListItems: function (browser) {
browser
.elements('css selector', '#mytodos img', function (res) {
res.value.forEach(elementObject => {
browser.elementIdClick(elementObject.ELEMENT);
});
})
.api.pause(1000)
return this;
}
};
module.exports = {
url: "http://www.todolistme.net"
},
elements: {
myTodoList: {
selector: '#mytodos'
},
deleteItemButton: {
selector: 'img'
}
},
commands: [homePageCommands]
};
My test:
require('../nightwatch.conf.js');
module.exports = {
'Validate all todo list items can be removed' : function(browser) {
const homePage = browser.page.homePage();
homePage.navigate()
.deleteAllListItems(homePage)
// I have not continued the test yet because of the error
// Should assert that there are no list items left
}
};
Expected behaviour of the custom command is to iterate over the element and click on it.
Actual result:
TypeError: browser.elements is not a function
at Page.deleteAllListItems (/pageObjects/homePage.js:18:14)
at Object.Validate all todo list items can be removed (/specs/addToList.js:8:14)
at processTicksAndRejections (internal/process/next_tick.js:81:5)
And also:
Error while running .navigateTo() protocol action: invalid session id
Looks like you need to pass browser to the deleteAllListItems function instead of homePage on this line:
homePage.navigate()
.deleteAllListItems(homePage)

How can I test that an element does not exist on the page with Protractor?

I am trying to test if an element is not present on a page.
I have tried using the following method, but I get an error each time:
Method:
expect(element(CastModule.PersonXpath).isDisplayed()).toEqual(false);
Error: Failed: Timed out waiting for Protractor to synchronize with the page after
seconds. Please see https://github.com/angular/protractor/blob/master/docs/f ...
What method do you recommend?
The error should not be related to the checking for the absence of an element. Try the following:
var elm = element(CastModule.PersonXpath);
expect(browser.isElementPresent(elm)).toBe(false);
See also:
In protractor, browser.isElementPresent vs element.isPresent vs element.isElementPresent
Yeah, testing for NOT visible can be sucky. You should be able to use isPresent(), which means in the dom, where isDisplayed() means it's actually visible, which I'm thinking is your issue. Try...
expect(element(CastModule.PersonXpath).isPresent()).toEqual(false);
You may also want to break this out into a method and use an Expected Condition.
The error doesn't look like it's to do with the element being displayed. It looks like it's to do with page synchronization. Try ignoring the sync, then waiting for angular above the expect with:
browser.ignoreSynchronization = true;
browser.waitForAngular();
expect(element(CastModule.PersonXpath).isDisplayed()).toEqual(false);
To check for visibility (in case isDisplayed or isPresent isn't working), just use:
if (!EC.invisibilityOf(ug.personXpath)) {
throw new Error("Partner logo is not displayed");
}
I managed to find out a solution, using the protractor library.
var EC = protractor.ExpectedConditions; browser.wait(EC.invisibilityOf(element(by.xpath(CastModule.PersonXpath))), 5000).then(function() {
if (EC.invisibilityOf(element(by.xpath(x.LanguagesXpath)))) {
console.log("Persons module is not present - as expected for this scenario");
} else {
throw new Error("Element STILL present");
}
});
});
You can also try below code to handle element displayed or not. Below code returns true or false according to the visibility of the element.
browser.wait(() => {
return element(by.className("claasName")).isDisplayed()
.then(
(hasDisplayed) => {
console.log("Has displayed: "+ hasDisplayed);
return hasDisplayed === false;
}
);
}, 5000)
.then(
() => {
return true;
},
() => {
return false;
}
)
To use presence of element use:
var elm = element(CastModule.PersonXpath);
elm.isPresent().then(function (present) {
if (present) {
element(CastModule.PersonXpath).then(function (labels) {
});
} else {
console.log('Element did not found');
}`enter code here`
expect(elem.isNull===undefined).to.be.equal(true);

Jasmine2: get current spec name

In Jasmine 1.3, we had this option to the get current spec and suite names:
describe("name for describe", function () {
it("name for it", function () {
console.log(this.suite.getFullName()); // would print "name for describe"
console.log(this.description); // would print "name for it"
});
});
This does not longer work in Jasmine 2.x.
Anyone knows how to fetch those?
Thanks.
I add a new jasmine reporter, then get the spec name without define N variable on each spec. Hope can help, thanks.
var reporterCurrentSpec = {
specStarted: function(result) {
this.name = result.fullName;
}
};
jasmine.getEnv().addReporter(reporterCurrentSpec);
The reason this no longer works is because this is not the test. You can introduce a subtle change to your declarations however that fix it. Instead of just doing:
it("name for it", function() {});
Define the it as a variable:
var spec = it("name for it", function() {
console.log(spec.description); // prints "name for it"
});
This requires no plug-ins and works with standard Jasmine.
As far as Jasmine 2 is concerned currentSpec is discontinued on purpose. However there is a custom plugin/library developed that is based on jasmine reporter plugin which you can use. Here's the Link. Hope it helps with your requirement.
Its very simple to use, install the package with npm command -
npm install -g jasmine-test-container-support
Get the test container support by writing below lines before your describe or test suite -
var JasmineTestContainerSupport = window.JasmineTestContainerSupport || require('jasmine-test-container-support');
JasmineTestContainerSupport.extend(jasmine);
Later use the test container in your spec's to get its description -
var specDesc = jasmine.getEnv().getTestContainer();
Hope this helps.
var currentSpecName = describe('Test1', function() {
var currentStepName = it("Step1", function(){
console.log(currentStepName.description); // Prints It Name
console.log(currentSpecName.getFullName()); //Prints Describe Name
});
});
This worked for me in jasmine 3.5+
I know this is a relatively old question but found something which worked for me
describe('Desc1',() => {
afterEach(() => {
const myReporter = {
specDone: (result) => {
console.log('Spec FullName: ' + result.fullName);
console.log('Spec Result: ' + result.status);
}
};
jasmine.getEnv().addReporter(myReporter);
});
})
Credit for the solution : https://groups.google.com/g/jasmine-js/c/qqOk6Nh7m4c/m/Nyovy2EjAgAJ
This is probably a bit late but you can get the suite name outside the spec.
Please try the following code:
describe("name for describe", function () {
console.log(this.getFullName()); // would print "name for describe"
it("name for it", function () {
//Your test spec
});
});

How to verify with Jasmine that a module called a sub-module method with correct arguments

The following test spec simulates calling a module that writes some content to the file system. Internally it uses fs to do that. I want to make sure fs.writeFile() was called with correct parameters. However, the toHaveBeenCalledWith() doesn't seem to work with a generic Function argument. Any ideas on how to make toHaveBeenCalledWith work as I expect?
Test Spec:
var fs = {
writeFile: function (arg1, arg2, cb){}
}
var writeContent = {
toFS: function (){
var path = "some/calculated/path";
var content = "some content";
fs.writeFile(path, content, function(){})
}
}
describe("writeContent", function() {
var writeFileSpy = null;
beforeEach(function() {
writeFileSpy = jasmine.createSpy('writeFileSpy');
spyOn(fs, 'writeFile').and.callFake(writeFileSpy);
});
it("can call spy with callback", function() {
writeContent.toFS();
expect(writeFileSpy).toHaveBeenCalledWith("some/calculated/path", "some content", Function);
});
});
Results:
Message:
Expected spy writeFileSpy to have been called with [ 'some/calculated/path', 'some content', Function ] but actual calls were [ 'some/calculated/path', 'some content', Function ].
Answering my own question :-) Just needed to enclose Function in jasmine.any() as in:
expect(writeFileSpy).toHaveBeenCalledWith("some/calculated/path", "some content", jasmine.any(Function));

Skipping a test in Qunit

I just found qHint, a method to integrate jsHint testing into Qunit... but it doesn't work locally (I don't mean localhost) except in Firefox.
So I wanted to add a "warning" or "notice", NOT a test failure, showing that the test was skipped:
// do unit test if not local or local and running Firefox
t = QUnit.isLocal;
if (!t || (t && /Firefox/.test(navigator.userAgent))) {
jsHintTest('JSHint core check', 'js/myplugin.js');
} else {
test('JSHint core check (skipped)', function(){
ok( true, 'check not done locally' );
});
}
I would just like to make it more obvious that a test was skipped, is this possible?
Update: Thanks to Odi for the answer!, but I had to make a slight modification to make the code work in QUnit v1.11.0pre:
QUnit.testSkip = function( testName, callback ) {
QUnit.test(testName + ' (SKIPPED)', function() {
if (typeof callback === "function") {
callback();
}
var li = document.getElementById(QUnit.config.current.id);
QUnit.done(function() {
li.style.background = '#FFFF99';
});
});
};
testSkip = QUnit.testSkip;
I had the same requirement and I simply defined a new kind of test() that I called testSkip().
This test method simply replaces your test function and changes the name to <test name> (SKIPPED). After that the test is considered passed by QUnit.
To further indicate that this is a skipped test, I added a callback function to QUnit.done for each skipped test to change the color of the test in the HTML output to yellow. These callbacks are executed when the test suite is done. Setting the value directly does not work, because QUnit applies the styles for passed/failed tests at the end of the run.
QUnit.testSkip = function() {
QUnit.test(arguments[0] + ' (SKIPPED)', function() {
QUnit.expect(0);//dont expect any tests
var li = document.getElementById(QUnit.config.current.id);
QUnit.done(function() {
li.style.background = '#FFFF99';
});
});
};
testSkip = QUnit.testSkip;
Then you can use testSkip() instead of test() for skipped tests.
For my test suite the result looks like that:
For anyone who may have glazed over the comments, Mottie's comment on the question points out that Qunit now has a skip() function. Just replace any call to test() with skip() to skip that test.

Resources