odeon_uk 4.0.0 → 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 (72) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +43 -0
  3. data/.gitignore +1 -1
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +33 -0
  6. data/README.md +90 -21
  7. data/Rakefile +14 -15
  8. data/lib/odeon_uk/cinema.rb +41 -23
  9. data/lib/odeon_uk/internal/api_response.rb +19 -39
  10. data/lib/odeon_uk/internal/guest_token.rb +23 -0
  11. data/lib/odeon_uk/internal/parser/api/showtime.rb +80 -0
  12. data/lib/odeon_uk/internal/title_sanitizer.rb +3 -8
  13. data/lib/odeon_uk/performance.rb +34 -40
  14. data/lib/odeon_uk/version.rb +3 -3
  15. data/lib/odeon_uk.rb +16 -2
  16. data/odeon_uk.gemspec +10 -6
  17. data/test/fixtures/api/showtimes-824.json +66 -0
  18. data/test/fixtures/api/sites.json +32 -0
  19. data/test/lib/odeon_uk/cinema_test.rb +66 -215
  20. data/test/lib/odeon_uk/internal/api_response_test.rb +48 -29
  21. data/test/lib/odeon_uk/internal/fixture_shape_test.rb +14 -0
  22. data/test/lib/odeon_uk/internal/guest_token_test.rb +84 -0
  23. data/test/lib/odeon_uk/internal/parser/api/showtime_test.rb +68 -0
  24. data/test/lib/odeon_uk/internal/title_sanitizer_test.rb +109 -89
  25. data/test/lib/odeon_uk/performance_test.rb +124 -123
  26. data/test/lib/odeon_uk/version_test.rb +3 -3
  27. data/test/live/api_shape_test.rb +19 -0
  28. data/test/live/integration_test.rb +21 -0
  29. data/test/live/live_helper.rb +11 -0
  30. data/test/package_test.rb +56 -0
  31. data/test/support/api_fixtures_helper.rb +5 -30
  32. data/test/support/api_shapes.rb +46 -0
  33. data/test/support/fake_api_response.rb +9 -6
  34. data/test/test_helper.rb +6 -3
  35. metadata +66 -89
  36. data/.travis.yml +0 -7
  37. data/lib/odeon_uk/internal/parser/api/film_lookup.rb +0 -34
  38. data/lib/odeon_uk/internal/parser/api/performance_day.rb +0 -92
  39. data/rake/fixture_creator.rb +0 -46
  40. data/test/fixtures/api/all_cinemas.plist +0 -0
  41. data/test/fixtures/api/app_init.plist +0 -0
  42. data/test/fixtures/api/film_times/71-14876.plist +0 -0
  43. data/test/fixtures/api/film_times/71-15408.plist +0 -0
  44. data/test/fixtures/api/film_times/71-15684.plist +0 -0
  45. data/test/fixtures/api/film_times/71-15866.plist +0 -0
  46. data/test/fixtures/api/film_times/71-15868.plist +0 -0
  47. data/test/fixtures/api/film_times/71-15961.plist +0 -0
  48. data/test/fixtures/api/film_times/71-15963.plist +0 -0
  49. data/test/fixtures/api/film_times/71-15965.plist +0 -0
  50. data/test/fixtures/api/film_times/71-15967.plist +0 -0
  51. data/test/fixtures/api/film_times/71-15969.plist +0 -0
  52. data/test/fixtures/api/film_times/71-15977.plist +0 -0
  53. data/test/fixtures/api/film_times/71-15980.plist +0 -0
  54. data/test/fixtures/api/film_times/71-16037.plist +0 -0
  55. data/test/fixtures/api/film_times/71-16136.plist +0 -0
  56. data/test/fixtures/api/film_times/71-16142.plist +0 -0
  57. data/test/fixtures/api/film_times/71-16143.plist +0 -0
  58. data/test/fixtures/api/film_times/71-16187.plist +0 -0
  59. data/test/fixtures/api/film_times/71-16369.plist +0 -0
  60. data/test/fixtures/api/film_times/71-16370.plist +0 -0
  61. data/test/fixtures/api/film_times/71-16374.plist +0 -0
  62. data/test/fixtures/api/film_times/71-16386.plist +0 -0
  63. data/test/fixtures/api/film_times/71-16387.plist +0 -0
  64. data/test/fixtures/api/film_times/71-16388.plist +0 -0
  65. data/test/fixtures/api/film_times/71-16438.plist +0 -0
  66. data/test/fixtures/api/film_times/71-16454.plist +0 -0
  67. data/test/fixtures/api/film_times/71-16457.plist +0 -0
  68. data/test/fixtures/api/film_times/71-16477.plist +0 -0
  69. data/test/fixtures/api/film_times/71-16478.plist +0 -0
  70. data/test/fixtures/api/film_times/71-16480.plist +0 -0
  71. data/test/fixtures/api/film_times/71-16482.plist +0 -0
  72. data/test/fixtures/api/film_times/71-16489.plist +0 -0
@@ -20,18 +20,25 @@ module OdeonUk
20
20
  # @option options [String] :dimension ('2d') dimension of the screening
21
21
  # @option options [String] :film_name name of the film
22
22
  # @option options [Time] :starting_at listed start time of the performance
23
+ # @option options [Cinebase::Festival] :festival (nil) festival edition
24
+ # @option options [String] :language (nil) audio language of the screening
23
25
 
24
- # All currently listed films showing at a cinema
25
- # @param [Integer] cinema_id id of the cinema on the website
26
+ # Performances within an inclusive range of cinema business dates.
27
+ # @param [Integer, String] cinema_id id of the cinema on the website
28
+ # @param [Date] from first date (defaults to today in London)
29
+ # @param [Date] to last date (defaults to 13 days after from)
26
30
  # @return [Array<OdeonUk::Performance>]
27
- def self.at(cinema_id)
28
- film_ids_at(cinema_id).flat_map do |film_id|
29
- api_response.film_times(cinema_id, film_id).flat_map do |day|
30
- performance_days(day).map do |hash|
31
- new(hash.merge(cinema_hash(cinema_id))
32
- .merge(film_name: film_name(film_id)))
33
- end
34
- end
31
+ def self.at(
32
+ cinema_id,
33
+ from: TZInfo::Timezone.get('Europe/London').now.to_date,
34
+ to: from + 13
35
+ )
36
+ raise ArgumentError, 'to must not precede from' if to < from
37
+
38
+ api = OdeonUk::Internal::ApiResponse.new
39
+ cinema = Cinema.new(cinema_id)
40
+ (from..to).flat_map do |date|
41
+ performances_on(api, cinema, date)
35
42
  end
36
43
  end
37
44
 
@@ -47,41 +54,28 @@ module OdeonUk
47
54
  # The kinds of screening (IMAX, kids, baby, senior)
48
55
  # @return <Array[String]>
49
56
 
50
- # private
51
-
52
- def self.api_response
53
- @api_response ||= OdeonUk::Internal::ApiResponse.new
54
- end
55
- private_class_method :api_response
56
-
57
- def self.cinema_hash(cinema_id)
58
- { cinema_id: cinema_id, cinema_name: Cinema.new(cinema_id).name }
59
- end
60
- private_class_method :cinema_hash
61
-
62
- def self.films_at(cinema_id)
63
- film_lookup.at(cinema_id)
64
- end
65
- private_class_method :films_at
66
57
 
67
- def self.film_lookup
68
- @film_lookup ||= OdeonUk::Internal::Parser::Api::FilmLookup.new
69
- end
70
- private_class_method :film_lookup
58
+ # private
71
59
 
72
- def self.film_ids_at(cinema_id)
73
- films_at(cinema_id).keys
74
- end
75
- private_class_method :film_ids_at
60
+ def self.performances_on(api, cinema, date)
61
+ response = api.showtimes(cinema.id, date)
62
+ related = response.fetch('relatedData')
63
+ films = by_id(related.fetch('films'))
64
+ attributes = by_id(related.fetch('attributes'))
76
65
 
77
- def self.film_name(film_id)
78
- film_lookup.to_hash[film_id]['title']
66
+ response.fetch('showtimes').map do |data|
67
+ showtime = OdeonUk::Internal::Parser::Api::Showtime.new(
68
+ data, films: films, attributes: attributes
69
+ )
70
+ new(showtime.to_hash.merge(cinema_id: cinema.id,
71
+ cinema_name: cinema.name))
72
+ end
79
73
  end
80
- private_class_method :film_name
74
+ private_class_method :performances_on
81
75
 
82
- def self.performance_days(data)
83
- OdeonUk::Internal::Parser::Api::PerformanceDay.new(data).to_a
76
+ def self.by_id(items)
77
+ items.to_h { |item| [item.fetch('id'), item] }
84
78
  end
85
- private_class_method :performance_days
79
+ private_class_method :by_id
86
80
  end
87
81
  end
@@ -1,6 +1,6 @@
1
- # Ruby interface for http://www.odeon.co.uk
2
- # @version 4.0.0
1
+ # Ruby interface for https://www.odeon.co.uk
2
+ # @version 5.0.0
3
3
  module OdeonUk
4
4
  # Gem version
5
- VERSION = '4.0.0'.freeze
5
+ VERSION = '5.0.0'.freeze
6
6
  end
data/lib/odeon_uk.rb CHANGED
@@ -1,16 +1,30 @@
1
+ require 'json'
2
+
1
3
  require 'cinebase'
4
+ require 'cinebase/vista'
2
5
 
3
6
  require_relative './odeon_uk/version'
4
7
 
5
8
  require_relative './odeon_uk/internal/api_response'
9
+ require_relative './odeon_uk/internal/guest_token'
6
10
  require_relative './odeon_uk/internal/title_sanitizer'
7
11
 
8
- require_relative './odeon_uk/internal/parser/api/film_lookup'
9
- require_relative './odeon_uk/internal/parser/api/performance_day'
12
+ require_relative './odeon_uk/internal/parser/api/showtime'
10
13
 
11
14
  require_relative './odeon_uk/cinema'
12
15
  require_relative './odeon_uk/performance'
13
16
 
14
17
  # odeon_uk gem
15
18
  module OdeonUk
19
+ AuthenticationError = Cinebase::Vista::AuthenticationError
20
+
21
+ # A raw guest JWT, without the "Bearer " prefix. Never persisted by the gem.
22
+ class << self
23
+ attr_accessor :token
24
+
25
+ # Explicit acquisition/renewal; ordinary API calls never launch a subprocess.
26
+ def acquire_token!(curl: nil)
27
+ self.token = Internal::GuestToken.new(curl: curl).fetch
28
+ end
29
+ end
16
30
  end
data/odeon_uk.gemspec CHANGED
@@ -7,21 +7,25 @@ Gem::Specification.new do |spec|
7
7
  spec.version = OdeonUk::VERSION
8
8
  spec.authors = ['Andy Croll']
9
9
  spec.email = ['andy@goodscary.com']
10
- spec.description = 'Pull movie & cinema information from the Odeon iOS API'
10
+ spec.description = 'Pull movie & cinema information from the ODEON Vista API'
11
11
  spec.summary = "It's a scraper, but a nice one"
12
- spec.homepage = 'http://github.com/andycroll/odeon_uk'
12
+ spec.homepage = 'https://github.com/andycroll/odeon_uk'
13
13
  spec.licenses = %w(AGPL MIT)
14
14
 
15
- spec.files = `git ls-files`.split($RS)
15
+ spec.required_ruby_version = '>= 3.4'
16
+
17
+ spec.files = `git ls-files`.split("\n")
16
18
  spec.executables = spec.files.grep(%r{^bin/}).map { |f| File.basename(f) }
