Nickolay - Test.Run-0.06

Documentation | Source

Name

Test.Run.Result - Abstract base class for individual result in test file

DESCRIPTION

Test.Run.Result is an abstract base class, representint individual result in test file. Its not supposed to be created manually, instead, the various methods of Test.Run.Test will create it for you.

ISA

Joose.Meta.Object

DOES

None

ATTRIBUTES

description

String description

Description of the result

METHODS

toString

String toString()

return string presentation of this result. Defaults to value of description property

SEE ALSO

Test.Run.Result.Diagnostic

Test.Run.Result.Assertion

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Name

Test.Run.Result.Diagnostic - Subclass of Test.Run.Result representing a result of diagnostic message

DESCRIPTION

Test.Run.Result.Diagnostic is not supposed to be created manually, instead, the diag method of Test.Run.Test will create it for you.

ISA

Test.Run.Result

DOES

None

SEE ALSO

Test.Run.Result.Assertion

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Name

Test.Run.Result.Assertion - Subclass of Test.Run.Result representing a result of assertion check

DESCRIPTION

Test.Run.Result.Assertion is not supposed to be created manually, instead, the various methods of Test.Run.Test will create it for you.

ISA

Test.Run.Result

DOES

None

ATTRIBUTES

pass

Boolean pass

Pass/fail sign

indx

Number indx

The index of this result in the results queue

METHODS

toString

String toString()

return TAP presentation of the assertion

SEE ALSO

Test.Run.Result.Diagnostic

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Name

Test.Run.Test - Base class for individual test file

SYNOPSIS

    t.plan(1)


    t.ok(1 == 1, 'Indeed')
    t.is(2 * 2, '4', 'Indeed')

    t.pass('Some assertion is correct')

DESCRIPTION

Test.Run.Test is a base testing class in Test.Run hierarchy. Its not supposed to be created manually, instead, the harness will create it for you.

This is a very base class, determining mostly the interface for the test object, its subclasses implements more useful assertion checks. See Test.Run.Test.Browser and Test.Run.Test.More

ISA

Joose.Meta.Object

DOES

Test.Run.Test.More

USAGE

Below is the list of methods, intended for usage in the individual tests.

plan

void plan(Number tests)

This method setups test's plan. It should be called before any assertions were checked.

tests - a number of planned assertions in this test file.

diag

void diag(String text)

This method add the diagnostic message into results queue. The actual presentation logic of the message is delegated to harness.

text - The text of diagnostic message

pass

void pass(String text)

This method add the passed assertion into results queue. The actual presentation logic of the passed assertion is delegated to harness.

text - The text of the assertion

fail

void fail(String text)

This method add the failed assertion into results queue. The actual presentation logic of the passed assertion is delegated to harness.

text - The text of the assertion

ok

void ok(Boolean condition, String text)

This method add the passed or failed assertion into results queue. The type of assertion to add is determined from 1st argument.

condition - The boolean condition, indicating wheter assertions is passed or failed

text - The text of the assertion

is

void is(Object value1, Object value2, String text)

This method add the passed or failed assertion into results queue. The type of assertion to add is determined from comparison of 1st and 2nd arguments. Comparison is performed with '==' operator

value1 - The 1st value for comparison

value2 - The 2nd value for comparison

text - The text of the assertion

ATTRIBUTES

url

String url

Url of the test file.

assertPlanned

Number assertPlanned

Planned number of assertions to test.

assertCount

Number assertCount

Current number of processed assertions (not includes the diagnostic messages).

diagCount

Number diagCount

Current number of processed diagnostic messages.

passCount

Number passCount

Current number of passed assertions.

failCount

Number failCount

Current number of failed assertions.

results

Test.Run.Result[] results

Array of Test.Run.Result instances (represent either assertion or diagnostic message).

run

Function run

The function, which contain test statements (is invoking with StartTest and will receive the instance of this class (or subclass) as a single argument)

harness

Test.Run.Harness harness

Reference to Test.Run.Harness (or subclass) instance, which represents the harness, under which the test is running.

failed

Boolean failed

The sign whether the test has threw an exception.

failedException

Object failedException

Thrown exception (see also failed)

startDate

Date startDate

Timestamp of test start

execEnd

Date execEnd

Timestamp of test end

topScope

Object topScope

The top scope object in which test function was declared (an iframe or window in which test is running)

passThroughEx

Boolean passThroughEx

The sign whether the test should re-throw any exceptions caught (useful for debugging with FireBug). Defaults to 'false'

METHODS

toString

String toString()

Return string presentation of this test. Defaults to value of 'url' property

addResult

void addResult(Test.Run.Result result)

This method adds the instance of Test.Run.Result to results queue. The result can be either assertion (Test.Run.Result.Assertion) or diagnostic message (Test.Run.Result.Diagnostic)

result - The result instance to add

start

protected void start()

This method starts the test execution. Execution is performing by running the function in the 'run' attribute.

finalize

protected void finalize()

This method is called when the test finished execution. It setup the 'execEnd' attribute

getSummaryMessage

protected String[] getSummaryMessage()

This method returns the summary message for this test. Should be called after the test has finished execution.

isPassed

protected Boolean isPassed()

This method returns the sign whether the whole test passed or failed. The test is considered passed, when a) no exceptions were thrown, b) there is no failing assertions c) the number of passed assertions is greater or equal to planned assertions number.

SEE ALSO

Subclass of this class, intended to run on browser platform: Test.Run.Test.Browser

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Name

Test.Run.Test.More - A role with additional assertion check, which can be used in tests.

SYNOPSIS

        t.plan(3)

        t.diag('Starting..')

        t.like('this', /this/, 'Probably similar things')

        t.unlike('this', 'that', 'Unlikely..')

        t.throws_ok(function(){
            throw "Ups"
        }, /ups/i, 'Ups was thrown correctly :)')

DESCRIPTION

Test.Run.Test.More is a role, consumed by the Test.Run.Test and providing some general-purpose (platform independed) assertions checks.

DOES

None

USAGE

Below is the list of methods, intended for usage in the individual tests.

like

void like(String str, String|RegExp regex, text)

This method add the passed or failed assertion into results queue. The type of assertion to add is determined from testing the passed string (1st argument) against a regular expression (2nd argument)

str - The string to test

regex - The regex against which to test the string, can be also a plain string

text - The text of the assertion

unlike

void unlike(String str, String|RegExp regex, text)

This method is the opposite of 'like', it adds failed assertion, when the string matches the passed regex.

str - The string to test

regex - The regex against which to test the string, can be also a plain string

text - The text of the assertion

throws_ok

void throws_ok(Function func, String|RegExp expected, text)

This method add the passed or failed assertion into results queue. The type of assertion to add is determined from the following: The passed 'func' function is executing, and its expected to throw an exception. Then the exception object is stringified and passed to 'like' method along with 'expected' parameter.

func - The function which supposed to throw an exception

expected - The regex against which to test the stringified exception, can be also a plain string

text - The text of the assertion

SEE ALSO

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Name

Test.Run.Test.Browser - Base class for test file, running on the browser platform.

SYNOPSIS

        t.plan(1)

        var async0 = t.beginAsync()

        use('Module.Stub', function () {

            //=========================================
            t.diag('Sanity')

            t.ok(Module.Stub, "Module.Stub is here")

            t.endAsync(async0)
        })

DESCRIPTION

Test.Run.Test.Browser is a base testing class for tests, running on browser. It assumes the presence of setTimeout/clearTimeout functions and provides the ability of asynchornous testsing.

ISA

Test.Run.Test

DOES

None

USAGE

Below is the list of methods, intended for usage in the individual tests.

beginAsync

Number beginAsync(Number? maxTime)

This method starts the "asynchronous frame". The test will not finished, until the frame will not be finished with endAsync call. endAsync will be automatically call after specified maxtime.

maxTime - the maximum time (in ms) to wait until explicitly finalize this async frame.

return - The timeoutId, which can be used in endAsync call

endAsync

void endAsync(Number timeoutId)

This method finalize the "asynchronous frame" started with beginAsync.

timeoutId - The timeoutId, returned by beginAsync call

ATTRIBUTES

timeoutIds

Object timeoutIds

The hash which keep the timeout ids, generated by beginAsync call

finished

Boolean finished

The sign whether this test has finished execution (its 'run' function was executed). Test still may be active, until there are active "asynchronous frames"

SEE ALSO

Additional general-purpose assertions checks: Test.Run.Test.More

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Name

Test.Run.Harness - Abstract base class for test harness

SYNOPSIS

        Test.Run.Harness.Browser.Multi.my.configure({
            title : 'Module.Stub Test Suite',

            passThroughEx : true,

            preload : [
                '/jsan/Task/Joose/Core.js',
                "/jsan/JooseX/SimpleRequest.js",
                '/jsan/Task/JooseX/Namespace/Depended/Web.js',
                {
                    text : "JooseX.Namespace.Depended.Manager.my.INC = " + Ext.encode(INC)
                }
            ]
        })


        Test.Run.Harness.Browser.Multi.my.start(
            '010_sanity.t.js',
            '020_basics.t.js'
        )

DESCRIPTION

Test.Run.Harness is an abstract base harness class in Test.Run hierarchy. This class provides no UI, you should use one of it subclasses, for example Test.Run.Harness.Browser.Multi

