Skip to content

Commit

Permalink
Convert all selenium tests to use xvfb.
Browse files Browse the repository at this point in the history
The d3 renderer was issuing an undefined event when it was resized.  This has been corrected to issue the d3.rescale event.

The tests in testing/test-cases/selenium-tests/featureVisible are already handled by tests/cases/feature.js, so they have been removed without conversion.

Taking a screenshot of mixed d3 and vgl layers could erroneously place the d3 layers on top.  This has been fixed.
  • Loading branch information
manthey committed Mar 15, 2017
1 parent e8370cf commit 93192bf
Show file tree
Hide file tree
Showing 130 changed files with 3,726 additions and 4,313 deletions.
92 changes: 0 additions & 92 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ set(PHANTOMJS_TESTS ON CACHE BOOL "Generate phantomjs unit tests.")
set(FFHEADLESS_TESTS ON CACHE BOOL "Generate headless Firefox unit tests (requires xvfb to be running).")
set(TEST_SAVE_IMAGE "none" CACHE STRING "Save headless test images even if there aren't errors. Valid options are none, all, or the a comma-separated list of test names.")
set(ESLINT_TESTS ON CACHE BOOL "Generate eslint style tests for JS source files.")
set(SELENIUM_TESTS ON CACHE BOOL "Generate selenium unit tests.")

site_name(HOSTNAME)

Expand All @@ -37,11 +36,6 @@ function(add_geojs_test test_name)
set_property(TEST "notes-report" APPEND PROPERTY DEPENDS "${test_name}")
endfunction()

set(MIDAS_BASE_URL "https://midas3.kitware.com/midas" CACHE STRING "MIDAS data store URL.")
mark_as_advanced(MIDAS_BASE_URL)
set(MIDAS_COMMUNITY "GeoJS" CACHE STRING "MIDAS community hosting test images.")
mark_as_advanced(MIDAS_COMMUNITY)

# set variables for girder.cmake
set(Girder_KEY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/testing/test-data")
set(Girder_DATA_DIR "${GEOJS_DEPLOY_DIR}/data")
Expand All @@ -53,11 +47,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testing/test-runners/geojs_test_runne
${CMAKE_CURRENT_BINARY_DIR}/test/geojs_test_runner.py
)

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testing/test-runners/selenium-test-utils.js
${GEOJS_DEPLOY_DIR}/test/lib/selenium-test-utils.js
COPYONLY
)

