hyper-spec 1.0.alpha1.8 → 1.0.0.lap28
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -4
- data/.rubocop.yml +107 -0
- data/.travis.yml +15 -20
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +1 -5
- data/LICENSE.txt +21 -0
- data/README.md +380 -0
- data/Rakefile +2 -0
- data/bin/console +0 -0
- data/bin/setup +0 -0
- data/dciy.toml +3 -0
- data/hyper-spec.gemspec +21 -19
- data/lib/hyper-spec.rb +23 -174
- data/lib/hyper-spec/component_test_helpers.rb +360 -0
- data/lib/hyper-spec/{internal/time_cop.rb → time_cop.rb} +2 -14
- data/lib/hyper-spec/version.rb +1 -1
- data/lib/hyper-spec/wait_for_ajax.rb +4 -4
- data/lib/react/top_level_rails_component.rb +94 -0
- metadata +54 -107
- data/lib/hyper-spec/controller_helpers.rb +0 -164
- data/lib/hyper-spec/expectations.rb +0 -64
- data/lib/hyper-spec/helpers.rb +0 -225
- data/lib/hyper-spec/internal/client_execution.rb +0 -94
- data/lib/hyper-spec/internal/component_mount.rb +0 -140
- data/lib/hyper-spec/internal/controller.rb +0 -70
- data/lib/hyper-spec/internal/copy_locals.rb +0 -103
- data/lib/hyper-spec/internal/patches.rb +0 -86
- data/lib/hyper-spec/internal/rails_controller_helpers.rb +0 -50
- data/lib/hyper-spec/internal/window_sizing.rb +0 -73
- data/lib/hyper-spec/rack.rb +0 -67
- data/lib/sources/top_level_rails_component.rb +0 -103
- data/multi_level_how_it_works.md +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b567b6e5e1eb4555bcf41ada038f247a2f83c346be6d21593f9777f9b73dfb8
|
4
|
+
data.tar.gz: c1691e64e39fad1442c94782f6e3094460b635bce026767b3ece63d757d0a24d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eeaa28e71f46802e74d4d2ecaf6405f8a9518e030d371c7397ede62976c66fe309be3a8f3a5b1434c5e56765ad73117e9660618bcc158830d9eb485a7fc157ea
|
7
|
+
data.tar.gz: 93fb42f8f0212cd415dddfd17e7d7ee235f1c2fb470edb1957bd8d8c4bf3b04a50f7290c450374fd5edd5c915a3e16848b314e79df13f4945d1a44801c3256a3
|
data/.gitignore
CHANGED
@@ -13,6 +13,7 @@ capybara-*.html
|
|
13
13
|
**.orig
|
14
14
|
rerun.txt
|
15
15
|
pickle-email-*.html
|
16
|
+
Gemfile.lock
|
16
17
|
|
17
18
|
# TODO Comment out these rules if you are OK with secrets being uploaded to the repo
|
18
19
|
config/initializers/secret_token.rb
|
@@ -52,7 +53,3 @@ bower.json
|
|
52
53
|
|
53
54
|
# ignore Idea files
|
54
55
|
.idea
|
55
|
-
|
56
|
-
# ignore Gemfile.locks https://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
|
57
|
-
/spec/test_app/Gemfile.lock
|
58
|
-
/Gemfile.lock
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
Style/BlockDelimiters:
|
2
|
+
EnforcedStyle: line_count_based
|
3
|
+
SupportedStyles:
|
4
|
+
# The `line_count_based` style enforces braces around single line blocks and
|
5
|
+
# do..end around multi-line blocks.
|
6
|
+
- line_count_based
|
7
|
+
# The `semantic` style enforces braces around functional blocks, where the
|
8
|
+
# primary purpose of the block is to return a value and do..end for
|
9
|
+
# procedural blocks, where the primary purpose of the block is its
|
10
|
+
# side-effects.
|
11
|
+
#
|
12
|
+
# This looks at the usage of a block's method to determine its type (e.g. is
|
13
|
+
# the result of a `map` assigned to a variable or passed to another
|
14
|
+
# method) but exceptions are permitted in the `ProceduralMethods`,
|
15
|
+
# `FunctionalMethods` and `IgnoredMethods` sections below.
|
16
|
+
- semantic
|
17
|
+
# The `braces_for_chaining` style enforces braces around single line blocks
|
18
|
+
# and do..end around multi-line blocks, except for multi-line blocks whose
|
19
|
+
# return value is being chained with another method (in which case braces
|
20
|
+
# are enforced).
|
21
|
+
- braces_for_chaining
|
22
|
+
ProceduralMethods:
|
23
|
+
# Methods that are known to be procedural in nature but look functional from
|
24
|
+
# their usage, e.g.
|
25
|
+
#
|
26
|
+
# time = Benchmark.realtime do
|
27
|
+
# foo.bar
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Here, the return value of the block is discarded but the return value of
|
31
|
+
# `Benchmark.realtime` is used.
|
32
|
+
- benchmark
|
33
|
+
- bm
|
34
|
+
- bmbm
|
35
|
+
- create
|
36
|
+
- each_with_object
|
37
|
+
- measure
|
38
|
+
- new
|
39
|
+
- realtime
|
40
|
+
- tap
|
41
|
+
- with_object
|
42
|
+
FunctionalMethods:
|
43
|
+
# Methods that are known to be functional in nature but look procedural from
|
44
|
+
# their usage, e.g.
|
45
|
+
#
|
46
|
+
# let(:foo) { Foo.new }
|
47
|
+
#
|
48
|
+
# Here, the return value of `Foo.new` is used to define a `foo` helper but
|
49
|
+
# doesn't appear to be used from the return value of `let`.
|
50
|
+
- let
|
51
|
+
- let!
|
52
|
+
- subject
|
53
|
+
- watch
|
54
|
+
IgnoredMethods:
|
55
|
+
# Methods that can be either procedural or functional and cannot be
|
56
|
+
# categorised from their usage alone, e.g.
|
57
|
+
#
|
58
|
+
# foo = lambda do |x|
|
59
|
+
# puts "Hello, #{x}"
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# foo = lambda do |x|
|
63
|
+
# x * 100
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# Here, it is impossible to tell from the return value of `lambda` whether
|
67
|
+
# the inner block's return value is significant.
|
68
|
+
- lambda
|
69
|
+
- proc
|
70
|
+
- it
|
71
|
+
|
72
|
+
Style/Documentation:
|
73
|
+
Description: 'Document classes and non-namespace modules.'
|
74
|
+
Enabled: false
|
75
|
+
Exclude:
|
76
|
+
- 'spec/**/*'
|
77
|
+
- 'test/**/*'
|
78
|
+
|
79
|
+
# Multi-line method chaining should be done with trailing dots.
|
80
|
+
Style/DotPosition:
|
81
|
+
EnforcedStyle: leading
|
82
|
+
SupportedStyles:
|
83
|
+
- leading
|
84
|
+
- trailing
|
85
|
+
|
86
|
+
Style/FrozenStringLiteralComment:
|
87
|
+
Description: >-
|
88
|
+
Add the frozen_string_literal comment to the top of files
|
89
|
+
to help transition from Ruby 2.3.0 to Ruby 3.0.
|
90
|
+
Enabled: false
|
91
|
+
|
92
|
+
Style/MultilineBlockChain:
|
93
|
+
Description: 'Avoid multi-line chains of blocks.'
|
94
|
+
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#single-line-blocks'
|
95
|
+
Enabled: false
|
96
|
+
|
97
|
+
Style/MutableConstant:
|
98
|
+
Description: 'Do not assign mutable objects to constants.'
|
99
|
+
Enabled: false
|
100
|
+
|
101
|
+
Metrics/AbcSize:
|
102
|
+
# The ABC size is a calculated magnitude, so this number can be a Fixnum or
|
103
|
+
# a Float.
|
104
|
+
Max: 20
|
105
|
+
|
106
|
+
Metrics/LineLength:
|
107
|
+
Max: 100
|
data/.travis.yml
CHANGED
@@ -1,26 +1,21 @@
|
|
1
|
-
dist: trusty
|
2
1
|
language: ruby
|
3
|
-
cache: bundler
|
4
2
|
rvm:
|
5
|
-
-
|
6
|
-
- 2.5.1
|
7
|
-
- ruby-head
|
3
|
+
- ruby
|
8
4
|
env:
|
9
|
-
- DRIVER=
|
10
|
-
matrix:
|
11
|
-
fast_finish: true
|
12
|
-
allow_failures:
|
13
|
-
- rvm: ruby-head
|
5
|
+
- DRIVER=travis HYPER_DEV_GEM_SOURCE="https://gems.ruby-hyperloop.org" TZ=Europe/Berlin
|
14
6
|
before_install:
|
15
|
-
-
|
16
|
-
-
|
17
|
-
-
|
7
|
+
- sudo apt-get install -y fonts-liberation
|
8
|
+
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
9
|
+
- sudo dpkg -i google-chrome*.deb
|
18
10
|
- gem install bundler
|
19
11
|
before_script:
|
20
|
-
-
|
21
|
-
-
|
22
|
-
-
|
23
|
-
-
|
24
|
-
-
|
25
|
-
|
26
|
-
|
12
|
+
- cd spec/test_app
|
13
|
+
- bundle update
|
14
|
+
- cd ../../
|
15
|
+
- chromedriver-update
|
16
|
+
- ls -lR ~/.chromedriver-helper/
|
17
|
+
script:
|
18
|
+
- bundle exec rake spec
|
19
|
+
gemfile:
|
20
|
+
- gemfiles/opal_0_11_react-rails_2_4.gemfile
|
21
|
+
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at mitch@catprint.com. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
CHANGED
@@ -1,7 +1,3 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
gem
|
3
|
-
gem 'hyper-store', path: '../hyper-store'
|
4
|
-
gem 'hyper-state', path: '../hyper-state'
|
5
|
-
gem 'hyperstack-config', path: '../hyperstack-config'
|
6
|
-
#gem 'unparser', path: '../../../unparser'
|
2
|
+
gem "opal-jquery", git: "https://github.com/opal/opal-jquery.git", branch: "master"
|
7
3
|
gemspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 catmando
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,380 @@
|
|
1
|
+
# HyperSpec
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/ruby-hyperloop/hyper-spec.svg?branch=master)](https://travis-ci.org/ruby-hyperloop/hyper-spec)
|
4
|
+
|
5
|
+
With HyperSpec you can run *isomorphic* specs for all your Hyperloop code using RSpec. Everything runs as standard RSpec test specs.
|
6
|
+
|
7
|
+
For example if you have a component like this:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class SayHello < React::Component::Base
|
11
|
+
param :name
|
12
|
+
render(DIV) do
|
13
|
+
"Hello there #{params.name}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
Your test spec would look like this:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
describe 'SayHello', js: true do
|
22
|
+
it 'has the correct content' do
|
23
|
+
mount "SayHello", name: 'Fred'
|
24
|
+
expect(page).to have_content('Hello there Fred')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
The `mount` method will setup a blank client window, and *mount* the named component in the window, passing any parameters.
|
30
|
+
|
31
|
+
Notice that the spec will need a client environment so we must set `js: true`.
|
32
|
+
|
33
|
+
The `mount` method can also take a block which will be recompiled and set to the client before mounting the component. You can place any client side code in the mount block including the definition of components.
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
describe "the mount's code block", js: true do
|
37
|
+
it 'will be recompiled on the client' do
|
38
|
+
mount 'ShowOff' do
|
39
|
+
class ShowOff < React::Component::Base
|
40
|
+
render(DIV) { 'Now how cool is that???' }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
expect(page).to have_content('Now how cool is that???' )
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
## Why?
|
49
|
+
|
50
|
+
Hyperloop wants to make the server-client divide as transparent to the developer as practical. Given this, it makes sense that the testing should also be done with as little concern for client versus server.
|
51
|
+
|
52
|
+
HyperSpec allows you to directly use tools like FactoryBot (or Hyperloop Operations) to setup some test data, then run a spec to make sure that a component correctly displays, or modifies that data. You can use Timecop to manipulate time and keep in sync between the server and client. This makes testing easier and more realistic without writing a lot of redundant code.
|
53
|
+
|
54
|
+
|
55
|
+
## Installation
|
56
|
+
|
57
|
+
Add this line to your application's Gemfile in the test section:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
gem 'hyper-spec'
|
61
|
+
```
|
62
|
+
|
63
|
+
Execute:
|
64
|
+
|
65
|
+
$ bundle install
|
66
|
+
|
67
|
+
and then in your spec_helper.rb file
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
require 'hyper-spec'
|
71
|
+
```
|
72
|
+
|
73
|
+
You will also need to install selenium, poltergeist and firefox version **46.0.1** (ff latest still does not play well with selenium).
|
74
|
+
|
75
|
+
Sadly at this time the selenium chrome driver does not play nicely with Opal, so you can't use Chrome. We are working on getting rid of the whole selenium business. Stay tuned.
|
76
|
+
|
77
|
+
## Environment Variables
|
78
|
+
|
79
|
+
You can set `DRIVER` to `ff` to run the client in Firefox and see what is going on. By default tests will run in poltergeist which is quicker, but harder to debug problems.
|
80
|
+
|
81
|
+
```
|
82
|
+
DRIVER=ff bundle exec rspec
|
83
|
+
```
|
84
|
+
|
85
|
+
## Spec Helpers
|
86
|
+
|
87
|
+
HyperSpec adds the following spec helpers to your test environment
|
88
|
+
|
89
|
+
+ `mount`
|
90
|
+
+ `client_option` and `client_options`
|
91
|
+
+ `on_client`
|
92
|
+
+ `isomorphic`
|
93
|
+
+ `evaluate_ruby`
|
94
|
+
+ `expect_evaluate_ruby`
|
95
|
+
+ `expect_promise`
|
96
|
+
+ call back and event history methods
|
97
|
+
+ `pause`
|
98
|
+
+ `attributes_on_client`
|
99
|
+
+ `size_window`
|
100
|
+
+ `add_class`
|
101
|
+
|
102
|
+
#### The `mount` Method
|
103
|
+
|
104
|
+
`mount` takes the name of a component, prepares an empty test window, and mounts the named component in the window.
|
105
|
+
You may give a block to `mount` which will be recompiled on the client, and run *before* mounting. This means that the component
|
106
|
+
mounted may be actually defined in the block, which is useful for setting up top level wrapper components, which will invoke your component under test. You can also modify existing components for white box testing, or local fixture data, constants, etc.
|
107
|
+
|
108
|
+
`mount` may also be given a hash of the parameters to be passed to the component.
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
mount 'Display', test: 123 do
|
112
|
+
class Display < React::Component::Base
|
113
|
+
param :test
|
114
|
+
render(DIV) { params.test.to_s }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
#### The `client_option` Method
|
120
|
+
|
121
|
+
There are several options that control the mounting process. Use `client_option` (or `client_options`) before accessing any client side to set any of these options:
|
122
|
+
|
123
|
+
+ `render_on`: `:server_only`, `:client_only`, or `:both`, default is client_only.
|
124
|
+
+ `layout`: specify the layout to be used. Default is :none.
|
125
|
+
+ `style_sheet`: specify the name of the style sheet to be loaded. Defaults to the application stylesheet.
|
126
|
+
+ `javascript`: specify the name of the javascript asset file to be loaded. Defaults to the application js file.
|
127
|
+
|
128
|
+
For example:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
it "can be rendered server side only" do
|
132
|
+
client_option render_on: :server_only
|
133
|
+
mount 'SayHello', name: 'George'
|
134
|
+
expect(page).to have_content('Hello there George')
|
135
|
+
# Server only means no code is downloaded to the client
|
136
|
+
expect(evaluate_script('typeof React')).to eq('undefined')
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
If you need to pull in alternative style sheets and javascript files, the recommended way to do this is to
|
141
|
+
|
142
|
+
1. Add them to a `specs/assets/stylesheets` and `specs/assets/javascripts` directory and
|
143
|
+
2. Add the following line to your `config/environment/test.rb` file:
|
144
|
+
```ruby
|
145
|
+
config.assets.paths << ::Rails.root.join('spec', 'assets', 'stylesheets').to_s
|
146
|
+
config.assets.paths << ::Rails.root.join('spec', 'assets', 'javascripts').to_s
|
147
|
+
```
|
148
|
+
|
149
|
+
This way you will not pollute your application with these 'test only' files.
|
150
|
+
|
151
|
+
*The javascript spec asset files can be `.rb` files and contain ruby code as well. See the specs for examples!*
|
152
|
+
|
153
|
+
#### The `on_client` Method
|
154
|
+
|
155
|
+
`on_client` takes a block and compiles and runs it on the client. This is useful in setting up test constants and client only fixtures.
|
156
|
+
|
157
|
+
Note that `on_client` needs to *proceed* any calls to `mount`, `evaluate_ruby`, `expect_evaluate_ruby` or `expect_promise` as these methods will initiate the client load process.
|
158
|
+
|
159
|
+
#### The `isomorphic` Method
|
160
|
+
|
161
|
+
Similar to `on_client` but the block is *also* run on the server. This is useful for setting constants shared by both client and server, and modifying behavior of isomorphic classes such as ActiveRecord models, and HyperOperations.
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
isomorphic do
|
165
|
+
class SomeModel < ActiveRecord::Base
|
166
|
+
def fake_attribute
|
167
|
+
12
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
#### The `evaluate_ruby` Method
|
174
|
+
|
175
|
+
Takes either a string or a block, dynamically compiles it, downloads it to the client and runs it.
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
evaluate_ruby do
|
179
|
+
i = 12
|
180
|
+
i * 2
|
181
|
+
end
|
182
|
+
# returns 24
|
183
|
+
|
184
|
+
isomorphic do
|
185
|
+
def factorial(n)
|
186
|
+
n == 1 ? 1 : n * factorial(n-1)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
expect(evaluate_ruby("factorial(5)")).to eq(factorial(5))
|
191
|
+
```
|
192
|
+
|
193
|
+
`evaluate_ruby` can also be very useful for debug. Set a breakpoint in your test, then use `evaluate_ruby` to interrogate the state of the client.
|
194
|
+
|
195
|
+
#### The `expect_evaluate_ruby` Method
|
196
|
+
|
197
|
+
Combines expect and evaluate methods:
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
expect_evaluate_ruby do
|
201
|
+
i = 1
|
202
|
+
5.times { |n| i = i*n }
|
203
|
+
i
|
204
|
+
end.to eq(120)
|
205
|
+
```
|
206
|
+
|
207
|
+
#### The `expect_promise` Method
|
208
|
+
|
209
|
+
Works like `expect_evaluate_ruby` but is used with promises. `expect_promise` will hang until the promise resolves and then return to the results.
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
expect_promise do
|
213
|
+
Promise.new.tap do |p|
|
214
|
+
after(2) { p.resolve('hello') }
|
215
|
+
end
|
216
|
+
end.to eq('hello')
|
217
|
+
```
|
218
|
+
|
219
|
+
#### Call Back and Event History Methods
|
220
|
+
|
221
|
+
HyperReact components can *generate* events and perform callbacks. HyperSpec provides methods to test if an event or callback was made.
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
mount 'CallBackOnEveryThirdClick' do
|
225
|
+
class CallBackOnEveryThirdClick < React::Component::Base
|
226
|
+
param :click3, type: Proc
|
227
|
+
def increment_click
|
228
|
+
@clicks ||= 0
|
229
|
+
@clicks = (@clicks + 1)
|
230
|
+
params.click3(@clicks) if @clicks % 3 == 0
|
231
|
+
end
|
232
|
+
render do
|
233
|
+
DIV(class: :tp_clicker) { "click me" }
|
234
|
+
.on(:click) { increment_click }
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
7.times { page.click('#tp_clicker') }
|
240
|
+
expect(callback_history_for(:click3)).to eq([[3], [6]])
|
241
|
+
```
|
242
|
+
|
243
|
+
Note that for things to work, the param must be declared as a `type: Proc`.
|
244
|
+
|
245
|
+
+ `callback_history_for`: the entire history given as an array of arrays
|
246
|
+
+ `last_callback_for`: same as `callback_history_for(xxx).last`
|
247
|
+
+ `clear_callback_history_for`: clears the array (userful for repeating test variations without remounting)
|
248
|
+
+ `event_history_for, last_event_for, clear_event_history_for`: same but for events.
|
249
|
+
|
250
|
+
#### The `pause` Method
|
251
|
+
|
252
|
+
For debugging. Everything stops, until you type `go()` in the client console. Running binding.pry also has this effect, and is often sufficient, however it will also block the server from responding unless you have a multithreaded server.
|
253
|
+
|
254
|
+
#### The `attributes_on_client` Method
|
255
|
+
|
256
|
+
*This feature is currently untested - use at your own risk.*
|
257
|
+
|
258
|
+
This reads the value of active record model attributes on the client.
|
259
|
+
|
260
|
+
In other words the method `attributes_on_client` is added to all ActiveRecord models. You then take a model you have instance of on the server, and by passing the Capybara page object, you get back the attributes for that same model instance, currently on the client.
|
261
|
+
|
262
|
+
```ruby
|
263
|
+
expect(some_record_on_server.attributes_on_client(page)[:fred]).to eq(12)
|
264
|
+
```
|
265
|
+
|
266
|
+
Note that after persisting a record the client and server will be synced so this is mainly useful for debug or in rare cases where it is important to interrogate the value on the client before its persisted.
|
267
|
+
|
268
|
+
#### The `size_window` Method
|
269
|
+
|
270
|
+
Sets the size of the test window. You can say:
|
271
|
+
`size_window(width, height)` or pass one of the following standard sizes: to one of the following standard sizes:
|
272
|
+
|
273
|
+
+ small: 480 X 320
|
274
|
+
+ mobile: 640 X 480
|
275
|
+
+ tablet: 960 X 640
|
276
|
+
+ large: 1920 X 6000
|
277
|
+
+ default: 1024 X 768
|
278
|
+
|
279
|
+
example: `size_window(:mobile)`
|
280
|
+
|
281
|
+
You can also modify the standard sizes with `:portrait`
|
282
|
+
|
283
|
+
example: `size_window(:table, :portrait)`
|
284
|
+
|
285
|
+
You can also specify the size by providing the width and height.
|
286
|
+
|
287
|
+
example: `size_window(600, 600)`
|
288
|
+
|
289
|
+
size_window with no parameters is the same as `size_window(:default)`
|
290
|
+
|
291
|
+
Typically you will use this in a `before(:each)` or `before(:step)` block
|
292
|
+
|
293
|
+
#### The `add_class` Method
|
294
|
+
|
295
|
+
Sometimes it's useful to change styles during testing (mainly for debug so that changes on screen are visible.)
|
296
|
+
|
297
|
+
The `add_class` method takes a class name (as a symbol or string), and hash representing the style.
|
298
|
+
|
299
|
+
```ruby
|
300
|
+
it "can add classes during testing" do
|
301
|
+
add_class :some_class, borderStyle: :solid
|
302
|
+
mount 'StyledDiv' do
|
303
|
+
class StyledDiv < React::Component::Base
|
304
|
+
render(DIV, id: 'hello', class: 'some_class') do
|
305
|
+
'Hello!'
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
expect(page.find('#hello').native.css_value('border-right-style')).to eq('solid')
|
310
|
+
end
|
311
|
+
```
|
312
|
+
|
313
|
+
## Integration with the Steps gem
|
314
|
+
|
315
|
+
The [rspec-steps gem](https://github.com/LRDesign/rspec-steps) can be useful in doing client side testing. Without rspec-steps, each test spec will cause a reload of the browser window. While this insures that each test runs in a clean environment, it is typically not necessary and can really slow down testing.
|
316
|
+
|
317
|
+
The rspec-steps gem will run each test without reloading the window, which is usually fine.
|
318
|
+
|
319
|
+
Checkout the rspec-steps example in the `hyper_spec.rb` file for an example.
|
320
|
+
|
321
|
+
*Note that hopefully in the near future we are going to build a custom capybara driver that will just directly talk to Hyperloop on the client side. Once this is in place these troubles should go away! - Volunteers welcome to help!*
|
322
|
+
|
323
|
+
## Timecop Integration
|
324
|
+
|
325
|
+
HyperSpec is integrated with [Timecop](https://github.com/travisjeffery/timecop) to freeze, move and speed up time. The client and server times will be kept in sync when you use any these Timecop methods:
|
326
|
+
|
327
|
+
+ `freeze`: Freezes time at the specified point in time (default is Time.now)
|
328
|
+
+ `travel`: Time runs normally forward from the point specified.
|
329
|
+
+ `scale`: Like travel but times runs faster.
|
330
|
+
+ `return`: Return to normal system time.
|
331
|
+
|
332
|
+
For example:
|
333
|
+
```ruby
|
334
|
+
Timecop.freeze # freeze time at current time
|
335
|
+
# ... test some stuff
|
336
|
+
Timecop.freeze Time.now+10.minutes # move time forward 10 minutes
|
337
|
+
# ... check to see if expected events happened etc
|
338
|
+
Timecop.return
|
339
|
+
```
|
340
|
+
|
341
|
+
```ruby
|
342
|
+
Timecop.scale 60, Time.now-1.year do
|
343
|
+
# Time will begin 1 year ago but advance 60 times faster than normal
|
344
|
+
sleep 10
|
345
|
+
# still sleeps for 10 seconds YOUR time, but server and client will
|
346
|
+
# think 10 minutes have passed
|
347
|
+
end
|
348
|
+
# no need for Timecop.return if using the block style
|
349
|
+
```
|
350
|
+
|
351
|
+
See the Timecop [README](https://github.com/travisjeffery/timecop/blob/master/README.markdown) for more details.
|
352
|
+
|
353
|
+
There is one confusing thing to note: On the server if you `sleep` then you will sleep for the specified number of seconds when viewed *outside* of the test. However inside the test environment if you look at Time.now, you will see it advancing according to the scale factor. Likewise if you have a `after` or `every` block on the client, you will wait according to *simulated* time.
|
354
|
+
|
355
|
+
## Common Problems
|
356
|
+
|
357
|
+
If you are getting failures on Poltergeist but not Firefox, make sure you are not requiring `browser` in your components.rb.
|
358
|
+
Requiring `browser/interval` or `browser/delay` is okay.
|
359
|
+
|
360
|
+
## Development
|
361
|
+
|
362
|
+
After checking out the repo, run bundle install and you should be good to go.
|
363
|
+
|
364
|
+
Tests are run either by running `rake` or for more control:
|
365
|
+
|
366
|
+
```
|
367
|
+
DRIVER=ff bundle exec rspec spec/hyper_spec.rb
|
368
|
+
```
|
369
|
+
|
370
|
+
where DRIVER can be either `ff` (firefox) or `pg` (poltergeist - default).
|
371
|
+
|
372
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
373
|
+
|
374
|
+
## Contributing
|
375
|
+
|
376
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/hyper-spec. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
377
|
+
|
378
|
+
## License
|
379
|
+
|
380
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|