This class is a pure static class - it defines only static properties. Please refer to Joose.Manual.Static

ISA

Joose.Meta.Object

DOES

None

USAGE

This section describes the end-user interface of this class.

Methods

configure

void configure(Object options)

This method configure the harness instance. It just copies the passed configuration option into static instance.

options - configuration options (values of attributes for this class, see below for details)

start

void start(String url1, String url2, ...)

This method starts a whole test suite

url1, url2, ... - the variable number of test files urls

Configuration options

passThroughEx

Boolean passThroughEx

The sign whether the each test in suite should re-throw any exceptions caught (useful for debugging with FireBug). Defaults to 'false'. If set to true, exceptions will not be displayed with UI, and should be traced manually.

ATTRIBUTES

This information is intended mostly for authoring Test.Run extensions, and not for end-users.

testClass

Class testClass

The test class which will be used for running tests, defaults to Test.Run.Test.

tests

Test.Run.Test[] tests

The array of all test instances in harness.

testsByURL

Test.Run.Test{} testsByURL

The hash of all test instances in harness, keyed by url attribute.

urls

Object urls

Hash of test files, keyed by url. Also contain arbitrary helper info about the tests.

testsGiven

Number testsGiven

The number of test files, given in 'start'

METHODS

This information is intended mostly for authoring Test.Run extensions, and not for end-users.

testUpdate

void testUpdate(Test.Run.Test test, Test.Run.Result result)

This method is called by the individual tests (instances of Test.Run.Test), each time the it has been updated (new result appeared in results queue). The harness is supposed to provide some UI representation of the update.

test - The test instance which has been updated

result - The results instance which just has been added to the results queue of test

testFail

void testFail(Test.Run.Test test, Object exception)

This method is called by the individual test (instances of Test.Run.Test), each time it has been failed (the exception was thrown). The harness is supposed to provide some UI representation of this event.

test - The test instance which has been failed

exception - The exception thrown

testStart

void testStart(Test.Run.Test test)

This method is called by the individual test (instances of Test.Run.Test), each time the test in the test suite has been started. The harness is supposed to provide some UI representation of this event.

test - The test instance which has been failed

testEnd

void testEnd(Test.Run.Test test)

This method is called by the individual test (instances of Test.Run.Test), each time the test in the test suite has been finished execution. The harness is supposed to provide some UI representation of this event.

test - The test instance which has been finished

testSuiteStart

void testSuiteStart()

This method is called when the whole test suite has been started

testSuiteEnd

void testSuiteEnd()

This method is called when the whole test suite has been finished

testSuiteProcessed

void testSuiteProcessed()

This method is called when the whole test suite was processed. Note that at this point some tests may still running. See also testSuiteEnd

startTest

void startTest(Function func, Class? testClass, Object topScope)

This method starts the execution of a single test file.

func - The function, which contain test statements. The instance of test will be passed to it as 1st argument

testClass - The class which should be used for instantiation of test (defaults to value of 'testClass' attribute)

topScope - The top scope in which this test was declared. This arguments is very important, because it allows the test to correctly catch the exceptions.

recordTest

void recordTest(Test.Run.Test test)

This method records a test into internal structures of harness.

test - The test instance being recorded

removeTest

void removeTest(Test.Run.Test test)

This method removes the test from harness. All necesery cleanup should be done here.

test - The test instance being removed

reRunTest

void reRunTest(Test.Run.Test test)

This method re-runs a single test from harness. Note - passed test instance will be removed and re-created.

test - The test instance being re-ran

reRunSuite

void reRunSuite()

This method re-runs a whole test suite.

processUrl

void processUrl(String url)

This method process a single test file url (it should create the global scope for it and launch the code)

test - The test file url

isPassed

Boolean isPassed()

This method return 'true' if all tests in test suite were passed succefully, 'false' otherwise

isRunning

Boolean isRunning()

This method return 'true' if there is any test in test suite which is still running, 'false' otherwise

SEE ALSO

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Name

Test.Run.Harness.Browser - Abstract base class for test harness

SYNOPSIS

        Test.Run.Harness.Browser.Multi.my.configure({
            title : 'Module.Stub Test Suite',

            passThroughEx : true,

            preload : [
                '/jsan/Task/Joose/Core.js',
                "/jsan/JooseX/SimpleRequest.js",
                '/jsan/Task/JooseX/Namespace/Depended/Web.js',
                {
                    text : "JooseX.Namespace.Depended.Manager.my.INC = " + Ext.encode(INC)
                }
            ]
        })


        Test.Run.Harness.Browser.Multi.my.start(
            '010_sanity.t.js',
            '020_basics.t.js'
        )

DESCRIPTION

Test.Run.Harness.Browser is an abstract harness class in Test.Run hierarchy, providing the methods for running tests on browser platform. This class still provides no UI, you should use one of it subclasses, for example Test.Run.Harness.Browser.Multi

This class is a pure static class - it defines only static properties. Please refer to Joose.Manual.Static

ISA

Test.Run.Harness

DOES

None

USAGE

This section describes the end-user interface of this class.

Configuration options

title

String title

The title of the test suite

disableCaching

Boolean disableCaching

The sign whether the harness should surpress the browser caching for each loading operation. Defaults to 'true'

preload

Object[] preload

The array which contain information about which files should be preloaded into each test's scope. The folloing rules applies during processing of the array:

  1. All string entries starting with '+' are replaced with corresponding components sequence.
  2. If the string entry represent a class name (for example : Test.Run.Test) it is converting to the url, like "../lib/Test/Run/Test.js"
  3. If the string entry ends with ".js", its supposed to be the url and is passing without modifications.
  4. If the entry is an Object with text property, then the value of that property will be evaluted in the test's global scope directly.

Using Components.js

Components.js is a file, which is intended to provide some basic bundling of individual files in your distribution. The purpose of this bundling is mostly to optimize the loading time of the test suites, though its also useful for other things.

Here is an example of this file:

        COMPONENTS = {
            "Core" : [
                "Test.Run.Result",
                "Test.Run.Result.Diagnostic",
                "Test.Run.Result.Assertion",

                "Test.Run.Test",
                "Test.Run.Test.More",
                "Test.Run.Test.Browser",

                "Test.Run.Harness",
                "Test.Run.Harness.Browser",
                "Test.Run.Harness.Browser.Single",

                "Test.Run.Harness.Browser.Proven",


                "Test.Run"
            ],

            "ExtJS" : [
                "+Core",

                "Test.Run.Harness.Browser.UI.Viewport",
                "Test.Run.Harness.Browser.UI.TestGrid",
                "Test.Run.Harness.Browser.UI.AssertionGrid",

                "Test.Run.Harness.Browser.Multi"
            ]
        } 

In this file, we assign the components description to global COMPONENTS variable. This variable will be picked up by harness, and parts of components definition can be used in preload configuration option.

The 1st level entries in the COMPONENTS variable will be the components sequences. They can have arbitrary names, usually corresponding to some deployment blocks of your distribution.

The 2nd level entries should be the arrays with packages names. Or, instead of package, another components sequence can be included, specified with leading + sign.

For additional details on using Components.js file please refer to action task of Module::Build::JSAN::Installable

ATTRIBUTES

This information is intended mostly for authoring Test.Run extensions, and not for end-users.

testClass

Class testClass

The test class which will be used for running tests, defaults to Test.Run.Test.Browser.

isIE

Boolean isIE

'true' if running under MS IE.

baseUrl

String baseUrl

Base url of harness file.

baseHost

String baseHost

Host of the baseUrl.

baseProtocol

String baseProtocol

Protocol of the baseUrl.

METHODS

resolveUrl

String resolveUrl(String url, Boolean onlyResolve)

This method returns the absolutized URL. "Absolutization" is performing against baseUrl property. As an addition, if 'onlyResolve' parameter is 'false' or not passed and disableCaching is set to 'true', the url will be appended with 'disableCaching' query parameter.

url - The url to resolve

onlyResolve - The sign, whether the url should be strictly only absolutized and not appended with disableCaching parameter

customizeIframe

void customizeIframe(DOMObject iframe)

This method is called before appending the created iframe into DOM. Its intented to be overloaded in custom classes and performing additional customization of the iframe.

iframe - The iframe being customizing

SEE ALSO

Web page of this module: http://github.com/SamuraiJack/Module-Stub/

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Name

Test.Run.Harness.Browser.Multi - a harness, which runs into browser and provides an ExtJS based GUI.

SYNOPSIS

        Test.Run.Harness.Browser.Multi.my.configure({
            title : 'Module.Stub Test Suite',

            passThroughEx : true,

            preload : [
                '/jsan/Task/Joose/Core.js',
                "/jsan/JooseX/SimpleRequest.js",
                '/jsan/Task/JooseX/Namespace/Depended/Web.js',
                {
                    text : "JooseX.Namespace.Depended.Manager.my.INC = " + Ext.encode(INC)
                }
            ]
        })


        Test.Run.Harness.Browser.Multi.my.start(
            '010_sanity.t.js',
            '020_basics.t.js'
        )

DESCRIPTION

Test.Run.Harness.Browser.Multi is already not an abstract class and it provides an ExtJS based GUI.

This class is a pure static class - it defines only static properties. Please refer to Joose.Manual.Static

