cineworld_uk 4.1.0 → 4.3.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/README.md +26 -1
  4. data/Rakefile +3 -24
  5. data/cineworld_uk.gemspec +2 -2
  6. data/lib/cineworld_uk/internal/api_response.rb +9 -31
  7. data/lib/cineworld_uk/internal/guest_token.rb +9 -52
  8. data/lib/cineworld_uk/internal/parser/api/film.rb +14 -1
  9. data/lib/cineworld_uk/internal/parser/api/performance.rb +5 -0
  10. data/lib/cineworld_uk/internal/title_sanitizer.rb +5 -10
  11. data/lib/cineworld_uk/performance.rb +5 -1
  12. data/lib/cineworld_uk/version.rb +2 -2
  13. data/lib/cineworld_uk.rb +2 -1
  14. data/test/fixtures/api/showtimes-014.json +76 -0
  15. data/test/fixtures/api/sites.json +52 -0
  16. data/test/lib/cineworld_uk/cinema_test.rb +63 -223
  17. data/test/lib/cineworld_uk/internal/api_response_test.rb +27 -182
  18. data/test/lib/cineworld_uk/internal/fixture_shape_test.rb +14 -0
  19. data/test/lib/cineworld_uk/internal/guest_token_test.rb +87 -0
  20. data/test/lib/cineworld_uk/internal/parser/api/cinema_address_test.rb +44 -85
  21. data/test/lib/cineworld_uk/internal/parser/api/film_test.rb +65 -127
  22. data/test/lib/cineworld_uk/internal/parser/api/performance_test.rb +27 -45
  23. data/test/lib/cineworld_uk/internal/title_sanitizer_test.rb +94 -120
  24. data/test/lib/cineworld_uk/performance_test.rb +165 -180
  25. data/test/lib/cineworld_uk/version_test.rb +3 -3
  26. data/test/live/api_shape_test.rb +22 -0
  27. data/test/live/integration_test.rb +13 -43
  28. data/test/live/live_helper.rb +11 -0
  29. data/test/package_test.rb +14 -7
  30. data/test/support/api_shapes.rb +48 -0
  31. data/test/support/vista_fixtures.rb +58 -0
  32. data/test/test_helper.rb +3 -0
  33. metadata +34 -29
  34. data/tasks/package.rake +0 -84
  35. data/test/fixtures/api/cinema-list.json +0 -1
  36. data/test/fixtures/api/dates-14.json +0 -1
  37. data/test/fixtures/api/performances-tomorrow-14.json +0 -1
  38. data/test/fixtures/api/vista-showtimes-brighton.json +0 -1
  39. data/test/support/fixture_reader.rb +0 -32
@@ -1,94 +1,53 @@
1
1
  require_relative '../../../../../test_helper'
2
- require_relative '../../../../../support/fixture_reader'
3
2
 
