116 lines
6.1 KiB
Python
116 lines
6.1 KiB
Python
"""Run: python3 -m unittest -v test_catalog_roundtrip.py. Uses disposable DBs only."""
|
|
import copy
|
|
import json
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
import server
|
|
from import_catalog import import_categories
|
|
|
|
|
|
class CatalogTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.tmp = tempfile.TemporaryDirectory()
|
|
server.DATA_DIR = Path(self.tmp.name)
|
|
server.DB_PATH = server.DATA_DIR / 'test.sqlite'
|
|
server.DIST_CATALOG = server.DATA_DIR / 'public.json'
|
|
self.admin = server.ensure_admin_user
|
|
server.ensure_admin_user = lambda: None
|
|
server.init_db()
|
|
self.payload = {'metadata':{'eurToTomanRate':302700}, 'images':[{'id':'photo','original_url':'/i/photo','local_path':'media/photo.webp'}],
|
|
'categories':[{'slug':'lip-gloss','name':'Lip Gloss','nameFa':'لیپ گلاس','parentSlug':'lips'}],
|
|
'products':[{'id':'parent','slug':'lip-gloss','name':'Official English Name','nameFa':'لیپ گلاس کیکو',
|
|
'description':'توضیحات فارسی محصول', 'seoTitle':'عنوان سئو', 'seoDescription':'متای فارسی',
|
|
'details':[{'key':'finish','label':'فینیش','value':'براق'}],
|
|
'blocks':[{'type':'SPECIFICATIONS','content':{'custom':'preserved'}}],
|
|
'variants':[{'id':'shade01','slug':'lip-gloss-01','name':'Official English Name 01','colorCode':'01','colorName':'Rose',
|
|
'description':'توضیحات رنگ اول','seoTitle':'سئو رنگ اول','seoDescription':'متای رنگ اول',
|
|
'details':[{'key':'finish','label':'فینیش','value':'مات'}],
|
|
'price':123456,'stock':3,'images':['/media/a.webp','/media/b.webp'],'heroImage':'/media/a.webp'},
|
|
{'id':'shade02','slug':'lip-gloss-02','name':'Official English Name 02','shade':'02 Red',
|
|
'description':'توضیحات رنگ دوم','details':{'coverage':'full'},'price':234567,'stock':0}]}]}
|
|
|
|
def tearDown(self):
|
|
server.ensure_admin_user = self.admin
|
|
self.tmp.cleanup()
|
|
|
|
def read(self):
|
|
with server.db() as conn:
|
|
return server.product_dict(conn.execute('SELECT * FROM products').fetchone())
|
|
|
|
def test_roundtrip_and_public_export(self):
|
|
import_categories(self.payload)
|
|
result = server.import_products_payload(self.payload)
|
|
self.assertEqual(result['created'],1)
|
|
self.assertEqual(result['errors'],[])
|
|
first = self.read()
|
|
self.assertEqual(len(first['colorVariants']),2)
|
|
self.assertEqual(first['stock'],3)
|
|
for key in ('description','seoTitle','seoDescription','details','blocks'):
|
|
self.assertEqual(first[key],self.payload['products'][0][key])
|
|
for actual,expected in zip(first['colorVariants'],self.payload['products'][0]['variants']):
|
|
for key,value in expected.items(): self.assertEqual(actual[key],value)
|
|
server.export_catalog()
|
|
public=json.loads(server.DIST_CATALOG.read_text())
|
|
self.assertEqual(public['products'][0],first)
|
|
dest=server.DATA_DIR/'backup.json'
|
|
server.export_import_bundle(dest)
|
|
bundle=json.loads(dest.read_text())
|
|
server.DB_PATH=server.DATA_DIR/'second.sqlite'
|
|
server.init_db()
|
|
import_categories(bundle)
|
|
server.import_products_payload(bundle)
|
|
self.assertEqual(self.read(),first)
|
|
with server.db() as conn:
|
|
category=conn.execute('SELECT * FROM categories').fetchone()
|
|
self.assertEqual(category['slug'],'lip-gloss')
|
|
self.assertEqual(category['name_fa'],'لیپ گلاس')
|
|
|
|
def test_reimport_idempotent_and_partial_parent(self):
|
|
server.import_products_payload(self.payload)
|
|
self.assertEqual(server.import_products_payload(self.payload)['updated'],1)
|
|
server.import_products_payload({'products':[{'id':'parent','name':'Updated','slug':'lip-gloss'}]})
|
|
self.assertEqual(self.read()['description'],'توضیحات فارسی محصول')
|
|
self.assertEqual(len(self.read()['colorVariants']),2)
|
|
with server.db() as conn:self.assertEqual(conn.execute('SELECT COUNT(*) FROM products').fetchone()[0],1)
|
|
|
|
def test_invalid_variants_do_not_replace_existing(self):
|
|
server.import_products_payload(self.payload)
|
|
before=self.read()
|
|
bad=copy.deepcopy(self.payload)
|
|
bad['products'][0]['variants'][1]['id']='shade01'
|
|
self.assertEqual(server.import_products_payload(bad)['skipped'],1)
|
|
self.assertEqual(self.read(),before)
|
|
bad['products'][0]['variants'][1]['id']='shade02'
|
|
bad['products'][0]['variants'][0]['price']=float('nan')
|
|
self.assertEqual(server.import_products_payload(bad)['skipped'],1)
|
|
self.assertEqual(self.read(),before)
|
|
|
|
def test_inactive_retained_in_backup_not_public(self):
|
|
self.payload['products'][0]['active']=False
|
|
server.import_products_payload(self.payload)
|
|
server.export_catalog()
|
|
self.assertEqual(json.loads(server.DIST_CATALOG.read_text())['products'],[])
|
|
dest=server.DATA_DIR/'backup.json'
|
|
server.export_import_bundle(dest)
|
|
self.assertEqual(len(json.loads(dest.read_text())['products']),1)
|
|
|
|
def test_old_database_migration(self):
|
|
# Recreate the original product table by dropping only the newly added column.
|
|
with server.db() as conn:conn.execute('ALTER TABLE products DROP COLUMN content_json')
|
|
server.init_db()
|
|
server.init_db()
|
|
self.assertEqual(server.import_products_payload(self.payload)['created'],1)
|
|
|
|
def test_image_batches_merge(self):
|
|
server.import_products_payload(self.payload)
|
|
server.import_products_payload({'metadata':{'newKey':'x'},'images':[{'id':'another','original_url':'/i/another'}],'products':[]})
|
|
dest=server.DATA_DIR/'backup.json'
|
|
server.export_import_bundle(dest)
|
|
data=json.loads(dest.read_text())
|
|
self.assertEqual(len(data['images']),2)
|
|
self.assertEqual(data['metadata']['eurToTomanRate'],302700)
|
|
|
|
|
|
if __name__=='__main__': unittest.main()
|