reports_kits 0.7.5 → 0.7.7

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.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.rubocop.yml +85 -0
  4. data/.travis.yml +21 -0
  5. data/Appraisals +27 -0
  6. data/Gemfile +3 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +35 -0
  9. data/Rakefile +2 -0
  10. data/app/assets/javascripts/reports_kits/application.js +14 -0
  11. data/app/assets/javascripts/reports_kits/lib/_init.js +9 -0
  12. data/app/assets/javascripts/reports_kits/lib/chart.js +73 -0
  13. data/app/assets/javascripts/reports_kits/lib/report.js +135 -0
  14. data/app/assets/javascripts/reports_kits/lib/table.js +87 -0
  15. data/app/assets/javascripts/reports_kits/vendor/chart.js +12269 -0
  16. data/app/assets/javascripts/reports_kits/vendor/daterangepicker.js +1627 -0
  17. data/app/assets/javascripts/reports_kits/vendor/jquery.tablesorter.min.js +4 -0
  18. data/app/assets/javascripts/reports_kits/vendor/moment.js +4040 -0
  19. data/app/assets/javascripts/reports_kits/vendor/select2.full.js +6436 -0
  20. data/app/assets/stylesheets/reports_kits/application.css.scss +3 -0
  21. data/app/assets/stylesheets/reports_kits/reports.css.sass +33 -0
  22. data/app/assets/stylesheets/reports_kits/select2_overrides.css.sass +7 -0
  23. data/app/assets/stylesheets/reports_kits/vendor/daterangepicker.css +269 -0
  24. data/app/assets/stylesheets/reports_kits/vendor/select2-bootstrap.css +721 -0
  25. data/app/assets/stylesheets/reports_kits/vendor/select2.css +484 -0
  26. data/config/initializers/mime_types.rb +1 -0
  27. data/config/routes.rb +10 -0
  28. data/docs/images/demo.gif +0 -0
  29. data/docs/images/users_by_created_at.png +0 -0
  30. data/gemfiles/mysql.gemfile +7 -0
  31. data/gemfiles/mysql.gemfile.lock +167 -0
  32. data/gemfiles/postgresql.gemfile +7 -0
  33. data/gemfiles/postgresql.gemfile.lock +165 -0
  34. data/gemfiles/postgresql_rails_5.1.4.gemfile +8 -0
  35. data/gemfiles/postgresql_rails_5.1.4.gemfile.lock +168 -0
  36. data/gemfiles/rails_4_mysql.gemfile +8 -0
  37. data/gemfiles/rails_4_mysql.gemfile.lock +165 -0
  38. data/gemfiles/rails_4_postgresql.gemfile +8 -0
  39. data/gemfiles/rails_4_postgresql.gemfile.lock +163 -0
  40. data/gemfiles/rails_5.1.4_postgresql.gemfile +8 -0
  41. data/gemfiles/rails_5.1.4_postgresql.gemfile.lock +169 -0
  42. data/gemfiles/rails_5_mysql.gemfile +8 -0
  43. data/gemfiles/rails_5_mysql.gemfile.lock +171 -0
  44. data/gemfiles/rails_5_postgresql.gemfile +8 -0
  45. data/gemfiles/rails_5_postgresql.gemfile.lock +169 -0
  46. data/lib/reports_kits/base_controller.rb +17 -0
  47. data/lib/reports_kits/cache.rb +37 -0
  48. data/lib/reports_kits/configuration.rb +50 -0
  49. data/lib/reports_kits/engine.rb +21 -0
  50. data/lib/reports_kits/entity.rb +3 -0
  51. data/lib/reports_kits/filters_controller.rb +11 -0
  52. data/lib/reports_kits/form_builder.rb +66 -0
  53. data/lib/reports_kits/helper.rb +24 -0
  54. data/lib/reports_kits/model.rb +16 -0
  55. data/lib/reports_kits/model_configuration.rb +28 -0
  56. data/lib/reports_kits/normalized_params.rb +16 -0
  57. data/lib/reports_kits/order.rb +33 -0
  58. data/lib/reports_kits/relative_time.rb +42 -0
  59. data/lib/reports_kits/report_builder.rb +88 -0
  60. data/lib/reports_kits/reports/abstract_series.rb +9 -0
  61. data/lib/reports_kits/reports/adapters/mysql.rb +26 -0
  62. data/lib/reports_kits/reports/adapters/postgresql.rb +26 -0
  63. data/lib/reports_kits/reports/composite_series.rb +48 -0
  64. data/lib/reports_kits/reports/contextual_filter.rb +19 -0
  65. data/lib/reports_kits/reports/data/add_table_aggregations.rb +105 -0
  66. data/lib/reports_kits/reports/data/aggregate_composite.rb +97 -0
  67. data/lib/reports_kits/reports/data/aggregate_one_dimension.rb +39 -0
  68. data/lib/reports_kits/reports/data/aggregate_two_dimensions.rb +39 -0
  69. data/lib/reports_kits/reports/data/chart_data_for_data_method.rb +62 -0
  70. data/lib/reports_kits/reports/data/chart_options.rb +155 -0
  71. data/lib/reports_kits/reports/data/format_one_dimension.rb +140 -0
  72. data/lib/reports_kits/reports/data/format_table.rb +63 -0
  73. data/lib/reports_kits/reports/data/format_two_dimensions.rb +143 -0
  74. data/lib/reports_kits/reports/data/generate.rb +156 -0
  75. data/lib/reports_kits/reports/data/generate_for_properties.rb +97 -0
  76. data/lib/reports_kits/reports/data/normalize_properties.rb +62 -0
  77. data/lib/reports_kits/reports/data/populate_one_dimension.rb +54 -0
  78. data/lib/reports_kits/reports/data/populate_two_dimensions.rb +104 -0
  79. data/lib/reports_kits/reports/data/utils.rb +178 -0
  80. data/lib/reports_kits/reports/dimension.rb +27 -0
  81. data/lib/reports_kits/reports/dimension_with_series.rb +144 -0
  82. data/lib/reports_kits/reports/filter.rb +29 -0
  83. data/lib/reports_kits/reports/filter_types/base.rb +48 -0
  84. data/lib/reports_kits/reports/filter_types/boolean.rb +47 -0
  85. data/lib/reports_kits/reports/filter_types/datetime.rb +51 -0
  86. data/lib/reports_kits/reports/filter_types/number.rb +30 -0
  87. data/lib/reports_kits/reports/filter_types/records.rb +26 -0
  88. data/lib/reports_kits/reports/filter_types/string.rb +38 -0
  89. data/lib/reports_kits/reports/filter_with_series.rb +97 -0
  90. data/lib/reports_kits/reports/generate_autocomplete_method_results.rb +29 -0
  91. data/lib/reports_kits/reports/generate_autocomplete_results.rb +57 -0
  92. data/lib/reports_kits/reports/inferrable_configuration.rb +116 -0
  93. data/lib/reports_kits/reports/model_settings.rb +30 -0
  94. data/lib/reports_kits/reports/properties.rb +10 -0
  95. data/lib/reports_kits/reports/properties_to_filter.rb +40 -0
  96. data/lib/reports_kits/reports/series.rb +121 -0
  97. data/lib/reports_kits/reports_controller.rb +65 -0
  98. data/lib/reports_kits/utils.rb +11 -0
  99. data/lib/reports_kits/value.rb +3 -0
  100. data/lib/reports_kits/version.rb +3 -0
  101. data/lib/reports_kits.rb +79 -0
  102. data/reports_kits.gemspec +26 -0
  103. data/spec/factories/issue_factory.rb +4 -0
  104. data/spec/factories/issues_label_factory.rb +4 -0
  105. data/spec/factories/label_factory.rb +4 -0
  106. data/spec/factories/pro_repo_factory.rb +5 -0
  107. data/spec/factories/repo_factory.rb +5 -0
  108. data/spec/factories/tag_factory.rb +4 -0
  109. data/spec/fixtures/generate_inputs.yml +254 -0
  110. data/spec/fixtures/generate_outputs.yml +1216 -0
  111. data/spec/reports_kit/form_builder_spec.rb +26 -0
  112. data/spec/reports_kit/relative_time_spec.rb +29 -0
  113. data/spec/reports_kit/reports/data/generate/contextual_filters_spec.rb +60 -0
  114. data/spec/reports_kit/reports/data/generate_spec.rb +1371 -0
  115. data/spec/reports_kit/reports/data/normalize_properties_spec.rb +196 -0
  116. data/spec/reports_kit/reports/dimension_with_series_spec.rb +67 -0
  117. data/spec/reports_kit/reports/filter_with_series_spec.rb +39 -0
  118. data/spec/reports_kit/reports/generate_autocomplete_results_spec.rb +69 -0
  119. data/spec/spec_helper.rb +77 -0
  120. data/spec/support/config.rb +41 -0
  121. data/spec/support/example_data_methods.rb +25 -0
  122. data/spec/support/factory_girl.rb +5 -0
  123. data/spec/support/helpers.rb +25 -0
  124. data/spec/support/models/issue.rb +14 -0
  125. data/spec/support/models/issues_label.rb +4 -0
  126. data/spec/support/models/label.rb +5 -0
  127. data/spec/support/models/pro/repo.rb +5 -0
  128. data/spec/support/models/pro/special_issue.rb +4 -0
  129. data/spec/support/models/repo.rb +13 -0
  130. data/spec/support/models/tag.rb +4 -0
  131. data/spec/support/schema.rb +39 -0
  132. metadata +134 -4