For details on usage of this class please refer to Test.Run.Harness.Browser documentation. This class solely provides a GUI.

ISA

Test.Run.Harness.Browser

DOES

None

ATTRIBUTES

This information is intended mostly for authoring Test.Run extensions, and not for end-users.

viewport

Ext.Viewport viewport

The reference to ExtJS viewport object.

SEE ALSO

Web page of this module: http://github.com/SamuraiJack/Module-Stub/

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/SamuraiJack/Module-Stub/issues

AUTHORS

Nickolay Platonov nplatonov@cpan.org

COPYRIGHT AND LICENSE

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Class('Test.Run.Result', {
    
    have : {
        description : null
    },
    
    
    methods : {
        
        toString : function () {
            return this.description
        }
        
    }
        
})
//eof Test.Run.Result


/**

Name
====


Test.Run.Result - Abstract base class for individual result in test file



DESCRIPTION
===========

`Test.Run.Result` is an abstract base class, representint individual result in test file. 
Its not supposed to be created manually, instead, the various methods of [Test.Run.Test] will create it for you.


ISA
===

[Joose.Meta.Object](http://openjsan.org/go?l=Joose.Meta.Object)


DOES
====

None


ATTRIBUTES
==========

### description

> `String description`

> Description of the result



METHODS
=======

### toString

> `String toString()`

> *return* string presentation of this result. Defaults to value of [description] property 



SEE ALSO
========

[Test.Run.Result.Diagnostic]

[Test.Run.Result.Assertion]

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

        
[Test.Run.Test]: Test.html
[Test.Run.Result.Diagnostic]: Result/Diagnostic.html
[Test.Run.Result.Assertion]: Result/Assertion.html

*/;
Class('Test.Run.Result.Diagnostic', {
    
    isa : Test.Run.Result
    
})


/**

Name
====


Test.Run.Result.Diagnostic - Subclass of [Test.Run.Result] representing a result of diagnostic message


DESCRIPTION
===========

`Test.Run.Result.Diagnostic` is not supposed to be created manually, instead, the `diag` method of [Test.Run.Test] will create it for you.


ISA
===

[Test.Run.Result]


DOES
====

None



SEE ALSO
========

[Test.Run.Result.Assertion]

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

        
[Test.Run.Test]: ../Test.html
[Test.Run.Result]: ../Result.html
[Test.Run.Result.Assertion]: Assertion.html

*/
;
Class('Test.Run.Result.Assertion', {
    
    isa : Test.Run.Result,
    

    have : {
        pass : null,
        
        indx : null
    },
    
    
    methods : {
        
        toString : function () {
            return (this.pass ? 'ok' : 'not ok') + ' ' + this.indx + ' - ' + this.description
        }
        
    }
        
})


/**

Name
====


Test.Run.Result.Assertion - Subclass of [Test.Run.Result] representing a result of assertion check


DESCRIPTION
===========

`Test.Run.Result.Assertion` is not supposed to be created manually, instead, the various methods of [Test.Run.Test] will create it for you.


ISA
===

[Test.Run.Result]


DOES
====

None


ATTRIBUTES
==========

### pass

> `Boolean pass`

> Pass/fail sign



### indx

> `Number indx`

> The index of this result in the results queue


METHODS
=======

### toString

> `String toString()`

> *return* TAP presentation of the assertion 



SEE ALSO
========

[Test.Run.Result.Diagnostic]

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

        
[Test.Run.Test]: ../Test.html
[Test.Run.Result]: ../Result.html
[Test.Run.Result.Diagnostic]: Diagnostic.html

*/
;
Class('Test.Run.Test', {
    
    have : {
        
        url : null,
        
        assertPlanned : null,
        assertCount : 0,
        
        diagCount : 0,
        
        passCount : 0,
        failCount : 0,
        
        results : null,
        
        run : null,
        
        harness : null,
        
        failed : false,
        failedException : null,
        
        startDate : null,
        execEnd : null,
        
        topScope : null,
        
        passThroughEx : false
    },
    
    
    after : {
    
        initialize : function (config) {
//            if (typeof this.run != 'function') throw "The body of test absent"
            
            this.results = []
        }
        
    },
    
    
    methods : {
        
        toString : function() {
            return this.url
        },
        
        
        plan : function (value) {
            if (this.assertPlanned != null) throw "Test plan can't be changed"
            
            this.assertPlanned = value; 
        },
        
        
        addResult : function (result) {
            if (this.assertPlanned == null && this.assertCount) throw "Plan wasn't setuped"
            
            this.results.push(result)
            
            this.harness.testUpdate(this, result)
        },
        
        
        diag : function (desc) {
            this.diagCount++
            
            this.addResult(new Test.Run.Result.Diagnostic({
                description : desc
            }))
        },
        
        
        //XXX pass&fail should be more flexible and overridable (for TODO, SKIP, etc)
        pass : function (desc) {
            this.passCount++
            
            this.addResult(new Test.Run.Result.Assertion({
                pass : true,
                
                description : desc,
                
                indx : ++this.assertCount
            }))
        },
        
        
        fail : function (desc) {
            this.failCount++
            
            this.addResult(new Test.Run.Result.Assertion({
                pass : false,
                
                description : desc,
                
                indx : ++this.assertCount
            }))
        },
        
        
        ok : function (condition, desc) {
            if (condition) this.pass(desc); else this.fail(desc)
        },
        
        
        is : function (got, expected, desc) {
            this.ok(got == expected, desc)
        },

        
        start : function () {
            this.startDate = new Date()
            
            this.harness.testStart(this)
            
            var me = this
            var run = this.run
            
            if (this.passThroughEx)
                run(me)
            else 
                var e = this.topScope.__EXCEPTION_CATCHER__(function(){
                    run(me)
                })
            
            if (e) {
                this.failed = true
                this.failedException = e
                
                this.harness.testFail(this, e)
                
                this.finalize()
                
//                if (this.passThroughEx) throw e
                
                return
            } 
            
            this.finalize()
        },
        
        
        finalize : function () {
            this.execEnd = new Date()
            
            this.harness.testEnd(this)
        },
        
        
        getSummaryMessage : function () {
            var res = []
            
            var passCount = this.passCount
            var failCount = this.failCount
            
            res.push('Passed: ' + passCount)
            res.push('Failed: ' + failCount)
            
            if (!this.failed) {
                if (failCount + passCount < this.assertPlanned) res.push('Looks like you planned ' + this.assertPlanned + ' tests, but ran only ' +  (failCount + passCount))
                if (failCount + passCount > this.assertPlanned) 
                    res.push('Looks like you planned ' + this.assertPlanned + ' tests, but ran ' +  (failCount + passCount - this.assertPlanned) + ' extra tests, ' + (failCount + passCount) + ' total.')
                
                if (passCount == this.assertPlanned && !failCount) res.push('All tests successfull')
            } else {
                res.push('Test suite threw an exception: ' + this.failedException)
            }
            
            return res
        },
        
        
        isPassed : function () {
            return !this.failed && !this.failCount && this.passCount >= this.assertPlanned
        }
        
    }
        
})
//eof Test.Run.Test


