The solution provided by Philip Walton was pretty good, but has a couple caveats. First let me explain what his solution is so you don't have to go read his entire post before continuing. He concludes that there are two camps of testing private JavaScript methods:
1. Don't
2. Everything is public
Obviously that isn't so good so he came up with a new option:
3. Export the private methods so they are public but do it in such a way that a code stripper removes them before going live.
The code stripper option isn't much of a stretch because most JavaScript goes through a compression process anyway removing white space and comments. I like his option but for me it wasn't an option to be able to modify the code stripper. We use YUI Compressor and aren't going to modify it. We could add a preprocessor but that isn't an option at this point. Plus there is potential for bugs because the code that is live isn't the same as the code you are testing. Our stripper has been around for a long time so we have confidence in it. So I came up with a new option:
4. If a global variable has been introduced and the .js file is loaded from a specific URL then initialize the global variable with a closure class containing only the private methods you want to test. For example if the URL is contains "http://localhost" or "file://", then initialize the closure. Any URL could be added here, including an internal test URL. However I can see how publishing a private URL is undesirable no matter how difficult it is to read.
For example:
var myclass = function() {
// Private
function someInternalMethod(arguments) {
}
function anotherInternalMethod(arguments) {
}
function initialize() {
if ((typeof __myclassTestHook__ !== 'undefined') &&
(__myclassTestHook__ == null) &&
((window.location.href.indexOf('http://localhost') == 0) ||
(window.location.href.indexOf('file://') == 0))
) {
__myclassTestHook__ = {
someInternalMethod: someInternalMethod,
anotherInternalMethod: someInternalMethod,
};
}
}
// Public
function publicMethod(arguments) {
}
function anotherPublicMethod(arguments) {
}
initialize();
return {
publicMethod: somePublicMethod,
anotherPublicMethod, anotherPublicMethod
};
}();
Now:
<script>
var __myclassTestHook__ = null;
</script>
<script type="text/javascript" src="testexample.js"></script>
then use it like this:
<script>
var stuff = __myclassTestHook__.someInternalMethod();
</script>
Is this perfect? No, but it comes pretty close in my opinion. What are your thoughts? The biggest concern is introducing security vulnerabilities.