4
- describe CineworldUk::Internal::Parser::Api::CinemaAddress do
5
- include Support::FixtureReader
6
-
7
- let(:described_class) { CineworldUk::Internal::Parser::Api::CinemaAddress }
8
- let(:api_response) { Minitest::Mock.new }
9
-
10
- before { WebMock.disable_net_connect! }
11
- after { WebMock.allow_net_connect! }
12
-
13
- describe '#to_hash' do
14
- subject { described_class.new(id).to_hash }
15
-
16
- before do
17
- api_response.expect(:cinema_list, cinema_list_json)
18
- end
19
-
20
- describe 'passed simple (Brighton)' do
21
- let(:id) { 14 }
22
-
23
- it 'returns address hash' do
24
- CineworldUk::Internal::ApiResponse.stub :new, api_response do
25
- _(subject).must_equal(street_address: 'Brighton Marina Village',
26
- extended_address: nil,
27
- locality: 'Brighton',
28
- region: nil,
29
- postal_code: 'BN2 5UF',
30
- country: 'United Kingdom')
31
- end
32
- end
33
- end
34
-
35
- describe 'passed three line (NEC)' do
36
- let(:id) { 90 }
37
-
38
- it 'returns address hash' do
39
- CineworldUk::Internal::ApiResponse.stub :new, api_response do
40
- _(subject).must_equal(street_address: 'Resorts World',
41
- extended_address: 'Pendigo Way',
42
- locality: 'Birmingham',
43
- region: nil,
44
- postal_code: 'B40 1PU',
45
- country: 'United Kingdom')
46
- end
47
- end
48
- end
3
+ class CineworldUk::Internal::Parser::Api::CinemaAddressTest < Minitest::Test
4
+ CINEMAS = [
5
+ {
6
+ 'id' => '014', 'displayName' => 'Brighton',
7
+ 'addressInfo' => { 'address1' => '1 Example Marina', 'city' => 'Brighton',
8
+ 'postalCode' => 'BN2 0ZZ' }
9
+ },
10
+ {
11
+ 'id' => '090', 'displayName' => 'Birmingham Example',
12
+ 'addressInfo' => { 'address1' => '2 Example Resort', 'address2' => 'Example Way',
13
+ 'city' => 'Birmingham', 'postalCode' => 'B40 0ZZ' }
14
+ },
15
+ {
16
+ 'id' => '037', 'displayName' => 'Edinburgh Example',
17
+ 'addressInfo' => { 'address1' => '3 Example Park', 'address3' => '4 Example Street',
18
+ 'city' => 'Edinburgh', 'postalCode' => 'EH11 0ZZ' }
19
+ },
20
+ {
21
+ 'id' => '103', 'displayName' => 'London - Leicester Square',
22
+ 'addressInfo' => { 'address1' => '5 Example Square', 'address2' => 'Example Row',
23
+ 'city' => 'London', 'postalCode' => 'WC2H 0ZZ' }
24
+ }
25
+ ].freeze
26
+
27
+ def test_one_line_address
28
+ assert_address 14, street_address: '1 Example Marina', extended_address: nil,
29
+ locality: 'Brighton', region: nil, postal_code: 'BN2 0ZZ'
30
+ end
49
31
 
50
- describe 'passed three line (Edinburgh)' do
51
- let(:id) { 37 }
32
+ def test_second_line_is_extended_address
33
+ assert_address 90, street_address: '2 Example Resort', extended_address: 'Example Way',
34
+ locality: 'Birmingham', region: nil, postal_code: 'B40 0ZZ'
35
+ end
52
36
 
53
- it 'returns address hash' do
54
- CineworldUk::Internal::ApiResponse.stub :new, api_response do
55
- _(subject).must_equal(street_address: 'Fountain Park',
56
- extended_address: '130/3 Dundee Street',
57
- locality: 'Edinburgh',
58
- region: nil,
59
- postal_code: 'EH11 1AF',
60
- country: 'United Kingdom')
61
- end
62
- end
63
- end
37
+ def test_third_line_is_extended_address_without_second
38
+ assert_address 37, street_address: '3 Example Park', extended_address: '4 Example Street',
39
+ locality: 'Edinburgh', region: nil, postal_code: 'EH11 0ZZ'
40
+ end
64
41
 
65
- describe 'passed two line (Leicester Square)' do
66
- let(:id) { 103 }
42
+ def test_london_has_region_and_no_extended_address
43
+ assert_address 103, street_address: '5 Example Square', extended_address: nil,
44
+ locality: 'London', region: 'London', postal_code: 'WC2H 0ZZ'
45
+ end
67
46
 
68
- it 'returns address hash' do
69
- CineworldUk::Internal::ApiResponse.stub :new, api_response do
70
- _(subject).must_equal(street_address: '5-6 Leicester Square',
71
- extended_address: nil,
72
- locality: 'London',
73
- region: 'London',
74
- postal_code: 'WC2H 7NA',
75
- country: 'United Kingdom')
76
- end
77
- end
78
- end
47
+ private
79
48
 
