diff --git a/tools/test-api b/tools/test-api index 04c3cd2c91..07c1d5dcfb 100755 --- a/tools/test-api +++ b/tools/test-api @@ -31,6 +31,7 @@ with test_server_running(force=options.force, external_host='zulipdev.com:9981') # Zerver imports should happen after `django.setup()` is run # by the test_server_running decorator. from zerver.openapi.python_examples import test_the_api, test_invalid_api_key + from zerver.openapi.javascript_examples import test_js_bindings from zerver.openapi.test_curl_examples import test_generated_curl_examples_for_success from zerver.lib.actions import do_create_user from zerver.lib.test_helpers import reset_emails_in_zulip_realm @@ -77,6 +78,7 @@ with test_server_running(force=options.force, external_host='zulipdev.com:9981') test_the_api(client, nonadmin_client) test_generated_curl_examples_for_success(client) + test_js_bindings(client) # Test error payloads client = Client( diff --git a/zerver/openapi/javascript_examples.py b/zerver/openapi/javascript_examples.py new file mode 100644 index 0000000000..cbb41a1457 --- /dev/null +++ b/zerver/openapi/javascript_examples.py @@ -0,0 +1,26 @@ +import os +import json +import subprocess + +from zulip import Client +from zerver.openapi.openapi import validate_against_openapi_schema + +def test_js_bindings(client: Client) -> None: + os.environ['ZULIP_USERNAME'] = client.email + os.environ['ZULIP_API_KEY'] = client.api_key + os.environ['ZULIP_REALM'] = client.base_url[:-5] + + output = subprocess.check_output( + args=['node', 'zerver/openapi/javascript_examples.js'], + universal_newlines=True, + ) + endpoint_responses = json.loads(output) + + for response_data in endpoint_responses: + print(f"Testing javascript example: {response_data['name']} ...") + validate_against_openapi_schema(response_data['result'], + response_data['endpoint'], + response_data['method'], + response_data['status_code']) + + print('JavaScript examples validated.') diff --git a/zerver/openapi/markdown_extension.py b/zerver/openapi/markdown_extension.py index e7d40a70c0..b83bbae490 100644 --- a/zerver/openapi/markdown_extension.py +++ b/zerver/openapi/markdown_extension.py @@ -1,6 +1,7 @@ import re import json import inspect +import subprocess from django.conf import settings @@ -37,6 +38,22 @@ client = zulip.Client(config_file="~/zuliprc-admin") """ +JS_CLIENT_CONFIG = """ +const Zulip = require('zulip-js'); + +// Pass the path to your zuliprc file here. +const config = { zuliprc: 'zuliprc' }; + +""" + +JS_CLIENT_ADMIN_CONFIG = """ +const Zulip = require('zulip-js'); + +// The user for this zuliprc file must be an organization administrator. +const config = { zuliprc: 'zuliprc-admin' }; + +""" + DEFAULT_AUTH_EMAIL = "BOT_EMAIL_ADDRESS" DEFAULT_AUTH_API_KEY = "BOT_API_KEY" DEFAULT_EXAMPLE = { @@ -108,6 +125,29 @@ def render_python_code_example(function: str, admin_config: Optional[bool]=False return code_example +def render_javascript_code_example(function: str, admin_config: Optional[bool]=False, + **kwargs: Any) -> List[str]: + output = subprocess.check_output( + args=['node', 'zerver/openapi/javascript_examples.js', 'generate-example', function], + universal_newlines=True, + ) + function_source_lines = output.splitlines() + if admin_config: + config = JS_CLIENT_ADMIN_CONFIG.splitlines() + else: + config = JS_CLIENT_CONFIG.splitlines() + + snippet = function_source_lines + + code_example = [] + code_example.append('```js') + code_example.extend(config) + for line in snippet: + # Strip newlines + code_example.append(line.rstrip()) + code_example.append('```') + return code_example + def curl_method_arguments(endpoint: str, method: str, api_url: str) -> List[str]: # We also include the -sS verbosity arguments here. @@ -269,6 +309,11 @@ SUPPORTED_LANGUAGES: Dict[str, Any] = { }, 'curl': { 'render': render_curl_example + }, + 'javascript': { + 'client_config': JS_CLIENT_CONFIG, + 'admin_config': JS_CLIENT_ADMIN_CONFIG, + 'render': render_javascript_code_example, } }