I have the following function which checks if cookies are enabled in a user's browser:
CookiesEnabled: function() {
var cookieEnabled = navigator.cookieEnabled;
if (!cookieEnabled) {
document.cookie = "test_cookie";
cookieEnabled = document.cookie.indexOf("test_cookie") != -1;
}
return cookieEnabled;
},
I want to unit test that this works using Sinon/Qunit but am unsure of how to approach this properly as I am not very experienced using Sinon or QUnit. Here is my attempt at putting together a test:
QUnit.test("CookiesEnabled - returns true if user has enabled cookies in their browser", function (assert) {
sinon.stub(CookieHelper, "CookiesEnabled")
.callsFake(function () {});
var result = CookieHelper.CookiesEnabled();
Assert.Equal(result, true);
CookieHelper.CookiesEnabled.restore();
});
Please can anyone point me in the right direction for unit testing this method using Qunit and Sinon? Thank you.
UPDATED ATTEMPT:
QUnit.test("CookiesEnabled - returns true if user has enabled cookies in their browser", function (assert) {
sinon.stub(navigator, "cookieEnabled").callsFake(function () {
return true;
});
var result = CookieHelper.CookiesEnabled();
assert.equal(result, true);
});
As mentioned, window.navigator is readonly. There are some things you could try to fake out the browser, but really, you should just inject the properties you're interested in for the function to use. This way you can override the browser setting or test it! Notice the addition of two arguments (since you also need to bypass your double-checking of cookie setting).
The additional flag argument is a boolean that essentially tells the function what the value of cookieEnabled should be (versus using navigator.cookieEnabled). However, if that parameter is missing, the code will use the browser setting. In other words, it's a way to "inject" the value you want, very useful in testing. This isn't ideal, but not much else you can without a lot more work and mocking (using a headless browser with cookies disabled).
Here's a jsfiddle of this working: https://jsfiddle.net/e5mtpboy/
CookiesEnabled: function(flag, bypassTest) {
var cookieEnabled = typeof(flag) === 'boolean' ? flag : navigator.cookieEnabled;
if (!cookieEnabled && !bypassTest) {
document.cookie = "test_cookie";
cookieEnabled = document.cookie.indexOf("test_cookie") != -1;
}
return cookieEnabled;
}
Then in your tests:
QUnit.test("CookiesEnabled - returns true if user has enabled cookies in their browser", function (assert) {
var result = CookieHelper.CookiesEnabled(true);
assert.equal(result, true);
});
QUnit.test("CookiesEnabled - returns true if user has disabled cookies, but we can still set one", function (assert) {
var result = CookieHelper.CookiesEnabled(false);
assert.equal(result, true);
});
QUnit.test("CookiesEnabled - returns false if browser does not support cookies", function (assert) {
var result = CookieHelper.CookiesEnabled(false, true);
assert.equal(result, false);
});
Related
I have a code that uses window.foo.abc as a condition to display something.
I want to test this functionality with cypress and I want to mock this value to be false and true.
How can I do that?
I've tried
before(function() {
Cypress.on('window:before:load', win => {
win.foo.abc = true;
});
and
cy.window().then(win => {
window.foo.abc = true;
});
with no success.
How can I mock this value?
thanks 🙏
This code is incorrect,
Cypress.on('window:before:load', win => {
window.foo.abc = true;
});
It should be
Cypress.on('window:before:load', win => {
win.foo.abc = true;
});
You don't have to use it in before(), but it should be at the top of the spec.
But I suspect it still won't work after correcting, most likely the app resets foo to a new object during loading, i.e during cy.visit()
You can use the 2nd block
cy.visit('...') // visit before changing
cy.window().then(win => {
win.foo.abc = true; // correct the syntax here as well
})
I am trying to pass an argument from the command line and check or uncheck a check box on my local website. If I substitute the system.args[4] in the returnVars function with a true or false it works, but the argument I pass from the command line doesn't affect the check box.
var returnVars = function(){
if (system.args.length > 4) {
console.log(system.args[4]); // this is getting the correct value from the args
return system.args[4];
}
};
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit(1);
} else {
var returnable = page.evaluate(function(r,s) {
return document.getElementById(r).checked = s;
}, 'returnable', returnVars());
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});
I am using the rasterize.js example and replacing the zoom option with my own. I call it with:
phantomjs rasterize.js mywebsite.com c:\foo.pdf "letter" false
You're passing a string "false" into evaluate and setting the checked property to this string. The string is then evaluated to true, because !!"false" === true and !!"true" === true. If hope you see the problem now.
This is easy to fix. Since you're passing JavaScript code (false) as a string, you need to execute the string so that it is JavaScript code again:
document.getElementById(r).checked = eval(s);
eval is usually evil, but since this is your local script, there is nothing you can break security-wise.
I have the following (simplified) javascript module which uses jQuery Cookie plugin to check if cookies are enabled. If cookies are disabled it warns the user:
var cookiePolicy = (function () {
var cookiesEnabled = function () {
return $.cookie('check', 'valid', { expires: 1 }) && $.cookie('check') == 'valid';
};
return {
updateCookiePolicy: function () {
if (!cookiesEnabled()) {
$("#cookie-policy").append('<p id="cookie-warning">Cookies are disabled. Some features of this site may not work correctly.</p>');
}
}
};
})();
I have the following unit test:
QUnit.test("When cookies are enabled the cookie policy text remains unchanged", function (assert) {
sinon.mock($).expects("cookie").once().withExactArgs("check", "valid", { expires: 1 });
sinon.mock($).expects("cookie").once().withExactArgs("check").returns("valid");
cookiePolicy.updateCookiePolicy();
assert.equal(0, $('#cookie-warning').length, "Failed!");
});
The test fails because "cookie is already wrapped". I assume this is because I am mocking $.cookie for both set and read. How can I mock the call to $.cookie for both setting and reading in this test?
Your assumption is correct. Depending on the version of Sinon you're using, you could do something like this:
// UUT
var foo = {
bar: function() {}
};
// Test setup
var mock = sinon.mock(foo);
var expectation = mock.expects('bar').twice();
expectation.onFirstCall().stub.calledWithExactly('baz');
expectation.onSecondCall().stub.calledWithExactly('qux');
// Test
foo.bar('baz');
foo.bar('qux');
mock.verify();
BTW, it's strange to use Sinon mocks without using .verify(). Maybe stubs would be a better fit?
I'm using osx 10.9.2, protractor 0.21.0, selenium-server-standalone 2.40.0 and chromedriver 2.9.
I'm having some problems, which (I believe) was due to window focusing issue.
When I run my e2e test using protractor, the browser window would show but my terminal will still be the one in focus. This is apparent from "Terminal" was still shown in my menu bar rather than "Chrome" (osx behavior that indicates which app is in focus).
I tried to remedy the situation by doing this to no avail:
browser.driver.getAllWindowHandles().then(function(handles) {
console.log(handles[0]);
browser.driver.switchTo().window(handles[0]);
});
This situation causes some of my tests to fail. For example, tests that include clicking a field with bootstrap datepicker won't show the calendar and making my test cannot interact with the datepicker calendar.
The situation is even worse on firefox. Firefox won't even show any dropdown menu when clicked if the browser is not in focus.
Funnily, when I click the browser window manually after it shows up the first time, the tests will work normally.
When I tried a different approach: Doing the test on a freshly installed debian linux, still not working. Behavior is similar as described above.
These are my configuration files: https://gist.github.com/giosakti/ca24a13705d15f4374b0
Unfortunately IE & Firefox don't ensure the windows handlers order, so we need iterate them. And getting focus on the new browser window/tab can be tricky too.
I've run into these issues so i created:
A helper function to overcome those issues
// Needs an element to make sure we are on the correct popup
var waitForPopUpHandle = function(elm, errorMessage) {
if (errorMessage == null) {
errorMessage = 'Expected a new browser tab or window to pop up';
};
if (elm == null) {
throw 'waitForPopUpHandle needs an element to wait for!';
};
browser.ignoreSynchronization = true; // not a protractor page
// IE & Firefox don't ensure the windows handlers order, so we need iterate them.
// First wait to have more that 1 browser tab
browser.manage().timeouts().implicitlyWait(300); // a reasonable wait-retry time
var i = 0;
var popUpHandle = browser.driver.wait(function() {
return browser.getAllWindowHandles().then(function(handles) {
if (handles.length > 1) {
return browser.switchTo().window(handles[i]).then(function() {
return browser.driver.isElementPresent(elm).then(function(result) {
if (result) {
return handles[i];
} else {
browser.sleep(400); // give it a break
i = i + 1;
if (i >= handles.length) {
i = 0;
};
return false;
};
});
});
} else {
browser.sleep(400); // give it a break
return false;
};
});
}, browser.params.timeouts.pageLoadTimeout, errorMessage);
// restore implicit wait
browser.manage().timeouts().implicitlyWait(0); //restore
return popUpHandle;
};
Sample usage of that helper
var popUpHandle = waitForPopUpHandle(by.css('div.some-element-unique-to-that-popup'));
browser.switchTo().window(popUpHandle).then(function() {
browser.ignoreSynchronization = true; // not an angular page
browser.driver.findElement(by.css('div.some-element-unique-to-that-popup')); // wait for the elm
// your expect()'s go here ...
// ...
browser.close().then(function() {
// This close() promise is necessary on IE and probably on Firefox too
var mainTab = waitForMainWindow();
expect(browser.switchTo().window(mainTab).then(function() {
browser.ignoreSynchronization = false; // restore if main window is an angular page
// Ensure we are back on the main window
// ....
return true;
})).toBe(true);
});
});
And finally waitForMainWindow helper
var waitForMainWindow = function(errorMessage) {
if (errorMessage == null) {
errorMessage = 'Expected main browser window to be available';
};
browser.ignoreSynchronization = true; // not an angular page
return browser.driver.wait(function() {
return browser.getAllWindowHandles().then(function(handles) {
if (handles.length > 1) {
var hnd = handles[handles.length - 1];
return browser.switchTo().window(hnd).then(function() {
return browser.close().then(function() {
browser.sleep(400); // wait for close
return false;
});
});
} else {
return handles[0];
};
});
}, 5000, errorMessage);
};
I found a silver lining! I downgrade the chrome using installer from http://google-chrome.en.uptodown.com/mac/old and the focus issues are gone.. (the issues still persist on firefox though)..
If you search "chrome 34 focus issues" on google, you will find several reports that maybe correlate with this issue. for example: https://productforums.google.com/forum/#!topic/chrome/pN5pYf2kolc
but I still don't know whether this was a bug or expected behavior of chrome 34. So for now I block google updater and use Chrome 33.
Thanks to everyone in advance -
I need to load a preference before any windows are loaded at startup. Below is some /component code I have been working with. The SetPreference method seems to fail when it is called (nothing executes afterwords either) - I am assuming because the resources that it needs are not available at the time of execution...or I am doing something wrong. Any suggestions with this code or another approach to setting a preference at startup?
Thanks again,
Sam
For some reason the code formatting for SO is not working properly - here is a link to the code as well - http://samingrassia.com/_FILES/startup.js
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
const Cc = Components.classes;
const Ci = Components.interfaces;
const ObserverService = Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
function MyStartupService() {};
MyStartupService.prototype = {
observe : function(aSubject, aTopic, aData) {
switch (aTopic) {
case 'xpcom-startup':
this.SetPreference("my.extension.is_running", "false");
break;
case 'app-startup':
this.SetPreference("my.extension.is_running", "false");
ObserverService.addObserver(this, 'final-ui-startup', false);
break;
case 'final-ui-startup':
//make sure is_running is set to false
this.SetPreference("my.extension.is_running", "false");
ObserverService.removeObserver(this, 'final-ui-startup');
const WindowWatcher = Cc['#mozilla.org/embedcomp/window-watcher;1'].getService(Ci.nsIWindowWatcher);
WindowWatcher.registerNotification(this);
break;
case 'domwindowopened':
this.initWindow(aSubject);
break;
}
},
SetPreference : function(Token, Value) {
var prefs = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
var str = Components.classes["#mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
str.data = Value;
prefs.setComplexValue(Token, Components.interfaces.nsISupportsString, str);
//save preferences
var prefService = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
prefService.savePrefFile(null);
},
initWindow : function(aWindow) {
if (aWindow != '[object ChromeWindow]') return;
aWindow.addEventListener('load', function() {
aWindow.removeEventListener('load', arguments.callee, false);
aWindow.document.title = 'domwindowopened!';
// for browser windows
var root = aWindow.document.documentElement;
root.setAttribute('title', aWindow.document.title);
root.setAttribute('titlemodifier', aWindow.document.title);
}, false);
},
classDescription : 'My Startup Service',
contractID : '#mystartupservice.com/startup;1',
classID : Components.ID('{770825e7-b39c-4654-94bc-008e5d6d57b7}'),
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver]),
_xpcom_categories : [{ category : 'app-startup', service : true }]
};
function NSGetModule(aCompMgr, aFileSpec) {
return XPCOMUtils.generateModule([MyStartupService]);
}
To answer your real question, which is
I have code that loads on every window load and I need to make sure that only gets executed once every time firefox starts up.
..you should just use a module, in the load handler that you wish to execute once, check a flag on the object exported from (i.e. "living in") the module, then after running the code you need, set the flag.
Since the module is shared across all windows, the flag will remain set until you close Firefox.
As for your intermediate problem, I'd suggest wrapping the code inside observe() in a try { ... } catch(e) {dump(e)} (you'll need to set a pref and run Firefox in a special way in order to see the output) and check the error returned.
I guess xpcom-startup and app-startup is too early to mess with preferences (I think you need a profile for that), note that you don't register to get xpcom-startup notification anyway. You probably want to register for profile-after-change instead.