Skip to content

Commit

Permalink
Merge branch 'update-api'
Browse files Browse the repository at this point in the history
  • Loading branch information
John Nguyen committed Oct 15, 2020
2 parents 7604306 + 584fcd6 commit f01ca92
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 52 deletions.
25 changes: 9 additions & 16 deletions myprotein.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
class Option(NamedTuple):
id: int
name: str
value: str


@dataclass
Expand All @@ -58,6 +57,7 @@ class ProductNotExistError(Exception):
'10852500': ProductInformation('impact_whey', 'Unflavored', '2.2 lb', 0.0),
'11464969': ProductInformation('whey_pouch', 'Vanilla', '0.55 lb', 0.0),
'10852482': ProductInformation('whey_isolate', 'Unflavored', '2.2 lb', 0.0),
'11181407': ProductInformation('impact_blend', 'Unflavored', '2.2 lb', 0.0),
'11111095': ProductInformation('iospro', 'Unflavored', '1.1 lb', 0.0),
# Creatine
'10852407': ProductInformation('creatine_monohydrate', 'Unflavored', '2.2 lb', 0.0),
Expand Down Expand Up @@ -189,21 +189,14 @@ def get_price_data(product_category_id: str) -> Dict[str, float]:

def get_all_products(product_id: str) -> Tuple[List[Option], List[Option]]:
"""Query endpoint to get possible product variations (size and flavour)"""
url = f'https://us.myprotein.com/variations.json?productId={product_id}'
response = addict.Dict(requests.get(url).json())
flavours = [
Option(**flavour)
for variation in response.variations
for flavour in variation.options
if variation.variation == 'Flavour'
]

sizes = [
Option(**size)
for variation in response.variations
for size in variation.options
if variation.variation == 'Amount'
]
response = requests.get(f'https://us.myprotein.com/{product_id}.html')
dom = bs4.BeautifulSoup(response.text, 'html.parser')

products = dom.select('#athena-product-variation-dropdown-5 option')
flavours = [Option(int(i['value']), i.text.strip()) for i in products]

sizes = dom.select('.athenaProductVariations_list button')
sizes = [Option(int(i['data-option-id']), name=i.text.strip()) for i in sizes]

return flavours, sizes

Expand Down
83 changes: 47 additions & 36 deletions myprotein_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Disable redefined function name warning because that's how pytest fixtures work by default
# pylint: disable=redefined-outer-name
import json
from typing import Any
from typing import Iterator
from unittest import mock
Expand Down Expand Up @@ -123,44 +122,56 @@ def test_get_product_information_not_found() -> None:


def test_get_all_products(mocked_responses: Any) -> None:
response = {
'variations': [
{
'id': 100,
'variation': 'Flavour',
'options': [{'id': 111, 'name': 'flavour_name', 'value': 'flavour_value'}],
},
{
'id': 200,
'variation': 'Amount',
'options': [
{'id': 211, 'name': 'size_name1', 'value': 'size_value1'},
{'id': 222, 'name': 'size_name2', 'value': 'size_value2'},
],
},
]
}

# This is a mocked snippet and apsires to demonstrate the rough structure of page
body = '''
<html>
<div class="athenaProductPage_productVariations">
<div class="athenaProductVariations">
<div role="group" aria-label="Flavor">
<div class="athenaProductVariations_dropdownSegment">
<select id="athena-product-variation-dropdown-5">
<option class="" value="111">
flavour_name
</option>
</select>
</div>
</div>
<div role="group" aria-label="Amount" data-product-variation="">
<div class="athenaProductVariations_radioBoxesSegment" data-product-variation-type="radio">
<div class="athenaProductVariations_boxes">
<ul class="athenaProductVariations_list" aria-label="Amount">
<li class="athenaProductVariations_listItem">
<button class="athenaProductVariations_box default" data-option-id="211" >
size_name1
</button>
</li>
<li class="athenaProductVariations_listItem">
<button class="athenaProductVariations_box default" data-option-id="222" >
size_name2
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</html>
'''
product_category_id = '12345'
mocked_responses.add(
responses.GET,
f'https://us.myprotein.com/variations.json?productId={product_category_id}',
body=json.dumps(response),
)
mocked_responses.add(responses.GET, f'https://us.myprotein.com/{product_category_id}.html', body=body)

flavours, sizes = myprotein.get_all_products(product_category_id)

assert len(flavours) == 1
assert flavours[0] == myprotein.Option(111, 'flavour_name', 'flavour_value')
assert flavours[0] == myprotein.Option(111, 'flavour_name')

TestCase().assertCountEqual(
sizes, [myprotein.Option(222, 'size_name2', 'size_value2'), myprotein.Option(211, 'size_name1', 'size_value1')]
)
TestCase().assertCountEqual(sizes, [myprotein.Option(222, 'size_name2'), myprotein.Option(211, 'size_name1')])


def test_resolve_options_to_product_id(mock_responses_with_default_product_information: Any) -> None:
flavour = myprotein.Option(111, 'name', 'value')
size = myprotein.Option(222, 'name', 'value')
flavour = myprotein.Option(111, 'name')
size = myprotein.Option(222, 'name')
# impact whey
product_category_id = '10852500'

Expand Down Expand Up @@ -245,8 +256,8 @@ def test_resolve_options_to_product_id_default_product(mock_responses_with_defau
product_category_id = '10852500'

# Queried option matches the default product
flavour = myprotein.Option(111, 'Unflavored', 'Unflavored')
size = myprotein.Option(222, '2.2 lb', '2.2 lb')
flavour = myprotein.Option(111, 'Unflavored')
size = myprotein.Option(222, '2.2 lb')

product_response = '''
<div
Expand Down Expand Up @@ -281,8 +292,8 @@ def test_resolve_options_to_product_id_product_not_found(mock_responses_with_def
product_category_id = '10852500'

# Queried options do not match default product
flavour = myprotein.Option(111, 'name', 'value')
size = myprotein.Option(222, 'name', 'value')
flavour = myprotein.Option(111, 'name')
size = myprotein.Option(222, 'name')

default_product_response = '''
<div
Expand Down Expand Up @@ -313,8 +324,8 @@ def test_resolve_options_to_product_id_bad_response(mock_responses_with_default_

# impact whey
product_category_id = '10852500'
flavour = myprotein.Option(111, 'name', 'value')
size = myprotein.Option(222, 'name', 'value')
flavour = myprotein.Option(111, 'name')
size = myprotein.Option(222, 'name')

mock_responses_with_default_product_information.add(
responses.POST,
Expand Down

0 comments on commit f01ca92

Please sign in to comment.