volt 0.8.27.beta2 → 0.8.27.beta3
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/.ruby-version +1 -1
- data/.travis.yml +3 -0
- data/CHANGELOG.md +7 -2
- data/CONTRIBUTING.md +133 -0
- data/Gemfile +0 -1
- data/Rakefile +11 -3
- data/Readme.md +4 -4
- data/VERSION +1 -1
- data/app/volt/models/user.rb +6 -3
- data/lib/volt/cli/console.rb +21 -12
- data/lib/volt/cli/runner.rb +1 -1
- data/lib/volt/cli.rb +5 -4
- data/lib/volt/config.rb +9 -11
- data/lib/volt/controllers/model_controller.rb +16 -0
- data/lib/volt/data_stores/data_store.rb +1 -1
- data/lib/volt/extra_core/array.rb +1 -6
- data/lib/volt/extra_core/blank.rb +1 -3
- data/lib/volt/extra_core/class.rb +1 -1
- data/lib/volt/extra_core/extra_core.rb +0 -1
- data/lib/volt/extra_core/logger.rb +78 -1
- data/lib/volt/extra_core/object.rb +4 -4
- data/lib/volt/models/array_model.rb +2 -3
- data/lib/volt/models/buffer.rb +1 -2
- data/lib/volt/models/field_helpers.rb +4 -5
- data/lib/volt/models/model.rb +27 -1
- data/lib/volt/models/model_hash_behaviour.rb +3 -4
- data/lib/volt/models/persistors/array_store.rb +6 -7
- data/lib/volt/models/persistors/cookies.rb +2 -2
- data/lib/volt/models/persistors/model_store.rb +5 -6
- data/lib/volt/models/validations.rb +5 -7
- data/lib/volt/models/validators/email_validator.rb +8 -29
- data/lib/volt/models/validators/format_validator.rb +116 -0
- data/lib/volt/models/validators/numericality_validator.rb +2 -2
- data/lib/volt/models/validators/phone_number_validator.rb +8 -29
- data/lib/volt/models/validators/unique_validator.rb +2 -2
- data/lib/volt/page/bindings/content_binding.rb +1 -1
- data/lib/volt/page/bindings/each_binding.rb +1 -1
- data/lib/volt/page/bindings/template_binding/view_lookup_for_path.rb +92 -0
- data/lib/volt/page/bindings/template_binding.rb +10 -85
- data/lib/volt/page/channel.rb +0 -1
- data/lib/volt/page/page.rb +5 -7
- data/lib/volt/page/sub_context.rb +1 -1
- data/lib/volt/page/targets/base_section.rb +2 -2
- data/lib/volt/page/targets/helpers/comment_searchers.rb +2 -2
- data/lib/volt/reactive/reactive_accessors.rb +1 -1
- data/lib/volt/reactive/reactive_array.rb +6 -6
- data/lib/volt/router/routes.rb +4 -4
- data/lib/volt/server/rack/asset_files.rb +1 -2
- data/lib/volt/server/rack/component_code.rb +0 -2
- data/lib/volt/server/rack/component_paths.rb +2 -2
- data/lib/volt/server/rack/quiet_common_logger.rb +2 -2
- data/lib/volt/spec/capybara.rb +1 -1
- data/lib/volt/spec/sauce_labs.rb +6 -6
- data/lib/volt/spec/setup.rb +8 -7
- data/lib/volt/tasks/dispatcher.rb +12 -10
- data/lib/volt/tasks/task_handler.rb +1 -1
- data/lib/volt/utils/generic_pool.rb +2 -2
- data/lib/volt/volt/users.rb +7 -9
- data/lib/volt.rb +2 -4
- data/spec/apps/file_loading/app/missing_deps/config/dependencies.rb +1 -1
- data/spec/apps/kitchen_sink/Gemfile +2 -2
- data/spec/apps/kitchen_sink/app/main/config/dependencies.rb +1 -1
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +0 -1
- data/spec/apps/kitchen_sink/app/main/models/user.rb +1 -1
- data/spec/apps/kitchen_sink/app/main/views/main/main.html +1 -1
- data/spec/apps/kitchen_sink/config/app.rb +1 -1
- data/spec/extra_core/array_spec.rb +4 -2
- data/spec/extra_core/blank_spec.rb +11 -0
- data/spec/extra_core/class_spec.rb +2 -2
- data/spec/extra_core/logger_spec.rb +50 -0
- data/spec/extra_core/string_transformations_spec.rb +0 -1
- data/spec/integration/cookies_spec.rb +1 -2
- data/spec/integration/flash_spec.rb +2 -3
- data/spec/integration/list_spec.rb +1 -1
- data/spec/integration/templates_spec.rb +0 -1
- data/spec/integration/url_spec.rb +1 -2
- data/spec/integration/user_spec.rb +3 -3
- data/spec/models/field_helpers_spec.rb +2 -2
- data/spec/models/model_spec.rb +21 -2
- data/spec/models/user_spec.rb +69 -0
- data/spec/models/validations_spec.rb +69 -78
- data/spec/models/validators/email_validator_spec.rb +3 -3
- data/spec/models/validators/format_validator_spec.rb +144 -0
- data/spec/models/validators/length_validator_spec.rb +82 -0
- data/spec/models/validators/phone_number_validator_spec.rb +3 -3
- data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +149 -0
- data/spec/page/bindings/template_binding_spec.rb +0 -151
- data/spec/reactive/computation_spec.rb +46 -0
- data/spec/reactive/dependency_spec.rb +0 -1
- data/spec/reactive/reactive_array_spec.rb +0 -1
- data/spec/router/routes_spec.rb +0 -4
- data/spec/server/html_parser/view_parser_spec.rb +0 -4
- data/spec/server/rack/asset_files_spec.rb +1 -1
- data/spec/server/rack/quite_common_logger_spec.rb +55 -0
- data/spec/spec_helper.rb +2 -5
- data/spec/tasks/dispatcher_spec.rb +16 -5
- data/spec/tasks/live_query_spec.rb +0 -1
- data/spec/tasks/query_tasks.rb +0 -1
- data/spec/tasks/query_tracker_spec.rb +0 -3
- data/spec/templates/targets/binding_document/component_node_spec.rb +0 -1
- data/spec/utils/generic_counting_pool_spec.rb +0 -1
- data/spec/utils/generic_pool_spec.rb +0 -1
- data/templates/component/assets/images/.empty_directory +0 -0
- data/templates/project/README.md.tt +3 -2
- data/templates/project/app/main/assets/images/.empty_directory +0 -0
- data/templates/project/config/base/index.html +6 -7
- data/volt.gemspec +3 -5
- metadata +27 -9
- data/lib/volt/extra_core/numeric.rb +0 -9
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
if RUBY_PLATFORM != 'opal'
|
|
2
|
+
describe Volt::VoltLogger do
|
|
3
|
+
let(:args) { [5, :arg2] }
|
|
4
|
+
let(:class_name) { 'ClassName' }
|
|
5
|
+
let(:method_name) { 'method_name' }
|
|
6
|
+
let(:run_time) { 50 }
|
|
7
|
+
|
|
8
|
+
let(:logger) { Volt::VoltLogger.new }
|
|
9
|
+
|
|
10
|
+
let(:logger_with_opts) do
|
|
11
|
+
Volt::VoltLogger.new({
|
|
12
|
+
args: args,
|
|
13
|
+
class_name: class_name,
|
|
14
|
+
method_name: method_name,
|
|
15
|
+
run_time: run_time
|
|
16
|
+
})
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'should log only severity and message wrapped in line breaks' do
|
|
20
|
+
expect(STDOUT).to receive(:write).with("\n\n[INFO] message\n")
|
|
21
|
+
logger.log(Logger::INFO, "message")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'should convert an array of arguments into a string' do
|
|
25
|
+
expect(logger_with_opts.args).to eq([5, :arg2])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'when STDOUT is a TTY' do
|
|
29
|
+
it 'should return a blue class name' do
|
|
30
|
+
expect(logger_with_opts.class_name).to eq("\e[1;34m#{class_name}\e[0;37m")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'should return a green method name' do
|
|
34
|
+
expect(logger_with_opts.method_name).to eq("\e[0;32m#{method_name}\e[0;37m")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should return a green run time in milliseconds' do
|
|
38
|
+
expect(logger_with_opts.run_time).to eq("\e[0;32m#{run_time}ms\e[0;37m")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context 'when STDOUT is not a TTY' do
|
|
43
|
+
before { allow(STDOUT).to receive(:tty?).and_return(false) }
|
|
44
|
+
|
|
45
|
+
it 'should not add any terminal color codes' do
|
|
46
|
+
expect(logger_with_opts.class_name).to eq(class_name)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
if ENV['BROWSER'] && ENV['BROWSER'] != 'sauce'
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
|
-
describe 'flash messages', type: :feature, :
|
|
5
|
+
describe 'flash messages', type: :feature, sauce: true do
|
|
6
6
|
it 'should flash on sucesses, notices, warnings, and errors' do
|
|
7
7
|
visit '/'
|
|
8
8
|
|
|
@@ -27,7 +27,6 @@ if ENV['BROWSER'] && ENV['BROWSER'] != 'sauce'
|
|
|
27
27
|
expect(page).to have_content('An error message')
|
|
28
28
|
find('.alert').click
|
|
29
29
|
expect(page).to_not have_content('An error message')
|
|
30
|
-
|
|
31
30
|
end
|
|
32
31
|
end
|
|
33
|
-
end
|
|
32
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
if ENV['BROWSER']
|
|
2
2
|
require 'spec_helper'
|
|
3
3
|
|
|
4
|
-
describe
|
|
4
|
+
describe 'user accounts', type: :feature, sauce: true do
|
|
5
5
|
before(:each) do
|
|
6
6
|
# Clear out db
|
|
7
7
|
DataStore.new.drop_database
|
|
@@ -38,7 +38,7 @@ if ENV['BROWSER']
|
|
|
38
38
|
visit '/'
|
|
39
39
|
|
|
40
40
|
# Add the user
|
|
41
|
-
$page.store._users << {email: 'test@test.com', password: 'awes0mesEcRet', name: 'Test Account 9550'}
|
|
41
|
+
$page.store._users << { email: 'test@test.com', password: 'awes0mesEcRet', name: 'Test Account 9550' }
|
|
42
42
|
|
|
43
43
|
click_link 'Login'
|
|
44
44
|
|
|
@@ -77,4 +77,4 @@ if ENV['BROWSER']
|
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
end
|
|
80
|
+
end
|
|
@@ -6,7 +6,7 @@ class ExampleModelWithField < Volt::Model
|
|
|
6
6
|
field :value, Numeric
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
describe
|
|
9
|
+
describe 'field helpers' do
|
|
10
10
|
it 'should allow a user to setup a field that can be written to and read' do
|
|
11
11
|
model = ExampleModelWithField.new
|
|
12
12
|
|
|
@@ -26,4 +26,4 @@ describe "field helpers" do
|
|
|
26
26
|
ExampleModelWithField.field :awesome, Array
|
|
27
27
|
end.to raise_error(FieldHelpers::InvalidFieldClass)
|
|
28
28
|
end
|
|
29
|
-
end
|
|
29
|
+
end
|
data/spec/models/model_spec.rb
CHANGED
|
@@ -8,7 +8,6 @@ class Item < Volt::Model
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
describe Volt::Model do
|
|
11
|
-
|
|
12
11
|
it 'should allow _ methods to be used to store values without predefining them' do
|
|
13
12
|
a = Volt::Model.new
|
|
14
13
|
a._stash = 'yes'
|
|
@@ -131,7 +130,6 @@ describe Volt::Model do
|
|
|
131
130
|
Volt::Computation.flush!
|
|
132
131
|
|
|
133
132
|
expect(values).to eq([nil, 'one'])
|
|
134
|
-
|
|
135
133
|
end
|
|
136
134
|
|
|
137
135
|
it 'should trigger changed for any indicies after a deleted index' do
|
|
@@ -401,6 +399,27 @@ describe Volt::Model do
|
|
|
401
399
|
end
|
|
402
400
|
end
|
|
403
401
|
|
|
402
|
+
describe 'reserved attributes' do
|
|
403
|
+
let(:model) { Volt::Model.new }
|
|
404
|
+
|
|
405
|
+
it 'should prevent reserved attributes from being read with underscores' do
|
|
406
|
+
[:attributes, :parent, :path, :options, :persistor].each do |attr_name|
|
|
407
|
+
expect do
|
|
408
|
+
model.send(:"_#{attr_name}")
|
|
409
|
+
end.to raise_error(Volt::InvalidFieldName, "`#{attr_name}` is reserved and can not be used as a field")
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
it 'should prevent reserved attributes from being assigned directly' do
|
|
415
|
+
[:attributes, :parent, :path, :options, :persistor].each do |attr_name|
|
|
416
|
+
expect do
|
|
417
|
+
model.send(:"_#{attr_name}=", 'assign val')
|
|
418
|
+
end.to raise_error(Volt::InvalidFieldName, "`#{attr_name}` is reserved and can not be used as a field")
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
404
423
|
describe 'persistors' do
|
|
405
424
|
it 'should setup a new instance of the persistor with self' do
|
|
406
425
|
persistor = double('volt/persistor')
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'volt/models/user'
|
|
3
|
+
|
|
4
|
+
class FakeConfig
|
|
5
|
+
def public; self; end
|
|
6
|
+
def auth; self; end
|
|
7
|
+
def use_username; true; end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe Volt::User do
|
|
11
|
+
describe '.login_field' do
|
|
12
|
+
subject { Volt::User.login_field }
|
|
13
|
+
|
|
14
|
+
context 'when use_username is set to true' do
|
|
15
|
+
before do
|
|
16
|
+
allow(Volt).to receive(:config).and_return FakeConfig.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "returns :username" do
|
|
20
|
+
expect(subject).to eq :username
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'when use_username is not set' do
|
|
25
|
+
it "returns :email" do
|
|
26
|
+
expect(subject).to eq :email
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#password=' do
|
|
32
|
+
let!(:user) { Volt::User.new }
|
|
33
|
+
|
|
34
|
+
subject { user.password = 'test' }
|
|
35
|
+
|
|
36
|
+
if RUBY_PLATFORM != 'opal'
|
|
37
|
+
context 'when it is a Volt server' do
|
|
38
|
+
before do
|
|
39
|
+
allow(BCrypt::Password).to receive(:create).with('test').
|
|
40
|
+
and_return 'hashed-password'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "encrypts password" do
|
|
44
|
+
subject
|
|
45
|
+
|
|
46
|
+
expect(BCrypt::Password).to have_received :create
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'sets _hashed_password to passed value' do
|
|
50
|
+
subject
|
|
51
|
+
|
|
52
|
+
expect(user._hashed_password).to eq "hashed-password"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'when it is not a Volt server' do
|
|
58
|
+
before do
|
|
59
|
+
allow(Volt).to receive(:server?).and_return false
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'sets _password to passed value' do
|
|
63
|
+
subject
|
|
64
|
+
|
|
65
|
+
expect(user._password).to eq 'test'
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
class TestModel < Volt::Model
|
|
4
|
-
validate :count, numericality: { min: 5, max: 10 }
|
|
5
|
-
validate :description, length: { message: 'needs to be longer', length: 50 }
|
|
6
|
-
validate :email, email: true
|
|
7
|
-
validate :name, length: 4
|
|
8
|
-
validate :phone_number, phone_number: true
|
|
9
|
-
validate :username, presence: true
|
|
10
|
-
end
|
|
11
|
-
|
|
12
3
|
describe Volt::Model do
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
let(:model) { test_model_class.new }
|
|
5
|
+
|
|
6
|
+
let(:test_model_class) do
|
|
7
|
+
Class.new(Volt::Model) do
|
|
8
|
+
validate :count, numericality: { min: 5, max: 10 }
|
|
9
|
+
validate :description, length: { message: 'needs to be longer',
|
|
10
|
+
length: 50 }
|
|
11
|
+
validate :email, email: true
|
|
12
|
+
validate :name, length: 4
|
|
13
|
+
validate :phone_number, phone_number: true
|
|
14
|
+
validate :username, presence: true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'should return errors for all failed validations' do
|
|
19
|
+
expect(model.errors).to eq(
|
|
15
20
|
count: ['must be a number'],
|
|
16
21
|
description: ['needs to be longer'],
|
|
17
22
|
email: ['must be an email address'],
|
|
@@ -21,23 +26,7 @@ describe Volt::Model do
|
|
|
21
26
|
)
|
|
22
27
|
end
|
|
23
28
|
|
|
24
|
-
it 'should show marked validations once they are marked' do
|
|
25
|
-
model = TestModel.new
|
|
26
|
-
|
|
27
|
-
expect(model.marked_errors).to eq({})
|
|
28
|
-
|
|
29
|
-
model.mark_field!(:name)
|
|
30
|
-
|
|
31
|
-
expect(model.marked_errors).to eq(
|
|
32
|
-
name: ['must be at least 4 characters']
|
|
33
|
-
)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
29
|
it 'should show all fields in marked errors once saved' do
|
|
37
|
-
model = TestModel.new
|
|
38
|
-
|
|
39
|
-
expect(model.marked_errors).to eq({})
|
|
40
|
-
|
|
41
30
|
model.save!
|
|
42
31
|
|
|
43
32
|
expect(model.marked_errors.keys).to eq(
|
|
@@ -45,73 +34,75 @@ describe Volt::Model do
|
|
|
45
34
|
)
|
|
46
35
|
end
|
|
47
36
|
|
|
48
|
-
describe '
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
expect(model.marked_errors).to eq(
|
|
57
|
-
description: ['needs to be longer']
|
|
58
|
-
)
|
|
37
|
+
describe 'builtin validations' do
|
|
38
|
+
shared_examples_for 'a built in validation' do |field, message|
|
|
39
|
+
specify do
|
|
40
|
+
expect { model.mark_field! field }
|
|
41
|
+
.to change { model.marked_errors }
|
|
42
|
+
.from({}).to({ field => [message ] })
|
|
43
|
+
end
|
|
59
44
|
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
describe 'presence' do
|
|
63
|
-
it 'should validate presence' do
|
|
64
|
-
model = TestModel.new
|
|
65
|
-
|
|
66
|
-
expect(model.marked_errors).to eq({})
|
|
67
45
|
|
|
68
|
-
|
|
46
|
+
describe 'numericality' do
|
|
47
|
+
message = 'must be a number'
|
|
48
|
+
it_should_behave_like 'a built in validation', :count, message
|
|
49
|
+
end
|
|
69
50
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
51
|
+
describe 'length' do
|
|
52
|
+
message = 'needs to be longer'
|
|
53
|
+
it_should_behave_like 'a built in validation', :description, message
|
|
73
54
|
end
|
|
74
|
-
end
|
|
75
55
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
56
|
+
describe 'email' do
|
|
57
|
+
message = 'must be an email address'
|
|
58
|
+
it_should_behave_like 'a built in validation', :email, message
|
|
59
|
+
end
|
|
79
60
|
|
|
80
|
-
|
|
61
|
+
describe 'name' do
|
|
62
|
+
message = 'must be at least 4 characters'
|
|
63
|
+
it_should_behave_like 'a built in validation', :name, message
|
|
64
|
+
end
|
|
81
65
|
|
|
82
|
-
|
|
66
|
+
describe 'phone_number' do
|
|
67
|
+
message = 'must be a phone number with area or country code'
|
|
68
|
+
it_should_behave_like 'a built in validation', :phone_number, message
|
|
69
|
+
end
|
|
83
70
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
71
|
+
describe 'presence' do
|
|
72
|
+
message = 'must be specified'
|
|
73
|
+
it_should_behave_like 'a built in validation', :username, message
|
|
87
74
|
end
|
|
88
75
|
end
|
|
89
76
|
|
|
90
|
-
describe '
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
77
|
+
describe 'validators with multiple criteria' do
|
|
78
|
+
let(:regex_message) { 'regex failed' }
|
|
79
|
+
let(:proc_message) { 'proc failed' }
|
|
80
|
+
|
|
81
|
+
let(:test_model_class) do
|
|
82
|
+
Class.new(Volt::Model) do
|
|
83
|
+
validate :special_field, format: [
|
|
84
|
+
{ with: /regex/, message: 'regex failed' },
|
|
85
|
+
{ with: ->(x) {x == false}, message: 'proc failed' }
|
|
86
|
+
]
|
|
87
|
+
end
|
|
101
88
|
end
|
|
102
|
-
end
|
|
103
89
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
model = TestModel.new
|
|
90
|
+
context 'when multiple fail' do
|
|
91
|
+
before { model._special_field = 'nope' }
|
|
107
92
|
|
|
108
|
-
|
|
93
|
+
it 'returns an array of errors' do
|
|
94
|
+
expect(model.errors).to eq({
|
|
95
|
+
special_field: [ regex_message, proc_message ]
|
|
96
|
+
})
|
|
97
|
+
end
|
|
98
|
+
end
|
|
109
99
|
|
|
110
|
-
|
|
100
|
+
context 'when one fails' do
|
|
101
|
+
before { model._special_field = 'regex' }
|
|
111
102
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
103
|
+
it 'returns an array with a single error' do
|
|
104
|
+
expect(model.errors).to eq({ special_field: [ proc_message ] })
|
|
105
|
+
end
|
|
115
106
|
end
|
|
116
107
|
end
|
|
117
108
|
end
|
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Volt::EmailValidator do
|
|
4
4
|
subject { Volt::EmailValidator.new(*params) }
|
|
5
|
-
let(:params) { [
|
|
5
|
+
let(:params) { [model, field_name, options] }
|
|
6
6
|
|
|
7
7
|
let(:model) { Volt::Model.new email: email }
|
|
8
8
|
let(:field_name) { :email }
|
|
@@ -105,14 +105,14 @@ describe Volt::EmailValidator do
|
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
context 'when provided a custom error message' do
|
|
108
|
-
let(:options) { {
|
|
108
|
+
let(:options) { { message: custom_message } }
|
|
109
109
|
let(:custom_message) { 'this is a custom message' }
|
|
110
110
|
|
|
111
111
|
context 'and the email is invalid' do
|
|
112
112
|
let(:email) { invalid_email }
|
|
113
113
|
|
|
114
114
|
it 'returns errors with the custom message' do
|
|
115
|
-
expect(subject.errors).to eq(email: [
|
|
115
|
+
expect(subject.errors).to eq(email: [custom_message])
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
118
|
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Volt::FormatValidator do
|
|
4
|
+
subject { described_class.new(*init_params) }
|
|
5
|
+
|
|
6
|
+
let(:init_params) { [ model, field_name ] }
|
|
7
|
+
let(:validate_params) { [ model, nil, field_name, options ] }
|
|
8
|
+
|
|
9
|
+
let(:model) { Volt::Model.new field: field_content }
|
|
10
|
+
let(:field_name) { :field }
|
|
11
|
+
let(:options) { regex_opts }
|
|
12
|
+
|
|
13
|
+
let(:regex) { /^valid/ }
|
|
14
|
+
let(:proc_regex) { /^valid/ }
|
|
15
|
+
let(:test_proc) { ->(content) { proc_regex.match content } }
|
|
16
|
+
|
|
17
|
+
let(:proc_opts) { { with: test_proc, message: proc_message } }
|
|
18
|
+
let(:regex_opts) { { with: regex, message: regex_message } }
|
|
19
|
+
|
|
20
|
+
let(:proc_message) { 'proc is invalid' }
|
|
21
|
+
let(:regex_message) { 'regex is invalid' }
|
|
22
|
+
|
|
23
|
+
let(:field_content) { valid_content }
|
|
24
|
+
let(:invalid_content) { 'invalid_content' }
|
|
25
|
+
let(:valid_content) { 'valid_content' }
|
|
26
|
+
|
|
27
|
+
let(:validate) { described_class.validate(*validate_params) }
|
|
28
|
+
|
|
29
|
+
before do
|
|
30
|
+
allow(described_class).to receive(:new).and_return subject
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context 'when no criteria is provided' do
|
|
34
|
+
before { validate }
|
|
35
|
+
|
|
36
|
+
it 'should have no errors' do
|
|
37
|
+
expect(subject.errors).to eq({})
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
specify { expect(subject).to be_valid }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'when the only criterion is a regex' do
|
|
44
|
+
let(:options) { regex_opts }
|
|
45
|
+
|
|
46
|
+
before { validate }
|
|
47
|
+
|
|
48
|
+
context 'and the field matches' do
|
|
49
|
+
let(:field_content) { valid_content }
|
|
50
|
+
|
|
51
|
+
it 'should have no errors' do
|
|
52
|
+
expect(subject.errors).to eq({})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
specify { expect(subject).to be_valid }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context 'and the field does not match' do
|
|
59
|
+
let(:field_content) { invalid_content }
|
|
60
|
+
|
|
61
|
+
it 'should report the related error message' do
|
|
62
|
+
expect(subject.errors).to eq field_name => [regex_message]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
specify { expect(subject).to_not be_valid }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context 'when the only criterion is a block' do
|
|
70
|
+
let(:options) { proc_opts }
|
|
71
|
+
|
|
72
|
+
before { validate }
|
|
73
|
+
|
|
74
|
+
context 'and the field passes the block' do
|
|
75
|
+
let(:field_content) { valid_content }
|
|
76
|
+
|
|
77
|
+
it 'should have no errors' do
|
|
78
|
+
expect(subject.errors).to eq({})
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
specify { expect(subject).to be_valid }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context 'and the field fails the block' do
|
|
85
|
+
let(:field_content) { invalid_content }
|
|
86
|
+
|
|
87
|
+
it 'should report the related error message' do
|
|
88
|
+
expect(subject.errors).to eq field_name => [proc_message]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
specify { expect(subject).to_not be_valid }
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context 'when there is both regex and block criteria' do
|
|
96
|
+
let(:options) { [ regex_opts, proc_opts ] }
|
|
97
|
+
|
|
98
|
+
before { validate }
|
|
99
|
+
|
|
100
|
+
context 'and the field passes all criteria' do
|
|
101
|
+
let(:field_content) { valid_content }
|
|
102
|
+
|
|
103
|
+
it 'should have no errors' do
|
|
104
|
+
expect(subject.errors).to eq({})
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
specify { expect(subject).to be_valid }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context 'and the field fails the regex' do
|
|
111
|
+
let(:regex) { /^invalid/ }
|
|
112
|
+
|
|
113
|
+
it 'should report the related error message' do
|
|
114
|
+
expect(subject.errors).to eq field_name => [regex_message]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
specify { expect(subject).to_not be_valid }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context 'and the field fails the block' do
|
|
121
|
+
let(:proc_regex) { /^invalid/ }
|
|
122
|
+
|
|
123
|
+
it 'should report the related error message' do
|
|
124
|
+
expect(subject.errors).to eq field_name => [proc_message]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
specify { expect(subject).to_not be_valid }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context 'and the field fails both the regex and the block' do
|
|
131
|
+
let(:field_content) { invalid_content }
|
|
132
|
+
|
|
133
|
+
it 'should report the regex error message' do
|
|
134
|
+
expect(subject.errors[field_name]).to include regex_message
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'should report the proc error message' do
|
|
138
|
+
expect(subject.errors[field_name]).to include proc_message
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
specify { expect(subject).to_not be_valid }
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|