reports_kit 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -5
  3. data/app/assets/javascripts/reports_kit/lib/chart.js +33 -8
  4. data/app/assets/javascripts/reports_kit/lib/report.js +27 -26
  5. data/app/assets/javascripts/reports_kit/lib/table.js +58 -0
  6. data/app/assets/javascripts/reports_kit/vendor/jquery.tablesorter.min.js +4 -0
  7. data/app/assets/stylesheets/reports_kit/reports.css.sass +20 -0
  8. data/config/initializers/mime_types.rb +1 -0
  9. data/docs/dimensions.md +34 -26
  10. data/docs/display_options.md +15 -12
  11. data/docs/filters.md +2 -2
  12. data/docs/measures.md +4 -3
  13. data/gemfiles/mysql.gemfile.lock +14 -1
  14. data/gemfiles/postgresql.gemfile.lock +14 -1
  15. data/lib/reports_kit.rb +15 -0
  16. data/lib/reports_kit/cache.rb +37 -0
  17. data/lib/reports_kit/configuration.rb +13 -1
  18. data/lib/reports_kit/helper.rb +54 -3
  19. data/lib/reports_kit/model_configuration.rb +6 -1
  20. data/lib/reports_kit/order.rb +33 -0
  21. data/lib/reports_kit/relative_time.rb +42 -0
  22. data/lib/reports_kit/report_builder.rb +34 -15
  23. data/lib/reports_kit/reports/abstract_measure.rb +9 -0
  24. data/lib/reports_kit/reports/adapters/mysql.rb +8 -1
  25. data/lib/reports_kit/reports/adapters/postgresql.rb +8 -1
  26. data/lib/reports_kit/reports/composite_measure.rb +43 -0
  27. data/lib/reports_kit/reports/data/chart_options.rb +5 -0
  28. data/lib/reports_kit/reports/data/composite_aggregation.rb +96 -0
  29. data/lib/reports_kit/reports/data/entity.rb +7 -0
  30. data/lib/reports_kit/reports/data/format_one_dimension.rb +120 -0
  31. data/lib/reports_kit/reports/data/format_two_dimensions.rb +141 -0
  32. data/lib/reports_kit/reports/data/generate.rb +72 -25
  33. data/lib/reports_kit/reports/data/generate_for_properties.rb +75 -0
  34. data/lib/reports_kit/reports/data/one_dimension.rb +15 -49
  35. data/lib/reports_kit/reports/data/populate_one_dimension.rb +36 -0
  36. data/lib/reports_kit/reports/data/populate_two_dimensions.rb +104 -0
  37. data/lib/reports_kit/reports/data/two_dimensions.rb +15 -110
  38. data/lib/reports_kit/reports/data/utils.rb +77 -12
  39. data/lib/reports_kit/reports/data/value.rb +7 -0
  40. data/lib/reports_kit/reports/dimension.rb +4 -110
  41. data/lib/reports_kit/reports/dimension_with_measure.rb +137 -0
  42. data/lib/reports_kit/reports/filter.rb +5 -64
  43. data/lib/reports_kit/reports/filter_types/base.rb +1 -1
  44. data/lib/reports_kit/reports/filter_types/boolean.rb +9 -7
  45. data/lib/reports_kit/reports/filter_types/datetime.rb +7 -5
  46. data/lib/reports_kit/reports/filter_types/number.rb +2 -0
  47. data/lib/reports_kit/reports/filter_with_measure.rb +84 -0
  48. data/lib/reports_kit/reports/generate_autocomplete_results.rb +1 -1
  49. data/lib/reports_kit/reports/inferrable_configuration.rb +32 -13
  50. data/lib/reports_kit/reports/measure.rb +48 -12
  51. data/lib/reports_kit/reports_controller.rb +42 -3
  52. data/lib/reports_kit/version.rb +1 -1
  53. data/reports_kit.gemspec +2 -0
  54. data/spec/fixtures/generate_inputs.yml +146 -21
  55. data/spec/fixtures/generate_outputs.yml +768 -17
  56. data/spec/reports_kit/relative_time_spec.rb +29 -0
  57. data/spec/reports_kit/report_builder_spec.rb +28 -0
  58. data/spec/reports_kit/reports/data/generate_spec.rb +614 -27
  59. data/spec/reports_kit/reports/dimension_with_measure_spec.rb +69 -0
  60. data/spec/reports_kit/reports/{filter_spec.rb → filter_with_measure_spec.rb} +4 -3
  61. data/spec/spec_helper.rb +7 -2
  62. data/spec/support/config.rb +11 -0
  63. data/spec/support/helpers.rb +3 -3
  64. data/spec/support/models/issue.rb +7 -0
  65. metadata +53 -4
  66. data/spec/reports_kit/reports/dimension_spec.rb +0 -54
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReportsKit::RelativeTime do
4
+ subject { described_class.parse(string) }
5
+
6
+ Timecop.freeze(TIMECOP_TIME) do
7
+ STRINGS_EXPECTED_VALUES = {
8
+ '2s' => 2.seconds.from_now,
9
+ '-3s' => 3.seconds.ago,
10
+ '4m' => 4.minutes.from_now,
11
+ '5h' => 5.hours.from_now,
12
+ '-6d' => 6.days.ago,
13
+ '7w' => 7.weeks.from_now,
14
+ '8M' => 8.months.from_now,
15
+ '9y' => 9.years.from_now,
16
+ '-2M1w' => (2.months + 1.week).ago
17
+ }
18
+ end
19
+
20
+ STRINGS_EXPECTED_VALUES.each do |string, expected_value|
21
+ context string do
22
+ let(:string) { string }
23
+
24
+ it 'transforms the filter criteria' do
25
+ expect(subject).to eq(expected_value)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReportsKit::ReportBuilder do
4
+ subject { described_class.new(properties) }
5
+
6
+ context 'with a datetime dimension' do
7
+ let(:properties) do
8
+ {
9
+ measure: {
10
+ key: 'issue',
11
+ filters: [
12
+ {
13
+ key: 'opened_at',
14
+ criteria: {
15
+ operator: 'between',
16
+ value: '-1w - now'
17
+ }
18
+ }
19
+ ]
20
+ }
21
+ }
22
+ end
23
+
24
+ it 'transforms the filter criteria' do
25
+ expect(subject.date_range('opened_at')).to include("#{format_criteria_time(1.week.ago)} - #{format_criteria_time(Time.zone.now)}")
26
+ end
27
+ end
28
+ end
@@ -13,6 +13,9 @@ describe ReportsKit::Reports::Data::Generate do
13
13
  end
