Saturday, August 24, 2013

XUnit.PhantomQ v1.1

I recently blogged about how to Use XUnit to Run QUnit Tests. The initial v1.0 release of XUnit.PhantomQ did not support error messages, but now in v1.1 it supports the must have feature of bringing error messages back with failed test results.

XUnit.PhantomQ on NuGet
XUnit.PhantomQ Source on GitHub

Enjoy,
Tom

Tuesday, August 13, 2013

Control Minification per Request with Web Optimizations

The Microsoft ASP.NET Web Optimization Framework is a great bundling and minification solution for your web applications. Simply grab the Microsoft.AspNet.Web.Optimization NuGet package, register your bundles, render them with a single line of code, and your environment will automatically resolve your dependencies based on whether or not the web server is running in debug mode.

But how can you debug minified styles and scripts in production?

Normally that is a difficult proposition, but here is a simple solution: JUST DON'T MINIFY THEM! With the little code snippets below you can add a simple query string parameter to disable minification for specific sessions or requests.

Adding this functionality to your website is extremely easy and requires no additional dependencies. Web Optimizations already has an internal AssetManager class that supports this functionality, we just need to access it via reflection.

Simply apply the following two steps and you will be ready to debug in production:

  1. Create the HtmlHelperExtensions class with the code below.
  2. Add a call to TrySetOptimizationEnabled inside of your ViewStart.

_ViewStart.cshtml

@using System.Web.Optimization
@{
    Layout = "~/Views/Shared/_Layout.cshtml";
    Html.TrySetOptimizationEnabled();
}

HtmlHelperExtensions.cs

public static class HtmlHelperExtensions
{
    public const string Key = "OptimizationEnabled";
 
    public static bool TrySetOptimizationEnabled(this HtmlHelper html)
    {
        var queryString = html.ViewContext.HttpContext.Request.QueryString;
        var session = html.ViewContext.HttpContext.Session;
 
        // Check the query string first, then the session.
        return TryQueryString(queryString, session) || TrySession(session);
    }
 
    private static bool TryQueryString(
        NameValueCollection queryString, 
        HttpSessionStateBase session)
    {
        // Does the query string contain the key?
        if (queryString.AllKeys.Contains(
            Key, 
            StringComparer.InvariantCultureIgnoreCase))
        {
            // Is the value a boolean?
            bool boolValue;
            var stringValue = queryString[Key];
            if (bool.TryParse(stringValue, out boolValue))
            {
                // Set the OptimizationEnabled flag
                // and then store that value in session.
                SetOptimizationEnabled(boolValue);
                session[Key] = boolValue;
                return true;
            }
        }
 
        return false;
    }
 
    private static bool TrySession(HttpSessionStateBase session)
    {
        if (session != null)
        {
            var value = session[Key] as bool?;
            if (value.HasValue)
            {
                // Use the session value to set the OptimizationEnabled flag.
                SetOptimizationEnabled(value.Value);
                return true;
            }
        }
 
        return false;
    }
 
    private static void SetOptimizationEnabled(bool value)
    {
        // Use reflection to set the internal AssetManager.OptimizationEnabled
        // flag for this request specific.
        var instance = ManagerProperty.GetValue(null, null);
        OptimizationEnabledProperty.SetValue(instance, value);
    }
 
    private static readonly PropertyInfo ManagerProperty = typeof(Scripts)
        .GetProperty("Manager", BindingFlags.Static | BindingFlags.NonPublic);
 
    private static readonly PropertyInfo OptimizationEnabledProperty = Assembly
        .GetAssembly(typeof(Scripts))
        .GetType("System.Web.Optimization.AssetManager")
        .GetProperty(
            "OptimizationEnabled",
            BindingFlags.Instance | BindingFlags.NonPublic);
}
Shout it

Enjoy,
Tom

Wednesday, August 7, 2013

Last in Win Replication for RavenDB

One of my favorite features of RavenDB is how easy it is customize and extend.

RavenDB offers an extremely easy to use built in replication bundle. To deal with replication conflicts, the RavenDB.Database NuGet Package includes an abstract base class (the AbstractDocumentReplicationConflictResolver) that you can implement with your own conflict resolution rules.

Last In Wins Replication Conflict Resolver

