releaf-content 0.2.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +19 -21
- data/app/assets/javascripts/{releaf/controllers → controllers}/releaf/content/nodes.js +0 -0
- data/app/assets/stylesheets/{releaf/controllers → controllers}/releaf/content/nodes.scss +0 -0
- data/app/builders/releaf/content/builders/action_dialog.rb +9 -1
- data/app/builders/releaf/content/builders/tree.rb +1 -1
- data/app/builders/releaf/content/content_type_dialog_builder.rb +2 -2
- data/app/builders/releaf/content/nodes/form_builder.rb +3 -3
- data/app/builders/releaf/content/nodes/index_builder.rb +1 -1
- data/app/builders/releaf/content/nodes/toolbox_builder.rb +0 -5
- data/app/controllers/releaf/content/nodes_controller.rb +109 -129
- data/app/middleware/releaf/content/routes_reloader.rb +12 -4
- data/app/services/releaf/content/node/copy.rb +90 -0
- data/app/services/releaf/content/node/move.rb +21 -0
- data/app/services/releaf/content/node/save_under_parent.rb +22 -0
- data/app/services/releaf/content/node/service.rb +17 -0
- data/app/validators/releaf/content/node/singleness_validator.rb +1 -24
- data/lib/releaf-content.rb +85 -6
- data/lib/releaf/content/acts_as_node.rb +0 -5
- data/lib/releaf/content/acts_as_node/active_record/acts/node.rb +2 -8
- data/lib/releaf/content/configuration.rb +61 -0
- data/lib/releaf/content/engine.rb +1 -34
- data/lib/releaf/content/node.rb +30 -101
- data/lib/releaf/content/node_mapper.rb +28 -2
- data/lib/releaf/content/route.rb +37 -25
- data/spec/builders/content/nodes/action_dialog_spec.rb +39 -0
- data/spec/builders/content/nodes/form_builder_spec.rb +47 -3
- data/spec/builders/content/nodes/toolbox_builder_spec.rb +1 -32
- data/spec/controllers/releaf/content/nodes_controller_spec.rb +42 -11
- data/spec/features/nodes_services_spec.rb +207 -0
- data/spec/features/nodes_spec.rb +328 -30
- data/spec/lib/releaf/content/acts_as_node_spec.rb +4 -32
- data/spec/lib/releaf/content/configuration_spec.rb +159 -0
- data/spec/lib/releaf/content/engine_spec.rb +149 -0
- data/spec/lib/releaf/content/node_spec.rb +66 -324
- data/spec/lib/releaf/content/route_spec.rb +223 -34
- data/spec/middleware/routes_reloader_spec.rb +62 -14
- data/spec/routing/node_mapper_spec.rb +223 -55
- data/spec/services/releaf/content/node/copy_spec.rb +115 -0
- data/spec/services/releaf/content/node/move_spec.rb +20 -0
- data/spec/services/releaf/content/node/save_under_parent_spec.rb +49 -0
- data/spec/services/releaf/content/node/service_spec.rb +19 -0
- metadata +38 -21
- data/app/builders/releaf/content/go_to_dialog_builder.rb +0 -9
- data/app/views/releaf/content/nodes/go_to_dialog.ruby +0 -1
- data/lib/releaf/content/builders_autoload.rb +0 -18
- data/releaf-content.gemspec +0 -20
@@ -35,23 +35,15 @@ describe ActsAsNode do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
describe "#node" do
|
39
|
-
it "returns corresponding node object" do
|
40
|
-
allow_any_instance_of(Releaf::Content::Node::RootValidator).to receive(:validate)
|
41
|
-
node = create(:node, content_type: "Book", content_attributes: {title: "xx"})
|
42
|
-
expect(Book.last.node).to eq(node)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
38
|
context ".acts_as_node_params" do
|
47
39
|
before do
|
48
|
-
allow_any_instance_of(Releaf::
|
40
|
+
allow_any_instance_of(Releaf::ResourceParams).to receive(:values).and_return(["a", "b"])
|
49
41
|
end
|
50
42
|
|
51
43
|
context "when `params` configuration is nil" do
|
52
44
|
it "returns model params with `id` param" do
|
53
45
|
allow(Book).to receive(:acts_as_node_configuration).and_return(params: nil)
|
54
|
-
expect(Releaf::
|
46
|
+
expect(Releaf::ResourceParams).to receive(:new).with(Book).and_call_original
|
55
47
|
expect(Book.acts_as_node_params).to eq(["a", "b", :id])
|
56
48
|
end
|
57
49
|
end
|
@@ -66,13 +58,13 @@ describe ActsAsNode do
|
|
66
58
|
|
67
59
|
context ".acts_as_node_fields" do
|
68
60
|
before do
|
69
|
-
allow_any_instance_of(Releaf::
|
61
|
+
allow_any_instance_of(Releaf::ResourceFields).to receive(:values).and_return(["a", "b"])
|
70
62
|
end
|
71
63
|
|
72
64
|
context "when `fields` configuration is nil" do
|
73
65
|
it "returns model fields" do
|
74
66
|
allow(Book).to receive(:acts_as_node_configuration).and_return(fields: nil)
|
75
|
-
expect(Releaf::
|
67
|
+
expect(Releaf::ResourceFields).to receive(:new).with(Book).and_call_original
|
76
68
|
expect(Book.acts_as_node_fields).to eq(["a", "b"])
|
77
69
|
end
|
78
70
|
end
|
@@ -85,16 +77,6 @@ describe ActsAsNode do
|
|
85
77
|
end
|
86
78
|
end
|
87
79
|
|
88
|
-
context ".nodes" do
|
89
|
-
it "loads tree nodes" do
|
90
|
-
expect(Node).to receive(:where).with(content_type: Book.name)
|
91
|
-
Book.nodes
|
92
|
-
end
|
93
|
-
|
94
|
-
it "returns relation" do
|
95
|
-
expect(Book.nodes.class).to eq(Node::ActiveRecord_Relation)
|
96
|
-
end
|
97
|
-
end
|
98
80
|
end
|
99
81
|
|
100
82
|
describe ActionController::Acts::Node do
|
@@ -104,15 +86,5 @@ describe ActsAsNode do
|
|
104
86
|
end
|
105
87
|
end
|
106
88
|
|
107
|
-
context ".nodes" do
|
108
|
-
it "loads tree nodes" do
|
109
|
-
expect(Node).to receive(:where).with(content_type: ContactFormController.name)
|
110
|
-
ContactFormController.nodes
|
111
|
-
end
|
112
|
-
|
113
|
-
it "returns array" do
|
114
|
-
expect(ContactFormController.nodes.class).to eq(Node::ActiveRecord_Relation)
|
115
|
-
end
|
116
|
-
end
|
117
89
|
end
|
118
90
|
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
describe Releaf::Content::Configuration do
|
4
|
+
class ContentConfigurationDummyNode; end;
|
5
|
+
class ContentConfigurationDummyNodesController; end;
|
6
|
+
subject{ described_class.new(resources: {}) }
|
7
|
+
|
8
|
+
describe "#verify_resources_config" do
|
9
|
+
context "when valid config" do
|
10
|
+
it "does no raise an error" do
|
11
|
+
config = {'Node' => { controller: 'Releaf::Content::NodesController'}}
|
12
|
+
expect{ subject.verify_resources_config(config) }.to_not raise_error
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when config is not a hash" do
|
17
|
+
it "raises an error" do
|
18
|
+
config = :foo
|
19
|
+
expect{ subject.verify_resources_config(config) }.to raise_error Releaf::Error, "Releaf.application.config.content.resources must be a Hash"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when any of the hash keys are not strings" do
|
24
|
+
it "raises an error" do
|
25
|
+
config = {Node => { controller: 'Releaf::Content::NodesController', foo: "wat"}}
|
26
|
+
expect{ subject.verify_resources_config(config) }.to raise_error Releaf::Error, "Releaf.application.config.content.resources must have string keys"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when any of the entries does not have a hash as a value" do
|
31
|
+
it "raises an error" do
|
32
|
+
config = {'Node' => :foo}
|
33
|
+
expect{ subject.verify_resources_config(config) }.to raise_error Releaf::Error, "Node in Releaf.application.config.content.resources must have a hash value"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when any of the entries does not have controller class name set" do
|
38
|
+
it "raises an error" do
|
39
|
+
config = {'Node' => { foo: "wat" }}
|
40
|
+
expect{ subject.verify_resources_config(config) }.to raise_error Releaf::Error, "Node in Releaf.application.config.content.resources must have controller class specified as a string"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when any of the entries does not have a string for the controller class name" do
|
45
|
+
it "raises an error" do
|
46
|
+
config = {'Node' => { controller: Releaf::Content::NodesController, foo: "wat" }}
|
47
|
+
expect{ subject.verify_resources_config(config) }.to raise_error Releaf::Error, "Node in Releaf.application.config.content.resources must have controller class specified as a string"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#models" do
|
53
|
+
it "returns an array of node model classes" do
|
54
|
+
expect(subject).to receive(:model_names).and_return(['ContentConfigurationDummyNode', 'Object'])
|
55
|
+
expect(subject.models).to eq [ContentConfigurationDummyNode, Object]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#model_names" do
|
60
|
+
it "returns an array of defined node class names" do
|
61
|
+
expect(subject).to receive(:resources).and_return(
|
62
|
+
'ContentConfigurationDummyNode' => { controller: 'Releaf::Content::NodesController' }
|
63
|
+
)
|
64
|
+
expect(subject.model_names).to eq [ 'ContentConfigurationDummyNode' ]
|
65
|
+
end
|
66
|
+
|
67
|
+
it "caches the result" do
|
68
|
+
expect(subject).to receive(:resources).once.and_call_original
|
69
|
+
subject.model_names
|
70
|
+
subject.model_names
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#default_model" do
|
75
|
+
it "returns the first model from #models" do
|
76
|
+
expect(subject).to receive(:models).and_return [ :foo, :bar ]
|
77
|
+
expect(subject.default_model).to eq :foo
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#controllers" do
|
82
|
+
it "returns an array of node controller classes" do
|
83
|
+
expect(subject).to receive(:controller_names).and_return([
|
84
|
+
'Releaf::Content::NodesController', 'Admin::OtherSite::OtherNodesController'
|
85
|
+
])
|
86
|
+
expect(subject.controllers).to eq [Releaf::Content::NodesController, Admin::OtherSite::OtherNodesController]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#controller_names" do
|
91
|
+
it "returns an array of defined node controller class names" do
|
92
|
+
allow(subject).to receive(:resources).and_return(
|
93
|
+
'Node' => { controller: 'Releaf::Content::NodesController' },
|
94
|
+
'ContentConfigurationDummyNode' => { controller: 'ContentConfigurationDummyNodesController' }
|
95
|
+
)
|
96
|
+
expect(subject.controller_names).to eq [ 'Releaf::Content::NodesController', 'ContentConfigurationDummyNodesController' ]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "caches the result" do
|
100
|
+
expect(subject).to receive(:resources).once.and_call_original
|
101
|
+
subject.controller_names
|
102
|
+
subject.controller_names
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe ".routing" do
|
107
|
+
it "returns a hash with all node class names as string keys" do
|
108
|
+
allow(subject).to receive(:resources).and_return(
|
109
|
+
'Node' => { controller: 'Releaf::Content::NodesController' },
|
110
|
+
'ContentConfigurationDummyNode' => { controller: 'ContentConfigurationDummyNodesController' }
|
111
|
+
)
|
112
|
+
result = subject.routing
|
113
|
+
expect( result ).to be_a Hash
|
114
|
+
expect( result.keys ).to eq ['Node', 'ContentConfigurationDummyNode' ]
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when node has no routing defined" do
|
118
|
+
it "returns routing hash with site and constraints set to nil" do
|
119
|
+
allow(subject).to receive(:resources).and_return(
|
120
|
+
'Node' => { controller: 'Releaf::Content::NodesController' }
|
121
|
+
)
|
122
|
+
expect(subject.routing).to eq 'Node' => { site: nil, constraints: nil }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "when node has nil values for site and constraints in routing config" do
|
127
|
+
it "returns routing hash with site and constraints set to nil" do
|
128
|
+
allow(subject).to receive(:resources).and_return(
|
129
|
+
'Node' => {controller: 'Releaf::Content::NodesController', routing: { site: nil, constraints: nil }}
|
130
|
+
)
|
131
|
+
expect(subject.routing).to eq 'Node' => { site: nil, constraints: nil }
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "when node has site defined in routing config" do
|
136
|
+
it "returns the defined value in routing hash" do
|
137
|
+
allow(subject).to receive(:resources).and_return(
|
138
|
+
'Node' => {controller: 'Releaf::Content::NodesController', routing: { site: "foo" }}
|
139
|
+
)
|
140
|
+
expect(subject.routing).to eq 'Node' => { site: "foo", constraints: nil }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "when node has constraints defined in routing config" do
|
145
|
+
it "returns the defined value in routing hash" do
|
146
|
+
allow(subject).to receive(:resources).and_return(
|
147
|
+
'Node' => {controller: 'Releaf::Content::NodesController', routing: { constraints: { host: /foo/ }}}
|
148
|
+
)
|
149
|
+
expect(subject.routing).to eq 'Node' => { site: nil, constraints: { host: /foo/ } }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it "caches the result" do
|
154
|
+
expect(subject).to receive(:resources).once.and_call_original
|
155
|
+
subject.routing
|
156
|
+
subject.routing
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
describe Releaf::Content do
|
4
|
+
let(:configuration){ Releaf::Content::Configuration.new(resources: {}) }
|
5
|
+
|
6
|
+
describe ".configure_component" do
|
7
|
+
it "adds new `Releaf::Content::Configuration` configuration with default resources" do
|
8
|
+
allow(Releaf::Content::Configuration).to receive(:new)
|
9
|
+
.with(resources: { 'Node' => { controller: 'Releaf::Content::NodesController' } }).and_return("_new")
|
10
|
+
expect(Releaf.application.config).to receive(:add_configuration).with("_new")
|
11
|
+
described_class.configure_component
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ".configuration" do
|
16
|
+
it "returns a configuration instance" do
|
17
|
+
expect(Releaf.application.config).to receive(:content).and_return(:ok)
|
18
|
+
expect(described_class.configuration).to eq :ok
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
[ :resources, :models, :default_model, :controllers, :routing ].each do |method|
|
23
|
+
describe ".#{method}" do
|
24
|
+
it "returns the method result from the configuration instance" do
|
25
|
+
allow(described_class).to receive(:configuration).and_return(configuration)
|
26
|
+
allow(configuration).to receive(method).and_return(:ok)
|
27
|
+
expect(described_class.send(method)).to eq :ok
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe ".draw_component_routes", type: :routing do
|
33
|
+
before do
|
34
|
+
allow(described_class).to receive(:configuration).and_return(configuration)
|
35
|
+
allow(configuration).to receive(:resources).and_return(
|
36
|
+
'Node' => { controller: 'Releaf::Content::NodesController' },
|
37
|
+
'OtherSite::OtherNode' => { controller: 'Admin::OtherSite::OtherNodesController' }
|
38
|
+
)
|
39
|
+
Dummy::Application.reload_routes!
|
40
|
+
end
|
41
|
+
|
42
|
+
after(:all) do
|
43
|
+
Dummy::Application.reload_routes!
|
44
|
+
end
|
45
|
+
|
46
|
+
context "draws named admin routes for all defined content node controllers" do
|
47
|
+
|
48
|
+
it "draws #index route" do
|
49
|
+
expect( releaf_content_nodes_path ).to eq "/admin/nodes"
|
50
|
+
expect( admin_other_site_other_nodes_path ).to eq "/admin/other_nodes"
|
51
|
+
expect(get: "/admin/nodes").to route_to("releaf/content/nodes#index")
|
52
|
+
expect(get: "/admin/other_nodes").to route_to("admin/other_site/other_nodes#index")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "draws #new route" do
|
56
|
+
expect( new_releaf_content_node_path ).to eq "/admin/nodes/new"
|
57
|
+
expect( new_admin_other_site_other_node_path ).to eq "/admin/other_nodes/new"
|
58
|
+
expect(get: "/admin/nodes/new").to route_to("releaf/content/nodes#new")
|
59
|
+
expect(get: "/admin/other_nodes/new").to route_to("admin/other_site/other_nodes#new")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "draws #create route" do
|
63
|
+
expect(post: "/admin/nodes").to route_to("releaf/content/nodes#create")
|
64
|
+
expect(post: "/admin/other_nodes").to route_to("admin/other_site/other_nodes#create")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "draws #content_type_dialog route" do
|
68
|
+
expect( content_type_dialog_releaf_content_nodes_path ).to eq "/admin/nodes/content_type_dialog"
|
69
|
+
expect( content_type_dialog_admin_other_site_other_nodes_path ).to eq "/admin/other_nodes/content_type_dialog"
|
70
|
+
expect(get: "/admin/nodes/content_type_dialog").to route_to("releaf/content/nodes#content_type_dialog")
|
71
|
+
expect(get: "/admin/other_nodes/content_type_dialog").to route_to("admin/other_site/other_nodes#content_type_dialog")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "draws #generate_url route" do
|
75
|
+
expect( generate_url_releaf_content_nodes_path ).to eq "/admin/nodes/generate_url"
|
76
|
+
expect( generate_url_admin_other_site_other_nodes_path ).to eq "/admin/other_nodes/generate_url"
|
77
|
+
expect(get: "/admin/nodes/generate_url").to route_to("releaf/content/nodes#generate_url")
|
78
|
+
expect(get: "/admin/other_nodes/generate_url").to route_to("admin/other_site/other_nodes#generate_url")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "draws #edit route" do
|
82
|
+
expect( edit_releaf_content_node_path(1) ).to eq "/admin/nodes/1/edit"
|
83
|
+
expect( edit_admin_other_site_other_node_path(1) ).to eq "/admin/other_nodes/1/edit"
|
84
|
+
expect(get: "/admin/nodes/1/edit").to route_to("releaf/content/nodes#edit", "id" => "1")
|
85
|
+
expect(get: "/admin/other_nodes/1/edit").to route_to("admin/other_site/other_nodes#edit", "id" => "1")
|
86
|
+
end
|
87
|
+
|
88
|
+
it "draws #update route" do
|
89
|
+
expect(patch: "/admin/nodes/1").to route_to("releaf/content/nodes#update", "id" => "1")
|
90
|
+
expect(patch: "/admin/other_nodes/1").to route_to("admin/other_site/other_nodes#update", "id" => "1")
|
91
|
+
end
|
92
|
+
|
93
|
+
it "draws #copy_dialog route" do
|
94
|
+
expect( copy_dialog_releaf_content_node_path(1) ).to eq "/admin/nodes/1/copy_dialog"
|
95
|
+
expect( copy_dialog_admin_other_site_other_node_path(1) ).to eq "/admin/other_nodes/1/copy_dialog"
|
96
|
+
expect(get: "/admin/nodes/1/copy_dialog").to route_to("releaf/content/nodes#copy_dialog", "id" => "1")
|
97
|
+
expect(get: "/admin/other_nodes/1/copy_dialog").to route_to("admin/other_site/other_nodes#copy_dialog", "id" => "1")
|
98
|
+
end
|
99
|
+
|
100
|
+
it "draws #copy route" do
|
101
|
+
expect( copy_releaf_content_node_path(1) ).to eq "/admin/nodes/1/copy"
|
102
|
+
expect( copy_admin_other_site_other_node_path(1) ).to eq "/admin/other_nodes/1/copy"
|
103
|
+
expect(post: "/admin/nodes/1/copy").to route_to("releaf/content/nodes#copy", "id" => "1")
|
104
|
+
expect(post: "/admin/other_nodes/1/copy").to route_to("admin/other_site/other_nodes#copy", "id" => "1")
|
105
|
+
end
|
106
|
+
|
107
|
+
it "draws #move_dialog route" do
|
108
|
+
expect( move_dialog_releaf_content_node_path(1) ).to eq "/admin/nodes/1/move_dialog"
|
109
|
+
expect( move_dialog_admin_other_site_other_node_path(1) ).to eq "/admin/other_nodes/1/move_dialog"
|
110
|
+
expect(get: "/admin/nodes/1/move_dialog").to route_to("releaf/content/nodes#move_dialog", "id" => "1")
|
111
|
+
expect(get: "/admin/other_nodes/1/move_dialog").to route_to("admin/other_site/other_nodes#move_dialog", "id" => "1")
|
112
|
+
end
|
113
|
+
|
114
|
+
it "draws #move route" do
|
115
|
+
expect( move_releaf_content_node_path(1) ).to eq "/admin/nodes/1/move"
|
116
|
+
expect( move_admin_other_site_other_node_path(1) ).to eq "/admin/other_nodes/1/move"
|
117
|
+
expect(post: "/admin/nodes/1/move").to route_to("releaf/content/nodes#move", "id" => "1")
|
118
|
+
expect(post: "/admin/other_nodes/1/move").to route_to("admin/other_site/other_nodes#move", "id" => "1")
|
119
|
+
end
|
120
|
+
|
121
|
+
it "draws #toolbox route" do
|
122
|
+
expect( toolbox_releaf_content_node_path(1) ).to eq "/admin/nodes/1/toolbox"
|
123
|
+
expect( toolbox_admin_other_site_other_node_path(1) ).to eq "/admin/other_nodes/1/toolbox"
|
124
|
+
expect(get: "/admin/nodes/1/toolbox").to route_to("releaf/content/nodes#toolbox", "id" => "1")
|
125
|
+
expect(get: "/admin/other_nodes/1/toolbox").to route_to("admin/other_site/other_nodes#toolbox", "id" => "1")
|
126
|
+
end
|
127
|
+
|
128
|
+
it "draws #confirm_destroy route" do
|
129
|
+
expect( confirm_destroy_releaf_content_node_path(1) ).to eq "/admin/nodes/1/confirm_destroy"
|
130
|
+
expect( confirm_destroy_admin_other_site_other_node_path(1) ).to eq "/admin/other_nodes/1/confirm_destroy"
|
131
|
+
expect(get: "/admin/nodes/1/confirm_destroy").to route_to("releaf/content/nodes#confirm_destroy", "id" => "1")
|
132
|
+
expect(get: "/admin/other_nodes/1/confirm_destroy").to route_to("admin/other_site/other_nodes#confirm_destroy", "id" => "1")
|
133
|
+
end
|
134
|
+
|
135
|
+
it "draws #destroy route" do
|
136
|
+
expect(delete: "/admin/nodes/1").to route_to("releaf/content/nodes#destroy", "id" => "1")
|
137
|
+
expect(delete: "/admin/other_nodes/1").to route_to("admin/other_site/other_nodes#destroy", "id" => "1")
|
138
|
+
end
|
139
|
+
|
140
|
+
it "does not draw #show route" do
|
141
|
+
expect(get: "/admin/nodes/1").to route_to("releaf/errors#page_not_found", "path" => "nodes/1")
|
142
|
+
expect(get: "/admin/other_nodes/1").to route_to("releaf/errors#page_not_found", "path" => "other_nodes/1")
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
@@ -42,14 +42,14 @@ describe Node do
|
|
42
42
|
context 'when #content_type is nil' do
|
43
43
|
it 'returns nil' do
|
44
44
|
subject.content_type = nil
|
45
|
-
expect( subject.content_class ).to
|
45
|
+
expect( subject.content_class ).to be nil
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
context "when #content_type is blank string" do
|
50
50
|
it 'returns nil' do
|
51
51
|
subject.content_type = ""
|
52
|
-
expect( subject.content_class ).to
|
52
|
+
expect( subject.content_class ).to be nil
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -121,8 +121,15 @@ describe Node do
|
|
121
121
|
|
122
122
|
describe "#attributes_to_not_copy" do
|
123
123
|
it "returns array with attributes" do
|
124
|
+
subject.locale = "lv"
|
124
125
|
expect( subject.attributes_to_not_copy ).to match_array %w[content_id depth id item_position lft rgt slug created_at updated_at]
|
125
126
|
end
|
127
|
+
|
128
|
+
context "when locale is blank" do
|
129
|
+
it "includes locale within returned list" do
|
130
|
+
expect( subject.attributes_to_not_copy ).to match_array %w[content_id depth id item_position lft rgt slug created_at updated_at locale]
|
131
|
+
end
|
132
|
+
end
|
126
133
|
end
|
127
134
|
|
128
135
|
describe "#attributes_to_copy" do
|
@@ -142,76 +149,7 @@ describe Node do
|
|
142
149
|
end
|
143
150
|
end
|
144
151
|
|
145
|
-
describe "#
|
146
|
-
let(:node1) { create(:node) }
|
147
|
-
|
148
|
-
it "saves node nuder node with given node_id" do
|
149
|
-
node2 = create(:text_page_node, parent: node1)
|
150
|
-
|
151
|
-
new_node = FactoryGirl.build(:text_page_node)
|
152
|
-
new_node.send(:save_under, node2.id)
|
153
|
-
expect( new_node ).to_not be_new_record
|
154
|
-
expect( new_node.parent ).to eq node2
|
155
|
-
end
|
156
|
-
|
157
|
-
it "maintains node name, updates slug and then saves record" do
|
158
|
-
new_node = FactoryGirl.build(:text_page_node)
|
159
|
-
expect( new_node ).to receive(:maintain_name).ordered.and_call_original
|
160
|
-
expect( new_node ).to receive(:reasign_slug).ordered.and_call_original
|
161
|
-
expect( new_node ).to receive(:save!).ordered.and_call_original
|
162
|
-
new_node.save_under(node1.id)
|
163
|
-
end
|
164
|
-
|
165
|
-
context "when #validate_root_locale_uniqueness? returns true" do
|
166
|
-
it "sets locale to nil" do
|
167
|
-
new_node = FactoryGirl.build(:node)
|
168
|
-
allow(new_node).to receive(:validate_root_locale_uniqueness?).and_return(true)
|
169
|
-
new_node.locale = 'xx'
|
170
|
-
expect { new_node.save_under(nil) }.to change { new_node.locale }.from('xx').to(nil)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
context "when #validate_root_locale_uniqueness? returns false" do
|
175
|
-
it "doesn't set locale to nil" do
|
176
|
-
new_node = FactoryGirl.build(:node)
|
177
|
-
allow(new_node).to receive(:validate_root_locale_uniqueness?).and_return(false)
|
178
|
-
new_node.locale = 'xx'
|
179
|
-
expect { new_node.save_under(nil) }.to_not change { new_node.locale }.from('xx')
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
end
|
184
|
-
|
185
|
-
|
186
|
-
describe "#duplicate_content" do
|
187
|
-
|
188
|
-
context "when #content_id is blank" do
|
189
|
-
let(:node) { create(:node) }
|
190
|
-
|
191
|
-
it "returns nil" do
|
192
|
-
expect( node.duplicate_content ).to be_nil
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
context "when #content_id is not blank" do
|
197
|
-
let(:node) { create(:home_page_node) }
|
198
|
-
|
199
|
-
it "returns saved duplicated content" do
|
200
|
-
content = double('new content')
|
201
|
-
expect( content ).to receive(:save!)
|
202
|
-
expect( node ).to receive_message_chain(:content, :dup).and_return(content)
|
203
|
-
expect( node.duplicate_content ).to eq content
|
204
|
-
end
|
205
|
-
|
206
|
-
it "doesn't return same as original content" do
|
207
|
-
result = node.duplicate_content
|
208
|
-
expect( result ).to be_an_instance_of HomePage
|
209
|
-
expect( result.id ).to_not eq node.content_id
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
describe "#copy_attributes_from" do
|
152
|
+
describe "#assign_attributes_from" do
|
215
153
|
let(:source_node) { create(:node, active: false) }
|
216
154
|
|
217
155
|
it "copies #attributes_to_copy attributes" do
|
@@ -225,181 +163,11 @@ describe Node do
|
|
225
163
|
|
226
164
|
new_node = Node.new
|
227
165
|
|
228
|
-
new_node.
|
229
|
-
|
230
|
-
expect( new_node.parent_id ).to be_nil
|
231
|
-
expect( new_node.content_type ).to be_nil
|
232
|
-
expect( new_node.active ).to be_truthy
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
describe "#duplicate_under!" do
|
237
|
-
let!(:source_node) { create(:node, locale: "lv") }
|
238
|
-
let!(:target_node) { create(:node, locale: "en") }
|
239
|
-
|
240
|
-
before do
|
241
|
-
allow_any_instance_of(Releaf::Content::Node::RootValidator).to receive(:validate)
|
242
|
-
end
|
243
|
-
|
244
|
-
it "creates duplicated node under target node" do
|
245
|
-
new_node = Node.new
|
246
|
-
duplicated_content = double('content', id: 1234)
|
247
|
-
expect( Node ).to receive(:new).ordered.and_return(new_node)
|
248
|
-
expect( new_node ).to receive(:copy_attributes_from).with(source_node).ordered.and_call_original
|
249
|
-
expect( source_node ).to receive(:duplicate_content).ordered.and_return(duplicated_content)
|
250
|
-
expect( new_node ).to receive(:content_id=).with(1234).ordered
|
251
|
-
expect( new_node ).to receive(:save_under).with(target_node.id).ordered.and_call_original
|
252
|
-
source_node.duplicate_under!(target_node.id)
|
253
|
-
end
|
166
|
+
new_node.assign_attributes_from source_node
|
254
167
|
|
255
|
-
|
256
|
-
expect(
|
257
|
-
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
describe "#copy", create_nodes: true do
|
262
|
-
before create_nodes: true do
|
263
|
-
@home_page_node = create(:home_page_node, locale: "lv")
|
264
|
-
@home_page_node_2 = create(:home_page_node, locale: "en")
|
265
|
-
@text_page_node_3 = create(:text_page_node, parent_id: @home_page_node_2.id)
|
266
|
-
@text_page_node_4 = create(:text_page_node, parent_id: @text_page_node_3.id)
|
267
|
-
@text_page_node_5 = create(:text_page_node, parent_id: @text_page_node_4.id)
|
268
|
-
|
269
|
-
# it is important to reload nodes, otherwise associations will return empty set
|
270
|
-
@home_page_node.reload
|
271
|
-
@home_page_node_2.reload
|
272
|
-
@text_page_node_3.reload
|
273
|
-
@text_page_node_4.reload
|
274
|
-
end
|
275
|
-
|
276
|
-
context "when one of children becomes invalid" do
|
277
|
-
before do
|
278
|
-
@text_page_node_4.name = nil
|
279
|
-
@text_page_node_4.save(validate: false)
|
280
|
-
end
|
281
|
-
|
282
|
-
it "raises ActiveRecord::RecordInvalid" do
|
283
|
-
expect { @text_page_node_3.copy(@home_page_node.id) }.to raise_error ActiveRecord::RecordInvalid
|
284
|
-
end
|
285
|
-
|
286
|
-
it "raises error on node being copied" do
|
287
|
-
begin
|
288
|
-
@text_page_node_3.copy(@home_page_node.id)
|
289
|
-
rescue ActiveRecord::RecordInvalid => e
|
290
|
-
expect( e.record ).to eq @text_page_node_3
|
291
|
-
end
|
292
|
-
expect(@text_page_node_3.errors.messages).to eq(base: ["descendant invalid"])
|
293
|
-
end
|
294
|
-
|
295
|
-
it "doesn't create any new nodes" do
|
296
|
-
expect do
|
297
|
-
begin
|
298
|
-
@text_page_node_3.copy(@home_page_node.id)
|
299
|
-
rescue ActiveRecord::RecordInvalid
|
300
|
-
end
|
301
|
-
end.to_not change { Node.count }
|
302
|
-
end
|
303
|
-
|
304
|
-
it "doesn't update settings timestamp" do
|
305
|
-
expect( Node ).to_not receive(:updated)
|
306
|
-
begin
|
307
|
-
@text_page_node_3.copy(@home_page_node.id)
|
308
|
-
rescue ActiveRecord::RecordInvalid
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
end
|
313
|
-
|
314
|
-
|
315
|
-
context "with corect parent_id" do
|
316
|
-
it "creates node along with descendant nodes" do
|
317
|
-
expect{ @text_page_node_3.copy(@home_page_node.id) }.to change{ Node.count }.by( @text_page_node_3.descendants.size + 1 )
|
318
|
-
end
|
319
|
-
|
320
|
-
it "correctly copies attributes" do
|
321
|
-
allow( @text_page_node_3 ).to receive(:children).and_return([@text_page_node_4])
|
322
|
-
allow( @text_page_node_4 ).to receive(:children).and_return([@text_page_node_5])
|
323
|
-
|
324
|
-
@text_page_node_3.update_attribute(:active, false)
|
325
|
-
@text_page_node_4.update_attribute(:active, false)
|
326
|
-
|
327
|
-
allow( @text_page_node_3 ).to receive(:attributes_to_copy).and_return(["name", "parent_id", "content_type"])
|
328
|
-
|
329
|
-
expect( @text_page_node_3 ).to receive(:duplicate_under!).and_call_original.ordered
|
330
|
-
expect( @text_page_node_4 ).to receive(:duplicate_under!).and_call_original.ordered
|
331
|
-
expect( @text_page_node_5 ).to receive(:duplicate_under!).and_call_original.ordered
|
332
|
-
|
333
|
-
@text_page_node_3.copy(@home_page_node.id)
|
334
|
-
|
335
|
-
@node_2_copy = @home_page_node.children.first
|
336
|
-
@node_3_copy = @node_2_copy.children.first
|
337
|
-
@node_4_copy = @node_3_copy.children.first
|
338
|
-
|
339
|
-
# new nodes by default are active, however we stubbed
|
340
|
-
# #attributes_to_copy of @test_node_2 to not return active attribute
|
341
|
-
# Also we updated @test_node_2#active to be false.
|
342
|
-
# However copy is active, because active attribute wasn't copied
|
343
|
-
expect( @node_2_copy ).to be_active
|
344
|
-
# for copy of @text_page_node_3 active attribute was copied however, as it
|
345
|
-
# should have been
|
346
|
-
expect( @node_3_copy ).to_not be_active
|
347
|
-
expect( @node_4_copy ).to be_active
|
348
|
-
|
349
|
-
expect( @node_2_copy.name ).to eq @text_page_node_3.name
|
350
|
-
expect( @node_3_copy.name ).to eq @text_page_node_4.name
|
351
|
-
expect( @node_4_copy.name ).to eq @text_page_node_5.name
|
352
|
-
end
|
353
|
-
|
354
|
-
it "updates settings timestamp only once" do
|
355
|
-
expect( Node ).to receive(:updated).once.and_call_original
|
356
|
-
@text_page_node_3.copy(@home_page_node.id)
|
357
|
-
end
|
358
|
-
|
359
|
-
context "when parent_id is nil" do
|
360
|
-
it "creates new node" do
|
361
|
-
allow_any_instance_of(Releaf::Content::Node::RootValidator).to receive(:validate)
|
362
|
-
expect{ @text_page_node_3.copy(nil) }.to change{ Node.count }.by(3)
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
context "when copying root nodes", create_nodes: false do
|
367
|
-
context "when root locale uniqueness is validated" do
|
368
|
-
it "resets locale to nil" do
|
369
|
-
@text_page_node = create(:home_page_node, locale: 'en')
|
370
|
-
allow_any_instance_of(Node).to receive(:validate_root_locale_uniqueness?).and_return(true)
|
371
|
-
@text_page_node.copy(nil)
|
372
|
-
expect( Node.last.locale ).to eq nil
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
|
-
context "when root locale uniqueness is not validated" do
|
377
|
-
it "doesn't reset locale to nil" do
|
378
|
-
@text_page_node = create(:home_page_node, locale: 'en')
|
379
|
-
allow_any_instance_of(Node).to receive(:validate_root_locale_uniqueness?).and_return(false)
|
380
|
-
@text_page_node.copy(nil)
|
381
|
-
expect( Node.last.locale ).to eq 'en'
|
382
|
-
end
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
context "with nonexistent parent_id" do
|
388
|
-
it "raises ActiveRecord::RecordInvalid" do
|
389
|
-
expect { @text_page_node_3.copy(99991) }.to raise_error(ActiveRecord::RecordInvalid)
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
context "with same parent_id as node.id" do
|
394
|
-
it "raises ActiveRecord::RecordInvalid" do
|
395
|
-
expect{ @text_page_node_3.copy(@text_page_node_3.id) }.to raise_error(ActiveRecord::RecordInvalid)
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
|
-
context "when copying to child node" do
|
400
|
-
it "raises ActiveRecord::RecordInvalid" do
|
401
|
-
expect{ @text_page_node_3.copy(@text_page_node_4.id) }.to raise_error(ActiveRecord::RecordInvalid)
|
402
|
-
end
|
168
|
+
expect( new_node.parent_id ).to be nil
|
169
|
+
expect( new_node.content_type ).to be nil
|
170
|
+
expect( new_node.active ).to be true
|
403
171
|
end
|
404
172
|
end
|
405
173
|
|
@@ -437,66 +205,10 @@ describe Node do
|
|
437
205
|
end
|
438
206
|
|
439
207
|
describe "#move" do
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
@text_page_node_3 = create(:text_page_node, parent_id: @home_page_node_2.id)
|
444
|
-
@text_page_node_4 = create(:text_page_node, parent_id: @text_page_node_3.id)
|
445
|
-
|
446
|
-
# it is important to reload nodes, otherwise associations will return empty set
|
447
|
-
@home_page_node.reload
|
448
|
-
@home_page_node_2.reload
|
449
|
-
@text_page_node_3.reload
|
450
|
-
@text_page_node_4.reload
|
208
|
+
it "calls Node move service" do
|
209
|
+
expect(Releaf::Content::Node::Move).to receive(:call).with(node: subject, parent_id: 12)
|
210
|
+
subject.move(12)
|
451
211
|
end
|
452
|
-
|
453
|
-
context "when one of children becomes invalid" do
|
454
|
-
before do
|
455
|
-
@text_page_node_4.name = nil
|
456
|
-
@text_page_node_4.save(validate: false)
|
457
|
-
end
|
458
|
-
|
459
|
-
it "raises ActiveRecord::RecordInvalid" do
|
460
|
-
expect { @text_page_node_3.move(@home_page_node.id) }.to raise_error ActiveRecord::RecordInvalid
|
461
|
-
end
|
462
|
-
|
463
|
-
it "raises error on node being moved, even tought descendant has error" do
|
464
|
-
begin
|
465
|
-
@text_page_node_3.move(@home_page_node.id)
|
466
|
-
rescue ActiveRecord::RecordInvalid => e
|
467
|
-
expect( e.record ).to eq @text_page_node_3
|
468
|
-
end
|
469
|
-
|
470
|
-
expect(@text_page_node_3.errors.messages).to eq(name: [], base: ["descendant invalid"])
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
|
-
context "when moving existing node to other nodes child's position" do
|
475
|
-
it "changes parent_id" do
|
476
|
-
expect{ @text_page_node_3.move(@home_page_node.id) }.to change{ Node.find(@text_page_node_3.id).parent_id }.from(@home_page_node_2.id).to(@home_page_node.id)
|
477
|
-
end
|
478
|
-
end
|
479
|
-
|
480
|
-
context "when moving to self child's position" do
|
481
|
-
it "raises ActiveRecord::RecordInvalid" do
|
482
|
-
expect{ @text_page_node_3.move(@text_page_node_3.id) }.to raise_error(ActiveRecord::RecordInvalid)
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
context "when passing nil as target node" do
|
487
|
-
it "updates parent_id" do
|
488
|
-
allow_any_instance_of(Releaf::Content::Node::RootValidator).to receive(:validate)
|
489
|
-
@home_page_node.destroy
|
490
|
-
expect{ @text_page_node_3.move(nil) }.to change { Node.find(@text_page_node_3.id).parent_id }.to(nil)
|
491
|
-
end
|
492
|
-
end
|
493
|
-
|
494
|
-
context "when passing nonexistent target node's id" do
|
495
|
-
it "raises ActiveRecord::RecordInvalid" do
|
496
|
-
expect{ @text_page_node_3.move(998123) }.to raise_error(ActiveRecord::RecordInvalid)
|
497
|
-
end
|
498
|
-
end
|
499
|
-
|
500
212
|
end
|
501
213
|
|
502
214
|
describe "#maintain_name" do
|
@@ -719,20 +431,6 @@ describe Node do
|
|
719
431
|
end
|
720
432
|
end
|
721
433
|
|
722
|
-
describe "#add_error_and_raise" do
|
723
|
-
it "raises error" do
|
724
|
-
expect { subject.add_error_and_raise('test error') }.to raise_error(ActiveRecord::RecordInvalid)
|
725
|
-
end
|
726
|
-
|
727
|
-
it "adds record on base and raise ActiveRecord::RecordInvalid" do
|
728
|
-
begin
|
729
|
-
subject.add_error_and_raise('test error')
|
730
|
-
rescue ActiveRecord::RecordInvalid => e
|
731
|
-
expect( e.record.errors[:base] ).to include 'test error'
|
732
|
-
end
|
733
|
-
end
|
734
|
-
end
|
735
|
-
|
736
434
|
describe "#prevent_auto_update_settings_timestamp" do
|
737
435
|
it "sets #prevent_auto_update_settings_timestamp? to true within block" do
|
738
436
|
expect do
|
@@ -769,11 +467,55 @@ describe Node do
|
|
769
467
|
end
|
770
468
|
|
771
469
|
describe "#path" do
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
470
|
+
before do
|
471
|
+
allow(subject).to receive(:path_parts).and_return(["some", "bar", "foo"])
|
472
|
+
end
|
473
|
+
|
474
|
+
it "returns relative node path built ny joining node path parts" do
|
475
|
+
expect(subject.path).to eq("/some/bar/foo")
|
476
|
+
end
|
477
|
+
|
478
|
+
context "when node has parent" do
|
479
|
+
it "ads trailing slash to returned node path" do
|
480
|
+
allow(subject).to receive(:trailing_slash_for_path?).and_return(true)
|
481
|
+
expect(subject.path).to eq("/some/bar/foo/")
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
|
487
|
+
describe "#trailing_slash_for_path?" do
|
488
|
+
context "when rails route has trailing slash enabled" do
|
489
|
+
it "returns true" do
|
490
|
+
allow(Rails.application.routes).to receive(:default_url_options).and_return(trailing_slash: true)
|
491
|
+
expect(subject.trailing_slash_for_path?).to be true
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
context "when rails route has trailing slash disabled" do
|
496
|
+
it "returns false" do
|
497
|
+
allow(Rails.application.routes).to receive(:default_url_options).and_return({})
|
498
|
+
expect(subject.trailing_slash_for_path?).to be false
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
describe "#path_parts" do
|
504
|
+
it "returns array with slug" do
|
505
|
+
expect(subject.path_parts).to eq([""])
|
506
|
+
subject.slug = "foo"
|
507
|
+
expect(subject.path_parts).to eq(["foo"])
|
508
|
+
end
|
509
|
+
|
510
|
+
context "when node has parent" do
|
511
|
+
it "prepends parent path parts to returned array" do
|
512
|
+
parent = described_class.new
|
513
|
+
allow(parent).to receive(:path_parts).and_return(%w(some bar))
|
514
|
+
|
515
|
+
subject.slug = "foo"
|
516
|
+
subject.parent = parent
|
517
|
+
expect(subject.path_parts).to eq(["some", "bar", "foo"])
|
518
|
+
end
|
777
519
|
end
|
778
520
|
end
|
779
521
|
end
|