80
- # describe 'passed non-existant api' do
81
- # let(:id) { 0 }
82
- #
83
- # it 'returns hash of nils' do
84
- # _(subject).must_be_instance_of(Hash)
85
- # _(subject).must_equal(street_address: nil,
86
- # extended_address: nil,
87
- # locality: "not an address",
88
- # region: nil,
89
- # postal_code: "not an address",
90
- # country: "United Kingdom")
91
- # end
92
- # end
49
+ def assert_address(id, expected)
50
+ assert_equal expected.merge(country: 'United Kingdom'),
51
+ CineworldUk::Internal::Parser::Api::CinemaAddress.new(id, CINEMAS).to_hash
93
52
  end
94
53
  end
@@ -1,160 +1,98 @@
1
1
  require_relative '../../../../../test_helper'
2
- require_relative '../../../../../support/fixture_reader'
3
2
 
4
- describe CineworldUk::Internal::Parser::Api::Film do
5
- include Support::FixtureReader
6
-
7
- let(:described_class) { CineworldUk::Internal::Parser::Api::Film }
8
- let(:data) { random_film }
9
-
10
- before { WebMock.disable_net_connect! }
11
- after { WebMock.allow_net_connect! }
12
-
13
- describe '#id' do
14
- subject { described_class.new(data).id }
15
-
16
- it 'is a string' do
17
- _(subject).must_be_instance_of(String)
18
- end
19
-
20
- it 'is the film id from the data' do
21
- _(subject).must_equal(data['id'])
22
- end
3
+ class CineworldUk::Internal::Parser::Api::FilmTest < Minitest::Test
4
+ def test_id
5
+ assert_equal '014-1001', film.id
23
6
  end
24
7
 
25
- describe '#dimension' do
26
- subject { described_class.new(data).dimension }
27
-
28
- it 'is a string' do
29
- _(subject).must_be_instance_of(String)
30
- end
31
-
32
- it 'is 2d or 3d' do
33
- _(subject).must_match(/[23]d/)
34
- end
35
-
36
- describe 'attributeIds includes "2d"' do
37
- let(:data) { random_film.merge('attributeIds' => ['2d']) }
38
-
39
- it 'is 2d' do
40
- _(subject).must_equal('2d')
41
- end
42
- end
43
-
44
- describe 'attributeIds includes "3d"' do
45
- let(:data) { random_film.merge('attributeIds' => ['3d']) }
46
-
47
- it 'is 3d' do
48
- _(subject).must_equal('3d')
49
- end
50
- end
51
-
52
- describe 'attributeIds with imax but not 3d' do
53
- let(:data) { random_film.merge('attributeIds' => ['imax', '2d']) }
8
+ def test_dimension_defaults_to_2d
9
+ assert_equal '2d', film.dimension
10
+ end
54
11
 
55
- it 'is 2d' do
56
- _(subject).must_equal('2d')
57
- end
58
- end
12
+ def test_dimension_2d
13
+ assert_equal '2d', film('attributeIds' => ['2d']).dimension
14
+ end
59
15
 
60
- describe 'attributeIds with imax and 3d' do
61
- let(:data) { random_film.merge('attributeIds' => ['imax', '3d']) }
16
+ def test_dimension_3d
17
+ assert_equal '3d', film('attributeIds' => ['3d']).dimension
18
+ end
62
19
 
63
- it 'is 3d' do
64
- _(subject).must_equal('3d')
65
- end
66
- end
20
+ def test_dimension_imax_without_3d
21
+ assert_equal '2d', film('attributeIds' => %w(imax 2d)).dimension
67
22
  end
68
23
 
69
- describe '#name' do
70
- subject { described_class.new(data).name }
24
+ def test_dimension_imax_with_3d
25
+ assert_equal '3d', film('attributeIds' => %w(imax 3d)).dimension
26
+ end
71
27
 
72
- it 'is a string' do
73
- _(subject).must_be_instance_of(String)
74
- end
28
+ def test_name
29
+ assert_equal 'Test Film Name', film('name' => 'Test Film Name').name
30
+ end
75
31
 
76
- describe 'film name' do
77
- let(:data) do
78
- random_film.merge('name' => 'Test Film Name')
79
- end
32
+ def test_name_is_sanitized
33
+ assert_equal 'Royal Opera House: Something', film('name' => 'ROH: Something').name
34
+ end
80
35
 
