picturehouse_uk 3.0.14 → 5.0.0

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 (63) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +26 -0
  3. data/.github/workflows/release.yml +26 -0
  4. data/.gitignore +1 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +44 -0
  7. data/LICENSE +617 -0
  8. data/README.md +5 -4
  9. data/Rakefile +12 -0
  10. data/lib/picturehouse_uk/cinema.rb +152 -127
  11. data/lib/picturehouse_uk/internal/api.rb +42 -0
  12. data/lib/picturehouse_uk/internal/parser/address.rb +36 -9
  13. data/lib/picturehouse_uk/internal/parser/screenings.rb +89 -95
  14. data/lib/picturehouse_uk/internal/title_sanitizer.rb +61 -65
  15. data/lib/picturehouse_uk/internal/website.rb +10 -12
  16. data/lib/picturehouse_uk/performance.rb +60 -0
  17. data/lib/picturehouse_uk/version.rb +2 -2
  18. data/lib/picturehouse_uk.rb +3 -4
  19. data/picturehouse_uk.gemspec +5 -7
  20. data/rake/fixture_creator.rb +62 -0
  21. data/test/fixtures/cinemas.html +4262 -0
  22. data/test/fixtures/duke-of-york-s-picturehouse/cinema.html +6187 -0
  23. data/test/fixtures/duke-of-york-s-picturehouse/get_movies.json +120552 -0
  24. data/test/fixtures/duke-of-york-s-picturehouse/information.html +3725 -0
  25. data/test/fixtures/duke-s-at-komedia/cinema.html +6138 -0
  26. data/test/fixtures/duke-s-at-komedia/get_movies.json +112 -0
  27. data/test/fixtures/duke-s-at-komedia/information.html +3690 -0
  28. data/test/fixtures/home.html +6236 -565
  29. data/test/fixtures/phoenix-picturehouse/cinema.html +6089 -0
  30. data/test/fixtures/phoenix-picturehouse/get_movies.json +120552 -0
  31. data/test/fixtures/phoenix-picturehouse/information.html +3630 -0
  32. data/test/lib/picturehouse_uk/cinema_test.rb +113 -142
  33. data/test/lib/picturehouse_uk/internal/api_test.rb +92 -0
  34. data/test/lib/picturehouse_uk/internal/parser/{address_parser_test.rb → address_test.rb} +11 -11
  35. data/test/lib/picturehouse_uk/internal/parser/screenings_test.rb +100 -48
  36. data/test/lib/picturehouse_uk/internal/title_sanitizer_test.rb +48 -48
  37. data/test/lib/picturehouse_uk/internal/website_test.rb +15 -31
  38. data/test/lib/picturehouse_uk/performance_test.rb +197 -0
  39. data/test/lib/picturehouse_uk/version_test.rb +1 -1
  40. data/test/live/integration_test.rb +15 -32
  41. data/test/support/fake_api.rb +16 -0
  42. data/test/support/fake_website.rb +24 -0
  43. data/test/test_helper.rb +13 -2
  44. metadata +52 -67
  45. data/.rdoc_options +0 -16
  46. data/.travis.yml +0 -5
  47. data/lib/picturehouse_uk/film.rb +0 -59
  48. data/lib/picturehouse_uk/screening.rb +0 -70
  49. data/test/fixture_updater.rb +0 -73
  50. data/test/fixtures/cinema/Duke_Of_Yorks.html +0 -2984
  51. data/test/fixtures/cinema/Dukes_At_Komedia.html +0 -5518
  52. data/test/fixtures/cinema/National_Media_Museum.html +0 -10266
  53. data/test/fixtures/cinema/Phoenix_Picturehouse.html +0 -5202
  54. data/test/fixtures/info/Duke_Of_Yorks.html +0 -549
  55. data/test/fixtures/info/Dukes_At_Komedia.html +0 -537
  56. data/test/fixtures/info/Phoenix_Picturehouse.html +0 -553
  57. data/test/fixtures/whats_on/Duke_Of_Yorks.html +0 -2737
  58. data/test/fixtures/whats_on/Dukes_At_Komedia.html +0 -5132
  59. data/test/fixtures/whats_on/National_Media_Museum.html +0 -9690
  60. data/test/fixtures/whats_on/Phoenix_Picturehouse.html +0 -4916
  61. data/test/lib/picturehouse_uk/film_test.rb +0 -141
  62. data/test/lib/picturehouse_uk/screening_test.rb +0 -181
  63. /data/{LICENSE.txt → COMM-LICENSE} +0 -0
