Initial commit.
This commit is contained in:
commit
628e5c3823
26 changed files with 3478 additions and 0 deletions
118
tests/test_receipt.py
Normal file
118
tests/test_receipt.py
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
from copy import deepcopy
|
||||
from decimal import Decimal
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from ocado_grocy.receipt import ImportError, number, parse_document, parse_ocado_order
|
||||
|
||||
FIXTURE = Path(__file__).parent / 'fixtures' / 'history_receipt.json'
|
||||
|
||||
|
||||
def api_data():
|
||||
return json.loads(FIXTURE.read_text())
|
||||
|
||||
|
||||
def test_synthetic_api_receipt():
|
||||
receipt = parse_ocado_order(api_data())
|
||||
assert receipt.order_id == '1000000000001'
|
||||
assert receipt.purchased_date == '2020-01-02'
|
||||
assert len(receipt.items) == 21
|
||||
assert sum(i.quantity for i in receipt.items) == 23
|
||||
assert sum(i.total for i in receipt.items) == Decimal('28.75')
|
||||
lettuce = next(i for i in receipt.items if 'Lettuce' in i.name)
|
||||
assert lettuce.best_before == '2020-01-05'
|
||||
assert lettuce.metadata['storage_type'] == 'FRIDGE'
|
||||
cloths = next(i for i in receipt.items if 'Cleaning Cloths' in i.name)
|
||||
assert cloths.quantity == 2
|
||||
assert cloths.unit_price == Decimal('1.25')
|
||||
assert cloths.best_before is None
|
||||
|
||||
|
||||
def test_order_identity_and_delivery_status():
|
||||
with pytest.raises(ImportError,match='does not match'):
|
||||
parse_ocado_order(api_data(),expected_order_id='123')
|
||||
data=api_data()
|
||||
data['entities']['order'][data['result']]['status']='CONFIRMED'
|
||||
with pytest.raises(ImportError,match='not delivered'):
|
||||
parse_ocado_order(data)
|
||||
|
||||
|
||||
def test_summary_detects_partial_receipt():
|
||||
data=api_data()
|
||||
data['entities']['order'][data['result']]['groupedProducts']['products'].pop()
|
||||
with pytest.raises(ImportError,match='quantities'):
|
||||
parse_ocado_order(data)
|
||||
|
||||
|
||||
def test_summary_detects_wrong_price():
|
||||
data=api_data()
|
||||
data['entities']['order'][data['result']]['groupedProducts']['products'][0]['prices']['offered']['amount']='9.99'
|
||||
with pytest.raises(ImportError,match='prices'):
|
||||
parse_ocado_order(data)
|
||||
|
||||
|
||||
def test_only_accepted_substitutes_are_imported():
|
||||
data=api_data()
|
||||
order=data['entities']['order'][data['result']]
|
||||
original=order['groupedProducts']['products'].pop(0)
|
||||
accepted={**deepcopy(original),'productId':'replacement','retailerProductId':'999','name':'Replacement bananas','status':'ACCEPTED'}
|
||||
rejected={**deepcopy(original),'productId':'rejected','retailerProductId':'888','name':'Rejected bananas','status':'REJECTED'}
|
||||
original['substitutes']=[accepted,rejected]
|
||||
order['groupedProducts']['substitutes']=[original]
|
||||
receipt=parse_ocado_order(data)
|
||||
assert len(receipt.items)==21
|
||||
assert any(i.product_id=='999' for i in receipt.items)
|
||||
assert not any(i.product_id in {'888',original['retailerProductId']} for i in receipt.items)
|
||||
assert next(i for i in receipt.items if i.product_id=='999').metadata['substituted_for']==original['name']
|
||||
|
||||
|
||||
def test_input_order_does_not_change_stable_line_order():
|
||||
first=api_data()
|
||||
second=deepcopy(first)
|
||||
second['entities']['order'][second['result']]['groupedProducts']['products'].reverse()
|
||||
assert parse_ocado_order(first)==parse_ocado_order(second)
|
||||
|
||||
|
||||
def test_discontinued_product_does_not_need_html_link():
|
||||
data=api_data()
|
||||
product=data['entities']['order'][data['result']]['groupedProducts']['products'][0]
|
||||
product['isInCurrentCatalog']=False
|
||||
receipt=parse_ocado_order(data)
|
||||
assert any(i.product_id==product['retailerProductId'] for i in receipt.items)
|
||||
|
||||
|
||||
def test_purchase_date_is_local_delivery_date():
|
||||
data=api_data()
|
||||
data['entities']['order'][data['result']]['dates']['deliveryStartDate']='2026-09-01T23:30:00Z'
|
||||
assert parse_ocado_order(data).purchased_date=='2026-09-02'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('value',['NaN','Infinity','-1','nonsense',None])
|
||||
def test_invalid_numbers(value):
|
||||
with pytest.raises(ImportError):number(value,'quantity')
|
||||
|
||||
|
||||
def test_free_and_weighted_items():
|
||||
receipt=parse_document({'order_id':'1','items':[
|
||||
{'name':'Free gift','quantity':1,'total':0},
|
||||
{'name':'Apples','quantity':'0.75','total':'1.50'}]})
|
||||
assert receipt.items[0].unit_price==0
|
||||
assert receipt.items[1].unit_price==2
|
||||
|
||||
|
||||
def test_receipt_json_roundtrip():
|
||||
receipt=parse_ocado_order(api_data())
|
||||
assert parse_document(json.loads(json.dumps(receipt.export(),default=str)))==receipt
|
||||
|
||||
|
||||
def test_live_basket_cannot_be_mistaken_for_order():
|
||||
with pytest.raises(ImportError,match='structure'):
|
||||
parse_ocado_order({'data':{'basket':{'items':[{'name':'Not an order'}]}}})
|
||||
|
||||
|
||||
def test_non_gbp_order_rejected():
|
||||
data=api_data()
|
||||
data['entities']['order'][data['result']]['groupedProducts']['products'][0]['prices']['offered']['currency']='EUR'
|
||||
with pytest.raises(ImportError,match='currency'):parse_ocado_order(data)
|
||||
Loading…
Add table
Add a link
Reference in a new issue