Window object not defined in jasmine - javascript

I am trying to test a method where one of the thing that it does it lock orientation of screen. Jasmine however is throwing error in the line:
(<any>window).screen.orientation.lock('portrait') saying that undefined is not a constructer.
I even tried not using typescript types and just window.screen.msOrientationLock('landscape') and other window.screen methods but I get same error. I have the _$window_ injected in beforeEach of my tests too.
Testing if it locks is not necessary part of my test so is there some way to skip this specific line or correct this error. Thanks :)

Well it was easy. I had to inject window object and assign it to a global variable in my global beforeEach like this:
$window = _$window_;
Then, the next issue was that the property orientation was not available in the window.screen object unfortunately. I just had to mock it inside my spec like this:
$window.screen.orientation = {
lock: function() { return; }
};
Just had to do this before spying/calling the method which had window.screen.orientation.lock method inside it.

Related

ESLint or Flow - Force references to a variable be prefixed by an existence check

Is there a way to force all references to a variable be prefixed by a check for their existence?
We recently added server side rendering for one of our applications and have had a few incidents with people referencing window in a server side rendered component, where window is not defined.
Is there a way for every time someone references window to have it prefixed by typeof window !== 'undefined'?
For instance
const isEligible = () =>
window &&
window.screen &&
window.screen.availHeight > 200;
should either be an eslint or flow error saying that there should be a check for typeof window !== 'undefined' before the first window reference?
Note that I already know about no-undef for eslint - https://eslint.org/docs/rules/no-undef. This doesn't work, however, because window will be defined for the vast majority of references, its only when its used in the render function of specific components that it should be flagged.
Flow's built-in libdefs declare window as type any. You can override that declaration to have type ?any, forcing a nullness check. You could do this in each of the files where you want these protections, or you could do it project-wide by putting it in a file included in the [libs] section of your .flowconfig.
declare var window: ?any;
window.foo; // expected error
if (window) {
window.foo; // no error
}
(try)

How to disable warnings about 'this' and strict mode using JSHint?