@@ -2,251 +2,222 @@ require_relative '../../test_helper'
2
2
 
3
3
  describe PicturehouseUk::Cinema do
4
4
  let(:described_class) { PicturehouseUk::Cinema }
5
- let(:website) { MockWebsite.new }
5
+ let(:website) { FakeWebsite.new }
6
6
 
7
- before do
8
- WebMock.disable_net_connect!
9
- end
7
+ before { WebMock.disable_net_connect! }
8
+ after { WebMock.allow_net_connect! }
10
9
 
11
10
  describe '.all' do
12
11
  subject { described_class.all }
13
12
 
14
13
  it 'returns an Array of CineworldUK::Cinemas' do
15
14
  PicturehouseUk::Internal::Website.stub :new, website do
16
- subject.must_be_instance_of(Array)
15
+ _(subject).must_be_instance_of(Array)
17
16
  subject.each do |value|
18
- value.must_be_instance_of(PicturehouseUk::Cinema)
17
+ _(value).must_be_instance_of(PicturehouseUk::Cinema)
19
18
  end
20
19
  end
21
20
  end
22
21
 
23
22
  it 'returns the correctly sized array' do
24
23
  PicturehouseUk::Internal::Website.stub :new, website do
25
- subject.size.must_equal 22
24
+ _(subject.size).must_equal 25
26
25
  end
27
26
  end
28
27
 
29
28
  it 'returns the right cinemas' do
30
29
  PicturehouseUk::Internal::Website.stub :new, website do
31
- subject.first.name.must_equal 'Clapham Picturehouse'
32
- subject.last.name.must_equal 'City Screen Picturehouse'
30
+ _(subject.first.name).must_equal 'Little Theatre Cinema'
31
+ _(subject.last.name).must_equal 'City Screen York'
33
32
  end
34
33
  end
35
34
  end
36
35
 
37
- describe '.find(id)' do
38
- subject { described_class.find(id) }
39
-
40
- let(:id) { 'Duke_Of_Yorks' }
41
-
42
- it 'returns a cinema' do
43
- PicturehouseUk::Internal::Website.stub :new, website do
44
- subject.must_be_instance_of(PicturehouseUk::Cinema)
45
-
46
- subject.id.must_equal id
47
- subject.brand.must_equal 'Picturehouse'
48
- subject.name.must_equal "Duke of York's Picturehouse"
49
- subject.slug.must_equal 'duke-of-yorks-picturehouse'
50
- subject.url.must_equal "http://www.picturehouses.com/cinema/#{id}"
51
- end
52
- end
53
- end
54
-
55
- describe '.new(options)' do
56
- let(:options) do
57
- {
58
- id: 'Dukes_At_Komedia',
59
- name: "Duke's At Komedia",
60
- url: '/cinema/Dukes_At_Komedia'
61
- }
62
- end
63
-
64
- subject { described_class.new(options) }
36
+ describe '.new(id)' do
37
+ subject { described_class.new('duke-s-at-komedia') }
65
38
 
66
39
  it 'stores id, name, slug and url' do
67
- subject.id.must_equal 'Dukes_At_Komedia'
68
- subject.brand.must_equal 'Picturehouse'
69
- subject.name.must_equal "Duke's At Komedia"
70
- subject.slug.must_equal 'dukes-at-komedia'
71
- subject.url.must_equal 'http://www.picturehouses.com/cinema/Dukes_At_Komedia'
40
+ _(subject).must_be_instance_of(PicturehouseUk::Cinema)
72
41
  end
73
42
  end
74
43
 
75
44
  describe '#adr' do
76
- let(:options) do
77
- {
78
- id: 'Phoenix_Picturehouse',
79
- name: "Pheonix Picturehouse",
80
- url: '/cinema/Phoenix_Picturehouse'
81
- }
82
- end
45
+ subject { described_class.new(id).adr }
83
46
 
84
- describe '#adr' do
85
- subject { described_class.new(options).adr }
47
+ describe 'no region' do
48
+ let(:id) { 'phoenix-picturehouse' }
86
49
 
87
50
  it 'returns address hash' do
88
51
  PicturehouseUk::Internal::Website.stub :new, website do
