govuk_content_models 6.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/.gitignore +17 -0
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +14 -0
  4. data/CONTRIBUTING.md +22 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +5 -0
  8. data/Rakefile +46 -0
  9. data/app/models/action.rb +60 -0
  10. data/app/models/answer_edition.rb +13 -0
  11. data/app/models/artefact.rb +341 -0
  12. data/app/models/artefact_action.rb +27 -0
  13. data/app/models/artefact_external_link.rb +15 -0
  14. data/app/models/business_support/business_size.rb +14 -0
  15. data/app/models/business_support/business_type.rb +14 -0
  16. data/app/models/business_support/location.rb +14 -0
  17. data/app/models/business_support/purpose.rb +14 -0
  18. data/app/models/business_support/sector.rb +14 -0
  19. data/app/models/business_support/stage.rb +14 -0
  20. data/app/models/business_support/support_type.rb +14 -0
  21. data/app/models/business_support_edition.rb +69 -0
  22. data/app/models/campaign_edition.rb +72 -0
  23. data/app/models/completed_transaction_edition.rb +14 -0
  24. data/app/models/curated_list.rb +32 -0
  25. data/app/models/edition.rb +286 -0
  26. data/app/models/expectant.rb +21 -0
  27. data/app/models/expectation.rb +12 -0
  28. data/app/models/guide_edition.rb +19 -0
  29. data/app/models/help_page_edition.rb +13 -0
  30. data/app/models/licence_edition.rb +35 -0
  31. data/app/models/local_authority.rb +58 -0
  32. data/app/models/local_interaction.rb +20 -0
  33. data/app/models/local_service.rb +49 -0
  34. data/app/models/local_transaction_edition.rb +49 -0
  35. data/app/models/overview_dashboard.rb +25 -0
  36. data/app/models/part.rb +28 -0
  37. data/app/models/parted.rb +32 -0
  38. data/app/models/place_edition.rb +20 -0
  39. data/app/models/programme_edition.rb +26 -0
  40. data/app/models/simple_smart_answer_edition.rb +66 -0
  41. data/app/models/simple_smart_answer_edition/node.rb +40 -0
  42. data/app/models/simple_smart_answer_edition/node/option.rb +31 -0
  43. data/app/models/tag.rb +88 -0
  44. data/app/models/transaction_edition.rb +28 -0
  45. data/app/models/travel_advice_edition.rb +177 -0
  46. data/app/models/user.rb +54 -0
  47. data/app/models/video_edition.rb +24 -0
  48. data/app/models/workflow.rb +217 -0
  49. data/app/models/workflow_actor.rb +141 -0
  50. data/app/traits/attachable.rb +60 -0
  51. data/app/traits/govspeak_smart_quotes_fixer.rb +19 -0
  52. data/app/traits/taggable.rb +113 -0
  53. data/app/validators/safe_html.rb +33 -0
  54. data/app/validators/slug_validator.rb +53 -0
  55. data/config/mongoid.yml +5 -0
  56. data/govuk_content_models.gemspec +42 -0
  57. data/jenkins.sh +7 -0
  58. data/lib/fact_check_address.rb +36 -0
  59. data/lib/govuk_content_models.rb +12 -0
  60. data/lib/govuk_content_models/require_all.rb +14 -0
  61. data/lib/govuk_content_models/test_helpers/factories.rb +213 -0
  62. data/lib/govuk_content_models/test_helpers/local_services.rb +24 -0
  63. data/lib/govuk_content_models/version.rb +4 -0
  64. data/test/fixtures/contactotron_api_response.json +1 -0
  65. data/test/fixtures/uploads/image.jpg +0 -0
  66. data/test/models/artefact_action_test.rb +123 -0
  67. data/test/models/artefact_external_link_test.rb +32 -0
  68. data/test/models/artefact_tag_test.rb +52 -0
  69. data/test/models/artefact_test.rb +583 -0
  70. data/test/models/business_support/business_size_test.rb +25 -0
  71. data/test/models/business_support/business_type_test.rb +25 -0
  72. data/test/models/business_support/location_test.rb +25 -0
  73. data/test/models/business_support/purpose_test.rb +29 -0
  74. data/test/models/business_support/sector_test.rb +25 -0
  75. data/test/models/business_support/stage_test.rb +25 -0
  76. data/test/models/business_support/support_type_test.rb +25 -0
  77. data/test/models/business_support_edition_test.rb +186 -0
  78. data/test/models/campaign_edition_test.rb +90 -0
  79. data/test/models/curated_list_test.rb +32 -0
  80. data/test/models/edition_test.rb +826 -0
  81. data/test/models/fact_check_address_test.rb +36 -0
  82. data/test/models/help_page_edition_test.rb +38 -0
  83. data/test/models/licence_edition_test.rb +104 -0
  84. data/test/models/local_authority_test.rb +113 -0
  85. data/test/models/local_service_test.rb +199 -0
  86. data/test/models/local_transaction_edition_test.rb +78 -0
  87. data/test/models/overview_dashboard_test.rb +47 -0
  88. data/test/models/simple_smart_answer_edition_test.rb +169 -0
  89. data/test/models/simple_smart_answer_node_test.rb +134 -0
  90. data/test/models/simple_smart_answer_option_test.rb +90 -0
  91. data/test/models/tag_test.rb +92 -0
  92. data/test/models/time_zone_test.rb +48 -0
  93. data/test/models/transaction_edition_test.rb +20 -0
  94. data/test/models/travel_advice_edition_test.rb +480 -0
  95. data/test/models/user_test.rb +114 -0
  96. data/test/models/video_edition_test.rb +64 -0
  97. data/test/models/workflow_actor_test.rb +61 -0
  98. data/test/models/workflow_test.rb +307 -0
  99. data/test/test_helper.rb +47 -0
  100. data/test/traits/attachable_test.rb +143 -0
  101. data/test/traits/taggable_test.rb +114 -0
  102. data/test/validators/safe_html_validator_test.rb +86 -0
  103. data/test/validators/slug_validator_test.rb +42 -0
  104. metadata +511 -0
