From 979499602ff351af3329a247014c2669ed2898f9 Mon Sep 17 00:00:00 2001 From: jableader Date: Sun, 29 Sep 2024 15:04:10 +1000 Subject: [PATCH] Add support for coles, and tests --- products/__init__.py | 65 ++++----- products/coles.py | 88 +++++++++++++ products/db.py | 20 +-- products/{scraping.py => woolworths.py} | 36 ++++- tests/httpx_mocks.py | 124 ++++++++++++++++++ .../coles/GET_https:__www.coles.com.au_.json | 41 ++++++ ..._coles-strawberries-250g-5191256.json.json | 46 +++++++ .../GET_https:__www.woolworths.com.au_.json | 57 ++++++++ ....com.au_apis_ui_product_detail_144607.json | 61 +++++++++ tests/test_data.py | 8 ++ tests/test_main.py | 27 +--- tests/test_products.py | 104 +++++++++++++++ 12 files changed, 597 insertions(+), 80 deletions(-) create mode 100644 products/coles.py rename products/{scraping.py => woolworths.py} (64%) create mode 100644 tests/httpx_mocks.py create mode 100644 tests/sample_files/coles/GET_https:__www.coles.com.au_.json create mode 100644 tests/sample_files/coles/GET_https:__www.coles.com.au__next_data_20240926.02_v4.18.0_en_product_coles-strawberries-250g-5191256.json.json create mode 100644 tests/sample_files/woolworths/GET_https:__www.woolworths.com.au_.json create mode 100644 tests/sample_files/woolworths/GET_https:__www.woolworths.com.au_apis_ui_product_detail_144607.json create mode 100644 tests/test_products.py diff --git a/products/__init__.py b/products/__init__.py index 5313c28..f3bf01d 100644 --- a/products/__init__.py +++ b/products/__init__.py @@ -1,44 +1,20 @@ import json -from products.db import Product, find_product_by_tag, find_product_by_product_id, insert_product, get_tags, add_tag, find_product_by_id -from products.scraping import scrape_woolies_data, get_product_id, get_product_details_url +from products.db import Product, find_product_by_tag, find_product_by_key, insert_product, get_tags, add_tag, find_product_by_id -from typing import List +from products import woolworths, coles +SCRAPERS = { 'woolworths': woolworths, 'coles': coles } + +from typing import List, Union import re -def get_package_size(data: dict) -> str: - size = data['Product']['PackageSize'] - if size: - match = re.match(r'(\d+)(.*)', size) - if match: - return int(match.group(1)), match.group(2) +def _get_shop_key(link: str) -> Union[str, str]: # (shop_code, product_id) + for shop_code, shop_scraper in SCRAPERS.items(): + product_id = shop_scraper.get_product_id(link) + if product_id: + return shop_code, product_id + return None, None - return 1, 'items' - -async def create_product(link: str) -> Product: - product_id = get_product_id(link) - if not product_id: - return None, None - - product_url = get_product_details_url(product_id) - product, data = None, await scrape_woolies_data(product_url) - if data: - _dump_json_data_to_log(data, product_id) - - quantity, unit = get_package_size(data) - product = Product( - id=0, - product_id=product_id, - name=data['Product']['Name'], - link=link, - quantity=quantity, - unit=unit, - img_small=data['Product']['SmallImageFile'], - img_large=data['Product']['LargeImageFile'], - ) - - return product, data - async def add_missing_tags(conn, product: Product, tags: List[str]): existing_tags = set() async for tag in get_tags(conn, product): @@ -54,19 +30,26 @@ async def add_missing_tags(conn, product: Product, tags: List[str]): return product async def get_or_create(conn, url: str, tags: List[str]) -> Product: - product_id = get_product_id(url) + shop_code, product_id = _get_shop_key(url) if not product_id: return None - existing = await find_product_by_product_id(conn, product_id) + existing = await find_product_by_key(conn, shop_code, product_id) if existing: await add_missing_tags(conn, existing, tags) return existing - product, data = await create_product(url) - if product: - await insert_product(conn, product, data) - await add_missing_tags(conn, product, tags) + product_data, raw_response = await SCRAPERS[shop_code].scrape(product_id) + product = Product( + id=-1, + shop_code=shop_code, + product_id=product_id, + link=url, + **product_data + ) + + await insert_product(conn, product, raw_response) + await add_missing_tags(conn, product, tags) return product diff --git a/products/coles.py b/products/coles.py new file mode 100644 index 0000000..1244c7e --- /dev/null +++ b/products/coles.py @@ -0,0 +1,88 @@ +import re, httpx +from typing import Union + +HEADERS = { + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate, br', + 'DNT': '1', + 'Sec-GPC': '1', + 'Connection': 'keep-alive', + 'Upgrade-Insecure-Requests': '1', + 'Sec-Fetch-Dest': 'document', + 'Sec-Fetch-Mode': 'navigate', + 'Sec-Fetch-Site': 'none', + 'Sec-Fetch-User': '?1', + 'Pragma': 'no-cache', + 'Cache-Control': 'no-cache', +} + +async def _get_cookies(client): + # Make a request to https://www.coles.com.au/ as if we were a normal browser, then return the cookies + response = await client.get('https://www.coles.com.au/', headers=HEADERS, follow_redirects=True) + return dict(response.cookies) + +def _get_package_size(size: str) -> Union[int, str]: + if size: + match = re.match(r'(\d+)(.*)', size) + if match: + return int(match.group(1)), match.group(2) + + return 1, 'items' + +def _get_client(): + return httpx.AsyncClient() + +last_cookies = None +async def _request_url(url: str) -> dict: + global last_cookies + + async with _get_client() as client: + if last_cookies: + cookies = last_cookies + else: + cookies = await _get_cookies(client) + last_cookies = cookies + + try: + response = await client.get(url, headers=HEADERS, follow_redirects=True, cookies=cookies) + response.raise_for_status() + return response.json() + except httpx.NetworkError as ne: + print(ne) + last_cookies = None + return None + +def _get_product_details_url(product_id) -> str: + # https://www.coles.com.au/_next/data/20240926.02_v4.18.0/en/product/cadbury-favourites-boxed-chocolate-340g-3571992.json?slug=cadbury-favourites-boxed-chocolate-340g-3571992 + # https://www.coles.com.au/_next/data/20240926.02_v4.18.0/en/product/coles-blueberries-170g-3571948.json?slug=coles-blueberries-170g-3571948 + return f'https://www.coles.com.au/_next/data/20240926.02_v4.18.0/en/product/{product_id}.json' + +def get_product_id(url: str) -> str: + # https://www.coles.com.au/product/cadbury-favourites-boxed-chocolate-340g-3571992 + regex = r'https://www.coles.com.au/product/([^/]+)/?.*' + match = re.match(regex, url) + if match: + return match.group(1) + return None + +async def scrape(product_id: str) -> Union[dict, dict]: + details_url = _get_product_details_url(product_id) + raw_data = await _request_url(details_url) + + product = raw_data['pageProps']['product'] + + quantity, unit = _get_package_size(product['size']) + + img_prefix = 'https://shop.coles.com.au' + images = product['images'][0] + product_data = { + 'name': product['name'], + 'quantity': quantity, + 'unit': unit, + 'img_small': (img_prefix + images['thumb']['path']) if images else None, + 'img_large': (img_prefix + images['full']['path']) if images else None, + } + + return product_data, raw_data \ No newline at end of file diff --git a/products/db.py b/products/db.py index 22107b4..cf6b788 100644 --- a/products/db.py +++ b/products/db.py @@ -4,11 +4,12 @@ from pydantic import BaseModel import json class Product(BaseModel): - KEYS: ClassVar[List[str]] = ['id', 'product_id', 'link', 'name', 'quantity', 'unit', 'img_small', 'img_large'] + KEYS: ClassVar[List[str]] = ['id', 'product_id', 'shop_code', 'link', 'name', 'quantity', 'unit', 'img_small', 'img_large'] NON_INSERT_KEYS: ClassVar[List[str]] = ['id'] id: int = -1 product_id: str + shop_code: str link: str name: str quantity: int @@ -20,11 +21,12 @@ async def create(conn): await conn.execute(''' CREATE TABLE IF NOT EXISTS Product ( id INTEGER PRIMARY KEY, - product_id TEXT UNIQUE, - link TEXT, - name TEXT, - quantity INTEGER, - unit TEXT, + product_id TEXT UNIQUE NOT NULL, + shop_code TEXT NOT NULL, + link TEXT NOT NULL, + name TEXT NOT NULL, + quantity INTEGER NOT NULL, + unit TEXT NOT NULL, img_small TEXT, img_large TEXT, raw_data TEXT @@ -58,12 +60,12 @@ async def find_product_by_id(conn, product_id: str) -> Product: async for row in cursor: return Product(**{k:v for k,v in zip(Product.KEYS, row)}) -async def find_product_by_product_id(conn, product_id: str) -> Product: +async def find_product_by_key(conn, shop_code: str, product_id: str) -> Product: async with conn.execute(f''' SELECT {','.join(Product.KEYS)} FROM Product - WHERE product_id = ? + WHERE shop_code = ? AND product_id = ? LIMIT 1 - ''', (product_id,)) as cursor: + ''', (shop_code, product_id,)) as cursor: async for row in cursor: return Product(**{k:v for k,v in zip(Product.KEYS, row)}) diff --git a/products/scraping.py b/products/woolworths.py similarity index 64% rename from products/scraping.py rename to products/woolworths.py index 0c50473..e7614e3 100644 --- a/products/scraping.py +++ b/products/woolworths.py @@ -1,5 +1,7 @@ import re, httpx +from typing import Union + HEADERS = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', @@ -22,11 +24,23 @@ async def _get_cookies(client): response = await client.get('https://www.woolworths.com.au/', headers=HEADERS, follow_redirects=True) return dict(response.cookies) +def _get_package_size(data: dict) -> str: + size = data['Product']['PackageSize'] + if size: + match = re.match(r'(\d+)(.*)', size) + if match: + return int(match.group(1)), match.group(2) + + return 1, 'items' + +def _get_client() -> httpx.AsyncClient: + return httpx.AsyncClient() + last_cookies = None -async def scrape_woolies_data(url: str) -> dict: +async def _request_url(url: str) -> dict: global last_cookies - async with httpx.AsyncClient() as client: + async with _get_client() as client: if last_cookies: cookies = last_cookies else: @@ -42,6 +56,9 @@ async def scrape_woolies_data(url: str) -> dict: last_cookies = None return None +def _get_product_details_url(product_id) -> str: + return f'https://www.woolworths.com.au/apis/ui/product/detail/{product_id}' + def get_product_id(url: str) -> str: woolies_regex = r'https://www.woolworths.com.au/shop/productdetails/(\d+)/?.*' match = re.match(woolies_regex, url) @@ -49,6 +66,17 @@ def get_product_id(url: str) -> str: return match.group(1) return None -def get_product_details_url(product_id) -> str: - return f'https://www.woolworths.com.au/apis/ui/product/detail/{product_id}' +async def scrape(product_id: str) -> Union[dict, dict]: + details_url = _get_product_details_url(product_id) + raw_data = await _request_url(details_url) + quantity, unit = _get_package_size(raw_data) + product_data = { + 'name': raw_data['Product']['Name'], + 'quantity': quantity, + 'unit': unit, + 'img_small': raw_data['Product']['SmallImageFile'], + 'img_large': raw_data['Product']['LargeImageFile'], + } + + return product_data, raw_data \ No newline at end of file diff --git a/tests/httpx_mocks.py b/tests/httpx_mocks.py new file mode 100644 index 0000000..eaebbd4 --- /dev/null +++ b/tests/httpx_mocks.py @@ -0,0 +1,124 @@ +import httpx +import json +import os + +class RecordingAsyncClient: + def __init__(self, save_dir: str): + self.save_dir = save_dir + os.makedirs(self.save_dir, exist_ok=True) + self.client = None # Will be initialized in __aenter__ + + async def __aenter__(self): + # Initialize the actual AsyncClient when entering the context manager + self.client = httpx.AsyncClient() + return self + + async def __aexit__(self, exc_type, exc_value, traceback): + # Ensure the client is closed when exiting the context manager + await self.client.aclose() + + async def request(self, method: str, url: str, **kwargs): + # Send the actual request + response = await self.client.request(method, url, **kwargs) + + # Record the request and response + record = { + "request": { + "method": method, + "url": url, + "headers": dict(response.request.headers), + "content": response.request.content.decode('utf-8', errors='ignore'), + }, + "response": { + "status_code": response.status_code, + "headers": dict(response.headers), + "content": response.text, + "cookies": dict(response.cookies), + } + } + + # Generate a filename based on the URL and method + record_file = os.path.join(self.save_dir, f"{method}_{url.replace('/', '_')}.json") + + # Save the record to a file + with open(record_file, 'w') as f: + json.dump(record, f, indent=4) + + return response + + async def get(self, url: str, **kwargs): + return await self.request("GET", url, **kwargs) + + async def post(self, url: str, **kwargs): + return await self.request("POST", url, **kwargs) + + async def put(self, url: str, **kwargs): + return await self.request("PUT", url, **kwargs) + + async def delete(self, url: str, **kwargs): + return await self.request("DELETE", url, **kwargs) + +from unittest.mock import Mock +import os +import json + +class MockAsyncClient: + def __init__(self, load_dir: str): + self.load_dir = load_dir + + async def __aenter__(self): + # No actual client to initialize, just return the instance + return self + + async def __aexit__(self, exc_type, exc_value, traceback): + # No actual client to close + pass + + async def request(self, method: str, url: str, **kwargs): + # Generate the filename based on the URL and method + record_file = os.path.join(self.load_dir, f"{method}_{url.replace('/', '_')}.json") + + if not os.path.exists(record_file): + raise FileNotFoundError(f"Recorded response not found for {method} {url}") + + # Load the recorded response from the file + with open(record_file, 'r') as f: + record = json.load(f) + + # Create a mock response object + mock_response = Mock() + + # Mock the status code + mock_response.status_code = record['response']['status_code'] + + # Mock the json method to return the content as a parsed JSON + def mock_json(): + try: + return json.loads(record['response']['content']) + except json.JSONDecodeError: + return record['response']['content'] + + mock_response.json = mock_json + + # Mock the cookies as a dictionary + mock_response.cookies = record['response']['cookies'] + + # Mock the headers as a dictionary + mock_response.headers = record['response']['headers'] + + # Mock the text attribute + mock_response.text = record['response']['content'] + + return mock_response + + async def get(self, url: str, **kwargs): + return await self.request("GET", url, **kwargs) + + async def post(self, url: str, **kwargs): + return await self.request("POST", url, **kwargs) + + async def put(self, url: str, **kwargs): + return await self.request("PUT", url, **kwargs) + + async def delete(self, url: str, **kwargs): + return await self.request("DELETE", url, **kwargs) diff --git a/tests/sample_files/coles/GET_https:__www.coles.com.au_.json b/tests/sample_files/coles/GET_https:__www.coles.com.au_.json new file mode 100644 index 0000000..269b705 --- /dev/null +++ b/tests/sample_files/coles/GET_https:__www.coles.com.au_.json @@ -0,0 +1,41 @@ +{ + "request": { + "method": "GET", + "url": "https://www.coles.com.au/", + "headers": { + "host": "www.coles.com.au", + "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0", + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "accept-language": "en-US,en;q=0.5", + "accept-encoding": "gzip, deflate, br", + "dnt": "1", + "sec-gpc": "1", + "connection": "keep-alive", + "upgrade-insecure-requests": "1", + "sec-fetch-dest": "document", + "sec-fetch-mode": "navigate", + "sec-fetch-site": "none", + "sec-fetch-user": "?1", + "pragma": "no-cache", + "cache-control": "no-cache" + }, + "content": "" + }, + "response": { + "status_code": 200, + "headers": { + "content-type": "text/html", + "cache-control": "no-cache, no-store", + "connection": "close", + "content-length": "3345", + "x-iinfo": "7-26769261-0 0CNN RT(1727584618151 22) q(0 -1 -1 1) r(0 -1) B10(14,0,0)", + "strict-transport-security": "max-age=31536000; includeSubDomains", + "set-cookie": "visid_incap_2800108=vNYK15gzRoOHbzyO31mNh2rZ+GYAAAAAQUIPAAAAAABwIQoipD3Nw8q38f6JHIb5; expires=Sun, 28 Sep 2025 12:16:28 GMT; HttpOnly; path=/; Domain=.coles.com.au; Secure; SameSite=None, incap_ses_808_2800108=AWejGplhXmNxgGAG25c2C2rZ+GYAAAAAr91ZD4bl3op+nNtxHCpveg==; path=/; Domain=.coles.com.au; Secure; SameSite=None" + }, + "content": "\r\n\r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n\r\n \r\n\r\n
\r\n \r\n \r\n

Pardon Our Interruption

\r\n

As you were browsing something about your browser made us think you were a bot. There are a few reasons this might happen:

\r\n\r\n

To regain access, please make sure that cookies and JavaScript are enabled before reloading the page.

\r\n\r\n\r\n
\r\n \r\n \r\n\r\n", + "cookies": { + "visid_incap_2800108": "vNYK15gzRoOHbzyO31mNh2rZ+GYAAAAAQUIPAAAAAABwIQoipD3Nw8q38f6JHIb5", + "incap_ses_808_2800108": "AWejGplhXmNxgGAG25c2C2rZ+GYAAAAAr91ZD4bl3op+nNtxHCpveg==" + } + } +} \ No newline at end of file diff --git a/tests/sample_files/coles/GET_https:__www.coles.com.au__next_data_20240926.02_v4.18.0_en_product_coles-strawberries-250g-5191256.json.json b/tests/sample_files/coles/GET_https:__www.coles.com.au__next_data_20240926.02_v4.18.0_en_product_coles-strawberries-250g-5191256.json.json new file mode 100644 index 0000000..1bff513 --- /dev/null +++ b/tests/sample_files/coles/GET_https:__www.coles.com.au__next_data_20240926.02_v4.18.0_en_product_coles-strawberries-250g-5191256.json.json @@ -0,0 +1,46 @@ +{ + "request": { + "method": "GET", + "url": "https://www.coles.com.au/_next/data/20240926.02_v4.18.0/en/product/coles-strawberries-250g-5191256.json", + "headers": { + "host": "www.coles.com.au", + "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0", + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "accept-language": "en-US,en;q=0.5", + "accept-encoding": "gzip, deflate, br", + "dnt": "1", + "sec-gpc": "1", + "connection": "keep-alive", + "upgrade-insecure-requests": "1", + "sec-fetch-dest": "document", + "sec-fetch-mode": "navigate", + "sec-fetch-site": "none", + "sec-fetch-user": "?1", + "pragma": "no-cache", + "cache-control": "no-cache", + "cookie": "visid_incap_2800108=vNYK15gzRoOHbzyO31mNh2rZ+GYAAAAAQUIPAAAAAABwIQoipD3Nw8q38f6JHIb5; incap_ses_808_2800108=AWejGplhXmNxgGAG25c2C2rZ+GYAAAAAr91ZD4bl3op+nNtxHCpveg==; visid_incap_2800108=vNYK15gzRoOHbzyO31mNh2rZ+GYAAAAAQUIPAAAAAABwIQoipD3Nw8q38f6JHIb5; incap_ses_808_2800108=AWejGplhXmNxgGAG25c2C2rZ+GYAAAAAr91ZD4bl3op+nNtxHCpveg==" + }, + "content": "" + }, + "response": { + "status_code": 200, + "headers": { + "content-type": "application/json", + "date": "Sun, 29 Sep 2024 04:37:02 GMT", + "cache-control": "private, no-cache, no-store, max-age=0, must-revalidate", + "content-encoding": "gzip", + "etag": "\"afgb8q55swd9s\"", + "transfer-encoding": "chunked", + "vary": "Accept-Encoding", + "request-context": "appId=cid-v1:", + "set-cookie": "nlbi_2800108_2670698=RtwgEfqECW7ISipTjQyMFgAAAADh8zh0Q4u70LwfHUW03dqj; HttpOnly; path=/; Domain=.coles.com.au; Secure; SameSite=None", + "strict-transport-security": "max-age=31536000; includeSubDomains", + "x-cdn": "Imperva", + "x-iinfo": "10-31454574-31454577 NNNY CT(3 13 0) RT(1727584621988 15) q(0 0 0 -1) r(1 1) U5" + }, + "content": "{\"pageProps\":{\"assetsUrl\":\"https://shop.coles.com.au\",\"_sentryTraceData\":\"22f9fa32d82242eb85b4804437666def-92027aa4ba82bdba-0\",\"_sentryBaggage\":\"sentry-environment=prod,sentry-release=20240926.02_v4.18.0,sentry-transaction=%2Fproduct%2F%5Bslug%5D,sentry-public_key=fe929b0cab4a4e3694d4ce2c52b13210,sentry-trace_id=22f9fa32d82242eb85b4804437666def,sentry-sample_rate=0.6\",\"product\":{\"id\":5191256,\"name\":\"Strawberries\",\"brand\":\"Coles\",\"description\":\"STRAWBERRIES:BERRIES:.:250 GRAM\",\"size\":\"250g\",\"imageUris\":[{\"altText\":\"\",\"type\":\"default\",\"uri\":\"/5/5191256.jpg\"}],\"minGuarantee\":null,\"merchandiseHeir\":{\"tradeProfitCentre\":\"FRESH PROD\",\"categoryGroup\":\"FRUIT\",\"category\":\"BERRIES & CHERRIES\",\"subCategory\":\"BERRIES.\",\"className\":\"STRAWBERRIES.\"},\"onlineHeirs\":[{\"aisle\":\"Berries & cherries\",\"category\":\"Fruit\",\"subCategory\":\"Fruit & vegetables\",\"categoryId\":\"1302\",\"aisleId\":\"1701\",\"subCategoryId\":\"2100\"}],\"associatedProductId\":null,\"continuity\":null,\"lifestyle\":null,\"lastUpdated\":\"2024-09-29T04:37:02Z\",\"locations\":[{\"aisleSide\":\"Front of Store\",\"description\":\"Located in Fresh produce at $STORE\",\"facing\":0,\"aisle\":\"Fresh produce\",\"order\":0,\"shelf\":null}],\"additionalInfo\":[],\"excludeFromSubstitution\":false,\"brandDetails\":{\"id\":3955134709,\"name\":\"Coles\",\"seoToken\":\"coles\"},\"collectableCampaign\":null,\"disclaimers\":null,\"internalDescription\":\"\",\"longDescription\":\"

Technically related to roses, there is no wonder why strawberries look, smell and taste appealing. Strawberries are best stored in the refrigerator but are sweeter when eaten at room temperature

\",\"nutrition\":null,\"nutritionalClaims\":null,\"pricing\":{\"now\":3,\"was\":null,\"saveAmount\":null,\"saveStatement\":null,\"unit\":{\"quantity\":1,\"ofMeasureQuantity\":1,\"ofMeasureUnits\":\"kg\",\"price\":12,\"ofMeasureType\":\"kg\",\"isWeighted\":false,\"isIncremental\":false},\"comparable\":\"$12.00 per 1kg\",\"promotionType\":null,\"onlineSpecial\":false,\"multiBuyPromotion\":null,\"priceDescription\":null,\"savePercent\":null,\"specialType\":null,\"offerDescription\":null},\"variations\":null,\"images\":[{\"thumb\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256-th.jpg\",\"description\":null},\"zoom\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256-zm.jpg\",\"description\":\"Product Image of Strawberries\"},\"full\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256.jpg\",\"description\":null}}],\"restrictions\":{\"retailLimit\":50,\"promotionalLimit\":50,\"liquorAgeRestrictionFlag\":false,\"tobaccoAgeRestrictionFlag\":false,\"delivery\":[\"OVN\",\"REMOTE SERVICE\",\"TEMP\"],\"restrictedByOrganisation\":false},\"countryOfOrigin\":{\"logoRequired\":true,\"barcodeRequired\":true,\"descriptionRequired\":true,\"country\":\"Australian\",\"barcodePercentage\":100,\"statement\":\"Australian Grown\",\"description\":\"Australian Grown\"},\"availability\":false},\"baseUrl\":\"https://www.coles.com.au\",\"isRestricted\":false,\"isFromGoogleAdSource\":false,\"initialState\":{\"user\":{\"error\":null,\"auth\":{\"authenticated\":false},\"account\":{\"notifications\":[]}},\"modal\":{\"active\":null,\"state\":{}},\"notifications\":{\"notifications\":[],\"listNotifications\":[],\"showShoppableWarning\":false},\"mpgs\":{\"formFieldValidity\":{\"cardNumberValidity\":\"undetermined\",\"expiryYearValidity\":\"undetermined\",\"expiryMonthValidity\":\"undetermined\",\"cvvValidity\":\"undetermined\"},\"initStatus\":\"unset\",\"submitStatus\":\"unsubmitted\",\"successData\":null,\"unexpectedError\":false,\"saveToProfile\":false},\"trolley\":{\"error\":null,\"itemsBeingUpdated\":[],\"failedItemGroups\":[],\"resolvedProductIdsFromFailedItemGroup\":[],\"storeId\":\"0584\",\"validation\":{\"isValidating\":false,\"isValid\":false,\"validationErrors\":null,\"error\":null,\"restrictedItems\":null},\"isSwappingItems\":false,\"updateQueue\":[],\"updateQueueCallbacks\":[],\"processUpdateQueueImmediately\":false,\"isProcessUpdateQueueErrorNotificationMuted\":false,\"fetchContext\":{}},\"drawer\":{\"active\":[],\"state\":{}},\"shoppingMethod\":{\"isEditing\":false,\"didStoreIdChange\":false,\"state\":{}},\"enquiryForms\":{\"ids\":[],\"entities\":{}},\"list\":{\"error\":null,\"patchListItemsQueue\":[]},\"content\":{\"pageCategoryL1\":\"\",\"pageCategoryL2\":\"\",\"displayFilter\":false,\"expandFilter\":[],\"nextLevel\":false,\"pageTitle\":\"\",\"pageType\":\"\",\"breadcrumbs\":[],\"recipeId\":\"\",\"isDisplayShopIngredients\":false,\"globalUrgencyStrip\":{},\"recipeServingSize\":4,\"deliveryMethod\":false},\"seoJsonLd\":{\"componentJsonLd\":{},\"showAsJsonLd\":false},\"bffApi\":{\"queries\":{\"getProductDetails({\\\"productId\\\":\\\"5191256\\\",\\\"storeId\\\":\\\"0584\\\"})\":{\"status\":\"fulfilled\",\"endpointName\":\"getProductDetails\",\"requestId\":\"Km0bBANWNebKcNPoMor5f\",\"originalArgs\":{\"storeId\":\"0584\",\"productId\":\"5191256\",\"isGQLEnabled\":true},\"startedTimeStamp\":1727584622499,\"data\":{\"id\":5191256,\"name\":\"Strawberries\",\"brand\":\"Coles\",\"description\":\"STRAWBERRIES:BERRIES:.:250 GRAM\",\"size\":\"250g\",\"imageUris\":[{\"altText\":\"\",\"type\":\"default\",\"uri\":\"/5/5191256.jpg\"}],\"minGuarantee\":null,\"merchandiseHeir\":{\"tradeProfitCentre\":\"FRESH PROD\",\"categoryGroup\":\"FRUIT\",\"category\":\"BERRIES & CHERRIES\",\"subCategory\":\"BERRIES.\",\"className\":\"STRAWBERRIES.\"},\"onlineHeirs\":[{\"aisle\":\"Berries & cherries\",\"category\":\"Fruit\",\"subCategory\":\"Fruit & vegetables\",\"categoryId\":\"1302\",\"aisleId\":\"1701\",\"subCategoryId\":\"2100\"}],\"associatedProductId\":null,\"continuity\":null,\"lifestyle\":null,\"lastUpdated\":\"2024-09-29T04:37:02Z\",\"locations\":[{\"aisleSide\":\"Front of Store\",\"description\":\"Located in Fresh produce at $STORE\",\"facing\":0,\"aisle\":\"Fresh produce\",\"order\":0,\"shelf\":null}],\"additionalInfo\":[],\"excludeFromSubstitution\":false,\"brandDetails\":{\"id\":3955134709,\"name\":\"Coles\",\"seoToken\":\"coles\"},\"collectableCampaign\":null,\"disclaimers\":null,\"internalDescription\":\"\",\"longDescription\":\"