89
- subject.must_equal(
52
+ _(subject).must_equal(
90
53
  street_address: '57 Walton Street',
91
54
  extended_address: nil,
92
55
  locality: 'Oxford',
93
56
  region: nil,
94
57
  postal_code: 'OX2 6AE',
95
- country: 'United Kingdom'
58
+ country_name: 'United Kingdom'
96
59
  )
97
60
  end
98
61
  end
99
62
  end
100
- end
101
-
102
- describe 'integration-y address tests' do
103
- let(:options) do
104
- {
105
- id: 'Dukes_At_Komedia',
106
- name: "Duke's At Komedia",
107
- url: '/cinema/Dukes_At_Komedia'
108
- }
109
- end
110
63
 
111
- describe '#adr' do
112
- subject { described_class.new(options).adr }
64
+ describe 'with region' do
65
+ let(:id) { 'duke-s-at-komedia' }
113
66
 
114
67
  it 'returns address hash' do
115
68
  PicturehouseUk::Internal::Website.stub :new, website do
116
- subject.must_equal(
69
+ _(subject).must_equal(
117
70
  street_address: '44–47 Gardner Street',
118
71
  extended_address: nil,
119
72
  locality: 'Brighton',
120
73
  region: 'East Sussex',
121
74
  postal_code: 'BN1 1UN',
122
- country: 'United Kingdom'
75
+ country_name: 'United Kingdom'
123
76
  )
124
77
  end
125
78
  end
126
79
  end
80
+ end
81
+
82
+ describe '#address' do
83
+ subject { described_class.new(id).address }
127
84
 
128
- describe '#street_address' do
129
- subject { described_class.new(options).street_address }
85
+ describe 'no region' do
86
+ let(:id) { 'phoenix-picturehouse' }
130
87
 
131
- it 'returns first line of address' do
88
+ it 'returns address hash' do
132
89
  PicturehouseUk::Internal::Website.stub :new, website do
133
- subject.must_equal('44–47 Gardner Street')
90
+ _(subject).must_equal(
91
+ street_address: '57 Walton Street',
92
+ extended_address: nil,
93
+ locality: 'Oxford',
94
+ region: nil,
95
+ postal_code: 'OX2 6AE',
96
+ country_name: 'United Kingdom'
97
+ )
134
98
  end
135
99
  end
136
100
  end
101
+ end
137
102
 
138
- describe '#extended_address' do
139
- subject { described_class.new(options).extended_address }
103
+ describe '#brand' do
104
+ subject { described_class.new(id).brand }
140
105
 
141
- it 'returns second line of address' do
142
- PicturehouseUk::Internal::Website.stub :new, website do
143
- subject.must_equal(nil)
144
- end
106
+ let(:id) { 'duke-s-at-komedia' }
107
+
108
+ it 'returns Picturehouse' do
109
+ PicturehouseUk::Internal::Website.stub :new, website do
110
+ _(subject).must_equal('Picturehouse')
145
111
  end
146
112
  end
113
+ end
147
114
 
148
- describe '#locality' do
149
- subject { described_class.new(options).locality }
115
+ describe '#country_name' do
116
+ subject { described_class.new(id).country_name }
150
117
 
151
- it 'returns second line of address' do
152
- PicturehouseUk::Internal::Website.stub :new, website do
153
- subject.must_equal('Brighton')
154
- end
118
+ let(:id) { 'duke-s-at-komedia' }
119
+
120
+ it 'returns country' do
121
+ PicturehouseUk::Internal::Website.stub :new, website do
122
+ _(subject).must_equal('United Kingdom')
155
123
  end
156
124
  end
125
+ end
157
126
 
158
- describe '#region' do
159
- subject { described_class.new(options).region }
127
+ describe '#extended_address' do
128
+ subject { described_class.new(id).extended_address }
160
129
 
161
- it 'returns second line of address' do
162
- PicturehouseUk::Internal::Website.stub :new, website do
163
- subject.must_equal('East Sussex')
164
- end
130
+ let(:id) { 'duke-s-at-komedia' }
131
+
132
+ it 'returns second line of address' do
133
+ PicturehouseUk::Internal::Website.stub :new, website do
134
+ _(subject).must_equal('')
165
135
  end
166
136
  end
137
+ end
138
+
139
+ describe '#full_name' do
140
+ subject { described_class.new(id).full_name }
167
141
 
168
- describe '#postal_code' do
169
- subject { described_class.new(options).postal_code }
142
+ let(:id) { 'duke-s-at-komedia' }
170
143
 
171
- it 'returns second line of address' do
172
- PicturehouseUk::Internal::Website.stub :new, website do
173
- subject.must_equal('BN1 1UN')
174
- end
144
+ it 'returns full name (same as name)' do
145
+ PicturehouseUk::Internal::Website.stub :new, website do
146
+ _(subject).must_equal("Duke's at Komedia")
147
+ _(subject).must_equal(described_class.new(id).name)
175
148
  end
176
149
  end
177
150
  end
178
151
 
179
- describe '#films' do
180
- let(:options) do
181
- {
182
- id: 'Dukes_At_Komedia',
183
- name: "Duke's At Komedia",
184
- url: '/cinema/Dukes_At_Komedia'
185
- }
186
- end
152
+ describe '#locality' do
153
+ subject { described_class.new(id).locality }
187
154
 
188
- subject { described_class.new(options).films }
155
+ let(:id) { 'duke-s-at-komedia' }
189
156
 
190
- it 'calls out to Film object' do
191
- PicturehouseUk::Film.stub :at, [:film] do
192
- subject.must_equal([:film])
157
+ it 'returns second line of address' do
158
+ PicturehouseUk::Internal::Website.stub :new, website do
159
+ _(subject).must_equal('Brighton')
193
160
  end
194
161
  end
195
162
  end
196
163
 
197
- describe '#full_name' do
198
- let(:options) do
199
- {
200
- id: 'Dukes_At_Komedia',
201
- name: "Duke's At Komedia",
202
- url: '/cinema/Dukes_At_Komedia'
203
- }
204
- end
164
+ describe '#name' do
165
+ subject { described_class.new(id).name }
205
166
 
206
- subject { described_class.new(options).full_name }
167
+ let(:id) { 'duke-s-at-komedia' }
207
168
 
208
- it 'returns the cinema name' do
209
- subject.must_equal "Duke's At Komedia"
169
+ it 'returns full name (same as name)' do
170
+ PicturehouseUk::Internal::Website.stub :new, website do
171
+ _(subject).must_equal("Duke's at Komedia")
172
+ end
210
173
  end
211
174
  end
212
175
 
213
- describe '#screenings' do
214
- let(:options) do
215
- {
216
- id: 'Dukes_At_Komedia',
217
- name: "Duke's At Komedia",
218
- url: '/cinema/Dukes_At_Komedia'
219
- }
220
- end
176
+ describe '#postal_code' do
177
+ subject { described_class.new(id).postal_code }
221
178
 
222
- subject { described_class.new(options).screenings }
179
+ let(:id) { 'duke-s-at-komedia' }
223
180
 
224
- it 'calls out to Screening object' do
225
- PicturehouseUk::Screening.stub :at, [:screening] do
226
- subject.must_equal([:screening])
181
+ it 'returns second line of address' do
182
+ PicturehouseUk::Internal::Website.stub :new, website do
183
+ _(subject).must_equal('BN1 1UN')
227
184
  end
228
185
  end
229
186
  end
230
187
 
231
- private
188
+ describe '#region' do
189
+ subject { described_class.new(id).region }
232
190
 
233
- class MockWebsite
234
- def home
235
- read_file('../../../fixtures/home.html')
236
- end
191
+ let(:id) { 'duke-s-at-komedia' }
237
192
 
238
- def cinema(filename)
239
- read_file("../../../fixtures/cinema/#{filename}.html")
193
+ it 'returns second line of address' do
194
+ PicturehouseUk::Internal::Website.stub :new, website do
195
+ _(subject).must_equal('East Sussex')
196
+ end
240
197
  end
198
+ end
241
199
 
242
- def info(filename)
243
- read_file("../../../fixtures/info/#{filename}.html")
200
+ describe '#slug' do
201
+ subject { described_class.new(id).slug }
202
+
203
+ let(:id) { 'duke-s-at-komedia' }
204
+
205
+ it 'returns downcased' do
206
+ PicturehouseUk::Internal::Website.stub :new, website do
207
+ _(subject).must_equal('dukes-at-komedia')
208
+ end
244
209
  end
210
+ end
211
+
212
+ describe '#street_address' do
213
+ subject { described_class.new(id).street_address }
245
214
 
246
- private
215
+ let(:id) { 'duke-s-at-komedia' }
247
216
 
248
- def read_file(filepath)
249
- File.read(File.expand_path(filepath, __FILE__))
217
+ it 'returns first line of address' do
218
+ PicturehouseUk::Internal::Website.stub :new, website do
219
+ _(subject).must_equal('44–47 Gardner Street')
220
+ end
250
221
  end
251
222
  end
252
223
  end
@@ -0,0 +1,92 @@
1
+ require_relative '../../../test_helper'
2
+
3
+ describe PicturehouseUk::Internal::Api do
4
+ let(:described_class) { PicturehouseUk::Internal::Api }
5
+
6
+ before { WebMock.disable_net_connect! }
7
+ after { WebMock.allow_net_connect! }
8
+
9
+ describe '#get_movies' do
10
+ let(:client) { described_class.new }
11
+ let(:cinema_id) { 'duke-s-at-komedia' }
12
+
13
+ it 'makes POST request to correct endpoint' do
14
+ stub_request(:post, 'https://www.picturehouses.com/api/get-movies-ajax')
15
+ .with do |request|
16
+ request.body.include?('start_date=show_all_dates') &&
17
+ request.body.include?("cinema_id=#{cinema_id}")
18
+ end
19
+ .to_return(
20
+ status: 200,
21
+ body: '{"response":"success","movies":[]}',
22
+ headers: { 'Content-Type' => 'application/json' }
23
+ )
24
+
25
+ result = client.get_movies(cinema_id)
26
+
27
+ _(result).must_be_instance_of(Hash)
28
+ _(result['response']).must_equal 'success'
29
+ end
30
+
31
+ it 'accepts custom date parameter' do
32
+ stub_request(:post, 'https://www.picturehouses.com/api/get-movies-ajax')
33
+ .with do |request|
34
+ request.body.include?('start_date=2024-11-01') &&
35
+ request.body.include?("cinema_id=#{cinema_id}")
36
+ end
37
+ .to_return(
38
+ status: 200,
39
+ body: '{"response":"success","movies":[]}',
40
+ headers: { 'Content-Type' => 'application/json' }
41
+ )
42
+
43
+ result = client.get_movies(cinema_id, '2024-11-01')
44
+
45
+ _(result['response']).must_equal 'success'
46
+ end
47
+
48
+ it 'returns empty hash on HTTP error' do
49
+ stub_request(:post, 'https://www.picturehouses.com/api/get-movies-ajax')
50
+ .to_return(status: 500, body: 'Internal Server Error')
51
+
52
+ result = client.get_movies(cinema_id)
53
+
54
+ _(result).must_equal({})
55
+ end
56
+
57
+ it 'returns empty hash on network error' do
58
+ stub_request(:post, 'https://www.picturehouses.com/api/get-movies-ajax')
59
+ .to_raise(StandardError.new('Network error'))
60
+
61
+ result = client.get_movies(cinema_id)
62
+
63
+ _(result).must_equal({})
64
+ end
65
+
66
+ it 'parses JSON response' do
67
+ response_body = {
68
+ 'response' => 'success',
69
+ 'movies' => [
70
+ {
71
+ 'Title' => 'Test Film',
72
+ 'ScheduledFilmId' => '12345',
73
+ 'movie_times' => []
74
+ }
75
+ ]
76
+ }.to_json
77
+
78
+ stub_request(:post, 'https://www.picturehouses.com/api/get-movies-ajax')
79
+ .to_return(
80
+ status: 200,
81
+ body: response_body,
82
+ headers: { 'Content-Type' => 'application/json' }
83
+ )
84
+
85
+ result = client.get_movies(cinema_id)
86
+
87
+ _(result).must_be_instance_of(Hash)
88
+ _(result['movies']).must_be_instance_of(Array)
89
+ _(result['movies'].first['Title']).must_equal 'Test Film'
90
+ end
91
+ end
92
+ end
@@ -12,13 +12,13 @@ describe PicturehouseUk::Internal::Parser::Address do
12
12
  let(:html) { nil }
13
13
 
14
14
  it 'returns hash of nils' do
15
- subject.must_be_instance_of(Hash)
16
- subject.must_equal(street_address: nil,
15
+ _(subject).must_be_instance_of(Hash)
16
+ _(subject).must_equal(street_address: nil,
17
17
  extended_address: nil,
18
18
  locality: nil,
19
19
  region: nil,
20
20
  postal_code: nil,
21
- country: "United Kingdom")
21
+ country_name: "United Kingdom")
22
22
  end
23
23
  end
24
24
 
@@ -26,13 +26,13 @@ describe PicturehouseUk::Internal::Parser::Address do
26
26
  let(:html) { '' }
27
27
 
28
28
  it 'returns hash of nils' do
29
- subject.must_be_instance_of(Hash)
30
- subject.must_equal(street_address: nil,
29
+ _(subject).must_be_instance_of(Hash)
30
+ _(subject).must_equal(street_address: nil,
31
31
  extended_address: nil,
32
32
  locality: nil,
33
33
  region: nil,
34
34
  postal_code: nil,
35
- country: "United Kingdom")
35
+ country_name: "United Kingdom")
36
36
  end
37
37
  end
38
38
 
@@ -40,13 +40,13 @@ describe PicturehouseUk::Internal::Parser::Address do
40
40
  let(:html) { 'not an address' }
41
41
 
42
42
  it 'returns hash of nils' do
43
- subject.must_be_instance_of(Hash)
44
- subject.must_equal(street_address: nil,
43
+ _(subject).must_be_instance_of(Hash)
44
+ _(subject).must_equal(street_address: nil,
45
45
  extended_address: nil,
46
- locality: "not an address",
46
+ locality: nil,
47
47
  region: nil,
48
- postal_code: "not an address",
49
- country: "United Kingdom")
48
+ postal_code: nil,
49
+ country_name: "United Kingdom")
50
50
  end
51
51
  end
52
52
  end
@@ -2,71 +2,123 @@ require_relative '../../../../test_helper'
2
2
 
3
3
  describe PicturehouseUk::Internal::Parser::Screenings do
4
4
  let(:described_class) { PicturehouseUk::Internal::Parser::Screenings }
5
+ let(:api_client) { FakeApi.new }
5
6
 
6
- let(:website) { Minitest::Mock.new }
7
+ before { WebMock.disable_net_connect! }
8
+ after { WebMock.allow_net_connect! }
7
9
 
8
- before do
9
- WebMock.disable_net_connect!
10
- end
10
+ describe '#to_a' do
11
+ subject { described_class.new('duke-s-at-komedia').to_a }
11
12
 
12
- %w(Duke_Of_Yorks Dukes_At_Komedia Phoenix_Picturehouse).each do |cinema|
13
- describe "#{cinema}: #to_a" do
14
- subject { described_class.new(cinema).to_a }
15
-
16
- before { website.expect(:whats_on, html(cinema), [cinema]) }
17
-
18
- it 'returns an non-zero array of hashes' do
19
- PicturehouseUk::Internal::Website.stub :new, website do
20
- subject.must_be_instance_of(Array)
21
- subject.size.must_be :>, 0
22
-
23
- subject.each do |element|
24
- element.must_be_instance_of(Hash)
25
- element.keys.must_equal([:film_name, :dimension, :variant, :booking_url, :time])
26
- element[:film_name].must_be_kind_of(String)
27
- element[:dimension].must_match(/\A[23]d\z/)
28
- if element[:booking_url]
29
- element[:booking_url].must_match(/\Ahttps?\:\/\//)
30
- element[:booking_url].must_match(/ticketing/)
31
- element[:booking_url].must_match(/visSelectTickets\.aspx\?cinemacode=\d+\&txtSessionId=\d+/)
32
- end
33
- element[:time].must_be_kind_of(Time)
34
- end
35
-
36
- variants = subject.flat_map { |e| e[:variant] }.uniq
37
- %w(arts baby senior).each do |expected| # also kids
38
- variants.must_include(expected)
39
- end
13
+ it 'returns an array of hashes' do
14
+ PicturehouseUk::Internal::Api.stub :new, api_client do
15
+ _(subject).must_be_instance_of(Array)
16
+ subject.each do |element|
17
+ _(element).must_be_instance_of(Hash)
40
18
  end
41
19
  end
42
20
  end
43
- end
44
21
 
45
- %w(National_Media_Museum).each do |cinema|
46
- describe "#{cinema}: #to_a" do
47
- subject { described_class.new(cinema).to_a }
22
+ it 'has correct hash keys' do
23
+ PicturehouseUk::Internal::Api.stub :new, api_client do
24
+ subject.each do |element|
25
+ _(element.keys.sort).must_equal([:booking_url, :dimension, :film_name, :starting_at, :variant].sort)
26
+ end
27
+ end
28
+ end
48
29
 
49
- before { website.expect(:whats_on, html(cinema), [cinema]) }
30
+ it 'has valid film names' do
31
+ PicturehouseUk::Internal::Api.stub :new, api_client do
32
+ film_names = subject.map { |s| s[:film_name] }.uniq
33
+ _(film_names).must_include 'The Holdovers'
34
+ _(film_names).must_include 'The Marvels'
35
+ end
36
+ end
50
37
 
51
- it 'returns an non-zero array of hashes with imax variants' do
52
- PicturehouseUk::Internal::Website.stub :new, website do
53
- subject.must_be_instance_of(Array)
54
- subject.size.must_be :>, 0
38
+ it 'correctly identifies dimensions' do
39
+ PicturehouseUk::Internal::Api.stub :new, api_client do
40
+ subject.each do |element|
41
+ _(element[:dimension]).must_match(/\A[23]d\z/)
42
+ end
43
+ end
44
+ end
45
+
46
+ it 'generates booking URLs with correct format' do
47
+ PicturehouseUk::Internal::Api.stub :new, api_client do
48
+ subject.each do |element|
49
+ _(element[:booking_url]).must_match(%r{\Ahttps://web\.picturehouses\.com/order/showtimes/})
50
+ _(element[:booking_url]).must_match(%r{/duke-s-at-komedia-\d+/seats\z})
51
+ end
52
+ end
53
+ end
55
54
 
56
- variants = subject.flat_map { |e| e[:variant] }.uniq
57
- variants.must_include('imax')
55
+ it 'parses starting_at as Time objects' do
56
+ PicturehouseUk::Internal::Api.stub :new, api_client do
57
+ subject.each do |element|
58
+ _(element[:starting_at]).must_be_kind_of(Time)
59
+ _(element[:starting_at]).wont_equal Time.utc(1970, 1, 1, 0, 0)
58
60
  end
59
61
  end
60
62
  end
63
+
64
+ it 'extracts variant arrays' do
65
+ PicturehouseUk::Internal::Api.stub :new, api_client do
66
+ variants = subject.flat_map { |e| e[:variant] }.uniq
67
+ _(variants).must_include('kids')
68
+ _(variants).must_include('senior')
69
+ _(variants).must_include('arts')
70
+ end
71
+ end
72
+
73
+ it 'identifies 3D films from title' do
74
+ PicturehouseUk::Internal::Api.stub :new, api_client do
75
+ three_d_films = subject.select { |s| s[:dimension] == '3d' }
76
+ _(three_d_films).wont_be_empty
77
+ three_d_films.each do |screening|
78
+ _(screening[:film_name]).must_match(/Marvels/i)
79
+ end
80
+ end
81
+ end
82
+
83
+ it 'skips sold out screenings' do
84
+ PicturehouseUk::Internal::Api.stub :new, api_client do
85
+ # Our fixture has 9 total screenings but none with SoldoutStatus == 2
86
+ _(subject.count).must_equal 8
87
+ end
88
+ end
61
89
  end
62
90
 
63
- private
91
+ describe 'with empty response' do
92
+ let(:empty_client) do
93
+ Class.new do
94
+ def get_movies(_cinema_id, _date = 'show_all_dates')
95
+ { 'response' => 'error', 'movies' => [] }
96
+ end
97
+ end.new
98
+ end
64
99
 
65
- def read_file(filepath)
66
- File.read(File.expand_path(filepath, __FILE__))
100
+ it 'returns empty array for error response' do
101
+ PicturehouseUk::Internal::Api.stub :new, empty_client do
102
+ result = described_class.new('nonexistent').to_a
103
+ _(result).must_equal []
104
+ end
105
+ end
67
106
  end
68
107
 
69
- def html(cinema)
70
- read_file("../../../../../fixtures/whats_on/#{cinema}.html")
108
+ describe 'with missing movies key' do
109
+ let(:missing_movies_client) do
110
+ Class.new do
111
+ def get_movies(_cinema_id, _date = 'show_all_dates')
112
+ { 'response' => 'success' }
113
+ end
114
+ end.new
115
+ end
116
+
117
+ it 'returns empty array when movies key missing' do
118
+ PicturehouseUk::Internal::Api.stub :new, missing_movies_client do
119
+ result = described_class.new('test').to_a
120
+ _(result).must_equal []
121
+ end
122
+ end
71
123
  end
72
124
  end