flipper-ui 0.21.0.rc1 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/docs/ui/README.md +1 -1
- data/examples/ui/authorization.ru +12 -50
- data/examples/ui/basic.ru +12 -23
- data/lib/flipper/ui/action.rb +48 -1
- data/lib/flipper/ui/actions/actors_gate.rb +1 -1
- data/lib/flipper/ui/actions/features.rb +2 -2
- data/lib/flipper/ui/actions/file.rb +1 -1
- data/lib/flipper/ui/actions/groups_gate.rb +1 -1
- data/lib/flipper/ui/actions/percentage_of_actors_gate.rb +1 -1
- data/lib/flipper/ui/actions/percentage_of_time_gate.rb +1 -1
- data/lib/flipper/ui/decorators/feature.rb +3 -3
- data/lib/flipper/ui/middleware.rb +2 -1
- data/lib/flipper/ui/public/css/application.css +7 -0
- data/lib/flipper/ui/views/feature.erb +3 -3
- data/lib/flipper/ui/views/features.erb +1 -1
- data/lib/flipper/ui/views/layout.erb +4 -5
- data/lib/flipper/ui.rb +2 -2
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/ui/actions/actors_gate_spec.rb +19 -2
- data/spec/flipper/ui/actions/boolean_gate_spec.rb +18 -0
- data/spec/flipper/ui/actions/feature_spec.rb +18 -0
- data/spec/flipper/ui/actions/features_spec.rb +16 -3
- data/spec/flipper/ui/actions/file_spec.rb +0 -10
- data/spec/flipper/ui/actions/groups_gate_spec.rb +20 -3
- data/spec/flipper/ui/actions/percentage_of_actors_gate_spec.rb +18 -1
- data/spec/flipper/ui/actions/percentage_of_time_gate_spec.rb +18 -1
- data/spec/flipper/ui_spec.rb +0 -13
- metadata +6 -14
- data/lib/flipper/ui/public/octicons/LICENSE.txt +0 -9
- data/lib/flipper/ui/public/octicons/README.md +0 -1
- data/lib/flipper/ui/public/octicons/octicons-local.ttf +0 -0
- data/lib/flipper/ui/public/octicons/octicons.css +0 -236
- data/lib/flipper/ui/public/octicons/octicons.eot +0 -0
- data/lib/flipper/ui/public/octicons/octicons.svg +0 -200
- data/lib/flipper/ui/public/octicons/octicons.ttf +0 -0
- data/lib/flipper/ui/public/octicons/octicons.woff +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a619370e297b8fc379c57c8394cdfc798120ebfd9d4d091bc1902f3d9a2183be
|
4
|
+
data.tar.gz: a36c5d0a79836aec62188c04f5954a506d737e110a135028b3fc7d9d889a2579
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b02d0683b248297b59e6013f816a6f09bbde28889e38201e0f41c89d29118f06f16061749d55041a786daf81d2d67da8e88885033c4819233794dbd55df3ea8d
|
7
|
+
data.tar.gz: 425e485bc419c1ae45554298df69a2d6cfdb4d2169fa2b0dc1b3e5e32009e5bafd27372796ab8a1bf3ac68dbc2d1be6a2474cbd7855b1d245fd61c8940e1cb81
|
data/docs/ui/README.md
CHANGED
@@ -5,50 +5,13 @@
|
|
5
5
|
# http://localhost:9999/
|
6
6
|
#
|
7
7
|
require 'bundler/setup'
|
8
|
-
require "
|
9
|
-
|
10
|
-
require "flipper-ui"
|
8
|
+
require "flipper/ui"
|
11
9
|
require "flipper/adapters/pstore"
|
12
|
-
require "active_support/notifications"
|
13
10
|
|
14
11
|
Flipper.register(:admins) { |actor|
|
15
12
|
actor.respond_to?(:admin?) && actor.admin?
|
16
13
|
}
|
17
14
|
|
18
|
-
Flipper.register(:early_access) { |actor|
|
19
|
-
actor.respond_to?(:early?) && actor.early?
|
20
|
-
}
|
21
|
-
|
22
|
-
# Setup logging of flipper calls.
|
23
|
-
if ENV["LOG"] == "1"
|
24
|
-
$logger = Logger.new(STDOUT)
|
25
|
-
require "flipper/instrumentation/log_subscriber"
|
26
|
-
Flipper::Instrumentation::LogSubscriber.logger = $logger
|
27
|
-
end
|
28
|
-
|
29
|
-
adapter = Flipper::Adapters::PStore.new
|
30
|
-
flipper = Flipper.new(adapter, instrumenter: ActiveSupport::Notifications)
|
31
|
-
|
32
|
-
Flipper::UI.configure do |config|
|
33
|
-
# config.banner_text = 'Production Environment'
|
34
|
-
# config.banner_class = 'danger'
|
35
|
-
config.feature_creation_enabled = true
|
36
|
-
config.feature_removal_enabled = true
|
37
|
-
# config.show_feature_description_in_list = true
|
38
|
-
config.descriptions_source = lambda do |_keys|
|
39
|
-
{
|
40
|
-
"search_performance_another_long_thing" => "Just to test feature name length.",
|
41
|
-
"gauges_tracking" => "Should we track page views with gaug.es.",
|
42
|
-
"unused" => "Not used.",
|
43
|
-
"suits" => "Are suits necessary in business?",
|
44
|
-
"secrets" => "Secrets are lies.",
|
45
|
-
"logging" => "Log all the things.",
|
46
|
-
"new_cache" => "Like the old cache but newer.",
|
47
|
-
"a/b" => "Why would someone use a slash? I don't know but someone did. Let's make this really long so they regret using slashes. Please don't use slashes.",
|
48
|
-
}
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
15
|
# Example middleware to allow reading the Flipper UI but nothing else.
|
53
16
|
class FlipperReadOnlyMiddleware
|
54
17
|
def initialize(app)
|
@@ -67,18 +30,17 @@ class FlipperReadOnlyMiddleware
|
|
67
30
|
end
|
68
31
|
|
69
32
|
# You can uncomment these to get some default data:
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
|
80
|
-
|
81
|
-
run Flipper::UI.app(flipper) { |builder|
|
33
|
+
# Flipper.enable(:search_performance_another_long_thing)
|
34
|
+
# Flipper.disable(:gauges_tracking)
|
35
|
+
# Flipper.disable(:unused)
|
36
|
+
# Flipper.enable_actor(:suits, Flipper::Actor.new('1'))
|
37
|
+
# Flipper.enable_actor(:suits, Flipper::Actor.new('6'))
|
38
|
+
# Flipper.enable_group(:secrets, :admins)
|
39
|
+
# Flipper.enable_percentage_of_time(:logging, 5)
|
40
|
+
# Flipper.enable_percentage_of_actors(:new_cache, 15)
|
41
|
+
# Flipper.add("a/b")
|
42
|
+
|
43
|
+
run Flipper::UI.app { |builder|
|
82
44
|
builder.use Rack::Session::Cookie, secret: "_super_secret"
|
83
45
|
builder.use FlipperReadOnlyMiddleware
|
84
46
|
}
|
data/examples/ui/basic.ru
CHANGED
@@ -9,9 +9,8 @@
|
|
9
9
|
# http://localhost:9999/
|
10
10
|
#
|
11
11
|
require 'bundler/setup'
|
12
|
-
require "flipper
|
12
|
+
require "flipper/ui"
|
13
13
|
require "flipper/adapters/pstore"
|
14
|
-
require "active_support/notifications"
|
15
14
|
|
16
15
|
Flipper.register(:admins) { |actor|
|
17
16
|
actor.respond_to?(:admin?) && actor.admin?
|
@@ -21,16 +20,6 @@ Flipper.register(:early_access) { |actor|
|
|
21
20
|
actor.respond_to?(:early?) && actor.early?
|
22
21
|
}
|
23
22
|
|
24
|
-
# Setup logging of flipper calls.
|
25
|
-
if ENV["LOG"] == "1"
|
26
|
-
$logger = Logger.new(STDOUT)
|
27
|
-
require "flipper/instrumentation/log_subscriber"
|
28
|
-
Flipper::Instrumentation::LogSubscriber.logger = $logger
|
29
|
-
end
|
30
|
-
|
31
|
-
adapter = Flipper::Adapters::PStore.new
|
32
|
-
flipper = Flipper.new(adapter, instrumenter: ActiveSupport::Notifications)
|
33
|
-
|
34
23
|
Flipper::UI.configure do |config|
|
35
24
|
# config.banner_text = 'Production Environment'
|
36
25
|
# config.banner_class = 'danger'
|
@@ -53,17 +42,17 @@ Flipper::UI.configure do |config|
|
|
53
42
|
end
|
54
43
|
|
55
44
|
# You can uncomment these to get some default data:
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
45
|
+
# Flipper.enable(:search_performance_another_long_thing)
|
46
|
+
# Flipper.disable(:gauges_tracking)
|
47
|
+
# Flipper.disable(:unused)
|
48
|
+
# Flipper.enable_actor(:suits, Flipper::Actor.new('1'))
|
49
|
+
# Flipper.enable_actor(:suits, Flipper::Actor.new('6'))
|
50
|
+
# Flipper.enable_group(:secrets, :admins)
|
51
|
+
# Flipper.enable_group(:secrets, :early_access)
|
52
|
+
# Flipper.enable_percentage_of_time(:logging, 5)
|
53
|
+
# Flipper.enable_percentage_of_actors(:new_cache, 15)
|
54
|
+
# Flipper.add("a/b")
|
66
55
|
|
67
|
-
run Flipper::UI.app
|
56
|
+
run Flipper::UI.app { |builder|
|
68
57
|
builder.use Rack::Session::Cookie, secret: "_super_secret"
|
69
58
|
}
|
data/lib/flipper/ui/action.rb
CHANGED
@@ -26,6 +26,36 @@ module Flipper
|
|
26
26
|
'delete'.freeze,
|
27
27
|
]).freeze
|
28
28
|
|
29
|
+
SOURCES = {
|
30
|
+
bootstrap_css: {
|
31
|
+
src: "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css".freeze,
|
32
|
+
hash: "sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm".freeze
|
33
|
+
}.freeze,
|
34
|
+
jquery_js: {
|
35
|
+
src: "https://code.jquery.com/jquery-3.2.1.slim.min.js".freeze,
|
36
|
+
hash: "sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN".freeze
|
37
|
+
}.freeze,
|
38
|
+
popper_js: {
|
39
|
+
src: "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js".freeze,
|
40
|
+
hash: "sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q".freeze
|
41
|
+
}.freeze,
|
42
|
+
bootstrap_js: {
|
43
|
+
src: "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js".freeze,
|
44
|
+
hash: "sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl".freeze
|
45
|
+
}.freeze
|
46
|
+
}.freeze
|
47
|
+
SCRIPT_SRCS = SOURCES.values_at(:jquery_js, :popper_js, :bootstrap_js).map { |s| s[:src] }
|
48
|
+
STYLE_SRCS = SOURCES.values_at(:bootstrap_css).map { |s| s[:src] }
|
49
|
+
CONTENT_SECURITY_POLICY = <<-CSP.delete("\n")
|
50
|
+
default-src 'none';
|
51
|
+
img-src 'self';
|
52
|
+
font-src 'self';
|
53
|
+
script-src 'report-sample' 'self' #{SCRIPT_SRCS.join(' ')};
|
54
|
+
style-src 'self' 'unsafe-inline' #{STYLE_SRCS.join(' ')};
|
55
|
+
style-src-attr 'unsafe-inline' ;
|
56
|
+
style-src-elem 'self' #{STYLE_SRCS.join(' ')};
|
57
|
+
CSP
|
58
|
+
|
29
59
|
# Public: Call this in subclasses so the action knows its route.
|
30
60
|
#
|
31
61
|
# regex - The Regexp that this action should run for.
|
@@ -130,6 +160,7 @@ module Flipper
|
|
130
160
|
# Returns a response.
|
131
161
|
def view_response(name)
|
132
162
|
header 'Content-Type', 'text/html'
|
163
|
+
header 'Content-Security-Policy', CONTENT_SECURITY_POLICY
|
133
164
|
body = view_with_layout { view_without_layout name }
|
134
165
|
halt [@code, @headers, [body]]
|
135
166
|
end
|
@@ -151,7 +182,7 @@ module Flipper
|
|
151
182
|
# location - The String location to set the Location header to.
|
152
183
|
def redirect_to(location)
|
153
184
|
status 302
|
154
|
-
header 'Location', "#{script_name}#{location}"
|
185
|
+
header 'Location', "#{script_name}#{Rack::Utils.escape_path(location)}"
|
155
186
|
halt [@code, @headers, ['']]
|
156
187
|
end
|
157
188
|
|
@@ -237,6 +268,22 @@ module Flipper
|
|
237
268
|
def valid_request_method?
|
238
269
|
VALID_REQUEST_METHOD_NAMES.include?(request_method_name)
|
239
270
|
end
|
271
|
+
|
272
|
+
def bootstrap_css
|
273
|
+
SOURCES[:bootstrap_css]
|
274
|
+
end
|
275
|
+
|
276
|
+
def bootstrap_js
|
277
|
+
SOURCES[:bootstrap_js]
|
278
|
+
end
|
279
|
+
|
280
|
+
def popper_js
|
281
|
+
SOURCES[:popper_js]
|
282
|
+
end
|
283
|
+
|
284
|
+
def jquery_js
|
285
|
+
SOURCES[:jquery_js]
|
286
|
+
end
|
240
287
|
end
|
241
288
|
end
|
242
289
|
end
|
@@ -27,7 +27,7 @@ module Flipper
|
|
27
27
|
value = params['value'].to_s.strip
|
28
28
|
|
29
29
|
if Util.blank?(value)
|
30
|
-
error =
|
30
|
+
error = "#{value.inspect} is not a valid actor value."
|
31
31
|
redirect_to("/features/#{feature.key}/actors?error=#{error}")
|
32
32
|
end
|
33
33
|
|
@@ -49,14 +49,14 @@ module Flipper
|
|
49
49
|
value = params['value'].to_s.strip
|
50
50
|
|
51
51
|
if Util.blank?(value)
|
52
|
-
error =
|
52
|
+
error = "#{value.inspect} is not a valid feature name."
|
53
53
|
redirect_to("/features/new?error=#{error}")
|
54
54
|
end
|
55
55
|
|
56
56
|
feature = flipper[value]
|
57
57
|
feature.add
|
58
58
|
|
59
|
-
redirect_to "/features/#{
|
59
|
+
redirect_to "/features/#{value}"
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -35,7 +35,7 @@ module Flipper
|
|
35
35
|
|
36
36
|
redirect_to("/features/#{feature.key}")
|
37
37
|
else
|
38
|
-
error =
|
38
|
+
error = "The group named #{value.inspect} has not been registered."
|
39
39
|
redirect_to("/features/#{feature.key}/groups?error=#{error}")
|
40
40
|
end
|
41
41
|
end
|
@@ -16,7 +16,7 @@ module Flipper
|
|
16
16
|
begin
|
17
17
|
feature.enable_percentage_of_actors params['value']
|
18
18
|
rescue ArgumentError => exception
|
19
|
-
error =
|
19
|
+
error = "Invalid percentage of actors value: #{exception.message}"
|
20
20
|
redirect_to("/features/#{@feature.key}?error=#{error}")
|
21
21
|
end
|
22
22
|
|
@@ -16,7 +16,7 @@ module Flipper
|
|
16
16
|
begin
|
17
17
|
feature.enable_percentage_of_time params['value']
|
18
18
|
rescue ArgumentError => exception
|
19
|
-
error =
|
19
|
+
error = "Invalid percentage of time value: #{exception.message}"
|
20
20
|
redirect_to("/features/#{@feature.key}?error=#{error}")
|
21
21
|
end
|
22
22
|
|
@@ -12,6 +12,7 @@ module Flipper
|
|
12
12
|
def initialize(app, options = {})
|
13
13
|
@app = app
|
14
14
|
@env_key = options.fetch(:env_key, 'flipper')
|
15
|
+
@flipper = options.fetch(:flipper) { Flipper }
|
15
16
|
|
16
17
|
@action_collection = ActionCollection.new
|
17
18
|
|
@@ -43,7 +44,7 @@ module Flipper
|
|
43
44
|
if action_class.nil?
|
44
45
|
@app.call(env)
|
45
46
|
else
|
46
|
-
flipper = env.fetch(@env_key)
|
47
|
+
flipper = env.fetch(@env_key) { Flipper }
|
47
48
|
action_class.run(flipper, request)
|
48
49
|
end
|
49
50
|
end
|
@@ -21,7 +21,7 @@
|
|
21
21
|
<div class="card">
|
22
22
|
<%# Gate State Header %>
|
23
23
|
<div class="card-header">
|
24
|
-
<span class="
|
24
|
+
<span class="status <%= @feature.color_class %> mr-2"></span>
|
25
25
|
<%= @feature.gate_state_title %>
|
26
26
|
</div>
|
27
27
|
|
@@ -69,8 +69,8 @@
|
|
69
69
|
<%== csrf_input_tag %>
|
70
70
|
<input type="hidden" name="operation" value="disable">
|
71
71
|
<input type="hidden" name="value" value="<%= item %>">
|
72
|
-
<button type="submit" value="Disable" class="btn btn-
|
73
|
-
|
72
|
+
<button type="submit" value="Disable" class="btn btn-outline-danger" data-toggle="tooltip" title="Disable <%= item %>" data-placement="left">
|
73
|
+
Remove
|
74
74
|
</button>
|
75
75
|
</form>
|
76
76
|
</div>
|
@@ -40,7 +40,7 @@
|
|
40
40
|
<% @features.each do |feature| %>
|
41
41
|
<div class="feature row align-items-center mt-0 px-3 border-bottom">
|
42
42
|
<div class="col-1 col-md-auto">
|
43
|
-
<span class="
|
43
|
+
<span class="status <%= feature.color_class %>" data-toggle="tooltip" title=<%= feature.state.to_s.capitalize %>></span>
|
44
44
|
</div>
|
45
45
|
<div class="col-10">
|
46
46
|
<a href="<%= "#{script_name}/features/#{feature.key}" %>" class="d-block px-0 py-3 btn text-left text-dark">
|
@@ -6,8 +6,7 @@
|
|
6
6
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
8
8
|
|
9
|
-
<link rel="stylesheet" href="
|
10
|
-
<link rel="stylesheet" href="<%= script_name %>/octicons/octicons.css">
|
9
|
+
<link rel="stylesheet" href="<%= bootstrap_css[:src] %>" integrity="<%= bootstrap_css[:hash] %>" crossorigin="anonymous">
|
11
10
|
<link rel="stylesheet" href="<%= script_name %>/css/application.css">
|
12
11
|
</head>
|
13
12
|
<body class="py-4">
|
@@ -52,9 +51,9 @@
|
|
52
51
|
<% end %>
|
53
52
|
</div>
|
54
53
|
|
55
|
-
<script src="
|
56
|
-
<script src="
|
57
|
-
<script src="
|
54
|
+
<script src="<%= jquery_js[:src] %>" integrity="<%= jquery_js[:hash] %>" crossorigin="anonymous"></script>
|
55
|
+
<script src="<%= popper_js[:src] %>" integrity="<%= popper_js[:hash] %>" crossorigin="anonymous"></script>
|
56
|
+
<script src="<%= bootstrap_js[:src] %>" integrity="<%= bootstrap_js[:hash] %>" crossorigin="anonymous"></script>
|
58
57
|
<script src="<%= script_name %>/js/application.js"></script>
|
59
58
|
</body>
|
60
59
|
</html>
|
data/lib/flipper/ui.rb
CHANGED
@@ -39,14 +39,14 @@ module Flipper
|
|
39
39
|
def self.app(flipper = nil, options = {})
|
40
40
|
env_key = options.fetch(:env_key, 'flipper')
|
41
41
|
rack_protection_options = options.fetch(:rack_protection, use: :authenticity_token)
|
42
|
+
|
42
43
|
app = ->(_) { [200, { 'Content-Type' => 'text/html' }, ['']] }
|
43
44
|
builder = Rack::Builder.new
|
44
45
|
yield builder if block_given?
|
45
46
|
builder.use Rack::Protection, rack_protection_options
|
46
47
|
builder.use Rack::MethodOverride
|
47
48
|
builder.use Flipper::Middleware::SetupEnv, flipper, env_key: env_key
|
48
|
-
builder.use Flipper::Middleware
|
49
|
-
builder.use Flipper::UI::Middleware, env_key: env_key
|
49
|
+
builder.use Flipper::UI::Middleware, flipper: flipper, env_key: env_key
|
50
50
|
builder.run app
|
51
51
|
klass = self
|
52
52
|
builder.define_singleton_method(:inspect) { klass.inspect } # pretty rake routes output
|
data/lib/flipper/version.rb
CHANGED
@@ -61,6 +61,23 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
|
|
61
61
|
expect(last_response.headers['Location']).to eq('/features/search')
|
62
62
|
end
|
63
63
|
|
64
|
+
context "when feature name contains space" do
|
65
|
+
before do
|
66
|
+
post 'features/sp%20ace/actors',
|
67
|
+
{ 'value' => value, 'operation' => 'enable', 'authenticity_token' => token },
|
68
|
+
'rack.session' => session
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'adds item to members' do
|
72
|
+
expect(flipper["sp ace"].actors_value).to include('User;6')
|
73
|
+
end
|
74
|
+
|
75
|
+
it "redirects back to feature" do
|
76
|
+
expect(last_response.status).to be(302)
|
77
|
+
expect(last_response.headers['Location']).to eq('/features/sp%20ace')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
64
81
|
context 'value contains whitespace' do
|
65
82
|
let(:value) { ' User;6 ' }
|
66
83
|
|
@@ -75,7 +92,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
|
|
75
92
|
|
76
93
|
it 'redirects back to feature' do
|
77
94
|
expect(last_response.status).to be(302)
|
78
|
-
expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22
|
95
|
+
expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22%20is%20not%20a%20valid%20actor%20value.')
|
79
96
|
end
|
80
97
|
end
|
81
98
|
|
@@ -84,7 +101,7 @@ RSpec.describe Flipper::UI::Actions::ActorsGate do
|
|
84
101
|
|
85
102
|
it 'redirects back to feature' do
|
86
103
|
expect(last_response.status).to be(302)
|
87
|
-
expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22
|
104
|
+
expect(last_response.headers['Location']).to eq('/features/search/actors?error=%22%22%20is%20not%20a%20valid%20actor%20value.')
|
88
105
|
end
|
89
106
|
end
|
90
107
|
end
|