14
14
  chart_data
15
15
  end
16
+ let(:table_data) do
17
+ subject[:table_data]
18
+ end
16
19
 
17
20
  let(:chart_type) { subject[:type] }
18
21
  let(:chart_options) { subject[:chart_data][:options] }
@@ -21,8 +24,10 @@ describe ReportsKit::Reports::Data::Generate do
21
24
  context 'with default granularity' do
22
25
  let(:properties) do
23
26
  {
24
- measure: 'issue',
25
- dimensions: %w(opened_at)
27
+ measure: {
28
+ key: 'issue',
29
+ dimensions: %w(opened_at)
30
+ }
26
31
  }
27
32
  end
28
33
  let!(:issues) do
@@ -63,12 +68,12 @@ describe ReportsKit::Reports::Data::Generate do
63
68
  key: 'opened_at',
64
69
  criteria: {
65
70
  operator: 'between',
66
- value: "#{date_string_for_filter(now - 1.week)} - #{date_string_for_filter(now)}"
71
+ value: "#{format_criteria_time(now - 1.week)} - #{format_criteria_time(now)}"
67
72
  }
68
73
  }
69
- ]
70
- },
71
- dimensions: %w(opened_at)
74
+ ],
75
+ dimensions: %w(opened_at)
76
+ }
72
77
  }
73
78
  end
74
79
 
@@ -83,14 +88,95 @@ describe ReportsKit::Reports::Data::Generate do
83
88
  ]
84
89
  })
85
90
  end