John Bennett wrote a LastInWinsReplicationConflictResolver for RavenDB 1.0, and I have updated it for RavenDB 2.0 and 2.5. As always you can get that code from GitHub!

Download RavenExtensions from GitHub

Once you have built your resolver, you need only drop the assembly into the Plugins folder at the root of your RavenDB server and it will automatically be detected and loaded the next time that your server starts.

public class LastInWinsReplicationConflictResolver
    : AbstractDocumentReplicationConflictResolver
{
    private readonly ILog _log = LogManager.GetCurrentClassLogger();
 
    public override bool TryResolve(
        string id,
        RavenJObject metadata,
        RavenJObject document,
        JsonDocument existingDoc,
        Func<string, JsonDocument> getDocument)
    {
        if (ExistingDocShouldWin(metadata, existingDoc))
        {
            ReplaceValues(metadata, existingDoc.Metadata);
            ReplaceValues(document, existingDoc.DataAsJson);
            _log.Debug(
                "Replication conflict for '{0}' resolved with existing doc",
                id);
        }
        else
        {
            _log.Debug(
                "Replication conflict for '{0}' resolved with inbound doc",
                id);
        }
 
        return true;
    }
 
    private static bool ExistingDocShouldWin(
        RavenJObject newMetadata, 
        JsonDocument existingDoc)
    {
        if (existingDoc == null ||
            ExistingDocHasConflict(existingDoc) ||
            ExistingDocIsOlder(newMetadata, existingDoc))
        {
            return false;
        }
 
        return true;
    }
 
    private static bool ExistingDocHasConflict(JsonDocument existingDoc)
    {
        return existingDoc.Metadata[Constants.RavenReplicationConflict] != null;
    }
 
    private static bool ExistingDocIsOlder(
        RavenJObject newMetadata,
        JsonDocument existingDoc)
    {
        var newLastModified = GetLastModified(newMetadata);
 
        if (!existingDoc.LastModified.HasValue ||
            newLastModified.HasValue &&
            existingDoc.LastModified <= newLastModified)
        {
            return true;
        }
 
        return false;
    }
 
    private static DateTime? GetLastModified(RavenJObject metadata)
    {
        var lastModified = metadata[Constants.LastModified];
 
        return (lastModified == null)
            ? new DateTime?()
            : lastModified.Value<DateTime?>();
    }
 
    private static void ReplaceValues(RavenJObject target, RavenJObject source)
    {
        var targetKeys = target.Keys.ToArray();
        foreach (var key in targetKeys)
        {
            target.Remove(key);
        }
 
        foreach (var key in source.Keys)
        {
            target.Add(key, source[key]);
        }
    }
}
Shout it

Enjoy,
Tom

Thursday, August 1, 2013

PhantomJS, the Headless Browser for your .NET WebDriver Tests

Did you know that Selenium already supports PhantomJS?

WebDriver is a specification for controlling the behavior of a web browser. PhantomJS is a headless WebKit scriptable with a JavaScript API. Ghost Driver is a WebDriver implementation that uses PhantomJS for its back-end. Selenium is a software testing framework for web applications. Selenium WebDriver is the successor to Selenium RC. The Selenium WebDriver NuGet Package is a .NET client for for Selenium WebDriver that includes support for PhantomJs via GhostDriver.

NuGet Packages

You need only install two NuGet packages in order to use PhantomJS with WebDriver. You will probably also want which ever Unit Testing framework you prefer. As always, I suggest xUnit.

  1. Selenium.WebDriver
  2. phantomjs.exe

PhantomJSDriver

After installing those, using the PhantomJSDriver is as easy as any other WebDriver!

const string PhantomDirectory =
    @"..\..\..\packages\phantomjs.exe.1.8.1\tools\phantomjs";
 
[Fact]
public void GoogleTitle()
{
    using (IWebDriver phantomDriver = new PhantomJSDriver(PhantomDirectory))
    {
        phantomDriver.Url = "http://www.google.com/";
        Assert.Contains("Google", phantomDriver.Title);
    }
}
Shout it

Enjoy,
Tom

Sunday, July 14, 2013

Use XUnit to Run QUnit Tests

I read a great article recently about Unit testing JavaScript in VisualStudio with ReSharper, written by Chris Seroka. As cool as this feature is, it left me with two questions:

  1. What about developers that do not have ReSharper?
  2. How do I run my JavaScript unit tests on a builder server?