Technically related to roses, there is no wonder why strawberries look, smell and taste appealing. Strawberries are best stored in the refrigerator but are sweeter when eaten at room temperature

\",\"nutrition\":null,\"nutritionalClaims\":null,\"pricing\":{\"now\":3,\"was\":null,\"saveAmount\":null,\"saveStatement\":null,\"unit\":{\"quantity\":1,\"ofMeasureQuantity\":1,\"ofMeasureUnits\":\"kg\",\"price\":12,\"ofMeasureType\":\"kg\",\"isWeighted\":false,\"isIncremental\":false},\"comparable\":\"$12.00 per 1kg\",\"promotionType\":null,\"onlineSpecial\":false,\"multiBuyPromotion\":null,\"priceDescription\":null,\"savePercent\":null,\"specialType\":null,\"offerDescription\":null},\"variations\":null,\"images\":[{\"thumb\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256-th.jpg\",\"description\":null},\"zoom\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256-zm.jpg\",\"description\":\"Product Image of Strawberries\"},\"full\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256.jpg\",\"description\":null}}],\"restrictions\":{\"retailLimit\":50,\"promotionalLimit\":50,\"liquorAgeRestrictionFlag\":false,\"tobaccoAgeRestrictionFlag\":false,\"delivery\":[\"OVN\",\"REMOTE SERVICE\",\"TEMP\"],\"restrictedByOrganisation\":false},\"countryOfOrigin\":{\"logoRequired\":true,\"barcodeRequired\":true,\"descriptionRequired\":true,\"country\":\"Australian\",\"barcodePercentage\":100,\"statement\":\"Australian Grown\",\"description\":\"Australian Grown\"},\"availability\":false},\"fulfilledTimeStamp\":1727584622593}},\"mutations\":{},\"provided\":{},\"subscriptions\":{\"getProductDetails({\\\"productId\\\":\\\"5191256\\\",\\\"storeId\\\":\\\"0584\\\"})\":{\"Km0bBANWNebKcNPoMor5f\":{}}},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"bffApi\"}},\"aemApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"aemApi\"}},\"enquiryFormApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"enquiryFormApi\"}},\"b2bFormsApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"b2bFormsApi\"}},\"radioComplaintsFormApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"radioComplaintsFormApi\"}},\"psdsFormApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"psdsFormApi\"}},\"adobeTargetApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"adobeTargetApi\"}},\"abandonedTrolleyFormApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"abandonedTrolleyFormApi\"}},\"digitalGraphQLApi\":{\"queries\":{\"GetProductDetails({\\\"productId\\\":\\\"5191256\\\",\\\"storeId\\\":\\\"COL:0584\\\"})\":{\"status\":\"fulfilled\",\"endpointName\":\"GetProductDetails\",\"requestId\":\"u8CAjkFrvBHOH_C1wBmOi\",\"originalArgs\":{\"storeId\":\"COL:0584\",\"productId\":\"5191256\"},\"startedTimeStamp\":1727584622501,\"data\":{\"product\":{\"id\":5191256,\"name\":\"Strawberries\",\"brand\":\"Coles\",\"description\":\"STRAWBERRIES:BERRIES:.:250 GRAM\",\"size\":\"250g\",\"imageUris\":[{\"altText\":\"\",\"type\":\"default\",\"uri\":\"/5/5191256.jpg\"}],\"images\":[{\"thumb\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256-th.jpg\",\"description\":null},\"zoom\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256-zm.jpg\",\"description\":\"Product Image of Strawberries\"},\"full\":{\"path\":\"/wcsstore/Coles-CAS/images/5/1/9/5191256.jpg\",\"description\":null}}],\"restrictions\":{\"retailLimit\":50,\"promotionalLimit\":50,\"liquorAgeRestrictionFlag\":false,\"tobaccoAgeRestrictionFlag\":false,\"delivery\":[\"OVN\",\"REMOTE SERVICE\",\"TEMP\"],\"restrictedByOrganisation\":false},\"availability\":false,\"minGuarantee\":null,\"merchandiseHeir\":{\"tradeProfitCentre\":\"FRESH PROD\",\"categoryGroup\":\"FRUIT\",\"category\":\"BERRIES & CHERRIES\",\"subCategory\":\"BERRIES.\",\"className\":\"STRAWBERRIES.\"},\"onlineHeirs\":[{\"aisle\":\"Berries & cherries\",\"category\":\"Fruit\",\"subCategory\":\"Fruit & vegetables\",\"categoryId\":\"1302\",\"aisleId\":\"1701\",\"subCategoryId\":\"2100\"}],\"associatedProductId\":null,\"continuity\":null,\"lifestyle\":null,\"countryOfOrigin\":{\"logoRequired\":true,\"barcodeRequired\":true,\"descriptionRequired\":true,\"country\":\"Australian\",\"barcodePercentage\":100,\"statement\":\"Australian Grown\",\"description\":\"Australian Grown\"},\"lastUpdated\":\"2024-09-29T04:37:02Z\",\"locations\":[{\"aisleSide\":\"Front of Store\",\"description\":\"Located in Fresh produce at $STORE\",\"facing\":0,\"aisle\":\"Fresh produce\",\"order\":0,\"shelf\":null}],\"additionalInfo\":[],\"excludeFromSubstitution\":false,\"brandDetails\":{\"id\":3955134709,\"name\":\"Coles\",\"seoToken\":\"coles\"},\"collectableCampaign\":null,\"disclaimers\":null,\"internalDescription\":\"\",\"longDescription\":\"

Technically related to roses, there is no wonder why strawberries look, smell and taste appealing. Strawberries are best stored in the refrigerator but are sweeter when eaten at room temperature