17
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
20
  spec.require_paths = ['lib']
19
21
 
20
- spec.add_development_dependency 'codeclimate-test-reporter'
22
+ spec.add_development_dependency 'base64'
23
+ spec.add_development_dependency 'bundler', '>= 2.0'
24
+ spec.add_development_dependency 'minitest-mock'
21
25
  spec.add_development_dependency 'minitest-reporters'
22
26
  spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'simplecov', '< 1'
23
28
  spec.add_development_dependency 'webmock'
24
29
 
25
- spec.add_runtime_dependency 'CFPropertyList'
26
- spec.add_runtime_dependency 'cinebase', '~> 3.0'
30
+ spec.add_runtime_dependency 'cinebase', '~> 5.2'
27
31
  end
@@ -0,0 +1,66 @@
1
+ {
2
+ "businessDate": "2026-10-24",
3
+ "showtimes": [
4
+ {
5
+ "id": "824-1001",
6
+ "filmId": "FILM-1",
7
+ "schedule": { "startsAt": "2026-10-24T09:00:00+01:00" },
8
+ "attributeIds": ["A-AD"],
9
+ "requires3dGlasses": false
10
+ },
11
+ {
12
+ "id": "824-1002",
13
+ "filmId": "FILM-1",
14
+ "schedule": { "startsAt": "2026-10-24T14:30:00+01:00" },
15
+ "attributeIds": ["A-3D", "A-IMAX"],
16
+ "requires3dGlasses": true
17
+ },
18
+ {
19
+ "id": "824-1003",
20
+ "filmId": "FILM-2",
21
+ "schedule": { "startsAt": "2026-10-24T18:00:00+01:00" },
22
+ "attributeIds": ["A-KOREAN", "A-SUB", "A-EVENT"],
23
+ "requires3dGlasses": false
24
+ },
25
+ {
26
+ "id": "824-1004",
27
+ "filmId": "FILM-3",
28
+ "schedule": { "startsAt": "2026-10-24T20:15:00+01:00" },
29
+ "attributeIds": ["A-TAMIL", "A-SUB"],
30
+ "requires3dGlasses": false
31
+ },
32
+ {
33
+ "id": "824-1005",
34
+ "filmId": "FILM-4",
35
+ "schedule": { "startsAt": "2026-10-24T10:00:00+01:00" },
36
+ "attributeIds": ["A-KIDS", "A-CAPT"],
37
+ "requires3dGlasses": false
38
+ },
39
+ {
40
+ "id": "824-1006",
41
+ "filmId": "FILM-1",
42
+ "schedule": { "startsAt": "2026-10-25T00:15:00+01:00" },
43
+ "attributeIds": [],
44
+ "requires3dGlasses": false
45
+ }
46
+ ],
47
+ "relatedData": {
48
+ "films": [
49
+ { "id": "FILM-1", "title": { "text": "The Example Film 3D" } },
50
+ { "id": "FILM-2", "title": { "text": "Made Up Concert: Live" } },
51
+ { "id": "FILM-3", "title": { "text": "Imaginary Picture (Tamil)" } },
52
+ { "id": "FILM-4", "title": { "text": "Pretend Pups" } }
53
+ ],
54
+ "attributes": [
55
+ { "id": "A-AD", "shortName": { "text": "AudioDes" }, "name": { "text": "Audio Described" } },
56
+ { "id": "A-3D", "shortName": { "text": "3D" }, "name": { "text": "3D" } },
57
+ { "id": "A-IMAX", "shortName": { "text": "IMAX" }, "name": { "text": "IMAX" } },
58
+ { "id": "A-KOREAN", "shortName": { "text": "KoreanLang" }, "name": { "text": "Korean (Audio)" } },
59
+ { "id": "A-TAMIL", "shortName": { "text": "TamilA" }, "name": { "text": "Tamil (Audio)" } },
60
+ { "id": "A-SUB", "shortName": { "text": "EnglishSub" }, "name": { "text": "English (Sub)" } },
61
+ { "id": "A-EVENT", "shortName": { "text": "EventCinem" }, "name": { "text": "Event Cinema" } },
62
+ { "id": "A-KIDS", "shortName": { "text": "ODEON Kids" }, "name": { "text": "ODEON Kids" } },
63
+ { "id": "A-CAPT", "shortName": { "text": "OpenCapt" }, "name": { "text": "Open Captioned" } }
64
+ ]
65
+ }
66
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "sites": [
3
+ {
4
+ "id": "017",
5
+ "name": { "text": "Birmingham New Street" },
6
+ "contactDetails": {
7
+ "address": { "line1": "1 Example Arcade", "line2": "New Street", "city": "Birmingham" }
8
+ }
9
+ },
10
+ {
11
+ "id": "153",
12
+ "name": { "text": "London Leicester Square" },
13
+ "contactDetails": {
14
+ "address": { "line1": "2 Example Square", "line2": "", "city": "London" }
15
+ }
16
+ },
17
+ {
18
+ "id": "824",
19
+ "name": { "text": "Brighton" },
20
+ "contactDetails": {
21
+ "address": { "line1": "3 Example Parade", "line2": "Seafront", "city": "Brighton" }
22
+ }
23
+ },
24
+ {
25
+ "id": "955",
26
+ "name": { "text": "Trafford Centre" },
27
+ "contactDetails": {
28
+ "address": { "line1": "4 Example Dome", "line2": "", "city": "Manchester" }
29
+ }
30
+ }
31
+ ]
32
+ }
@@ -1,262 +1,113 @@
1
1
  require_relative '../../test_helper'
