Commit acb7721f authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'rs-teaspoon' into 'master'

Add Teaspoon for Javascript testing

Looking to expand our Javascript unit tests, and this gem makes things a bit better in that respect.

See https://github.com/modeset/teaspoon

See merge request !715
parents ac584d6b bd12ca5e
......@@ -253,11 +253,13 @@ group :development, :test do
# PhantomJS driver for Capybara
gem 'poltergeist', '~> 1.5.1'
gem 'jasmine-rails'
gem 'teaspoon', '~> 1.0.0'
gem 'teaspoon-jasmine'
gem "spring", '~> 1.3.1'
gem "spring-commands-rspec", '1.0.4'
gem "spring-commands-spinach", '1.0.0'
gem 'spring', '~> 1.3.1'
gem 'spring-commands-rspec', '~> 1.0.0'
gem 'spring-commands-spinach', '~> 1.0.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem "byebug"
end
......
......@@ -300,12 +300,6 @@ GEM
i18n (0.7.0)
ice_cube (0.11.1)
ice_nine (0.10.0)
jasmine-core (2.2.0)
jasmine-rails (0.10.8)
jasmine-core (>= 1.3, < 3.0)
phantomjs (>= 1.9)
railties (>= 3.2.0)
sprockets-rails
jquery-atwho-rails (1.0.1)
jquery-rails (3.1.0)
railties (>= 3.0, < 5.0)
......@@ -400,7 +394,6 @@ GEM
parser (2.2.0.2)
ast (>= 1.1, < 3.0)
pg (0.15.1)
phantomjs (1.9.8.0)
poltergeist (1.5.1)
capybara (~> 2.1)
cliver (~> 0.3.1)
......@@ -594,6 +587,8 @@ GEM
spring (>= 0.9.1)
spring-commands-spinach (1.0.0)
spring (>= 0.9.1)
spring-commands-teaspoon (0.0.2)
spring (>= 0.9.1)
sprockets (2.11.0)
hike (~> 1.2)
multi_json (~> 1.0)
......@@ -608,6 +603,10 @@ GEM
stringex (2.5.2)
task_list (1.0.2)
html-pipeline
teaspoon (1.0.2)
railties (>= 3.2.5, < 5)
teaspoon-jasmine (2.2.0)
teaspoon (>= 1.0.0)
temple (0.6.7)
term-ansicolor (1.2.2)
tins (~> 0.8)
......@@ -737,7 +736,6 @@ DEPENDENCIES
hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0)
httparty
jasmine-rails
jquery-atwho-rails (~> 1.0.0)
jquery-rails
jquery-scrollto-rails
......@@ -798,11 +796,14 @@ DEPENDENCIES
slim
spinach-rails
spring (~> 1.3.1)
spring-commands-rspec (= 1.0.4)
spring-commands-spinach (= 1.0.0)
spring-commands-rspec (~> 1.0.0)
spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2)
stamp
state_machine
task_list (= 1.0.2)
teaspoon (~> 1.0.0)
teaspoon-jasmine
test_after_commit
thin
tinder (~> 1.9.2)
......
#= require jquery
#= require jquery.waitforimages
#= require task_list
......
#= require jquery
#= require bootstrap
#= require jquery.waitforimages
#= require task_list
class @MergeRequest
......
#= require jquery
#= require autosave
#= require bootstrap
#= require dropzone
#= require dropzone_input
#= require gfm_auto_complete
......
#= require jquery
#= require mousetrap
#= require shortcuts_navigation
class @ShortcutsIssuable extends ShortcutsNavigation
......
#= require d3
#= require jquery
#= require stat_graph_contributors_util
class @ContributorsStatGraph
......
......@@ -3,7 +3,8 @@ if Rails.env.development?
# initialization is skipped so trigger it
Rack::MiniProfilerRails.initialize!(Rails.application)
Rack::MiniProfiler.config.position = 'right'
Rack::MiniProfiler.config.start_hidden = true
Rack::MiniProfiler.config.skip_paths << '/specs'
Rack::MiniProfiler.config.skip_paths << '/teaspoon'
end
......@@ -2,7 +2,6 @@ require 'sidekiq/web'
require 'api/api'
Gitlab::Application.routes.draw do
mount JasmineRails::Engine => '/specs' if defined?(JasmineRails)
use_doorkeeper do
controllers applications: 'oauth/applications',
authorized_applications: 'oauth/authorized_applications',
......
......@@ -7,6 +7,6 @@ task jasmine: ['jasmine:ci']
namespace :jasmine do
task :ci do
Rake::Task['spec:javascript'].invoke
Rake::Task['teaspoon'].invoke
end
end
%form.js-main-target-form
%textarea#note_note
%ul
%li.note
.js-task-list-container
.note-text
%ul.task-list
%li.task-list-item
%input.task-list-item-checkbox{type: 'checkbox'}
Task List Item
.note-edit-form
%form
%textarea.js-task-list-field
\- [ ] Task List Item
%a.btn-close
.issue-details
.description.js-task-list-container
.wiki
%ul.task-list
%li.task-list-item
%input.task-list-item-checkbox{type: 'checkbox'}
Task List Item
%textarea.js-task-list-field
\- [ ] Task List Item
%form.js-issue-update{action: '/foo'}
%a.btn-close
.merge-request-details
.description.js-task-list-container
.wiki
%ul.task-list
%li.task-list-item
%input.task-list-item-checkbox{type: 'checkbox'}
Task List Item
%textarea.js-task-list-field
\- [ ] Task List Item
%form.js-merge-request-update{action: '/foo'}
#= require jquery
#= require jasmine-fixture
#= require issue
describe 'Issue', ->
describe 'task lists', ->
selectors = {
container: '.issue-details .description.js-task-list-container'
item: '.wiki ul.task-list li.task-list-item input.task-list-item-checkbox[type=checkbox] {Task List Item}'
textarea: '.wiki textarea.js-task-list-field{- [ ] Task List Item}'
form: 'form.js-issue-update[action="/foo"]'
close: 'a.btn-close'
}
fixture.preload('issues_show.html')
beforeEach ->
$container = affix(selectors.container)
# # These two elements are siblings inside the container
$container.find('.js-task-list-container').append(affix(selectors.item))
$container.find('.js-task-list-container').append(affix(selectors.textarea))
# Task lists don't get initialized unless this button exists. Not ideal.
$container.append(affix(selectors.close))
# This form is used to get the `update` URL. Not ideal.
$container.append(affix(selectors.form))
fixture.load('issues_show.html')
@issue = new Issue()
it 'modifies the Markdown field', ->
spyOn(jQuery, 'ajax').and.stub()
$('input[type=checkbox]').attr('checked', true).trigger('change')
expect($('.js-task-list-field').val()).toBe('- [x] Task List Item')
it 'submits an ajax request on tasklist:changed', ->
spyOn($, 'ajax').and.callFake (req) ->
spyOn(jQuery, 'ajax').and.callFake (req) ->
expect(req.type).toBe('PATCH')
expect(req.url).toBe('/foo')
expect(req.data.issue.description).not.toBe(null)
......
#= require jquery
#= require jasmine-fixture
#= require merge_request
window.disableButtonIfEmptyField = -> null
describe 'MergeRequest', ->
describe 'task lists', ->
selectors = {
container: '.merge-request-details .description.js-task-list-container'
item: '.wiki ul.task-list li.task-list-item input.task-list-item-checkbox[type=checkbox] {Task List Item}'
textarea: '.wiki textarea.js-task-list-field{- [ ] Task List Item}'
form: 'form.js-merge-request-update[action="/foo"]'
close: 'a.btn-close'
}
fixture.preload('merge_requests_show.html')
beforeEach ->
$container = affix(selectors.container)
# # These two elements are siblings inside the container
$container.find('.js-task-list-container').append(affix(selectors.item))
$container.find('.js-task-list-container').append(affix(selectors.textarea))
# Task lists don't get initialized unless this button exists. Not ideal.
$container.append(affix(selectors.close))
fixture.load('merge_requests_show.html')
@merge = new MergeRequest({})
# This form is used to get the `update` URL. Not ideal.
$container.append(affix(selectors.form))
it 'modifies the Markdown field', ->
spyOn(jQuery, 'ajax').and.stub()
@merge = new MergeRequest({})
$('input[type=checkbox]').attr('checked', true).trigger('change')
expect($('.js-task-list-field').val()).toBe('- [x] Task List Item')
it 'submits an ajax request on tasklist:changed', ->
spyOn($, 'ajax').and.callFake (req) ->
spyOn(jQuery, 'ajax').and.callFake (req) ->
expect(req.type).toBe('PATCH')
expect(req.url).toBe('/foo')
expect(req.data.merge_request.description).not.toBe(null)
......
#= require jquery
#= require jasmine-fixture
#= require notes
window.gon = {}
......@@ -7,21 +5,18 @@ window.disableButtonIfEmptyField = -> null
describe 'Notes', ->
describe 'task lists', ->
selectors = {
container: 'li.note .js-task-list-container'
item: '.note-text ul.task-list li.task-list-item input.task-list-item-checkbox[type=checkbox] {Task List Item}'
textarea: '.note-edit-form form textarea.js-task-list-field{- [ ] Task List Item}'
}
fixture.preload('issue_note.html')
beforeEach ->
$container = affix(selectors.container)
# These two elements are siblings inside the container
$container.find('.js-task-list-container').append(affix(selectors.item))
$container.find('.js-task-list-container').append(affix(selectors.textarea))
fixture.load('issue_note.html')
$('form').on 'submit', (e) -> e.preventDefault()
@notes = new Notes()
it 'modifies the Markdown field', ->
$('input[type=checkbox]').attr('checked', true).trigger('change')
expect($('.js-task-list-field').val()).toBe('- [x] Task List Item')
it 'submits the form on tasklist:changed', ->
submitted = false
$('form').on 'submit', (e) -> submitted = true; e.preventDefault()
......
#= require jquery
#= require jasmine-fixture
#= require shortcuts_issuable
describe 'ShortcutsIssuable', ->
fixture.preload('issuable.html')
beforeEach ->
fixture.load('issuable.html')
@shortcut = new ShortcutsIssuable()
describe '#replyWithSelectedText', ->
......@@ -14,7 +14,6 @@ describe 'ShortcutsIssuable', ->
beforeEach ->
@selector = 'form.js-main-target-form textarea#note_note'
affix(@selector)
describe 'with empty selection', ->
it 'does nothing', ->
......
# Teaspoon includes some support files, but you can use anything from your own
# support path too.
# require support/jasmine-jquery-1.7.0
# require support/jasmine-jquery-2.0.0
# require support/jasmine-jquery-2.1.0
# require support/sinon
# require support/your-support-file
# PhantomJS (Teaspoons default driver) doesn't have support for
# Function.prototype.bind, which has caused confusion. Use this polyfill to
# avoid the confusion.
#= require support/bind-poly
# You can require your own javascript files here. By default this will include
# everything in application, however you may get better load performance if you
# require the specific files that are being used in the spec that tests them.
#= require jquery
#= require bootstrap
#= require underscore
# Deferring execution
# If you're using CommonJS, RequireJS or some other asynchronous library you can
# defer execution. Call Teaspoon.execute() after everything has been loaded.
# Simple example of a timeout:
# Teaspoon.defer = true
# setTimeout(Teaspoon.execute, 1000)
# Matching files
# By default Teaspoon will look for files that match
# _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your spec path
# and it'll be included in the default suite automatically. If you want to
# customize suites, check out the configuration in teaspoon_env.rb
# Manifest
# If you'd rather require your spec files manually (to control order for
# instance) you can disable the suite matcher in the configuration and use this
# file as a manifest.
# For more information: http://github.com/modeset/teaspoon
# path to parent directory of spec_files
# relative path from Rails.root
#
# Alternatively accept an array of directory to include external spec files
# spec_dir:
# - spec/javascripts
# - ../engine/spec/javascripts
#
# defaults to spec/javascripts
spec_dir: spec/javascripts
# list of file expressions to include as specs into spec runner
# relative path from spec_dir
spec_files:
- "**/*[Ss]pec.{js.coffee,js,coffee}"
#Use this file to set/override Jasmine configuration options
#You can remove it if you don't need it.
#This file is loaded *after* jasmine.yml is interpreted.
#
#Example: using a different boot file.
#Jasmine.configure do |config|
# config.boot_dir = '/absolute/path/to/boot_dir'
# config.boot_files = lambda { ['/absolute/path/to/boot_dir/file.js'] }
#end
#
#Example: prevent PhantomJS auto install, uses PhantomJS already on your path.
#Jasmine.configure do |config|
# config.prevent_phantom_js_auto_install = true
#end
#
Teaspoon.configure do |config|
# Determines where the Teaspoon routes will be mounted. Changing this to "/jasmine" would allow you to browse to
# `http://localhost:3000/jasmine` to run your tests.
config.mount_at = "/teaspoon"
# Specifies the root where Teaspoon will look for files. If you're testing an engine using a dummy application it can
# be useful to set this to your engines root (e.g. `Teaspoon::Engine.root`).
# Note: Defaults to `Rails.root` if nil.
config.root = nil
# Paths that will be appended to the Rails assets paths
# Note: Relative to `config.root`.
config.asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets"]
# Fixtures are rendered through a controller, which allows using HAML, RABL/JBuilder, etc. Files in these paths will
# be rendered as fixtures.
config.fixture_paths = ["spec/javascripts/fixtures"]
# SUITES
#
# You can modify the default suite configuration and create new suites here. Suites are isolated from one another.
#
# When defining a suite you can provide a name and a block. If the name is left blank, :default is assumed. You can
# omit various directives and the ones defined in the default suite will be used.
#
# To run a specific suite
# - in the browser: http://localhost/teaspoon/[suite_name]
# - with the rake task: rake teaspoon suite=[suite_name]
# - with the cli: teaspoon --suite=[suite_name]
config.suite do |suite|
# Specify the framework you would like to use. This allows you to select versions, and will do some basic setup for
# you -- which you can override with the directives below. This should be specified first, as it can override other
# directives.
# Note: If no version is specified, the latest is assumed.
#
# Versions: 1.3.1, 2.0.3, 2.1.3, 2.2.0
suite.use_framework :jasmine, "2.2.0"
# Specify a file matcher as a regular expression and all matching files will be loaded when the suite is run. These
# files need to be within an asset path. You can add asset paths using the `config.asset_paths`.
suite.matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.coffee,coffee}"
# Load additional JS files, but requiring them in your spec helper is the preferred way to do this.
#suite.javascripts = []
# You can include your own stylesheets if you want to change how Teaspoon looks.
# Note: Spec related CSS can and should be loaded using fixtures.
#suite.stylesheets = ["teaspoon"]
# This suites spec helper, which can require additional support files. This file is loaded before any of your test
# files are loaded.
suite.helper = "spec_helper"
# Partial to be rendered in the head tag of the runner. You can use the provided ones or define your own by creating
# a `_boot.html.erb` in your fixtures path, and adjust the config to `"/boot"` for instance.
#
# Available: boot, boot_require_js
suite.boot_partial = "boot"
# Partial to be rendered in the body tag of the runner. You can define your own to create a custom body structure.
suite.body_partial = "body"
# Hooks allow you to use `Teaspoon.hook("fixtures")` before, after, or during your spec run. This will make a
# synchronous Ajax request to the server that will call all of the blocks you've defined for that hook name.
#suite.hook :fixtures, &proc{}
# Determine whether specs loaded into the test harness should be embedded as individual script tags or concatenated
# into a single file. Similar to Rails' asset `debug: true` and `config.assets.debug = true` options. By default,
# Teaspoon expands all assets to provide more valuable stack traces that reference individual source files.
#suite.expand_assets = true
end
# Example suite. Since we're just filtering to files already within the root test/javascripts, these files will also
# be run in the default suite -- but can be focused into a more specific suite.
#config.suite :targeted do |suite|
# suite.matcher = "spec/javascripts/targeted/*_spec.{js,js.coffee,coffee}"
#end
# CONSOLE RUNNER SPECIFIC
#
# These configuration directives are applicable only when running via the rake task or command line interface. These
# directives can be overridden using the command line interface arguments or with ENV variables when using the rake
# task.
#
# Command Line Interface:
# teaspoon --driver=phantomjs --server-port=31337 --fail-fast=true --format=junit --suite=my_suite /spec/file_spec.js
#
# Rake:
# teaspoon DRIVER=phantomjs SERVER_PORT=31337 FAIL_FAST=true FORMATTERS=junit suite=my_suite
# Specify which headless driver to use. Supports PhantomJS and Selenium Webdriver.
#
# Available: :phantomjs, :selenium, :capybara_webkit
# PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS
# Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver
# Capybara Webkit: https://github.com/modeset/teaspoon/wiki/Using-Capybara-Webkit
#config.driver = :phantomjs
# Specify additional options for the driver.
#
# PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS
# Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver
# Capybara Webkit: https://github.com/modeset/teaspoon/wiki/Using-Capybara-Webkit
#config.driver_options = nil
# Specify the timeout for the driver. Specs are expected to complete within this time frame or the run will be
# considered a failure. This is to avoid issues that can arise where tests stall.
#config.driver_timeout = 180
# Specify a server to use with Rack (e.g. thin, mongrel). If nil is provided Rack::Server is used.
#config.server = nil
# Specify a port to run on a specific port, otherwise Teaspoon will use a random available port.
#config.server_port = nil
# Timeout for starting the server in seconds. If your server is slow to start you may have to bump this, or you may
# want to lower this if you know it shouldn't take long to start.
#config.server_timeout = 20
# Force Teaspoon to fail immediately after a failing suite. Can be useful to make Teaspoon fail early if you have
# several suites, but in environments like CI this may not be desirable.
#config.fail_fast = true
# Specify the formatters to use when outputting the results.
# Note: Output files can be specified by using `"junit>/path/to/output.xml"`.
#
# Available: :dot, :clean, :documentation, :json, :junit, :pride, :rspec_html, :snowday, :swayze_or_oprah, :tap, :tap_y, :teamcity
#config.formatters = [:dot]
# Specify if you want color output from the formatters.
#config.color = true
# Teaspoon pipes all console[log/debug/error] to $stdout. This is useful to catch places where you've forgotten to
# remove them, but in verbose applications this may not be desirable.
#config.suppress_log = false
# COVERAGE REPORTS / THRESHOLD ASSERTIONS
#
# Coverage reports requires Istanbul (https://github.com/gotwarlost/istanbul) to add instrumentation to your code and
# display coverage statistics.
#
# Coverage configurations are similar to suites. You can define several, and use different ones under different
# conditions.
#
# To run with a specific coverage configuration
# - with the rake task: rake teaspoon USE_COVERAGE=[coverage_name]
# - with the cli: teaspoon --coverage=[coverage_name]
# Specify that you always want a coverage configuration to be used. Otherwise, specify that you want coverage
# on the CLI.
# Set this to "true" or the name of your coverage config.
#config.use_coverage = nil
# You can have multiple coverage configs by passing a name to config.coverage.
# e.g. config.coverage :ci do |coverage|
# The default coverage config name is :default.
config.coverage do |coverage|
# Which coverage reports Istanbul should generate. Correlates directly to what Istanbul supports.
#
# Available: text-summary, text, html, lcov, lcovonly, cobertura, teamcity
#coverage.reports = ["text-summary", "html"]
# The path that the coverage should be written to - when there's an artifact to write to disk.
# Note: Relative to `config.root`.
#coverage.output_path = "coverage"
# Assets to be ignored when generating coverage reports. Accepts an array of filenames or regular expressions. The
# default excludes assets from vendor, gems and support libraries.
#coverage.ignore = [%r{/lib/ruby/gems/}, %r{/vendor/assets/}, %r{/support/}, %r{/(.+)_helper.}]
# Various thresholds requirements can be defined, and those thresholds will be checked at the end of a run. If any
# aren't met the run will fail with a message. Thresholds can be defined as a percentage (0-100), or nil.
#coverage.statements = nil
#coverage.functions = nil
#coverage.branches = nil
#coverage.lines = nil
end
end
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment