Skip to content

feat(typeform): upgrade to SDK 2.0.0 with unit + integration tests#379

Merged
Tram-Nguyen87 merged 4 commits into
masterfrom
feat/typeform-sdk-v2-upgrade
Jun 22, 2026
Merged

feat(typeform): upgrade to SDK 2.0.0 with unit + integration tests#379
Tram-Nguyen87 merged 4 commits into
masterfrom
feat/typeform-sdk-v2-upgrade

Conversation

@Tram-Nguyen87

@Tram-Nguyen87 Tram-Nguyen87 commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Upgrades the Typeform integration from SDK 1.0.2 to 2.0.0, covering source, tests, requirements.txt, and config.json. Adds full unit + integration test suites (the integration previously had only a legacy script-style test).

Draft — code, unit tests, and all local CI checks are green. Marked not-ready pending a live integration-test run against a real Typeform account (no token available in this environment yet). Will flip to ready once those pass.

What changed

Source (typeform.py) — all 24 actions

  • Access .data on every context.fetch() result (user, forms, responses, workspaces, themes, images, webhooks — including the chained update_form / update_workspace fetches).
  • Convert genuine exception paths to ActionError(message=...).
  • Deliberately keep the structured 429 rate-limit response as an ActionResult (create_rate_limit_response) rather than converting to ActionError, so the documented retry contract (error_type, retry_after_seconds, _retry_attempt, can_retry) the agent relies on survives. Verified it still passes output-schema validation.
  • Guard the two chained-fetch actions against the v2 empty-body case (.data is None) so an unexpected body returns a clean ActionError instead of an AttributeError / VALIDATION_ERROR.

Config / deps

  • config.json version 1.1.02.0.0. Output schemas unchanged: there was no error property to remove, and result is a genuine success flag (returned on success), not error-only.
  • requirements.txt pins autohive-integrations-sdk~=2.0.0.

Tests

  • tests/test_typeform_unit.py107 tests (mock_context + FetchResponse). Every action covered for: happy path, request verification (URL/method/body/params), ActionError on exceptions, structured rate-limit, and VALIDATION_ERROR on missing required inputs; plus direct tests of the is_rate_limit_error / create_rate_limit_response helpers.
  • tests/test_typeform_integration.pylive_context platform-OAuth fixture; 13 read-only tests (chained list→get, skip gracefully on empty accounts) + 4 destructive lifecycle tests (form / workspace / theme / webhook, each cleans up after itself). real_fetch mirrors the SDK contract — raises RateLimitError on 429 and HTTPError on other non-ok — so error-path assertions exercise the same code production does.
  • tests/conftest.py added (sys.path + platform-OAuth mock_context). Legacy test_typeform.py / context.py removed.
  • .env.example documents TYPEFORM_ACCESS_TOKEN (+ optional TYPEFORM_TEST_FORM_ID, TYPEFORM_TEST_WORKSPACE_ID).

Test runs (local, this branch)

ruff check + ruff format (CI config, 120 cols)   → pass
pytest typeform/tests/test_typeform_unit.py       → 107 passed
validate_integration.py typeform                  → 0 errors (1 benign unused-scope warning)
check_code.py typeform                            → all 9 checks pass

Integration tests collect correctly (13 read-only + 4 destructive) and skip cleanly without a token.

To run the integration tests (after setting TYPEFORM_ACCESS_TOKEN):

# Safe — read-only (default)
pytest typeform/tests/test_typeform_integration.py -m "integration and not destructive"

# Destructive — creates/updates/deletes real forms, workspaces, themes, webhooks on the connected account
pytest typeform/tests/test_typeform_integration.py -m "integration and destructive"

Reviewer notes

  • The rate-limit ActionResult retention is intentional (see above) — not an overlooked error-path conversion.
  • The list_responses config-code-sync warnings are false positives: those params are read via a param_keys loop the linter can't trace.
Screenshot 2026-06-19 121248 Screenshot 2026-06-19 121258

Migrate all 24 actions to the SDK 2.0.0 FetchResponse contract and ActionError
error model:

- Access .data on every context.fetch() result (forms, responses, workspaces,
  themes, images, webhooks + the chained update_form/update_workspace fetches).
- Convert genuine exception paths to ActionError(message=...).
- Intentionally keep the structured 429 rate-limit response as an ActionResult so
  the documented retry contract (retry_after_seconds, _retry_attempt) survives.
- Guard the two chained-fetch actions against v2 empty-body (.data is None).
- Bump config.json to 2.0.0 and pin autohive-integrations-sdk~=2.0.0.

Tests:
- test_typeform_unit.py: 107 tests (mock_context + FetchResponse) covering every
  action's happy path, request verification, ActionError, structured rate-limit,
  and validation-error cases, plus the rate-limit helpers.
- test_typeform_integration.py: live_context (platform-OAuth) read-only + destructive
  lifecycle tests; real_fetch mirrors the SDK contract (raises on 429/non-ok).
- Replace the legacy script-style test_typeform.py; document env vars in .env.example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

🔍 Integration Validation Results