2
2
 
3
- describe OdeonUk::Cinema do
4
- include ApiFixturesHelper
5
-
6
- let(:described_class) { OdeonUk::Cinema }
7
- let(:api_response) { FakeApiResponse.new }
8
-
9
- before { WebMock.disable_net_connect! }
10
- after { WebMock.allow_net_connect! }
11
-
12
- describe '.new(id)' do
13
- subject { described_class.new(id) }
14
-
15
- describe 'Brighton' do
16
- let(:id) { 71 }
17
-
18
- it 'returns a cinema with a string id' do
19
- subject.must_be_instance_of(described_class)
20
- subject.id.must_equal(id.to_s)
21
- end
22
- end
3
+ class OdeonUk::CinemaTest < Minitest::Test
4
+ def setup
5
+ @api_response = FakeApiResponse.new
23
6
  end
24
7
 
25
- describe '.all' do
26
- subject { described_class.all }
8
+ def test_new_returns_cinema_with_string_id
9
+ cinema = OdeonUk::Cinema.new(824)
27
10
 
28
- it 'returns an array of cinemas' do
29
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
30
- subject.must_be_instance_of(Array)
31
- subject.each do |element|
32
- element.must_be_instance_of(described_class)
33
- end
34
- subject.count.must_be :>, 100
35
- end
36
- end
11
+ assert_instance_of OdeonUk::Cinema, cinema
12
+ assert_equal '824', cinema.id
37
13
  end
38
14
 
39
- describe '#adr' do
40
- subject { described_class.new(id).adr }
41
-
42
- describe 'short address' do
43
- let(:id) { 71 }
44
-
45
- it 'returns the postcode' do
46
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
47
- subject.must_equal(street_address: 'Kingswest',
48
- extended_address: nil,
49
- locality: 'Brighton',
50
- region: nil,
51
- postal_code: 'BN1 2RE',
52
- country_name: 'United Kingdom')
53
- end
54
- end
55
- end
15
+ def test_new_zero_pads_id
16
+ assert_equal '017', OdeonUk::Cinema.new(17).id
56
17
  end
57
18
 