It is no secret that I, absolutely, love, xUnit! Thus I decided to extend xUnit theories to be able to run QUnit tests by implementing a new DataAttribute.

Introducing XUnit.PhantomQ

XUnit.PhantomQ is a little NuGet package you can install to get access to the QUnitDataAttribute (see below for an example). This library will allow you to execute your QUnit tests as XUnit tests.

XUnit.PhantomQ supports both library and web projects, and features the ability to easily specify test files and their dependencies by real relative path to the root of your project.

XUnit.PhantomQ on NuGet
XUnit.PhantomQ Source on GitHub

QUnitData Attribute

Here is an example of writing some JavaScript, a file of QUnit tests, and then using an xUnit theory and a QUnitData Attribute to execute all of those tests right inside of Visual Studio.

// Contents of Demo.js
function getFive() {
    return 5;
}
 
// Contents of Tests.js
test('Test Five', function() {
    var actual = getFive();
    equal(actual, 5);
});
test('Test Not Four', function () {
    var actual = getFive();
    notEqual(actual, 4);
});
 
// Contents of QUnitTests.cs
public class QUnitTests
{
    [Theory, QUnitData("Tests.js", "Demo.js")]
    public void ReturnFiveTests(QUnitTest test)
    {
        test.AssertSuccess();
    }
}
 

Integrating XUnit, PhantomJS, and QUnit

So, how does this thing work under the hood? Below is the complete pipeline, step by step, of whenever the tests are executed:

  1. The XUnit test runner identifies your theory tests.
  2. The QUnitDataAttribute is invoked.
  3. A static helper locates PhantomJS.exe and the root folder of your project.
    • It will automatically walk up the folder structure and try to find PhantomJS.exe in your packages folder. However, you can override this and explicitly set the full path by adding an AppSetting to your config file:
      <add key="PhantomQ.PhantomJsExePath" value="C:/PhantomJS.exe" />
    • The same goes for the root of your project, you can override this location with another AppSetting to your config:
      <add key="PhantomQ.WorkingDirectory" value="C:/Code/DemoProject" />
  4. PhantomJS.exe is invoked as a separate process.
  5. The server loads up XUnit.PhantomQ.Server.js
  6. The server now opens XUnit.PhantomQ.html
  7. QUnit is set to autoRun false.
  8. Event handlers are added to QUnit for testDone and done.
  9. All of the dependencies are now added to the page as script tags.
  10. The test file itself is loaded.
  11. QUnit.start is invoked.
  12. The server waits for the test to complete.
  13. Upon completion the server reads the results out of the page.
  14. The tests and their results are serialized to a JSON dictionary.
  15. The result dictionary is written to the standard output.
  16. The resulting JSON string is read in from the process output.
  17. The results are deserialized using Newtonsoft.JSON
  18. The results are loaded into QUnitTest objects.
  19. The QUnitTest array is passed back from the DataAttribute
  20. Each test run finally calls the AssertSuccess and throws on failure.

...and that's (finally) all folks! If you have any questions, comments, or thoughts on how this could be improved, please let me know!

Shout it

Enjoy,
Tom

Sunday, July 7, 2013

Lucene.Net Analyzer Viewer for RavenDB

To query your data in RavenDB you need to write queries in Lucene.Net.

To know which documents your queries are going to return means that you need to know exactly how your query is being parsed by Lucene.Net. Full text analysis is a great baked in feature of RavenDB, but I have found that they Lucene.NET standard analyzer that parses full text fields can sometimes return surprising results.

This Lucene.Net 3.0 Analyzer Viewer is an update of Andrew Smith's original version for Lucene.Net 2.0. This update now allows you to view the results of text analysis for the same version of Lucene that RavenDB is using. This simple tool can be invaluable to debugging full text searches in RavenDB!

Download Raven.Extensions.AnalyzerViewer from GitHub

This tool also comes with my Alphanumeric Analyzer built in.

Shout it

Enjoy,
Tom

Friday, July 5, 2013

Microsoft Build 2013 for Web Developers

Build 2013 was a whole lot of fun!

