Skip to content

netzke/netzke-testing

Repository files navigation

Netzke Testing Build Status Gem Version

This gem helps with development and testing of Netzke components. In parcticular, it helps you with:

  • isolated component development
  • client-side testing of components with Mocha and Expect.js

Usage:

gem 'netzke-testing'

Isolated component development

The gem implements a Rails engine, which (in development and test environments only) adds a route to load your application's Netzke components individually, which can be useful for isolated development. Example (say, we have a UserGrid component defined):

http://localhost:3000/netzke/components/UserGrid

This will load a view with UserGrid occupying the available window width, with default height of 400px. You can change the height by providing the height parameter in the URL:

http://localhost:3000/netzke/components/UserGrid?height=600

Testing components with Mocha and Expect.js

Place the Mocha specs (written in Coffeescript) for your components inside spec/features/javascripts folder. An example spec may look like this (in spec/features/javascripts/user_grid.js.coffee):

describe 'UserGrid', ->
  it 'shows proper title', ->
    expect(grid().getHeader().title).to.eql 'Test component'

This spec can be run by appending the spec parameter to the url:

http://localhost:3000/netzke/components/UserGrid?spec=user_grid

Specs can be structured into directories. For example, let's say we have a namescope for admin components:

class Admin::UserGrid < Netzke::Grid::Base
end

It makes sense to put the corresponding specs in spec/features/javascripts/admin/user_grid.js.coffee. In this case, the URL to run the Mocha specs will be:

http://localhost:3000/netzke/components/UserGrid?spec=admin/user_grid

Mocha spec helpers

The gem provides a number of helpers that may help you writing less code and make your specs look something like this:

describe 'UserGrid', ->
  it 'allows instant removing of all users with a single button click', (done) ->
    click button 'Remove all'
    wait ->
      expectToSee header 'Empty'
      done()

In order to enable these helpers, add the following line somewhere in your RSpec.configure block:

RSpec.configure do |config|
  Netzke::Testing.rspec_init(config)
  # ...
end

Keep in mind the following:

  • the current set of helpers is in flux, and may be drastically changed sooner than you may expect
  • the helpers directly pollute the global (window) namespace; if you decide you're better off without provided helpers, specify 'no-helpers=true' as an extra URL parameter

See the source code for currently implemented helpers (TODO: document them). Also, refer to other Netzke gems source code (like netzke-core and netzke-basepack) to see examples using the helpers.

Adding custom spec helpers

You may add (or require, by means of Sprockets) additional helpers in app/assets/javascripts/netzke/testing.js, which will be included in the testing template after the helpers provided by netzke-testing. For example:

// in app/assets/javascripts/netzke/testing.js
//= require_tree ./testing

# in app/assets/javascripts/netzke/testing/grid.js.coffee
Ext.apply window,
  enableColumnFilter: (column, value) ->
  # ...

After this the enableColumnFilter helper will be available in your Mocha specs.

Testing with selenium webdriver

Generate the netzke_mocha_spec.rb file that will automatically run the specs that follow a certain naming convention:

rails g netzke_testing

This spec will pick up all the *_spec.js.coffee files from spec/features/javascripts folder and generate an it clause for each of them. Let's say we want to create the spec for UserGrid. For this we name the spec file spec/features/javascripts/user_grid_spec.js.coffee. And the other way around: when netzke_mocha_spec.rb finds a file called spec/features/javascripts/order_grid_spec.js.coffee, it'll assume existance of OrderGrid component that should be tested.

Mixing client- and server-side testing code

Often we want to run some Ruby code before running the Mocha spec (e.g. to seed some test data using factories), or after (e.g. to assert changes in the database). In this case you can create a RSpec spec that uses the run_mocha_spec helper provided by the netzke_testing gem. Here's an example (in spec/user_grid_spec.rb):

require 'spec_helper'
feature GridWithDestructiveButton do
  it 'allows instant removing of all records with a single button click', js: true do
    10.times { FactoryGirl.create :user }
    expect(User.count).to eql == 10
    run_mocha_spec 'grid_with_destructive_button'
    expect(User.count).to eql == 0
  end
end

The run_mocha_spec here will run a Mocha spec from spec/grid_with_destructive_button.js.coffee.

You can explicitely specify a component to run the spec on:

run_mocha_spec 'grid_with_destructive_button', component: 'UserGrid'

To investigate the problem in case of a failing Mocha spec, set stop_on_error to true (this will keep the browser open on the failed spec):

run_mocha_spec 'grid_with_destructive_button', stop_on_error: true

(in this case you'll have to terminate the specs by pressing ctrl+c)

Setting timeout for longer running JS specs

Netzke-testing by default assumes that your specs do not take longer than 5 seconds, and mark them failed if they do. If your spec are as complex as taking longer than that, you can increase this value in an initializer, e.g.:

# in config/initializers/netzke.rb
Netzke::Testing.setup do |config|
  config.js_timeout = 10 # seconds
end

You could also set this in spec_helper.rb like this:

Netzke::Testing.js_timeout = 10

However, keep in mind, that this won't have effect on running specs manually in the browser (by specifying the spec URL parameter, as shown above). For this case, you may provide the timeout URL paramter (takes precedence over Netzke::Testing.js_timeout):

http://localhost:3000/netzke/components/UserGrid?spec=user_grid&timeout=10

Asynchronous helpers

Asynchronous helpers like wait can either call the provided callback function, or (if none was provided) return a promise, so you can do:

it 'does something asynchronous', ->
  wait().
  .then ->
    doSomething()
    wait()
  .then
    doSomeMore()

NOTE: we should not use the done parameter here, as promises are handled differently than callbacks by Mocha.

Note on headless browser testing

No headless browsers like PhantomJS or WebKit were used for testing because our tests rely heavily on HTMLElement's click event, which is only properly implemented in "real" browsers like Firefox (which is what we use).

Requirements

  • Ruby >= 2.3.0
  • Rails ~> 5.1.0
  • Ext JS = 6.5.1

Copyright (c) 2009-2017 Good Bit Labs, released under the same license as Ext JS