91
+
92
+ context 'with zero results' do
93
+ let(:properties) do
94
+ {
95
+ measure: {
96
+ key: 'tag',
97
+ filters: [
98
+ {
99
+ key: 'created_at',
100
+ criteria: {
101
+ operator: 'between',
102
+ value: "#{format_criteria_time(now - 1.week)} - #{format_criteria_time(now)}"
103
+ }
104
+ }
105
+ ],
106
+ dimensions: %w(created_at)
107
+ }
108
+ }
109
+ end
110
+
111
+ it 'returns the data' do
112
+ expect(chart_data).to eq({
113
+ labels: [
114
+ format_week_offset(1),
115
+ format_week_offset(0)
116
+ ],
117
+ datasets: [
118
+ {
119
+ label: 'Tags',
120
+ data: [0, 0]
121
+ }
122
+ ]
123
+ })
124
+ end
125
+ end
126
+
127
+ context 'with multiple measures and datetime filters with different keys' do
128
+ let!(:tags) do
129
+ [
130
+ create(:tag, repo: repo, created_at: now - 1.weeks),
131
+ create(:tag, repo: repo, created_at: now)
132
+ ]
133
+ end
134
+ let(:properties) do
135
+ {
136
+ measures: [
137
+ {
138
+ key: 'issue',
139
+ filters: %w(opened_at),
140
+ dimensions: %w(opened_at)
141
+ },
142
+ {
143
+ key: 'tag',
144
+ filters: %w(created_at),
145
+ dimensions: %w(created_at)
146
+ }
147
+ ],
148
+ ui_filters: {
149
+ created_at: "#{format_criteria_time(now - 1.week)} - #{format_criteria_time(now)}"
150
+ }
151
+ }
152
+ end
153
+
154
+ it 'returns the chart_data' do
155
+ expect(chart_data).to eq({
156
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
157
+ datasets: [
158
+ {
159
+ label: "Issues",
160
+ data: [2, 0, 1]
161
+ },
162
+ {
163
+ label: "Tags",
164
+ data: [0, 1, 1]
165
+ }
166
+ ]
167
+ })
168
+ end
169
+ end
86
170
  end
87
171
  end
88
172
 
89
173
  context 'with day granularity' do
90
174
  let(:properties) do
91
175
  {
92
- measure: 'issue',
93
- dimensions: [{ key: 'opened_at', granularity: 'day' }]
176
+ measure: {
177
+ key: 'issue',
178
+ dimensions: [{ key: 'opened_at', granularity: 'day' }]
179
+ }
94
180
  }
95
181
  end
96
182
  let!(:issues) do
@@ -121,8 +207,10 @@ describe ReportsKit::Reports::Data::Generate do
121
207
  context 'with an association dimension' do
122
208
  let(:properties) do
123
209
  {
124
- measure: 'issue',
125
- dimensions: %w(repo)
210
+ measure: {
211
+ key: 'issue',
212
+ dimensions: %w(repo)
213
+ }
126
214
  }
127
215
  end
128
216
  let!(:issues) do
@@ -151,6 +239,51 @@ describe ReportsKit::Reports::Data::Generate do
151
239
  end
152
240
  end
153
241
 
242
+ context 'with a dimension limit' do
243
+ let(:properties) do
244
+ {
245
+ measure: {
246
+ key: 'issue',
247
+ dimensions: [{ key: 'repo', limit: 1 }]
248
+ }
249
+ }
250
+ end
251
+
252
+ it 'returns the chart_data' do
253
+ expect(chart_data).to eq({
254
+ labels: [repo.to_s],
255
+ datasets: [{ label: 'Issues', data: [2] }]
256
+ })
257
+ end
258
+ end
259
+
260
+ context 'with a custom aggregation' do
261
+ let(:properties) do
262
+ {
263
+ measure: {
264
+ key: 'issue',
265
+ name: 'Average Durations',
266
+ aggregation: 'average_duration',
267
+ dimensions: %w(repo)
268
+ }
269
+ }
270
+ end
271
+ let!(:issues) do
272
+ [
273
+ create(:issue, repo: repo, opened_at: now, closed_at: now),
274
+ create(:issue, repo: repo, opened_at: now - 2.weeks, closed_at: now),
275
+ create(:issue, repo: repo2, opened_at: now - 2.weeks, closed_at: now)
276
+ ]
277
+ end
278
+
279
+ it 'returns the chart_data' do
280
+ expect(chart_data).to eq({
281
+ labels: [repo2.to_s, repo.to_s],
282
+ datasets: [{ label: 'Average Durations', data: [14, 7] }]
283
+ })
284
+ end
285
+ end
286
+
154
287
  context 'with a belongs_to association filter' do