58
- describe '#address' do
59
- subject { described_class.new(id).address }
60
-
61
- describe 'London address' do
62
- let(:id) { 105 }
19
+ def test_all_returns_cinemas
20
+ with_fake_api do
21
+ cinemas = OdeonUk::Cinema.all
63
22
 
64
- it 'returns the postcode' do
65
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
66
- subject.must_equal(street_address: '24-26 Leicester Square',
67
- extended_address: nil,
68
- locality: 'London',
69
- region: nil,
70
- postal_code: 'WC2H 7JY',
71
- country_name: 'United Kingdom')
72
- end
73
- end
23
+ assert(cinemas.all? { |cinema| cinema.instance_of?(OdeonUk::Cinema) })
24
+ assert_equal %w(017 153 824 955), cinemas.map(&:id)
74
25
  end
75
26
  end
76
27
 
77
- describe '#brand' do
78
- subject { described_class.new(id).brand }
79
- describe 'short address' do
80
- let(:id) { 71 }
28
+ def test_adr_has_no_postcode
29
+ expected = {
30
+ street_address: '3 Example Parade',
31
+ extended_address: 'Seafront',
32
+ locality: 'Brighton',
33
+ region: nil,
34
+ postal_code: nil,
35
+ country_name: 'United Kingdom'
36
+ }
81
37
 
82
- it 'returns the postcode' do
83
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
84
- subject.must_equal 'Odeon'
85
- end
86
- end
38
+ with_fake_api do
39
+ assert_equal expected, OdeonUk::Cinema.new(824).adr
87
40
  end
88
41
  end
89
42
 
90
- describe '#country_name' do
91
- subject { described_class.new(id).country_name }
92
- describe 'short address' do
93
- let(:id) { 71 }
43
+ def test_address_for_london
44
+ expected = {
45
+ street_address: '2 Example Square',
46
+ extended_address: '',
47
+ locality: 'London',
48
+ region: nil,
49
+ postal_code: nil,
50
+ country_name: 'United Kingdom'
51
+ }
94
52
 
95
- it 'returns the postcode' do
96
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
97
- subject.must_equal 'United Kingdom'
98
- end
99
- end
53
+ with_fake_api do
54
+ assert_equal expected, OdeonUk::Cinema.new(153).address
100
55
  end
101
56
  end
102
57
 
103
- describe '#extended_address' do
104
- subject { described_class.new(id).extended_address }
105
- describe 'short address' do
106
- let(:id) { 71 }
107
-
108
- it 'returns the postcode' do
109
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
110
- subject.must_equal ''
111
- end
112
- end
113
- end
58
+ def test_brand
59
+ assert_equal 'Odeon', OdeonUk::Cinema.new(824).brand
114
60
  end
115
61
 
116
- describe '#full_name' do
117
- subject { described_class.new(id).full_name }
118
- describe 'Brighton' do
119
- let(:id) { 71 }
120
-
121
- it 'returns cinema name' do
122
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
123
- subject.must_equal 'Odeon Brighton'
124
- end
125
- end
126
- end
127
-
128
- describe 'Leicester Square' do
129
- let(:id) { 105 }
130
-
131
- it 'returns cinema name' do
132
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
133
- subject.must_equal 'Odeon Leicester Square'
134
- end
135
- end
62
+ def test_full_name
63
+ with_fake_api do
64
+ assert_equal 'Odeon Brighton', OdeonUk::Cinema.new(824).full_name
65
+ assert_equal 'Odeon Leicester Square', OdeonUk::Cinema.new(153).full_name
136
66
  end
137
67
  end
138
68
 
139
- describe '#locality' do
140
- subject { described_class.new(id).locality }
141
- describe 'Short Address (Brighton)' do
142
- let(:id) { 71 }
143
-
144
- it 'returns town name' do
145
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
146
- subject.must_equal 'Brighton'
147
- end
148
- end
69
+ def test_name_removes_london_prefix
70
+ with_fake_api do
71
+ assert_equal 'Leicester Square', OdeonUk::Cinema.new(153).name
149
72
  end
150
73
  end