/**

Name
====


Test.Run.Test - Base class for individual test file


SYNOPSIS
========

        t.plan(1)
       
       
        t.ok(1 == 1, 'Indeed')
        t.is(2 * 2, '4', 'Indeed')
        
        t.pass('Some assertion is correct')
        


DESCRIPTION
===========

`Test.Run.Test` is a base testing class in Test.Run hierarchy. Its not supposed to be created manually, instead, the harness will create it for you.

This is a very base class, determining mostly the interface for the test object, its subclasses implements more useful assertion checks.
See [Test.Run.Test.Browser] and [Test.Run.Test.More] 


ISA
===

[Joose.Meta.Object](http://openjsan.org/go?l=Joose.Meta.Object)


DOES
====

[Test.Run.Test.More]


USAGE
=====

Below is the list of methods, intended for usage in the individual tests.


### plan

> `void plan(Number tests)`

> This method setups test's plan. It should be called before any assertions were checked. 

> **tests** - a number of planned assertions in this test file.


### diag

> `void diag(String text)`

> This method add the diagnostic message into results queue. The actual presentation logic of the message is delegated to harness.

> **text** - The text of diagnostic message


### pass

> `void pass(String text)`

> This method add the passed assertion into results queue. The actual presentation logic of the passed assertion is delegated to harness.

> **text** - The text of the assertion


### fail

> `void fail(String text)`

> This method add the failed assertion into results queue. The actual presentation logic of the passed assertion is delegated to harness.

> **text** - The text of the assertion


### ok

> `void ok(Boolean condition, String text)`

> This method add the passed or failed assertion into results queue. The type of assertion to add is determined from 1st argument.

> **condition** - The boolean condition, indicating wheter assertions is passed or failed

> **text** - The text of the assertion

        
### is

> `void is(Object value1, Object value2, String text)`

> This method add the passed or failed assertion into results queue. The type of assertion to add is determined from comparison of 1st and 2nd arguments.
Comparison is performed with '==' operator

> **value1** - The 1st value for comparison

> **value2** - The 2nd value for comparison

> **text** - The text of the assertion



ATTRIBUTES
==========

### url

> `String url`

> Url of the test file.


### assertPlanned

> `Number assertPlanned`  

> Planned number of assertions to test.


### assertCount

> `Number assertCount` 

> Current number of processed assertions (not includes the diagnostic messages).
        

### diagCount

> `Number diagCount` 

> Current number of processed diagnostic messages.
        

### passCount

> `Number passCount` 

> Current number of passed assertions.


### failCount

> `Number failCount` 

> Current number of failed assertions.

        
### results

> `Test.Run.Result[] results` 

> Array of [Test.Run.Result] instances (represent either assertion or diagnostic message).

        
### run

> `Function  run` 

> The function, which contain test statements (is invoking with `StartTest` and will receive the instance of this class (or subclass) as a single argument)
        
        
### harness

> `Test.Run.Harness  harness`

> Reference to [Test.Run.Harness] (or subclass) instance, which represents the harness, under which the test is running.


#### failed

> `Boolean failed`

> The sign whether the test has threw an exception. 


### failedException

> `Object failedException`

> Thrown exception (see also [failed]) 


### startDate

> `Date startDate` 

> Timestamp of test start
        

### execEnd

> `Date execEnd` 

> Timestamp of test end

        
### topScope

> `Object topScope` 

> The top scope object in which test function was declared (an iframe or window in which test is running) 


### passThroughEx

> `Boolean passThroughEx`

> The sign whether the test should re-throw any exceptions caught (useful for debugging with FireBug). Defaults to 'false'



METHODS
=======

### toString

> `String toString()`

> Return string presentation of this test. Defaults to value of 'url' property 


### addResult

> `void addResult(Test.Run.Result result)`

> This method adds the instance of [Test.Run.Result] to results queue. The result can be either assertion ([Test.Run.Result.Assertion]) or diagnostic message ([Test.Run.Result.Diagnostic])

> **result** - The result instance to add


### start

> `protected void start()`

> This method starts the test execution. Execution is performing by running the function in the 'run' attribute.


### finalize

> `protected void finalize()`

> This method is called when the test finished execution. It setup the 'execEnd' attribute
        

### getSummaryMessage

> `protected String[] getSummaryMessage()`

> This method returns the summary message for this test. Should be called after the test has finished execution.

        

### isPassed

> `protected Boolean isPassed()`

> This method returns the sign whether the whole test passed or failed. The test is considered passed, when a) no exceptions were thrown,
b) there is no failing assertions c) the number of passed assertions is greater or equal to planned assertions number.



SEE ALSO
========

Subclass of this class, intended to run on browser platform: [Test.Run.Test.Browser]

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

        
[Test.Run.Result]: Result.html
[Test.Run.Harness]: Harness.html
[Test.Run.Test.Browser]: Test/Browser.html
[Test.Run.Test.More]: Test/More.html

*/;
Role('Test.Run.Test.More', {
    
    methods : {
        
        like : function (string, regex, desc) {
            if (regex instanceof RegExp) 
                this.ok(string.match(regex), desc)
            else
                this.ok(string.indexOf(regex) != -1, desc)
        },
        
        
        unlike : function(string, regex, desc) {
            if (regex instanceof RegExp) 
                this.ok(!string.match(regex), desc)
            else
                this.ok(string.indexOf(regex) == -1, desc)
        },        
        
        
        throws_ok : function(func, expected, desc) {
            if (typeof func != 'function') throw 'throws_ok accepts a function as 1st argument'
            
            var e = this.topScope.__EXCEPTION_CATCHER__(func)
            
            if (e instanceof this.topScope.Error)
                //IE uses non-standard 'description' property for error msg
                e = e.message || e.description
            
            this.like('' + e, expected, desc + ' (got [' + e + '], expected [' + expected + '])')
        }    
        
    }
        
})
//eof Test.Run.Test.More

Test.Run.Test.meta.extend({
    does : [ Test.Run.Test.More ]
})


/**

Name
====

Test.Run.Test.More - A role with additional assertion check, which can be used in tests.



SYNOPSIS
========

            t.plan(3)
            
            t.diag('Starting..')
            
            t.like('this', /this/, 'Probably similar things')
            
            t.unlike('this', 'that', 'Unlikely..')
            
            t.throws_ok(function(){
                throw "Ups"
            }, /ups/i, 'Ups was thrown correctly :)')
        


DESCRIPTION
===========

`Test.Run.Test.More` is a role, consumed by the [Test.Run.Test] and providing some general-purpose (platform independed) assertions checks.


DOES
====

None


USAGE
=====

Below is the list of methods, intended for usage in the individual tests.


### like

> `void like(String str, String|RegExp regex, text)`

> This method add the passed or failed assertion into results queue. The type of assertion to add is determined from testing the passed string (1st argument)
against a regular expression  (2nd argument)

> **str** - The string to test

> **regex** - The regex against which to test the string, can be also a plain string

> **text** - The text of the assertion


### unlike

> `void unlike(String str, String|RegExp regex, text)`

> This method is the opposite of 'like', it adds failed assertion, when the string matches the passed regex.

> **str** - The string to test

> **regex** - The regex against which to test the string, can be also a plain string

> **text** - The text of the assertion



### throws_ok

> `void throws_ok(Function func, String|RegExp expected, text)`

> This method add the passed or failed assertion into results queue. The type of assertion to add is determined from the following:
The passed 'func' function is executing, and its expected to throw an exception. Then the exception object is stringified and passed to 'like' method along with 'expected' parameter.  

> **func** - The function which supposed to throw an exception

> **expected** - The regex against which to test the *stringified* exception, can be also a plain string

> **text** - The text of the assertion


SEE ALSO
========

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

        
[Test.Run.Test]: ../Test.html

*/
;
Class('Test.Run.Test.Browser', {
    
    isa : Test.Run.Test,
    
    have : {
        iframe          : null,
        
        timeoutIds      : null,
        
        finished        : false
    },
    
    
    after : {
        
        initialize : function () {
            this.timeoutIds = {}
        }
        
    },
    
    
    methods : {
        
        beginAsync : function (time) {
            var me = this
            
            var timeoutId = this.topScope.setTimeout(function () {
                me.endAsync(timeoutId)
            }, time || 1e4)
            
            this.timeoutIds[timeoutId] = true
            
            return timeoutId
        },
        
        
        endAsync : function (timeoutId) {
            var counter = 0
            
            if (!timeoutId) Joose.O.each(this.timeoutIds, function (value, name) {
                timeoutId = name
                if (counter++) throw "Calls to endAsync without argument should only be performed if you have single beginAsync statement" 
            })
            
            this.topScope.clearTimeout(timeoutId)
            delete this.timeoutIds[timeoutId]
            
            if (this.finished) this.finalize()
        },
        
        
        finalize : function () {
            this.finished = true
            
            if (!Joose.O.isEmpty(this.timeoutIds)) return
            
            this.SUPER()
        }
        
    }
    
})
//eof Test.Run.Test.Browser


/**

Name
====

Test.Run.Test.Browser - Base class for test file, running on the browser platform.


SYNOPSIS
========

            t.plan(1)
            
            var async0 = t.beginAsync()
            
            use('Module.Stub', function () {
                
                //=========================================
                t.diag('Sanity')
                
                t.ok(Module.Stub, "Module.Stub is here")
                
                t.endAsync(async0)
            })
        


DESCRIPTION
===========

`Test.Run.Test.Browser` is a base testing class for tests, running on browser. It assumes the presence of `setTimeout/clearTimeout` functions and provides the ability of asynchornous testsing.


ISA
===

[Test.Run.Test]


DOES
====

None


USAGE
=====

Below is the list of methods, intended for usage in the individual tests.


### beginAsync

> `Number beginAsync(Number? maxTime)`

> This method starts the "asynchronous frame". The test will not finished, until the frame will not be finished with [endAsync] call.
[endAsync] will be automatically call after specified `maxtime`.

> **maxTime** - the maximum time (in ms) to wait until explicitly finalize this async frame.

> *return* - The timeoutId, which can be used in [endAsync] call



### endAsync

> `void endAsync(Number timeoutId)`

> This method finalize the "asynchronous frame" started with [beginAsync].

> **timeoutId** - The timeoutId, returned by [beginAsync] call


ATTRIBUTES
==========

### timeoutIds

> `Object timeoutIds`

> The hash which keep the timeout ids, generated by [beginAsync] call



### finished

> `Boolean finished`

> The sign whether this test has finished execution (its 'run' function was executed). Test still may be active, until there are active "asynchronous frames"



SEE ALSO
========

Additional general-purpose assertions checks: [Test.Run.Test.More]

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

        
[Test.Run.Test]: ../Test.html
[Test.Run.Test.More]: More.html


*/
;
Class('Test.Run.Harness', {
    
    my : {
        
        have : {
            testClass       : Test.Run.Test,
            
            tests           : null,
            testsByURL      : null,
            
            passThroughEx   : false,
            
            urls            : null,
            testsGiven      : 0
        },
        
        
        after : {
            
            initialize : function () {
                this.testsByURL = {} 
                this.tests      = []
                this.urls       = {}
            }
        },
        
        
        methods : {
            
            getTest : function (url) {
                return this.testsByURL[url]
            },
            
            
            testUpdate : function (test, result) {
            },
            
            
            testFail : function (test, exception) {
            },
            
            
            testStart : function (test) {
            },
            
            
            testEnd : function (test) {
                if (!this.isRunning()) this.testSuiteEnd()
            },
            
            
            testSuiteEnd : function () {
            },
            
            
            configure : function (config) {
                Joose.O.copy(config, this)
            },
            
            
            startTest : function (func, testClass, topScope) {
                var test = new (testClass || this.testClass)({
                    harness         : this,
                    run             : func,
                    topScope        : topScope,
                    passThroughEx   : this.passThroughEx
                })
                
                this.recordTest(test)
                
                test.start()
            },
            
            
            removeTest : function (test) {
                delete this.testsByURL[test.url]
                this.tests = Joose.A.remove(this.tests, test)
            },
            
            
            reRunTest : function (test) {
                this.removeTest(test)
            },
            
            
            reRunSuite : function () {
                Joose.A.each(this.tests, function (test) {
                    this.reRunTest(test)
                }, this)
            },
            
            
            recordTest : function (test) {
                this.tests.push(test)
                this.testsByURL[test.url] = test
            },
            
            
            start : function () {
                this.testSuiteStart()
                
                this.testsGiven = arguments.length
                
                Joose.A.each(arguments, function (url) {
                    
                    this.processUrl(url)
                    
                }, this)
                
                this.testSuiteProcessed()
            },
            
            
            testSuiteStart : function () {
                Test.Run.my.configure({
                    harness : this
                })
            },
            
            
            testSuiteProcessed : function () {
            },
            
            
            processUrl : function (url) {
                this.urls[url] = {}
            },
            
            
            isPassed : function () {
                var res = true
                
                Joose.A.each(this.tests, function (test) {
                    if (!test.isPassed()) res = false
                })
                
                return res
            },
            
            
            isRunning : function () {
                if (this.testsGiven != this.tests.length) return true
                
                var res = false
                
                Joose.A.each(this.tests, function (test) {
                    if (!test.execEnd) res = true
                })
                
                return res
            }
            
        }
        
    }
    //eof my
})
//eof Test.Run.Harness



/**

Name
====


Test.Run.Harness - Abstract base class for test harness


SYNOPSIS
========

            Test.Run.Harness.Browser.Multi.my.configure({
                title : 'Module.Stub Test Suite',
                
                passThroughEx : true,
                
                preload : [
                    '/jsan/Task/Joose/Core.js',
                    "/jsan/JooseX/SimpleRequest.js",
                    '/jsan/Task/JooseX/Namespace/Depended/Web.js',
                    {
                        text : "JooseX.Namespace.Depended.Manager.my.INC = " + Ext.encode(INC)
                    }
                ]
            })
            
            
            Test.Run.Harness.Browser.Multi.my.start(
                '010_sanity.t.js',
                '020_basics.t.js'
            )
        


DESCRIPTION
===========

`Test.Run.Harness` is an abstract base harness class in Test.Run hierarchy. This class provides no UI, you should use one of it subclasses, 
for example [Test.Run.Harness.Browser.Multi]

This class is a pure static class - it defines only static properties. Please refer to [Joose.Manual.Static](http://openjsan.org/go?l=Joose.Manual.Static)


ISA
===

[Joose.Meta.Object](http://openjsan.org/go?l=Joose.Meta.Object)


DOES
====

None


USAGE
=====

This section describes the end-user interface of this class.


Methods
-------

### configure

> `void configure(Object options)`

> This method configure the harness instance. It just copies the passed configuration option into static instance. 

> **options** - configuration options (values of attributes for this class, see below for details)


### start

> `void start(String url1, String url2, ...)`

> This method starts a whole test suite 

> **url1, url2, ...** - the variable number of test files urls


Configuration options
---------------------

### passThroughEx

> `Boolean passThroughEx`

> The sign whether the each test in suite should re-throw any exceptions caught (useful for debugging with FireBug). Defaults to 'false'.
If set to true, exceptions will not be displayed with UI, and should be traced manually.


ATTRIBUTES
==========

This information is intended mostly for authoring Test.Run extensions, and not for end-users.


### testClass

> `Class testClass`

> The test class which will be used for running tests, defaults to [Test.Run.Test].


### tests

> `Test.Run.Test[] tests`

> The array of all test instances in harness.


### testsByURL

> `Test.Run.Test{} testsByURL`

> The hash of all test instances in harness, keyed by [url] attribute.


### urls

> `Object urls`

> Hash of test files, keyed by url. Also contain arbitrary helper info about the tests.



### testsGiven

> `Number testsGiven`

> The number of test files, given in 'start'



METHODS
=======

This information is intended mostly for authoring Test.Run extensions, and not for end-users.


### testUpdate

> `void testUpdate(Test.Run.Test test, Test.Run.Result result)`

> This method is called by the individual tests (instances of [Test.Run.Test]), each time the it has been updated (new result appeared in results queue).
The harness is supposed to provide some UI representation of the update.

> **test** - The test instance which has been updated

> **result** - The results instance which just has been added to the results queue of test


### testFail

> `void testFail(Test.Run.Test test, Object exception)`

> This method is called by the individual test (instances of [Test.Run.Test]), each time it has been failed (the exception was thrown).
The harness is supposed to provide some UI representation of this event.

> **test** - The test instance which has been failed

> **exception** - The exception thrown 



### testStart

> `void testStart(Test.Run.Test test)`

> This method is called by the individual test (instances of [Test.Run.Test]), each time the test in the test suite has been started.
The harness is supposed to provide some UI representation of this event.

> **test** - The test instance which has been failed


### testEnd

> `void testEnd(Test.Run.Test test)`

> This method is called by the individual test (instances of [Test.Run.Test]), each time the test in the test suite has been finished execution.
The harness is supposed to provide some UI representation of this event.

> **test** - The test instance which has been finished



### testSuiteStart

> `void testSuiteStart()`

> This method is called when the whole test suite has been started


### testSuiteEnd

> `void testSuiteEnd()`

> This method is called when the whole test suite has been finished


### testSuiteProcessed

> `void testSuiteProcessed()`

> This method is called when the whole test suite was processed. Note that at this point some tests may still running. See also [testSuiteEnd]



### startTest

> `void startTest(Function func, Class? testClass, Object topScope)`

> This method starts the execution of a single test file.

> **func** - The function, which contain test statements. The instance of test will be passed to it as 1st argument

> **testClass** - The class which should be used for instantiation of test (defaults to value of 'testClass' attribute)

> **topScope** - The top scope in which this test was declared. This arguments is very important, because it allows the test to correctly catch the exceptions.



### recordTest

> `void recordTest(Test.Run.Test test)`

> This method records a test into internal structures of harness.

> **test** - The test instance being recorded



### removeTest

> `void removeTest(Test.Run.Test test)`

> This method removes the test from harness. All necesery cleanup should be done here. 

> **test** - The test instance being removed



### reRunTest

> `void reRunTest(Test.Run.Test test)`

> This method re-runs a single test from harness. Note - passed test instance will be removed and re-created.

> **test** - The test instance being re-ran



### reRunSuite

> `void reRunSuite()`

> This method re-runs a whole test suite.  


### processUrl

> `void processUrl(String url)`

> This method process a single test file url (it should create the global scope for it and launch the code)  

> **test** - The test file url



### isPassed

> `Boolean isPassed()`

> This method return 'true' if all tests in test suite were passed succefully, 'false' otherwise  


### isRunning

> `Boolean isRunning()`

> This method return 'true' if there is any test in test suite which is still running, 'false' otherwise  



SEE ALSO
========

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

        
[Test.Run.Harness.Browser.Multi]: Harness/Browser/Multi.html
[Test.Run.Test]: Test.html

*/
;
Class('Test.Run.Harness.Browser', {
    
    isa : Test.Run.Harness,
    
    my : {
        
        have : {
            testClass           : Test.Run.Test.Browser,
            
            title               : null,
            
            disableCaching      : true,
            
            isIE                : /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent),
            
            baseUrl             : window.location.href.replace(/\?.*$/,'').replace(/\/[^/]*$/, '/'),
            baseHost            : window.location.host,
            baseProtocol        : window.location.protocol,
            
            preload             : null,
            
            componentsExpanded  : false,
            
            keepWindows         : false  
        },
        
        
        after : {
        
            reRunTest : function (test) {
                this.processUrl(test.url)
            },
            
            
            testEnd : function (test) {
                var url = this.urls[test.url]
                
                if (!this.keepWindows && !url.iframe) url.topScope.close()
            }
        },
        
        
        before : {
            
            recordTest : function (test) {
                Joose.O.each(this.urls, function (value, url) {
                    if (value.topScope == test.topScope) test.url = url
                })
            },
            
            
            start : function () {
                if (!this.preload && window.COMPONENTS) this.setPreloadFromTaskName('core')
                
                this.preload = this.expandPreload(this.preload)
            },
            
            
            configure : function (config) {
                var browser = /browser=(.+)/.exec(window.location.search)
                
                if (browser) {
                    Test.Run.Harness.Browser.meta.extend({
                        does : [ Test.Run.Harness.Browser.Proven ]
                    });
                    
                    config.browser = browser[1]
                }
                
                if (typeof config.preload == 'string') {
                    this.setPreloadFromTaskName(config.preload)
                    delete config.preload
                }
            },
            
            
            removeTest : function (test) {
                var url = this.urls[test.url]
                
                var iframe = url.iframe
                
                if (iframe) {
                    
                    //XXX cleanup 'load' listeners of iframe here
                    
                    document.body.removeChild(iframe)
                }
            }
            
        },
        
        
        methods : {
            
            expandComponents : function () {
                if (this.componentsExpanded || !window.COMPONENTS) return
                
                Joose.O.each(COMPONENTS, function (components, taskName) {
                    var res = []
                    
                    Joose.A.each(components, function (comp) {
                        var match = /^\+(.+)/.exec(comp)
                        
                        res = res.concat(match ? COMPONENTS[match[1]] : comp)
                    })
                    
                    COMPONENTS[taskName] = res
                })
                
                this.componentsExpanded = true
            },
            
            
            setPreloadFromTaskName : function (taskName) {
                this.preload = COMPONENTS[taskName]
            },
            
            
            expandPreload : function (preload) {
                this.expandComponents()
                
                var expanded = []
                
                Joose.A.each(preload || [], function (comp) {
                    var match
                    
                    if (typeof comp == 'object' || /\.js$/.test(comp))
                        expanded.push(comp)
                    else if (match = /^\+(.+)/.exec(comp))
                        expanded = expanded.concat(this.expandPreload(COMPONENTS[match[1]]))
                    else
                        expanded.push('../lib/' + comp.split('.').join('/') + '.js')
                }, this)
                
                return expanded
            },
            
            
            //webkit bug - base urls for iframes are broken
            //https://bugs.webkit.org/show_bug.cgi?id=13364
            resolveUrl : function (url, onlyResolve) {
                var resolved
                
                if (!/^http/.test(url))
                    if (!/^\//.test(url))
                        resolved = this.baseUrl + url
                    else
                        resolved = this.baseProtocol + '//' + this.baseHost + url
                
                if (this.disableCaching && !onlyResolve) resolved += '?disableCaching=' + new Date().getTime()
                
                return resolved
            },
            
            
            processUrl : function (testDescriptor) {
                if (typeof testDescriptor == 'string')
                    testDescriptor = {
                        url         : testDescriptor,
                        target      : 'iframe'
                    }
                
                var url         = testDescriptor.url
                var target      = testDescriptor.target || 'iframe'
                
                this.SUPER(url)
                
                if (target == 'iframe')
                    this.processIframeTarget(url)
                else
                    this.processWindowTarget(url)
            },
            
            
            processWindowTarget : function (url) {
                var resolved = this.resolveUrl(url)
                
                var me = this
                
                var popup
                
                __ON_STUB_LOADED__ = function () {
                    me.setupWindow(popup, resolved) 
                }
                
                // 'resolveUrl' for stubs to disable synchronous loading in IE, which fires __ON_STUB_LOADED__
                // even before assignment to 'popup' variable
                var src = /\.html$/.test(url) ? resolved : this.resolveUrl('/jsan/Test/Run/static/stub-window.html')
                
                popup = window.open(src, '_blank')
                if (!popup) {
                    alert('Enable popups for the host with this test suite running')
                    throw 'Enable popups for the host with this test suite running'
                }
                
                
//                
//                
//                //ugh, some day we all will be happy )
//                
//                //IE
//                if (popup.attachEvent) 
//                    popup.attachEvent('onload', onload)
//                else 
//                    //chrom or safari (c) from http://rhio.tistory.com/tag/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%20%EC%8A%A4%EB%8B%88%ED%95%91
//                    //https://bugs.webkit.org/show_bug.cgi?id=28716
//                    if (/source/.test((/a/.toString + '')) || /a/.__proto__ == '//') {
//                        var checkPopupLoaded = function () {
//                            try {
//                                popup.document.body
//                                
//                                onload()
//                            } catch (e) {
//                                setTimeout(checkPopupLoaded, 50)
//                            }
//                        }
//                        
//                        checkPopupLoaded()
//                    } else
//                        //FF
//                        popup.onload = onload
                    
                     
                
                this.urls[url].topScope = popup
            },
            
            
            processIframeTarget : function (url) {
                var me = this
                
                var resolved = this.resolveUrl(url)
                
                var iframe = document.createElement('iframe')
                
                var onload = function () {
                    me.setupWindow(iframe.contentWindow, resolved) 
                }
                
                if (iframe.attachEvent) 
                    iframe.attachEvent('onload', onload)
                else
                    iframe.onload = onload 
                
                iframe.src = /\.html$/.test(url) ? resolved : '/jsan/Test/Run/static/stub.html'
                
                this.customizeIframe(iframe)
                
                document.body.appendChild(iframe)
                
                this.urls[url].topScope = iframe.contentWindow
                this.urls[url].iframe = iframe
            },
            
            
            customizeIframe : function (iframe) {
            },
            
            
            setupWindow : function (windowObj, resolvedUrl) {
                var urlCopy = resolvedUrl.replace(/\?.*$/,'')
                
                if (/\.js$/.test(urlCopy)) this.finalizeUrl(windowObj, resolvedUrl)
            },
            
            
            finalizeUrl : function (windowObj, resolvedUrl) {
                var documentObj = windowObj.document
                var bodyObj = documentObj.body
                
                var scriptTags = []
                
                
                if (this.preload) Joose.A.each(this.preload, function (preloadUrl) {
                    if (typeof preloadUrl == 'object') {
                        scriptTags.push([ preloadUrl.text, null, null, documentObj ])
                    } else {
                        preloadUrl = this.resolveUrl(preloadUrl)
                        
                        scriptTags.push([ null, preloadUrl, null, documentObj ])
                    }
                }, this)
                    
                scriptTags.push([
                    'StartTest = function(testFunc, testClass) { (window.parent.Test || window.opener.Test).Run.my.start(testFunc, testClass, this) }; ' +
                    '__EXCEPTION_CATCHER__ = function (func) { var ex; try { func() } catch (e) { ex = e; }; return ex; };',
                    null, 
                    null, 
                    documentObj
                ])
                
                scriptTags.push([ null, resolvedUrl, null, documentObj ])
                
                this.processScripTagQueue(bodyObj, scriptTags)
            },
            
            
            processScripTagQueue : function (container, queue) {
                if (queue.length) {
                    var params = queue.shift()
                    
                    //no text - loading via 'src'
                    if (!params[0]) {
                        var me = this
                        params[2] = function () {
                            me.processScripTagQueue(container, queue)
                        }
                    }
                    
                    container.appendChild(this.createScriptTag.apply(this, params))
                    
                    //have text - need to process further manually
                    if (params[0]) this.processScripTagQueue(container, queue)
                }
            },
            
            
            createScriptTag : function (text, url, onload, doc) {
                var node = (doc || document).createElement("script")
                
                node.setAttribute("type", "text/javascript")
                
                if (url) node.setAttribute("src", url)
                
                if (text) node.text = text
                
                if (onload) node.onload = node.onreadystatechange = function() {
                    if (!node.readyState || node.readyState == "loaded" || node.readyState == "complete" || node.readyState == 4 && node.status == 200)
                        //surely for IE6..
                        setTimeout(onload, 1)
                }
                
                return node
            }
            
        }
        
    }
    //eof my
})
//eof Test.Run.Harness.Browser



/**

Name
====


Test.Run.Harness.Browser - Abstract base class for test harness


SYNOPSIS
========

            Test.Run.Harness.Browser.Multi.my.configure({
                title : 'Module.Stub Test Suite',
                
                passThroughEx : true,
                
                preload : [
                    '/jsan/Task/Joose/Core.js',
                    "/jsan/JooseX/SimpleRequest.js",
                    '/jsan/Task/JooseX/Namespace/Depended/Web.js',
                    {
                        text : "JooseX.Namespace.Depended.Manager.my.INC = " + Ext.encode(INC)
                    }
                ]
            })
            
            
            Test.Run.Harness.Browser.Multi.my.start(
                '010_sanity.t.js',
                '020_basics.t.js'
            )
        


DESCRIPTION
===========

`Test.Run.Harness.Browser` is an abstract harness class in Test.Run hierarchy, providing the methods for running tests on browser platform. 
This class still provides no UI, you should use one of it subclasses, for example [Test.Run.Harness.Browser.Multi]

This class is a pure static class - it defines only static properties. Please refer to [Joose.Manual.Static](http://openjsan.org/go?l=Joose.Manual.Static)


ISA
===

[Test.Run.Harness]


DOES
====

None


USAGE
=====

This section describes the end-user interface of this class.


Configuration options
---------------------

### title

> `String title`

> The title of the test suite


            
### disableCaching

> `Boolean disableCaching`

> The sign whether the harness should surpress the browser caching for each loading operation. Defaults to 'true'


### preload

> `Object[] preload`

> The array which contain information about which files should be preloaded into each test's scope.
The folloing rules applies during processing of the array:

>1. All string entries starting with '+' are replaced with corresponding [components sequence][Using Components.js].
2. If the string entry represent a class name (for example : Test.Run.Test) it is converting to the url, like "../lib/Test/Run/Test.js"
3. If the string entry ends with ".js", its supposed to be the url and is passing without modifications.
4. If the entry is an Object with `text` property, then the value of that property will be evaluted in the test's global scope directly.


Using `Components.js`
=====================

Components.js is a file, which is intended to provide some basic bundling of individual files in your distribution.
The purpose of this bundling is mostly to optimize the loading time of the test suites, though its also useful
for other things.

Here is an example of this file:

            COMPONENTS = {
                "Core" : [
                    "Test.Run.Result",
                    "Test.Run.Result.Diagnostic",
                    "Test.Run.Result.Assertion",
                    
                    "Test.Run.Test",
                    "Test.Run.Test.More",
                    "Test.Run.Test.Browser",
                    
                    "Test.Run.Harness",
                    "Test.Run.Harness.Browser",
                    "Test.Run.Harness.Browser.Single",
                    
                    "Test.Run.Harness.Browser.Proven",
                    
                    
                    "Test.Run"
                ],
                
                "ExtJS" : [
                    "+Core",
                    
                    "Test.Run.Harness.Browser.UI.Viewport",
                    "Test.Run.Harness.Browser.UI.TestGrid",
                    "Test.Run.Harness.Browser.UI.AssertionGrid",
                    
                    "Test.Run.Harness.Browser.Multi"
                ]
            } 

In this file, we assign the components description to global `COMPONENTS` variable. This variable will be picked up by harness,
and parts of components definition can be used in [preload] configuration option.

The 1st level entries in the `COMPONENTS` variable will be the *components sequences*. They can have arbitrary names, usually corresponding 
to some deployment blocks of your distribution. 

The 2nd level entries should be the arrays with packages names. Or, instead of package, another components sequence can be included, specified with
leading `+` sign.

For additional details on using `Components.js` file please refer to [action `task` of Module::Build::JSAN::Installable](http://search.cpan.org/~nplatonov/Module-Build-JSAN-Installable-0.09/lib/Module/Build/JSAN/Installable.pm)


ATTRIBUTES
==========

This information is intended mostly for authoring Test.Run extensions, and not for end-users.


### testClass

> `Class testClass`

> The test class which will be used for running tests, defaults to [Test.Run.Test.Browser].


### isIE

> `Boolean isIE`

> 'true' if running under MS IE.


### baseUrl

> `String baseUrl`

> Base url of harness file.

            
### baseHost

> `String baseHost`

> Host of the [baseUrl].


### baseProtocol

> `String baseProtocol`

> Protocol of the [baseUrl].



METHODS
=======


### resolveUrl

> `String resolveUrl(String url, Boolean onlyResolve)`

> This method returns the absolutized URL. "Absolutization" is performing against [baseUrl] property. As an addition, if 'onlyResolve' parameter is 'false' or not passed
and [disableCaching] is set to 'true', the url will be appended with 'disableCaching' query parameter.

> **url** - The url to resolve  

> **onlyResolve** - The sign, whether the url should be strictly only absolutized and not appended with disableCaching parameter



### customizeIframe

> `void customizeIframe(DOMObject iframe)`

> This method is called before appending the created iframe into DOM. Its intented to be overloaded in custom classes and performing additional customization of the iframe.

> **iframe** - The iframe being customizing



SEE ALSO
========

Web page of this module: [http://github.com/SamuraiJack/Module-Stub/](http://github.com/SamuraiJack/Module-Stub/)

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

[Test.Run.Harness]: ../Harness.html
[Test.Run.Harness.Browser.Multi]: Browser/Multi.html

[Test.Run.Test]: ../Test.html
[Test.Run.Test.Browser]: ../Test/Browser.html

*/
;
Class('Test.Run.Harness.Browser.Single', {
    
    isa : Test.Run.Harness.Browser,
    
    my : {
        
        after : {
        
            testUpdate : function (test, result) {
                this.print(result)
            },
            
            
            testFail : function (test, exception) {
                this.print('Test threw an exception: ' + exception)
            },
            
            
            testEnd : function (test) {
                this.print(test.getSummaryMessage().join('<br>')); 
            }
        },

        
        methods : {
            
            print : function (text) {
                var div = document.createElement('div')
                div.innerHTML = text
                document.body.appendChild(div)
            }
            
        }
        
    }
    //eof my
})
//eof Test.Run.Harness.Browser.Single;
Role('Test.Run.Harness.Browser.Proven', {
    
    my : {
        
        have : {
            browser : null
        },
        
        after : {
            
//          testStart : function (test) {
//          },
//            
//            
//          testUpdate : function (test, result) {
//          },
//            
//            
//          testFail : function (test, exception) {
//          },
//
//            
//          testEnd : function (test) {
//          },
            
            
            testSuiteEnd : function () {
                var req = new JooseX.SimpleRequest()
                var provenUrl = '/proven/' + this.browser + '/' + (this.isPassed() ? 'pass' : 'fail')
                
                try {
                    req.getText(this.resolveUrl(provenUrl))
                } catch (e) {
                }
            }
            
        }
        
    }
    //eof my
})
//eof Test.Run.Harness.Browser.Proven;
Class('Test.Run', {
    
    my : {
        
        have : {
            harness : null
        },
        
        
        methods : {
            
            configure : function (config) {
                Joose.O.copy(config, this)
            },

            
            start : function (testFunc, testClass, topScope) {
                (this.harness || window.parent.Test.Run.my.harness || window.opener.Test.Run.my.harness || Test.Run.Harness.Browser.Single.my).startTest(testFunc, testClass, topScope)
            }
            
        }
        
    }
    //eof my
})
//eof Test.Run


