Make all tests pass again.

This commit is contained in:
Alexis MÃtaireau 2020-04-08 17:55:52 +02:00
parent b7b31c23d7
commit a1cd995d9d
8 changed files with 144 additions and 171 deletions

View file

@ -119,21 +119,24 @@ class Groups(PersistedBase):
__lock__ = threading.Lock()
groups: Dict[str, Group]
@classmethod
def get_path(cls):
return cls.get_root() / "groups.yml"
@classmethod
def load(cls):
path = cls.get_root() / "groups.yml"
path = cls.get_path()
if path.exists():
data = yaml.safe_load(path.read_text())
data = {k: v for k, v in data.items() if k in cls.__dataclass_fields__}
else:
data = {"groups": {}}
groups = cls(**data)
groups.path = path
return groups
def persist(self):
with self.__lock__:
self.path.write_text(self.dump())
self.get_path().write_text(self.dump())
def add_group(self, group):
assert group.id not in self.groups, "Un groupe avec ce nom existe déjà."

View file

@ -4,5 +4,5 @@ pytest-asyncio
usine
pyquery
pytest-watch
python-emails
#python-emails
Weasyprint

View file

@ -8,7 +8,7 @@ from roll.testing import Client as BaseClient
from copanier import app as copanier_app
from copanier import config as kconfig
from copanier.utils import create_token
from copanier.models import Delivery, Person, Product
from copanier.models import Delivery, Person, Product, Producer, Groups, Group
def pytest_configure(config):
@ -25,7 +25,7 @@ def pytest_runtest_setup(item):
class Client(BaseClient):
content_type = 'application/x-www-form-urlencoded; charset=utf-8'
content_type = "application/x-www-form-urlencoded; charset=utf-8"
headers = {}
async def request(
@ -67,12 +67,44 @@ def app(): # Requested by Roll testing utilities.
@pytest.fixture
def delivery():
return Delivery(
name="Andines",
name="CRAC d'automne",
contact="mister@me.me",
from_date=datetime.now() + timedelta(days=10),
to_date=datetime.now() + timedelta(days=10),
order_before=datetime.now() + timedelta(days=7),
products=[Product(name="Lait", ref="123", price=1.5)],
products=[
Product(name="Lait", producer="ferme-du-coin", ref="lait", price=1.5,)
],
producers={"ferme-du-coin": Producer(name="Ferme du coin", id="ferme-du-coin")},
)
@pytest.fixture
def groups():
fractal_brocolis = Group(
id="fractal-brocolis", name="The Fractal Brocolis", members=["foo@bar.org"]
)
groups = Groups({"fractal-brocolis": fractal_brocolis})
groups.persist()
return groups
@pytest.fixture
def yaourt():
return Product(
ref="yaourt",
unit="pot 125ml",
name="Yaourt",
price="3.5",
packing=4,
producer="ferme-du-coin",
)
@pytest.fixture
def fromage():
return Product(
ref="fromage", name="Fromage", price="9.2", producer="ferme-du-coin",
)

View file

@ -1,56 +0,0 @@
from io import BytesIO
import pytest
from openpyxl import Workbook
from copanier import imports
from copanier.models import Product, Delivery
@pytest.fixture
def workbook():
def _(rows, headers=["ref", "name", "price"]):
wb = Workbook()
ws = wb.active
ws.append(headers)
for row in rows:
ws.append(row)
return wb
return _
def test_mandatory_headers_with_xlsx(delivery, workbook):
with pytest.raises(ValueError):
imports.products_and_producers_from_xlsx(
delivery,
workbook([("123", "Chocolat", "2.3")], headers=["ref", "nom", "prix"]),
)
def test_bad_xlsx_file(delivery, workbook):
with pytest.raises(ValueError):
imports.products_and_producers_from_xlsx(delivery, BytesIO(b"pouet"))
def test_simple_xlsx_import(delivery, workbook):
delivery.persist()
assert delivery.products == [Product(ref="123", name="Lait", price=1.5)]
imports.products_and_producers_from_xlsx(
delivery, workbook([("123", "Lait cru", 1.3)])
)
assert Delivery.load(delivery.id).products == [
Product(ref="123", name="Lait cru", price=1.3)
]
def test_simple_xlsx_import_invalid_price(delivery, workbook):
delivery.persist()
assert delivery.products == [Product(ref="123", name="Lait", price=1.5)]
with pytest.raises(ValueError):
imports.products_and_producers_from_xlsx(
delivery, workbook([("123", "Lait cru", "invalid")])
)
assert Delivery.load(delivery.id).products == [
Product(ref="123", name="Lait", price=1.5)
]

View file

@ -3,7 +3,15 @@ from datetime import datetime, timedelta
import pytest
from copanier import config
from copanier.models import Delivery, Product, Person, Order, ProductOrder, Groups, Group
from copanier.models import (
Delivery,
Product,
Person,
Order,
ProductOrder,
Groups,
Group,
)
now = datetime.now
@ -108,11 +116,11 @@ def test_order_has_adjustments():
def test_order_total(delivery):
delivery.products = [Product(name="Lait", ref="123", price=1.5)]
order = Order()
assert order.total(delivery.products) == 0
assert order.total(delivery.products, delivery) == 0
order.products["123"] = ProductOrder(wanted=2)
assert order.total(delivery.products) == 3
assert order.total(delivery.products, delivery) == 3
order.products["unknown"] = ProductOrder(wanted=2)
assert order.total(delivery.products) == 3
assert order.total(delivery.products, delivery) == 3
def test_can_persist_delivery(delivery):
@ -176,22 +184,22 @@ def test_archive_delivery(delivery):
def test_group_management():
ndp = Group(id='nid-de-poules', name='Nid de poules', members=['someone@domain.tld'])
assert ndp.id == 'nid-de-poules'
assert ndp.name == 'Nid de poules'
ndp = Group(
id="nid-de-poules", name="Nid de poules", members=["someone@domain.tld"]
)
assert ndp.id == "nid-de-poules"
assert ndp.name == "Nid de poules"
assert len(ndp.members) == 1
groups = Groups.load()
groups.persist()
groups.add_group(ndp)
groups.add_user('simon@tld', ndp.id)
assert 'simon@tld' in groups.groups[ndp.id].members
groups.add_user("simon@tld", ndp.id)
assert "simon@tld" in groups.groups[ndp.id].members
ladouce = Group(id='la-douce', name='La douce', members=[])
ladouce = Group(id="la-douce", name="La douce", members=[])
groups.add_group(ladouce)
groups.add_user('simon@tld', ladouce.id)
assert 'simon@tld' in groups.groups[ladouce.id].members
assert 'simon@tld' not in groups.groups[ndp.id].members
groups.add_user("simon@tld", ladouce.id)
assert "simon@tld" in groups.groups[ladouce.id].members
assert "simon@tld" not in groups.groups[ndp.id].members

View file

@ -6,20 +6,18 @@ from copanier import reports
from copanier.models import Order, Product, ProductOrder
def test_summary_report(delivery):
def test_summary_report(delivery, yaourt, fromage):
delivery.products[0].packing = 6
delivery.products.append(
Product(ref="456", name="yaourt", price="3.5", packing=4, unit="pot 125ml")
)
delivery.products.append(Product(ref="789", name="fromage", price="9.2"))
delivery.orders["foo@bar.org"] = Order(
products={"123": ProductOrder(wanted=1), "456": ProductOrder(wanted=4)}
delivery.products.append(yaourt)
delivery.products.append(fromage)
delivery.orders["fractals-brocoli"] = Order(
products={"lait": ProductOrder(wanted=1), "yaourt": ProductOrder(wanted=4)}
)
delivery.persist()
wb = load_workbook(filename=BytesIO(reports.summary(delivery)))
assert list(wb.active.values) == [
("ref", "produit", "prix unitaire", "quantité commandée", "unité", "total"),
("123", "Lait", 1.5, 1, None, 1.5),
("456", "yaourt (pot 125ml)", 3.5, 4, "pot 125ml", 14),
("lait", "Lait", 1.5, 1, None, 1.5),
("yaourt", "Yaourt", 3.5, 4, "pot 125ml", 14),
(None, None, None, None, "Total", 15.5),
]

View file

@ -10,12 +10,21 @@ from copanier.models import Delivery, Order, ProductOrder, Product
pytestmark = pytest.mark.asyncio
async def test_empty_home(client):
async def test_home_redirects_to_group_if_needed(client):
client.login(email="new@example.org")
resp = await client.get("/")
assert resp.status == 302
assert resp.headers["Location"] == "/groupes"
async def test_empty_home(client, delivery, groups):
groups.persist()
resp = await client.get("/")
assert resp.status == 200
async def test_home_should_list_active_delivery(client, delivery):
async def test_home_should_list_active_delivery(client, delivery, groups):
groups.persist()
delivery.persist()
resp = await client.get("/")
assert resp.status == 200
@ -55,12 +64,12 @@ async def test_create_delivery(client):
async def test_place_order_with_session(client, delivery):
delivery.persist()
body = {"wanted:123": "3"}
body = {"wanted:lait": "3"}
resp = await client.post(f"/distribution/{delivery.id}/commander", body=body)
assert resp.status == 302
delivery = Delivery.load(id=delivery.id)
assert delivery.orders["foo@bar.org"]
assert delivery.orders["foo@bar.org"].products["123"].wanted == 3
assert "fractal-brocolis" in delivery.orders.keys()
assert delivery.orders["fractal-brocolis"].products["lait"].wanted == 3
async def test_place_empty_order(client, delivery):
@ -72,7 +81,9 @@ async def test_place_empty_order(client, delivery):
async def test_place_empty_order_should_delete_previous(client, delivery):
delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=1)})
delivery.orders["fractal-brocolis"] = Order(
products={"lait": ProductOrder(wanted=1)}
)
delivery.persist()
resp = await client.post(f"/distribution/{delivery.id}/commander", body={})
assert resp.status == 302
@ -82,89 +93,66 @@ async def test_place_empty_order_should_delete_previous(client, delivery):
async def test_place_order_with_empty_string(client, delivery):
delivery.persist()
body = {"wanted:123": ""} # User deleted the field value.
body = {"wanted:lait": ""} # User deleted the field value.
resp = await client.post(f"/distribution/{delivery.id}/commander", body=body)
assert resp.status == 302
delivery = Delivery.load(id=delivery.id)
assert not delivery.orders
async def test_get_place_order_with_closed_delivery(client, delivery, monkeypatch):
async def test_get_place_order_if_not_adjustable(client, delivery, monkeypatch):
monkeypatch.setattr("copanier.config.STAFF", ["someone@else.org"])
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=1)})
delivery.orders["fractal-brocolis"] = Order(
products={"lait": ProductOrder(wanted=1)}
)
delivery.persist()
assert delivery.status == delivery.CLOSED
resp = await client.get(f"/distribution/{delivery.id}/commander")
doc = pq(resp.body)
assert doc('[name="wanted:123"]').attr("readonly")
assert not doc('[name="adjustment:123"]')
assert doc('[name="wanted:lait"]').attr("readonly")
assert not doc('[name="adjustment:lait"]')
assert not doc('input[type="submit"]')
async def test_get_place_order_with_adjustment_status(client, delivery):
async def test_get_place_order_with_adjustment_status(client, delivery, yaourt, fromage):
resp = await client.get(f"/distribution/{delivery.id}/commander")
doc = pq(resp.body)
assert not doc('[name="wanted:123"]').attr("readonly")
assert not doc('[name="adjustment:123"]')
assert not doc('[name="wanted:lait"]').attr("readonly")
assert not doc('[name="adjustment:lait"]')
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.products[0].packing = 6
delivery.products.append(Product(ref="456", name="yaourt", price="3.5", packing=4))
delivery.products.append(Product(ref="789", name="fromage", price="9.2"))
delivery.orders["foo@bar.org"] = Order(
products={"123": ProductOrder(wanted=1), "456": ProductOrder(wanted=4)}
delivery.products.append(yaourt)
delivery.products.append(fromage)
delivery.orders["fractal-brocolis"] = Order(
products={
"lait": ProductOrder(wanted=1),
"yaourt": ProductOrder(wanted=4)
}
)
delivery.persist()
assert delivery.status == delivery.ADJUSTMENT
resp = await client.get(f"/distribution/{delivery.id}/commander")
doc = pq(resp.body)
assert doc('[name="wanted:123"]').attr("readonly")
assert doc('[name="adjustment:123"]')
assert not doc('[name="adjustment:123"]').attr("readonly")
assert doc('[name="adjustment:123"]').attr("min") == "-1"
assert doc('[name="wanted:456"]').attr("readonly")
assert doc('[name="adjustment:456"]')
assert doc('[name="wanted:lait"]').attr("readonly")
assert doc('[name="adjustment:lait"]')
assert not doc('[name="adjustment:lait"]').attr("readonly")
assert doc('[name="adjustment:lait"]').attr("min") == "-1"
assert doc('[name="wanted:yaourt"]').attr("readonly")
assert doc('[name="adjustment:yaourt"]')
# Already adjusted.
assert doc('[name="adjustment:456"]').attr("readonly")
assert doc('[name="adjustment:789"]')
assert doc('[name="adjustment:yaourt"]').attr("readonly")
assert doc('[name="adjustment:fromage"]')
# Needs no adjustment.
assert doc('[name="adjustment:789"]').attr("readonly")
assert doc('[name="adjustment:fromage"]').attr("readonly")
assert doc('input[type="submit"]')
async def test_get_place_order_with_closed_delivery_but_adjustments(client, delivery):
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.orders["foo@bar.org"] = Order(
products={"123": ProductOrder(wanted=1, adjustment=1)}
)
delivery.persist()
assert delivery.status == delivery.CLOSED
resp = await client.get(f"/distribution/{delivery.id}/commander")
doc = pq(resp.body)
assert doc('[name="wanted:123"]').attr("readonly")
assert doc('[name="adjustment:123"]')
async def test_get_place_order_with_closed_delivery_but_force(client, delivery):
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=1)})
delivery.persist()
assert delivery.status == delivery.CLOSED
resp = await client.get(f"/distribution/{delivery.id}/commander")
doc = pq(resp.body)
assert doc('[name="wanted:123"]').attr("readonly") is not None
assert not doc('[name="adjustment:123"]')
resp = await client.get(f"/distribution/{delivery.id}/commander?adjust")
doc = pq(resp.body)
assert doc('[name="wanted:123"]').attr("readonly") is not None
assert doc('[name="adjustment:123"]')
async def test_cannot_place_order_on_closed_delivery(client, delivery, monkeypatch):
monkeypatch.setattr("copanier.config.STAFF", ["someone@else.org"])
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.persist()
body = {"wanted:123": "3"}
body = {"wanted:lait": "3"}
resp = await client.post(f"/distribution/{delivery.id}/commander", body=body)
assert resp.status == 302
delivery = Delivery.load(id=delivery.id)
@ -174,45 +162,45 @@ async def test_cannot_place_order_on_closed_delivery(client, delivery, monkeypat
async def test_get_adjust_product(client, delivery):
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.products[0].packing = 6
delivery.orders["foo@bar.org"] = Order(
products={"123": ProductOrder(wanted=2, adjustment=1)}
delivery.orders["fractal-brocolis"] = Order(
products={"lait": ProductOrder(wanted=2, adjustment=1)}
)
delivery.persist()
assert delivery.status == delivery.ADJUSTMENT
resp = await client.get(f"/distribution/{delivery.id}/ajuster/123")
resp = await client.get(f"/distribution/{delivery.id}/ajuster/lait")
doc = pq(resp.body)
assert doc('[name="foo@bar.org"]')
assert doc('[name="foo@bar.org"]').attr("value") == "1"
assert doc('[name="fractal-brocolis"]')
assert doc('[name="fractal-brocolis"]').attr("value") == "1"
async def test_post_adjust_product(client, delivery):
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.products[0].packing = 6
delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=2)})
delivery.orders["fractal-brocolis"] = Order(products={"lait": ProductOrder(wanted=2)})
delivery.persist()
assert delivery.status == delivery.ADJUSTMENT
body = {"foo@bar.org": "1"}
resp = await client.post(f"/distribution/{delivery.id}/ajuster/123", body=body)
body = {"fractal-brocolis": "1"}
resp = await client.post(f"/distribution/{delivery.id}/ajuster/lait", body=body)
assert resp.status == 302
delivery = Delivery.load(id=delivery.id)
assert delivery.orders["foo@bar.org"].products["123"].wanted == 2
assert delivery.orders["foo@bar.org"].products["123"].adjustment == 1
assert delivery.orders["fractal-brocolis"].products["lait"].wanted == 2
assert delivery.orders["fractal-brocolis"].products["lait"].adjustment == 1
async def test_only_staff_can_adjust_product(client, delivery, monkeypatch):
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.products[0].packing = 6
delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=2)})
delivery.orders["fractal-brocolis"] = Order(products={"lait": ProductOrder(wanted=2)})
delivery.persist()
monkeypatch.setattr("copanier.config.STAFF", ["someone@else.org"])
resp = await client.get(f"/distribution/{delivery.id}/ajuster/123")
resp = await client.get(f"/distribution/{delivery.id}/ajuster/lait")
assert resp.status == 302
body = {"foo@bar.org": "1"}
resp = await client.post(f"/distribution/{delivery.id}/ajuster/123", body=body)
body = {"fractal-brocolis": "1"}
resp = await client.post(f"/distribution/{delivery.id}/ajuster/lait", body=body)
assert resp.status == 302
delivery = Delivery.load(id=delivery.id)
assert delivery.orders["foo@bar.org"].products["123"].wanted == 2
assert delivery.orders["foo@bar.org"].products["123"].adjustment == 0
assert delivery.orders["fractal-brocolis"].products["lait"].wanted == 2
assert delivery.orders["fractal-brocolis"].products["lait"].adjustment == 0
async def test_export_products(client, delivery):
@ -221,15 +209,15 @@ async def test_export_products(client, delivery):
wb = load_workbook(filename=BytesIO(resp.body))
assert list(wb.active.values) == [
(
"name",
"ref",
"price",
"unit",
"description",
"url",
"img",
"packing",
"producer",
'name',
'ref',
'price',
'last_update',
'unit',
'description',
'packing',
'producer',
'rupture'
),
("Lait", "123", 1.5, None, None, None, None, None, None),
("Lait", "lait", 1.5, delivery.products[0].last_update, None, None, None, "ferme-du-coin", None),
]