155
288
  let(:properties) do
156
289
  {
@@ -164,9 +297,9 @@ describe ReportsKit::Reports::Data::Generate do
164
297
  value: [repo.id]
165
298
  }
166
299
  }
167
- ]
168
- },
169
- dimensions: %w(repo)
300
+ ],
301
+ dimensions: %w(repo)
302
+ }
170
303
  }
171
304
  end
172
305
 
@@ -191,9 +324,9 @@ describe ReportsKit::Reports::Data::Generate do
191
324
  value: [tag.id]
192
325
  }
193
326
  }
194
- ]
195
- },
196
- dimensions: %w(repo)
327
+ ],
328
+ dimensions: %w(repo)
329
+ }
197
330
  }
198
331
  end
199
332
  let(:tag) { create(:tag) }
@@ -223,9 +356,9 @@ describe ReportsKit::Reports::Data::Generate do
223
356
  value: [label.id]
224
357
  }
225
358
  }
226
- ]
227
- },
228
- dimensions: %w(repo)
359
+ ],
360
+ dimensions: %w(repo)
361
+ }
229
362
  }
230
363
  end
231
364
  let(:label) { create(:label) }
@@ -242,11 +375,41 @@ describe ReportsKit::Reports::Data::Generate do
242
375
  end
243
376
  end
244
377
 
378
+ context 'with a boolean dimension' do
379
+ let(:properties) do
380
+ {
381
+ measure: {
382
+ key: 'issue',
383
+ dimensions: %w(locked)
384
+ }
385
+ }
386
+ end
387
+ let!(:issues) do
388
+ [
389
+ create(:issue, locked: true),
390
+ create(:issue, locked: false),
391
+ create(:issue, locked: false)
392
+ ]
393
+ end
394
+
395
+ it 'returns the chart_data' do
396
+ expect(chart_data).to eq({
397
+ labels: ['false', 'true'],
398
+ datasets: [{ label: 'Issues', data: [2, 1] }]
399
+ })
400
+ end
401
+ end
402
+
245
403
  context 'with datetime and association dimensions' do
246
404
  let(:properties) do
247
405
  {
248
- measure: 'issue',
249
- dimensions: %w(opened_at repo)
406
+ measure: {
407
+ key: 'issue',
408
+ dimensions: [
409
+ { key: 'opened_at', label: nil },
410
+ { key: 'repo' }
411
+ ]
412
+ }
250
413
  }
251
414
  end
252
415
  let!(:issues) do
@@ -272,32 +435,456 @@ describe ReportsKit::Reports::Data::Generate do
272
435
  ]
273
436
  })
274
437
  end