Commit: 271223d8f0945fea82831afc89dc660cd4f59326 · chore(typeform): comment out Typeform vars in .env.example for consistency
Updated: 2026-06-21T23:13:12Z

Changed directories: typeform

Check Result
Structure ⚠️ Passed with warnings
Code ✅ Passed
Tests ✅ Passed
README ✅ Passed
Version ✅ Passed
⚠️ Structure Check output
Validating 1 integration(s)...

============================================================
Integration: typeform
============================================================

Warnings (1):
  ⚠️ Potentially unused scopes (please verify): accounts:read, offline

============================================================
SUMMARY
============================================================
Integrations validated: 1
Total errors: 0
Total warnings: 1

⚠️ Validation passed with warnings - please review
✅ Code Check output
----------------------------------------
Checking: typeform
----------------------------------------

📦 Installing dependencies...

🐍 Checking Python syntax...
   ✅ Syntax OK

📥 Checking imports...
   ✅ Imports OK

📄 Checking JSON files...
   ✅ JSON files OK

🔍 Linting with ruff...
   ✅ Lint OK

🎨 Checking formatting with ruff...
   ✅ Formatting OK

🔒 Scanning for security issues with bandit...
   ✅ Security OK

🛡️ Checking dependencies for vulnerabilities with pip-audit...
   ✅ Dependencies OK

🔗 Checking config-code sync...
   ✅ Config-code sync OK

🔄 Checking fetch patterns...
   ✅ Fetch patterns OK

========================================
✅ CODE CHECK PASSED
========================================
✅ Tests Check output

Integration   Tests  Coverage        Status
-------------------------------------------
typeform   107/107       92%      ✅ Passed
-------------------------------------------
Total      107/107            ✅ All passed

✅ Tests passed: typeform
✅ README Check output
========================================
✅ README CHECK PASSED
========================================
✅ Version Check output
✅ typeform: 1.1.0 → 2.0.0 (major bump)

========================================
✅ VERSION CHECK PASSED
========================================

Replace the param_keys loop with explicit inputs.get() guards so the
config-code sync checker can see each parameter (it only detects literal
inputs["key"]/inputs.get("key") access, not loop variables). Clears the 8
list_responses sync warnings. Behaviour is identical — same truthy guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Tram-Nguyen87 Tram-Nguyen87 marked this pull request as ready for review June 21, 2026 22:44
create_theme requires a font property; add it to the theme lifecycle payload. Make the webhook lifecycle test create its own throwaway form instead of depending on a pre-existing one, so destructive e2e passes on empty accounts.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Tram-Nguyen87

Copy link
Copy Markdown
Contributor Author

Local validation + live E2E results

Ran the full CI-equivalent pipeline plus live end-to-end tests against the real Typeform API.

Validation pipeline

Check Result
validate_integration.py (structure) ✅ pass (1 non-blocking warning: potentially unused scopes accounts:read, offline)
check_code.py (syntax, imports, JSON, ruff lint+format, bandit, pip-audit, config-code sync, fetch patterns) ✅ pass
Unit tests 107/107

Live E2E

Read-only (-m "integration and not destructive"): 9 passed, 4 skipped

  • Skips are expected on an empty test account (no forms / images → get_form, list_responses, list_webhooks, get_image skip gracefully).

Destructive (-m "integration and destructive"): 4/4 passed

  • Form lifecycle (create → get → update → delete) ✅
  • Workspace lifecycle ✅
  • Theme lifecycle ✅
  • Webhook lifecycle ✅

Fixes included in this push (0be3366)

  • Theme test: create_theme now requires a font property — added "font": "Arial" to the theme lifecycle payload (API returned 400 VALIDATION_ERROR: missing properties: 'font' without it).
  • Webhook test: made the webhook lifecycle self-contained — it creates its own throwaway form and cleans it up in finally, instead of depending on a pre-existing form. This lets destructive E2E pass on empty accounts.

SDK 2.0.0 migration (FetchResponse .data, ActionError error paths) verified working end-to-end against the live API.

…tency

Co-authored-by: Cursor <cursoragent@cursor.com>

@TheRealAgentK TheRealAgentK left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — the SDK v2 migration, tests, and validation look good. I left one nit about confirming the potentially-unused Typeform scopes, but it is not blocking.

Comment thread typeform/config.json

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: local validate_integration.py typeform passes, but it flags accounts:read and offline as potentially unused scopes. If those are required for Typeform/platform OAuth refresh behavior, this is fine as-is; otherwise consider trimming them to keep the OAuth request minimal.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both scopes are intentional:

  • accounts:read is required by Typeform's /me endpoint, used by get_current_user.
  • offline is the standard OAuth2 refresh-token scope — without it the platform can't refresh the access token after expiry.
    The validator can't detect these statically, hence the warning.

@Tram-Nguyen87 Tram-Nguyen87 merged commit 7b91e3c into master Jun 22, 2026
3 checks passed
@Tram-Nguyen87 Tram-Nguyen87 deleted the feat/typeform-sdk-v2-upgrade branch June 22, 2026 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants