quby 4.0.3 → 5.0.0.pre1
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/lib/quby/questionnaires.rb +1 -0
- data/lib/quby/questionnaires/api.rb +5 -1
- data/lib/quby/questionnaires/deserializer.rb +433 -0
- data/lib/quby/questionnaires/dsl.rb +10 -15
- data/lib/quby/questionnaires/entities.rb +1 -0
- data/lib/quby/questionnaires/entities/charting/line_chart.rb +23 -0
- data/lib/quby/questionnaires/entities/charting/overview_chart.rb +3 -1
- data/lib/quby/questionnaires/entities/definition.rb +3 -5
- data/lib/quby/questionnaires/entities/fields.rb +0 -15
- data/lib/quby/questionnaires/entities/question.rb +9 -32
- data/lib/quby/questionnaires/entities/questionnaire.rb +4 -15
- data/lib/quby/questionnaires/entities/questions/checkbox_question.rb +0 -24
- data/lib/quby/questionnaires/entities/questions/date_question.rb +0 -8
- data/lib/quby/questionnaires/entities/score_calculation.rb +36 -3
- data/lib/quby/questionnaires/repos.rb +1 -0
- data/lib/quby/questionnaires/repos/bundle_disk_repo.rb +51 -0
- data/lib/quby/version.rb +1 -1
- data/spec/internal/log/test-events.log +166 -0
- data/spec/internal/log/test.log +6170 -0
- data/spec/internal/tmp/capybara/screenshot_2020-10-27-14-25-21.063.html +207 -0
- data/spec/internal/tmp/capybara/screenshot_2020-10-27-14-25-21.063.png +0 -0
- data/spec/quby/answers/services/answer_validations_spec.rb +8 -8
- data/spec/quby/questionnaires/deserializer/questionnaire_spec.rb +237 -0
- data/spec/quby/questionnaires/dsl_spec.rb +0 -9
- data/spec/quby/questionnaires/entities/fields_spec.rb +3 -3
- data/spec/quby/questionnaires/entities/question_spec.rb +0 -8
- data/spec/quby/questionnaires/entities/questionnaire_spec.rb +2 -26
- data/spec/quby/table_backend/range_tree_spec.rb +7 -0
- data/spec/spec_helper.rb +1 -0
- metadata +25 -46
- data/lib/quby/questionnaires/dsl/base.rb +0 -20
- data/lib/quby/questionnaires/dsl/calls_custom_methods.rb +0 -29
- data/lib/quby/questionnaires/dsl/charting/bar_chart_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/charting/chart_builder.rb +0 -91
- data/lib/quby/questionnaires/dsl/charting/line_chart_builder.rb +0 -57
- data/lib/quby/questionnaires/dsl/charting/overview_chart_builder.rb +0 -31
- data/lib/quby/questionnaires/dsl/charting/radar_chart_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/helpers.rb +0 -51
- data/lib/quby/questionnaires/dsl/panel_builder.rb +0 -80
- data/lib/quby/questionnaires/dsl/question_builder.rb +0 -40
- data/lib/quby/questionnaires/dsl/questionnaire_builder.rb +0 -252
- data/lib/quby/questionnaires/dsl/questions/base.rb +0 -179
- data/lib/quby/questionnaires/dsl/questions/checkbox_question_builder.rb +0 -20
- data/lib/quby/questionnaires/dsl/questions/date_question_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/questions/deprecated_question_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/questions/float_question_builder.rb +0 -21
- data/lib/quby/questionnaires/dsl/questions/integer_question_builder.rb +0 -21
- data/lib/quby/questionnaires/dsl/questions/radio_question_builder.rb +0 -20
- data/lib/quby/questionnaires/dsl/questions/select_question_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/questions/string_question_builder.rb +0 -20
- data/lib/quby/questionnaires/dsl/questions/text_question_builder.rb +0 -22
- data/lib/quby/questionnaires/dsl/score_builder.rb +0 -22
- data/lib/quby/questionnaires/dsl/standardized_panel_generators.rb +0 -33
- data/lib/quby/questionnaires/dsl/table_builder.rb +0 -48
- data/lib/quby/questionnaires/services/definition_validator.rb +0 -298
- data/spec/quby/questionnaires/dsl/calls_custom_methods_spec.rb +0 -38
- data/spec/quby/questionnaires/dsl/charting/bar_chart_builder_spec.rb +0 -41
- data/spec/quby/questionnaires/dsl/charting/chart_builder_spec.rb +0 -127
- data/spec/quby/questionnaires/dsl/charting/line_chart_builder_spec.rb +0 -66
- data/spec/quby/questionnaires/dsl/charting/radar_chart_builder_spec.rb +0 -41
- data/spec/quby/questionnaires/dsl/helpers_spec.rb +0 -80
- data/spec/quby/questionnaires/dsl/questionnaire_builder_spec.rb +0 -480
- data/spec/quby/questionnaires/services/definition_validator_spec.rb +0 -793
- data/spec/support/examples_for_chart_builders.rb +0 -59
@@ -1,66 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
module Quby::Questionnaires::DSL
|
6
|
-
describe LineChartBuilder do
|
7
|
-
it_behaves_like ChartBuilder
|
8
|
-
|
9
|
-
let(:questionnaire) { double(key: 'questionnaire_key') }
|
10
|
-
|
11
|
-
it 'sets y-axis label' do
|
12
|
-
expect(dsl { y_axis_label 'Label' }.y_label).to eq 'Label'
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'sets y-axis range' do
|
16
|
-
expect(dsl { range 0..40 }.y_range).to eq (0..40)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'sets y-axis tick interval' do
|
20
|
-
expect(dsl { tick_interval 1 }.tick_interval).to eq 1
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'raises when y-axis range is not specified' do
|
24
|
-
expect { dsl(:test, {}) { } }.to raise_error(/no range specified/)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'sets tonality' do
|
28
|
-
expect(dsl { tonality :higher_is_better }.tonality).to eq :higher_is_better
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'sets baseline to constant value' do
|
32
|
-
expect(dsl { baseline 5 }.baseline.call(1, :male)).to eq 5.0
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'sets baseline by hash', :aggregate_failures do
|
36
|
-
chart = dsl { baseline({(0..1000) => {female: 5, default: 3}, default: {female: 1, default: 2}}) }
|
37
|
-
expect(chart.baseline.call(1, :female)).to eq(5)
|
38
|
-
expect(chart.baseline.call(1, :two_spirit)).to eq(3)
|
39
|
-
expect(chart.baseline.call(5000, nil)).to eq(2)
|
40
|
-
expect(chart.baseline.call(nil, :female)).to eq(1)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'sets baseline to proc' do
|
44
|
-
expect(dsl { baseline { |age, gender| age } }.baseline.call(5, :male)).to eq(5.0)
|
45
|
-
expect { dsl { baseline { |age| age } } }.to raise_error(ArgumentError, /must take two arguments/)
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'raises error if not giving baseline value or block' do
|
49
|
-
expect { dsl { baseline } }.to raise_error(ArgumentError, /either value or a block/)
|
50
|
-
expect { dsl { baseline(5.0) { |age, gender| age } } }.to raise_error(ArgumentError, /either value or a block/)
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'sets clinically relevant change' do
|
54
|
-
expect(dsl { clinically_relevant_change 5 }.clinically_relevant_change).to eq 5.0
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'makes a line chart' do
|
58
|
-
expect(dsl { }).to be_an_instance_of(::Quby::Questionnaires::Entities::Charting::LineChart)
|
59
|
-
end
|
60
|
-
|
61
|
-
def dsl(key = :test, options = {y_range: (0..20)}, &block)
|
62
|
-
builder = LineChartBuilder.new(questionnaire, key, options)
|
63
|
-
builder.build(&block)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
module Quby::Questionnaires::DSL
|
6
|
-
describe RadarChartBuilder do
|
7
|
-
it_behaves_like ChartBuilder
|
8
|
-
|
9
|
-
let(:questionnaire) { double(key: 'questionnaire_key') }
|
10
|
-
|
11
|
-
it 'makes a radar chart' do
|
12
|
-
expect(dsl { }).to be_an_instance_of(::Quby::Questionnaires::Entities::Charting::RadarChart)
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'sets y-axis range' do
|
16
|
-
expect(dsl { range 0..40 }.y_range).to eq (0..40)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'sets y-axis tick interval' do
|
20
|
-
expect(dsl { tick_interval 1 }.tick_interval).to eq 1
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'sets plotlines' do
|
24
|
-
plotlines =
|
25
|
-
dsl {
|
26
|
-
plotline 40, :orange
|
27
|
-
plotline 60, :red
|
28
|
-
}.plotlines
|
29
|
-
|
30
|
-
expect(plotlines).to eq [
|
31
|
-
{value: 40, color: :orange, width: 1, zIndex: 3},
|
32
|
-
{value: 60, color: :red, width: 1, zIndex: 3}
|
33
|
-
]
|
34
|
-
end
|
35
|
-
|
36
|
-
def dsl(key = :test, options = {}, &block)
|
37
|
-
builder = RadarChartBuilder.new(questionnaire, key, options)
|
38
|
-
builder.build(&block)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
module Quby::Questionnaires::DSL
|
6
|
-
describe Helpers do
|
7
|
-
let(:questionnaire) { Quby::Questionnaires::Entities::Questionnaire.new("example") }
|
8
|
-
let(:builder) { QuestionnaireBuilder.new(questionnaire) }
|
9
|
-
|
10
|
-
# this helper has some extra tests to check that helpers are included everywhere
|
11
|
-
describe '.image_tag' do
|
12
|
-
let(:expected_html) { %r{<p><img alt=\"Happy face\" src=\"/assets/quby/happy-face.*.png\" /></p>} }
|
13
|
-
|
14
|
-
it 'builds image tags outside of panels' do
|
15
|
-
dsl { text image_tag('quby/happy-face.png') }
|
16
|
-
expect(questionnaire.panels.first.items.first.text).to match(expected_html)
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'builds image tags inside of panels' do
|
20
|
-
dsl do
|
21
|
-
panel do
|
22
|
-
text image_tag('quby/happy-face.png')
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
expect(questionnaire.panels.first.items.first.text).to match(expected_html)
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'builds image tags inside of questions' do
|
30
|
-
# this one is different because markdown/maruku transforms double quotes into single quotes
|
31
|
-
# and question descriptions are not passed through markdown/maruku
|
32
|
-
expected_html = %r{<img .*?src="/assets/quby/happy-face.*.png"}
|
33
|
-
dsl do
|
34
|
-
panel do
|
35
|
-
question :v_1, type: :radio do
|
36
|
-
option :a1, description: image_tag('quby/happy-face.png')
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
expect(questionnaire.panels.first.items.first.options.first.description).to match(expected_html)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe 'video_tag' do
|
45
|
-
it 'makes a text item with a html 5 video player for the given video source urls' do
|
46
|
-
html = builder.video_tag 'https://www.example.com/video.mp4', 'https://www.example.com/video.webm'
|
47
|
-
|
48
|
-
expect(html).to \
|
49
|
-
eq("<video width=\"100%\" preload=\"none\" controls=\"controls\"><source src=\"https://www.example.com/video.mp4\" type=\"video/mp4\">\
|
50
|
-
<source src=\"https://www.example.com/video.webm\" type=\"video/webm\">\
|
51
|
-
Helaas kan je browser dit filmpje niet afspelen. Probeer een andere browser te gebruiken.</video>")
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'can add a autoplay attribute (with muted added to allow chrome autoplay)' do
|
55
|
-
html = builder.video_tag 'https://www.example.com/video.mp4', autoplay: true
|
56
|
-
|
57
|
-
expect(html).to \
|
58
|
-
include('<video width="100%" preload="none" autoplay="autoplay" muted="muted" controls="controls">')
|
59
|
-
end
|
60
|
-
|
61
|
-
it 'can add a loop attribute' do
|
62
|
-
html = builder.video_tag 'https://www.example.com/video.mp4', loop: true
|
63
|
-
|
64
|
-
expect(html).to \
|
65
|
-
include('<video width="100%" preload="none" loop="loop" controls="controls">')
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'can add a poster url' do
|
69
|
-
html = builder.video_tag 'https://www.example.com/video.mp4', poster: 'https://www.example.com/poster.jpg'
|
70
|
-
|
71
|
-
expect(html).to \
|
72
|
-
include('<video width="100%" preload="none" poster="https://www.example.com/poster.jpg" controls="controls">')
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def dsl(&block)
|
77
|
-
builder.instance_eval(&block)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,480 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
module Quby::Questionnaires::DSL
|
6
|
-
describe QuestionnaireBuilder do
|
7
|
-
let(:questionnaire) { Quby::Questionnaires::Entities::Questionnaire.new("example") }
|
8
|
-
let(:builder) { QuestionnaireBuilder.new(questionnaire) }
|
9
|
-
|
10
|
-
it 'sets title' do
|
11
|
-
dsl { title 'Foo' }
|
12
|
-
expect(questionnaire.title).to eq('Foo')
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'sets description' do
|
16
|
-
dsl { description 'This is a questionnaire description' }
|
17
|
-
expect(questionnaire.description).to eq('This is a questionnaire description')
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'sets outcome_description' do
|
21
|
-
dsl { outcome_description 'Outcome description' }
|
22
|
-
expect(questionnaire.outcome_description).to eq('Outcome description')
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'can disable checking key clashes' do
|
26
|
-
expect(questionnaire.check_key_clashes).to eq(true)
|
27
|
-
dsl { do_not_check_key_clashes }
|
28
|
-
expect(questionnaire.check_key_clashes).to eq(false)
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'set sbg_key' do
|
32
|
-
dsl { sbg_key 'foo' }
|
33
|
-
expect(questionnaire.sbg_key).to eq('foo')
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'can request outcome regeneration' do
|
37
|
-
timestamp = Time.local(2020, 5, 12, 4, 28, 19)
|
38
|
-
dsl { outcome_regeneration_requested_at timestamp }
|
39
|
-
expect(questionnaire.outcome_regeneration_requested_at).to eq(timestamp)
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'can request answers to be deactivated' do
|
43
|
-
timestamp = Time.local(2020, 5, 12, 4, 28, 19)
|
44
|
-
dsl { deactivate_answers_requested_at timestamp }
|
45
|
-
expect(questionnaire.deactivate_answers_requested_at).to eq(timestamp)
|
46
|
-
end
|
47
|
-
|
48
|
-
describe 'roqua keys' do
|
49
|
-
it 'defaults to key' do
|
50
|
-
dsl {}
|
51
|
-
expect(questionnaire.roqua_keys).to eq(["example"])
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'sets roqua keys' do
|
55
|
-
dsl { roqua_keys :alg_o, :alg_o2 }
|
56
|
-
expect(questionnaire.roqua_keys).to eq([:alg_o, :alg_o2])
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
describe 'sbg_domain' do
|
61
|
-
it 'sets sbg_domain' do
|
62
|
-
dsl do
|
63
|
-
sbg_domain '02', from: '2000-01-01', till: '2099-12-31', outcome: '01', sbg_key: 'OQ45-sd', primary: true
|
64
|
-
end
|
65
|
-
expect(questionnaire.sbg_domains).to eq(
|
66
|
-
[
|
67
|
-
{sbg_code: '02', from: '2000-01-01', till: '2099-12-31', outcome: '01', sbg_key: 'OQ45-sd', primary: true}
|
68
|
-
]
|
69
|
-
)
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'sets multiple sbg_domains with optional attributes' do
|
73
|
-
dsl do
|
74
|
-
sbg_domain '02', outcome: '01', sbg_key: 'OQ45-sd', primary: false
|
75
|
-
sbg_domain '03', outcome: '02', from: '2000-01-01', till: '2099-12-31'
|
76
|
-
end
|
77
|
-
expect(questionnaire.sbg_domains).to eq(
|
78
|
-
[
|
79
|
-
{sbg_code: '02', from: nil, till: nil, outcome: '01', sbg_key: 'OQ45-sd', primary: false},
|
80
|
-
{sbg_code: '03', from: '2000-01-01', till: '2099-12-31', outcome: '02', sbg_key: nil, primary: false}
|
81
|
-
]
|
82
|
-
)
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'defaults the sbg_key to the sbg_key of the questionnaire' do
|
86
|
-
dsl do
|
87
|
-
sbg_key 'example'
|
88
|
-
sbg_domain '03', from: '2000-01-01', till: '2099-12-31', outcome: '01'
|
89
|
-
end
|
90
|
-
expect(questionnaire.sbg_domains).to eq(
|
91
|
-
[
|
92
|
-
{sbg_code: '03', from: '2000-01-01', till: '2099-12-31', outcome: '01', sbg_key: 'example', primary: false}
|
93
|
-
]
|
94
|
-
)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'does not accept invalid sbg_domains options' do
|
99
|
-
expect { dsl { sbg_domain '02', foo: 'bar' } }.to raise_exception(ArgumentError, "missing keyword: outcome")
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'can be abortable' do
|
103
|
-
expect(questionnaire.abortable).to be_falsey
|
104
|
-
dsl { abortable }
|
105
|
-
expect(questionnaire.abortable).to be_truthy
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'can allow hotkeys' do
|
109
|
-
dsl { allow_hotkeys }
|
110
|
-
expect(questionnaire.allow_hotkeys).to eq("all")
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'can set license' do
|
114
|
-
dsl { license :free }
|
115
|
-
expect(questionnaire.license).to eq(:free)
|
116
|
-
expect(questionnaire.licensor).to be_nil
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'can set licensor' do
|
120
|
-
dsl { license :free, licensor: 'FOO' }
|
121
|
-
expect(questionnaire.licensor).to eq('FOO')
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'can set language' do
|
125
|
-
dsl { language :en }
|
126
|
-
expect(questionnaire.language).to eq(:en)
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'defaults to Dutch language' do
|
130
|
-
dsl { }
|
131
|
-
expect(questionnaire.language).to eq(:nl)
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'can set respondent_types' do
|
135
|
-
dsl { respondent_types :patient, :parent }
|
136
|
-
expect(questionnaire.respondent_types).to eq([:patient, :parent])
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'can set tags' do
|
140
|
-
dsl { tags :diary }
|
141
|
-
expect(questionnaire.tags.diary).to be_truthy
|
142
|
-
expect(questionnaire.tags.another_tag).to be_falsey
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'builds panels' do
|
146
|
-
dsl { panel { title 'My Title' } }
|
147
|
-
expect(questionnaire.panels.first.title).to eq('My Title')
|
148
|
-
end
|
149
|
-
|
150
|
-
it 'builds line charts' do
|
151
|
-
dsl { line_chart(:tot) { title 'My Title'; range 0..40 } }
|
152
|
-
expect(questionnaire.charts.find(:tot).title).to eq('My Title')
|
153
|
-
end
|
154
|
-
|
155
|
-
it 'builds bar charts' do
|
156
|
-
dsl { bar_chart(:tot) { title 'My Title' } }
|
157
|
-
expect(questionnaire.charts.find(:tot).title).to eq('My Title')
|
158
|
-
end
|
159
|
-
|
160
|
-
it 'builds radar charts' do
|
161
|
-
dsl { radar_chart(:tot) { title 'My Title' } }
|
162
|
-
expect(questionnaire.charts.find(:tot).title).to eq('My Title')
|
163
|
-
end
|
164
|
-
|
165
|
-
it 'checks for duplicate question keys' do
|
166
|
-
expect do
|
167
|
-
dsl do
|
168
|
-
question :v_1, type: :string
|
169
|
-
question :v_1, type: :string
|
170
|
-
end
|
171
|
-
end.to raise_exception(RuntimeError, "example:v_1: A question or option with input key v_1 is already defined.")
|
172
|
-
end
|
173
|
-
|
174
|
-
it 'checks for subquestion clashing with parent question' do
|
175
|
-
skip
|
176
|
-
expect do
|
177
|
-
dsl do
|
178
|
-
question :v_1, type: :radio do
|
179
|
-
option :a1 do
|
180
|
-
question :v_1, type: :string
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end.to raise_exception
|
185
|
-
end
|
186
|
-
|
187
|
-
it 'checks for duplicate option keys' do
|
188
|
-
expect do
|
189
|
-
dsl do
|
190
|
-
question :v_1, type: :radio do
|
191
|
-
option :a1
|
192
|
-
option :a1
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end.to raise_exception(RuntimeError, "example:v_1:a1: A question or option with input key v_1_a1 is already defined.")
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'checks for duplicate option input keys' do
|
199
|
-
expect do
|
200
|
-
dsl do
|
201
|
-
question :v_1_a, type: :radio do
|
202
|
-
option :a1
|
203
|
-
end
|
204
|
-
|
205
|
-
question :v_1, type: :radio do
|
206
|
-
option :a_a1
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end.to raise_exception(RuntimeError, "example:v_1:a_a1: A question or option with input key v_1_a_a1 is already defined.")
|
210
|
-
end
|
211
|
-
|
212
|
-
it 'checks for duplicates in past date input keys' do
|
213
|
-
expect do
|
214
|
-
dsl do
|
215
|
-
question :v_1_a, type: :date do
|
216
|
-
option :a1
|
217
|
-
end
|
218
|
-
|
219
|
-
question :v_1_yyyy, type: :text
|
220
|
-
end
|
221
|
-
end.to raise_exception(NoMethodError, /undefined method `option'/)
|
222
|
-
end
|
223
|
-
|
224
|
-
it 'checks for duplicates when creating date input keys' do
|
225
|
-
expect do
|
226
|
-
dsl do
|
227
|
-
question :v_1_yyyy, type: :text
|
228
|
-
|
229
|
-
question :v_1_a, type: :date do
|
230
|
-
option :a1
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end.to raise_exception(KeyError, "key not found: \"text\"")
|
234
|
-
end
|
235
|
-
|
236
|
-
it 'checks for checkbox option keys clashing with question keys' do
|
237
|
-
expect do
|
238
|
-
dsl do
|
239
|
-
question :v_1, type: :string
|
240
|
-
question :v_2, type: :check_box do
|
241
|
-
option :v_1
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end.to raise_exception(RuntimeError, "example:v_2:v_1: A question or option with input key v_1 is already defined.")
|
245
|
-
end
|
246
|
-
|
247
|
-
it 'checks for checkbox option keys clashing with their own question key' do
|
248
|
-
expect do
|
249
|
-
dsl do
|
250
|
-
question :v_1, type: :check_box do
|
251
|
-
option :v_2
|
252
|
-
option :v_1
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end.to raise_exception(RuntimeError, "example:v_1:v_1: A question or option with input key v_1 is already defined.")
|
256
|
-
end
|
257
|
-
|
258
|
-
it 'checks for checkbox option keys clashing with input keys' do
|
259
|
-
expect do
|
260
|
-
dsl do
|
261
|
-
question :v_1, type: :radio do
|
262
|
-
option :a1
|
263
|
-
end
|
264
|
-
question :v_2, type: :check_box do
|
265
|
-
option :v_1_a1
|
266
|
-
end
|
267
|
-
end
|
268
|
-
end.to raise_exception(RuntimeError, "example:v_2:v_1_a1: A question or option with input key v_1_a1 is already defined.")
|
269
|
-
end
|
270
|
-
|
271
|
-
it 'sets a depends_on key correctly' do
|
272
|
-
dsl do
|
273
|
-
question :v_1, type: :check_box do
|
274
|
-
option :v_1_a
|
275
|
-
end
|
276
|
-
question :v_2, type: :string, depends_on: [:v_1]
|
277
|
-
end
|
278
|
-
questionnaire.callback_after_dsl_enhance_on_questions
|
279
|
-
expect(questionnaire.question_hash[:v_2].depends_on).to eq [:v_1_a]
|
280
|
-
end
|
281
|
-
|
282
|
-
it 'raises when a depends_on key does not exist in the questionnaire' do
|
283
|
-
expect do
|
284
|
-
dsl do
|
285
|
-
question :v_1, type: :string, depends_on: [:unknown]
|
286
|
-
end
|
287
|
-
questionnaire.callback_after_dsl_enhance_on_questions
|
288
|
-
end.to raise_exception(Quby::Questionnaires::Entities::Questionnaire::UnknownInputKey, "Question v_1 depends_on contains an error: Unknown input key unknown")
|
289
|
-
end
|
290
|
-
|
291
|
-
it 'sets the parent option key on subquestions correctly' do
|
292
|
-
dsl do
|
293
|
-
question :v_1, type: :check_box do
|
294
|
-
option :v_1a do
|
295
|
-
question :v_2, type: :string
|
296
|
-
end
|
297
|
-
option :v_1b
|
298
|
-
end
|
299
|
-
end
|
300
|
-
expect(questionnaire.question_hash[:v_2].parent_option_key).to eq(:v_1a)
|
301
|
-
end
|
302
|
-
|
303
|
-
describe 'flag' do
|
304
|
-
before do
|
305
|
-
allow_any_instance_of(Quby::Questionnaires::Entities::Questionnaire).to receive(:add_flag)
|
306
|
-
end
|
307
|
-
|
308
|
-
it 'defines flags' do
|
309
|
-
dsl do
|
310
|
-
flag key: :test, description: 'test flag'
|
311
|
-
end
|
312
|
-
expect(questionnaire).to have_received(:add_flag).with(key: :test, description: 'test flag')
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
describe '#question' do
|
317
|
-
it 'does not overwrite the @default_question_options' do
|
318
|
-
dsl do
|
319
|
-
default_question_options required: false, type: :checkbox
|
320
|
-
question :v_1, type: :string, required: true
|
321
|
-
end
|
322
|
-
expect(builder.default_question_options[:required]).to eq false
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
describe '#do_not_check_score_keys_consistency' do
|
327
|
-
it 'sets check_score_keys_consistency flag to false' do
|
328
|
-
dsl do
|
329
|
-
do_not_check_score_keys_consistency
|
330
|
-
end
|
331
|
-
expect(questionnaire.check_score_keys_consistency).to eq false
|
332
|
-
end
|
333
|
-
it 'flag is true on the questionnaire if not altered' do
|
334
|
-
expect(questionnaire.check_score_keys_consistency).to eq true
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
describe '#custom_method' do
|
339
|
-
context 'valid definition' do
|
340
|
-
before do
|
341
|
-
dsl do
|
342
|
-
custom_method :zzl_question do |question_key, question_title|
|
343
|
-
question question_key, type: :scale do
|
344
|
-
title question_title
|
345
|
-
option :a1, value: 1
|
346
|
-
option :a2, value: 2
|
347
|
-
end
|
348
|
-
end
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
it 'can build a question with options' do
|
353
|
-
dsl do
|
354
|
-
panel do
|
355
|
-
zzl_question :v_1, 'zzl title'
|
356
|
-
end
|
357
|
-
end
|
358
|
-
expect(questionnaire.question_hash[:v_1].title).to eq 'zzl title'
|
359
|
-
expect(questionnaire.question_hash[:v_1].type).to eq :scale
|
360
|
-
expect(questionnaire.question_hash[:v_1].options[0].key).to eq :a1
|
361
|
-
end
|
362
|
-
|
363
|
-
it 'can be used within a table' do
|
364
|
-
dsl do
|
365
|
-
panel do
|
366
|
-
table columns: 4 do
|
367
|
-
zzl_question :v_1, 'zzl title'
|
368
|
-
end
|
369
|
-
end
|
370
|
-
end
|
371
|
-
expect(questionnaire.question_hash[:v_1].title).to eq 'zzl title'
|
372
|
-
expect(questionnaire.question_hash[:v_1].type).to eq :scale
|
373
|
-
expect(questionnaire.question_hash[:v_1].options[0].key).to eq :a1
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
it 'fails when specifying an existing method' do
|
378
|
-
expect do
|
379
|
-
dsl do
|
380
|
-
custom_method :question do |question_key, question_title|
|
381
|
-
question question_key, type: :string, title: question_title
|
382
|
-
end
|
383
|
-
panel do
|
384
|
-
zzl_question :v_1, 'zzl title'
|
385
|
-
end
|
386
|
-
end
|
387
|
-
end.to raise_exception(RuntimeError, "Custom method trying to override existing method")
|
388
|
-
end
|
389
|
-
|
390
|
-
it 'fails when specifying a a method twice' do
|
391
|
-
expect do
|
392
|
-
dsl do
|
393
|
-
custom_method :zzl_question do |question_key, question_title|
|
394
|
-
question question_key, type: :string, title: question_title
|
395
|
-
end
|
396
|
-
custom_method :zzl_question do |question_key, question_title|
|
397
|
-
question question_key, type: :string, title: question_title
|
398
|
-
end
|
399
|
-
panel do
|
400
|
-
zzl_question :v_1, 'zzl title'
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end.to raise_exception(RuntimeError, "Custom method trying to override existing method")
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
describe '#add_lookup_tree' do
|
408
|
-
it 'can add a lookup tree' do
|
409
|
-
dsl do
|
410
|
-
add_lookup_tree :interpretations,
|
411
|
-
levels: ['score', 'interpretation'],
|
412
|
-
tree: {
|
413
|
-
0..24 => 'low',
|
414
|
-
25..50 => 'high'
|
415
|
-
}
|
416
|
-
end
|
417
|
-
|
418
|
-
expect(questionnaire.lookup_tables[:interpretations].lookup(score: 26)).to eq 'high'
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
describe '#score' do
|
423
|
-
it 'requires scores to have a label' do
|
424
|
-
dsl do
|
425
|
-
score :totaal do
|
426
|
-
{value: 100}
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
expect(questionnaire.errors.full_messages).to eq(["Score totaal misses label in score call"])
|
431
|
-
end
|
432
|
-
end
|
433
|
-
|
434
|
-
describe '#score_schema' do
|
435
|
-
let(:subschema_options) { [{key: :value, export_key: :tot, label: 'Score'}] }
|
436
|
-
let(:set_dsl) do
|
437
|
-
options = subschema_options
|
438
|
-
dsl do
|
439
|
-
score :totaal, label: 'totaal' do
|
440
|
-
{value: 100}
|
441
|
-
end
|
442
|
-
|
443
|
-
score_schema :totaal, 'Totaal', options
|
444
|
-
end
|
445
|
-
end
|
446
|
-
|
447
|
-
it 'calls #add_score_schema with the given arguments' do
|
448
|
-
expect(questionnaire).to receive(:add_score_schema).with :totaal, 'Totaal', subschema_options
|
449
|
-
set_dsl
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
describe '#outcome_table' do
|
454
|
-
it 'calls questionnaire.add_outcome_table with the given arguments' do
|
455
|
-
expect(questionnaire).to receive(:add_outcome_table).with(score_keys: [:a], subscore_keys: [:b])
|
456
|
-
dsl do
|
457
|
-
outcome_table score_keys: [:a], subscore_keys: [:b]
|
458
|
-
end
|
459
|
-
end
|
460
|
-
end
|
461
|
-
|
462
|
-
describe '#video' do
|
463
|
-
it 'passes arguments to a video tag call, and puts the result in a text item' do
|
464
|
-
expect_any_instance_of(PanelBuilder).to receive(:video_tag).with('https://example.com/video.mp4', looping: true).and_return 'foo'
|
465
|
-
|
466
|
-
dsl do
|
467
|
-
panel do
|
468
|
-
video 'https://example.com/video.mp4', looping: true
|
469
|
-
end
|
470
|
-
end
|
471
|
-
expect(questionnaire.panels.first.items.first.raw_content).to eq('foo')
|
472
|
-
end
|
473
|
-
|
474
|
-
end
|
475
|
-
|
476
|
-
def dsl(&block)
|
477
|
-
builder.instance_eval(&block)
|
478
|
-
end
|
479
|
-
end
|
480
|
-
end
|