I am writing a web app using AngularJS (v1.5) so I have some controllers, and in those controllers I am often declaring something like :
function myController($someDirectives, ...){
var ctrl = this;
// My code
}
The thing is when I JSHint my code, I get this warning message for all of my 'this' declared in controllers :
If a strict mode function is executed using function invocation, its 'this' value will be undefined.
I must precise that in my .jshintrc file, I set "strict":false.
Does anyone know how to disable this message in particular?
Thanks in advance.
set the configuration in .jshintrc file
{
"validthis": true // Tolerate using this in a non-constructor
}
You can always override jshint options in the code-block ie.
/* jshint validthis: true */
I had the same issue, with a very similar environment angular 1.5.5 always getting the same lint warning:
If a strict mode function is executed using function invocation, its 'this' value will be undefined.
I've changed the name of my component's main function starting with upper-case and the warning disappeared
function MyController($someDirectives, ...){
I'm having the same issue. I'm doing "indirect invocation" with the function in question, not "function invocation", and 'this' is referenced many times in the function body.
In my case, I was having so many of these "errors" that jsHint quit before scanning my whole script.
To get around this I put this at the top of my script-file:
/*jshint maxerr: 10000 */
It did not suppress the errors, but at least it allowed me to scroll down to see jsHint's analysis of the entire script.

Avoid declaring large object in getDefaultProps prior to an event

The title might not be the best way to describe the problem, but I was wondering if there was a better practice to declaring an object in getDefaultProps?
In my render method I call several keys from from a prop/state that get updated on a click event i.e. this.props.player.name. The problem is that on page load this.props.player is blank and calling .name errors out. I know I can do something like ...
getDefaultProps: function() {
return {
player: {
name: null,
team: null
position: null
}
};
}
but it doesn't feel right. I was hoping there might be something similar to how Ruby does .try() where it won't try to call a method on a undefined prop.
The problem is specifically that this.props.player is undefined, if you define an empty object it will prevent the error from occurring. It's not bad practice to stub out the keys you're anticipating, but setting the default value to {} will be enough to prevent it from throwing.
You can create your data from ImmutableJS. Then you can get any part of your data like this:
this.state.getIn(['player', 'name', ...])
or
this.state.get('player')
This will not throw error even player is not defined or other, it will return undefined (or null) I don't remember
The update and updateIn work the same
see the doc here
I'd like to add this vanilla JS solution too - var x = (user || {}).name;
Source

Jasmine Unit Tests Unexpected this Reference

I am trying to test a fairly simple JavaScript function in Jasmine, however the first statement is throwing an error for being undefined.
myClass.prototype.functiontoBeTested = function() {
var x = this.method()
...
}
The above throws an error in Jasmine as method is not a function and is undefined. The prototype is altered earlier to have this method, and out of curiosity I assigned this method to my test object in the spec itself as such:
myObject.method = function(){return mockResults;};
So I decided to log this to the console and instead of it being my object, I see Window {top: Window, location: Location, document: document, window: Window, external: Object…} which doesn't seem right. I've had this issue before with testing a function in Jasmine that used this but just changed the source code to refer to the object by name since the function was being assigned to something within the closure. I can't do that in this case, and I'm curious why this is referring to something unexpected (at least to me).
Edit: Some details on what the test case looks like as requested:
it("updates the control count", function(){
var mockResults = { ... };
myObject.method = function() {return mockResults;};
expect(myObject.method).not.toThrow();
});
Right now I'm just trying to get the method to execute to completion during the test. The function to be tested updates the text on some HTML components, I'll work on verifying those once I can get it to actually run. The method that is causing an error is the first line of the function, and is simply an accessor method for the object being called. In actual execution, var x = this.method() runs without issue. When testing in jasmine var x = this.method() throws an error because method() is undefined for this. Instead of this referring to the calling object, it is referring to the window. This doesn't happen live, but only during testing with Jasmine. This method is undefined even when I forcibly define it for the test object just prior to execution in the test as above. That's when I decided to log this to console in the source code and realized it isn't referring to what I would have expected it to refer to.
In JavaScript this for a method depends on the context it was called from. When you do a call myObject.method(), then method was called from the context of myObject, therefore this is myObject.
When you pass your function to Jasmine toThrow matcher, it calls it as it was passed (see source code):
try {
actual();
} catch (e) {
// ....
}
Here, actual() is a call of your method. It has no any specific context, so by default it will be called from window context.
Solution is to explicitly bind you method to myObject like the following:
expect(myObject.method.bind(myObject)).not.toThrow();
Credits to questions, you can find more details there:
Does Jasmine's toThrow matcher require the argument to be wrapped in an anonymous function?
How to write a test which expects an Error to be thrown in Jasmine?

Protractor `addMockModule()` with arguments not handling structured data properly in Firefox

I recently read about the solution for these protractor issues:
Unable to easily pass context to addMockModule #695
feat(addMockModule): add third parameter to pass context #787
I have been eager to DRY up my protractor tests and this was the solution I needed. This solution is working great with ChromeDriver, but with FirefoxDriver it's oddly broken. Here's my code (in a beforeEach() block:
var httpBackendMock = function() {
angular.module('httpBackendMock', ['ngMockE2E'])
.value('mockData', arguments[0])
.run(function ($httpBackend, mockData) {
$httpBackend.whenGET(/.*aggregates/)
.respond(200, mockData.testAggregates);
$httpBackend.whenGET(/.*merchants\/123456/)
.respond(200, mockData.testMerchant);
});
};
browser.addMockModule('httpBackendMock', httpBackendMock, {
testAggregates: testAggregates,
testMerchant: testMerchant
});
(testAggregates and testMerchant are defined previously.)
This works perfectly in Chrome, but in Firefox when the whenGET expectations fire they return no data. It fails whether I use the mockData object or directly use arguments[0].
But it gets weirder. If I try to inspect the mockData module value I created above in a later browser.executeScript() call, the data is there, and console.log renders it the same way in both Chrome and Firefox.
browser.get('index.html#/experiments');
browser.executeScript(function() {
return angular.injector(["httpBackendMock"]).get('mockData');
}).then(function(data) {
console.log("DATA", data);
});
When the test runs the data shows up as expected.
The only workaround for this I have found is to JSON.stringify() the input to addMockModule() and JSON.parse() it inside. It seems to work, but is ugly - the framework should already be taking care of it.
So I think this is a bug, but I'm really not sure which component this is a bug in.

Categories

Resources