\",\"nutrition\":null,\"nutritionalClaims\":null,\"pricing\":{\"now\":3,\"was\":null,\"saveAmount\":null,\"saveStatement\":null,\"unit\":{\"quantity\":1,\"ofMeasureQuantity\":1,\"ofMeasureUnits\":\"kg\",\"price\":12,\"ofMeasureType\":\"kg\",\"isWeighted\":false,\"isIncremental\":false},\"comparable\":\"$12.00 per 1kg\",\"promotionType\":null,\"onlineSpecial\":false,\"multiBuyPromotion\":null,\"priceDescription\":null,\"savePercent\":null,\"specialType\":null,\"offerDescription\":null},\"variations\":null}},\"fulfilledTimeStamp\":1727584622591}},\"mutations\":{},\"provided\":{},\"subscriptions\":{\"GetProductDetails({\\\"productId\\\":\\\"5191256\\\",\\\"storeId\\\":\\\"COL:0584\\\"})\":{}},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"digitalGraphQLApi\"}},\"nextApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":true,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"nextApi\"}}}},\"initialState\":{\"user\":{\"error\":null,\"auth\":{\"authenticated\":false},\"account\":{\"notifications\":[]}},\"modal\":{\"active\":null,\"state\":{}},\"notifications\":{\"notifications\":[],\"listNotifications\":[],\"showShoppableWarning\":false},\"mpgs\":{\"formFieldValidity\":{\"cardNumberValidity\":\"undetermined\",\"expiryYearValidity\":\"undetermined\",\"expiryMonthValidity\":\"undetermined\",\"cvvValidity\":\"undetermined\"},\"initStatus\":\"unset\",\"submitStatus\":\"unsubmitted\",\"successData\":null,\"unexpectedError\":false,\"saveToProfile\":false},\"trolley\":{\"error\":null,\"itemsBeingUpdated\":[],\"failedItemGroups\":[],\"resolvedProductIdsFromFailedItemGroup\":[],\"storeId\":\"0584\",\"validation\":{\"isValidating\":false,\"isValid\":false,\"validationErrors\":null,\"error\":null,\"restrictedItems\":null},\"isSwappingItems\":false,\"updateQueue\":[],\"updateQueueCallbacks\":[],\"processUpdateQueueImmediately\":false,\"isProcessUpdateQueueErrorNotificationMuted\":false,\"fetchContext\":{}},\"drawer\":{\"active\":[],\"state\":{}},\"shoppingMethod\":{\"isEditing\":false,\"didStoreIdChange\":false,\"state\":{}},\"enquiryForms\":{\"ids\":[],\"entities\":{}},\"list\":{\"error\":null,\"patchListItemsQueue\":[]},\"content\":{\"pageCategoryL1\":\"\",\"pageCategoryL2\":\"\",\"displayFilter\":false,\"expandFilter\":[],\"nextLevel\":false,\"pageTitle\":\"\",\"pageType\":\"\",\"breadcrumbs\":[],\"recipeId\":\"\",\"isDisplayShopIngredients\":false,\"globalUrgencyStrip\":{},\"recipeServingSize\":4,\"deliveryMethod\":false},\"seoJsonLd\":{\"componentJsonLd\":{},\"showAsJsonLd\":false},\"bffApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"bffApi\"}},\"aemApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"aemApi\"}},\"enquiryFormApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"enquiryFormApi\"}},\"b2bFormsApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"b2bFormsApi\"}},\"radioComplaintsFormApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"radioComplaintsFormApi\"}},\"psdsFormApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"psdsFormApi\"}},\"adobeTargetApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"adobeTargetApi\"}},\"abandonedTrolleyFormApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"abandonedTrolleyFormApi\"}},\"digitalGraphQLApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"digitalGraphQLApi\"}},\"nextApi\":{\"queries\":{},\"mutations\":{},\"provided\":{},\"subscriptions\":{},\"config\":{\"online\":true,\"focused\":true,\"middlewareRegistered\":false,\"refetchOnFocus\":false,\"refetchOnReconnect\":false,\"refetchOnMountOrArgChange\":false,\"keepUnusedDataFor\":60,\"reducerPath\":\"nextApi\"}}},\"__N_SSP\":true}", + "cookies": { + "nlbi_2800108_2670698": "RtwgEfqECW7ISipTjQyMFgAAAADh8zh0Q4u70LwfHUW03dqj" + } + } +} \ No newline at end of file diff --git a/tests/sample_files/woolworths/GET_https:__www.woolworths.com.au_.json b/tests/sample_files/woolworths/GET_https:__www.woolworths.com.au_.json new file mode 100644 index 0000000..51025b4 --- /dev/null +++ b/tests/sample_files/woolworths/GET_https:__www.woolworths.com.au_.json @@ -0,0 +1,57 @@ +{ + "request": { + "method": "GET", + "url": "https://www.woolworths.com.au/", + "headers": { + "host": "www.woolworths.com.au", + "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0", + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "accept-language": "en-US,en;q=0.5", + "accept-encoding": "gzip, deflate, br", + "dnt": "1", + "sec-gpc": "1", + "connection": "keep-alive", + "upgrade-insecure-requests": "1", + "sec-fetch-dest": "document", + "sec-fetch-mode": "navigate", + "sec-fetch-site": "none", + "sec-fetch-user": "?1", + "pragma": "no-cache", + "cache-control": "no-cache" + }, + "content": "" + }, + "response": { + "status_code": 200, + "headers": { + "content-type": "text/html; charset=utf-8", + "etag": "W/\"c990f-hOikGv+sfwKJcQjq5KLWqFk5iGw:dtagent10299240903104354fmwM:dtagent10299240903104354fmwM\"", + "request-context": "appId=cid-v1:6e80a3cd-b964-4d8a-a650-bc43e6bc1b8a", + "x-powered-by": "Express", + "ssr": "true", + "link": ";rel=\"preconnect\"", + "x-oneagent-js-injection": "true", + "x-ruxit-js-agent": "true", + "x-akamai-transformed": "9 - 0 pmb=mTOE,3mRUM,2", + "vary": "Accept-Encoding", + "content-encoding": "gzip", + "date": "Sun, 29 Sep 2024 04:21:48 GMT", + "transfer-encoding": "chunked", + "connection": "keep-alive, Transfer-Encoding", + "set-cookie": "AKA_A2=A; expires=Sun, 29-Sep-2024 05:21:48 GMT; path=/; domain=woolworths.com.au; secure; HttpOnly, bff_region=syd1; path=/; secure; HttpOnly; SameSite=None, akaalb_woolworths.com.au=~op=www_woolworths_com_au_BFF_SYD_Launch:WOW-BFF-SYD|~rv=67~m=WOW-BFF-SYD:0|~os=43eb3391333cc20efbd7f812851447e6~id=356708499428e6ee80814838492e4e39; path=/; HttpOnly; Secure; SameSite=None, _abck=CE7BD43CAE3CA29C1426890F1C20208A~-1~YAAQvW44F0CFey2SAQAAVWYDPAyHOnBJF8c//yasWTPLFD/KNx4qh9jFAhckWBD44IYQ3iyhGov2YrrBDxQe4ejFqBaw+JayLdtSh0NE3G+dI9f/OpYtKwY9IsBjff0xsQZHjMHDEtUZBG0+Svjpo7B27CeglWpL/cBMIoUHEbwWFC7Uhh/Y3hEUZTXVNeFx5XSCFKGI91Pc985MULAp2wNlRZ+qe+0Zj9DSAq/aEmb6LgZSVgSGsiWpT3asXm1fiEM5ziOFrPx1cg4z7hoPAlumq6L5V3KT5GRAeaa/mT6GNkK7XvyuE74IboFs35T171Wk+zqg38A36em2M1thtMxb0qGUE206PyPUaBuHop71qRvucrFkllq0WgE36P6eAIDWIQe7QB53R8D2kOIrDX6YRXoEHHmboM4rlTTB00c4bTgXm0XTOpKYDsJNZw==~-1~-1~-1; Domain=.woolworths.com.au; Path=/; Expires=Mon, 29 Sep 2025 04:21:48 GMT; Max-Age=31536000; Secure, ak_bmsc=BDACEA9D9EDAF413A9911ABF605C6545~000000000000000000000000000000~YAAQvW44F0GFey2SAQAAVWYDPBm+BoqdTBsg0j1QQJcrwJOA/S6SGvGXJXfaa1xL6b5uCzuGM3qdcLFpohuvjj7UhR67BE5kbv3vPcZSADCM8Y2WSufzNvUTKlII1KHCsGLG0v1U0fH2ZL6SwHj1cPYJuVN/uXOiqeNLx2/H7KpYrJcWi9RuGDd5ERCpwNUG2alhGSJV3rXMhYGEcAHDKNP9+TZF2VySIioKjrsjhC1hiRaABaVT4gvHydTnCX/FZBY/+4UX98lHGs3sQLOSa1+1NYqsGtdpIiLYAaXvu2cl5lmJMZUyFZwFEMAoUtnwxZekCC2Ionm4+5TEFSCcJFXAgDX2ihjN+ZWYqC8SddF6wAUh0YxP/tCg62tj0g5owLI=; Domain=.woolworths.com.au; Path=/; Expires=Sun, 29 Sep 2024 06:21:48 GMT; Max-Age=7200, bm_mi=E510A8B9C93EBD334A758CB3FC355E79~YAAQvW44F0KFey2SAQAAVWYDPBmjGCe6XLQ+LEDbgCQnvoZa5FvLYTCRlksv1EIQLgH4/CnZj+N6ZQIiXP1Kdo269GGcfaL27k9dywON3bFxEACFFjvCJHAxz5Ii15oce9hY+ih/p1SPn5y/NTIhzd6f+lLmJb6jJNcNX6joAn4vhl776Yg28SMX6378tpcQSJLtIarQWEvYeOe7oTZTS4RTDJfNU+2a0XdyaMjVgSnNRiJHRCf+Lqz2lwWR1bcRfFvii3jntb8eNwAap6+RyUEBZX7fgMAtIKS4e3XbQiX6GjHRwNmiht1gGYre8py4+tUYLRI=~1; Domain=.woolworths.com.au; Path=/; Expires=Sun, 29 Sep 2024 04:21:48 GMT; Max-Age=0; Secure, bm_sz=4DBC37D756B16B7CC270C309173ECC6A~YAAQvW44F0OFey2SAQAAVWYDPBkvAs+BmfGR1wU8/9/Mymj9BWqgzrD4qfBqvub139Mx1kSXMr0j6ez26RBMnnpvTjYXRcDya6Dq+lX5zMQllr9e5XwFDV6vxh2jMHa+8m+w2Rx6cdmIeG0OQmKhzPv6iGm2z+T0wDSliIigky5ASH5tR0+3CfhMU5yRSeUs9Voyq3imNDz8ig/bK84Ni+BrDsweAyC1tekVL/mWR0o/xTaxeTPACUvLPEOILT7C8rx7k6gj1wZtld98mabR5kgqM0c1ifg74b4IFqkcwlx0e5ZBIIozOd/7O8+kDl3pdQocJwqi0nAhnxoZO/7mtGZhDi0r0E/Mgf1sKYWtArS9tghhsvRIrPFqWIbqwVms4GnII5OFY256Zw==~4405058~4408898; Domain=.woolworths.com.au; Path=/; Expires=Sun, 29 Sep 2024 08:21:48 GMT; Max-Age=14400", + "server-timing": "cdn-cache; desc=HIT, edge; dur=1, dtSInfo;desc=\"1\", ak_p; desc=\"1727583708119_389574333_247158941_84_540598_15_60_-\";dur=1", + "x-content-type-options": "nosniff", + "x-xss-protection": "1; mode=block", + "strict-transport-security": "max-age=31536000 ; includeSubDomains" + }, + "content": "\n\n \n Woolworths Supermarket - Buy Groceries Online\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n\n \n \n \n \n \n \n \n \n\n \n\n \n \n\n\n\n\n
\n \n\n\n
\n \n
\n\n
\n \n \n \n \n \n \"Woolworths\n \n \n\n
\n
\n
\n \n \n\n
\n
\n
\n
\n
\n
\n
\n \n \n
\n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n
\n
\n\n
\n
\n
\n \n
\n
\n \n
\n
\n \n
\n \n View cart button\n
\n
\n
\n
\n\n
\n
\n
$0.00
\n
\n
\n \n Your Cart has \n 0\n item worth\n $0 in total\n \n
\n \n
\n
\n
\n
\n
0
\n
\n
\n
\n
\n \n \n \n
\n
\n\n \n \n
\n\n
\n
\n
\n
\n \n Next, choose a time\n
\n\n
\n \n \n
\n \n \n \n\n \n\n
\n \n Delivery to:\n \n \n Set your Delivery address\n \n
\n
\n
\n Choose\n \n
\n \n\n
\n\n \n \n
\n \n \n\n
\n Select a time:\n \n \n View available times\n \n Choose Time of Delivery. View available times\n \n
\n
\n
\n Choose\n \n
\n \n
\n
\n
\n\n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n

Woolworths Homepage

Helping you find great value

\n \n \n \n
\n \n
\n
\n
\n \n \"Woolworths\n \n Back to top \n \n
\n
\n\n
\n
\n
\n \n \n\n
\n
\n

\n \n

\n\n \n \n \n Click to expand section\n \n

\n \n
\n \n\n
\n \n
\n
\n
\n\n\n \n\n
\n
\n

\n \n

\n\n \n \n \n Click to expand section\n \n

\n \n
\n \n\n
\n \n
\n
\n
\n\n\n \n\n
\n
\n

\n \n

\n\n \n \n \n Click to expand section\n \n

\n \n
\n \n\n
\n \n
\n
\n
\n\n\n \n\n
\n
\n

\n \n

\n\n \n \n \n Click to expand section\n \n

\n \n
\n \n\n
\n \n
\n
\n
\n\n\n
\n
\n
\n\n
\n
\n \"Acknowledgment\n
\n
We acknowledge the Traditional Owners and Custodians of Country throughout Australia. \n We pay our respects to all First Nations peoples and acknowledge Elders past and present.
\n
Read more about our commitment to reconciliation
\n
\n
\n
\n \n
\n
\n
\n
Our Partners
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n
\n\n
\n \n
\n\n
\n \n
\n
\n\n \n\n", + "cookies": { + "AKA_A2": "A", + "_abck": "CE7BD43CAE3CA29C1426890F1C20208A~-1~YAAQvW44F0CFey2SAQAAVWYDPAyHOnBJF8c//yasWTPLFD/KNx4qh9jFAhckWBD44IYQ3iyhGov2YrrBDxQe4ejFqBaw+JayLdtSh0NE3G+dI9f/OpYtKwY9IsBjff0xsQZHjMHDEtUZBG0+Svjpo7B27CeglWpL/cBMIoUHEbwWFC7Uhh/Y3hEUZTXVNeFx5XSCFKGI91Pc985MULAp2wNlRZ+qe+0Zj9DSAq/aEmb6LgZSVgSGsiWpT3asXm1fiEM5ziOFrPx1cg4z7hoPAlumq6L5V3KT5GRAeaa/mT6GNkK7XvyuE74IboFs35T171Wk+zqg38A36em2M1thtMxb0qGUE206PyPUaBuHop71qRvucrFkllq0WgE36P6eAIDWIQe7QB53R8D2kOIrDX6YRXoEHHmboM4rlTTB00c4bTgXm0XTOpKYDsJNZw==~-1~-1~-1", + "ak_bmsc": "BDACEA9D9EDAF413A9911ABF605C6545~000000000000000000000000000000~YAAQvW44F0GFey2SAQAAVWYDPBm+BoqdTBsg0j1QQJcrwJOA/S6SGvGXJXfaa1xL6b5uCzuGM3qdcLFpohuvjj7UhR67BE5kbv3vPcZSADCM8Y2WSufzNvUTKlII1KHCsGLG0v1U0fH2ZL6SwHj1cPYJuVN/uXOiqeNLx2/H7KpYrJcWi9RuGDd5ERCpwNUG2alhGSJV3rXMhYGEcAHDKNP9+TZF2VySIioKjrsjhC1hiRaABaVT4gvHydTnCX/FZBY/+4UX98lHGs3sQLOSa1+1NYqsGtdpIiLYAaXvu2cl5lmJMZUyFZwFEMAoUtnwxZekCC2Ionm4+5TEFSCcJFXAgDX2ihjN+ZWYqC8SddF6wAUh0YxP/tCg62tj0g5owLI=", + "bm_sz": "4DBC37D756B16B7CC270C309173ECC6A~YAAQvW44F0OFey2SAQAAVWYDPBkvAs+BmfGR1wU8/9/Mymj9BWqgzrD4qfBqvub139Mx1kSXMr0j6ez26RBMnnpvTjYXRcDya6Dq+lX5zMQllr9e5XwFDV6vxh2jMHa+8m+w2Rx6cdmIeG0OQmKhzPv6iGm2z+T0wDSliIigky5ASH5tR0+3CfhMU5yRSeUs9Voyq3imNDz8ig/bK84Ni+BrDsweAyC1tekVL/mWR0o/xTaxeTPACUvLPEOILT7C8rx7k6gj1wZtld98mabR5kgqM0c1ifg74b4IFqkcwlx0e5ZBIIozOd/7O8+kDl3pdQocJwqi0nAhnxoZO/7mtGZhDi0r0E/Mgf1sKYWtArS9tghhsvRIrPFqWIbqwVms4GnII5OFY256Zw==~4405058~4408898", + "bff_region": "syd1", + "akaalb_woolworths.com.au": "~op=www_woolworths_com_au_BFF_SYD_Launch:WOW-BFF-SYD|~rv=67~m=WOW-BFF-SYD:0|~os=43eb3391333cc20efbd7f812851447e6~id=356708499428e6ee80814838492e4e39" + } + } +} \ No newline at end of file diff --git a/tests/sample_files/woolworths/GET_https:__www.woolworths.com.au_apis_ui_product_detail_144607.json b/tests/sample_files/woolworths/GET_https:__www.woolworths.com.au_apis_ui_product_detail_144607.json new file mode 100644 index 0000000..dae72eb --- /dev/null +++ b/tests/sample_files/woolworths/GET_https:__www.woolworths.com.au_apis_ui_product_detail_144607.json @@ -0,0 +1,61 @@ +{ + "request": { + "method": "GET", + "url": "https://www.woolworths.com.au/apis/ui/product/detail/144607", + "headers": { + "host": "www.woolworths.com.au", + "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0", + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "accept-language": "en-US,en;q=0.5", + "accept-encoding": "gzip, deflate, br", + "dnt": "1", + "sec-gpc": "1", + "connection": "keep-alive", + "upgrade-insecure-requests": "1", + "sec-fetch-dest": "document", + "sec-fetch-mode": "navigate", + "sec-fetch-site": "none", + "sec-fetch-user": "?1", + "pragma": "no-cache", + "cache-control": "no-cache", + "cookie": "AKA_A2=A; _abck=CE7BD43CAE3CA29C1426890F1C20208A~-1~YAAQvW44F0CFey2SAQAAVWYDPAyHOnBJF8c//yasWTPLFD/KNx4qh9jFAhckWBD44IYQ3iyhGov2YrrBDxQe4ejFqBaw+JayLdtSh0NE3G+dI9f/OpYtKwY9IsBjff0xsQZHjMHDEtUZBG0+Svjpo7B27CeglWpL/cBMIoUHEbwWFC7Uhh/Y3hEUZTXVNeFx5XSCFKGI91Pc985MULAp2wNlRZ+qe+0Zj9DSAq/aEmb6LgZSVgSGsiWpT3asXm1fiEM5ziOFrPx1cg4z7hoPAlumq6L5V3KT5GRAeaa/mT6GNkK7XvyuE74IboFs35T171Wk+zqg38A36em2M1thtMxb0qGUE206PyPUaBuHop71qRvucrFkllq0WgE36P6eAIDWIQe7QB53R8D2kOIrDX6YRXoEHHmboM4rlTTB00c4bTgXm0XTOpKYDsJNZw==~-1~-1~-1; ak_bmsc=BDACEA9D9EDAF413A9911ABF605C6545~000000000000000000000000000000~YAAQvW44F0GFey2SAQAAVWYDPBm+BoqdTBsg0j1QQJcrwJOA/S6SGvGXJXfaa1xL6b5uCzuGM3qdcLFpohuvjj7UhR67BE5kbv3vPcZSADCM8Y2WSufzNvUTKlII1KHCsGLG0v1U0fH2ZL6SwHj1cPYJuVN/uXOiqeNLx2/H7KpYrJcWi9RuGDd5ERCpwNUG2alhGSJV3rXMhYGEcAHDKNP9+TZF2VySIioKjrsjhC1hiRaABaVT4gvHydTnCX/FZBY/+4UX98lHGs3sQLOSa1+1NYqsGtdpIiLYAaXvu2cl5lmJMZUyFZwFEMAoUtnwxZekCC2Ionm4+5TEFSCcJFXAgDX2ihjN+ZWYqC8SddF6wAUh0YxP/tCg62tj0g5owLI=; bm_sz=4DBC37D756B16B7CC270C309173ECC6A~YAAQvW44F0OFey2SAQAAVWYDPBkvAs+BmfGR1wU8/9/Mymj9BWqgzrD4qfBqvub139Mx1kSXMr0j6ez26RBMnnpvTjYXRcDya6Dq+lX5zMQllr9e5XwFDV6vxh2jMHa+8m+w2Rx6cdmIeG0OQmKhzPv6iGm2z+T0wDSliIigky5ASH5tR0+3CfhMU5yRSeUs9Voyq3imNDz8ig/bK84Ni+BrDsweAyC1tekVL/mWR0o/xTaxeTPACUvLPEOILT7C8rx7k6gj1wZtld98mabR5kgqM0c1ifg74b4IFqkcwlx0e5ZBIIozOd/7O8+kDl3pdQocJwqi0nAhnxoZO/7mtGZhDi0r0E/Mgf1sKYWtArS9tghhsvRIrPFqWIbqwVms4GnII5OFY256Zw==~4405058~4408898; bff_region=syd1; akaalb_woolworths.com.au=~op=www_woolworths_com_au_BFF_SYD_Launch:WOW-BFF-SYD|~rv=67~m=WOW-BFF-SYD:0|~os=43eb3391333cc20efbd7f812851447e6~id=356708499428e6ee80814838492e4e39; AKA_A2=A; _abck=CE7BD43CAE3CA29C1426890F1C20208A~-1~YAAQvW44F0CFey2SAQAAVWYDPAyHOnBJF8c//yasWTPLFD/KNx4qh9jFAhckWBD44IYQ3iyhGov2YrrBDxQe4ejFqBaw+JayLdtSh0NE3G+dI9f/OpYtKwY9IsBjff0xsQZHjMHDEtUZBG0+Svjpo7B27CeglWpL/cBMIoUHEbwWFC7Uhh/Y3hEUZTXVNeFx5XSCFKGI91Pc985MULAp2wNlRZ+qe+0Zj9DSAq/aEmb6LgZSVgSGsiWpT3asXm1fiEM5ziOFrPx1cg4z7hoPAlumq6L5V3KT5GRAeaa/mT6GNkK7XvyuE74IboFs35T171Wk+zqg38A36em2M1thtMxb0qGUE206PyPUaBuHop71qRvucrFkllq0WgE36P6eAIDWIQe7QB53R8D2kOIrDX6YRXoEHHmboM4rlTTB00c4bTgXm0XTOpKYDsJNZw==~-1~-1~-1; ak_bmsc=BDACEA9D9EDAF413A9911ABF605C6545~000000000000000000000000000000~YAAQvW44F0GFey2SAQAAVWYDPBm+BoqdTBsg0j1QQJcrwJOA/S6SGvGXJXfaa1xL6b5uCzuGM3qdcLFpohuvjj7UhR67BE5kbv3vPcZSADCM8Y2WSufzNvUTKlII1KHCsGLG0v1U0fH2ZL6SwHj1cPYJuVN/uXOiqeNLx2/H7KpYrJcWi9RuGDd5ERCpwNUG2alhGSJV3rXMhYGEcAHDKNP9+TZF2VySIioKjrsjhC1hiRaABaVT4gvHydTnCX/FZBY/+4UX98lHGs3sQLOSa1+1NYqsGtdpIiLYAaXvu2cl5lmJMZUyFZwFEMAoUtnwxZekCC2Ionm4+5TEFSCcJFXAgDX2ihjN+ZWYqC8SddF6wAUh0YxP/tCg62tj0g5owLI=; bm_sz=4DBC37D756B16B7CC270C309173ECC6A~YAAQvW44F0OFey2SAQAAVWYDPBkvAs+BmfGR1wU8/9/Mymj9BWqgzrD4qfBqvub139Mx1kSXMr0j6ez26RBMnnpvTjYXRcDya6Dq+lX5zMQllr9e5XwFDV6vxh2jMHa+8m+w2Rx6cdmIeG0OQmKhzPv6iGm2z+T0wDSliIigky5ASH5tR0+3CfhMU5yRSeUs9Voyq3imNDz8ig/bK84Ni+BrDsweAyC1tekVL/mWR0o/xTaxeTPACUvLPEOILT7C8rx7k6gj1wZtld98mabR5kgqM0c1ifg74b4IFqkcwlx0e5ZBIIozOd/7O8+kDl3pdQocJwqi0nAhnxoZO/7mtGZhDi0r0E/Mgf1sKYWtArS9tghhsvRIrPFqWIbqwVms4GnII5OFY256Zw==~4405058~4408898; bff_region=syd1; akaalb_woolworths.com.au=~op=www_woolworths_com_au_BFF_SYD_Launch:WOW-BFF-SYD|~rv=67~m=WOW-BFF-SYD:0|~os=43eb3391333cc20efbd7f812851447e6~id=356708499428e6ee80814838492e4e39" + }, + "content": "" + }, + "response": { + "status_code": 200, + "headers": { + "content-type": "application/json; charset=utf-8", + "cache-control": "no-cache, no-store, must-revalidate", + "pragma": "no-cache", + "expires": "-1", + "request-context": "appId=cid-v1:dc2e13b4-0bc8-4547-a30b-307a5efa07bc", + "access-control-expose-headers": "Request-Context", + "access-control-allow-origin": "*", + "access-control-allow-headers": "Content-type", + "vary": "Accept-Encoding", + "content-encoding": "gzip", + "date": "Sun, 29 Sep 2024 04:21:55 GMT", + "content-length": "3770", + "connection": "keep-alive", + "set-cookie": "INGRESSCOOKIE=1727583715.972.1428.343737|37206e05370eb151ee9f1b6a1c80a538; Path=/; Secure; HttpOnly, w-loggedin=; expires=Sat, 28-Sep-2024 04:21:54 GMT; path=/; secure, w-rctx=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3Mjc1ODM3MTQsImV4cCI6MTcyNzU4NzMxNCwiaWF0IjoxNzI3NTgzNzE0LCJpc3MiOiJXb29sd29ydGhzIiwiYXVkIjoid3d3Lndvb2x3b3J0aHMuY29tLmF1Iiwic2lkIjoiMCIsInVpZCI6IjkwYzU2MmI0LTY5NDYtNDk3My05ZTEwLTIzOTY1YzIyNjJhNCIsIm1haWQiOiIwIiwiYXV0IjoiU2hvcHBlciIsImF1YiI6IjAiLCJhdWJhIjoiMCIsIm1mYSI6IjEifQ.Y1Iy-WR1QuMXhwrpl7SSn9JaF7rqQwJNy4Jbh_CLb6pkG4kqZp7SZh7MDXgXcn09kftoJHbuFqMA_0sVtEXolKxGiodj7DJu-yz0BtE6vS7SYocLy5u4IBIOC8uUHhcXxYa8Vgckw5u72jouNw5k08Yl9sGqZEZThvZoPF7SOVJ7kdY19rxl7LGrPl1lYByKfKrpifdkmiOETSXHfy8r1xOGtDPlqJxD5zjBxnrfmRmldYwqzfG61M8FhLbI_PUCu5X4Trbh5bShCK0hq9jnRXI8ljfTIWMxj_bRMyGtqkiTrKAgVj_uwdGkMRDb7q1Cw_T3c4uVzLN2NjVBF35oHA; expires=Sun, 29-Sep-2024 05:21:54 GMT; path=/; secure; HttpOnly, wow-auth-token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3Mjc1ODM3MTQsImV4cCI6MTcyNzU4NzMxNCwiaWF0IjoxNzI3NTgzNzE0LCJpc3MiOiJXb29sd29ydGhzIiwiYXVkIjoid3d3Lndvb2x3b3J0aHMuY29tLmF1Iiwic2lkIjoiMCIsInVpZCI6IjkwYzU2MmI0LTY5NDYtNDk3My05ZTEwLTIzOTY1YzIyNjJhNCIsIm1haWQiOiIwIiwiYXV0IjoiU2hvcHBlciIsImF1YiI6IjAiLCJhdWJhIjoiMCIsIm1mYSI6IjEifQ.Y1Iy-WR1QuMXhwrpl7SSn9JaF7rqQwJNy4Jbh_CLb6pkG4kqZp7SZh7MDXgXcn09kftoJHbuFqMA_0sVtEXolKxGiodj7DJu-yz0BtE6vS7SYocLy5u4IBIOC8uUHhcXxYa8Vgckw5u72jouNw5k08Yl9sGqZEZThvZoPF7SOVJ7kdY19rxl7LGrPl1lYByKfKrpifdkmiOETSXHfy8r1xOGtDPlqJxD5zjBxnrfmRmldYwqzfG61M8FhLbI_PUCu5X4Trbh5bShCK0hq9jnRXI8ljfTIWMxj_bRMyGtqkiTrKAgVj_uwdGkMRDb7q1Cw_T3c4uVzLN2NjVBF35oHA; domain=woolworths.com.au; expires=Sun, 29-Sep-2024 05:21:54 GMT; path=/; secure; HttpOnly, prodwow-auth-token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3Mjc1ODM3MTQsImV4cCI6MTcyNzU4NzMxNCwiaWF0IjoxNzI3NTgzNzE0LCJpc3MiOiJXb29sd29ydGhzIiwiYXVkIjoid3d3Lndvb2x3b3J0aHMuY29tLmF1Iiwic2lkIjoiMCIsInVpZCI6IjkwYzU2MmI0LTY5NDYtNDk3My05ZTEwLTIzOTY1YzIyNjJhNCIsIm1haWQiOiIwIiwiYXV0IjoiU2hvcHBlciIsImF1YiI6IjAiLCJhdWJhIjoiMCIsIm1mYSI6IjEifQ.Y1Iy-WR1QuMXhwrpl7SSn9JaF7rqQwJNy4Jbh_CLb6pkG4kqZp7SZh7MDXgXcn09kftoJHbuFqMA_0sVtEXolKxGiodj7DJu-yz0BtE6vS7SYocLy5u4IBIOC8uUHhcXxYa8Vgckw5u72jouNw5k08Yl9sGqZEZThvZoPF7SOVJ7kdY19rxl7LGrPl1lYByKfKrpifdkmiOETSXHfy8r1xOGtDPlqJxD5zjBxnrfmRmldYwqzfG61M8FhLbI_PUCu5X4Trbh5bShCK0hq9jnRXI8ljfTIWMxj_bRMyGtqkiTrKAgVj_uwdGkMRDb7q1Cw_T3c4uVzLN2NjVBF35oHA; domain=woolworths.com.au; expires=Sun, 29-Sep-2024 05:21:54 GMT; path=/; secure; HttpOnly, dtCookie=v_4_srv_2_sn_2D816B5A35435EA3B913F2E59FB46987_perc_100000_ol_0_mul_1_app-3Af908d76079915f06_1_rcs-3Acss_0; Path=/; Domain=.woolworths.com.au, akaalb_woolworths.com.au=~op=www_woolworths_com_au_ZoneC:PROD-ZoneC|www_woolworths_com_au_BFF_SYD_Launch:WOW-BFF-SYD|~rv=67~m=PROD-ZoneC:0|WOW-BFF-SYD:0|~os=43eb3391333cc20efbd7f812851447e6~id=d6306819d15ffae3b0d80ba2605effea; path=/; HttpOnly; Secure; SameSite=None, _abck=CE7BD43CAE3CA29C1426890F1C20208A~-1~YAAQnG44FyM4qSuSAQAAGn8DPAxnDv9VeYnloz9Q/k6EJBtjgKbDMYNYyGGw53bOVCQEZjnbz4OZ6oFXrCycF6GPHVLpvIscj/qGBe7HordjIjxgGha1Kx3zGIOXrUkaoJ5BLAS2f7AKTAfyCZJQAB0TANm1l3/5FQ5SH6WUvf8dUBfGByYPXGHHEepOfJpXvCtJxO5z4BH9KqjYQyXazQON6tH5+xI6mzAIw0lBVIyjMVA15GyhHM/Fdh+pPZpzvPoDArl2GRh9D4dvEHIcNX60fubP+beC6LpfTWHCnLMlu+nBrdr1TXBxqHyOw+xyU8jZ9ezc0TLHF7ZDP0o9stF/zIanSfjEjD4s1TrlPiW62MyPUZl+93Kyd7pth45u2L56x44Z4GVYK7Gn+FeJWjyNBz9UYdJnuiqdRWbtbOwM0RUdrt7rPEM8B5AoVO2RXqfdUOzmCaE6IzTskv4UH83g76y8VSuI5IxLmFl5G5ZBO+EHcYI5tJbCWf6ZWVssyD4iBk0opZOCAfsGqnIJ5ks/kUC8mIJYxzZONpLbt1IN+evhripS0LLKn85W8Nsq9lDY34n2SC7pR+zWQEt+fkHbp9cRy+qq~-1~-1~-1; Domain=.woolworths.com.au; Path=/; Expires=Mon, 29 Sep 2025 04:21:55 GMT; Max-Age=31536000; Secure, bm_sv=F7C9613B8BD4F2B706AE67DF8AA5DF85~YAAQnG44FyQ4qSuSAQAAG38DPBnf0WZdCFBgzQLxs9742gfb2JZpasH/Gzzso//WhpK27bGw6rbwwG4IGb5o4F2kFxvqdwWGM5suX6Tb8m3Or/kzWoDmIprsjzxoXotkvESkYJ2WsAOS+bnZqdSwffIUlSkwQsfYlciWbAIpYvq4CquutapUTO4D7h5Q6zrPi08b7RvTczbTtQ2PExhr9Mx0rpUW2DPE05V67i+vPq2pjP6gEybGpeYmuQieqF6cAQrAs1JDEg==~1; Domain=.woolworths.com.au; Path=/; Expires=Sun, 29 Sep 2024 06:21:55 GMT; Max-Age=7200; Secure, bm_sz=4DBC37D756B16B7CC270C309173ECC6A~YAAQnG44FyU4qSuSAQAAG38DPBmLG7oDep46JBDP+gtyyj+TsI5tG3+AlAwbHMkJZhQbNuvBzGQ8tOW4GuffBzYIouBTqCn3zTao1a9TdUVKMMpfrnwNllNZFnLGdtV+VUNd2DjqcU7NdB7hyzO0NqjKob8o4xxeHxSDDA/fEGTXjEdflZOrJ4kyZXaxNcKA6ZHRxoGKZKSCVWJAbqxCRNECLb2IHoihyaRufDguUZaltlPFmwkK6zVuILAJop/uZELYi6Uzbk3DTzvcsddVWV4fvaDmHmkyB7vNgKcu28jPYEF9lM9SAItPGKMYf/r04FI09ZS9SqA3YKIP6AQXZON70HqnoVJ09CK2QVq1k28OSX0c97PgX68FGqwtI5g0MRPWBQhnBJLxeR9KZLCd~4405058~4408898; Domain=.woolworths.com.au; Path=/; Expires=Sun, 29 Sep 2024 08:21:48 GMT; Max-Age=14393", + "server-timing": "cdn-cache; desc=MISS, edge; dur=159, origin; dur=71, dtSInfo;desc=\"1\", ak_p; desc=\"1727583714774_389574300_265251627_23018_60478_17_19_-\";dur=1", + "link": ";rel=\"preconnect\"", + "x-content-type-options": "nosniff", + "x-xss-protection": "1; mode=block", + "strict-transport-security": "max-age=31536000 ; includeSubDomains" + }, + "content": "{\"Product\":{\"TileID\":0,\"Stockcode\":144607,\"Barcode\":\"9300633026028\",\"GtinFormat\":13,\"CupPrice\":14,\"InstoreCupPrice\":14,\"CupMeasure\":\"1KG\",\"CupString\":\"$14.00 / 1KG\",\"InstoreCupString\":\"$14.00 / 1KG\",\"HasCupPrice\":true,\"InstoreHasCupPrice\":true,\"Price\":3.5,\"InstorePrice\":3.5,\"Name\":\"Strawberries\",\"DisplayName\":\"Strawberries 250g Punnet\",\"UrlFriendlyName\":\"strawberries\",\"Description\":\" Strawberries 250g Punnet\",\"SmallImageFile\":\"https://cdn0.woolworths.media/content/wowproductimages/small/144607.jpg\",\"MediumImageFile\":\"https://cdn0.woolworths.media/content/wowproductimages/medium/144607.jpg\",\"LargeImageFile\":\"https://cdn0.woolworths.media/content/wowproductimages/large/144607.jpg\",\"IsNew\":false,\"IsHalfPrice\":false,\"IsOnlineOnly\":false,\"IsOnSpecial\":false,\"InstoreIsOnSpecial\":false,\"IsEdrSpecial\":false,\"SavingsAmount\":0.0,\"InstoreSavingsAmount\":0.0,\"WasPrice\":3.5,\"InstoreWasPrice\":3.5,\"QuantityInTrolley\":0,\"Unit\":\"Each\",\"MinimumQuantity\":1,\"HasBeenBoughtBefore\":false,\"IsInTrolley\":false,\"Source\":\"ProductDetail\",\"SupplyLimit\":36,\"ProductLimit\":36,\"MaxSupplyLimitMessage\":\"36 item limit\",\"IsRanged\":true,\"IsInStock\":true,\"PackageSize\":\"250g Punnet\",\"IsPmDelivery\":false,\"IsForCollection\":true,\"IsForDelivery\":true,\"IsForExpress\":true,\"ProductRestrictionMessage\":null,\"ProductWarningMessage\":null,\"CentreTag\":{\"TagContent\":null,\"TagLink\":null,\"FallbackText\":null,\"TagType\":\"None\",\"MultibuyData\":null,\"MemberPriceData\":null,\"TagContentText\":null,\"DualImageTagContent\":null,\"PromotionType\":\"NOT_SET\",\"IsRegisteredRewardCardPromotion\":false},\"IsCentreTag\":false,\"ImageTag\":{\"TagContent\":\"/content/promotiontags/australian-grown-roundel-200x200.png\",\"TagLink\":null,\"FallbackText\":\"Australian Grown\",\"TagType\":\"None\",\"MultibuyData\":null,\"MemberPriceData\":null,\"TagContentText\":null,\"DualImageTagContent\":null,\"PromotionType\":\"NOT_SET\",\"IsRegisteredRewardCardPromotion\":false},\"HeaderTag\":null,\"HasHeaderTag\":false,\"UnitWeightInGrams\":280,\"SupplyLimitMessage\":\"'Strawberries' has a supply limit of 36. The quantity in your cart has been reduced accordingly. To purchase a larger quantity, please contact us on 1800 000 610. Please note we do not supply trade orders.\",\"SmallFormatDescription\":\" Strawberries \",\"FullDescription\":\" Strawberries \",\"IsAvailable\":true,\"InstoreIsAvailable\":true,\"IsPurchasable\":true,\"InstoreIsPurchasable\":true,\"AgeRestricted\":false,\"DisplayQuantity\":1,\"RichDescription\":\"
Strawberries are firm, sweet and juicy red fruit.\u00a0

How to Pick:
Pick firm strawberries with a red and glossy appearance that are free from bruising. Fresh looking green stems are a sign of freshness!\u00a0

How to Store:
Store strawberries in their punnets or in a covered container in the refrigerator.

Where it's Grown:
Depending on seasonality, Australian strawberries are grown all year round across different regions.
In winter, most are grown in Queensland and Western Australia while in summer, most come from Victoria, South Australia and Tasmania.

Health Benefits:
Strawberries are packed with vitamin C to support a healthy immune system, and are high in folate.

*Based on 1 cup strawberries (150g), as part of a healthy balanced diet
\",\"HideWasSavedPrice\":false,\"SapCategories\":{\"SapDepartmentName\":\"FRUIT AND VEG\",\"SapCategoryName\":\"FRUIT\",\"SapSubCategoryName\":\"STRAWBERRY\",\"SapSegmentName\":\"STRAWBERRIES\"},\"Brand\":null,\"IsRestrictedByDeliveryMethod\":false,\"FooterTag\":{\"TagContent\":null,\"TagLink\":null,\"FallbackText\":null,\"TagType\":\"None\",\"MultibuyData\":null,\"MemberPriceData\":null,\"TagContentText\":null,\"DualImageTagContent\":null,\"PromotionType\":\"NOT_SET\",\"IsRegisteredRewardCardPromotion\":false},\"IsFooterEnabled\":false,\"Diagnostics\":\"0\",\"IsBundle\":false,\"IsInFamily\":false,\"ChildProducts\":[],\"UrlOverride\":null,\"AdditionalAttributes\":{\"boxedcontents\":null,\"addedvitaminsandminerals\":\"False\",\"sapdepartmentname\":\"FRUIT AND VEG\",\"spf\":null,\"haircolour\":null,\"lifestyleanddietarystatement\":\"Low Fat,Low Salt,Low Sugar\",\"sapcategoryname\":\"FRUIT\",\"skintype\":null,\"importantinformation\":null,\"allergystatement\":null,\"productdepthmm\":null,\"skincondition\":null,\"ophthalmologistapproved\":null,\"healthstarrating\":\"5\",\"hairtype\":null,\"fragrance-free\":null,\"sapsegmentname\":\"STRAWBERRIES\",\"suitablefor\":null,\"PiesProductDepartmentsjson\":\"[{\\\"Id\\\":\\\"1_6E4F4E4\\\",\\\"Description\\\":\\\"Dairy, Eggs & Fridge\\\"},{\\\"Id\\\":\\\"1_9E92C35\\\",\\\"Description\\\":\\\"Lunch Box\\\"},{\\\"Id\\\":\\\"1-E5BEE36E\\\",\\\"Description\\\":\\\"Fruit & Veg\\\"}]\",\"piessubcategorynamesjson\":\"[\\\"Kids Snacks & Lunch\\\",\\\"Fruit\\\",\\\"Berries & Cherries\\\"]\",\"sapsegmentno\":\"1\",\"productwidthmm\":null,\"contains\":null,\"sapsubcategoryname\":\"STRAWBERRY\",\"dermatologisttested\":null,\"wool_productpackaging\":null,\"dermatologicallyapproved\":null,\"specialsgroupid\":null,\"productimages\":\"144607.jpg\",\"productheightmm\":null,\"r&r_hidereviews\":null,\"microwavesafe\":\"False\",\"paba-free\":null,\"lifestyleclaim\":null,\"alcoholfree\":null,\"tgawarning\":null,\"activeconstituents\":null,\"microwaveable\":\"False\",\"soap-free\":null,\"countryoforigin\":null,\"isexcludedfromsubstitution\":\"False\",\"productimagecount\":\"1\",\"r&r_loggedinreviews\":null,\"anti-dandruff\":null,\"servingsize-total-nip\":null,\"tgahealthwarninglink\":null,\"allergenmaybepresent\":null,\"PiesProductDepartmentNodeId\":\"1_6E4F4E4\",\"parabenfree\":\"False\",\"vendorarticleid\":null,\"containsgluten\":\"False\",\"containsnuts\":\"False\",\"ingredients\":null,\"colour\":null,\"manufacturer\":null,\"sapcategoryno\":\"69\",\"storageinstructions\":null,\"tgawarnings\":null,\"piesdepartmentnamesjson\":\"[\\\"Dairy, Eggs & Fridge\\\",\\\"Lunch Box\\\",\\\"Fruit & Veg\\\"]\",\"brand\":\"gala berry\",\"oilfree\":null,\"fragrance\":null,\"antibacterial\":\"False\",\"non-comedogenic\":null,\"antiseptic\":\"False\",\"bpafree\":\"False\",\"vendorcostprice\":null,\"description\":\"
Strawberries are firm, sweet and juicy red fruit.\u00a0

How to Pick:
Pick firm strawberries with a red and glossy appearance that are free from bruising. Fresh looking green stems are a sign of freshness!\u00a0

How to Store:
Store strawberries in their punnets or in a covered container in the refrigerator.

Where it's Grown:
Depending on seasonality, Australian strawberries are grown all year round across different regions.
In winter, most are grown in Queensland and Western Australia while in summer, most come from Victoria, South Australia and Tasmania.

Health Benefits:
Strawberries are packed with vitamin C to support a healthy immune system, and are high in folate.

*Based on 1 cup strawberries (150g), as part of a healthy balanced diet
\",\"sweatresistant\":null,\"sapsubcategoryno\":\"718\",\"antioxidant\":\"False\",\"claims\":null,\"phbalanced\":null,\"wool_dietaryclaim\":null,\"ophthalmologisttested\":null,\"sulfatefree\":\"False\",\"piescategorynamesjson\":\"[\\\"Healthier Lunch Box\\\",\\\"Fruit & Veg\\\",\\\"Fruit\\\"]\",\"servingsperpack-total-nip\":null,\"nutritionalinformation\":\"{\\\"Name\\\":\\\"Nutritional Information\\\",\\\"Attributes\\\":[{\\\"Id\\\":702,\\\"Name\\\":\\\"Calcium Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"18mg\\\",\\\"Description\\\":\\\"Calcium Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":71},{\\\"Id\\\":705,\\\"Name\\\":\\\"Carbohydrate Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"3.9g\\\",\\\"Description\\\":\\\"Carbohydrate Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":83},{\\\"Id\\\":191,\\\"Name\\\":\\\"Dietary Fibre Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"2.5g\\\",\\\"Description\\\":\\\"Dietary Fibre Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":175},{\\\"Id\\\":759,\\\"Name\\\":\\\"Energy kJ Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"108kJ\\\",\\\"Description\\\":\\\"Energy kJ Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":239},{\\\"Id\\\":764,\\\"Name\\\":\\\"Fat Total Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"0.2g\\\",\\\"Description\\\":\\\"Fat Total Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":263},{\\\"Id\\\":166,\\\"Name\\\":\\\"Fat Total Quantity Per 100g - ValueWord - NIP\\\",\\\"Value\\\":\\\"0.2\\\",\\\"Description\\\":\\\"Fat Total Quantity Per 100g - ValueWord - NIP\\\",\\\"SortOrder\\\":264},{\\\"Id\\\":443,\\\"Name\\\":\\\"Potassium Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"158mg\\\",\\\"Description\\\":\\\"Potassium Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":575},{\\\"Id\\\":878,\\\"Name\\\":\\\"Protein Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"0.7g\\\",\\\"Description\\\":\\\"Protein Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":587},{\\\"Id\\\":491,\\\"Name\\\":\\\"Sodium Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"3mg\\\",\\\"Description\\\":\\\"Sodium Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":623},{\\\"Id\\\":908,\\\"Name\\\":\\\"Sugars Quantity Per 100g - SuffixUnits - NIP\\\",\\\"Value\\\":\\\"g\\\",\\\"Description\\\":\\\"Sugars Quantity Per 100g - SuffixUnits - NIP\\\",\\\"SortOrder\\\":646},{\\\"Id\\\":909,\\\"Name\\\":\\\"Sugars Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"3.8g\\\",\\\"Description\\\":\\\"Sugars Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":647},{\\\"Id\\\":910,\\\"Name\\\":\\\"Sugars Quantity Per 100g - ValueWord - NIP\\\",\\\"Value\\\":\\\"3.8\\\",\\\"Description\\\":\\\"Sugars Quantity Per 100g - ValueWord - NIP\\\",\\\"SortOrder\\\":648}]}\",\"ovencook\":\"False\",\"vegetarian\":\"False\",\"hypo-allergenic\":null,\"timer\":null,\"dermatologistrecommended\":null,\"sapdepartmentno\":\"30\",\"allergencontains\":null,\"waterresistant\":null,\"friendlydisclaimer\":null,\"recyclableinformation\":null,\"usageinstructions\":null,\"freezable\":\"False\"},\"DetailsImagePaths\":[\"https://cdn0.woolworths.media/content/wowproductimages/large/144607.jpg\"],\"Variety\":null,\"Rating\":{\"ReviewCount\":0,\"RatingCount\":0,\"RatingSum\":0,\"OneStarCount\":0,\"TwoStarCount\":0,\"ThreeStarCount\":0,\"FourStarCount\":0,\"FiveStarCount\":0,\"Average\":0,\"OneStarPercentage\":0,\"TwoStarPercentage\":0,\"ThreeStarPercentage\":0,\"FourStarPercentage\":0,\"FiveStarPercentage\":0},\"HasProductSubs\":false,\"IsSponsoredAd\":false,\"AdID\":null,\"AdIndex\":null,\"AdStatus\":null,\"IsMarketProduct\":false,\"IsGiftable\":false,\"Vendor\":null,\"Untraceable\":false,\"ThirdPartyProductInfo\":null,\"MarketFeatures\":null,\"MarketSpecifications\":null,\"SupplyLimitSource\":\"ProductLimit\",\"Tags\":[{\"Content\":{\"Type\":\"Roundel\",\"Position\":\"Top\",\"Attributes\":{\"ImagePath\":\"/content/promotiontags/australian-grown-roundel-200x200.png\",\"FallbackText\":\"Australian Grown\"}},\"TemplateId\":null,\"Metadata\":null}],\"IsPersonalisedByPurchaseHistory\":false,\"IsFromFacetedSearch\":false,\"NextAvailabilityDate\":\"2024-09-30T00:00:00.0000000Z\",\"NumberOfSubstitutes\":0,\"IsPrimaryVariant\":false,\"VariantGroupId\":0,\"HasVariants\":false,\"VariantTitle\":null,\"IsTobacco\":false,\"IsB2BExtendedRangeSapCategory\":false},\"Nutrition\":null,\"VideoUrl\":null,\"PrimaryCategory\":{\"Department\":\"fruit & vegetables\",\"Aisle\":\"fresh fruit\",\"VisualShoppingAisleId\":18,\"DisplayOrder\":0,\"OverrideName\":null,\"Instance\":\"Alpha\"},\"AdditionalAttributes\":{\"boxedcontents\":null,\"addedvitaminsandminerals\":\"False\",\"sapdepartmentname\":\"FRUIT AND VEG\",\"spf\":null,\"haircolour\":null,\"lifestyleanddietarystatement\":\"Low Fat,Low Salt,Low Sugar\",\"sapcategoryname\":\"FRUIT\",\"skintype\":null,\"importantinformation\":null,\"allergystatement\":null,\"productdepthmm\":null,\"skincondition\":null,\"ophthalmologistapproved\":null,\"healthstarrating\":\"5\",\"hairtype\":null,\"fragrance-free\":null,\"sapsegmentname\":\"STRAWBERRIES\",\"suitablefor\":null,\"PiesProductDepartmentsjson\":\"[{\\\"Id\\\":\\\"1_6E4F4E4\\\",\\\"Description\\\":\\\"Dairy, Eggs & Fridge\\\"},{\\\"Id\\\":\\\"1_9E92C35\\\",\\\"Description\\\":\\\"Lunch Box\\\"},{\\\"Id\\\":\\\"1-E5BEE36E\\\",\\\"Description\\\":\\\"Fruit & Veg\\\"}]\",\"piessubcategorynamesjson\":\"[\\\"Kids Snacks & Lunch\\\",\\\"Fruit\\\",\\\"Berries & Cherries\\\"]\",\"sapsegmentno\":\"1\",\"productwidthmm\":null,\"contains\":null,\"sapsubcategoryname\":\"STRAWBERRY\",\"dermatologisttested\":null,\"wool_productpackaging\":null,\"dermatologicallyapproved\":null,\"specialsgroupid\":null,\"productimages\":\"144607.jpg\",\"productheightmm\":null,\"r&r_hidereviews\":null,\"microwavesafe\":\"False\",\"paba-free\":null,\"lifestyleclaim\":null,\"alcoholfree\":null,\"tgawarning\":null,\"activeconstituents\":null,\"microwaveable\":\"False\",\"soap-free\":null,\"countryoforigin\":null,\"isexcludedfromsubstitution\":\"False\",\"productimagecount\":\"1\",\"r&r_loggedinreviews\":null,\"anti-dandruff\":null,\"servingsize-total-nip\":null,\"tgahealthwarninglink\":null,\"allergenmaybepresent\":null,\"PiesProductDepartmentNodeId\":\"1_6E4F4E4\",\"parabenfree\":\"False\",\"vendorarticleid\":null,\"containsgluten\":\"False\",\"containsnuts\":\"False\",\"ingredients\":null,\"colour\":null,\"manufacturer\":null,\"sapcategoryno\":\"69\",\"storageinstructions\":null,\"tgawarnings\":null,\"piesdepartmentnamesjson\":\"[\\\"Dairy, Eggs & Fridge\\\",\\\"Lunch Box\\\",\\\"Fruit & Veg\\\"]\",\"brand\":\"gala berry\",\"oilfree\":null,\"fragrance\":null,\"antibacterial\":\"False\",\"non-comedogenic\":null,\"antiseptic\":\"False\",\"bpafree\":\"False\",\"vendorcostprice\":null,\"description\":\"
Strawberries are firm, sweet and juicy red fruit.\u00a0

How to Pick:
Pick firm strawberries with a red and glossy appearance that are free from bruising. Fresh looking green stems are a sign of freshness!\u00a0

How to Store:
Store strawberries in their punnets or in a covered container in the refrigerator.

Where it's Grown:
Depending on seasonality, Australian strawberries are grown all year round across different regions.
In winter, most are grown in Queensland and Western Australia while in summer, most come from Victoria, South Australia and Tasmania.

Health Benefits:
Strawberries are packed with vitamin C to support a healthy immune system, and are high in folate.

*Based on 1 cup strawberries (150g), as part of a healthy balanced diet
\",\"sweatresistant\":null,\"sapsubcategoryno\":\"718\",\"antioxidant\":\"False\",\"claims\":null,\"phbalanced\":null,\"wool_dietaryclaim\":null,\"ophthalmologisttested\":null,\"sulfatefree\":\"False\",\"piescategorynamesjson\":\"[\\\"Healthier Lunch Box\\\",\\\"Fruit & Veg\\\",\\\"Fruit\\\"]\",\"servingsperpack-total-nip\":null,\"nutritionalinformation\":\"{\\\"Name\\\":\\\"Nutritional Information\\\",\\\"Attributes\\\":[{\\\"Id\\\":702,\\\"Name\\\":\\\"Calcium Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"18mg\\\",\\\"Description\\\":\\\"Calcium Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":71},{\\\"Id\\\":705,\\\"Name\\\":\\\"Carbohydrate Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"3.9g\\\",\\\"Description\\\":\\\"Carbohydrate Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":83},{\\\"Id\\\":191,\\\"Name\\\":\\\"Dietary Fibre Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"2.5g\\\",\\\"Description\\\":\\\"Dietary Fibre Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":175},{\\\"Id\\\":759,\\\"Name\\\":\\\"Energy kJ Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"108kJ\\\",\\\"Description\\\":\\\"Energy kJ Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":239},{\\\"Id\\\":764,\\\"Name\\\":\\\"Fat Total Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"0.2g\\\",\\\"Description\\\":\\\"Fat Total Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":263},{\\\"Id\\\":166,\\\"Name\\\":\\\"Fat Total Quantity Per 100g - ValueWord - NIP\\\",\\\"Value\\\":\\\"0.2\\\",\\\"Description\\\":\\\"Fat Total Quantity Per 100g - ValueWord - NIP\\\",\\\"SortOrder\\\":264},{\\\"Id\\\":443,\\\"Name\\\":\\\"Potassium Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"158mg\\\",\\\"Description\\\":\\\"Potassium Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":575},{\\\"Id\\\":878,\\\"Name\\\":\\\"Protein Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"0.7g\\\",\\\"Description\\\":\\\"Protein Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":587},{\\\"Id\\\":491,\\\"Name\\\":\\\"Sodium Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"3mg\\\",\\\"Description\\\":\\\"Sodium Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":623},{\\\"Id\\\":908,\\\"Name\\\":\\\"Sugars Quantity Per 100g - SuffixUnits - NIP\\\",\\\"Value\\\":\\\"g\\\",\\\"Description\\\":\\\"Sugars Quantity Per 100g - SuffixUnits - NIP\\\",\\\"SortOrder\\\":646},{\\\"Id\\\":909,\\\"Name\\\":\\\"Sugars Quantity Per 100g - Total - NIP\\\",\\\"Value\\\":\\\"3.8g\\\",\\\"Description\\\":\\\"Sugars Quantity Per 100g - Total - NIP\\\",\\\"SortOrder\\\":647},{\\\"Id\\\":910,\\\"Name\\\":\\\"Sugars Quantity Per 100g - ValueWord - NIP\\\",\\\"Value\\\":\\\"3.8\\\",\\\"Description\\\":\\\"Sugars Quantity Per 100g - ValueWord - NIP\\\",\\\"SortOrder\\\":648}]}\",\"ovencook\":\"False\",\"vegetarian\":\"False\",\"hypo-allergenic\":null,\"timer\":null,\"dermatologistrecommended\":null,\"sapdepartmentno\":\"30\",\"allergencontains\":null,\"waterresistant\":null,\"friendlydisclaimer\":null,\"recyclableinformation\":null,\"usageinstructions\":null,\"freezable\":\"False\"},\"TgaAttributes\":{\"Directions\":null,\"ProductWarnings\":null,\"SuitableFor\":null,\"StorageInstructions\":null},\"DetailsImagePaths\":[\"https://cdn0.woolworths.media/content/wowproductimages/large/144607.jpg\"],\"NutritionalInformation\":[{\"Name\":\"Energy\",\"Values\":{\"Quantity Per Serving\":\"-\",\"Quantity Per 100g / 100mL\":\"108kJ\"},\"ServingSize\":null,\"ServingsPerPack\":null},{\"Name\":\"Protein\",\"Values\":{\"Quantity Per Serving\":\"-\",\"Quantity Per 100g / 100mL\":\"0.7g\"},\"ServingSize\":null,\"ServingsPerPack\":null},{\"Name\":\"Fat, Total\",\"Values\":{\"Quantity Per Serving\":\"-\",\"Quantity Per 100g / 100mL\":\"0.2g\"},\"ServingSize\":null,\"ServingsPerPack\":null},{\"Name\":\"\u2013 Saturated\",\"Values\":{\"Quantity Per Serving\":\"-\",\"Quantity Per 100g / 100mL\":\"-\"},\"ServingSize\":null,\"ServingsPerPack\":null},{\"Name\":\"Carbohydrate\",\"Values\":{\"Quantity Per Serving\":\"-\",\"Quantity Per 100g / 100mL\":\"3.9g\"},\"ServingSize\":null,\"ServingsPerPack\":null},{\"Name\":\"\u2013 Sugars\",\"Values\":{\"Quantity Per Serving\":\"-\",\"Quantity Per 100g / 100mL\":\"3.8g\"},\"ServingSize\":null,\"ServingsPerPack\":null},{\"Name\":\"Dietary Fibre\",\"Values\":{\"Quantity Per Serving\":\"-\",\"Quantity Per 100g / 100mL\":\"2.5g\"},\"ServingSize\":null,\"ServingsPerPack\":null},{\"Name\":\"Sodium\",\"Values\":{\"Quantity Per Serving\":\"-\",\"Quantity Per 100g / 100mL\":\"3mg\"},\"ServingSize\":null,\"ServingsPerPack\":null}],\"RichRelevancePlacements\":[{\"placement_name\":null,\"message\":null,\"Products\":[],\"Items\":[],\"StockcodesForDiscover\":[]}],\"Variants\":[],\"VariantOptionGroups\":[],\"IsTobacco\":false,\"CountryOfOriginLabel\":{\"PngImageFile\":\"https://cdn0.woolworths.media/content/countryoforiginlabelling/b30db8e7-2a70-43c8-8115-b2d6e0805210.png\",\"SvgImageFile\":\"https://cdn0.woolworths.media/content/countryoforiginlabelling/b30db8e7-2a70-43c8-8115-b2d6e0805210.svg\",\"AltText\":\"Grown in Australia\",\"CountryOfOrigin\":\"Australia\",\"IngredientPercentage\":\"100\",\"Disclaimer\":null},\"DiagnosticsData\":null}", + "cookies": { + "INGRESSCOOKIE": "1727583715.972.1428.343737|37206e05370eb151ee9f1b6a1c80a538", + "w-rctx": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3Mjc1ODM3MTQsImV4cCI6MTcyNzU4NzMxNCwiaWF0IjoxNzI3NTgzNzE0LCJpc3MiOiJXb29sd29ydGhzIiwiYXVkIjoid3d3Lndvb2x3b3J0aHMuY29tLmF1Iiwic2lkIjoiMCIsInVpZCI6IjkwYzU2MmI0LTY5NDYtNDk3My05ZTEwLTIzOTY1YzIyNjJhNCIsIm1haWQiOiIwIiwiYXV0IjoiU2hvcHBlciIsImF1YiI6IjAiLCJhdWJhIjoiMCIsIm1mYSI6IjEifQ.Y1Iy-WR1QuMXhwrpl7SSn9JaF7rqQwJNy4Jbh_CLb6pkG4kqZp7SZh7MDXgXcn09kftoJHbuFqMA_0sVtEXolKxGiodj7DJu-yz0BtE6vS7SYocLy5u4IBIOC8uUHhcXxYa8Vgckw5u72jouNw5k08Yl9sGqZEZThvZoPF7SOVJ7kdY19rxl7LGrPl1lYByKfKrpifdkmiOETSXHfy8r1xOGtDPlqJxD5zjBxnrfmRmldYwqzfG61M8FhLbI_PUCu5X4Trbh5bShCK0hq9jnRXI8ljfTIWMxj_bRMyGtqkiTrKAgVj_uwdGkMRDb7q1Cw_T3c4uVzLN2NjVBF35oHA", + "akaalb_woolworths.com.au": "~op=www_woolworths_com_au_ZoneC:PROD-ZoneC|www_woolworths_com_au_BFF_SYD_Launch:WOW-BFF-SYD|~rv=67~m=PROD-ZoneC:0|WOW-BFF-SYD:0|~os=43eb3391333cc20efbd7f812851447e6~id=d6306819d15ffae3b0d80ba2605effea", + "wow-auth-token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3Mjc1ODM3MTQsImV4cCI6MTcyNzU4NzMxNCwiaWF0IjoxNzI3NTgzNzE0LCJpc3MiOiJXb29sd29ydGhzIiwiYXVkIjoid3d3Lndvb2x3b3J0aHMuY29tLmF1Iiwic2lkIjoiMCIsInVpZCI6IjkwYzU2MmI0LTY5NDYtNDk3My05ZTEwLTIzOTY1YzIyNjJhNCIsIm1haWQiOiIwIiwiYXV0IjoiU2hvcHBlciIsImF1YiI6IjAiLCJhdWJhIjoiMCIsIm1mYSI6IjEifQ.Y1Iy-WR1QuMXhwrpl7SSn9JaF7rqQwJNy4Jbh_CLb6pkG4kqZp7SZh7MDXgXcn09kftoJHbuFqMA_0sVtEXolKxGiodj7DJu-yz0BtE6vS7SYocLy5u4IBIOC8uUHhcXxYa8Vgckw5u72jouNw5k08Yl9sGqZEZThvZoPF7SOVJ7kdY19rxl7LGrPl1lYByKfKrpifdkmiOETSXHfy8r1xOGtDPlqJxD5zjBxnrfmRmldYwqzfG61M8FhLbI_PUCu5X4Trbh5bShCK0hq9jnRXI8ljfTIWMxj_bRMyGtqkiTrKAgVj_uwdGkMRDb7q1Cw_T3c4uVzLN2NjVBF35oHA", + "prodwow-auth-token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3Mjc1ODM3MTQsImV4cCI6MTcyNzU4NzMxNCwiaWF0IjoxNzI3NTgzNzE0LCJpc3MiOiJXb29sd29ydGhzIiwiYXVkIjoid3d3Lndvb2x3b3J0aHMuY29tLmF1Iiwic2lkIjoiMCIsInVpZCI6IjkwYzU2MmI0LTY5NDYtNDk3My05ZTEwLTIzOTY1YzIyNjJhNCIsIm1haWQiOiIwIiwiYXV0IjoiU2hvcHBlciIsImF1YiI6IjAiLCJhdWJhIjoiMCIsIm1mYSI6IjEifQ.Y1Iy-WR1QuMXhwrpl7SSn9JaF7rqQwJNy4Jbh_CLb6pkG4kqZp7SZh7MDXgXcn09kftoJHbuFqMA_0sVtEXolKxGiodj7DJu-yz0BtE6vS7SYocLy5u4IBIOC8uUHhcXxYa8Vgckw5u72jouNw5k08Yl9sGqZEZThvZoPF7SOVJ7kdY19rxl7LGrPl1lYByKfKrpifdkmiOETSXHfy8r1xOGtDPlqJxD5zjBxnrfmRmldYwqzfG61M8FhLbI_PUCu5X4Trbh5bShCK0hq9jnRXI8ljfTIWMxj_bRMyGtqkiTrKAgVj_uwdGkMRDb7q1Cw_T3c4uVzLN2NjVBF35oHA", + "dtCookie": "v_4_srv_2_sn_2D816B5A35435EA3B913F2E59FB46987_perc_100000_ol_0_mul_1_app-3Af908d76079915f06_1_rcs-3Acss_0", + "_abck": "CE7BD43CAE3CA29C1426890F1C20208A~-1~YAAQnG44FyM4qSuSAQAAGn8DPAxnDv9VeYnloz9Q/k6EJBtjgKbDMYNYyGGw53bOVCQEZjnbz4OZ6oFXrCycF6GPHVLpvIscj/qGBe7HordjIjxgGha1Kx3zGIOXrUkaoJ5BLAS2f7AKTAfyCZJQAB0TANm1l3/5FQ5SH6WUvf8dUBfGByYPXGHHEepOfJpXvCtJxO5z4BH9KqjYQyXazQON6tH5+xI6mzAIw0lBVIyjMVA15GyhHM/Fdh+pPZpzvPoDArl2GRh9D4dvEHIcNX60fubP+beC6LpfTWHCnLMlu+nBrdr1TXBxqHyOw+xyU8jZ9ezc0TLHF7ZDP0o9stF/zIanSfjEjD4s1TrlPiW62MyPUZl+93Kyd7pth45u2L56x44Z4GVYK7Gn+FeJWjyNBz9UYdJnuiqdRWbtbOwM0RUdrt7rPEM8B5AoVO2RXqfdUOzmCaE6IzTskv4UH83g76y8VSuI5IxLmFl5G5ZBO+EHcYI5tJbCWf6ZWVssyD4iBk0opZOCAfsGqnIJ5ks/kUC8mIJYxzZONpLbt1IN+evhripS0LLKn85W8Nsq9lDY34n2SC7pR+zWQEt+fkHbp9cRy+qq~-1~-1~-1", + "bm_sv": "F7C9613B8BD4F2B706AE67DF8AA5DF85~YAAQnG44FyQ4qSuSAQAAG38DPBnf0WZdCFBgzQLxs9742gfb2JZpasH/Gzzso//WhpK27bGw6rbwwG4IGb5o4F2kFxvqdwWGM5suX6Tb8m3Or/kzWoDmIprsjzxoXotkvESkYJ2WsAOS+bnZqdSwffIUlSkwQsfYlciWbAIpYvq4CquutapUTO4D7h5Q6zrPi08b7RvTczbTtQ2PExhr9Mx0rpUW2DPE05V67i+vPq2pjP6gEybGpeYmuQieqF6cAQrAs1JDEg==~1", + "bm_sz": "4DBC37D756B16B7CC270C309173ECC6A~YAAQnG44FyU4qSuSAQAAG38DPBmLG7oDep46JBDP+gtyyj+TsI5tG3+AlAwbHMkJZhQbNuvBzGQ8tOW4GuffBzYIouBTqCn3zTao1a9TdUVKMMpfrnwNllNZFnLGdtV+VUNd2DjqcU7NdB7hyzO0NqjKob8o4xxeHxSDDA/fEGTXjEdflZOrJ4kyZXaxNcKA6ZHRxoGKZKSCVWJAbqxCRNECLb2IHoihyaRufDguUZaltlPFmwkK6zVuILAJop/uZELYi6Uzbk3DTzvcsddVWV4fvaDmHmkyB7vNgKcu28jPYEF9lM9SAItPGKMYf/r04FI09ZS9SqA3YKIP6AQXZON70HqnoVJ09CK2QVq1k28OSX0c97PgX68FGqwtI5g0MRPWBQhnBJLxeR9KZLCd~4405058~4408898" + } + } +} \ No newline at end of file diff --git a/tests/test_data.py b/tests/test_data.py index 7526e1f..352d511 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -22,6 +22,7 @@ import products class Products: broccoli = products.Product( id=0, + shop_code='woolworths', name="Fresh Broccoli", product_id="134681", quantity=1, @@ -34,6 +35,7 @@ class Products: garlic_bread = products.Product( id=0, + shop_code='woolworths', name="La Famiglia Garlic Bread", product_id="294517", quantity=1, @@ -46,6 +48,7 @@ class Products: beans_round = products.Product( id=0, + shop_code='woolworths', name="Beans Round", product_id="134072", quantity=1, @@ -58,6 +61,7 @@ class Products: western_star_unsalted_butter_chefs_choice = products.Product( id=0, + shop_code='woolworths', name="Western Star Unsalted Butter Chef's Choice", product_id="712251", quantity=500, @@ -70,6 +74,7 @@ class Products: saxa_iodised_table_salt_shaker = products.Product( id=0, + shop_code='woolworths', name="Saxa Iodised Table Salt Shaker", quantity=750, unit="g", @@ -82,6 +87,7 @@ class Products: mckenzies_pepper_black_ground = products.Product( id=0, + shop_code='woolworths', name="Mckenzie's Pepper Black Ground", quantity=100, unit="g", @@ -94,6 +100,7 @@ class Products: apple = products.Product( id=0, + shop_code='woolworths', name="Apple", product_id="3542", quantity=1, @@ -106,6 +113,7 @@ class Products: banana = products.Product( id=0, + shop_code='woolworths', name="Banana", product_id="214", quantity=1, diff --git a/tests/test_main.py b/tests/test_main.py index 01fff08..c1118c6 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -10,7 +10,6 @@ def reload_test_data(): from db import connect, create -import products.db as products_db import recipes.db as recipes_db def unique(lst: list, key: callable): @@ -21,31 +20,6 @@ def unique(lst: list, key: callable): seen.add(k) yield item -class TestProducts(unittest.IsolatedAsyncioTestCase): - async def asyncSetUp(self): - self.conn = await connect(':memory:') - await create(self.conn) - reload_test_data() - return await super().asyncSetUp() - - async def asyncTearDown(self) -> None: - await self.conn.close() - return await super().asyncTearDown() - - async def testCreateAndFind(self) -> None: - product = test_data.Products.broccoli - await products_db.insert_product(self.conn, product, {}) - self.assertIsNotNone(product) - self.assertGreater(product.id, 0) - - product_by_id = await products_db.find_product_by_id(self.conn, product.id) - self.assertIsNotNone(product_by_id) - self.assertEqual(product_by_id.id, product.id) - self.assertEqual(product_by_id.name, product.name) - self.assertEqual(product_by_id.link, product.link) - self.assertEqual(product_by_id.img_large, product.img_large) - self.assertEqual(product_by_id.img_small, product.img_small) - import main class TestRecipe(unittest.IsolatedAsyncioTestCase): @@ -110,6 +84,7 @@ class TestRecipe(unittest.IsolatedAsyncioTestCase): self.assertIsInstance(all_recipes, list, msg=all_recipes.body if hasattr(all_recipes, 'body') else all_recipes) self.assertEqual(len(all_recipes), 0) +import products.db as products_db import meals class TestMeals(unittest.IsolatedAsyncioTestCase): diff --git a/tests/test_products.py b/tests/test_products.py new file mode 100644 index 0000000..266445b --- /dev/null +++ b/tests/test_products.py @@ -0,0 +1,104 @@ +import unittest + +import tests.test_data as test_data + +import products.db as products_db +from db import connect, create + +import importlib +def reload_test_data(): + global test_data + test_data = importlib.reload(test_data) + +class TestProductsDb(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self): + self.conn = await connect(':memory:') + await create(self.conn) + reload_test_data() + return await super().asyncSetUp() + + async def asyncTearDown(self) -> None: + await self.conn.close() + return await super().asyncTearDown() + + async def testCreateAndFind(self) -> None: + product = test_data.Products.broccoli + await products_db.insert_product(self.conn, product, {}) + self.assertIsNotNone(product) + self.assertGreater(product.id, 0) + + product_by_id = await products_db.find_product_by_id(self.conn, product.id) + self.assertIsNotNone(product_by_id) + self.assertEqual(product_by_id.id, product.id) + self.assertEqual(product_by_id.name, product.name) + self.assertEqual(product_by_id.link, product.link) + self.assertEqual(product_by_id.img_large, product.img_large) + self.assertEqual(product_by_id.img_small, product.img_small) + + +from . import httpx_mocks +from products import woolworths + +class TestWoolworths(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self) -> None: + local_path = './tests/sample_files/woolworths' + woolworths._get_client = lambda: httpx_mocks.MockAsyncClient(local_path) + # woolworths._get_client = lambda: httpx_mocks.RecordingAsyncClient(local_path) + return await super().asyncSetUp() + + async def test_get_product_id(self) -> None: + params = [ + ('https://www.woolworths.com.au/shop/productdetails/144607/strawberries', '144607'), + ('https://www.woolworths.com.au/shop/productdetails/133211/cavendish-bananas', '133211'), + ('https://www.coles.com.au/product/coles-strawberries-250g-5191256', None), + ] + + for url, id in params: + self.assertEqual(woolworths.get_product_id(url), id) + + async def test_get_strawberries(self) -> None: + details, raw_data = await woolworths.scrape('144607') + expected = { + 'name': 'Strawberries', + 'quantity': 250, + 'unit': 'g Punnet', + 'img_small': 'https://cdn0.woolworths.media/content/wowproductimages/small/144607.jpg', + 'img_large': 'https://cdn0.woolworths.media/content/wowproductimages/large/144607.jpg' + } + + for key, value in expected.items(): + self.assertEqual(details[key], value, msg=key) + + +from products import coles + +class TestColes(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self) -> None: + local_path = './tests/sample_files/coles' + coles._get_client = lambda: httpx_mocks.MockAsyncClient(local_path) + # coles._get_client = lambda: httpx_mocks.RecordingAsyncClient(local_path) + return await super().asyncSetUp() + + async def test_get_product_id(self) -> None: + params = [ + ('https://www.coles.com.au/product/coles-strawberries-250g-5191256', 'coles-strawberries-250g-5191256'), + ('https://www.coles.com.au/product/coles-blueberries-170g-3571948', 'coles-blueberries-170g-3571948'), + ('https://www.woolworths.com.au/shop/productdetails/144607/strawberries', None), + ] + + for url, id in params: + self.assertEqual(coles.get_product_id(url), id) + + async def test_get_strawberries(self) -> None: + details, raw_data = await coles.scrape('coles-strawberries-250g-5191256') + expected = { + 'name': 'Strawberries', + 'quantity': 250, + 'unit': 'g', + 'img_small': 'https://shop.coles.com.au/wcsstore/Coles-CAS/images/5/1/9/5191256-th.jpg', + 'img_large': 'https://shop.coles.com.au/wcsstore/Coles-CAS/images/5/1/9/5191256.jpg' + } + + for key, value in expected.items(): + self.assertEqual(details[key], value, msg=key) +