# Generate notes to send along with the test reports
add_test(
NAME "notes-reset"
Expand Down Expand Up @@ -159,87 +148,6 @@ add_custom_target(baseline_images DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/base-imag
add_test(NAME baseline_images CONFIGURATIONS "baseline_images" COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target baseline_images)
set_property(TEST "baseline_images" APPEND PROPERTY ENVIRONMENT "CTEST_IMAGE_PATH=${CMAKE_CURRENT_BINARY_DIR}/images")

if(SELENIUM_TESTS)

find_package(PythonInterp REQUIRED)
set(FIREFOX_TESTS ON CACHE BOOL "Turn on Firefox selenium tests.")
set(CHROME_TESTS OFF CACHE BOOL "Turn on Chrome selenium tests.")
set(DATA_REPO_PATH "" CACHE PATH "Local path to the geojs data repository (optional).")
set(SELENIUM_TEST_DIR "${GEOJS_DEPLOY_DIR}/test/selenium")
set(SELENIUM_HOST localhost CACHE STRING "The selenium test server host.")
mark_as_advanced(SELENIUM_HOST)
set(SELENIUM_PORT 4444 CACHE STRING "The selenium test server port.")
mark_as_advanced(SELENIUM_PORT)

configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/testing/js/selenium-blanket.js
${GEOJS_DEPLOY_DIR}/test/lib/selenium-blanket.js
COPYONLY
)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/testing/test-runners/selenium_test.py.in"
"${CMAKE_CURRENT_BINARY_DIR}/test/selenium_test.py"
)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/testing/test-runners/midas_handler.py"
"${CMAKE_CURRENT_BINARY_DIR}/test/midas_handler.py"
COPYONLY
)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/testing/test-runners/upload_test_cases.py"
"${CMAKE_CURRENT_BINARY_DIR}/test/upload_test_cases.py"
COPYONLY
)
file(GLOB SELENIUM_TEST_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/testing/test-cases/selenium-tests/*
)
foreach(dir ${SELENIUM_TEST_DIRS})
if(IS_DIRECTORY "${dir}" AND EXISTS "${dir}/include.js")
set(html "${dir}/include.html")
set(js "${dir}/include.js")
set(css "${dir}/include.css")
get_filename_component(f "${dir}" NAME_WE)
set(test_dir "${SELENIUM_TEST_DIR}/${f}")
set(output_html "${test_dir}/index.html")

add_custom_command(OUTPUT "${output_html}"
COMMAND ${CMAKE_COMMAND} -DHTML_INCLUDE="${html}"
-DJS_INCLUDE="${js}"
-DCSS_INCLUDE="${css}"
-DOUTPUT_HTML="${output_html}"
-DTEMPLATE_HTML="${CMAKE_CURRENT_SOURCE_DIR}/testing/test-runners/selenium-template.html.in"
-P ${CMAKE_SOURCE_DIR}/cmake/configure-js-selenium-test.cmake
COMMAND ${CMAKE_COMMAND} -E touch "${output_html}"
DEPENDS "${html}" "${js}" "${css}" "${CMAKE_CURRENT_SOURCE_DIR}/testing/test-runners/selenium-template.html.in"
COMMENT "Generating selenium test ${f}"
)
list(APPEND SELENIUM_TEST_FILES "${output_html}")

add_test(
NAME "selenium:${f}"
WORKING_DIRECTORY "${GEOJS_DEPLOY_DIR}"
COMMAND ${PYTHON_EXECUTABLE} -m unittest discover -v -s "${dir}"
)

set_property(TEST "selenium:${f}" APPEND PROPERTY DEPENDS "notes-reset")
set_property(TEST "notes-report" APPEND PROPERTY DEPENDS "selenium:${f}")
set_property(TEST "selenium:${f}" APPEND PROPERTY ENVIRONMENT "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}/test")
set_property(TEST "selenium:${f}" APPEND PROPERTY ENVIRONMENT "FIREFOX_TESTS=${FIREFOX_TESTS}")
set_property(TEST "selenium:${f}" APPEND PROPERTY ENVIRONMENT "CHROME_TESTS=${CHROME_TESTS}")
endif()
endforeach()

set_property(TEST "selenium:glPointsSpeed" APPEND PROPERTY ENVIRONMENT "LOAD_SPEED_THRESHOLD=1000")
set_property(TEST "selenium:glPointsSpeed" APPEND PROPERTY ENVIRONMENT "FRAMERATE_THRESHOLD=5")

add_custom_target(
selenium_tests
ALL
DEPENDS ${SELENIUM_TEST_FILES} ${Girder_DOWNLOAD_FILES}
)

endif()

if(${ESLINT_TESTS})

find_program(NPM_EXECUTABLE npm)
Expand Down
3 changes: 0 additions & 3 deletions cmake/travis_build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
set(coverage_file "${CTEST_SOURCE_DIRECTORY}/dist/cobertura/cobertura-coverage.xml")

ctest_start("Continuous")
ctest_configure(
OPTIONS "-DSELENIUM_TESTS=OFF"
)
ctest_build()
ctest_test(PARALLEL_LEVEL 1 RETURN_VALUE res)
if(EXISTS "${coverage_file}")
Expand Down
1 change: 0 additions & 1 deletion dashboard/github_service/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ def run_test(repo, commit, testdir, branch):
s, out = _communicate(
' '.join([
cmake,
'-D', 'SELENIUM_TESTS=ON',
'-D', 'CHROME_TESTS=OFF',
'-D', 'FIREFOX_TESTS=ON',
'-D', 'COVERAGE_TESTS=OFF',
Expand Down
154 changes: 4 additions & 150 deletions docs/developers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Headless browser testing
Geojs uses `PhantomJS <http://phantomjs.org/>`_ for headless browser
testing of core utilities. Unfortunately because PhantomJS does not
support webgl at this time, so code paths requiring gl must be either
mocked or run via selenium.
mocked or run in an environment such as xvfb.

The headless unit tests should be placed in the ``tests/cases/``
directory. All javascript files in this directory will be detected
Expand Down Expand Up @@ -81,9 +81,9 @@ will run the headless WebGL tests. After the data for tests is downloaded,
the tests can also be run via ``npm run test-webgl``, which assumes that
``xvfb-run`` is available.

The headless unit tests that require WebGL should be placed in the
``tests/gl-cases/`` directory. When tests are run in a normal browser via
``npm run start``, the webgl tests are included.
The headless unit tests that require WebGL or should run in a standard browser
should be placed in the ``tests/gl-cases/`` directory. When tests are run in a
normal browser via ``npm run start``, the webgl tests are included.

Many of these tests compare against a baseline image. If a test is changed or
added, new baselines can be generated and optionally uploaded via the script
Expand Down Expand Up @@ -115,149 +115,3 @@ directory. To run these tests in a normal browser, run
Since the browser's direct screen output is used, the browser must be running
on the same machine as the ``npm run start`` command.

Selenium testing
----------------

The selenium testing infrastructure of Geojs is run via CTest, it assumes
that the testing "server" is started prior to execution. To start the
server, just run ::

npm run start-test

This will start a server on the default port of ``30100``. The port
and selenium host names are configurable with cmake. For example inside
the Kitware firewall, you can run the following to test on the selenium
node on ``garant`` ::

cmake -DSELENIUM_TESTS=ON -DSELENIUM_HOST=garant /path/to/geojs
make
ctest -VV

You may need to also set the variable ``TESTING_HOST`` to your computer's
IP address reachable by the selenium node.

Most tests for geojs require a full browser with webgl support.
For these test, a framework based on `Selenium <http://docs.seleniumhq.org/>`_
is provided. This test framework is intentionally lightweight to allow
for many different kinds of testing from simple Jasmine style unit tests
to complicated mouse interactions with screenshot comparisons.

All selenium based tests should be placed inside subdirectories of
``testing/test-cases/selenium-tests``. All subdirectories are assumed
to be selenium tests by CMake and will be instrumented and run accordingly.
Each subdirectory should, at a minimum, contain the following three files,
which may be empty:

1. ``include.css``: CSS that will be concatenated into a ``style`` node
in the ``head``.

2. ``include.html``: HTML that will be concatenated into the ``body``.

3. ``include.js``: Javascript source that will be concatenated into a ``script``
node in the ``head`` after the inclusion of the geojs source and all dependent
libraries.

Generally, developers are free to put arbitrary content into these files; however,
one convention **must** be followed for the default instrumentation to work correctly.
The javascript source should be wrapped in a global function called ``startTest``.
This function will be called automatically by the testing framework after all of
the instrumentation is in place and the page is loaded. The ``startTest`` function will
be called with function as an argument that should be called when page is ready to
run the unit tests. This is provided as a convenience for the default behavior
of :py:func:`selenium_test.BaseTest.wait` with no arguments. Developers can
extend this behavior as necessary to provide more complicated use cases.

The compiled version of these
tests are placed inside the deployment root so the users can manually see the test
results. The path to each test is derived from the relative path inside
``testing/test-cases/selenium-tests/``. For example, the test page in
``testing/test-cases/selenium-tests/osmLayer/`` is available at
`<http://localhost:30100/test/selenium/osmLayer/>`_ after starting the test web server.

The unit tests themselves are derived from Python's
`unittest <https://docs.python.org/2/library/unittest.html>`_ module via a customized
subclass :py:class:`selenium_test.BaseTest`. Detailed documentation of the methods
this class provides is given in the next section. Developers should feel free to
extend this class with any generally useful methods as they become necessary for
a wider variety test cases.

Example unit test
^^^^^^^^^^^^^^^^^

The following is a minimal example of a selenium unit test using the testing framework.
More complicated examples can be found by examining the existing tests present
in the source.

``hello/index.html``:

.. code-block:: html

<div id="div-node"></div>

``hello/index.css``:

.. code-block:: css
#div-node {
text-align: center;
}
``hello/index.js``:

.. code-block:: js
window.startTest = function (done) {
$("#div-node").text("Hello, World!");
done();
};
``hello/testHelloWorld.py``:

.. code-block:: python
# Importing setupModule and tearDownModule will start up and
# shut down the web server automatically.
from selenium_test import FirefoxTest, setupModule, tearDownModule
# This test will run on firefox only.
class HelloWorld(FirefoxTest):
testCase = ('hello', 'world')
def test_main(self):
# Resize the window to have consistent results.
self.resizeWindow(640, 480)
# Load the main html for this test directory.
self.loadUrl('hello/index.html')
# Wait for it to be loaded.
self.wait()
# Now we are ready to test the page.
# The base class provide easy methods to test a screen shot.
# This will take a screen shot and compare it against any
# screenshots in the test image store at revision number 1.
# Any failure here will raise an exception that will mark the
# test as failed.
self.screenshotTest('helloWorldScreenshot', revision=1)
Uploading screenshots to the image store
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

A script is provided in the source to help developers upload
images to the data store in a way that they can be loaded automatically
by the testing infrastructure. The script is built into ``test/upload_test_cases.py``
when selenium testing is enabled in CMake. When creating a new test
(or updating a revision), the following is the recommended method for uploading
test data for the example test ``hello/`` described above. ::

# inside the build directory
python test/upload_test_cases.py ../testing/test-cases/selenium-tests/hello

The script will run all the tests in this directory and prompt you if you want to upload a new image
in the event that a screenshot test has failed. If you intend to start a new
revision, then the revision number should be changed in the unit test source
before running this script. Note: you must have write permission in the MIDAS
GeoJS community before you can upload new images. Contact a community administrator
for an invitation.

5 changes: 0 additions & 5 deletions docs/midas_handler.rst

This file was deleted.

7 changes: 3 additions & 4 deletions docs/provisioning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ Provisioning for Development
Ubuntu 14.04
-------------

This shows how to set up a build and test environment in Ubuntu 14.04, using
all but the Selenium-based tests.
This shows how to set up a build and test environment in Ubuntu 14.04.

These instructions will probably work for any Ubuntu release from 14.04
onward. They assume a basic installation, as, for instance, from the
Expand Down Expand Up @@ -64,9 +63,9 @@ Run the headless WebGL tests ::

xvfb-run -s '-ac -screen 0 1280x1024x24' ctest -VV -R ffheadless

Run all but the Selenium tests ::
Run all tests ::

xvfb-run -s '-ac -screen 0 1280x1024x24' ctest --output-on-failure -E selenium
xvfb-run -s '-ac -screen 0 1280x1024x24' ctest --output-on-failure

Install python packages ::

Expand Down
1 change: 0 additions & 1 deletion docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ and testing of geojs.
* `Girder Client <http://girder.readthedocs.io>`_
* `Pillow <http://pillow.readthedocs.io>`_
* `Requests <http://docs.python-requests.org/en/latest/>`_
* `Selenium <http://docs.seleniumhq.org/>`_

For testing WebGL in a headless environment, the additional packages are needed:

Expand Down
1 change: 0 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Pillow
selenium
requests
sphinx_rtd_theme
graphviz
5 changes: 0 additions & 5 deletions docs/selenium_test.rst

This file was deleted.

2 changes: 0 additions & 2 deletions docs/testingutils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,4 @@ Testing infrastructure
:maxdepth: 2

baseline_images
selenium_test
midas_handler
upload_test_cases
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"d3": "^3.5.16"
},
"devDependencies": {
"blanket": "~1.2",
"body-parser": "^1.15.0",
"bootstrap": "^3.3.6",
"bootswatch": "^3.3.6",
Expand Down
2 changes: 1 addition & 1 deletion src/d3/d3Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ var d3Renderer = function (arg) {
m_svg.attr('width', w);
m_svg.attr('height', h);
m_this._setTransform();
m_this.layer().geoTrigger(geo_event.d3Rescale, { scale: m_scale }, true);
m_this.layer().geoTrigger(d3Rescale, { scale: m_scale }, true);
};

////////////////////////////////////////////////////////////////////////////
Expand Down
11 changes: 7 additions & 4 deletions src/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -1689,10 +1689,13 @@ var map = function (arg) {
return;
}
layer.node().children('canvas').each(function () {
if (layer.renderer().api() === 'vgl') {
layer.renderer()._renderFrame();
}
drawLayerImageToContext(context, opacity, $(this), $(this)[0]);
var canvasElem = $(this);
defer = defer.then(function () {
if (layer.renderer().api() === 'vgl') {
layer.renderer()._renderFrame();
}
drawLayerImageToContext(context, opacity, canvasElem, canvasElem[0]);
});
});
if (layer.node().children().not('canvas').length) {
defer = defer.then(function () {
Expand Down
Loading

0 comments on commit 93192bf

Please sign in to comment.