JsUnit + Accuracy
After I got my tests passing in JsUnit, I decided I needed to automate the execution of the JavaScript Unit Tests for Fjords(more on that in a later post). So, the only way I could think of doing that was to drive the browser to the JsUnit Test Runner page and type the correct parameters. Thank god I have an amazing Browser Driver called Stormwind.Accuracy.
Introduction
You can check how the JsUnit test runner looks here. But in the local version you get to choose the path to the test (in a textbox). "So", I thought, "It's pretty easy to automate that. I just write the test path in the textbox and click on run. Then I check that there were zero failures. How hard can that be?".
Whenever you finish a sentence with "How hard can that be?" you know that you are in for a world of pain. First thing that I noticed is that the JsUnit test runner uses a FrameSet, but not only that, it uses a FrameSet inside a FrameSet. That tends to be hard for Accuracy, since you need to specify the frame you want to find the control in. The thing here is I had never done any code with frames inside frames.
I was thrilled to see that the code in Accuracy is so simple that I managed to change the code to use hierarchical frames in no time. Now you can just say I.AmIn("some frame name").Frame or I.AmIn("Some Frame>Some Sub Frame>Some Inner Frame").Frame and it will put you inside the correct frame. This way I got to automate JsUnit properly.
The Test Fixture
Let's check what the JsUnitTestFixture looks like:
1: public abstract class JsUnitTestFixture : AcceptanceTestFixture
2: { 3: [Test]
4: public void ShouldRunTests()
5: { 6: //Context.Current.DebugMode = true;
7: Context.Current.ElementNamingStrategy = new CustomNamingStrategy();
8: var story = Story
9: .AsA("Web Site User") 10: .IWantTo("Unit test JavaScript using the " + TestPageUrl + " Page") 11: .SoThat("I can verify that my JavaScript code is correct"); 12:
13: var url = Path.Combine(Context.Current.RootUrl, "UnitTests/" + TestPageUrl);
14:
15: story.WithScenario("The tests run") 16: .Given(I.GoTo("Js Unit Test Runner Page")) 17: .And(I.AmIn("Main Frame>Main Data").Frame) 18: .When(I.Fill.TextBox("Test File Name").With(url)) 19: .And(I.Click("Run Button").Button) 20: .Then(I.AmIn("Main Frame>Main Status").Frame) 21: .And(I.WaitFor("Status: Done").Message) 22: .And(I.AmIn("Main Frame>Main Counts>Main Counts Errors").Frame) 23: .And(I.See("Errors: 0").Message) 24: .And(I.AmIn("Main Frame>Main Counts>Main Counts Failures").Frame) 25: .And(I.See("Failures: 0").Message); 26: }
27:
28: public abstract string TestPageUrl { get;} 29: }
30:
31: internal class CustomNamingStrategy : INamingStrategy
32: { 33: public string Resolve(ElementType type, string key)
34: { 35: return string.Join(string.Empty, key.Split(' ')); 36: }
37: }
Oh, that's right, Accuracy allows you to specify the naming strategy you want. In this case, none!
So we have one abstract property saying what Test Url is your test case in, and one Test which just runs the tests in that page. I think the code is pretty self-explanatory (one of the main advantages of using Accuracy).
Now let's check one of my test classes:
1: [TestFixture]
2: public class StormwindFjordsBusTest : JsUnitTestFixture
3: { 4: public override string TestPageUrl
5: { 6: get { return "StormwindFjordsBusTests.html"; } 7: }
8: }
Woot?! That's it? How come? This test doesn't have any assertions!!!
Calm down my hasty friend. Remember that your test is written in the html form. This is just a way to automate the run of those tests.
I could run all of them in the same Unit Test, but if I did that, I'd never know which ones are broken. So, that's why I have one JsUnitTestFixture for each of my Test Pages. There's just one last thing missing, the JsUnitTestRunnerPage, which is shown here and must be initialized in Accuracy.
1: public class JsUnitTestRunnerPage : Page
2: { 3: public JsUnitTestRunnerPage()
4: : base("/UnitTests/jsUnit/TestRunner.html") 5: { 6: Register.Textbox("Test File Name"); 7: }
8: }
Conclusion
That's all you need my friend to have your JsUnit tests being run together with all your other unit tests.
Now I can really write as many JsUnit tests as I want to.
Hope that helps!
#146