//starter, which also capture the top scope - it will be re-defined in Test.Run.Harness.Browser
StartTest = function (testFunc, testClass) {
    Test.Run.my.start(testFunc, testClass, this)
}

__EXCEPTION_CATCHER__ = function (func) { var ex; try { func() } catch (e) { ex = e; }; return ex; }
;
Class('Test.Run.Harness.Browser.UI.Viewport', {
    
    isa : Ext.Viewport,
    
    have : {
        title           : null,
        
        harness         : null,
        
        urls            : null
    },
    
    before : {
        
        initComponent : function () {
            this.urls = {}
            
            Ext.apply(this, {
                
                slots : true,
                
                id : 'outer',
                
                layout : 'border',
                items : [
                    {
                        region : 'north',
                        slot : 'title',
                        
                        cls : 'x-test-title',
                        
                        html : '<a href="http://code.google.com/p/joose-js/"><div class="joose-logo"></div></a><h1>' + this.title + '</h1> ',
                        
                        height : 75
                    },
                    {
                        region : 'center',
                        
                        id : 'inner',
                        
                        layout : 'border',
                        
                        items : [
                            {
                                region : 'west',
                                xtype : 'testgrid',
                                slot : 'tests',
                                
                                split : true,
                                
                                harness : this.harness
                            },
                            {
                                region : 'center',
                                xtype : 'tabpanel',
                                slot : 'tabs',
                                
                                enableTabScroll : true
                            }
                        ]
                    }
                ]
            })
        }
        //eof initComponent
    },
    
    
    after : {
        initComponent : function () {
            var slots = this.slots
            
            var paused = false
            
            slots.tests.on('rowselect', function (grid, record) {
                if (!paused) {
                    paused = true
                    slots.tabs.activate(this.urls[record.get('name')].assertionGrid)
                    paused = false
                }
            }, this)
            
            slots.tabs.on('tabchange', function (tabs, panel) {
                if (!paused) {
                    paused = true
                    
                    var url = panel.url
                    
                    slots.tests.getSelectionModel().selectRecords([ this.getTestRecordByURL(url) ])
                    
                    paused = false
                }
            }, this)
        }
    },
    
    
    methods : {
        
        getTestRecordByURL : function (url) {
            var testStore   = this.slots.tests.store
            
            return testStore.getAt(testStore.find('name', url))
        },
        
        
        addUrlRecord : function (url) {
            var slots       = this.slots
            var testStore   = slots.tests.store
            var recType     = testStore.recordType
            
            var record = this.getTestRecordByURL(url)
            
            if (!record) { 
                record = new recType({ name : url })
                
                testStore.add([ record ])
            }
            
            var urlData     = this.urls[url]
            if (!urlData) urlData = this.urls[url] = {}
            
            var assertionGrid = urlData.assertionGrid
            
            if (!assertionGrid) {
                urlData.assertionGrid = assertionGrid = new Test.Run.Harness.Browser.UI.AssertionGrid({
                    title   : record.get('name'),
                    url     : url
                })
            
                slots.tabs.add(assertionGrid)
                
                if (slots.tabs.items.getCount() == 1) slots.tabs.activate(0)
            }
        },
        
        
        testStart : function (test) {
            var slots = this.slots
            var testStore = slots.tests.store
            
            this.urls[test.url].testRecord = testStore.getAt(testStore.find('name', test.url))
        },
        
        
        testUpdate : function (test, result) {
            var urlData     = this.urls[test.url]
            var testRecord  = urlData.testRecord
            
            testRecord.set('passCount', test.passCount)
            testRecord.set('failCount', test.failCount)
            testRecord.commit()
            
            var assertStore = urlData.assertionGrid.store
            var assertRecType = assertStore.recordType
            
            assertStore.add([
                new assertRecType({
                    indx        : test.assertCount,
                    ok          : result.pass ? 'ok' : 'not ok',
                    description : result.description,
                    type        : result.meta.name
                })
            ])
        },
        
        
        testEnd : function (test) {
            var urlData     = this.urls[test.url]
            var testRecord  = urlData.testRecord
            
            testRecord.set('time', (test.execEnd - test.startDate) + 'ms')
            testRecord.commit()
        },
        
        
        removeTest : function (test) {
            var urlData     = this.urls[test.url]
            var testRecord  = urlData.testRecord
            
            testRecord.set('passCount', 0)
            testRecord.set('failCount', 0)
            testRecord.set('time', '')
            testRecord.commit()
            
            var assertionGrid = urlData.assertionGrid
            assertionGrid.store.removeAll()
        }        
        
        
    }
    
})
//eof Test.Run.Harness.Browser.UI.Viewport;
Class('Test.Run.Harness.Browser.UI.TestGrid', {
    
    isa : Ext.grid.GridPanel,
    
    
    have : {
        harness : null
    },
    
    
    before : {
        initComponent : function () {
            var sm = new Ext.grid.CheckboxSelectionModel({ singleSelect : false })
            
            this.addEvents('rowselect')
            
            Ext.apply(this, {
                
                tbar : [
                    { 
                        text : 'Re-run all',
                        iconCls : 'x-test-icon-refresh',
                        scale : 'large',
                        handler : this.reRunSuite,
                        scope : this
                    },
                    { 
                        text : 'Re-run selected',
                        iconCls : 'x-test-icon-refresh-single',
                        scale : 'large',
                        handler : this.reRunSelected,
                        scope : this
                    }
                    
                ],
                
                width : 400,
                
                columns: [
                    sm,
                    { header: 'Name', width: 210, sortable: true, dataIndex: 'name', renderer : this.testRowRenderer.createDelegate(this) },
                    { header: 'Passed', width: 60, sortable: true, dataIndex: 'passCount', align : 'center' },
                    { header: 'Failed', width: 60, sortable: true, dataIndex: 'failCount', align : 'center' },
                    { header: 'Time', width: 50, sortable: true, dataIndex: 'time', align : 'center' }
                ],
                
                viewConfig : {
                    forceFit : true
                },
                
                sm: sm,//new Ext.grid.CheckboxSelectionModel({ header : 'yo' }),//({ singleSelect : true }),
                
                store: new Ext.data.ArrayStore({
                    fields: [
                       'name',
                       'passCount',
                       'failCount',
                       'time'
                    ],

                    autoDestroy: true,
                    data: []
                })

 
            })
        }
    },
    
    
    after : {
        initComponent : function () {
            this.getSelectionModel().on('rowselect', this.onRowSelect, this)
        }
    },
    
    
    methods : {
        
        onRowSelect : function (selModel, indx, record) {
            this.fireEvent('rowselect', this, record)
        },
        
        
        reRunSuite : function () {
            this.harness.reRunSuite()
        },
        
        
        reRunSelected : function () {
            var records = this.getSelectionModel().getSelections()
            
            Joose.A.each(records, function (record) {
                var test = this.harness.getTest(record.get('name'))
                
                if (test) this.harness.reRunTest(test)
            }, this)
        },
        
        
        testRowRenderer : function (value, metaData, record, rowIndex, colIndex, store) {
            var test = this.harness.getTest(record.get('name'))
            
            metaData.css = 'x-test-test-status '
            if (test) {
                if (test.failed)
                    metaData.css += 'x-test-test-status-thrown'
                else if (test.failCount)
                    metaData.css += 'x-test-test-status-failed'
                else if (test.passCount >= test.assertPlanned)
                    metaData.css += 'x-test-test-status-passed'
                else
                    metaData.css += 'x-test-test-status-working'
                    
            } else 
                metaData.css += 'x-test-test-status-question'
            
            return value
        }
        
    }
    
})