@@ -0,0 +1,1371 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReportsKit::Reports::Data::Generate do
4
+ subject { described_class.new(properties, context_record: context_record).perform }
5
+
6
+ let(:repo) { create(:repo) }
7
+ let(:repo2) { create(:repo) }
8
+ let(:context_record) { nil }
9
+ let(:chart_data) do
10
+ chart_data = subject[:chart_data].except(:options)
11
+ chart_data[:datasets] = chart_data[:datasets].map do |dataset|
12
+ dataset.except(:backgroundColor, :borderColor)
13
+ end
14
+ chart_data
15
+ end
16
+ let(:table_data) do
17
+ subject[:table_data]
18
+ end
19
+
20
+ let(:chart_type) { subject[:type] }
21
+ let(:chart_options) { subject[:chart_data][:options] }
22
+
23
+ context 'with a datetime dimension' do
24
+ context 'with default granularity' do
25
+ let(:properties) do
26
+ {
27
+ measure: 'issue',
28
+ dimensions: %w(opened_at)
29
+ }
30
+ end
31
+ let!(:issues) do
32
+ [
33
+ create(:issue, repo: repo, opened_at: now - 2.weeks),
34
+ create(:issue, repo: repo, opened_at: now - 2.weeks),
35
+ create(:issue, repo: repo, opened_at: now)
36
+ ]
37
+ end
38
+
39
+ it 'returns the type' do
40
+ expect(chart_type).to eq('bar')
41
+ end
42
+
43
+ it 'returns the data' do
44
+ expect(chart_data).to eq({
45
+ labels: [
46
+ format_week_offset(2),
47
+ format_week_offset(1),
48
+ format_week_offset(0)
49
+ ],
50
+ datasets: [
51
+ {
52
+ label: 'Issues',
53
+ data: [2, 0, 1]
54
+ }
55
+ ]
56
+ })
57
+ end
58
+
59
+ context 'with an absolute datetime filter' do
60
+ let(:properties) do
61
+ {
62
+ measure: 'issue',
63
+ filters: [
64
+ {
65
+ key: 'opened_at',
66
+ criteria: {
67
+ operator: 'between',
68
+ value: "#{format_configuration_time(now - 1.week)} - #{format_configuration_time(now)}"
69
+ }
70
+ }
71
+ ],
72
+ dimensions: %w(opened_at)
73
+ }
74
+ end
75
+
76
+ it 'returns the chart_data' do
77
+ expect(chart_data).to eq({
78
+ labels: [format_week_offset(1), format_week_offset(0)],
79
+ datasets: [
80
+ {
81
+ label: 'Issues',
82
+ data: [0, 1]
83
+ }
84
+ ]
85
+ })
86
+ end
87
+
88
+ context 'with a old end date' do
89
+ let(:properties) do
90
+ {
91
+ measure: 'issue',
92
+ filters: [
93
+ {
94
+ key: 'opened_at',
95
+ criteria: {
96
+ operator: 'between',
97
+ value: "#{format_configuration_time(now - 2.weeks)} - #{format_configuration_time(now - 1.week)}"
98
+ }
99
+ }
100
+ ],
101
+ dimensions: %w(opened_at)
102
+ }
103
+ end
104
+
105
+ it 'returns the chart_data' do
106
+ expect(chart_data).to eq({
107
+ labels: [format_week_offset(2), format_week_offset(1)],
108
+ datasets: [
109
+ {
110
+ label: 'Issues',
111
+ data: [2, 0]
112
+ }
113
+ ]
114
+ })
115
+ end
116
+ end
117
+
118
+ context 'with zero results' do
119
+ let(:properties) do
120
+ {
121
+ measure: 'tag',
122
+ filters: [
123
+ {
124
+ key: 'created_at',
125
+ criteria: {
126
+ operator: 'between',
127
+ value: "#{format_configuration_time(now - 1.week)} - #{format_configuration_time(now)}"
128
+ }
129
+ }
130
+ ],
131
+ dimensions: %w(created_at)
132
+ }
133
+ end
134
+
135
+ it 'returns the data' do
136
+ expect(chart_data).to eq({
137
+ labels: [
138
+ format_week_offset(1),
139
+ format_week_offset(0)
140
+ ],
141
+ datasets: [
142
+ {
143
+ label: 'Tags',
144
+ data: [0, 0]
145
+ }
146
+ ]
147
+ })
148
+ end
149
+ end
150
+
151
+ context 'with multiple series and datetime filters with different keys' do
152
+ let!(:tags) do
153
+ [
154
+ create(:tag, repo: repo, created_at: now - 1.weeks),
155
+ create(:tag, repo: repo, created_at: now)
156
+ ]
157
+ end
158
+ let(:properties) do
159
+ {
160
+ series: [
161
+ {
162
+ measure: 'issue',
163
+ filters: %w(opened_at),
164
+ dimensions: %w(opened_at)
165
+ },
166
+ {
167
+ measure: 'tag',
168
+ filters: %w(created_at),
169
+ dimensions: %w(created_at)
170
+ }
171
+ ],
172
+ ui_filters: {
173
+ created_at: "#{format_configuration_time(now - 1.week)} - #{format_configuration_time(now)}"
174
+ }
175
+ }
176
+ end
177
+
178
+ it 'returns the chart_data' do
179
+ expect(chart_data).to eq({
180
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
181
+ datasets: [
182
+ {
183
+ label: 'Issues',
184
+ data: [2, 0, 1]
185
+ },
186
+ {
187
+ label: 'Tags',
188
+ data: [0, 1, 1]
189
+ }
190
+ ]
191
+ })
192
+ end
193
+ end
194
+ end
195
+
196
+ context 'with a relative datetime filter' do
197
+ let(:properties) do
198
+ {
199
+ measure: 'issue',
200
+ filters: [
201
+ {
202
+ key: 'opened_at',
203
+ criteria: {
204
+ operator: 'between',
205
+ value: '-1w - now'
206
+ }
207
+ }
208
+ ],
209
+ dimensions: %w(opened_at)
210
+ }
211
+ end
212
+
213
+ it 'returns the chart_data' do
214
+ expect(chart_data).to eq({
215
+ labels: [format_week_offset(1), format_week_offset(0)],
216
+ datasets: [
217
+ {
218
+ label: 'Issues',
219
+ data: [0, 1]
220
+ }
221
+ ]
222
+ })
223
+ end
224
+
225
+ context 'when a record\'s timestamp is closer to the beginning of the week than the current date' do
226
+ let!(:issues) do
227
+ [
228
+ create(:issue, repo: repo, opened_at: Date.parse('2009-12-22'))
229
+ ]
230
+ end
231
+
232
+ it 'includes record' do
233
+ expect(chart_data).to eq({
234
+ labels: [format_week_offset(1), format_week_offset(0)],
235
+ datasets: [
236
+ {
237
+ label: 'Issues',
238
+ data: [1, 0]
239
+ }
240
+ ]
241
+ })
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ context 'with day granularity' do
248
+ let(:properties) do
249
+ {
250
+ measure: 'issue',
251
+ dimensions: [{ key: 'opened_at', granularity: 'day' }]
252
+ }
253
+ end
254
+ let!(:issues) do
255
+ [
256
+ create(:issue, repo: repo, opened_at: now - 2.days),
257
+ create(:issue, repo: repo, opened_at: now)
258
+ ]
259
+ end
260
+
261
+ it 'returns the data' do
262
+ expect(chart_data).to eq({
263
+ labels: [
264
+ format_day_offset(2),
265
+ format_day_offset(1),
266
+ format_day_offset(0)
267
+ ],
268
+ datasets: [
269
+ {
270
+ label: 'Issues',
271
+ data: [1, 0, 1]
272
+ }
273
+ ]
274
+ })
275
+ end
276
+ end
277
+
278
+ context 'with month granularity' do
279
+ let(:properties) do
280
+ {
281
+ measure: 'issue',
282
+ dimensions: [{ key: 'opened_at', granularity: 'month' }]
283
+ }
284
+ end
285
+ let!(:issues) do
286
+ [
287
+ create(:issue, repo: repo, opened_at: now - 2.days),
288
+ create(:issue, repo: repo, opened_at: now)
289
+ ]
290
+ end
291
+
292
+ it 'returns the data' do
293
+ expect(chart_data).to eq({
294
+ labels: [
295
+ ReportsKit::Reports::Data::Utils.format_display_time(issues.first.opened_at.beginning_of_month),
296
+ ReportsKit::Reports::Data::Utils.format_display_time(issues.last.opened_at.beginning_of_month)
297
+ ],
298
+ datasets: [
299
+ {
300
+ label: 'Issues',
301
+ data: [1, 1]
302
+ }
303
+ ]
304
+ })
305
+ end
306
+ end
307
+ end
308
+
309
+ context 'with an association dimension' do
310
+ let(:properties) do
311
+ {
312
+ measure: 'issue',
313
+ dimensions: %w(repo)
314
+ }
315
+ end
316
+ let!(:issues) do
317
+ [
318
+ create(:issue, repo: repo),
319
+ create(:issue, repo: repo),
320
+ create(:issue, repo: repo2)
321
+ ]
322
+ end
323
+
324
+ it 'returns the chart_data' do
325
+ expect(chart_data).to eq({
326
+ labels: [repo.to_s, repo2.to_s],
327
+ datasets: [{ label: 'Issues', data: [2, 1] }]
328
+ })
329
+ end
330
+
331
+ context 'with a context_record' do
332
+ let(:context_record) { repo }
333
+
334
+ it 'returns the chart_data' do
335
+ expect(chart_data).to eq({
336
+ labels: [repo.to_s],
337
+ datasets: [{ label: 'Issues', data: [2.0] }]
338
+ })
339
+ end
340
+
341
+ context 'with a namespaced context_record class' do
342
+ let(:pro_repo) { create(:pro_repo) }
343
+ let(:context_record) { pro_repo }
344
+ let(:properties) do
345
+ {
346
+ measure: 'special_issue',
347
+ dimensions: %w(repo)
348
+ }
349
+ end
350
+
351
+ let!(:issues) do
352
+ [
353
+ create(:issue, repo: pro_repo),
354
+ create(:issue, repo: pro_repo),
355
+ create(:issue, repo: pro_repo),
356
+ create(:issue, repo: repo2)
357
+ ]
358
+ end
359
+
360
+ it 'returns the chart_data' do
361
+ expect(chart_data).to eq({
362
+ labels: [pro_repo.to_s],
363
+ datasets: [{ label: 'Special Issues', data: [3.0] }]
364
+ })
365
+ end
366
+ end
367
+ end
368
+
369
+ context 'with a limit' do
370
+ let(:properties) do
371
+ {
372
+ measure: 'issue',
373
+ dimensions: %w(repo),
374
+ limit: 1
375
+ }
376
+ end
377
+
378
+ it 'returns the chart_data' do
379
+ expect(chart_data).to eq({
380
+ labels: [repo.to_s],
381
+ datasets: [{ label: 'Issues', data: [2] }]
382
+ })
383
+ end
384
+ end
385
+
386
+ context 'with a dimension limit' do
387
+ let(:properties) do
388
+ {
389
+ measure: 'issue',
390
+ dimensions: [{ key: 'repo', limit: 1 }]
391
+ }
392
+ end
393
+
394
+ it 'returns the chart_data' do
395
+ expect(chart_data).to eq({
396
+ labels: [repo.to_s],
397
+ datasets: [{ label: 'Issues', data: [2] }]
398
+ })
399
+ end
400
+ end
401
+
402
+ context 'with a custom aggregation' do
403
+ let(:properties) do
404
+ {
405
+ measure: {
406
+ key: 'issue',
407
+ name: 'Average Durations',
408
+ aggregation: 'average_duration'
409
+ },
410
+ dimensions: %w(repo)
411
+ }
412
+ end
413
+ let!(:issues) do
414
+ [
415
+ create(:issue, repo: repo, opened_at: now, closed_at: now),
416
+ create(:issue, repo: repo, opened_at: now - 2.weeks, closed_at: now),
417
+ create(:issue, repo: repo2, opened_at: now - 2.weeks, closed_at: now)
418
+ ]
419
+ end
420
+
421
+ it 'returns the chart_data' do
422
+ expect(chart_data).to eq({
423
+ labels: [repo2.to_s, repo.to_s],
424
+ datasets: [{ label: 'Average Durations', data: [14, 7] }]
425
+ })
426
+ end
427
+ end
428
+
429
+ context 'with a belongs_to association filter' do
430
+ let(:properties) do
431
+ {
432
+ measure: 'issue',
433
+ filters: [
434
+ {
435
+ key: 'repo',
436
+ criteria: {
437
+ operator: 'include',
438
+ value: [repo.id]
439
+ }
440
+ }
441
+ ],
442
+ dimensions: %w(repo)
443
+ }
444
+ end
445
+
446
+ it 'returns the chart_data' do
447
+ expect(chart_data).to eq({
448
+ labels: [repo.to_s],
449
+ datasets: [{ label: 'Issues', data: [2.0] }]
450
+ })
451
+ end
452
+ end
453
+
454
+ context 'with a has_many association filter' do
455
+ let(:properties) do
456
+ {
457
+ measure: 'issue',
458
+ filters: [
459
+ {
460
+ key: 'tags',
461
+ criteria: {
462
+ operator: 'include',
463
+ value: [tag.id]
464
+ }
465
+ }
466
+ ],
467
+ dimensions: %w(repo)
468
+ }
469
+ end
470
+ let(:tag) { create(:tag) }
471
+ before(:each) do
472
+ issues[0].tags << tag
473
+ end
474
+
475
+ it 'returns the chart_data' do
476
+ chart_data
477
+ expect(chart_data).to eq({
478
+ labels: [repo.to_s],
479
+ datasets: [{ label: 'Issues', data: [1.0] }]
480
+ })
481
+ end
482
+ end
483
+
484
+ context 'with a has_many :through association filter' do
485
+ let(:properties) do
486
+ {
487
+ measure: 'issue',
488
+ filters: [
489
+ {
490
+ key: 'labels',
491
+ criteria: {
492
+ operator: 'include',
493
+ value: [label.id]
494
+ }
495
+ }
496
+ ],
497
+ dimensions: %w(repo)
498
+ }
499
+ end
500
+ let(:label) { create(:label) }
501
+ before(:each) do
502
+ issues[0].labels << label
503
+ end
504
+
505
+ it 'returns the chart_data' do
506
+ expect(chart_data).to eq({
507
+ labels: [repo.to_s],
508
+ datasets: [{ label: 'Issues', data: [1.0] }]
509
+ })
510
+ end
511
+ end
512
+ end
513
+
514
+ context 'with a boolean dimension' do
515
+ let(:properties) do
516
+ {
517
+ measure: 'issue',
518
+ dimensions: %w(locked)
519
+ }
520
+ end
521
+ let!(:issues) do
522
+ [
523
+ create(:issue, locked: true),
524
+ create(:issue, locked: false),
525
+ create(:issue, locked: false)
526
+ ]
527
+ end
528
+
529
+ it 'returns the chart_data' do
530
+ expect(chart_data).to eq({
531
+ labels: ['false', 'true'],
532
+ datasets: [{ label: 'Issues', data: [2, 1] }]
533
+ })
534
+ end
535
+ end
536
+
537
+ context 'with datetime and association dimensions' do
538
+ let(:properties) do
539
+ {
540
+ measure: 'issue',
541
+ dimensions: [
542
+ { key: 'opened_at', label: nil },
543
+ { key: 'repo' }
544
+ ]
545
+ }
546
+ end
547
+ let!(:issues) do
548
+ [
549
+ create(:issue, repo: repo, opened_at: now),
550
+ create(:issue, repo: repo, opened_at: now - 2.weeks),
551
+ create(:issue, repo: repo2, opened_at: now)
552
+ ]
553
+ end
554
+
555
+ it 'returns the chart_data' do
556
+ expect(chart_data).to eq({
557
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
558
+ datasets: [
559
+ {
560
+ label: repo.to_s,
561
+ data: [1, 0, 1]
562
+ },
563
+ {
564
+ label: repo2.to_s,
565
+ data: [0, 0, 1]
566
+ }
567
+ ]
568
+ })
569
+ end
570
+
571
+ context "with format: 'csv'" do
572
+ subject { described_class.new(properties.merge(format: 'csv'), context_record: context_record).perform }
573
+
574
+ it 'returns the table_data' do
575
+ expect(table_data).to eq([
576
+ [nil, repo.to_s, repo2.to_s],
577
+ [format_csv_week_offset(2), 1, 0],
578
+ [format_csv_week_offset(1), 0, 0],
579
+ [format_csv_week_offset(0), 1, 1]
580
+ ])
581
+ end
582
+
583
+ context 'with a data_format_method that adds HTML tags' do
584
+ subject { described_class.new(properties.merge(format: 'csv', report_options: { data_format_method: 'add_label_link' }), context_record: context_record).perform }
585
+
586
+ it 'returns the table_data without the HTML tags' do
587
+ expect(table_data).to eq([
588
+ [nil, repo.to_s, repo2.to_s],
589
+ ["#{format_csv_week_offset(2)} Bar", 1, 0],
590
+ ["#{format_csv_week_offset(1)} Bar", 0, 0],
591
+ ["#{format_csv_week_offset(0)} Bar", 1, 1]
592
+ ])
593
+ end
594
+ end
595
+
596
+ context 'with a csv_data_format_method' do
597
+ subject { described_class.new(properties.merge(format: 'csv', report_options: { csv_data_format_method: 'prepend_column' }), context_record: context_record).perform }
598
+
599
+ it 'returns the table_data' do
600
+ expect(table_data).to eq([
601
+ [nil, 'Day of Month', repo.to_s, repo2.to_s],
602
+ [format_csv_week_offset(2), 13, 1, 0],
603
+ [format_csv_week_offset(1), 20, 0, 0],
604
+ [format_csv_week_offset(0), 27, 1, 1]
605
+ ])
606
+ end
607
+ end
608
+
609
+ context 'with both a data_format_method and a csv_data_format_method' do
610
+ subject { described_class.new(properties.merge(format: 'csv', report_options: { data_format_method: 'add_label_link', csv_data_format_method: 'prepend_column' }), context_record: context_record).perform }
611
+
612
+ it 'returns the table_data' do
613
+ expect(table_data).to eq([
614
+ [nil, 'Day of Month', repo.to_s, repo2.to_s],
615
+ ["#{format_csv_week_offset(2)} Bar", 13, 1, 0],
616
+ ["#{format_csv_week_offset(1)} Bar", 20, 0, 0],
617
+ ["#{format_csv_week_offset(0)} Bar", 27, 1, 1]
618
+ ])
619
+ end
620
+ end
621
+
622
+ context 'with a csv_data_format_method and aggregations' do
623
+ subject { described_class.new(properties.merge(format: 'csv', report_options: report_options), context_record: context_record).perform }
624
+ let(:report_options) do
625
+ {
626
+ csv_data_format_method: 'prepend_column',
627
+ aggregations: [
628
+ {
629
+ from: 'columns',
630
+ operator: 'sum',
631
+ label: 'Total'
632
+ }
633
+ ]
634
+ }
635
+ end
636
+
637
+ it 'returns the table_data' do
638
+ expect(table_data).to eq([
639
+ [nil, 'Day of Month', repo.to_s, repo2.to_s],
640
+ [format_csv_week_offset(2), 13, 1, 0],
641
+ [format_csv_week_offset(1), 20, 0, 0],
642
+ [format_csv_week_offset(0), 27, 1, 1],
643
+ ['Total', nil, 2, 1]
644
+ ])
645
+ end
646
+ end
647
+ end
648
+
649
+ context "with format: 'table'" do
650
+ subject { described_class.new(properties.merge(format: 'table'), context_record: context_record).perform }
651
+
652
+ it 'returns the table_data' do
653
+ expect(table_data).to eq([
654
+ [nil, repo.to_s, repo2.to_s],
655
+ [format_week_offset(2), 1, 0],
656
+ [format_week_offset(1), 0, 0],
657
+ [format_week_offset(0), 1, 1]
658
+ ])
659
+ end
660
+
661
+ context 'with a data_format_method that adds HTML tags' do
662
+ subject { described_class.new(properties.merge(format: 'table', report_options: { data_format_method: 'add_label_link' }), context_record: context_record).perform }
663
+
664
+ it 'returns the table_data with the HTML tags' do
665
+ expect(table_data).to eq([
666
+ [nil, repo.to_s, repo2.to_s],
667
+ ["<a href='#'>#{format_week_offset(2)}</a> Bar", 1, 0],
668
+ ["<a href='#'>#{format_week_offset(1)}</a> Bar", 0, 0],
669
+ ["<a href='#'>#{format_week_offset(0)}</a> Bar", 1, 1]
670
+ ])
671
+ end
672
+ end
673
+ end
674
+
675
+ context 'with a data_format_method' do
676
+ subject { described_class.new(properties.merge(report_options: { data_format_method: 'add_label_suffix' }), context_record: context_record).perform }
677
+
678
+ it 'returns the chart_data' do
679
+ expect(chart_data).to eq({
680
+ labels: ["#{format_week_offset(2)} Foo", "#{format_week_offset(1)} Foo", "#{format_week_offset(0)} Foo"],
681
+ datasets: [
682
+ {
683
+ label: repo.to_s,
684
+ data: [1, 0, 1]
685
+ },
686
+ {
687
+ label: repo2.to_s,
688
+ data: [0, 0, 1]
689
+ }
690
+ ]
691
+ })
692
+ end
693
+
694
+ context 'with dependence on the context_record' do
695
+ subject { described_class.new(properties.merge(report_options: { data_format_method: 'add_context_record_suffix' }), context_record: context_record).perform }
696
+ let(:context_record) { repo }
697
+
698
+ it 'returns the chart_data' do
699
+ expect(chart_data).to eq({
700
+ labels: ["#{format_week_offset(2)} #{context_record}", "#{format_week_offset(1)} #{context_record}", "#{format_week_offset(0)} #{context_record}"],
701
+ datasets: [
702
+ {
703
+ label: repo.to_s,
704
+ data: [1, 0, 1]
705
+ }
706
+ ]
707
+ })
708
+ end
709
+ end
710
+ end
711
+
712
+ context 'with an edit_relation_method' do
713
+ subject { described_class.new(properties.merge(report_options: { edit_relation_method: 'empty_result_set_for_relation' }), context_record: context_record).perform }
714
+
715
+ it 'returns the chart_data' do
716
+ expect(chart_data).to eq({
717
+ labels: [],
718
+ datasets: [
719
+ {
720
+ label: 'Issues',
721
+ data: []
722
+ }
723
+ ]
724
+ })
725
+ end
726
+ end
727
+ end
728
+
729
+ context 'with a dimension with a blank label' do
730
+ let(:properties) do
731
+ {
732
+ measure: 'issue',
733
+ dimensions: %w(repo)
734
+ }
735
+ end
736
+
737
+ before do
738
+ allow_any_instance_of(Repo).to receive(:to_s).and_return(nil)
739
+ end
740
+
741
+ it 'hides the dimension' do
742
+ expect(chart_data).to eq({
743
+ labels: [],
744
+ datasets: [
745
+ {
746
+ label: 'Issues',
747
+ data: []
748
+ }
749
+ ]
750
+ })
751
+ end
752
+ end
753
+
754
+ context 'with two series' do
755
+ let(:properties) do
756
+ {
757
+ series: [
758
+ {
759
+ measure: 'issue',
760
+ dimensions: [{ key: 'created_at', label: nil }]
761
+ },
762
+ {
763
+ measure: 'tag',
764
+ dimensions: %w(created_at)
765
+ }
766
+ ]
767
+ }
768
+ end
769
+ let!(:issues) do
770
+ [
771
+ create(:issue, repo: repo, created_at: now),
772
+ create(:issue, repo: repo, created_at: now - 2.weeks),
773
+ create(:issue, repo: repo2, created_at: now)
774
+ ]
775
+ end
776
+ let!(:tags) do
777
+ [
778
+ create(:tag, repo: repo, created_at: now - 1.week),
779
+ create(:tag, repo: repo, created_at: now - 2.weeks)
780
+ ]
781
+ end
782
+
783
+ it 'returns the chart_data' do
784
+ expect(chart_data).to eq({
785
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
786
+ datasets: [
787
+ {
788
+ label: 'Issues',
789
+ data: [1, 0, 2]
790
+ },
791
+ {
792
+ label: 'Tags',
793
+ data: [1, 1, 0]
794
+ }
795
+ ]
796
+ })
797
+ end
798
+
799
+ context 'with edit_dimension_keys_method and a dimension without data' do
800
+ let(:properties) do
801
+ {
802
+ series: [
803
+ {
804
+ measure: 'issue',
805
+ dimensions: %w(repo)
806
+ },
807
+ {
808
+ measure: 'tag',
809
+ dimensions: %w(repo)
810
+ }
811
+ ],
812
+ report_options: {
813
+ edit_dimension_keys_method: 'all_repo_ids'
814
+ }
815
+ }
816
+ end
817
+ let!(:repo3) { create(:repo) }
818
+
819
+ it 'returns the chart_data' do
820
+ expect(chart_data).to eq({
821
+ labels: [repo, repo2, repo3].map(&:to_s),
822
+ datasets: [
823
+ {
824
+ label: 'Issues',
825
+ data: [2, 1, 0]
826
+ },
827
+ {
828
+ label: 'Tags',
829
+ data: [2, 0, 0]
830
+ }
831
+ ]
832
+ })
833
+ end
834
+ end
835
+
836
+ context 'with concurrent queries enabled' do
837
+ around :each do |example|
838
+ ReportsKit.configuration.use_concurrent_queries = true
839
+ example.run
840
+ ReportsKit.configuration.use_concurrent_queries = false
841
+ end
842
+
843
+ it 'returns the chart_data' do
844
+ expect(chart_data).to eq({
845
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
846
+ datasets: [
847
+ {
848
+ label: 'Issues',
849
+ data: [1, 0, 2]
850
+ },
851
+ {
852
+ label: 'Tags',
853
+ data: [1, 1, 0]
854
+ }
855
+ ]
856
+ })
857
+ end
858
+ end
859
+
860
+ context "with format: 'table'" do
861
+ subject { described_class.new(properties.merge(format: 'table'), context_record: context_record).perform }
862
+
863
+ it 'returns the table_data' do
864
+ expect(table_data).to eq([
865
+ [nil, 'Issues', 'Tags'],
866
+ [format_week_offset(2), 1, 1],
867
+ [format_week_offset(1), 0, 1],
868
+ [format_week_offset(0), 2, 0]
869
+ ])
870
+ end
871
+ end
872
+ end
873
+
874
+ context 'with two dimensions' do
875
+ context 'with a custom aggregation' do
876
+ let(:properties) do
877
+ {
878
+ measure: {
879
+ key: 'issue',
880
+ aggregation: 'average_duration'
881
+ },
882
+ dimensions: %w(repo created_at)
883
+ }
884
+ end
885
+ let!(:issues) do
886
+ [
887
+ create(:issue, repo: repo, opened_at: now, closed_at: now),
888
+ create(:issue, repo: repo, opened_at: now - 2.weeks, closed_at: now),
889
+ create(:issue, repo: repo2, opened_at: now - 2.weeks, closed_at: now)
890
+ ]
891
+ end
892
+
893
+ it 'returns the chart_data' do
894
+ expect(chart_data).to eq({
895
+ labels: [repo2.to_s, repo.to_s],
896
+ datasets: [{ label: format_week_offset(0), data: [14, 7] }]
897
+ })
898
+ end
899
+ end
900
+ end
901
+
902
+ describe 'configuration' do
903
+ let(:properties) do
904
+ {
905
+ measure: 'issue',
906
+ dimensions: %w(repo)
907
+ }
908
+ end
909
+ let!(:issues) do
910
+ [
911
+ create(:issue, repo: repo),
912
+ create(:issue, repo: repo),
913
+ create(:issue, repo: repo2)
914
+ ]
915
+ end
916
+
917
+ context 'with default_properties' do
918
+ around :each do |example|
919
+ ReportsKit.configuration.default_properties = {
920
+ chart: {
921
+ options: {
922
+ foo: 'bar'
923
+ }
924
+ }
925
+ }
926
+ example.run
927
+ ReportsKit.configuration.default_properties = nil
928
+ end
929
+
930
+ it 'returns the chart_data' do
931
+ expect(subject[:chart_data][:options][:foo]).to eq('bar')
932
+ end
933
+ end
934
+ end
935
+
936
+ describe 'composite series' do
937
+ context 'with two series' do
938
+ let(:properties) do
939
+ {
940
+ name: name,
941
+ composite_operator: composite_operator,
942
+ series: [
943
+ {
944
+ measure: 'issue',
945
+ dimensions: %w(created_at)
946
+ },
947
+ {
948
+ measure: 'tag',
949
+ dimensions: %w(created_at)
950
+ }
951
+ ]
952
+ }
953
+ end
954
+ let!(:issues) do
955
+ [
956
+ create(:issue, repo: repo, created_at: now),
957
+ create(:issue, repo: repo, created_at: now - 2.weeks),
958
+ create(:issue, repo: repo2, created_at: now)
959
+ ]
960
+ end
961
+ let!(:tags) do
962
+ [
963
+ create(:tag, repo: repo, created_at: now),
964
+ create(:tag, repo: repo, created_at: now - 1.week),
965
+ create(:tag, repo: repo, created_at: now - 1.week)
966
+ ]
967
+ end
968
+ let(:name) { 'My Name' }
969
+
970
+ context 'with +' do
971
+ let(:composite_operator) { '+' }
972
+
973
+ it 'returns the chart_data' do
974
+ expect(chart_data).to eq({
975
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
976
+ datasets: [
977
+ {
978
+ label: name,
979
+ data: [1, 2, 3]
980
+ }
981
+ ]
982
+ })
983
+ end
984
+ end
985
+
986
+ context 'with %' do
987
+ let(:composite_operator) { '%' }
988
+
989
+ it 'returns the chart_data' do
990
+ expect(chart_data).to eq({
991
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
992
+ datasets: [
993
+ {
994
+ label: name,
995
+ data: [0, 0, 200]
996
+ }
997
+ ]
998
+ })
999
+ end
1000
+ end
1001
+
1002
+ context 'with % and a custom value_format_method' do
1003
+ let(:composite_operator) { '%' }
1004
+ let(:properties) do
1005
+ {
1006
+ name: name,
1007
+ composite_operator: composite_operator,
1008
+ value_format_method: 'format_percentage',
1009
+ series: [
1010
+ {
1011
+ measure: 'issue',
1012
+ dimensions: %w(created_at)
1013
+ },
1014
+ {
1015
+ measure: 'tag',
1016
+ dimensions: %w(created_at)
1017
+ }
1018
+ ]
1019
+ }
1020
+ end
1021
+
1022
+ it 'returns the chart_data' do
1023
+ expect(chart_data).to eq({
1024
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
1025
+ datasets: [
1026
+ {
1027
+ label: name,
1028
+ data: ['0%', '0%', '200%']
1029
+ }
1030
+ ]
1031
+ })
1032
+ end
1033
+ end
1034
+
1035
+ context 'with a limit' do
1036
+ let(:properties) do
1037
+ {
1038
+ name: name,
1039
+ composite_operator: '+',
1040
+ limit: 1,
1041
+ series: [
1042
+ {
1043
+ measure: 'issue',
1044
+ dimensions: %w(repo)
1045
+ },
1046
+ {
1047
+ measure: 'tag',
1048
+ dimensions: %w(repo)
1049
+ }
1050
+ ]
1051
+ }
1052
+ end
1053
+
1054
+ it 'returns the chart_data' do
1055
+ expect(chart_data).to eq({
1056
+ labels: [repo.to_s],
1057
+ datasets: [
1058
+ {
1059
+ label: name,
1060
+ data: [5]
1061
+ }
1062
+ ]
1063
+ })
1064
+ end
1065
+ end
1066
+
1067
+ context 'with a limit and an order' do
1068
+ context 'with an ascending order' do
1069
+ let(:properties) do
1070
+ {
1071
+ name: name,
1072
+ composite_operator: '%',
1073
+ limit: 1,
1074
+ order: '1',
1075
+ series: [
1076
+ {
1077
+ measure: 'issue',
1078
+ dimensions: %w(repo)
1079
+ },
1080
+ {
1081
+ measure: 'tag',
1082
+ dimensions: %w(repo)
1083
+ }
1084
+ ]
1085
+ }
1086
+ end
1087
+
1088
+ it 'returns the chart_data' do
1089
+ expect(chart_data).to eq({
1090
+ labels: [repo2.to_s],
1091
+ datasets: [
1092
+ {
1093
+ label: name,
1094
+ data: [0]
1095
+ }
1096
+ ]
1097
+ })
1098
+ end
1099
+ end
1100
+
1101
+ context 'with a descending order' do
1102
+ let(:properties) do
1103
+ {
1104
+ name: name,
1105
+ composite_operator: '%',
1106
+ limit: 1,
1107
+ order: '1 desc',
1108
+ series: [
1109
+ {
1110
+ measure: 'issue',
1111
+ dimensions: %w(repo)
1112
+ },
1113
+ {
1114
+ measure: 'tag',
1115
+ dimensions: %w(repo)
1116
+ }
1117
+ ]
1118
+ }
1119
+ end
1120
+
1121
+ it 'returns the chart_data' do
1122
+ expect(chart_data).to eq({
1123
+ labels: [repo.to_s],
1124
+ datasets: [
1125
+ {
1126
+ label: name,
1127
+ data: [66.7]
1128
+ }
1129
+ ]
1130
+ })
1131
+ end
1132
+ end
1133
+ end
1134
+
1135
+ context 'with a boolean dimension' do
1136
+ let!(:issues) do
1137
+ [
1138
+ create(:issue, locked: true),
1139
+ create(:issue, locked: false),
1140
+ create(:issue, locked: false)
1141
+ ]
1142
+ end
1143
+ let(:composite_operator) { '+' }
1144
+ let(:properties) do
1145
+ {
1146
+ name: name,
1147
+ composite_operator: composite_operator,
1148
+ series: [
1149
+ {
1150
+ measure: 'issue',
1151
+ dimensions: %w(locked)
1152
+ },
1153
+ {
1154
+ measure: 'issue',
1155
+ dimensions: %w(locked)
1156
+ }
1157
+ ]
1158
+ }
1159
+ end
1160
+
1161
+ it 'returns the chart_data' do
1162
+ expect(chart_data).to eq({
1163
+ labels: ['false', 'true'],
1164
+ datasets: [
1165
+ {
1166
+ label: name,
1167
+ data: [4, 2]
1168
+ }
1169
+ ]
1170
+ })
1171
+ end
1172
+ end
1173
+
1174
+ context 'with a nested composite series' do
1175
+ let(:properties) do
1176
+ {
1177
+ series: [
1178
+ {
1179
+ name: name,
1180
+ composite_operator: '+',
1181
+ series: [
1182
+ {
1183
+ measure: 'issue',
1184
+ dimensions: %w(created_at)
1185
+ },
1186
+ {
1187
+ measure: 'tag',
1188
+ dimensions: %w(created_at)
1189
+ }
1190
+ ]
1191
+ },
1192
+ {
1193
+ measure: 'issue',
1194
+ dimensions: %w(created_at)
1195
+ },
1196
+ {
1197
+ measure: 'tag',
1198
+ dimensions: %w(created_at)
1199
+ }
1200
+ ]
1201
+ }
1202
+ end
1203
+
1204
+ it 'returns the chart_data' do
1205
+ expect(chart_data).to eq({
1206
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
1207
+ datasets: [
1208
+ {
1209
+ label: name,
1210
+ data: [1, 2, 3]
1211
+ },
1212
+ {
1213
+ label: 'Issues',
1214
+ data: [1, 0, 2]
1215
+ },
1216
+ {
1217
+ label: 'Tags',
1218
+ data: [0, 2, 1]
1219
+ }
1220
+ ]
1221
+ })
1222
+ end
1223
+
1224
+ context 'with ui_filters' do
1225
+ let(:properties) do
1226
+ {
1227
+ series: [
1228
+ {
1229
+ name: name,
1230
+ composite_operator: '+',
1231
+ series: [
1232
+ {
1233
+ measure: 'issue',
1234
+ filters: %w(created_at),
1235
+ dimensions: %w(created_at)
1236
+ },
1237
+ {
1238
+ measure: 'tag',
1239
+ filters: %w(created_at),
1240
+ dimensions: %w(created_at)
1241
+ }
1242
+ ]
1243
+ },
1244
+ {
1245
+ measure: 'issue',
1246
+ filters: %w(created_at),
1247
+ dimensions: %w(created_at)
1248
+ },
1249
+ {
1250
+ measure: 'tag',
1251
+ filters: %w(created_at),
1252
+ dimensions: %w(created_at)
1253
+ }
1254
+ ],
1255
+ ui_filters: {
1256
+ created_at: "#{format_configuration_time(now - 1.week)} - #{format_configuration_time(now)}"
1257
+ }
1258
+ }
1259
+ end
1260
+
1261
+ it 'returns the chart_data' do
1262
+ expect(chart_data).to eq({
1263
+ labels: [format_week_offset(1), format_week_offset(0)],
1264
+ datasets: [
1265
+ {
1266
+ label: name,
1267
+ data: [2, 3]
1268
+ },
1269
+ {
1270
+ label: 'Issues',
1271
+ data: [0, 2]
1272
+ },
1273
+ {
1274
+ label: 'Tags',
1275
+ data: [2, 1]
1276
+ }
1277
+ ]
1278
+ })
1279
+ end
1280
+ end
1281
+
1282
+ context 'with two dimensions' do
1283
+ let(:properties) do
1284
+ {
1285
+ series: [
1286
+ {
1287
+ name: name,
1288
+ composite_operator: '+',
1289
+ series: [
1290
+ {
1291
+ measure: 'issue',
1292
+ dimensions: %w(created_at repo)
1293
+ },
1294
+ {
1295
+ measure: 'tag',
1296
+ dimensions: %w(created_at repo)
1297
+ }
1298
+ ]
1299
+ }
1300
+ ]
1301
+ }
1302
+ end
1303
+
1304
+ it 'returns the chart_data' do
1305
+ expect(chart_data).to eq({
1306
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
1307
+ datasets: [
1308
+ {
1309
+ label: repo.to_s,
1310
+ data: [1, 2, 2]
1311
+ },
1312
+ {
1313
+ label: repo2.to_s,
1314
+ data: [0, 0, 1]
1315
+ }
1316
+ ]
1317
+ })
1318
+ end
1319
+ end
1320
+ end
1321
+ end
1322
+ end
1323
+
1324
+ # These examples allow for quick comparisons of many types of inputs and outputs.
1325
+ # When making functional modifications, run these to see whether the modifications impact the output in any cases.
1326
+ # If the output effects are desired, run `REWRITE_RESULTS=1 rspec` to write them to the outputs YAML file, then verify that the output
1327
+ # modifications are desired, then commit the result and uncomment the `skip`.
1328
+ describe 'YAML-based output comparisons' do
1329
+ FIXTURES_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'fixtures'))
1330
+
1331
+ let(:inputs) { YAML.load_file("#{FIXTURES_DIRECTORY}/generate_inputs.yml") }
1332
+ let(:outputs_path) { "#{FIXTURES_DIRECTORY}/generate_outputs.yml" }
1333
+ let(:outputs) { YAML.load_file(outputs_path) }
1334
+
1335
+ let!(:repo) { create(:repo, full_name: 'foo/bar1') }
1336
+ let!(:repo2) { create(:repo, full_name: 'foo/bar2') }
1337
+ let!(:issues) do
1338
+ [
1339
+ create(:issue, repo: repo, state: 'open', opened_at: now - 2.weeks),
1340
+ create(:issue, repo: repo, state: 'closed', opened_at: now)
1341
+ ]
1342
+ end
1343
+ let!(:labels) do
1344
+ [
1345
+ create(:label, repo: repo),
1346
+ create(:label, repo: repo2),
1347
+ create(:label, repo: repo2)
1348
+ ]
1349
+ end
1350
+
1351
+ context 'input examples' do
1352
+ YAML.load_file("#{FIXTURES_DIRECTORY}/generate_inputs.yml").each.with_index do |inputs, index|
1353
+ it "returns the expected output for input ##{index}: #{inputs.to_json}" do
1354
+ expect(described_class.new(inputs).perform.to_yaml).to eq(outputs[index].to_yaml)
1355
+ end
1356
+ end
1357
+ end
1358
+
1359
+ context 'writing the outputs' do
1360
+ it 'writes the outputs' do
1361
+ # For documentation about this `skip`, see the comment at the top of this `describe` block.
1362
+ skip unless ENV['REWRITE_RESULTS'] == '1'
1363
+
1364
+ outputs = inputs.map do |example|
1365
+ described_class.new(example).perform
1366
+ end
1367
+ File.write(outputs_path, outputs.to_yaml)
1368
+ end
1369
+ end
1370
+ end
1371
+ end