diff --git a/doc/CTS.md b/doc/CTS.md index b5fb67e9740..86cbc31c984 100644 --- a/doc/CTS.md +++ b/doc/CTS.md @@ -25,15 +25,15 @@ The test generation script requires a JSON file name from the `operationId` (e.g { "testName": "the name of the test (e.g. test('search endpoint')) (default: 'method')", "method": "the method to call (e.g. search)", - "parameters": [ - "indexName", - { - "$objectName": "the name of the object for strongly type language", + "parameters": { + "indexName": "testIndex", + "searchParam": { + "$objectName": "the name of the object for strongly type language, should be on every 'object' type", "query": "the string to search" } - ], + }, "request": { - "path": "/1/indexes/indexName/query", + "path": "/1/indexes/testIndex/query", "method": "POST", "data": { "query": "the string to search" } } @@ -45,5 +45,45 @@ And that's it! If the name of the file matches a real `operationId` in the spec, ## How to add a new language -- Create a template in `test/CTS/templates/.mustache` that parse a array of test into your test framework of choice - Add the language in the array `languages` in `tests/generateCTS.ts`. +- Create a template in `test/CTS/templates/.mustache` that parse a array of test into your test framework of choice + +When writing your template, here is a list of variables accessible from `mustache`: +```js +{ + "import": "the name of the package or library to import", + "client": "the name of the API Client object to instanciate and import", + "blocks": [{ + // The list of test to implement + "operationID": "the name of the endpoint and the cts file to test", + "tests": [{ + "testName": "the descriptive name test (default to `method`)" + "method": "the method to call on the API Client", + "parameters": { + // Object of all parameters with their name, tobe used for languages that require the parameter name + "parameterName": "value", + ... + }, + "parametersArray": [ + // The same paremeters but passed as an array for other languages + // It includes the `-last` properties used to join the parameters + ], + "request": { + "path": "the expected path of the request", + "method": "the expected method: GET, POST, PUT, DELETE or PATCH", + "data": { + // The expected body of the request + } + } + }] + }] +} +``` + +## Get the list of remaining CTS to implement + +To get the list of `operationId` not yet in the CTS but in the spec, run this command: +```bash +rm -rf ./specs/dist +comm -3 <(grep -r operationId ./specs | awk -F: '{gsub(/ /,""); print $NF}' | sort) <(find ./tests/CTS/clients -type f -name '*.json' | awk -F/ '{gsub(/.json/,"");print $NF}' | sort) +``` diff --git a/tests/CTS/clients/insights/pushEvents.json b/tests/CTS/clients/insights/pushEvents.json index 27ebfaf7517..3de1e39ef2e 100644 --- a/tests/CTS/clients/insights/pushEvents.json +++ b/tests/CTS/clients/insights/pushEvents.json @@ -1,41 +1,51 @@ [ { "method": "pushEvents", - "parameters": [ - { - "insightEvents": { - "events": [ - { - "eventType": "click", - "eventName": "Product Clicked", - "index": "products", - "userToken": "user-123456", - "timestamp": 1641290601962, - "objectIDs": ["9780545139700", "9780439784542"], - "queryID": "43b15df305339e827f0ac0bdc5ebcaa7", - "positions": [7, 6] - }, - { - "eventType": "view", - "eventName":"Product Detail Page Viewed", - "index": "products", - "userToken": "user-123456", - "timestamp": 1641290601962, - "objectIDs": ["9780545139700", "9780439784542"] - }, - { - "eventType": "conversion", - "eventName": "Product Purchased", - "index": "products", - "userToken": "user-123456", - "timestamp": 1641290601962, - "objectIDs": ["9780545139700", "9780439784542"], - "queryID": "43b15df305339e827f0ac0bdc5ebcaa7" - } - ] - } + "parameters": { + "insightEvents": { + "events": [ + { + "eventType": "click", + "eventName": "Product Clicked", + "index": "products", + "userToken": "user-123456", + "timestamp": 1641290601962, + "objectIDs": [ + "9780545139700", + "9780439784542" + ], + "queryID": "43b15df305339e827f0ac0bdc5ebcaa7", + "positions": [ + 7, + 6 + ] + }, + { + "eventType": "view", + "eventName": "Product Detail Page Viewed", + "index": "products", + "userToken": "user-123456", + "timestamp": 1641290601962, + "objectIDs": [ + "9780545139700", + "9780439784542" + ] + }, + { + "eventType": "conversion", + "eventName": "Product Purchased", + "index": "products", + "userToken": "user-123456", + "timestamp": 1641290601962, + "objectIDs": [ + "9780545139700", + "9780439784542" + ], + "queryID": "43b15df305339e827f0ac0bdc5ebcaa7" + } + ] } - ], + }, "request": { "path": "/1/events", "method": "POST", @@ -47,17 +57,26 @@ "index": "products", "userToken": "user-123456", "timestamp": 1641290601962, - "objectIDs": ["9780545139700", "9780439784542"], + "objectIDs": [ + "9780545139700", + "9780439784542" + ], "queryID": "43b15df305339e827f0ac0bdc5ebcaa7", - "positions": [7, 6] + "positions": [ + 7, + 6 + ] }, { "eventType": "view", - "eventName":"Product Detail Page Viewed", + "eventName": "Product Detail Page Viewed", "index": "products", "userToken": "user-123456", "timestamp": 1641290601962, - "objectIDs": ["9780545139700", "9780439784542"] + "objectIDs": [ + "9780545139700", + "9780439784542" + ] }, { "eventType": "conversion", @@ -65,7 +84,10 @@ "index": "products", "userToken": "user-123456", "timestamp": 1641290601962, - "objectIDs": ["9780545139700", "9780439784542"], + "objectIDs": [ + "9780545139700", + "9780439784542" + ], "queryID": "43b15df305339e827f0ac0bdc5ebcaa7" } ] diff --git a/tests/CTS/clients/recommend/getRecommendations.json b/tests/CTS/clients/recommend/getRecommendations.json index fb7ec3e0867..d40432fdbe6 100644 --- a/tests/CTS/clients/recommend/getRecommendations.json +++ b/tests/CTS/clients/recommend/getRecommendations.json @@ -2,20 +2,18 @@ { "method": "getRecommendations", "testName": "get recommendations with minimal parameters", - "parameters": [ - { - "getRecommendations": { - "requests": [ - { - "indexName": "indexName", - "objectID": "objectID", - "model": "related-products", - "threshold": 42 - } - ] - } + "parameters": { + "getRecommendations": { + "requests": [ + { + "indexName": "indexName", + "objectID": "objectID", + "model": "related-products", + "threshold": 42 + } + ] } - ], + }, "request": { "path": "/1/indexes/*/recommendations", "method": "POST", @@ -34,22 +32,28 @@ { "method": "getRecommendations", "testName": "get recommendations with all parameters", - "parameters": [ - { - "getRecommendations": { - "requests": [ - { - "indexName": "indexName", - "objectID": "objectID", - "model": "related-products", - "threshold": 42, - "queryParameters": { "facetFilters": ["query"] }, - "fallbackParameters": { "facetFilters": ["fallback"] } + "parameters": { + "getRecommendations": { + "requests": [ + { + "indexName": "indexName", + "objectID": "objectID", + "model": "related-products", + "threshold": 42, + "queryParameters": { + "facetFilters": [ + "query" + ] + }, + "fallbackParameters": { + "facetFilters": [ + "fallback" + ] } - ] - } + } + ] } - ], + }, "request": { "path": "/1/indexes/*/recommendations", "method": "POST", @@ -60,8 +64,16 @@ "objectID": "objectID", "model": "related-products", "threshold": 42, - "queryParameters": { "facetFilters": ["query"] }, - "fallbackParameters": { "facetFilters": ["fallback"] } + "queryParameters": { + "facetFilters": [ + "query" + ] + }, + "fallbackParameters": { + "facetFilters": [ + "fallback" + ] + } } ] } @@ -70,26 +82,24 @@ { "method": "getRecommendations", "testName": "get multiple recommendations with minimal parameters", - "parameters": [ - { - "getRecommendations": { - "requests": [ - { - "indexName": "indexName1", - "objectID": "objectID1", - "model": "related-products", - "threshold": 21 - }, - { - "indexName": "indexName2", - "objectID": "objectID2", - "model": "related-products", - "threshold": 21 - } - ] - } + "parameters": { + "getRecommendations": { + "requests": [ + { + "indexName": "indexName1", + "objectID": "objectID1", + "model": "related-products", + "threshold": 21 + }, + { + "indexName": "indexName2", + "objectID": "objectID2", + "model": "related-products", + "threshold": 21 + } + ] } - ], + }, "request": { "path": "/1/indexes/*/recommendations", "method": "POST", @@ -114,30 +124,44 @@ { "method": "getRecommendations", "testName": "get multiple recommendations with all parameters", - "parameters": [ - { - "getRecommendations": { - "requests": [ - { - "indexName": "indexName1", - "objectID": "objectID1", - "model": "related-products", - "threshold": 21, - "queryParameters": { "facetFilters": ["query1"] }, - "fallbackParameters": { "facetFilters": ["fallback1"] } + "parameters": { + "getRecommendations": { + "requests": [ + { + "indexName": "indexName1", + "objectID": "objectID1", + "model": "related-products", + "threshold": 21, + "queryParameters": { + "facetFilters": [ + "query1" + ] + }, + "fallbackParameters": { + "facetFilters": [ + "fallback1" + ] + } + }, + { + "indexName": "indexName2", + "objectID": "objectID2", + "model": "related-products", + "threshold": 21, + "queryParameters": { + "facetFilters": [ + "query2" + ] }, - { - "indexName": "indexName2", - "objectID": "objectID2", - "model": "related-products", - "threshold": 21, - "queryParameters": { "facetFilters": ["query2"] }, - "fallbackParameters": { "facetFilters": ["fallback2"] } + "fallbackParameters": { + "facetFilters": [ + "fallback2" + ] } - ] - } + } + ] } - ], + }, "request": { "path": "/1/indexes/*/recommendations", "method": "POST", @@ -148,16 +172,32 @@ "objectID": "objectID1", "model": "related-products", "threshold": 21, - "queryParameters": { "facetFilters": ["query1"] }, - "fallbackParameters": { "facetFilters": ["fallback1"] } + "queryParameters": { + "facetFilters": [ + "query1" + ] + }, + "fallbackParameters": { + "facetFilters": [ + "fallback1" + ] + } }, { "indexName": "indexName2", "objectID": "objectID2", "model": "related-products", "threshold": 21, - "queryParameters": { "facetFilters": ["query2"] }, - "fallbackParameters": { "facetFilters": ["fallback2"] } + "queryParameters": { + "facetFilters": [ + "query2" + ] + }, + "fallbackParameters": { + "facetFilters": [ + "fallback2" + ] + } } ] } @@ -166,20 +206,18 @@ { "method": "getRecommendations", "testName": "get frequently bought together recommendations", - "parameters": [ - { - "getRecommendations": { - "requests": [ - { - "indexName": "indexName1", - "objectID": "objectID1", - "model": "bought-together", - "threshold": 42 - } - ] - } + "parameters": { + "getRecommendations": { + "requests": [ + { + "indexName": "indexName1", + "objectID": "objectID1", + "model": "bought-together", + "threshold": 42 + } + ] } - ], + }, "request": { "path": "/1/indexes/*/recommendations", "method": "POST", diff --git a/tests/CTS/clients/search/addApiKey.json b/tests/CTS/clients/search/addApiKey.json index 66d733c5830..8477c1d65e0 100644 --- a/tests/CTS/clients/search/addApiKey.json +++ b/tests/CTS/clients/search/addApiKey.json @@ -1,22 +1,26 @@ [ { "method": "addApiKey", - "parameters": [ - { - "apiKey": { - "acl": ["search", "addObject"], - "description": "my new api key", - "validity": 300, - "maxQueriesPerIPPerHour": 100, - "maxHitsPerQuery": 20 - } + "parameters": { + "apiKey": { + "acl": [ + "search", + "addObject" + ], + "description": "my new api key", + "validity": 300, + "maxQueriesPerIPPerHour": 100, + "maxHitsPerQuery": 20 } - ], + }, "request": { "path": "/1/keys", "method": "POST", "data": { - "acl": ["search", "addObject"], + "acl": [ + "search", + "addObject" + ], "description": "my new api key", "validity": 300, "maxQueriesPerIPPerHour": 100, diff --git a/tests/CTS/clients/search/batchDictionaryEntries.json b/tests/CTS/clients/search/batchDictionaryEntries.json index 91c73db3020..15fb381ef17 100644 --- a/tests/CTS/clients/search/batchDictionaryEntries.json +++ b/tests/CTS/clients/search/batchDictionaryEntries.json @@ -2,29 +2,27 @@ { "method": "batchDictionaryEntries", "testName": "get batchDictionaryEntries results with minimal parameters", - "parameters": [ - { - "dictionaryName": "dictionaryName", - "batchDictionaryEntries": { - "requests": [ - { - "action": "addEntry", - "body": { - "objectID": "1", - "language": "en" - } - }, - { - "action": "deleteEntry", - "body": { - "objectID": "2", - "language": "fr" - } + "parameters": { + "dictionaryName": "dictionaryName", + "batchDictionaryEntries": { + "requests": [ + { + "action": "addEntry", + "body": { + "objectID": "1", + "language": "en" + } + }, + { + "action": "deleteEntry", + "body": { + "objectID": "2", + "language": "fr" } - ] - } + } + ] } - ], + }, "request": { "path": "/1/dictionaries/dictionaryName/batch", "method": "POST", @@ -51,38 +49,48 @@ { "method": "batchDictionaryEntries", "testName": "get batchDictionaryEntries results with all parameters", - "parameters": [ - { - "dictionaryName": "dictionaryName", - "batchDictionaryEntries": { - "clearExistingDictionaryEntries": false, - "requests": [ - { - "action": "addEntry", - "body": { - "objectID": "1", - "language": "en", - "word": "yo", - "words": ["yo", "algolia"], - "decomposition": ["yo", "algolia"], - "state": "enabled" - } - }, - { - "action": "deleteEntry", - "body": { - "objectID": "2", - "language": "fr", - "word": "salut", - "words": ["salut", "algolia"], - "decomposition": ["salut", "algolia"], - "state": "enabled" - } + "parameters": { + "dictionaryName": "dictionaryName", + "batchDictionaryEntries": { + "clearExistingDictionaryEntries": false, + "requests": [ + { + "action": "addEntry", + "body": { + "objectID": "1", + "language": "en", + "word": "yo", + "words": [ + "yo", + "algolia" + ], + "decomposition": [ + "yo", + "algolia" + ], + "state": "enabled" } - ] - } + }, + { + "action": "deleteEntry", + "body": { + "objectID": "2", + "language": "fr", + "word": "salut", + "words": [ + "salut", + "algolia" + ], + "decomposition": [ + "salut", + "algolia" + ], + "state": "enabled" + } + } + ] } - ], + }, "request": { "path": "/1/dictionaries/dictionaryName/batch", "method": "POST", @@ -95,8 +103,14 @@ "objectID": "1", "language": "en", "word": "yo", - "words": ["yo", "algolia"], - "decomposition": ["yo", "algolia"], + "words": [ + "yo", + "algolia" + ], + "decomposition": [ + "yo", + "algolia" + ], "state": "enabled" } }, @@ -106,8 +120,14 @@ "objectID": "2", "language": "fr", "word": "salut", - "words": ["salut", "algolia"], - "decomposition": ["salut", "algolia"], + "words": [ + "salut", + "algolia" + ], + "decomposition": [ + "salut", + "algolia" + ], "state": "enabled" } } diff --git a/tests/CTS/clients/search/batchRules.json b/tests/CTS/clients/search/batchRules.json index b340f6a1ba4..c0e1656bf69 100644 --- a/tests/CTS/clients/search/batchRules.json +++ b/tests/CTS/clients/search/batchRules.json @@ -1,43 +1,41 @@ [ { "method": "batchRules", - "parameters": [ - { - "indexName": "indexName", - "rule": [ - { - "objectID": "a-rule-id", - "conditions": [ - { - "pattern": "smartphone", - "anchoring": "contains" - } - ], - "consequence": { - "params": { - "filters": "category:smartphone" - } + "parameters": { + "indexName": "indexName", + "rule": [ + { + "objectID": "a-rule-id", + "conditions": [ + { + "pattern": "smartphone", + "anchoring": "contains" } - }, - { - "objectID": "a-second-rule-id", - "conditions": [ - { - "pattern": "apple", - "anchoring": "contains" - } - ], - "consequence": { - "params": { - "filters": "brand:apple" - } + ], + "consequence": { + "params": { + "filters": "category:smartphone" } } - ], - "forwardToReplicas": true, - "clearExistingRules": true - } - ], + }, + { + "objectID": "a-second-rule-id", + "conditions": [ + { + "pattern": "apple", + "anchoring": "contains" + } + ], + "consequence": { + "params": { + "filters": "brand:apple" + } + } + } + ], + "forwardToReplicas": true, + "clearExistingRules": true + }, "request": { "path": "/1/indexes/indexName/rules/batch", "method": "POST", diff --git a/tests/CTS/clients/search/browse.json b/tests/CTS/clients/search/browse.json index caa1101e8d8..56fb3a8a25d 100644 --- a/tests/CTS/clients/search/browse.json +++ b/tests/CTS/clients/search/browse.json @@ -2,7 +2,9 @@ { "method": "browse", "testName": "get browse results with minimal parameters", - "parameters": [{ "indexName": "indexName" }], + "parameters": { + "indexName": "indexName" + }, "request": { "path": "/1/indexes/indexName/browse", "method": "POST" @@ -11,15 +13,13 @@ { "method": "browse", "testName": "get browse results with all parameters", - "parameters": [ - { - "indexName": "indexName", - "browseRequest": { - "params": "query=foo&facetFilters=['bar']", - "cursor": "cts" - } + "parameters": { + "indexName": "indexName", + "browseRequest": { + "params": "query=foo&facetFilters=['bar']", + "cursor": "cts" } - ], + }, "request": { "path": "/1/indexes/indexName/browse", "method": "POST", diff --git a/tests/CTS/clients/search/clearAllSynonyms.json b/tests/CTS/clients/search/clearAllSynonyms.json index 12d891ee969..61daf6c09aa 100644 --- a/tests/CTS/clients/search/clearAllSynonyms.json +++ b/tests/CTS/clients/search/clearAllSynonyms.json @@ -1,7 +1,9 @@ [ { "method": "clearAllSynonyms", - "parameters": [{ "indexName": "indexName" }], + "parameters": { + "indexName": "indexName" + }, "request": { "path": "/1/indexes/indexName/synonyms/clear", "method": "POST" diff --git a/tests/CTS/clients/search/clearRules.json b/tests/CTS/clients/search/clearRules.json index fd1fa700ebf..962a2eab170 100644 --- a/tests/CTS/clients/search/clearRules.json +++ b/tests/CTS/clients/search/clearRules.json @@ -1,7 +1,9 @@ [ { "method": "clearRules", - "parameters": [{ "indexName": "indexName" }], + "parameters": { + "indexName": "indexName" + }, "request": { "path": "/1/indexes/indexName/rules/clear", "method": "POST" diff --git a/tests/CTS/clients/search/deleteApiKey.json b/tests/CTS/clients/search/deleteApiKey.json index 2295b6dce0e..0836c7ab23b 100644 --- a/tests/CTS/clients/search/deleteApiKey.json +++ b/tests/CTS/clients/search/deleteApiKey.json @@ -1,7 +1,9 @@ [ { "method": "deleteApiKey", - "parameters": [{ "key": "myTestApiKey" }], + "parameters": { + "key": "myTestApiKey" + }, "request": { "path": "/1/keys/myTestApiKey", "method": "DELETE" diff --git a/tests/CTS/clients/search/deleteRule.json b/tests/CTS/clients/search/deleteRule.json index 7e63e5535e7..c7e191e719e 100644 --- a/tests/CTS/clients/search/deleteRule.json +++ b/tests/CTS/clients/search/deleteRule.json @@ -1,7 +1,10 @@ [ { "method": "deleteRule", - "parameters": [{ "indexName": "indexName", "objectID": "id1" }], + "parameters": { + "indexName": "indexName", + "objectID": "id1" + }, "request": { "path": "/1/indexes/indexName/rules/id1", "method": "DELETE" diff --git a/tests/CTS/clients/search/deleteSynonym.json b/tests/CTS/clients/search/deleteSynonym.json index eb59860a969..2c81eb8c6e4 100644 --- a/tests/CTS/clients/search/deleteSynonym.json +++ b/tests/CTS/clients/search/deleteSynonym.json @@ -1,7 +1,10 @@ [ { "method": "deleteSynonym", - "parameters": [{ "indexName": "indexName", "objectID": "id1" }], + "parameters": { + "indexName": "indexName", + "objectID": "id1" + }, "request": { "path": "/1/indexes/indexName/synonyms/id1", "method": "DELETE" diff --git a/tests/CTS/clients/search/getApiKey.json b/tests/CTS/clients/search/getApiKey.json index b92233fbd54..e19f6b510f9 100644 --- a/tests/CTS/clients/search/getApiKey.json +++ b/tests/CTS/clients/search/getApiKey.json @@ -1,7 +1,9 @@ [ { "method": "getApiKey", - "parameters": [{ "key": "myTestApiKey" }], + "parameters": { + "key": "myTestApiKey" + }, "request": { "path": "/1/keys/myTestApiKey", "method": "GET" diff --git a/tests/CTS/clients/search/getDictionaryLanguages.json b/tests/CTS/clients/search/getDictionaryLanguages.json index ae95478efc9..bd7d3e76c62 100644 --- a/tests/CTS/clients/search/getDictionaryLanguages.json +++ b/tests/CTS/clients/search/getDictionaryLanguages.json @@ -2,7 +2,7 @@ { "method": "getDictionaryLanguages", "testName": "get getDictionaryLanguages", - "parameters": [], + "parameters": {}, "request": { "path": "/1/dictionaries/*/languages", "method": "GET" diff --git a/tests/CTS/clients/search/getDictionarySettings.json b/tests/CTS/clients/search/getDictionarySettings.json index 7363485ac9d..981fedb2bb5 100644 --- a/tests/CTS/clients/search/getDictionarySettings.json +++ b/tests/CTS/clients/search/getDictionarySettings.json @@ -2,7 +2,7 @@ { "method": "getDictionarySettings", "testName": "get getDictionarySettings results", - "parameters": [], + "parameters": {}, "request": { "path": "/1/dictionaries/*/settings", "method": "GET" diff --git a/tests/CTS/clients/search/getRule.json b/tests/CTS/clients/search/getRule.json index 3cc5f79190f..55fed888ddd 100644 --- a/tests/CTS/clients/search/getRule.json +++ b/tests/CTS/clients/search/getRule.json @@ -1,7 +1,10 @@ [ { "method": "getRule", - "parameters": [{ "indexName": "indexName", "objectID": "id1" }], + "parameters": { + "indexName": "indexName", + "objectID": "id1" + }, "request": { "path": "/1/indexes/indexName/rules/id1", "method": "GET" diff --git a/tests/CTS/clients/search/getSynonym.json b/tests/CTS/clients/search/getSynonym.json index f74e3791227..80f44921fe9 100644 --- a/tests/CTS/clients/search/getSynonym.json +++ b/tests/CTS/clients/search/getSynonym.json @@ -1,7 +1,10 @@ [ { "method": "getSynonym", - "parameters": [{ "indexName": "indexName", "objectID": "id1" }], + "parameters": { + "indexName": "indexName", + "objectID": "id1" + }, "request": { "path": "/1/indexes/indexName/synonyms/id1", "method": "GET" diff --git a/tests/CTS/clients/search/listApiKeys.json b/tests/CTS/clients/search/listApiKeys.json index cb50fe10977..a5b48efa01d 100644 --- a/tests/CTS/clients/search/listApiKeys.json +++ b/tests/CTS/clients/search/listApiKeys.json @@ -1,7 +1,7 @@ [ { "method": "listApiKeys", - "parameters": [], + "parameters": {}, "request": { "path": "/1/keys", "method": "GET" diff --git a/tests/CTS/clients/search/restoreApiKey.json b/tests/CTS/clients/search/restoreApiKey.json index 493be3170a3..9d6048bd1fa 100644 --- a/tests/CTS/clients/search/restoreApiKey.json +++ b/tests/CTS/clients/search/restoreApiKey.json @@ -1,7 +1,9 @@ [ { "method": "restoreApiKey", - "parameters": [{ "key": "myApiKey" }], + "parameters": { + "key": "myApiKey" + }, "request": { "path": "/1/keys/myApiKey/restore", "method": "POST" diff --git a/tests/CTS/clients/search/saveRule.json b/tests/CTS/clients/search/saveRule.json index dd8aad816d7..066c64a739b 100644 --- a/tests/CTS/clients/search/saveRule.json +++ b/tests/CTS/clients/search/saveRule.json @@ -1,27 +1,25 @@ [ { "method": "saveRule", - "parameters": [ - { - "indexName": "indexName", + "parameters": { + "indexName": "indexName", + "objectID": "id1", + "rule": { "objectID": "id1", - "rule": { - "objectID": "id1", - "conditions": [ - { - "pattern": "apple", - "anchoring": "contains" - } - ], - "consequence": { - "params": { - "filters": "brand:apple" - } + "conditions": [ + { + "pattern": "apple", + "anchoring": "contains" } - }, - "forwardToReplicas": true - } - ], + ], + "consequence": { + "params": { + "filters": "brand:apple" + } + } + }, + "forwardToReplicas": true + }, "request": { "path": "/1/indexes/indexName/rules/id1", "method": "PUT", diff --git a/tests/CTS/clients/search/saveSynonym.json b/tests/CTS/clients/search/saveSynonym.json index d081390a600..d5eb3acb52e 100644 --- a/tests/CTS/clients/search/saveSynonym.json +++ b/tests/CTS/clients/search/saveSynonym.json @@ -1,25 +1,31 @@ [ { "method": "saveSynonym", - "parameters": [ - { - "indexName": "indexName", + "parameters": { + "indexName": "indexName", + "objectID": "id1", + "synonymHit": { "objectID": "id1", - "synonymHit": { - "objectID": "id1", - "type": "synonym", - "synonyms": ["car", "vehicule", "auto"] - }, - "forwardToReplicas": true - } - ], + "type": "synonym", + "synonyms": [ + "car", + "vehicule", + "auto" + ] + }, + "forwardToReplicas": true + }, "request": { "path": "/1/indexes/indexName/synonyms/id1", "method": "PUT", "data": { "objectID": "id1", "type": "synonym", - "synonyms": ["car", "vehicule", "auto"] + "synonyms": [ + "car", + "vehicule", + "auto" + ] } } } diff --git a/tests/CTS/clients/search/saveSynonyms.json b/tests/CTS/clients/search/saveSynonyms.json index 3acd2329c16..006a0c3f1bd 100644 --- a/tests/CTS/clients/search/saveSynonyms.json +++ b/tests/CTS/clients/search/saveSynonyms.json @@ -1,26 +1,32 @@ [ { "method": "saveSynonyms", - "parameters": [ - { - "indexName": "indexName", - "synonymHit": [ - { - "objectID": "id1", - "type": "synonym", - "synonyms": ["car", "vehicule", "auto"] - }, - { - "objectID": "id2", - "type": "onewaysynonym", - "input": "iphone", - "synonyms": ["ephone", "aphone", "yphone"] - } - ], - "forwardToReplicas": true, - "replaceExistingSynonyms": false - } - ], + "parameters": { + "indexName": "indexName", + "synonymHit": [ + { + "objectID": "id1", + "type": "synonym", + "synonyms": [ + "car", + "vehicule", + "auto" + ] + }, + { + "objectID": "id2", + "type": "onewaysynonym", + "input": "iphone", + "synonyms": [ + "ephone", + "aphone", + "yphone" + ] + } + ], + "forwardToReplicas": true, + "replaceExistingSynonyms": false + }, "request": { "path": "/1/indexes/indexName/synonyms/batch", "method": "POST", @@ -28,13 +34,21 @@ { "objectID": "id1", "type": "synonym", - "synonyms": ["car", "vehicule", "auto"] + "synonyms": [ + "car", + "vehicule", + "auto" + ] }, { "objectID": "id2", "type": "onewaysynonym", "input": "iphone", - "synonyms": ["ephone", "aphone", "yphone"] + "synonyms": [ + "ephone", + "aphone", + "yphone" + ] } ] } diff --git a/tests/CTS/clients/search/search.json b/tests/CTS/clients/search/search.json index f564f7c9c07..23f6bfecef5 100644 --- a/tests/CTS/clients/search/search.json +++ b/tests/CTS/clients/search/search.json @@ -1,15 +1,13 @@ [ { "method": "search", - "parameters": [ - { - "indexName": "indexName", - "searchParams": { - "$objectName": "Query", - "query": "queryString" - } + "parameters": { + "indexName": "indexName", + "searchParams": { + "$objectName": "Query", + "query": "queryString" } - ], + }, "request": { "path": "/1/indexes/indexName/query", "method": "POST", diff --git a/tests/CTS/clients/search/searchDictionaryEntries.json b/tests/CTS/clients/search/searchDictionaryEntries.json index aee149fccd7..7a4e114fd12 100644 --- a/tests/CTS/clients/search/searchDictionaryEntries.json +++ b/tests/CTS/clients/search/searchDictionaryEntries.json @@ -2,14 +2,12 @@ { "method": "searchDictionaryEntries", "testName": "get searchDictionaryEntries results with minimal parameters", - "parameters": [ - { - "dictionaryName": "dictionaryName", - "searchDictionaryEntries": { - "query": "foo" - } + "parameters": { + "dictionaryName": "dictionaryName", + "searchDictionaryEntries": { + "query": "foo" } - ], + }, "request": { "path": "/1/dictionaries/dictionaryName/search", "method": "POST", @@ -21,17 +19,15 @@ { "method": "searchDictionaryEntries", "testName": "get searchDictionaryEntries results with all parameters", - "parameters": [ - { - "dictionaryName": "dictionaryName", - "searchDictionaryEntries": { - "query": "foo", - "page": 4, - "hitsPerPage": 2, - "language": "fr" - } + "parameters": { + "dictionaryName": "dictionaryName", + "searchDictionaryEntries": { + "query": "foo", + "page": 4, + "hitsPerPage": 2, + "language": "fr" } - ], + }, "request": { "path": "/1/dictionaries/dictionaryName/search", "method": "POST", diff --git a/tests/CTS/clients/search/searchForFacetValues.json b/tests/CTS/clients/search/searchForFacetValues.json index eb90bedcfd7..56d7627fc5b 100644 --- a/tests/CTS/clients/search/searchForFacetValues.json +++ b/tests/CTS/clients/search/searchForFacetValues.json @@ -2,7 +2,10 @@ { "method": "searchForFacetValues", "testName": "get searchForFacetValues results with minimal parameters", - "parameters": [{ "indexName": "indexName", "facetName": "facetName" }], + "parameters": { + "indexName": "indexName", + "facetName": "facetName" + }, "request": { "path": "/1/indexes/indexName/facets/facetName/query", "method": "POST" @@ -11,17 +14,15 @@ { "method": "searchForFacetValues", "testName": "get searchForFacetValues results with all parameters", - "parameters": [ - { - "indexName": "indexName", - "facetName": "facetName", - "searchForFacetValuesRequest": { - "params": "query=foo&facetFilters=['bar']", - "facetQuery": "foo", - "maxFacetHits": 42 - } + "parameters": { + "indexName": "indexName", + "facetName": "facetName", + "searchForFacetValuesRequest": { + "params": "query=foo&facetFilters=['bar']", + "facetQuery": "foo", + "maxFacetHits": 42 } - ], + }, "request": { "path": "/1/indexes/indexName/facets/facetName/query", "method": "POST", diff --git a/tests/CTS/clients/search/searchRules.json b/tests/CTS/clients/search/searchRules.json index 3d17c9cb4fb..8c9a181bcda 100644 --- a/tests/CTS/clients/search/searchRules.json +++ b/tests/CTS/clients/search/searchRules.json @@ -1,16 +1,18 @@ [ { "method": "searchRules", - "parameters": [ - { - "indexName": "indexName", - "searchRulesParams": { "query": "something" } + "parameters": { + "indexName": "indexName", + "searchRulesParams": { + "query": "something" } - ], + }, "request": { "path": "/1/indexes/indexName/rules/search", "method": "POST", - "data": { "query": "something" } + "data": { + "query": "something" + } } } ] diff --git a/tests/CTS/clients/search/searchSynonyms.json b/tests/CTS/clients/search/searchSynonyms.json index e35d13a5012..7784de2dc51 100644 --- a/tests/CTS/clients/search/searchSynonyms.json +++ b/tests/CTS/clients/search/searchSynonyms.json @@ -1,13 +1,11 @@ [ { "method": "searchSynonyms", - "parameters": [ - { - "indexName": "indexName", - "query": "queryString", - "type": "onewaysynonym" - } - ], + "parameters": { + "indexName": "indexName", + "query": "queryString", + "type": "onewaysynonym" + }, "request": { "path": "/1/indexes/indexName/synonyms/search", "method": "POST" diff --git a/tests/CTS/clients/search/setDictionarySettings.json b/tests/CTS/clients/search/setDictionarySettings.json index 7d06d8d590c..d438327a4b6 100644 --- a/tests/CTS/clients/search/setDictionarySettings.json +++ b/tests/CTS/clients/search/setDictionarySettings.json @@ -2,19 +2,17 @@ { "method": "setDictionarySettings", "testName": "get setDictionarySettings results with minimal parameters", - "parameters": [ - { - "dictionarySettingsRequest": { - "disableStandardEntries": { - "plurals": { - "fr": false, - "en": false, - "ru": true - } + "parameters": { + "dictionarySettingsRequest": { + "disableStandardEntries": { + "plurals": { + "fr": false, + "en": false, + "ru": true } } } - ], + }, "request": { "path": "/1/dictionaries/*/settings", "method": "PUT", @@ -32,25 +30,23 @@ { "method": "setDictionarySettings", "testName": "get setDictionarySettings results with all parameters", - "parameters": [ - { - "dictionarySettingsRequest": { - "disableStandardEntries": { - "plurals": { - "fr": false, - "en": false, - "ru": true - }, - "stopwords": { - "fr": false - }, - "compounds": { - "ru": true - } + "parameters": { + "dictionarySettingsRequest": { + "disableStandardEntries": { + "plurals": { + "fr": false, + "en": false, + "ru": true + }, + "stopwords": { + "fr": false + }, + "compounds": { + "ru": true } } } - ], + }, "request": { "path": "/1/dictionaries/*/settings", "method": "PUT", diff --git a/tests/CTS/clients/search/updateApiKey.json b/tests/CTS/clients/search/updateApiKey.json index cb5a654f6c4..f4d1a654867 100644 --- a/tests/CTS/clients/search/updateApiKey.json +++ b/tests/CTS/clients/search/updateApiKey.json @@ -1,22 +1,26 @@ [ { "method": "updateApiKey", - "parameters": [ - { - "key": "myApiKey", - "apiKey": { - "acl": ["search", "addObject"], - "validity": 300, - "maxQueriesPerIPPerHour": 100, - "maxHitsPerQuery": 20 - } + "parameters": { + "key": "myApiKey", + "apiKey": { + "acl": [ + "search", + "addObject" + ], + "validity": 300, + "maxQueriesPerIPPerHour": 100, + "maxHitsPerQuery": 20 } - ], + }, "request": { "path": "/1/keys/myApiKey", "method": "PUT", "data": { - "acl": ["search", "addObject"], + "acl": [ + "search", + "addObject" + ], "validity": 300, "maxQueriesPerIPPerHour": 100, "maxHitsPerQuery": 20 diff --git a/tests/CTS/templates/javascript.mustache b/tests/CTS/templates/javascript.mustache index f43c371470e..1274920d489 100644 --- a/tests/CTS/templates/javascript.mustache +++ b/tests/CTS/templates/javascript.mustache @@ -7,7 +7,7 @@ const client = new {{client}}(process.env.ALGOLIA_APPLICATION_ID, process.env.AL describe('{{operationId}}', () => { {{#tests}} test('{{testName}}', async () => { - const req = await client.{{method}}({{#parameters}}{{{value}}}{{^-last}}, {{/-last}}{{/parameters}}); + const req = await client.{{method}}({{{parameters}}}); expect(req).toMatchObject({ path: '{{{request.path}}}', method: '{{{request.method}}}', diff --git a/tests/generateCTS.ts b/tests/generateCTS.ts index 46c4949319c..8c945f37488 100644 --- a/tests/generateCTS.ts +++ b/tests/generateCTS.ts @@ -11,10 +11,12 @@ import openapitools from '../openapitools.json'; const availableLanguages = ['javascript'] as const; type Language = typeof availableLanguages[number]; +// This does not reflect the expected type of the CTS, it's rather the type passed to mustache type Tests = { testName?: string; method: string; - parameters: any[]; + parameters: any; + parametersArray: any; request: { path: string; method: string; @@ -70,6 +72,17 @@ function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } +function removeObjectName(obj: Record): void { + for (const prop in obj) { + if (prop === '$objectName') { + // eslint-disable-next-line no-param-reassign + delete obj[prop]; + } else if (typeof obj[prop] === 'object') { + removeObjectName(obj[prop]); + } + } +} + async function loadCTSForClient(client: string): Promise { // load the list of operations from the spec const spec = await SwaggerParser.validate(`../specs/${client}/spec.yml`); @@ -105,18 +118,26 @@ async function loadCTSForClient(client: string): Promise { if (test.testName === undefined) { test.testName = test.method; } + if ( + typeof test.parameters !== 'object' || + Array.isArray(test.parameters) + ) { + throw new Error(`parameters of ${test.testName} must be an object`); + } - // for now we stringify all params for mustache to render them properly - for (let i = 0; i < test.parameters.length; i++) { - // delete the object name for now, but it could be use for `new $objectName(params)` - delete test.parameters[i].$objectName; + // we stringify the param for mustache to render them properly + // delete the object name recursively for now, but it could be use for `new $objectName(params)` + removeObjectName(test.parameters); - // include the `-last` param to join with comma in mustache - test.parameters[i] = { - value: JSON.stringify(test.parameters[i]), - '-last': i === test.parameters.length - 1, - }; - } + test.parameters = JSON.stringify(test.parameters); + + // include the `-last` param to join with comma in mustache + test.parametersArray = Object.values(test.parameters).map( + (val, i, arr) => ({ + value: JSON.stringify(val), + '-last': i === arr.length - 1, + }) + ); // stringify request.data too test.request.data = JSON.stringify(test.request.data); @@ -128,7 +149,9 @@ async function loadCTSForClient(client: string): Promise { }); } - return ctsClient; + return ctsClient.sort((t1, t2) => + t1.operationId.localeCompare(t2.operationId) + ); } async function loadCTS(): Promise { diff --git a/tests/output/javascript/search.test.ts b/tests/output/javascript/search.test.ts index 31af67f3155..ae7cf0befef 100644 --- a/tests/output/javascript/search.test.ts +++ b/tests/output/javascript/search.test.ts @@ -251,7 +251,7 @@ describe('getApiKey', () => { describe('getDictionaryLanguages', () => { test('get getDictionaryLanguages', async () => { - const req = await client.getDictionaryLanguages(); + const req = await client.getDictionaryLanguages({}); expect(req).toMatchObject({ path: '/1/dictionaries/*/languages', method: 'GET', @@ -261,7 +261,7 @@ describe('getDictionaryLanguages', () => { describe('getDictionarySettings', () => { test('get getDictionarySettings results', async () => { - const req = await client.getDictionarySettings(); + const req = await client.getDictionarySettings({}); expect(req).toMatchObject({ path: '/1/dictionaries/*/settings', method: 'GET', @@ -297,7 +297,7 @@ describe('getSynonym', () => { describe('listApiKeys', () => { test('listApiKeys', async () => { - const req = await client.listApiKeys(); + const req = await client.listApiKeys({}); expect(req).toMatchObject({ path: '/1/keys', method: 'GET', @@ -407,7 +407,7 @@ describe('search', () => { test('search', async () => { const req = await client.search({ indexName: 'indexName', - searchParams: { $objectName: 'Query', query: 'queryString' }, + searchParams: { query: 'queryString' }, }); expect(req).toMatchObject({ path: '/1/indexes/indexName/query',