Ext.reg('testgrid', Test.Run.Harness.Browser.UI.TestGrid);
Class('Test.Run.Harness.Browser.UI.AssertionGrid', {

    isa : Ext.grid.GridPanel,
    
    have : {
        url         : null
    },

    
    
    before : {
        initComponent : function() {
            Ext.apply(this, {
                
//                iconCls : 'x-test-test-status-question',
                
                columns : [
                    {
                        header : '#',
                        width : 23,
                        dataIndex : 'indx',
                        align : 'center'
                    },
                    {
                        header : 'Result',
                        width : 60,
                        sortable : true,
                        dataIndex : 'ok',
                        align : 'center',
                        
                        renderer : this.resultRenderer
                    },
                    {
                        header : 'Assertion',
                        width : 500,
                        sortable : true,
                        dataIndex : 'description'
                    }, 
                    {
                        header : 'Status',
                        width : 60,
                        sortable : true,
                        dataIndex : 'status'
                    }
                ],

                view : new Ext.grid.GridView({
                    forceFit : true,
                    enableRowBody : true,
                    
                    getRowClass : function(record, index, rowParams, store) {
                        var type = record.get('type')
                        
                        if (type == 'Test.Run.Result.Diagnostic') {
                            rowParams.body = '<h2>' + record.get('description') + '</h2>'
                            return 'x-test-diagnostic-row'
                        } else {
                            rowParams.body = ''
                        }
                    }
                }),

                store : new Ext.data.ArrayStore({
                    fields : ['indx', 'ok', 'description', 'status', 'type' ],

                    autoDestroy : true,
                    data : []
                })

            })
        }
    },

    
    after : {
        initComponent : function() {
        }
    },
    
    
    methods : {
        resultRenderer : function (value, metaData, record, rowIndex, colIndex, store) {
            if (value == 'ok') 
                metaData.css = 'x-test-assert-row-ok-cell'
            else
                metaData.css = 'x-test-assert-row-bug-cell'
            
            return ''
        }
    }

})

Ext.reg('assertgrid', Test.Run.Harness.Browser.UI.AssertionGrid);
Class('Test.Run.Harness.Browser.Multi', {
    
    isa : Test.Run.Harness.Browser,
    
    my : {
        
        have : {
            viewport : null
        },
        
        
        after : {
            
            processUrl : function (urlOrDesc) {
                this.viewport.addUrlRecord(typeof urlOrDesc == 'string' ? urlOrDesc : urlOrDesc.url)
            },
            
            
            testStart : function (test) {
                this.viewport.testStart(test)
            },
            
            
            testUpdate : function (test, result) {
                this.viewport.testUpdate(test, result)
            },
            
            
            testEnd : function (test) {
                this.viewport.testEnd(test)
                test.diag(test.getSummaryMessage().join('<br>'))
            },
            
            
            testFail : function (test, exception) {
            },
            
            
            removeTest : function (test) {
                this.viewport.removeTest(test)
            }
            
        },
        
        
        methods : {
            
            start : function () {
                var me = this
                
                //waiting for viewport
                if (!this.viewport) { 
                    var startArguments = Array.prototype.slice.call(arguments)
                    
                    Ext.onReady(function(){
                        
                        me.viewport = new Test.Run.Harness.Browser.UI.Viewport({
                            title : me.title,
                            harness : me
                        })
                        
                        me.start.apply(me, startArguments)
                    })
                    
                } else 
                    this.SUPERARG(arguments)
            }
            
        }
        
    }
    //eof my
})
//eof Test.Run.Harness.Browser.Multi



/**

Name
====


Test.Run.Harness.Browser.Multi - a harness, which runs into browser and provides an ExtJS based GUI.


SYNOPSIS
========

            Test.Run.Harness.Browser.Multi.my.configure({
                title : 'Module.Stub Test Suite',
                
                passThroughEx : true,
                
                preload : [
                    '/jsan/Task/Joose/Core.js',
                    "/jsan/JooseX/SimpleRequest.js",
                    '/jsan/Task/JooseX/Namespace/Depended/Web.js',
                    {
                        text : "JooseX.Namespace.Depended.Manager.my.INC = " + Ext.encode(INC)
                    }
                ]
            })
            
            
            Test.Run.Harness.Browser.Multi.my.start(
                '010_sanity.t.js',
                '020_basics.t.js'
            )
        


DESCRIPTION
===========

`Test.Run.Harness.Browser.Multi` is already not an abstract class and it provides an ExtJS based GUI. 

This class is a pure static class - it defines only static properties. Please refer to [Joose.Manual.Static](http://openjsan.org/go?l=Joose.Manual.Static)

For details on usage of this class please refer to [Test.Run.Harness.Browser] documentation. This class solely provides a GUI. 


ISA
===

[Test.Run.Harness.Browser]


DOES
====

None


ATTRIBUTES
==========

This information is intended mostly for authoring Test.Run extensions, and not for end-users.


### viewport

> `Ext.Viewport viewport`

> The reference to ExtJS viewport object.



SEE ALSO
========

Web page of this module: [http://github.com/SamuraiJack/Module-Stub/](http://github.com/SamuraiJack/Module-Stub/)

General documentation for Joose: [http://openjsan.org/go/?l=Joose](http://openjsan.org/go/?l=Joose)


BUGS
====

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at [http://github.com/SamuraiJack/Module-Stub/issues](http://github.com/SamuraiJack/Module-Stub/issues)



AUTHORS
=======

Nickolay Platonov [nplatonov@cpan.org](mailto:nplatonov@cpan.org)



COPYRIGHT AND LICENSE
=====================

Copyright (c) 2009, Nickolay Platonov

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Nickolay Platonov nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

[Test.Run.Harness.Browser]: ../Browser.html

*/;