reports_kits 0.7.5 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
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