@@ -0,0 +1,78 @@
1
+ require "test_helper"
2
+ require "govuk_content_models/test_helpers/local_services"
3
+
4
+ class LocalTransactionEditionTest < ActiveSupport::TestCase
5
+ include LocalServicesHelper
6
+ def setup
7
+ @artefact = FactoryGirl.create(:artefact)
8
+ end
9
+
10
+ test "should report that an authority provides a service" do
11
+ bins_transaction = LocalTransactionEdition.new(
12
+ lgsl_code: "bins",
13
+ title: "Transaction",
14
+ slug: "slug",
15
+ panopticon_id: @artefact.id
16
+ )
17
+ county_council = make_authority_providing("bins")
18
+ assert bins_transaction.service_provided_by?(county_council.snac)
19
+ end
20
+
21
+ test "should report that an authority does not provide a service" do
22
+ bins_transaction = LocalTransactionEdition.new(
23
+ lgsl_code: "bins",
24
+ title: "Transaction",
25
+ slug: "slug",
26
+ panopticon_id: @artefact.id
27
+ )
28
+ county_council = make_authority_providing("housing-benefit")
29
+ refute bins_transaction.service_provided_by?(county_council.snac)
30
+ end
31
+
32
+ test "should be a transaction search format" do
33
+ bins_transaction = LocalTransactionEdition.new(
34
+ lgsl_code: "bins",
35
+ title: "Transaction",
36
+ slug: "slug",
37
+ panopticon_id: @artefact.id
38
+ )
39
+ assert_equal "transaction", bins_transaction.search_format
40
+ end
41
+
42
+
43
+ test "should validate on save that a LocalService exists for that lgsl_code" do
44
+ s = LocalService.create!(lgsl_code: "bins", providing_tier: %w{county unitary})
45
+
46
+ lt = LocalTransactionEdition.new(lgsl_code: "nonexistent", title: "Foo", slug: "foo", panopticon_id: @artefact.id)
47
+ lt.save
48
+ assert !lt.valid?
49
+
50
+ lt = LocalTransactionEdition.new(lgsl_code: s.lgsl_code, title: "Bar", slug: "bar", panopticon_id: @artefact.id)
51
+ lt.save
52
+ assert lt.valid?
53
+ assert lt.persisted?
54
+ end
55
+
56
+ test "should create a diff between the versions when publishing a new version" do
57
+ make_service(149, %w{county unitary})
58
+ edition_one = LocalTransactionEdition.new(title: "Transaction", slug: "transaction", lgsl_code: "149", panopticon_id: @artefact.id)
59
+ user = User.create name: "Thomas"
60
+
61
+ edition_one.introduction = "Test"
62
+ edition_one.state = :ready
63
+ edition_one.save!
64
+
65
+ user.publish edition_one, comment: "First edition"
66
+
67
+ edition_two = edition_one.build_clone
68
+ edition_two.introduction = "Testing"
69
+ edition_two.state = :ready
70
+ edition_two.save!
71
+
72
+ user.publish edition_two, comment: "Second edition"
73
+
74
+ publish_action = edition_two.actions.where(request_type: "publish").last
75
+
76
+ assert_equal "{\"Test\" >> \"Testing\"}", publish_action.diff
77
+ end
78
+ end
@@ -0,0 +1,47 @@
1
+ require "test_helper"
2
+
3
+ class OverviewDashboardTest < ActiveSupport::TestCase
4
+
5
+ test "Can create and retrieve dashboard overview objects" do
6
+ overview = create_test_overview
7
+
8
+ assert_equal overview.dashboard_type, "Format"
9
+ assert_equal overview.result_group, "Guide"
10
+ check_status_equal overview, row_status
11
+ end
12
+
13
+ private
14
+ def create_test_overview
15
+ overview = OverviewDashboard.create dashboard_type: "Format", result_group: "Guide"
16
+
17
+ row_status.each do |k, v|
18
+ overview[k] = v
19
+ end
20
+
21
+ overview.save
22
+
23
+ found_overviews = OverviewDashboard.where(dashboard_type: "Format")
24
+ assert_equal found_overviews.size, 1
25
+ found_overviews.first
26
+ end
27
+
28
+ def row_status
29
+ {
30
+ lined_up: 1,
31
+ draft: 1,
32
+ ammends_needed: 1,
33
+ in_review: 1,
34
+ ready: 1,
35
+ fact_check_recieved: 1,
36
+ fact_check: 1,
37
+ published: 1,
38
+ archived: 1
39
+ }
40
+ end
41
+
42
+ def check_status_equal(actual_object, expected_hash)
43
+ expected_hash.each do |k, v|
44
+ assert_equal actual_object[k], expected_hash[k]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,169 @@
1
+ require "test_helper"
2
+
3
+ class SimpleSmartAnswerEditionTest < ActiveSupport::TestCase
4
+ setup do
5
+ @artefact = FactoryGirl.create(:artefact)
6
+ end
7
+
8
+ should "be created with valid nodes" do
9
+ edition = FactoryGirl.build(:simple_smart_answer_edition, panopticon_id: @artefact.id)
10
+ edition.body = "This is a simple smart answer."
11
+
12
+ edition.nodes.build(:slug => "question1", :title => "You approach two locked doors. Which do you choose?", :kind => "question", :order => 1)
13
+ edition.nodes.build(:slug => "left", :title => "As you open the door, a lion bursts out and mauls you to death.", :order => 2, :kind => "outcome")
14
+ edition.nodes.build(:slug => "right", :title => "As you open the door, a tiger bursts out and mauls you to death.", :order => 3, :kind => "outcome")
15
+ edition.save!
16
+
17
+ edition = SimpleSmartAnswerEdition.first
18
+
19
+ assert_equal "This is a simple smart answer.", edition.body
20
+ assert_equal 3, edition.nodes.count
21
+ assert_equal ["question1", "left", "right"], edition.nodes.all.map(&:slug)
22
+ end
23
+
24
+ should "copy the body and nodes when cloning an edition" do
25
+ edition = FactoryGirl.create(:simple_smart_answer_edition,
26
+ panopticon_id: @artefact.id,
27
+ body: "This smart answer is somewhat unique and calls for a different kind of introduction",
28
+ state: "published"
29
+ )
30
+ edition.nodes.build(:slug => "question1", :title => "You approach two open doors. Which do you choose?", :kind => "question", :order => 1)
31
+ edition.nodes.build(:slug => "left", :title => "As you wander through the door, it slams shut behind you, as a lion starts pacing towards you...", :order => 2, :kind => "outcome")
32
+ edition.nodes.build(:slug => "right", :title => "As you wander through the door, it slams shut behind you, as a tiger starts pacing towards you...", :order => 3, :kind => "outcome")
33
+ edition.save!
34
+
35
+ cloned_edition = edition.build_clone
36
+ cloned_edition.save!
37
+
38
+ old_edition = SimpleSmartAnswerEdition.find(edition.id)
39
+ assert_equal ["question", "outcome", "outcome"], old_edition.nodes.all.map(&:kind)
40
+ assert_equal ["question1", "left", "right"], old_edition.nodes.all.map(&:slug)
41
+
42
+ new_edition = SimpleSmartAnswerEdition.find(cloned_edition.id)
43
+ assert_equal edition.body, new_edition.body
44
+ assert_equal ["question", "outcome", "outcome"], new_edition.nodes.all.map(&:kind)
45
+ assert_equal ["question1", "left", "right"], new_edition.nodes.all.map(&:slug)
46
+ end
47
+
48
+ should "not copy nodes when new edition is not a smart answer" do
49
+ edition = FactoryGirl.create(:simple_smart_answer_edition,
50
+ panopticon_id: @artefact.id,
51
+ body: "This smart answer is somewhat unique and calls for a different kind of introduction",
52
+ state: "published"
53
+ )
54
+ edition.nodes.build(:slug => "question1", :title => "You approach two open doors. Which do you choose?", :kind => "question", :order => 1)
55
+ edition.save!
56
+
57
+ new_edition = edition.build_clone(AnswerEdition)
58
+
59
+ assert_equal edition.body, new_edition.body
60
+
61
+ assert new_edition.is_a?(AnswerEdition)
62
+ assert ! new_edition.respond_to?(:nodes)
63
+ end
64
+
65
+ should "select the first node as the starting node" do
66
+ edition = FactoryGirl.create(:simple_smart_answer_edition)
67
+ edition.nodes.build(:slug => "question1", :title => "Question 1", :kind => "question", :order => 1)
68
+ edition.nodes.build(:slug => "question2", :title => "Question 2", :kind => "question", :order => 2)
69
+ edition.nodes.build(:slug => "foo", :title => "Outcome 1.", :order => 3, :kind => "outcome")
70
+ edition.nodes.build(:slug => "bar", :title => "Outcome 2", :order => 4, :kind => "outcome")
71
+
72
+ assert_equal "question1", edition.initial_node.slug
73
+ end
74
+
75
+ should "create nodes with nested attributes" do
76
+ edition = FactoryGirl.create(:simple_smart_answer_edition, :nodes_attributes => [
77
+ { slug: "question1", title: "Question 1", kind: "question", order: 1},
78
+ { slug: "foo", title: "Outcome 1", kind: "outcome", order: 2 },
79
+ ])
80
+
81
+ assert_equal 2, edition.nodes.size
82
+ assert_equal ["question1", "foo"], edition.nodes.all.map(&:slug)
83
+ end
84
+
85
+ should "destroy nodes using nested attributes" do
86
+ edition = FactoryGirl.create(:simple_smart_answer_edition)
87
+ edition.nodes.build(:slug => "question1", :title => "Question 1", :kind => "question", :order => 1)
88
+ edition.nodes.build(:slug => "question2", :title => "Question 2", :kind => "question", :order => 1)
89
+ edition.save!
90
+
91
+ assert_equal 2, edition.nodes.size
92
+
93
+ edition.update_attributes({
94
+ :nodes_attributes => {
95
+ "1" => { "id" => edition.nodes.first.id, "_destroy" => "1" }
96
+ }
97
+ })
98
+ edition.reload
99
+
100
+ assert_equal 1, edition.nodes.size
101
+ end
102
+
103
+ context "update_attributes method" do
104
+ setup do
105
+ @edition = FactoryGirl.create(:simple_smart_answer_edition)
106
+ @edition.nodes.build(:slug => "question1", :title => "Question 1", :kind => "question", :order => 1)
107
+ @edition.nodes.build(:slug => "question2", :title => "Question 2", :kind => "question", :order => 1)
108
+ @edition.nodes.first.options.build(
109
+ :label => "Option 1", :next_node => "question2", :order => 1)
110
+ @edition.save!
111
+ end
112
+
113
+ should "update edition and nested node and option attributes" do
114
+ @edition.update_attributes(:title => "Smarter than the average answer",
115
+ :body => "No developers were involved in the changing of this copy",
116
+ :nodes_attributes => {
117
+ "0" => { "id" => @edition.nodes.first.id, "title" => "Question the first", "options_attributes" => {
118
+ "0" => { "id" => @edition.nodes.first.options.first.id, "label" => "Option the first" }
119
+ }
120
+ }
121
+ })
122
+
123
+ @edition.reload
124
+
125
+ assert_equal "Smarter than the average answer", @edition.title
126
+ assert_equal "No developers were involved in the changing of this copy", @edition.body
127
+ assert_equal "Question the first", @edition.nodes.first.title
128
+ assert_equal "Option the first", @edition.nodes.first.options.first.label
129
+ end
130
+
131
+ should "create and destroy nodes and options using nested attributes" do
132
+ @edition.update_attributes({
133
+ :nodes_attributes => {
134
+ "0" => { "id" => @edition.nodes.first.id, "options_attributes" => {
135
+ "0" => { "id" => @edition.nodes.first.options.first.id, "_destroy" => "1" }
136
+ }
137
+ },
138
+ "1" => { "id" => @edition.nodes.second.id, "_destroy" => "1" },
139
+ "2" => { "kind" => "question", "title" => "Question 3", "slug" => "question3", "options_attributes" => {
140
+ "0" => { "label" => "Goes to outcome 1", "next_node" => "outcome1" }
141
+ } },
142
+ "3" => { "kind" => "outcome", "title" => "Outcome 1", "slug" => "outcome1" }
143
+ }
144
+ })
145
+
146
+ @edition.reload
147
+
148
+ assert_equal 3, @edition.nodes.size
149
+ assert_equal 0, @edition.nodes.first.options.size
150
+ assert_equal "Question 3", @edition.nodes.second.title
151
+ assert_equal 1, @edition.nodes.second.options.size
152
+ assert_equal "outcome1", @edition.nodes.second.options.first.next_node
153
+ assert_equal "Outcome 1", @edition.nodes.third.title
154
+ end
155
+
156
+ should "ignore new nodes if they are to be destroyed" do
157
+ @edition.update_attributes({
158
+ :nodes_attributes => {
159
+ "0" => { "id" => @edition.nodes.first.id, "title" => "Question the first" },
160
+ "1" => { "title" => "", "slug" => "", "kind" => "outcome", "_destroy" => "1" }
161
+ }
162
+ })
163
+ @edition.reload
164
+
165
+ assert_equal "Question the first", @edition.nodes.first.title
166
+ assert_equal 2, @edition.nodes.size
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,134 @@
1
+ require "test_helper"
2
+
3
+ class SimpleSmartAnswerNodeTest < ActiveSupport::TestCase
4
+
5
+ context "given a smart answer exists" do
6
+ setup do
7
+ @edition = FactoryGirl.create(:simple_smart_answer_edition)
8
+
9
+ @atts = {
10
+ title: "How much wood could a woodchuck chuck if a woodchuck could chuck wood?",
11
+ slug: "how-much-wood-could-a-woodchuck-chuck-if-a-woodchuck-could-chuck-wood",
12
+ body: "This is a serious question.",
13
+ kind: "question"
14
+ }
15
+ end
16
+
17
+ should "be able to create a valid node" do
18
+ @node = @edition.nodes.build(@atts)
19
+
20
+ assert @node.save!
21
+
22
+ @edition.reload
23
+
24
+ assert_equal "how-much-wood-could-a-woodchuck-chuck-if-a-woodchuck-could-chuck-wood", @edition.nodes.first.slug
25
+ assert_equal "How much wood could a woodchuck chuck if a woodchuck could chuck wood?", @edition.nodes.first.title
26
+ assert_equal "This is a serious question.", @edition.nodes.first.body
27
+ end
28
+
29
+ should "not be valid without a slug" do
30
+ @node = @edition.nodes.build( @atts.merge(slug: "") )
31
+
32
+ assert ! @node.valid?
33
+ assert_equal [:slug], @node.errors.keys
34
+ end
35
+
36
+ should "not be valid with an invalid slug" do
37
+ @node = @edition.nodes.build(@atts)
38
+
39
+ [
40
+ 'under_score',
41
+ 'space space',
42
+ 'punct.u&ation',
43
+ ].each do |slug|
44
+ @node.slug = slug
45
+ refute @node.valid?
46
+ end
47
+ end
48
+
49
+ should "not be valid without a title" do
50
+ @node = @edition.nodes.build( @atts.merge(title: "") )
51
+
52
+ assert ! @node.valid?
53
+ assert_equal [:title], @node.errors.keys
54
+ end
55
+
56
+ should "not be valid without a kind" do
57
+ @node = @edition.nodes.build(@atts.merge(:kind => nil))
58
+ assert ! @node.valid?
59
+
60
+ assert_equal [:kind], @node.errors.keys
61
+ end
62
+
63
+ should "not be valid with a kind other than 'question' or 'outcome'" do
64
+ @node = @edition.nodes.build(@atts.merge(:kind => 'blah'))
65
+ assert ! @node.valid?
66
+
67
+ assert_equal [:kind], @node.errors.keys
68
+ end
69
+
70
+ should "create options using nested attributes" do
71
+ @node = @edition.nodes.create!(@atts.merge(:options_attributes => [
72
+ { :label => "Yes", :next_node => "yes" },
73
+ { :label => "No", :next_node => "no" }
74
+ ]))
75
+
76
+ @node.reload
77
+ assert_equal 2, @node.options.count
78
+ assert_equal ["Yes", "No"], @node.options.all.map(&:label)
79
+ assert_equal ["yes", "no"], @node.options.all.map(&:next_node)
80
+ end
81
+
82
+ should "destroy options using nested attributes" do
83
+ @node = @edition.nodes.create!(@atts.merge(:options_attributes => [
84
+ { :label => "Yes", :next_node => "yes" },
85
+ { :label => "No", :next_node => "no" }
86
+ ]))
87
+ assert_equal 2, @node.options.count
88
+
89
+ @node.update_attributes!(:options_attributes => {
90
+ "1" => { "id" => @node.options.first.id, "_destroy" => "1" }
91
+ })
92
+ @node.reload
93
+
94
+ assert_equal 1, @node.options.count
95
+ assert_equal ["No"], @node.options.all.map(&:label)
96
+ assert_equal ["no"], @node.options.all.map(&:next_node)
97
+ end
98
+
99
+ should "not be valid if an outcome has options" do
100
+ @node = @edition.nodes.build(@atts.merge(:kind => 'outcome', options_attributes: [
101
+ { :label => "Yes", :next_node => "yes" },
102
+ { :label => "No", :next_node => "no" }
103
+ ]))
104
+ assert ! @node.valid?
105
+
106
+ assert_equal [:options], @node.errors.keys
107
+ end
108
+
109
+ should "be able to create an outcome without options" do
110
+ @node = @edition.nodes.build(@atts.merge(:kind => 'outcome', :options_attributes => [] ))
111
+
112
+ assert @node.valid?
113
+ assert @node.save!
114
+ end
115
+
116
+ should "be returned in order" do
117
+ @nodes = [
118
+ @edition.nodes.create(@atts.merge(:title => "Third", :order => 3)),
119
+ @edition.nodes.create(@atts.merge(:title => "First", :order => 1)),
120
+ @edition.nodes.create(@atts.merge(:title => "Second", :order => 2)),
121
+ ]
122
+
123
+ assert_equal ["First","Second","Third"], @edition.nodes.all.map(&:title)
124
+ end
125
+
126
+ should "expose the simple smart answer edition" do
127
+ @node = @edition.nodes.build(@atts)
128
+
129
+ assert_equal @node.edition, @edition
130
+ end
131
+
132
+ end
133
+
134
+ end
@@ -0,0 +1,90 @@
1
+ require "test_helper"
2
+
3
+ class SimpleSmartAnswerOptionTest < ActiveSupport::TestCase
4
+
5
+ context "given a smart answer exists with a node" do
6
+ setup do
7
+ @node = SimpleSmartAnswerEdition::Node.new(:slug => "question1", :title => "Question One?", :kind => "question")
8
+ @edition = FactoryGirl.create(:simple_smart_answer_edition, :nodes => [
9
+ @node,
10
+ SimpleSmartAnswerEdition::Node.new(:slug => "outcome1", :title => "Outcome One", :kind => "outcome")
11
+ ])
12
+
13
+ @atts = {
14
+ label: "Yes",
15
+ next_node: "yes"
16
+ }
17
+ end
18
+
19
+ should "be able to create a valid option" do
20
+ @option = @node.options.build(@atts)
21
+
22
+ assert @option.save!
23
+ @node.reload
24
+
25
+ assert_equal "Yes", @node.options.first.label
26
+ assert_equal "yes", @node.options.first.next_node
27
+ end
28
+
29
+ should "not be valid without a label" do
30
+ @option = @node.options.build(@atts.merge(label: nil))
31
+
32
+ assert !@option.valid?
33
+ assert @option.errors.keys.include?(:label)
34
+ end
35
+
36
+ should "not be valid without the next node" do
37
+ @option = @node.options.build(@atts.merge(next_node: nil))
38
+
39
+ assert !@option.valid?
40
+ assert @option.errors.keys.include?(:next_node)
41
+ end
42
+
43
+ should "expose the node" do
44
+ @option = @node.options.create(@atts)
45
+ @option.reload
46
+
47
+ assert_equal @node, @option.node
48
+ end
49
+
50
+ should "return in order" do
51
+ @options = [
52
+ @node.options.create(@atts.merge(:label => "Third", :next_node => "baz", :order => 3)),
53
+ @node.options.create(@atts.merge(:label => "First", :next_node => "foo", :order => 1)),
54
+ @node.options.create(@atts.merge(:label => "Second", :next_node => "bar", :order => 2)),
55
+ ]
56
+
57
+ assert_equal ["First","Second","Third"], @node.options.all.map(&:label)
58
+ assert_equal ["foo","bar","baz"], @node.options.all.map(&:next_node)
59
+ end
60
+
61
+ context "slug" do
62
+ should "generate a slug from the label if blank" do
63
+ @option = @node.options.build(@atts)
64
+
65
+ assert @option.valid?
66
+ assert_equal "yes", @option.slug
67
+ end
68
+
69
+ should "not overwrite a given slug" do
70
+ @option = @node.options.build(@atts.merge(:slug => "fooey"))
71
+
72
+ assert @option.valid?
73
+ assert_equal "fooey", @option.slug
74
+ end
75
+
76
+ should "not be valid with an invalid slug" do
77
+ @option = @node.options.build(@atts)
78
+
79
+ [
80
+ 'under_score',
81
+ 'space space',
82
+ 'punct.u&ation',
83
+ ].each do |slug|
84
+ @option.slug = slug
85
+ refute @option.valid?
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end