1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove<div class="intro">
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>YUI Test is a testing framework for browser-based JavaScript solutions. Using YUI Test, you can easily add unit testing to your JavaScript solutions. While not a direct port from any specific xUnit framework, YUI Test does derive some characteristics from <a href="http://www.nunit.org/">nUnit</a> and <a href="http://www.junit.org/">JUnit</a>.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>YUI Test features:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li>Rapid creation of <strong>test cases</strong> through simple syntax.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li>Advanced <strong>failure detection</strong> for methods that throw errors.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li>Grouping of related test cases using <strong>test suites</strong>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><strong>Mock objects</strong> for writing tests without external dependencies.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><strong>Asynchronous tests</strong> for testing events and Ajax communication.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><strong>DOM Event simulation</strong> in all A-grade browsers (through <a href="../event/index.html">Event</a>).</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove{{>getting-started}}
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h2 id="testcases">Using Test Cases</h2>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The basis of Test is the <code>Y.Test.Case</code> object. A <code>TestCase</code> object is created by using the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>Y.Test.Case</code> constructor and passing in an object containing methods and other information with which
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove to initialize the test case. Typically, the argument is an object literal, for example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //traditional test names
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSomething : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSomethingElse : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this example, a simple test case is created named "TestCase Name". The <code>name</code> property is automatically applied to the test case so that it can be distinguished from other test cases that may be run during the same cycle. The two methods in this example are tests methods ( <code>testSomething()</code> and <code>testSomethingElse())</code>, which means that they are methods designed to test a specific piece of functional code. Test methods are indicatd by their name, either using the traditional manner of prepending the word <code>test</code> to the method name, or using a "friendly name," which is a sentence containing the word "should" that describes the test's purpose. For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //friendly test names
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "Something should happen here" : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "Something else should happen here" : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Regardless of the naming convention used for test names, each should contain one or more <a href="#assertions">assertions</a> that test data for validity.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3 id="setup-and-teardown">setUp() and tearDown()</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>As each test method is called, it may be necessary to setup information before it's run and then potentially clean up that information
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove after the test is run. The <code>setUp()</code> method is run before each and every test in the test case and likewise the <code>tearDown()</code> method is run
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove after each test is run. These methods should be used in conjunction to create objects before a test is run and free up memory after the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove test is run. For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove // Setup and tear down
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove setUp : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove this.data = { name : "Nicholas", age : 28 };
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove tearDown : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testName: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual("Nicholas", this.data.name, "Name should be 'Nicholas'");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testAge: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual(28, this.data.age, "Age should be 28");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this example, a <code>setUp()</code> method creates a data object with some basic information. Each property of the data object is checked with
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove a different test, <code>testName()</code> tests the value of <code>data.name</code> while <code>testAge()</code> tests the value of <code>data.age</code>. Afterwards, the data object is deleted
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove to free up the memory. Real-world implementations will have more complex tests, of course, but they should follow the basic pattern you see in the above code.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p><strong>Note: </strong>Both <code>setUp()</code> and <code>tearDown()</code> are optional methods and are only used when defined.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3 id="ignoring">Ignoring Tests</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There may be times when you want to ignore a test (perhaps the test is invalid for your purposes or the functionality is being re-engineered and so it shouldn't be tested at this time). To specify tests to ignore,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove use the <code>_should.ignore</code> property and name each test to skip as a property whose value is set to <code>true</code>:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove // Special instructions
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testName: true //ignore this test
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove // Setup and tear down
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove setUp : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove this.data = { name : "Nicholas", age : 28 };
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove tearDown : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testName: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual("Nicholas", this.data.name, "Name should be 'Nicholas'");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testAge: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual(28, this.data.age, "Age should be 28");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Here the <code>testName()</code> method will be ignored when the test case is run. This is accomplished by first defining the special <code>_should</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove property and within it, an <code>ignore</code> property. The ignore property is an object containing name-value pairs representing the names of the tests
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove to ignore. By defining a property named "testName" and setting its value to <code>true</code>, it says that the method named "testName"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove should not be executed.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3 id="intentional-errors">Intentional Errors</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There may be a time that a test throws an error that was expected. For instance, perhaps you're testing a function that should throw an error if invalid data
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove is passed in. A thrown error in this case can signify that the test has passed. To indicate that
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove a test should throw an error, use the <code>_should.error</code> property. For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovefunction sortArray(array) {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove if (array instanceof Array){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove throw new TypeError("Expected an array");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove // Special instructions
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSortArray: true //this test should throw an error
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSortArray: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove sortArray(12); //this should throw an error
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this example, a test case is created to test the standalone <code>sortArray()</code> function, which simply accepts an array and calls its <code>sort()</code> method.
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove But if the argument is not an array, an error is thrown. When <code>testSortArray()</code> is called, it throws an error because a number is passed into <code>sortArray()</code>.
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Since the <code>_should.error</code> object has a property called "testSortArray" set to <code>true</code>, this indicates that <code>testSortArray()</code> should
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove pass only if an error is thrown.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>It is possible to be more specific about the error that should be thrown. By setting a property in <code>_should.error</code> to a string, you can
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove specify that only a specific error message can be construed as a passed test. Here's an example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovefunction sortArray(array) {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove if (array instanceof Array){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove throw new TypeError("Expected an array");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove // Special instructions
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSortArray: "Expected an array"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSortArray: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove sortArray(12); //this should throw an error
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this example, the <code>testSortArray()</code> test will only pass if the error that is thrown has a message of "Expected an array".
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove If a different error occurs within the course of executing <code>testSortArray()</code>, then the test will fail due to an unexpected error.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>If you're unsure of the message but know the type of error that will be thrown, you can specify the error constructor for the error
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove you're expecting to occur:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovefunction sortArray(array) {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove if (array instanceof Array){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove throw new TypeError("Expected an array");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove // Special instructions
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSortArray: TypeError
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSortArray: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove sortArray(12); //this should throw an error
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this example, the test will pass if a <code>TypeError</code> gets thrown; if any other type of error is thrown,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the test will fail. A word of caution: <code>TypeError</code> is the most frequently thrown error by browsers,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove so specifying a <code>TypeError</code> as expected may give false passes.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>To narrow the margin of error between checking for an error message and checking the error type, you can create a specific error
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove object and set that in the <code>_should.error</code> property, such as:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovefunction sortArray(array) {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove if (array instanceof Array){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove throw new TypeError("Expected an array");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove // Special instructions
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSortArray: new TypeError("Expected an array")
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSortArray: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove sortArray(12); //this should throw an error
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Using this code, the <code>testSortArray()</code> method will only pass if a <code>TypeError</code> object is thrown with a message of
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "Expected an array"; if any other type of error occurs, then the test fails due to an unexpected error.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p><strong>Note: </strong>If a test is marked as expecting an error, the test will fail unless that specific error is thrown. If the test completes without an error being thrown, then it fails.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h2 id="assertions">Assertions</h2>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Test methods use assertions to check the validity of a particular action or function. An assertion method tests (asserts) that a condition is valid; if not, it throws an error that causes the test to fail. If all assertions pass within a test method, it is said that the test has passed. The simplest assertion is <code>Y.assert()</code>, which takes two arguments: a condition to test and a message. If the condition is <em>not</em> true, then an assertion error is thrown with the specified message. For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testUsingAsserts : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.assert(value == 5, "The value should be five.");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.assert(flag, "Flag should be true.");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this example, <code>testUsingAsserts()</code> will fail if <code>value</code> is not equal to 5 of <code>flag</code> is not set to <code>true</code>. The <code>Y.assert()</code> method may be all that you need, but there are advanced options available. The <code>Y.Assert</code> object contains several assertion methods that can be used to validate data.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3 id="equality">Equality Assertions</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The simplest assertions are <code>areEqual()</code> and <code>areNotEqual()</code>. Both methods accept three arguments: the expected value,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the actual value, and an optional failure message (a default one is generated if this argument is omitted). For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testEqualityAsserts : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual(5, 5); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual(5, "5"); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual(5, 6, "Five was expected."); //fails
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>These methods use the double equals (<code>==</code>) operator to determine if two values are equal, so type coercion may occur. This means
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove that the string <code>"5"</code> and the number <code>5</code> are considered equal because the double equals sign converts the number to
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove a string before doing the comparison. If you don't want values to be converted for comparison purposes, use the sameness assertions instead.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3 id="sameness">Sameness Assertions</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The sameness assertions are <code>areSame()</code> and <code>areNotSame()</code>, and these accept the same three arguments as the equality
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove assertions: the expected value, the actual value, and an optional failure message. Unlike the equality assertions, these methods use
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the triple equals operator (<code>===</code>) for comparisions, assuring that no type coercion will occur. For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSamenessAsserts : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areSame(5, 5); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areSame(5, "5"); //fails
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areNotSame(5, "5"); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areSame(5, 6, "Five was expected."); //fails
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p><strong>Note: </strong>Even though this example shows multiple assertions failing, a test will stop as soon as one
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove assertion fails, causing all others to be skipped.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3 id="datatypes">Data Type Assertions</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There may be times when some data should be of a particular type. To aid in this case, there are several methods that test the data type
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove of variables. Each of these methods acce<prepts two arguments: the data to test and an optional failure message. The data type assertions are as
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove follows:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isArray()</code> - passes only if the value is an instance of <code>Array</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isBoolean()</code> - passes only if the value is a Boolean.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isFunction()</code> - passes only if the value is a function.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isNumber()</code> - passes only if the value is a number.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isObject()</code> - passes only if the value is an object or a function.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isString()</code> - passes only if the value is a string.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>These are used as in the following example: </p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testDataTypeAsserts : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isString("Hello world"); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isFunction(function(){}); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isBoolean(true); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isObject(function(){}); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isNumber("1", "Value should be a number."); //fails
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isString(1, "Value should be a string."); //fails
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In addition to these specific data type assertions, there are two generic data type assertions.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The <code>isTypeOf()</code> method tests the string returned when the <code>typeof</code> operator is applied to a value. This
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove method accepts three arguments: the type that the value should be ("string", "number",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "boolean", "undefined", "object", or "function"), the value to test, and an optional failure message.
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testTypeOf : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf("string", "Hello world"); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf("number", 1); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf("boolean", true); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf("number", 1.5); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf("function", function(){}); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf("object", {}); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf("undefined", this.blah); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf("number", "Hello world", "Value should be a number."); //fails
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>If you need to test object types instead of simple data types, you can also use the <code>isInstanceOf()</code> assertion, which accepts three
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove arguments: the constructor function to test for, the value to test, and an optional failure message. This assertion uses the <code>instanceof</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove operator to determine if it should pass or fail. Example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testInstanceOf : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isInstanceOf(Object, {}); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isInstanceOf(Array, []); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isInstanceOf(Object, []); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isInstanceOf(Function, function(){}); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isInstanceOf(Object, function(){}); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTypeOf(Array, {}, "Value should be an array."); //fails
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3 id="specialvalues">Special Value Assertions</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There are numerous special values in JavaScript that may occur in code. These include <code>true</code>, <code>false</code>, <code>NaN</code>,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>null</code>, and <code>undefined</code>. There are a number of assertions designed to test for these values specifically:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isFalse()</code> - passes if the value is <code>false</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isTrue()</code> - passes if the value is <code>true</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isNaN()</code> - passes if the value is <code>NaN</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isNotNaN()</code> - passes if the value is not <code>NaN</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isNull()</code> - passes if the value is <code>null</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isNotNull()</code> - passes if the value is not <code>null</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isUndefined()</code> - passes if the value is <code>undefined</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>isNotUndefined()</code> - passes if the value is not <code>undefined</code>.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Each of these methods accepts two arguments: the value to test and an optional failure message. All of the assertions expect the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove exact value (no type coercion occurs), so for example calling <code>isFalse(0)</code> will fail.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSpecialValues : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isFalse(false); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isTrue(true); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isNaN(NaN); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isNaN(5 / "5"); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isNull(null); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isNotNull(undefined); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isUndefined(undefined); //passes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.isUndefined({}, "Value should be undefined."); //fails
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3 id="forcedfailures">Forced Failures</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>While most tests fail as a result of an assertion, there may be times when
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove you want to force a test to fail or create your own assertion method. To do this, use the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>fail()</code> method to force a test method to fail immediately:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testForceFail : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.fail(); //causes the test to fail
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this case, the <code>testForceFail()</code> method does nothing but force
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the method to fail. Optionally, you can pass in a message to <code>fail()</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove which will be displayed as the failure message:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testForceFail : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.fail("I decided this should fail.");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>When the failure of this method is reported, the message "I decided this should fail." will be reported.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h2 id="mockobjects">Mock Objects</h2>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Mock objects are used to eliminate test dependencies on other objects. In complex software systems, there's often multiple
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove object that have dependence on one another to do their job. Perhaps part of your code relies on the <code>XMLHttpRequest</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove object to get more information; if you're running the test without a network connection, you can't really be sure if the test
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove is failing because of your error or because the network connection is down. In reality, you just want to be sure that the correct
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove data was passed to the <code>open()</code> and <code>send()</code> methods because you can assume that, after that point,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the <code>XMLHttpRequest</code> object works as expected. This is the perfect case for using a mock object.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>To create a mock object, use the <code>Y.Mock()</code> method to create a new object and then use <code>Y.Mock.expect()</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove to define expectations for that object. Expectations define which methods you're expecting to call, what the arguments should be,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove and what the expected result is. When you believe all of the appropriate methods have been called, you call <code>Y.Mock.verify()</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove on the mock object to check that everything happened as it should. For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//code being tested
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovefunction logToServer(message, xhr){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove xhr.open("get", "/log.php?msg=" + encodeURIComponent(message), true);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//test case for testing the above function
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "logToServer Tests",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testPassingDataToXhr : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove var mockXhr = Y.Mock();
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //I expect the open() method to be called with the given arguments
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove method: "open",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove args: ["get", "/log.php?msg=hi", true]
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //I expect the send() method to be called with the given arguments
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove method: "send",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove args: [null]
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //now call the function
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove logToServer("hi", mockXhr);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //verify the expectations were met
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this code, a mock <code>XMLHttpRequest</code> object is created to aid in testing. The mock object defines two
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove expectations: that the <code>open()</code> method will be called with a given set of arguments and that the <code>send()</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove method will be called with a given set of arguments. This is done by using <code>Y.Mock.expect()</code> and passing in the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove mock object as well as some information about the expectation. The <code>method</code> property indicates the method name
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove that will be called and the <code>args</code> property is an array of arguments that should be passed into the method. Each
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove argument is compared against the actual arguments using the identically equal (<code>===</code>) operator, and if any of the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove arguments doesn't match, an assertion failure is thrown when the method is called (it "fails fast" to allow easier debugging).</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The call to <code>Y.Mock.verify()</code> is the final step in making sure that all expectations have been met. It's at this stage
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove that the mock object checks to see that all methods have been called. If <code>open()</code> was called but <code>send()</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove was not, then an assertion failure is thrown and the test fails. It's very important to call <code>Y.Mock.verify()</code> to test
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove all expectations; failing to do so can lead to false passes when the test should actually fail.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In order to use mock objects, your code must be able to swap in and out objects that it uses. For example, a hardcoded
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove reference to <code>XMLHttpRequest</code> in your code would prevent you from using a mock object in its place. It's sometimes
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove necessary to refactor code in such a way that referenced objects are passed in rather than hardcoded so that mock objects
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove can be used.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Note that you can use assertions and mock objects together; either will correctly indicate a test failure.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>Special Argument Values</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There may be times when you don't necessarily care about a specific argument's value. Since you must always specify the correct
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove number of arguments being passed in, you still need to indicate that an argument is expected. There are several special values
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove you can use as placeholders for real values. These values do a minimum amount of data validation:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Mock.Value.Any</code> - any value is valid regardless of type.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Mock.Value.String</code> - any string value is valid.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Mock.Value.Number</code> - any number value is valid.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Mock.Value.Boolean</code> - any Boolean value is valid.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Mock.Value.Object</code> - any non-<code>null</code> object value is valid.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Mock.Value.Function</code> - any function value is valid.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Each of these special values can be used in the <code>args</code> property of an expectation, such as:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove method: "open",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove args: [Y.Mock.Value.String, "/log.php?msg=hi", Y.Mock.Value.Boolean]
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The expecation here will allow any string value as the first argument and any Boolean value as the last argument.
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove These special values should be used with care as they can let invalid values through if they are too general. The
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>Y.Mock.Value.Any</code> special value should be used only if you're absolutely sure that the argument doesn't
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>Property Expectations</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Since it's not possible to create property getters and setters in all browsers, creating a true cross-browser property
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove expectation isn't feasible. YUI Test mock objects allow you to specify a property name and it's expected value when
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>Y.Mock.verify()</code> is called. This isn't a true property expectation but rather an expectation that the property
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove will have a certain value at the end of the test. You can specify a property expectation like this:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//expect that the status property will be set to 404
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove property: "status",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>This example indicates that the <code>status</code> property of the mock object should be set to 404 before
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the test is completed. When <code>Y.Mock.verify()</code> is called on <code>mockXhr</code>, it will check
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the property and throw an assertion failure if it has not been set appropriately.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h2 id="asynctests">Asynchronous Tests</h2>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>YUI Test allows you to pause a currently running test and resume either after a set amount of time or
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove at another designated time. The <code>TestCase</code> object has a method called <code>wait()</code>. When <code>wait()</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove is called, the test immediately exits (meaning that any code after that point will be ignored) and waits for a signal to resume
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the test.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>A test may be resumed after a certain amount of time by passing in two arguments to <code>wait()</code>: a function to execute
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove and the number of milliseconds to wait before executing the function (similar to using <code>setTimeout()</code>). The function
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove passed in as the first argument will be executed as part of the current test (in the same scope) after the specified amount of time.
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove // Setup and tear down
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove setUp : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove this.data = { name : "Nicholas", age : 29 };
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove tearDown : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testAsync: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual("Nicholas", this.data.name, "Name should be 'Nicholas'");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //wait 1000 milliseconds and then run this function
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual(29, this.data.age, "Age should be 29");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this code, the <code>testAsync()</code> function does one assertion, then waits 1000 milliseconds before performing
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove another assertion. The function passed into <code>wait()</code> is still in the scope of the original test, so it has
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove access to <code>this.data</code> just as the original part of the test does. Timed waits are helpful in situations when
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove there are no events to indicate when the test should resume.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>If you want a test to wait until a specific event occurs before resuming, the <code>wait()</code> method can be called
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove with a timeout argument (the number of milliseconds to wait before considering the test a failure). At that point, testing will resume only when the <code>resume()</code> method is called. The
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>resume()</code> method accepts a single argument, which is a function to run when the test resumes. This function
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove should specify additional assertions. If <code>resume()</code> isn't called before the timeout expires, then the test fails. The following tests to see if the <code>Anim</code> object has performed its
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove animation completely:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar testCase = new Y.Test.Case({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "TestCase Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //---------------------------------------------
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testAnimation : function (){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //animate width to 400px
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove var myAnim = new Y.Anim({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove node: '#testDiv',
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove var test = this;
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //assign oncomplete handler
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove myAnim.on("end", function(){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //tell the TestRunner to resume
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove Y.Assert.areEqual(myAnim.get("node").get("offsetWidth"), 400, "Width of the DIV should be 400.");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //start the animation
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //wait until something happens
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this example, an <code>Anim</code> object is used to animate the width of an element to 400 pixels. When the animation
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove is complete, the <code>end</code> event is fired, so that is where the <code>resume()</code> method is called. The
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove function passed into <code>resume()</code> simply tests that the final width of the element is indeed 400 pixels. Once the event handler is set up, the animation begins.
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove In order to allow enough time for the animation to complete, the <code>wait()</code> method is called
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove with a timeout of 3.1 seconds (just longer than the 3 seconds needed to complete the animation). At that point, testing stops until the animation completes and <code>resume()</code> is called or until 3100 milliseconds have passed.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h2 id="testsuites">Test Suites</h2>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>For large web applications, you'll probably have many test cases that should be run during a testing phase. A test suite helps to handle multiple test cases
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove by grouping them together into functional units that can be run together. To create new test suite, use the <code>Y.Test.Suite</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove constructor and pass in the name of the test suite. The name you pass in is for logging purposes and allows you to discern which <code>TestSuite</code> instance currently running. For example: </p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//create the test suite
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar suite = new Y.Test.Suite("TestSuite Name");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//add test cases
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Here, a test suite is created and three test cases are added to it using the <code>add()</code> method. The test suite now contains all of the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove information to run a series of tests.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>It's also possible to add other multiple <code>TestSuite</code> instances together under a parent <code>TestSuite</code> using the same <code>add()</code> method:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//create a test suite
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar suite = new Y.Test.Suite("TestSuite Name");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//add a test case
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//create another suite
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar anotherSuite = new Y.Test.Suite("test_suite_name");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//add a test case
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//add the second suite to the first
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovesuite.add(anotherSuite);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>By grouping test suites together under a parent test suite you can more effectively manage testing of particular aspects of an application.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Test suites may also have <code>setUp()</code> and <code>tearDown()</code> methods. A test suite's <code>setUp()</code> method is called before
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the first test in the first test case is executed (prior to the test case's <code>setUp()</code> method); a test suite's <code>tearDown()</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove method executes after all tests in all test cases/suites have been executed (after the last test case's <code>tearDown()</code> method). To specify
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove these methods, pass an object literal into the <code>Y.Test.Suite</code> constructor:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//create a test suite
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar suite = new Y.Test.Suite({
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name : "TestSuite Name",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove setUp : function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //test-suite-level setup
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove tearDown: function () {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //test-suite-level teardown
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Test suite <code>setUp()</code> and <code>tearDown()</code> may be helpful in setting up global objects that are necessary for a multitude of tests
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove and test cases.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h2 id="running-tests">Running Tests</h2>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In order to run test cases and test suites, use the <code>Y.Test.Runner</code> object. This object is a singleton that
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove simply runs all of the tests in test cases and suites, reporting back on passes and failures. To determine which test cases/suites
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove will be run, add them to the <code>Y.Test.Runner</code> using the <code>add()</code> method. Then, to run the tests, call the <code>run()</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//add the test cases and suites
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove//run all tests
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>If at some point you decide not to run the tests that have already been added to the <code>TestRunner</code>, they can be removed by calling <code>clear()</code>:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Making this call removes all test cases and test suites that were added using the <code>add()</code> method.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>TestRunner Events</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The <code>Y.Test.Runner</code> provides results and information about the process by publishing several events. These events can occur at four
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove different points of interest: at the test level, at the test case level, at the test suite level, and at the <code>Y.Test.Runner</code> level.
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove The data available for each event depends completely on the type of event and the level at which the event occurs.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>Test-Level Events</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Test-level events occur during the execution of specific test methods. There are three test-level events:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.TEST_PASS_EVENT</code> - occurs when the test passes.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.TEST_FAIL_EVENT</code> - occurs when the test fails.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.TEST_IGNORE_EVENT</code> - occurs when a test is ignored.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>For each of these events, the event data object has three properties:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>type</code> - indicates the type of event that occurred.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>testCase</code> - the test case that is currently being run.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>testName</code> - the name of the test that was just executed or ignored.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>For <code>Y.Test.Runner.TEST_FAIL_EVENT</code>, an <code>error</code> property containing the error object
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove that caused the test to fail.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>TestCase-Level Events</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There are two events that occur at the test case level:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.TEST_CASE_BEGIN_EVENT</code> - occurs when the test case is next to be executed but before the first test is run.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.TEST_CASE_COMPLETE_EVENT</code> - occurs when all tests in the test case have been executed or ignored.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>For these two events, the event data object has three properties:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>type</code> - indicates the type of event that occurred.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>testCase</code> - the test case that is currently being run.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>For <code>TEST_CASE_COMPLETE_EVENT</code>, an additional property called <code>results</code> is included. The <code>results</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove property is an object containing the aggregated results for all tests in the test case (it does not include information about tests that
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove were ignored). Each test that was run has an entry in the <code>result</code> object where the property name is the name of the test method
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove and the value is an object with two properties: <code>result</code>, which is either "pass" or "fail", and <code>message</code>, which is a
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove text description of the result (simply "Test passed" when a test passed or the error message when a test fails). Additionally, the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>failed</code> property indicates the number of tests that failed in the test case, the <code>passed</code> property indicates the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove number of tests that passed, and the <code>total</code> property indicates the total number of tests executed. A typical <code>results</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove object looks like this:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testcase",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "Test Case 0",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Test passed",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test0"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "fail",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Assertion failed",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test1"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The <code>TEST_CASE_COMPLETE_EVENT</code> provides this information for transparency into the testing process.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>TestSuite-Level Events</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There are two events that occur at the test suite level:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.TEST_SUITE_BEGIN_EVENT</code> - occurs when the test suite is next to be executed but before the first test is run.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.TEST_SUITE_COMPLETE_EVENT</code> - occurs when all tests in all test cases in the test suite have been executed or ignored.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>For these two events, the event data object has three properties:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>type</code> - indicates the type of event that occurred.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>testSuite</code> - the test suite that is currently being run.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The <code>TEST_SUITE_COMPLETE_EVENT</code> also has a <code>results</code> property, which contains aggregated results for all of the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove test cases (and other test suites) it contains. Each test case and test suite contained within the main suite has an entry in the
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>results</code> object, forming a hierarchical structure of data. A typical <code>results</code> object may look like this:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testsuite",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "Test Suite 0",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testCase0: {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testcase",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "testCase0",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Test passed."
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test0"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "fail",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Assertion failed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test1"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testCase1: {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testcase",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "testCase1",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test0"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "fail",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Assertion failed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test1"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>This example shows the results for a test suite with two test cases, but there may be test suites contained within test suites. In that case,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the hierarchy is built out accordingly, for example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testsuite",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "Test Suite 0",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testCase0: {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testcase",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "testCase0",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test0"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "fail",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Assertion failed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test1"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testCase1: {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testcase",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "testCase1",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test0"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "fail",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Assertion failed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test1"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testSuite0:{
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testsuite",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "testSuite0",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove testCase2: {
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "testcase",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "testCase2",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test0"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove result: "fail",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove message: "Assertion failed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove type: "test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove name: "test1"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this code, the test suite contained another test suite named "testSuite0", which is included in the results along
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove with its test cases. At each level, the results are aggregated so that you can tell how many tests passed or failed within each
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove test case or test suite.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>TestRunner-Level Events</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There are two events that occur at the <code>Y.Test.Runner</code> level:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.BEGIN_EVENT</code> - occurs when testing is about to begin but before any tests are run.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Runner.COMPLETE_EVENT</code> - occurs when all tests in all test cases and test suites have been executed or ignored.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The data object for these events contain a <code>type</code> property, indicating the type of event that occurred. <code>COMPLETE_EVENT</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove also includes a <code>results</code> property that is formatted the same as the data returned from <code>TEST_SUITE_COMPLETE_EVENT</code> and
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove contains rollup information for all test cases and tests suites that were added to the <code>TestRunner</code>.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>Subscribing to Events</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>You can subscribe to particular events by calling the <code>subscribe()</code> method. Your event handler code
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove should expect a single object to be passed in as an argument. This object provides information about the event that just occured. Minimally,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the object has a <code>type</code> property that tells you which type of event occurred. Example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovefunction handleTestFail(data){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove alert("Test named '" + data.testName + "' failed with message: '" + data.error.message + "'.");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar TestRunner = Y.Test.Runner;
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan GroveTestRunner.subscribe(TestRunner.TEST_FAIL_EVENT, handleTestFail);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>In this code, the <code>handleTestFail()</code> function is assigned as an event handler for <code>TEST_FAIL_EVENT</code>. You can also
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove use a single event handler to subscribe to any number of events, using the event data object's <code>type</code> property to determine
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove what to do:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovefunction handleTestResult(data){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove var TestRunner = Y.Test.Runner;
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove alert("Test named '" + data.testName + "' failed with message: '" + data.error.message + "'.");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove alert("Test named '" + data.testName + "' passed.");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove alert("Test named '" + data.testName + "' was ignored.");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan GroveTestRunner.subscribe(TestRunner.TEST_FAIL_EVENT, handleTestResult);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan GroveTestRunner.subscribe(TestRunner.TEST_IGNORE_EVENT, handleTestResult);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan GroveTestRunner.subscribe(TestRunner.TEST_PASS_EVENT, handleTestResult);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h2 id="viewing-results">Viewing Results</h2>
1ac6d38f8eef642ee4f7191b863a986f4cb7571fDav Glass <p>There are two ways to view test results. The first is to output test results to the TestConsole
1ac6d38f8eef642ee4f7191b863a986f4cb7571fDav Glass component. To do so, you need only create a new `Test.Console` instance; the result results will be posted
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove to the logger automatically:</p>
1ac6d38f8eef642ee4f7191b863a986f4cb7571fDav GlassYUI({ logInclude: { TestRunner: true } }).use('test-console', "test", function(Y){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //tests go here
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //initialize the console
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove newestOnTop: false
1ac6d38f8eef642ee4f7191b863a986f4cb7571fDav Glass })).render('#log');
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //run the tests
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>If you are using a browser that supports the <code>console</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove object (Firefox with Firebug installed, Safari 3+, Internet Explorer 8+, Chrome), then you can
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove direct the test results onto the console. To do so, make sure that you've specified your <code>YUI</code>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove instance to use the console when logging:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan GroveYUI({ useBrowserConsole: true }).use("test", function(Y){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //tests go here
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>You can also extract the test result data using the <code>Y.Test.Runner.getResults()</code> method. By default, this method
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove returns an object representing the results of the tests that were just run (the method returns <code>null</code> if called
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove while tests are still running). You can optionally specify a format in which the results should be returned. There are four
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove possible formats:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Format.XML</code> - YUI Test XML (default)</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Format.JSON</code> - JSON</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Format.JUnitXML</code> - JUnit XML</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Format.TAP</code> - <a href="http://testanything.org/">TAP</a></li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>You can pass any of these into <code>Y.Test.Runner.getResults()</code> to get a string with the test result information properly
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove formatted. For example:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan GroveYUI({ useBrowserConsole: true }).use("test", function(Y){
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //tests go here
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //get object of results
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove var resultsObject = Y.Test.Runner.getResults();
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove //get XML results
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove var resultsXML = Y.Test.Runner.getResults(Y.Test.Format.XML);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The XML format outputs results in the following
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove<?xml version="1.0" encoding="UTF-8" ?>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove<report name="YUI Test Results" passed="5" failed="3" ignored="1" total="5">
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <testsuite name="yuisuite" passed="5" failed="0" ignored="0" total="5">
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <testcase name="Y.Anim" passed="5" failed="0" ignored="0" total="5">
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <test name="test_getEl" result="pass" message="Test passed" />
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <test name="test_isAnimated" result="pass" message="Test passed" />
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <test name="test_stop" result="pass" message="Test passed" />
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <test name="test_onStart" result="pass" message="Test passed" />
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <test name="test_endValue" result="pass" message="Test passed" />
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove </testsuite>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The JSON format requires the <a href="../json/index.html">JSON utility</a> to be loaded on the page and outputs results in a format that follows the object/array hierarchy of the results object, such as:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "passed": 5,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "failed": 0,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "ignored": 0,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "type": "report",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "name": "YUI Test Results",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "yuisuite":{
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "passed": 5,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "failed": 0,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "ignored": 0,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "type": "testsuite",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "name": "yuisuite",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "passed": 5,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "failed": 0,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "ignored": 0,
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "type":"testcase",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "test_getEl":{
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "result":"pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "message":"Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "type":"test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "name":"test_getEl"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "test_isAnimated":{
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "result":"pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "message":"Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "type":"test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "name":"test_isAnimated"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "test_stop":{
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "result":"pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "message":"Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "type":"test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "name":"test_stop"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "test_onStart":{
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "result":"pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "message":"Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "type":"test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "name":"test_onStart"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "test_endValue":{
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "result":"pass",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "message":"Test passed.",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "type":"test",
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove "name":"test_endValue"
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove<p>The JUnit XML format outputs results in the following format:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove<?xml version="1.0" encoding="UTF-8" ?>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <testsuite name="Y.Anim" failures="0" total="5" time="0.0060">
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <testcase name="test_getEl" time="0.0"></testcase>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <testcase name="test_isAnimated" time="0.0010"></testcase>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <testcase name="test_stop" time="0.0010"></testcase>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <testcase name="test_onStart" time="0.0010"></testcase>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <testcase name="test_endValue" time="0.0010"></testcase>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove </testsuite>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove</testsuites>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove<p>Note that there isn't a direct mapping between YUI Test test suites and JUnit test suites, so some
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Groveof the hierarchical information is lost.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove<p>The TAP format outputs results in the following format:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove```nohighlight
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove#Begin report YUI Test Results (0 failed of 5)
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove#Begin testcase Y.Anim (0 failed of 5)
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Groveok 1 - testGetServiceFromUntrustedModule
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Groveok 2 - testGetServiceFromTrustedModule
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Groveok 3 - testGetServiceFromService
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Groveok 4 - testGetServiceMultipleTimesFromService
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Groveok 5 - testGetServiceMultipleTimesFromUntrustedModule
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove#End testcase Y.Anim
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove#End report YUI Test Results
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The XML, JSON, and JUnit XML formats produce a string with no extra white space (white space and indentation shown here is for readability
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove purposes only).</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h2 id="test-reporting">Test Reporting</h2>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>When all tests have been completed and the results object has been returned, you can post those results to a server
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove using a <code>Y.Test.Reporter</code> object. A <code>Y.Test.Reporter</code> object creates a form that is POSTed
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove to a specific URL with the following fields:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>results</code> - the serialized results object.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>useragent</code> - the user-agent string of the browser.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>timestamp</code> - the date and time that the report was sent.</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>You can create a new <code>Y.Test.Reporter</code> object by passing in the URL to report to. The results object can
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove then be passed into the <code>report()</code> method to submit the results:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar reporter = new Y.Test.Reporter("http://www.yourserver.com/path/to/target");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The form submission happens behind-the-scenes and will not cause your page to navigate away. This operation is
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove one direction; the reporter does not get any content back from the server.</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>There are four predefined serialization formats for results objects: </p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Format.XML</code> (default)</li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Format.JSON</code></li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Format.JUnitXML</code></li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <li><code>Y.Test.Format.TAP</code></li>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>The format in which to submit the results can be specified in the <code>Y.Test.Reporter</code> constructor by passing in the appropriate
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <code>Y.Test.Format</code> value (when no argument is specified, <code>Y.Test.Format.XML</code> is used:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovevar reporter = new Y.Test.Reporter("http://www.yourserver.com/path/to/target", Y.Test.Format.JSON);
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <h3>Custom Fields</h3>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>You can optionally specify additional fields to be sent with the results report by using the <code>addField()</code> method.
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove This method accepts two arguments: a name and a value. Any field added using <code>addField()</code> is POSTed along with
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the default fields back to the server:</p>
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovereporter.addField("color", "blue");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grovereporter.addField("message", "Hello world!");
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove <p>Note that if you specify a field name that is the same as a default field, the custom field is ignored in favor of
1b7d9ee6f1128c8cb5e16c3a11ba045998296171Ryan Grove the default field.</p>