81
- it 'is the film name' do
82
- _(subject).must_equal('Test Film Name')
83
- end
84
- end
36
+ def test_name_drops_festival_prefix
37
+ assert_equal 'Scum Of The Earth', film('name' => 'Cine-Excess 2026: Scum Of The Earth').name
38
+ end
85
39
 
86
- describe 'film name is unsanitized' do
87
- let(:data) { random_film.merge('name' => 'ROH: Something') }
40
+ def test_festival
41
+ festival = film('name' => 'Cine-Excess 2026: Scum Of The Earth').festival(2026)
88
42
 
89
- it 'is sanitized' do
90
- _(subject).must_equal('Royal Opera House: Something')
91
- end
92
- end
43
+ assert_equal Cinebase::Festival.new(name: 'Cine-Excess', year: 2026), festival
93
44
  end
94
45
 
95
- describe '#variant' do
96
- subject { described_class.new(data).variant }
46
+ def test_festival_without_prefix
47
+ assert_nil film.festival(2026)
48
+ end
97
49
 
98
- it 'is a sorted array of strings' do
99
- _(subject).must_be_instance_of(Array)
100
- subject.each { |element| _(element).must_be_instance_of(String) }
101
- _(subject.sort).must_equal(subject)
102
- end
50
+ def test_film_year
51
+ assert_equal 1996, film('name' => 'Horror Season 2026 From Dusk Till Dawn (1996)').film_year
52
+ end
103
53
 
104
- describe 'attributeIds includes "junior"' do
105
- let(:data) do
106
- random_film.merge('attributeIds' => ['junior'])
107
- end
54
+ def test_film_year_without_year
55
+ assert_nil film.film_year
56
+ end
108
57
 
109
- it 'includes "kids"' do
110
- _(subject).must_include('kids')
111
- end
112
- end
58
+ def test_variant_4dx
59
+ assert_includes film('attributeIds' => ['4dx']).variant, '4dx'
60
+ end
113
61
 
114
- describe 'attributeIds includes "imax"' do
115
- let(:data) do
116
- random_film.merge('attributeIds' => ['imax', '3d'])
117
- end
62
+ def test_variant_screenx
63
+ assert_includes film('attributeIds' => ['screenx']).variant, 'screenx'
64
+ end
118
65
 
119
- it 'includes "imax"' do
120
- _(subject).must_include('imax')
121
- end
122
- end
66
+ def test_variant_is_sorted
67
+ variant = film('attributeIds' => %w(qa junior imax)).variant
123
68
 
124
- describe 'attributeIds includes "unlimited-screening"' do
125
- let(:data) do
126
- random_film.merge('attributeIds' => ['unlimited-screening'])
127
- end
69
+ assert_equal variant.sort, variant
70
+ end
128
71
 
129
- it 'includes "members"' do
130
- _(subject).must_include('members')
131
- end
132
- end
72
+ def test_variant_junior_is_kids
73
+ assert_includes film('attributeIds' => ['junior']).variant, 'kids'
74
+ end
133
75
 
134
- describe 'attributeIds includes "qa"' do
135
- let(:data) do
136
- random_film.merge('attributeIds' => ['qa'])
137
- end
76
+ def test_variant_imax
77
+ assert_includes film('attributeIds' => %w(imax 3d)).variant, 'imax'
78
+ end
138
79
 
139
- it 'includes "q&a"' do
140
- _(subject).must_include('q&a')
141
- end
142
- end
80
+ def test_variant_unlimited_screening_is_members
81
+ assert_includes film('attributeIds' => ['unlimited-screening']).variant, 'members'
82
+ end
143
83
 
144
- describe 'combination' do
145
- let(:data) do
146
- random_film.merge('attributeIds' => ['imax', 'unlimited-screening'])
147
- end
84
+ def test_variant_q_and_a
85
+ assert_includes film('attributeIds' => ['qa']).variant, 'q&a'
86
+ end
148
87
 