The big reveals at Build 2013 was Windows 8.1 and Visual Studio 2013. Admittedly Microsoft's big focus was on the Windows 8 store, but that does not mean that they are not delivering great tools for the fastest growing development environment in the world: the web!

Before we discuss web development, let's first take a moment to talk about Windows.

Windows 8.1 actually looks really good! Like all Microsoft products, the first major patch manages to iron out most of the kinks. The new UI updates and inclusion of the start button make the modern UI and desktop seem much less polarizing. Additionally, I am very optimistic about seeing Windows 8 applications come to PC, table, and phone. Microsoft has always had great potential for creating a homogeneous ecosystem consumer devices, and I am finally getting excited about the product line up that they are delivering.

New Editors in Visual Studio 2013

The Visual Studio Team has completely rewritten the HTML and JavaScript editors from scratch in Visual Studio 2013. This is great news; not only are the new editors faster, more responsive, and have much better intellisense, but they also come with a set of fun new features.

  • The overall Razor experience has been greatly improved.
  • Intellisense now include expandable groups to keep drop downs from getting cluttered.
  • CSS intellisense now displays browser compatibility for each rule.
  • New shift alt keys allows you to select content from tree structures.

Microsoft has yet to announce how they will charge for Visual Studio 2013. Will it be a stand alone install, will it be full price, we just do not know yet. Personally, I would love to see Visual Studio more to incremental update system, but obviously there would be lot of technical limitation to doing so...but hey, a dev can dream!

HTML Editing Features in Visual Studio 2013 Preview

Browser Link

Visual Studio 2013 comes with a built in feature called Browser Link. This is where Visual Studio opens a socket connection directly to your browsers (yes, plural) via SignalR that allows your IDE to send commands directly to the browser itself. The most basic use of this a simple refresh button that allows you to refresh all your browser windows on command.

The potential of this feature is fun to think about! Right now the Visual Studio team is intentionally keeping their default feature set for Browser link very simple, but also open source; as they want to see what us developers come up with. Remember that this is a two way channel of communication between the browser and the IDE, so sending error messages back to Visual Studio is just the first thing that comes to my mind.

A cool demo that they showed us at Build was keeping multiple browser windows in sync, this included form elements and page navigation. The cool part was that these browsers included Chrome, Firefox, and IE running on a virtualized windows phone. It was a very compelling demo!

Browser Link feature in Visual Studio Preview 2013

Web API 2.0

Web API was a great addition to Microsoft's web development library, and 2.0 looks like a great incrimental update to that framework. Forgive me if it seems that I do not have much to say about Web API 2, it just seems like a very simple but very welcome update to the framework; but don't let that fool you, I am stoked!

  • Attribute based routing.
  • Integrated OAuth 2 authentication.
  • OWIN Web hosting (run your APIs outside of IIS)
  • Cross-Origin Resource Sharing

ASP.NET Web API 2

TypeScript 0.9

I am SO excited about TypeScript!

TypeScript is a development language that is a super set of JavaScript. It adds type checking, interfaces, and inheritance to JavaScript. The idea is that you develop in TypeScript and then compile that language down to JavaScript for deployment on the web. The key here is that TypeScript is a super set of JavaScript, so all JavaScript code is already valid TypeScript, making it very easy for you to start your migration from language to the other.

There are essentially two ways that you could choose to use TypeScript:

  1. Use TypeScript for simple type checking and enhanced refactoring.

This is probably the more ideal use of TypeScript, or at least the simplest. The idea being that you can constrain your function parameters by type and interface, and make use of TypeScripts more strick declarations for easier refactoring. You would also get significantly improved intellisense both for your code and other frameworks, as a very active open source community has been creating interface wrappers for everything from JQuery to Knockout.

  1. Go full monty, and make your JavaScript completely Object Oriented.

Using TypeScript would allow you to define and extend both classes and interfaces, just as you would a language like C#. This opens the possibility for polymorphism, dependency injection, mocking, testing, the whole object oriented play book. While this does go against many principals of a very functional programming language like JavaScript, it also enables a lot of best practices that help simplify large scale application development.

...how far you want to go using TypeScript is up to you, but regardless of which side of the fence you are on, I definitely feel that TypeScript is worth looking into!

www.typescriptlang.org

Shout it

The future looks bright,
Tom

Real Time Web Analytics