151
74
 
152
- describe '#name' do
153
- subject { described_class.new(id).name }
154
- describe 'Brighton' do
155
- let(:id) { 71 }
156
-
157
- it 'returns cinema name' do
158
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
159
- subject.must_equal 'Brighton'
160
- end
161
- end
162
- end
163
-
164
- describe 'Leicester Square' do
165
- let(:id) { 105 }
166
-
167
- it 'returns cinema name' do
168
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
169
- subject.must_equal 'Leicester Square'
170
- end
171
- end
75
+ def test_postal_code_is_empty
76
+ with_fake_api do
77
+ assert_equal '', OdeonUk::Cinema.new(824).postal_code
172
78
  end
173
79
  end
174
80
 
175
- describe '#postal_code' do
176
- subject { described_class.new(id).postal_code }
177
- describe 'short address' do
178
- let(:id) { 71 }
179
-
180
- it 'returns the postcode' do
181
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
182
- subject.must_equal 'BN1 2RE'
183
- end
184
- end
185
- end
186
-
187
- describe 'short address (London)' do
188
- let(:id) { 211 }
189
-
190
- it 'returns the postcode' do
191
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
192
- subject.must_equal 'SE1 8XR'
193
- end
194
- end
195
- end
196
-
197
- describe 'short address (extra London Postcode)' do
198
- let(:id) { 105 }
199
-
200
- it 'returns the postcode' do
201
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
202
- subject.must_equal 'WC2H 7JY'
203
- end
204
- end
81
+ def test_slug
82
+ with_fake_api do
83
+ assert_equal 'odeon-brighton', OdeonUk::Cinema.new(824).slug
205
84
  end
206
85
  end
207
86
 
208
- describe '#region' do
209
- subject { described_class.new(id).region }
210
- describe 'short address' do
211
- let(:id) { 71 }
212
-
213
- it 'returns the postcode' do
214
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
215
- subject.must_equal ''
216
- end
217
- end
87
+ def test_url
88
+ with_fake_api do
89
+ assert_equal 'https://www.odeon.co.uk/cinemas/brighton/',
90
+ OdeonUk::Cinema.new(824).url
218
91
  end
219
92
  end
220
93
 
221
- describe '#slug' do
222
- subject { described_class.new(id).slug }
223
-
224
- describe 'short address' do
225
- let(:id) { 71 }
226
-
227
- it 'returns first line of address' do
228
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
229
- subject.must_equal 'odeon-brighton'
230
- end
231
- end
94
+ def test_url_keeps_london_prefix
95
+ with_fake_api do
96
+ assert_equal 'https://www.odeon.co.uk/cinemas/london-leicester-square/',
97
+ OdeonUk::Cinema.new(153).url
232
98
  end
233
99
  end
234
100
 
235
- describe '#street_address' do
236
- subject { described_class.new(id).street_address }
237
-
238
- describe 'short address' do
239
- let(:id) { 71 }
240
-
241
- it 'returns first line of address' do
242
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
243
- subject.must_equal 'Kingswest'
244
- end
245
- end
101
+ def test_url_uses_slug_that_differs_from_name
102
+ with_fake_api do
103
+ assert_equal 'https://www.odeon.co.uk/cinemas/manchester-trafford-centre/',
104
+ OdeonUk::Cinema.new(955).url
246
105
  end
247
106
  end
248
107
 
249
- describe '#url' do
250
- subject { described_class.new(id).url }
108
+ private
251
109
 
252
- describe 'short address' do
253
- let(:id) { 71 }
254
-
255
- it 'returns first line of address' do
256
- OdeonUk::Internal::ApiResponse.stub :new, api_response do
257
- subject.must_equal 'http://www.odeon.co.uk/cinemas/brighton/71/'
258
- end
259
- end
260
- end
110
+ def with_fake_api(&block)
111
+ OdeonUk::Internal::ApiResponse.stub(:new, @api_response, &block)
261
112
  end
262
113
  end