149
- it 'includes "members"' do
150
- _(subject).must_include('imax', 'members')
151
- end
152
- end
88
+ def test_variant_combination
89
+ assert_equal %w(imax members), film('attributeIds' => %w(imax unlimited-screening)).variant
153
90
  end
154
91
 
155
92
  private
156
93
 
157
- def random_film
158
- JSON.parse(performances_tomorrow_json(14))['body']['films'].sample
94
+ def film(overrides = {})
95
+ data = { 'id' => '014-1001', 'name' => 'The Example Film', 'attributeIds' => [] }
96
+ CineworldUk::Internal::Parser::Api::Film.new(data.merge(overrides))
159
97
  end
160
98
  end
@@ -1,62 +1,44 @@
1
1
  require_relative '../../../../../test_helper'
2
- require_relative '../../../../../support/fixture_reader'
3
2
 
4
- describe CineworldUk::Internal::Parser::Api::Performance do
5
- include Support::FixtureReader
6
-
7
- let(:described_class) { CineworldUk::Internal::Parser::Api::Performance }
8
- let(:data) { random_performance }
9
-
10
- before { WebMock.disable_net_connect! }
11
- after { WebMock.allow_net_connect! }
12
-
13
- describe '#booking_url' do
14
- subject { described_class.new(data).booking_url }
15
-
16
- it 'should be a url on the cineworld website' do
17
- _(subject).must_match(%r{cineworld.co.uk})
18
- end
3
+ class CineworldUk::Internal::Parser::Api::PerformanceTest < Minitest::Test
4
+ def test_booking_url
5
+ assert_equal 'https://web.cineworld.co.uk/order/showtimes/014-1001/seats',
6
+ performance.booking_url
19
7
  end
20
8
 
21
- describe '#film_id' do
22
- subject { described_class.new(data).film_id }
23
-
24
- it 'should be a string' do
25
- _(subject).must_be_instance_of(String)
26
- end
9
+ def test_film_id
10
+ assert_equal '014-1001', performance.film_id
27
11
  end
28
12
 
29
- describe '#starting_at' do
30
- subject { described_class.new(data).starting_at }
31
-
32
- it 'should be a time' do
33
- _(subject).must_be_instance_of(Time)
34
- end
13
+ def test_starting_at
14
+ assert_equal Time.utc(2026, 10, 24, 8, 0), performance.starting_at
35
15
  end
36
16
 
37
- describe '#variant' do
38
- subject { described_class.new(data).variant }
39
-
40
- describe 'has "audio-described" in attributeIds' do
41
- let(:data) { random_performance.merge('attributeIds' => ['audio-described']) }
17
+ def test_language
18
+ assert_equal 'Tamil', performance('language' => 'Tamil').language
19
+ end
42
20
 
43
- it 'includes "audio_described"' do
44
- _(subject).must_include('audio_described')
45
- end
46
- end
21
+ def test_language_defaults_to_nil
22
+ assert_nil performance.language
23
+ end
47
24
 
48
- describe 'has "subbed" in attributeIds' do
49
- let(:data) { random_performance.merge('attributeIds' => ['subbed']) }
25
+ def test_variant_audio_described
26
+ assert_includes performance('attributeIds' => ['audio-described']).variant, 'audio_described'
27
+ end
50
28
 
51
- it 'includes "subtitled"' do
52
- _(subject).must_include('subtitled')
53
- end
54
- end
29
+ def test_variant_subtitled
30
+ assert_includes performance('attributeIds' => ['subbed']).variant, 'subtitled'
55
31
  end
56
32
 
57
33
  private
58
34
 
59
- def random_performance
60
- JSON.parse(performances_tomorrow_json(14))['body']['events'].sample
35
+ def performance(overrides = {})
36
+ data = {
37
+ 'filmId' => '014-1001',
38
+ 'attributeIds' => [],
39
+ 'eventDateTime' => '2026-10-24T08:00:00Z',
40
+ 'bookingLink' => 'https://web.cineworld.co.uk/order/showtimes/014-1001/seats'
41
+ }
42
+ CineworldUk::Internal::Parser::Api::Performance.new(data.merge(overrides))
61
43
  end
62
44
  end