Monthly Archives: March 2013

Spying on native functions in Jasmine

Recently I’ve been getting really into Jasmine spies. I’ve come across plenty of people online talking about the basics of how to use spies in Jasmine. They’re great resources and I’m indebted to them, but I don’t think they really do Spies justice. Spies are incredible. I feel like now I’m really starting to get my head around them and wanted to talk about that.

This week I’ve been using Spies to spy on native functions. It’s possible that the reason I’ve never found anyone else talking about doing this is it’s a bad idea, or so basic that no one else has thought to mention it before. I find it important to never discount the idea that I might be an idiot.. However, this wasn’t obvious to me at first and has proven devilishly useful so here’s what I’ve been up to.

It all started with testing a form submission. In the natural course of events this would take us off the page running the Jasmine tests, or create an endless loop of page refreshes. It occurred to me that there had to be a function behind the form submission hidden somewhere, and if I could spy on that, it’d prevent the form submitting and I could get on with my life. I can even use it to check that the form submission has been called. Sure enough, a bit of poking around revealed that:
spyOn(HTMLFormElement.prototype, 'submit');
Gives you a spy on the native submit function. It makes perfect sense really, of course the HTMLFormElement prototype has a submit function attached to it, and why shouldn’t Jasmine be able to spy on it? And with that one line, the headache of not refreshing or leaving your spec runner on form submissions goes away.

Pleased with this little trick I later came up against a bit of code that needed testing. It took an uploaded image file, converted it into an Image object and looked at scaled it to fit the user’s screen size. We’ve dabbled in actually uploading images for another image uploader test in the past. It was horrible and involved adding a timeOut into the test then hoping it was long enough. We eventually took that out. Keen not to re-introduce it, I figured if I could spy on a Form submission then why not spy on the Image object constructor? Sure enough:
spyOn(window, 'Image')
let me spy on that constructor, so I could then get it to return a mock object with just the information needed for the test.
spyOn(window, 'Image').andReturn({width: 100, height: 200});

Alas, I can’t claim to understand the inner workings of JavaScript well enough to predict what object any given function is attached to. I had assumed that the Image constructor would be attached to document, but turned out it’s on the window. There’s probably some easy way to look it up if you know where to look. If I were a better person, that last sentence would have been a link to that resource but I don’t have it, just assume it exists somewhere.

So anyone who, like me, didn’t find this immediately obvious I encourage you to go out and give it a try. Then if it creates some sort of horrible mess come back and let me know why I shouldn’t be doing it either. Remember, I may well be an idiot.

Advertisements
Tagged , , , , ,

Organising IE specific SASS stylesheets

So last week I spoke about using SASS to create IE specific stylesheets. This is a good idea if you’re using SASS (Or any CSS pre-compiler really) and, like me, you prefer to keep your dirty IE fixes away from proper styling.

At the end of that I said I’d talk about how we’re organising these. Unfortunately, thinking about it, this isn’t too exciting. Premature promises, eh? So here it is in brief:

Every version of IE has its own bundle. There is also a bundle for all IEs. The All IE bundle includes the regular CSS bundle and anything we want applied to all versions. Then, each specific IE version bundle includes the All IE bundle and anything specific to that version.

Fixes are (as far as practical) kept in separate, small files with names describing what they’re for and which versions they should apply to.

This means, for example, that we have a single file for applying a polyfill for gradients which is then imported into the relevant IE version bundles.

That’s about it really. Have a good week.

Tagged , , , ,

IE Specific Stylesheets with SASS

Recently I’ve been concerning myself with fixing IE. Well obviously not fixing it, but navigating around its idiosyncrasies. We’re trying to develop the site for modern browsers with fallbacks and fixes appended for old ones (IE) in such a way that when they go obsolete we can whip them out quickly and easily. In styling terms this means we need a way to apply rules to elements in IE only, or even in some cases to specific versions of IE only.

Keeping styling rules separate seems to be somewhat contentious. Paul Irish for whom I have great respect prefers the IE specific rules to be next to the other rules styling an element. His complaint is that it can be hard to identify which stylesheet a rule is coming from if it’s from an external one. I see his point but still have a personal preference for keeping them separate as it means the main CSS is cleaner and I’ve never really had a problem with identifying the source stylesheet for anything.

In previous projects we’ve adopted one of two approaches. We’ve used JavaScript to detect if it’s IE and add a class to the body tag and then included these IE specific rules with the proper CSS. I dislike this approach because it keeps the IE specific rules in with the main CSS. More significantly, it introduces a hard JavaScript dependency. I’m all for ignoring IE users without JavaScript on the grounds that they’re clearly being willfully awkward, but apparently that’s not allowed.

We’ve also used IE Specific stylesheets. This approach uses Conditional statements in the html. These are ignored by real browsers but picked up by IE, meaning you can add an extra stylesheet to IE full of fixes. I like this because it keeps the IE fixes separate and only punishes IE users with the extra (admittedly tiny) download size and it doesn’t depend on JavaScript. On the down side however, this adds an extra http request to IE uses.

Paul Irish has discussed this. In brief, his solution was to use IE Conditional comments to add classes to the html tag. This bypasses the need for JavaScript but lets you put your styling in amongst your code proper. This is an elegant solution and I like it, but as I’ve said I don’t want my IE styling rules in my main CSS. Instead we’re taking advantage of SASS to do something a little different.

Because SASS’ stylesheet import copies the whole imported sheet it does not create extra http requests. This means that if we create a special stylesheet for each version of IE and import our regular stylesheet bundle into it, we can have IE specific rules in a separate stylesheet for development but bundled up for the user meaning it only needs one http request. Then, using the same conditional comments we were using for import an extra stylesheet we can import the single bundle for each version of IE. The only change needed to these is the addition of a not IE selector to import the regular bundle

<!--[if !IE]><!-->
<link rel="stylesheet" href="/css/desktop/bundle.css"/>
<!--<![endif]-->

<!--[if IE 7]>
<link rel="stylesheet" href="/css/desktop/ie/ie7-bundle.css"/>
<![endif]-->
<!--[if IE 8]>
<link rel="stylesheet" href="/css/desktop/ie/ie8-bundle.css"/>
<![endif]-->
<!--[if IE 9]>
<link rel="stylesheet" href="/css/desktop/ie/ie9-bundle.css"/>
<![endif]-->
<!--[if IE 10]>
<link rel="stylesheet" href="/css/desktop/ie/ie10-bundle.css"/>
<![endif]-->

Do take note of the extra <!--> in the not IE selector, this means that the stylesheet is still loaded in in not-IE browsers while the others are ignored as html comments.

Now we’re not actually keeping all the IE fixes in a file each for every version of IE. But I won’t talk about how we’re doing it now, that’ll be something to talk about next time.

Tagged , , , ,