diff --git a/README.md b/README.md index b0bff791..2205d860 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,14 @@ Thousands of code examples for using the EasyPost API across 7+ programming lang ## Folder Structure +- `community` code snippets contributed from the community. These may include custom workflows, how to integrate EasyPost with other software, etc. These are **unofficial** and **not supported or maintained by EasyPost**. - `official` official code snippets that populate on the EasyPost website - `docs` code snippets that populate on our API docs page. Each language will have its own subdirectory - `fixtures` test data used as fixtures in our client library test suites - `guides` code snippets that populate on our guides page. Each language will have its own subdirectory - `responses` responses for our example snippets found in the `docs` directory that will give you a good idea of what to expect back from the EasyPost API -- `community` code snippets contributed from the community. These may include custom workflows, how to integrate EasyPost with other software, etc. These are **unofficial** and **not supported or maintained by EasyPost**. +- `style_guides` contain the style guides and configs for tooling we use in each public language we support +- `tools` contain utilities to help facilitate the code in this repo such as the response snippet generation suite > NOTE: filenames may not match language convention - this is intentional. Our documentation website uses these example snippets and expects folder/filenames to follow a certain templated naming convention. diff --git a/tools/docs/responses/.gitignore b/tools/docs/responses/.gitignore new file mode 100644 index 00000000..fc5262cc --- /dev/null +++ b/tools/docs/responses/.gitignore @@ -0,0 +1,2 @@ +cassettes +responses diff --git a/tools/docs/responses/Makefile b/tools/docs/responses/Makefile new file mode 100644 index 00000000..06c8ba41 --- /dev/null +++ b/tools/docs/responses/Makefile @@ -0,0 +1,62 @@ +PYTHON_BINARY := /opt/python3.10/bin/python3.10 +VIRTUAL_ENV := venv +VIRTUAL_BIN := $(VIRTUAL_ENV)/bin +PROJECT_NAME := easypost_responses +TEST_DIR := tests +TARGERT := tests + +## help - Display help about make targets for this Makefile +help: + @cat Makefile | grep '^## ' --color=never | cut -c4- | sed -e "`printf 's/ - /\t- /;'`" | column -s "`printf '\t'`" -t + +## build - Builds the project in preparation for release +build: + $(VIRTUAL_BIN)/python setup.py sdist bdist_wheel + +## clean - Remove the virtual environment and clear out .pyc files +clean: + rm -rf $(VIRTUAL_ENV) dist/ build/ *.egg-info/ .pytest_cache .mypy_cache + find . -name '*.pyc' -delete + +## black - Runs the Black Python formatter against the project +black: + $(VIRTUAL_BIN)/black $(PROJECT_NAME)/ $(TEST_DIR)/ + +## black-check - Checks if the project is formatted correctly against the Black rules +black-check: + $(VIRTUAL_BIN)/black $(PROJECT_NAME)/ $(TEST_DIR)/ --check + +## format - Runs all formatting tools against the project +format: black isort + +## format-check - Checks if the project is formatted correctly against all formatting rules +format-check: black-check isort-check lint mypy + +## install - Install the project locally +install: + $(PYTHON_BINARY) -m venv $(VIRTUAL_ENV) + $(VIRTUAL_BIN)/pip install -e ."[dev]" + git submodule init + git submodule update + +## isort - Sorts imports throughout the project +isort: + $(VIRTUAL_BIN)/isort $(PROJECT_NAME)/ $(TEST_DIR)/ + +## isort-check - Checks that imports throughout the project are sorted correctly +isort-check: + $(VIRTUAL_BIN)/isort $(PROJECT_NAME)/ $(TEST_DIR)/ --check-only + +## lint - Lint the project +lint: + $(VIRTUAL_BIN)/flake8 $(PROJECT_NAME)/ $(TEST_DIR)/ + +## test - Test the project +test: + $(VIRTUAL_BIN)/pytest $(TARGET) + +## update-examples-submodule Updates the examples submodule +update-examples-submodule: + git submodule update --remote ../../docs/examples + +.PHONY: help build clean black black-check format format-check install isort isort-check lint test diff --git a/tools/docs/responses/README.md b/tools/docs/responses/README.md new file mode 100644 index 00000000..9a951367 --- /dev/null +++ b/tools/docs/responses/README.md @@ -0,0 +1,19 @@ +# Response Generation Tooling + +This tool generates the response snippets that accompany the example snippets on the EasyPost Docs page. + +The tool is setup as a "test suite" that will record the requests and responses via `pyvcr` and load the yaml to extract the response content to save as a standalone file. Whenever new responses are needed, simply re-run the tool and each response will be regenerated. + +> NOTE: The test names are VERY important and must match up with the expected plural object and action name so that when generated, we can drop them into the examples without manual intervention. + +## Usage + +> NOTE: Currently, you'll need to run the command twice - it will fail the first time through. The first time will record the cassette, the second time it will save the standalone files. This is necessary because `vcrpy` doesn't save the file until the test function closes, though we call the standalone function inside the test function to capture the test name. + +```bash +# Run the following to save recordings to standalone files +make test + +# Run the following to overwrite previous interactions +OVERWRITE=true make test +``` diff --git a/tools/docs/responses/builder/__init__.py b/tools/docs/responses/builder/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/docs/responses/builder/snippets.py b/tools/docs/responses/builder/snippets.py new file mode 100644 index 00000000..dba9bc71 --- /dev/null +++ b/tools/docs/responses/builder/snippets.py @@ -0,0 +1,164 @@ +import json +import os +from typing import ( + Any, + Dict, + Optional, + Tuple, +) + +import yaml + + +ALL_RESOURCES = { + "addresses", + "api-keys", + "batches", + "billing", + "brand", + "carrier-accounts", + "carrier-types", + "child-users", + "customs-infos", + "customs-items", + "endshipper", + "events", + "insurance", + "options", + "orders", + "parcels", + "pickups", + "rates", + "referral-customers", + "refunds", + "reports", + "returns", + "scan-form", + "shipments", + "shipping-insurance", + "smartrate", + "tax-identifiers", + "trackers", + "users", + "webhooks", +} + + +def build_response_snippet( + interaction_index: Optional[int] = 0, objects_to_persist: Optional[int] = None +): + """Builds the response snippet from a recorded VCR interaction.""" + create_dir("responses") + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + cassette_filename = f"{test_name}.yaml" + + cassette_content = extract_response_from_cassette( + cassette_filename, interaction_index + ) + + response_snippet_folder, bare_snippet_name = save_response_snippet( + cassette_filename, cassette_content, objects_to_persist + ) + + # Assert the standalone snippet actually got saved, fail if not + assert os.path.exists( + os.path.join("responses", response_snippet_folder, bare_snippet_name) + ), f"{bare_snippet_name} standalone snippet file missing!" + + +def create_dir(dir_name: str): + """Creates a directory if it does not exist yet.""" + if not os.path.exists(dir_name): + os.mkdir(dir_name) + + +def extract_response_from_cassette( + cassette_filename: str, interaction_index: Optional[int] = 0 +) -> Any: + """Opens a single cassette file and extracts the response content.""" + with open(os.path.join("tests", "cassettes", cassette_filename), "r") as cassette: + try: + cassette_data = yaml.safe_load(cassette) + for key, _ in cassette_data.items(): + if key == "interactions": + response_content = cassette_data[key][interaction_index][ + "response" + ]["body"]["string"] + response = response_content if response_content else "{}" + except yaml.YAMLError: + raise + + return response + + +def _setup_saving_response_snippet(response_snippet_filename: str): + """Reusable helper to setup the logic to save a standalone response snippet.""" + + bare_snippet_name = response_snippet_filename.replace("test_", "").replace( + ".yaml", ".json" + ) + split_resource_name = bare_snippet_name.split("_") + first_resource_name = split_resource_name[0] + second_resource_name = split_resource_name[1] + first_and_second_resource_name = f"{first_resource_name}-{second_resource_name}" + resource_name = ( + first_resource_name + if first_and_second_resource_name not in ALL_RESOURCES + else first_and_second_resource_name + ) + + # Setup the names like the website wants it + response_snippet_folder = resource_name.replace("_", "-") + bare_snippet_name = bare_snippet_name.replace("_", "-") + + create_dir(os.path.join("responses", response_snippet_folder)) + + return response_snippet_folder, bare_snippet_name + + +def save_response_snippet( + response_snippet_filename: str, + response_snippet_content: Any, + objects_to_persist: Optional[int] = None, +) -> Tuple[str, str]: + """Saves the response content of a cassette to a standalone snippet file.""" + response_snippet_folder, bare_snippet_name = _setup_saving_response_snippet( + response_snippet_filename + ) + + with open( + os.path.join("responses", response_snippet_folder, bare_snippet_name), "w" + ) as response_snippet_file: + if objects_to_persist: + json.dump( + json.loads(response_snippet_content)[:objects_to_persist], + response_snippet_file, + indent=2, + ) + else: + json.dump( + json.loads(response_snippet_content), response_snippet_file, indent=2 + ) + + response_snippet_file.write("\n") + + return response_snippet_folder, bare_snippet_name + + +def save_raw_json(response_snippet_filename: str, response_dict: Dict[str, Any]): + """Saves a raw response dictionary to a standalone snippet file (used for hard-coded responses + that cannot easily be plugged into a test suite (eg: Billing functions). + """ + response_snippet_folder, bare_snippet_name = _setup_saving_response_snippet( + response_snippet_filename + ) + + bare_snippet_name = f"{bare_snippet_name}.json" + + with open( + os.path.join("responses", response_snippet_folder, bare_snippet_name), "w" + ) as response_snippet_file: + json.dump(response_dict, response_snippet_file, indent=2) + + response_snippet_file.write("\n") diff --git a/tools/docs/responses/setup.py b/tools/docs/responses/setup.py new file mode 100644 index 00000000..a5755cc2 --- /dev/null +++ b/tools/docs/responses/setup.py @@ -0,0 +1,45 @@ +from setuptools import ( + find_packages, + setup, +) + + +REQUIREMENTS = [ + "easypost==7.*", + "python-dotenv", +] + +DEV_REQUIREMENTS = [ + "black==22.*", + "flake8==5.*", + "isort==5.*", + "pytest-vcr==1.*", + "pytest==7.*", + "vcrpy==4.*", +] + +with open("README.md", encoding="utf-8") as f: + long_description = f.read() + +setup( + name="easypost_responses", + version="0.1.0", + description="", + author="EasyPost", + author_email="support@easypost.com", + url="https://easypost.com/", + packages=find_packages( + exclude=[ + "examples", + "tests", + ] + ), + install_requires=REQUIREMENTS, + extras_require={ + "dev": DEV_REQUIREMENTS, + }, + test_suite="test", + long_description=long_description, + long_description_content_type="text/markdown", + python_requires=">=3.6, <4", +) diff --git a/tools/docs/responses/tests/__init__.py b/tools/docs/responses/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/docs/responses/tests/conftest.py b/tools/docs/responses/tests/conftest.py new file mode 100644 index 00000000..7cd09181 --- /dev/null +++ b/tools/docs/responses/tests/conftest.py @@ -0,0 +1,256 @@ +import json +import os +from typing import ( + Any, + Dict, + List, + Tuple, +) + +import easypost +import pytest +from dotenv import load_dotenv + +load_dotenv() + + +EASYPOST_TEST_API_KEY = os.getenv("EASYPOST_TEST_API_KEY") +EASYPOST_PROD_API_KEY = os.getenv("EASYPOST_PROD_API_KEY") +PARTNER_USER_PROD_API_KEY = os.getenv("PARTNER_USER_PROD_API_KEY", "123") + +OVERWRITE = "all" if os.getenv("OVERWRITE", False) else "once" + +SCRUBBED_STRING = "" +SCRUBBED_ARRAY: List = [] +SCRUBBED_DICT: Dict = {} + + +@pytest.fixture(autouse=True) +def setup_api_key(): + """This fixture is auto-loaded by all tests; it sets up the api key.""" + default_key = easypost.api_key + easypost.api_key = EASYPOST_TEST_API_KEY + yield + easypost.api_key = default_key + + +@pytest.fixture +def prod_api_key(): + """If a test needs to use the prod api key, make it depend on this fixture.""" + default_key = easypost.api_key + easypost.api_key = EASYPOST_PROD_API_KEY + yield + easypost.api_key = default_key + + +@pytest.fixture +def partner_prod_api_key(): + """If a test needs to use the partner prod api key, make it depend on this fixture.""" + default_key = easypost.api_key + easypost.api_key = PARTNER_USER_PROD_API_KEY + yield + easypost.api_key = default_key + + +@pytest.fixture(scope="session") +def vcr_config(): + """Setup the VCR config for the test suite.""" + return { + "match_on": [ + "body", + "method", + "query", + "uri", + ], + "record_mode": OVERWRITE, + "decode_compressed_response": True, + "filter_headers": [ + ("authorization", SCRUBBED_STRING), + ("user-agent", SCRUBBED_STRING), + ], + "filter_query_parameters": [ + "card[number]", + "card[cvc]", + ], + "before_record_response": scrub_response_bodies( + scrubbers=[ + ["client_ip", SCRUBBED_STRING], + ["key", SCRUBBED_STRING], + ] + ), + } + + +def scrub_response_bodies(scrubbers: List[Tuple[str, Any]]) -> Any: + """Scrub sensitive data from response bodies prior to recording the cassette.""" + + def before_record_response(response: Any) -> Any: + """This function fires prior to persisting data to a cassette.""" + if response["body"]["string"]: + response_body = json.loads(response["body"]["string"].decode()) + + for scrubber in scrubbers: + response_body = scrub_data(response_body, scrubber) + + response["body"]["string"] = json.dumps(response_body).encode() + return response + + def scrub_data(data: Any, scrubber: Tuple[str, Any]) -> Any: + """Scrub data from a cassette recursively.""" + key = scrubber[0] + replacement = scrubber[1] + + # Root-level list scrubbing + if isinstance(data, list): + for index, item in enumerate(data): + if key in item: + data[index][key] = replacement + elif isinstance(data, dict): + # Root-level key scrubbing + if key in data: + data[key] = replacement + else: + # Nested scrubbing + for item in data: + element = data[item] + if isinstance(element, list): + for nested_index, nested_item in enumerate(element): + data[item][nested_index] = scrub_data(nested_item, scrubber) + elif isinstance(element, dict): + data[item] = scrub_data(element, scrubber) + return data + + return before_record_response + + +def read_fixture_data(): + """Reads fixture data from the fixtures JSON file.""" + with open(os.path.join("..", "..", "..", "..", "official", "fixtures", "example-snippet-fixtures.json")) as data: + fixtures = json.load(data) + + return fixtures + + +@pytest.fixture +def page_size(): + """We keep the page_size of retrieving `all` records small so cassettes stay small.""" + return 1 + + +@pytest.fixture +def usps_carrier_account_id(): + """This is the USPS carrier account ID that comes with your + EasyPost account by default and should be used for all tests. + """ + # Fallback to the EasyPost Docs Tooling User USPS carrier account ID due to strict matching + return os.getenv("USPS_CARRIER_ACCOUNT_ID", "ca_9685a1198a75477885a3cdca37559bac") + + +@pytest.fixture +def report_type(): + return "shipment" + + +@pytest.fixture +def report_date(): + return "2022-10-01" + + +@pytest.fixture +def address_create(): + return read_fixture_data()["address"]["create"] + + +@pytest.fixture +def address_create_and_verify(): + return read_fixture_data()["address"]["create_and_verify"] + + +@pytest.fixture +def address_create_strictly_verified(): + return read_fixture_data()["address"]["create_strictly_verified"] + + +@pytest.fixture +def carrier_account_create(): + return read_fixture_data()["carrier_account"]["create"] + + +@pytest.fixture +def customs_info_create(): + return read_fixture_data()["customs_info"]["create"] + + +@pytest.fixture +def customs_item_create(): + return read_fixture_data()["customs_item"]["create"] + + +@pytest.fixture +def end_shipper_create(): + return read_fixture_data()["end_shipper"]["create"] + + +@pytest.fixture +def form_create(): + return read_fixture_data()["form"]["create"] + + +@pytest.fixture +def insurance_create(): + return read_fixture_data()["insurance"]["create"] + + +@pytest.fixture +def order_create(): + return read_fixture_data()["order"]["create"] + + +@pytest.fixture +def parcel_create(): + return read_fixture_data()["parcel"]["create"] + + +@pytest.fixture +def pickup_create(): + """This fixture will require you to add a `shipment` key with a Shipment object from a test. + If you need to re-record cassettes, increment the date below and ensure it is one day in the future, + USPS only does "next-day" pickups including Saturday but not Sunday or Holidays. + """ + pickup_date = "2022-10-29" + + pickup_data = read_fixture_data()["pickup"]["create"] + pickup_data["min_datetime"] = pickup_date + pickup_data["max_datetime"] = pickup_date + + return pickup_data + + +@pytest.fixture +def shipment_create(): + return read_fixture_data()["shipment"]["create"] + + +@pytest.fixture +def shipment_one_call_buy(usps_carrier_account_id): + shipment_data = read_fixture_data()["shipment"]["create"] + shipment_data["service"] = "Priority" + shipment_data["carrier"] = "USPS" + shipment_data["carrier_accounts"] = [usps_carrier_account_id] + + return shipment_data + + +@pytest.fixture +def tax_identifier_create(): + return read_fixture_data()["tax_identifier"]["create"] + + +@pytest.fixture +def tracker_create(): + return read_fixture_data()["tracker"]["create"] + + +@pytest.fixture +def webhook_create(): + return read_fixture_data()["webhook"]["create"] diff --git a/tools/docs/responses/tests/test_address.py b/tools/docs/responses/tests/test_address.py new file mode 100644 index 00000000..2c87ff3e --- /dev/null +++ b/tools/docs/responses/tests/test_address.py @@ -0,0 +1,68 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_addresses_create(address_create): + easypost.Address.create(**address_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_addresses_create_and_verify(address_create_and_verify): + easypost.Address.create_and_verify(**address_create_and_verify) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_addresses_verify_param(address_create): + address_create["verify"] = True + easypost.Address.create(**address_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_addresses_verify_strict_param(address_create): + address_create["verify_strict"] = True + easypost.Address.create(**address_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_addresses_verify(address_create): + """Verify and already created address.""" + address = easypost.Address.create(**address_create) + address.verify() + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_addresses_verify_failure(address_create): + """Verify and already created address.""" + address_create["street1"] = "UNDELIVERABLE ST" + address_create["street2"] = None + address_create["verify"] = True + easypost.Address.create(**address_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_addresses_retrieve(address_create): + address = easypost.Address.create(**address_create) + easypost.Address.retrieve(address.id) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_addresses_list(page_size): + easypost.Address.all(page_size=page_size) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_api_keys.py b/tools/docs/responses/tests/test_api_keys.py new file mode 100644 index 00000000..b02b86c5 --- /dev/null +++ b/tools/docs/responses/tests/test_api_keys.py @@ -0,0 +1,69 @@ +import os + +import easypost +import pytest +from builder.snippets import ( + build_response_snippet, + save_raw_json, +) + + +@pytest.mark.vcr() +def test_api_keys_retrieve(prod_api_key): + user = easypost.User.retrieve_me() + user.api_keys() + + build_response_snippet(interaction_index=1) + + +def test_api_keys_create(): + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + + response_dict = { + "object": "ApiKey", + "key": "", + "mode": "test", + "created_at": "2022-01-29T00:02:36Z", + "active": True, + "id": "ak_...", + } + + save_raw_json(test_name, response_dict) + + +def test_api_keys_delete(): + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + + response_dict = {} + + save_raw_json(test_name, response_dict) + + +def test_api_keys_enable(): + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + + response_dict = { + "object": "ApiKey", + "key": "", + "mode": "test", + "created_at": "2022-01-29T00:02:36Z", + "active": True, + "id": "ak_...", + } + + save_raw_json(test_name, response_dict) + + +def test_api_keys_disable(): + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + + response_dict = { + "object": "ApiKey", + "key": "", + "mode": "test", + "created_at": "2022-01-29T00:02:36Z", + "active": False, + "id": "ak_...", + } + + save_raw_json(test_name, response_dict) diff --git a/tools/docs/responses/tests/test_batch.py b/tools/docs/responses/tests/test_batch.py new file mode 100644 index 00000000..a12d2c6c --- /dev/null +++ b/tools/docs/responses/tests/test_batch.py @@ -0,0 +1,100 @@ +import inspect +import os +import time + +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_batches_create(shipment_one_call_buy): + easypost.Batch.create(shipments=[shipment_one_call_buy]) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_batches_retrieve(shipment_one_call_buy): + batch = easypost.Batch.create(shipments=[shipment_one_call_buy]) + easypost.Batch.retrieve(batch.id) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_batches_list(page_size): + easypost.Batch.all(page_size=page_size) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_batches_create_and_buy(shipment_one_call_buy): + """This may not be documented?""" + easypost.Batch.create_and_buy( + shipments=[ + shipment_one_call_buy, + shipment_one_call_buy, + ], + ) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_batches_buy(shipment_one_call_buy): + function_name = inspect.stack()[0][3] + batch = easypost.Batch.create(shipments=[shipment_one_call_buy]) + if not os.path.exists(os.path.join("tests", "cassettes", f"{function_name}.yaml")): + time.sleep(5) # Wait enough time for the batch to process buying the shipment + batch.buy() + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_batches_scan_forms(shipment_one_call_buy): + function_name = inspect.stack()[0][3] + batch = easypost.Batch.create(shipments=[shipment_one_call_buy]) + if not os.path.exists(os.path.join("tests", "cassettes", f"{function_name}.yaml")): + time.sleep(5) # Wait enough time for the batch to process buying the shipment + batch.buy() + if not os.path.exists(os.path.join("tests", "cassettes", f"{function_name}.yaml")): + time.sleep(5) # Wait enough time for the batch to process buying the shipment + batch.create_scan_form() + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_batches_add_shipments(shipment_one_call_buy): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + batch = easypost.Batch.create() + batch.add_shipments(shipments=[shipment]) + + build_response_snippet(interaction_index=2) + + +@pytest.mark.vcr() +def test_batches_remove_shipments(shipment_one_call_buy): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + batch = easypost.Batch.create() + batch.add_shipments(shipments=[shipment]) + batch.remove_shipments(shipments=[shipment]) + + build_response_snippet(interaction_index=3) + + +@pytest.mark.vcr() +def test_batches_label(shipment_one_call_buy): + function_name = inspect.stack()[0][3] + batch = easypost.Batch.create(shipments=[shipment_one_call_buy]) + if not os.path.exists(os.path.join("tests", "cassettes", f"{function_name}.yaml")): + time.sleep(5) # Wait enough time for the batch to process buying the shipment + batch.buy() + if not os.path.exists(os.path.join("tests", "cassettes", f"{function_name}.yaml")): + time.sleep(5) # Wait enough time for the batch to process buying the shipment + batch.label(file_format="ZPL") + + build_response_snippet(interaction_index=2) diff --git a/tools/docs/responses/tests/test_billing.py b/tools/docs/responses/tests/test_billing.py new file mode 100644 index 00000000..708f85c9 --- /dev/null +++ b/tools/docs/responses/tests/test_billing.py @@ -0,0 +1,69 @@ +import os + +from builder.snippets import save_raw_json + + +def test_billing_fund(): + response_dict = {} + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) + + +def test_billing_delete(): + response_dict = {} + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) + + +def test_billing_list(): + response_dict = { + "id": "cust_...", + "object": "PaymentMethods", + "primary_payment_method": { + "id": "card_...", + "disabled_at": None, + "object": "CreditCard", + "name": None, + "last4": "4242", + "exp_month": 1, + "exp_year": 2025, + "brand": "Visa", + }, + "secondary_payment_method": { + "id": "card_...", + "disabled_at": None, + "object": "CreditCard", + "name": None, + "last4": "4444", + "exp_month": 1, + "exp_year": 2025, + "brand": "Mastercard", + }, + } + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) + + +def test_billing_create_referral_token(): + response_dict = {"public_key": "pk_..."} + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) + + +def test_billing_create_ep_credit_card(): + response_dict = { + "id": "card_...", + "object": "CreditCard", + "name": None, + "last4": "1234", + "exp_month": 1, + "exp_year": 2025, + "brand": "Visa", + } + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) diff --git a/tools/docs/responses/tests/test_brand.py b/tools/docs/responses/tests/test_brand.py new file mode 100644 index 00000000..32d12c21 --- /dev/null +++ b/tools/docs/responses/tests/test_brand.py @@ -0,0 +1,11 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_brand_update(prod_api_key): + user = easypost.User.retrieve_me() + user.update_brand(color="#123456") + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_carrier_account.py b/tools/docs/responses/tests/test_carrier_account.py new file mode 100644 index 00000000..75bd3c26 --- /dev/null +++ b/tools/docs/responses/tests/test_carrier_account.py @@ -0,0 +1,48 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_carrier_accounts_create(prod_api_key, carrier_account_create): + carrier_account = easypost.CarrierAccount.create(**carrier_account_create) + + carrier_account.delete() # Delete the carrier account once it's done being tested. + + build_response_snippet() + + +@pytest.mark.vcr() +def test_carrier_accounts_retrieve(prod_api_key, carrier_account_create): + carrier_account = easypost.CarrierAccount.create(**carrier_account_create) + easypost.CarrierAccount.retrieve(carrier_account.id) + + carrier_account.delete() # Delete the carrier account once it's done being tested. + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_carrier_accounts_list(prod_api_key, page_size): + easypost.CarrierAccount.all(page_size=page_size) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_carrier_accounts_update(prod_api_key, carrier_account_create): + carrier_account = easypost.CarrierAccount.create(**carrier_account_create) + carrier_account.description = "My custom description" + carrier_account.save() + + carrier_account.delete() # Delete the carrier account once it's done being tested. + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_carrier_accounts_delete(prod_api_key, carrier_account_create): + carrier_account = easypost.CarrierAccount.create(**carrier_account_create) + carrier_account.delete() + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_carrier_types.py b/tools/docs/responses/tests/test_carrier_types.py new file mode 100644 index 00000000..4ed50c9f --- /dev/null +++ b/tools/docs/responses/tests/test_carrier_types.py @@ -0,0 +1,10 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_carrier_types_list(prod_api_key): + easypost.CarrierAccount.types() + + build_response_snippet(objects_to_persist=3) diff --git a/tools/docs/responses/tests/test_customs_info.py b/tools/docs/responses/tests/test_customs_info.py new file mode 100644 index 00000000..72367747 --- /dev/null +++ b/tools/docs/responses/tests/test_customs_info.py @@ -0,0 +1,18 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_customs_infos_create(customs_info_create): + easypost.CustomsInfo.create(**customs_info_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_customs_infos_retrieve(customs_info_create): + customs_info = easypost.CustomsInfo.create(**customs_info_create) + easypost.CustomsInfo.retrieve(customs_info.id) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_customs_item.py b/tools/docs/responses/tests/test_customs_item.py new file mode 100644 index 00000000..01395383 --- /dev/null +++ b/tools/docs/responses/tests/test_customs_item.py @@ -0,0 +1,18 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_customs_items_create(customs_item_create): + easypost.CustomsItem.create(**customs_item_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_customs_items_retrieve(customs_item_create): + customs_item = easypost.CustomsItem.create(**customs_item_create) + easypost.CustomsItem.retrieve(customs_item.id) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_end_shipper.py b/tools/docs/responses/tests/test_end_shipper.py new file mode 100644 index 00000000..301cec4a --- /dev/null +++ b/tools/docs/responses/tests/test_end_shipper.py @@ -0,0 +1,54 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_endshipper_create(end_shipper_create): + easypost.EndShipper.create(**end_shipper_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_endshipper_retrieve(end_shipper_create): + endshipper = easypost.EndShipper.create(**end_shipper_create) + + easypost.EndShipper.retrieve(endshipper.id) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_endshipper_list(page_size): + easypost.EndShipper.all(page_size=page_size) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_endshipper_update(end_shipper_create): + endshipper = easypost.EndShipper.create(**end_shipper_create) + + endshipper.name = "NEW NAME" + endshipper.company = "BAZ" + endshipper.street1 = "164 TOWNSEND STREET UNIT 1" + endshipper.street2 = "UNIT 1" + endshipper.city = "SAN FRANCISCO" + endshipper.state = "CA" + endshipper.zip = "94107" + endshipper.country = "US" + endshipper.phone = "555-555-5555" + endshipper.email = "FOO@EXAMPLE.COM" + endshipper = endshipper.save() + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_endshipper_buy(end_shipper_create, shipment_create): + end_shipper = easypost.EndShipper.create(**end_shipper_create) + shipment = easypost.Shipment.create(**shipment_create) + shipment.buy(rate=shipment.lowest_rate(), end_shipper_id=end_shipper["id"]) + + build_response_snippet(interaction_index=2) diff --git a/tools/docs/responses/tests/test_event.py b/tools/docs/responses/tests/test_event.py new file mode 100644 index 00000000..e0cdb5ad --- /dev/null +++ b/tools/docs/responses/tests/test_event.py @@ -0,0 +1,112 @@ +import os +import easypost +import pytest +from builder.snippets import ( + build_response_snippet, + save_raw_json, +) + + +@pytest.mark.vcr() +def test_events_list(page_size): + easypost.Event.all(page_size=page_size) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_events_retrieve(page_size): + events = easypost.Event.all(page_size=page_size) + easypost.Event.retrieve(events["events"][0].id) + + build_response_snippet(interaction_index=1) + + +def test_events_retrieve_payload(): + response_dict = { + "id": "payload_734d47163d0711ecb29421da38a2f124", + "object": "Payload", + "created_at": "2021-11-04T00:37:55Z", + "updated_at": "2021-11-04T01:14:18Z", + "request_url": "https://api.example.com/webhook", + "request_headers": { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": "Go-http-client/1.1" + }, + "request_body": "{\"key\":\"value\"}", + "response_code": 200, + "response_headers": { + "Content-Type": "application/json; charset=utf-8", + "Date": "Tue, 02 Nov 2021 23:37:55 GMT", + "Server": "nginx/1.19.6", + "X-Content-Type-Options": "nosniff", + "X-Frame-Options": "SAMEORIGIN", + "X-Request-Id": "a1b2c3d4e5f6g7h8i9j0", + "X-Runtime": "0.001000", + "X-Xss-Protection": "1; mode=block" + }, + "total_time": 34 + } + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) + + +def test_events_retrieve_all_payloads(): + response_dict = { + "payloads": [ + { + "id": "payload_734d47163d0711ecb29421da38a2f124", + "object": "Payload", + "created_at": "2021-11-04T00:37:55Z", + "updated_at": "2021-11-04T01:14:18Z", + "request_url": "https://api.example.com/webhook", + "request_headers": { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": "Go-http-client/1.1" + }, + "request_body": "{\"key\":\"value\"}", + "response_code": 200, + "response_headers": { + "Content-Type": "application/json; charset=utf-8", + "Date": "Tue, 02 Nov 2021 23:37:55 GMT", + "Server": "nginx/1.19.6", + "X-Content-Type-Options": "nosniff", + "X-Frame-Options": "SAMEORIGIN", + "X-Request-Id": "a1b2c3d4e5f6g7h8i9j0", + "X-Runtime": "0.001000", + "X-Xss-Protection": "1; mode=block" + }, + "total_time": 34 + }, + { + "id": "payload_734d47163d0711ecb29421da38a2f414", + "object": "Payload", + "created_at": "2021-11-04T00:37:55Z", + "updated_at": "2021-11-04T01:14:18Z", + "request_url": "https://api.example.com/webhook", + "request_headers": { + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": "Go-http-client/1.1" + }, + "request_body": "{\"key\":\"value\"}", + "response_code": 404, + "response_headers": { + "Content-Type": "application/json; charset=utf-8", + "Date": "Tue, 02 Nov 2021 23:37:55 GMT", + "Server": "nginx/1.19.6", + "X-Content-Type-Options": "nosniff", + "X-Frame-Options": "SAMEORIGIN", + "X-Request-Id": "a1b2c3d4e5f6g7h8i9j0", + "X-Runtime": "0.001000", + "X-Xss-Protection": "1; mode=block" + }, + "total_time": 122 + } + ] + } + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) diff --git a/tools/docs/responses/tests/test_form.py b/tools/docs/responses/tests/test_form.py new file mode 100644 index 00000000..88563c77 --- /dev/null +++ b/tools/docs/responses/tests/test_form.py @@ -0,0 +1,15 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_forms_create(shipment_one_call_buy, form_create): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + form_type = "return_packing_slip" + shipment.generate_form( + form_type, + form_create, + ) + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_insurance.py b/tools/docs/responses/tests/test_insurance.py new file mode 100644 index 00000000..df5875ad --- /dev/null +++ b/tools/docs/responses/tests/test_insurance.py @@ -0,0 +1,25 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_insurance_create(insurance_create): + easypost.Insurance.create(**insurance_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_insurance_retrieve(page_size): + insurances = easypost.Insurance.all(page_size=page_size) + easypost.Insurance.retrieve(insurances["insurances"][0].id) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_insurance_list(page_size): + easypost.Insurance.all(page_size=page_size) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_options.py b/tools/docs/responses/tests/test_options.py new file mode 100644 index 00000000..212eeae7 --- /dev/null +++ b/tools/docs/responses/tests/test_options.py @@ -0,0 +1,11 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_options_create_with_options(shipment_create): + shipment_create["options"] = {"print_custom_1": "Custom label message"} + easypost.Shipment.create(**shipment_create) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_order.py b/tools/docs/responses/tests/test_order.py new file mode 100644 index 00000000..ec102b0b --- /dev/null +++ b/tools/docs/responses/tests/test_order.py @@ -0,0 +1,48 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_orders_create(order_create): + """NOTE: The response will show USPS because our test user doesn't have a FedEx account setup which is what + the example snippets use because FedEx supports Orders and USPS doesn't. + """ + easypost.Order.create(**order_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_orders_retrieve(order_create): + order = easypost.Order.create(**order_create) + easypost.Order.retrieve(order.id) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_orders_buy(order_create): + """NOTE: The response will show USPS because our test user doesn't have a FedEx account setup which is what + the example snippets use because FedEx supports Orders and USPS doesn't. + """ + order = easypost.Order.create(**order_create) + order.buy( + carrier="USPS", + service="First", + ) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_orders_one_call_buy(order_create, usps_carrier_account_id): + """NOTE: The response will show USPS because our test user doesn't have a FedEx account setup which is what + the example snippets use because FedEx supports Orders and USPS doesn't. + """ + order_create["carrier"] = "USPS" + order_create["service"] = "First" + order_create["carrier_accounts"] = [usps_carrier_account_id] + easypost.Order.create(**order_create) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_parcel.py b/tools/docs/responses/tests/test_parcel.py new file mode 100644 index 00000000..b3cd8d12 --- /dev/null +++ b/tools/docs/responses/tests/test_parcel.py @@ -0,0 +1,18 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_parcels_create(parcel_create): + easypost.Parcel.create(**parcel_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_parcels_retrieve(parcel_create): + parcel = easypost.Parcel.create(**parcel_create) + easypost.Parcel.retrieve(parcel.id) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_pickup.py b/tools/docs/responses/tests/test_pickup.py new file mode 100644 index 00000000..88268d28 --- /dev/null +++ b/tools/docs/responses/tests/test_pickup.py @@ -0,0 +1,43 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_pickups_create(shipment_one_call_buy, pickup_create): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + pickup_create["shipment"] = shipment + easypost.Pickup.create(**pickup_create) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_pickups_retrieve(shipment_one_call_buy, pickup_create): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + pickup_create["shipment"] = shipment + pickup = easypost.Pickup.create(**pickup_create) + easypost.Pickup.retrieve(pickup.id) + + build_response_snippet(interaction_index=2) + + +@pytest.mark.vcr() +def test_pickups_buy(shipment_one_call_buy, pickup_create): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + pickup_create["shipment"] = shipment + pickup = easypost.Pickup.create(**pickup_create) + pickup.buy(carrier="USPS", service="NextDay") + + build_response_snippet(interaction_index=2) + + +@pytest.mark.vcr() +def test_pickups_cancel(shipment_one_call_buy, pickup_create): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + pickup_create["shipment"] = shipment + pickup = easypost.Pickup.create(**pickup_create) + bought_pickup = pickup.buy(carrier="USPS", service="NextDay") + bought_pickup.cancel() + + build_response_snippet(interaction_index=3) diff --git a/tools/docs/responses/tests/test_rate.py b/tools/docs/responses/tests/test_rate.py new file mode 100644 index 00000000..6d39ebb2 --- /dev/null +++ b/tools/docs/responses/tests/test_rate.py @@ -0,0 +1,20 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_rates_retrieve(shipment_create): + shipment = easypost.Shipment.create(**shipment_create) + + easypost.Rate.retrieve(shipment.rates[0].id) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_rates_regenerate(shipment_create): + shipment = easypost.Shipment.create(**shipment_create) + shipment.regenerate_rates() + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_referral_customer.py b/tools/docs/responses/tests/test_referral_customer.py new file mode 100644 index 00000000..afa8e305 --- /dev/null +++ b/tools/docs/responses/tests/test_referral_customer.py @@ -0,0 +1,84 @@ +import os +from unittest.mock import patch + +import easypost +import pytest +from builder.snippets import ( + build_response_snippet, + save_raw_json, +) + + +REFERRAL_USER_PROD_API_KEY = os.getenv("REFERRAL_USER_PROD_API_KEY", "123") + + +def test_referral_customers_add_payment_method(): + response_dict = { + "id": "card_...", + "disabled_at": None, + "object": "CreditCard", + "name": None, + "last4": "1234", + "exp_month": 7, + "exp_year": 2024, + "brand": "MasterCard", + } + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) + + +def test_referral_customers_refund_by_amount(): + response_dict = { + "refunded_amount": 2000, + "payment_log_id": "paylog_...", + "refunded_payment_logs": ["paylog...", "paylog..."], + "errors": [], + } + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) + + +def test_referral_customers_refund_by_payment_log(): + response_dict = { + "refunded_amount": 2000, + "payment_log_id": "paylog_...", + "refunded_payment_logs": ["paylog...", "paylog..."], + "errors": [], + } + + test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] + save_raw_json(test_name, response_dict) + + +@pytest.mark.vcr() +def test_referral_customers_create(partner_prod_api_key): + """This test requires a partner user's production API key via PARTNER_USER_PROD_API_KEY.""" + easypost.Referral.create( + name="test test", + email="test@test.com", + phone="8888888888", + ) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_referral_customers_update(partner_prod_api_key): + """This test requires a partner user's production API key via PARTNER_USER_PROD_API_KEY.""" + referral_users = easypost.Referral.all() + easypost.Referral.update_email( + "email@example.com", + referral_users.referral_customers[0].id, + ) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_referral_customers_list(partner_prod_api_key, page_size): + """This test requires a partner user's production API key via PARTNER_USER_PROD_API_KEY.""" + easypost.Referral.all(page_size=page_size) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_refund.py b/tools/docs/responses/tests/test_refund.py new file mode 100644 index 00000000..00c18d37 --- /dev/null +++ b/tools/docs/responses/tests/test_refund.py @@ -0,0 +1,31 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_refunds_create(shipment_one_call_buy): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + # We need to retrieve the shipment so that the tracking_code has time to populate + retrieved_shipment = easypost.Shipment.retrieve(shipment.id) + easypost.Refund.create( + carrier="USPS", + tracking_codes=retrieved_shipment.tracking_code, + ) + + build_response_snippet(interaction_index=2) + + +@pytest.mark.vcr() +def test_refunds_list(page_size): + easypost.Refund.all(page_size=page_size) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_refunds_retrieve(page_size): + refunds = easypost.Refund.all(page_size=page_size) + easypost.Refund.retrieve(refunds["refunds"][0]["id"]) + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_report.py b/tools/docs/responses/tests/test_report.py new file mode 100644 index 00000000..51289a7d --- /dev/null +++ b/tools/docs/responses/tests/test_report.py @@ -0,0 +1,34 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_reports_create(report_type, report_date): + easypost.Report.create( + type=report_type, + start_date=report_date, + end_date=report_date, + ) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_reports_retrieve(report_type, report_date): + report = easypost.Report.create( + type=report_type, + start_date=report_date, + end_date=report_date, + ) + + easypost.Report.retrieve(report.id) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_reports_list(report_type, page_size): + easypost.Report.all(type=report_type, page_size=page_size) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_returns.py b/tools/docs/responses/tests/test_returns.py new file mode 100644 index 00000000..125ab2fd --- /dev/null +++ b/tools/docs/responses/tests/test_returns.py @@ -0,0 +1,11 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_returns_create(shipment_create): + shipment_create["is_return"] = True + easypost.Shipment.create(**shipment_create) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_scan_form.py b/tools/docs/responses/tests/test_scan_form.py new file mode 100644 index 00000000..870a1ec9 --- /dev/null +++ b/tools/docs/responses/tests/test_scan_form.py @@ -0,0 +1,27 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_scan_form_create(shipment_one_call_buy): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + easypost.ScanForm.create(shipment=[shipment]) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_scan_form_retrieve(shipment_one_call_buy): + shipment = easypost.Shipment.create(**shipment_one_call_buy) + scanform = easypost.ScanForm.create(shipment=[shipment]) + easypost.ScanForm.retrieve(scanform.id) + + build_response_snippet(interaction_index=2) + + +@pytest.mark.vcr() +def test_scan_form_list(page_size): + easypost.ScanForm.all(page_size=page_size) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_shipment.py b/tools/docs/responses/tests/test_shipment.py new file mode 100644 index 00000000..c6dc41c9 --- /dev/null +++ b/tools/docs/responses/tests/test_shipment.py @@ -0,0 +1,61 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_shipments_create(shipment_create): + easypost.Shipment.create(**shipment_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_shipments_retrieve(shipment_create): + shipment = easypost.Shipment.create(**shipment_create) + easypost.Shipment.retrieve(shipment.id) + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_shipments_list(page_size): + easypost.Shipment.all(page_size=page_size) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_shipments_buy(shipment_create): + shipment = easypost.Shipment.create(**shipment_create) + shipment.buy(rate=shipment.lowest_rate(), insurance="249.99") + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_shipments_one_call_buy(shipment_one_call_buy): + easypost.Shipment.create(**shipment_one_call_buy) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_shipments_label(shipment_create): + shipment = easypost.Shipment.create(**shipment_create) + shipment.buy(rate=shipment.lowest_rate()) + shipment.label(file_format="ZPL") + + build_response_snippet(interaction_index=2) + + +@pytest.mark.vcr() +def test_shipments_refund(shipment_one_call_buy): + """Refunding a test shipment must happen within seconds of the shipment being created as test shipments naturally + follow a flow of created -> delivered to cycle through tracking events in test mode - as such anything older + than a few seconds in test mode may not be refundable. + """ + shipment = easypost.Shipment.create(**shipment_one_call_buy) + shipment.refund() + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_shipping_insurance.py b/tools/docs/responses/tests/test_shipping_insurance.py new file mode 100644 index 00000000..a7cbe950 --- /dev/null +++ b/tools/docs/responses/tests/test_shipping_insurance.py @@ -0,0 +1,18 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_shipping_insurance_insure(shipment_one_call_buy): + """Set insurnace to `0` when buying a shipment. + + If the shipment was purchased with a USPS rate, it must have had its insurance set to `0` when bought + so that USPS doesn't automatically insure it so we could manually insure it here. + """ + # Set to 0 so USPS doesn't insure this automatically and we can insure the shipment manually + shipment_one_call_buy["insurance"] = 0 + shipment = easypost.Shipment.create(**shipment_one_call_buy) + shipment.insure(amount="100") + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_smartrate.py b/tools/docs/responses/tests/test_smartrate.py new file mode 100644 index 00000000..568d29a8 --- /dev/null +++ b/tools/docs/responses/tests/test_smartrate.py @@ -0,0 +1,11 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_smartrate_retrieve_time_in_transit_statistics(shipment_create): + shipment = easypost.Shipment.create(**shipment_create) + shipment.get_smartrates() + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_tax_identifiers.py b/tools/docs/responses/tests/test_tax_identifiers.py new file mode 100644 index 00000000..73489e30 --- /dev/null +++ b/tools/docs/responses/tests/test_tax_identifiers.py @@ -0,0 +1,12 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_tax_identifiers_create(shipment_create, tax_identifier_create): + shipment_data = shipment_create + shipment_data["tax_identifiers"] = [tax_identifier_create] + easypost.Shipment.create(**shipment_data) + + build_response_snippet() diff --git a/tools/docs/responses/tests/test_tracker.py b/tools/docs/responses/tests/test_tracker.py new file mode 100644 index 00000000..b4d5bf25 --- /dev/null +++ b/tools/docs/responses/tests/test_tracker.py @@ -0,0 +1,18 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_trackers_create(tracker_create): + easypost.Tracker.create(**tracker_create) + + build_response_snippet() + + +@pytest.mark.vcr() +def test_trackers_retrieve(page_size): + trackers = easypost.Tracker.all(page_size=page_size) + easypost.Tracker.retrieve(trackers["trackers"][0].id) + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_user.py b/tools/docs/responses/tests/test_user.py new file mode 100644 index 00000000..4db67ea9 --- /dev/null +++ b/tools/docs/responses/tests/test_user.py @@ -0,0 +1,37 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_child_users_create(prod_api_key): + user = easypost.User.create(name="Test User") + + # Delete the user so we don't clutter up the test environment + user.delete() + + build_response_snippet() + + +@pytest.mark.vcr() +def test_users_retrieve(prod_api_key): + easypost.User.retrieve_me() + + build_response_snippet() + + +@pytest.mark.vcr() +def test_users_update(prod_api_key): + user = easypost.User.retrieve_me() + user.phone = "5555555555" + user.save() + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_child_users_delete(prod_api_key): + user = easypost.User.create(name="Test User") + user.delete() + + build_response_snippet(interaction_index=1) diff --git a/tools/docs/responses/tests/test_webhook.py b/tools/docs/responses/tests/test_webhook.py new file mode 100644 index 00000000..1b9d7d73 --- /dev/null +++ b/tools/docs/responses/tests/test_webhook.py @@ -0,0 +1,50 @@ +import easypost +import pytest +from builder.snippets import build_response_snippet + + +@pytest.mark.vcr() +def test_webhooks_create(webhook_create): + webhook = easypost.Webhook.create(**webhook_create) + + webhook.delete() # we are deleting the webhook here so we don't keep sending events to a dead webhook. + + build_response_snippet() + + +@pytest.mark.vcr() +def test_webhooks_retrieve(webhook_create): + webhook = easypost.Webhook.create(**webhook_create) + easypost.Webhook.retrieve(webhook.id) + + webhook.delete() # we are deleting the webhook here so we don't keep sending events to a dead webhook. + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_webhooks_list(webhook_create, page_size): + webhook = easypost.Webhook.create(**webhook_create) + easypost.Webhook.all(page_size=page_size) + + webhook.delete() # we are deleting the webhook here so we don't keep sending events to a dead webhook. + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_webhooks_update(webhook_create): + webhook = easypost.Webhook.create(**webhook_create) + webhook.update() + + webhook.delete() # we are deleting the webhook here so we don't keep sending events to a dead webhook. + + build_response_snippet(interaction_index=1) + + +@pytest.mark.vcr() +def test_webhooks_delete(webhook_create): + webhook = easypost.Webhook.create(**webhook_create) + webhook.delete() + + build_response_snippet(interaction_index=1)