438
+
439
+ context "with format: 'table'" do
440
+ subject { described_class.new(properties.merge(format: 'table'), context_record: context_record).perform }
441
+
442
+ it 'returns the table_data' do
443
+ expect(table_data).to eq([
444
+ [nil, repo.to_s, repo2.to_s],
445
+ [format_week_offset(2), 1, 0],
446
+ [format_week_offset(1), 0, 0],
447
+ [format_week_offset(0), 1, 1]
448
+ ])
449
+ end
450
+ end
451
+
452
+ context "with a data_format_method" do
453
+ subject { described_class.new(properties.merge(data_format_method: 'add_label_suffix'), context_record: context_record).perform }
454
+
455
+ it 'returns the chart_data' do
456
+ expect(chart_data).to eq({
457
+ labels: ["#{format_week_offset(2)} Foo", "#{format_week_offset(1)} Foo", "#{format_week_offset(0)} Foo"],
458
+ datasets: [
459
+ {
460
+ label: repo.to_s,
461
+ data: [1, 0, 1]
462
+ },
463
+ {
464
+ label: repo2.to_s,
465
+ data: [0, 0, 1]
466
+ }
467
+ ]
468
+ })
469
+ end
470
+ end
471
+ end
472
+
473
+ context 'with two measures' do
474
+ let(:properties) do
475
+ {
476
+ measures: [
477
+ {
478
+ key: 'issue',
479
+ dimensions: [{ key: 'created_at', label: nil }]
480
+ },
481
+ {
482
+ key: 'tag',
483
+ dimensions: %w(created_at)
484
+ },
485
+ ]
486
+ }
487
+ end
488
+ let!(:issues) do
489
+ [
490
+ create(:issue, repo: repo, created_at: now),
491
+ create(:issue, repo: repo, created_at: now - 2.weeks),
492
+ create(:issue, repo: repo2, created_at: now)
493
+ ]
494
+ end
495
+ let!(:tags) do
496
+ [
497
+ create(:tag, repo: repo, created_at: now - 1.week),
498
+ create(:tag, repo: repo, created_at: now - 2.weeks)
499
+ ]
500
+ end
501
+
502
+ it 'returns the chart_data' do
503
+ expect(chart_data).to eq({
504
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
505
+ datasets: [
506
+ {
507
+ label: 'Issues',
508
+ data: [1, 0, 2]
509
+ },
510
+ {
511
+ label: 'Tags',
512
+ data: [1, 1, 0]
513
+ }
514
+ ]
515
+ })
516
+ end
517
+
518
+ context "with format: 'table'" do
519
+ subject { described_class.new(properties.merge(format: 'table'), context_record: context_record).perform }
520
+
521
+ it 'returns the table_data' do
522
+ expect(table_data).to eq([
523
+ [nil, 'Issues', 'Tags'],
524
+ [format_week_offset(2), 1, 1],
525
+ [format_week_offset(1), 0, 1],
526
+ [format_week_offset(0), 2, 0]
527
+ ])
528
+ end
529
+ end
530
+ end
531
+
532
+ context 'with two dimensions' do
533
+ context 'with a custom aggregation' do
534
+ let(:properties) do
535
+ {
536
+ measure: {
537
+ key: 'issue',
538
+ aggregation: 'average_duration',
539
+ dimensions: %w(repo created_at)
540
+ }
541
+ }
542
+ end
543
+ let!(:issues) do
544
+ [
545
+ create(:issue, repo: repo, opened_at: now, closed_at: now),
546
+ create(:issue, repo: repo, opened_at: now - 2.weeks, closed_at: now),
547
+ create(:issue, repo: repo2, opened_at: now - 2.weeks, closed_at: now)
548
+ ]
549
+ end
550
+
551
+ it 'returns the chart_data' do
552
+ expect(chart_data).to eq({
553
+ labels: [repo2.to_s, repo.to_s],
554
+ datasets: [{ label: format_week_offset(0), data: [14, 7] }]
555
+ })
556
+ end
557
+ end
558
+ end
559
+
560
+ describe 'composite aggregations' do
561
+ context 'with two measures' do
562
+ let(:properties) do
563
+ {
564
+ name: name,
565
+ composite_operator: composite_operator,
566
+ measures: [
567
+ {
568
+ key: 'issue',
569
+ dimensions: %w(created_at)
570
+ },
571
+ {
572
+ key: 'tag',
573
+ dimensions: %w(created_at)
574
+ }
575
+ ]
576
+ }
577
+ end
578
+ let!(:issues) do
579
+ [
580
+ create(:issue, repo: repo, created_at: now),
581
+ create(:issue, repo: repo, created_at: now - 2.weeks),
582
+ create(:issue, repo: repo2, created_at: now)
583
+ ]
584
+ end
585
+ let!(:tags) do
586
+ [
587
+ create(:tag, repo: repo, created_at: now),
588
+ create(:tag, repo: repo, created_at: now - 1.week),
589
+ create(:tag, repo: repo, created_at: now - 1.week)
590
+ ]
591
+ end
592
+ let(:name) { 'My Name' }
593
+
594
+ context 'with +' do
595
+ let(:composite_operator) { '+' }
596
+
597
+ it 'returns the chart_data' do
598
+ expect(chart_data).to eq({
599
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
600
+ datasets: [
601
+ {
602
+ label: name,
603
+ data: [1, 2, 3]
604
+ }
605
+ ]
606
+ })
607
+ end
608
+ end
609
+
610
+ context 'with %' do
611
+ let(:composite_operator) { '%' }
612
+
613
+ it 'returns the chart_data' do
614
+ expect(chart_data).to eq({
615
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
616
+ datasets: [
617
+ {
618
+ label: name,
619
+ data: [0, 0, 200]
620
+ }
621
+ ]
622
+ })
623
+ end
624
+ end
625
+
626
+ context 'with % and a custom value_format_method' do
627
+ let(:composite_operator) { '%' }
628
+ let(:properties) do
629
+ {
630
+ name: name,
631
+ composite_operator: composite_operator,
632
+ value_format_method: 'format_percentage',
633
+ measures: [
634
+ {
635
+ key: 'issue',
636
+ dimensions: %w(created_at)
637
+ },
638
+ {
639
+ key: 'tag',
640
+ dimensions: %w(created_at)
641
+ }
642
+ ]
643
+ }
644
+ end
645
+
646
+ it 'returns the chart_data' do
647
+ expect(chart_data).to eq({
648
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
649
+ datasets: [
650
+ {
651
+ label: name,
652
+ data: ['0%', '0%', '200%']
653
+ }
654
+ ]
655
+ })
656
+ end
657
+ end
658
+
659
+ context 'with a boolean dimension' do
660
+ let!(:issues) do
661
+ [
662
+ create(:issue, locked: true),
663
+ create(:issue, locked: false),
664
+ create(:issue, locked: false)
665
+ ]
666
+ end
667
+ let(:composite_operator) { '+' }
668
+ let(:properties) do
669
+ {
670
+ name: name,
671
+ composite_operator: composite_operator,
672
+ measures: [
673
+ {
674
+ key: 'issue',
675
+ dimensions: %w(locked)
676
+ },
677
+ {
678
+ key: 'issue',
679
+ dimensions: %w(locked)
680
+ }
681
+ ]
682
+ }
683
+ end
684
+
685
+ it 'returns the chart_data' do
686
+ expect(chart_data).to eq({
687
+ labels: ['false', 'true'],
688
+ datasets: [
689
+ {
690
+ label: name,
691
+ data: [4, 2]
692
+ }
693
+ ]
694
+ })
695
+ end
696
+ end
697
+
698
+ context 'with a nested composite aggregation' do
699
+ let(:properties) do
700
+ {
701
+ measures: [
702
+ {
703
+ name: name,
704
+ composite_operator: '+',
705
+ measures: [
706
+ {
707
+ key: 'issue',
708
+ dimensions: %w(created_at)
709
+ },
710
+ {
711
+ key: 'tag',
712
+ dimensions: %w(created_at)
713
+ }
714
+ ]
715
+ },
716
+ {
717
+ key: 'issue',
718
+ dimensions: %w(created_at)
719
+ },
720
+ {
721
+ key: 'tag',
722
+ dimensions: %w(created_at)
723
+ }
724
+ ]
725
+ }
726
+ end
727
+
728
+ it 'returns the chart_data' do
729
+ expect(chart_data).to eq({
730
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
731
+ datasets: [
732
+ {
733
+ label: name,
734
+ data: [1, 2, 3]
735
+ },
736
+ {
737
+ label: 'Issues',
738
+ data: [1, 0, 2]
739
+ },
740
+ {
741
+ label: 'Tags',
742
+ data: [0, 2, 1]
743
+ }
744
+ ]
745
+ })
746
+ end
747
+
748
+ context 'with ui_filters' do
749
+ let(:properties) do
750
+ {
751
+ measures: [
752
+ {
753
+ name: name,
754
+ composite_operator: '+',
755
+ measures: [
756
+ {
757
+ key: 'issue',
758
+ filters: %w(created_at),
759
+ dimensions: %w(created_at)
760
+ },
761
+ {
762
+ key: 'tag',
763
+ filters: %w(created_at),
764
+ dimensions: %w(created_at)
765
+ }
766
+ ]
767
+ },
768
+ {
769
+ key: 'issue',
770
+ filters: %w(created_at),
771
+ dimensions: %w(created_at)
772
+ },
773
+ {
774
+ key: 'tag',
775
+ filters: %w(created_at),
776
+ dimensions: %w(created_at)
777
+ }
778
+ ],
779
+ ui_filters: {
780
+ created_at: "#{format_criteria_time(now - 1.week)} - #{format_criteria_time(now)}"
781
+ }
782
+ }
783
+ end
784
+
785
+ it 'returns the chart_data' do
786
+ expect(chart_data).to eq({
787
+ labels: [format_week_offset(1), format_week_offset(0)],
788
+ datasets: [
789
+ {
790
+ label: name,
791
+ data: [2, 3]
792
+ },
793
+ {
794
+ label: 'Issues',
795
+ data: [0, 2]
796
+ },
797
+ {
798
+ label: 'Tags',
799
+ data: [2, 1]
800
+ }
801
+ ]
802
+ })
803
+ end
804
+ end
805
+
806
+ context 'with two dimensions' do
807
+ let(:properties) do
808
+ {
809
+ measures: [
810
+ {
811
+ name: name,
812
+ composite_operator: '+',
813
+ measures: [
814
+ {
815
+ key: 'issue',
816
+ dimensions: %w(created_at repo)
817
+ },
818
+ {
819
+ key: 'tag',
820
+ dimensions: %w(created_at repo)
821
+ }
822
+ ]
823
+ }
824
+ ]
825
+ }
826
+ end
827
+
828
+ it 'returns the chart_data' do
829
+ expect(chart_data).to eq({
830
+ labels: [format_week_offset(2), format_week_offset(1), format_week_offset(0)],
831
+ datasets: [
832
+ {
833
+ label: repo.to_s,
834
+ data: [1, 2, 2]
835
+ },
836
+ {
837
+ label: repo2.to_s,
838
+ data: [0, 0, 1]
839
+ }
840
+ ]
841
+ })
842
+ end
843
+ end
844
+ end
845
+ end
275
846
  end
276
847
 
277
848
  # These examples allow for quick comparisons of many types of inputs and outputs.
278
849
  # When making functional modifications, run these to see whether the modifications impact the output in any cases.
279
850
  # If the output effects are desired, run `REWRITE_RESULTS=1 rspec` to write them to the outputs YAML file, then verify that the output
280
851
  # modifications are desired, then commit the result and uncomment the `skip`.
281
- describe 'chart options' do
852
+ describe 'YAML-based output comparisons' do
282
853
  FIXTURES_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'fixtures'))
283
854
 
284
855
  let(:inputs) { YAML.load_file("#{FIXTURES_DIRECTORY}/generate_inputs.yml") }
285
856
  let(:outputs_path) { "#{FIXTURES_DIRECTORY}/generate_outputs.yml" }
286
857
  let(:outputs) { YAML.load_file(outputs_path) }
287
858
 
859
+ let!(:repo) { create(:repo, full_name: 'foo/bar1') }
860
+ let!(:repo2) { create(:repo, full_name: 'foo/bar2') }
861
+ let!(:issues) do
862
+ [
863
+ create(:issue, repo: repo, state: 'open', opened_at: now - 2.weeks),
864
+ create(:issue, repo: repo, state: 'closed', opened_at: now)
865
+ ]
866
+ end
867
+ let!(:labels) do
868
+ [
869
+ create(:label, repo: repo),
870
+ create(:label, repo: repo2),
871
+ create(:label, repo: repo2)
872
+ ]
873
+ end
874
+
288
875
  context 'input examples' do
289
876
  YAML.load_file("#{FIXTURES_DIRECTORY}/generate_inputs.yml").each.with_index do |inputs, index|
290
- it 'returns the expected output' do
291
- expect(described_class.new(inputs).perform).to eq(outputs[index])
877
+ it "returns the expected output for input ##{index}: #{inputs.to_json}" do
878
+ expect(described_class.new(inputs).perform.to_yaml).to eq(outputs[index].to_yaml)
292
879
  end
293
880
  end
294
881
  end
295
882
 
296
883
  context 'writing the outputs' do
297
- # For documentation about this `skip`, see the comment at the top of this `describe` block.
298
- skip unless ENV['REWRITE_RESULTS'] == '1'
299
-
300
884
  it 'writes the outputs' do
885
+ # For documentation about this `skip`, see the comment at the top of this `describe` block.
886
+ skip unless ENV['REWRITE_RESULTS'] == '1'
887
+
301
888
  outputs = inputs.map do |example|
302
889
  described_class.new(example).perform
303
890
  end