api-tuner 0.5.5 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -188,6 +188,19 @@ Query parameters can be added to a request using `tuner:query`.
188
188
  ?req tuner:query ( "name" "value" ) .
189
189
  ```
190
190
 
191
+ #### Shell Variables
192
+
193
+ Values used in request URL, headers and query params are resolved from the shell environment.
194
+
195
+ ```turtle
196
+ <#test> tuner:request [
197
+ a tuner:Request ;
198
+ tuner:url <http://example.com/api/$PATH> ;
199
+ tuner:header ( "X-Api-Key" "$API_KEY" ) ;
200
+ tuner:query ( "q" "$QUERY" ) ;
201
+ ] .
202
+ ```
203
+
191
204
  ### Assertions
192
205
 
193
206
  Assertions are performed on the `tuner:Response` object (usually captured in a variable like `?res`).
@@ -226,18 +239,15 @@ Assert the presence and value of an HTTP header. Header names are case-insensiti
226
239
  ```
227
240
  ⚠️ Be careful when using `?res!log:includes` resource path shorthand which will not work inside `tuner:formula`. Please refer to [this discussion](https://github.com/eyereasoner/eye/issues/148#issuecomment-2810940959).
228
241
 
229
- <<<<<<< json-assertions
230
242
  - **JSON Path**: If the response is JSON, you can use `tuner:jsonPath` to assert values within the body.
231
243
  ```turtle
232
- ?res tuner:body ?body .
233
244
  # Exact match
234
- ?body tuner:jsonPath ( "$.foo" "bar" ) .
245
+ ?res tuner:jsonPath ( "$.foo" "bar" ) .
235
246
  # Custom assertion (e.g. regex, contains, math)
236
- ?body tuner:jsonPath ( "$.baz" "42" string:contains ) .
247
+ ?res tuner:jsonPath ( "$.baz" "42" string:contains ) .
237
248
  ```
249
+ ⚠️ Note that unlike RDF assersion, JSON Path assertions are used on the response itself, without using `tuner:body`.
238
250
 
239
- =======
240
- >>>>>>> master
241
251
  #### Generic Assertions
242
252
 
243
253
  Use `tuner:assertThat` to fail a test with a custom message if a condition is not met.
@@ -1,11 +1,26 @@
1
1
  #! /usr/bin/env node
2
2
  /* eslint-disable no-console */
3
3
  import fs from 'node:fs'
4
+ import { spawnSync } from 'node:child_process'
4
5
  import { Readable } from 'node:stream'
5
6
  import * as tar from 'tar'
6
7
 
7
8
  async function main() {
8
9
  const EYE_VERSION = process.env.EYE_VERSION
10
+
11
+ if (fs.existsSync('eye')) {
12
+ try {
13
+ const versionOutput = spawnSync('eye/bin/eye', ['--version'], { encoding: 'utf-8' })
14
+ if (versionOutput.stderr.includes(EYE_VERSION)) {
15
+ console.log(`EYE v${EYE_VERSION} already installed`)
16
+ return
17
+ }
18
+ } catch (e) {
19
+ console.warn(`Failed to check EYE version: ${e.message}`)
20
+ console.warn('Re-downloading...')
21
+ }
22
+ }
23
+
9
24
  const url = `https://github.com/eyereasoner/eye/archive/refs/tags/v${EYE_VERSION}.tar.gz`
10
25
 
11
26
  // Download and extract tarball directly from stream
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-tuner",
3
- "version": "0.5.5",
3
+ "version": "0.6.1",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -8,12 +8,12 @@
8
8
  "api-tuner": "bin/tuner.sh"
9
9
  },
10
10
  "scripts": {
11
- "download-eye": "EYE_VERSION=11.16.4 ./lib/download-eye.js",
12
- "postinstall": "([ -d eye ] || npm run download-eye) && eye/install.sh --prefix=eye",
11
+ "download-eye": "EYE_VERSION=11.24.3 ./lib/download-eye.js",
12
+ "postinstall": "npm run download-eye && eye/install.sh --prefix=eye",
13
13
  "prepare": "husky",
14
14
  "lint": "eslint . --quiet --ignore-path .gitignore",
15
- "pre_test": "docker compose up -d && docker compose restart && npx wait-on http-get://localhost:1080/ping -t 10s",
16
- "_test": "./bin/tuner.sh --base-iri http://localhost:1080/",
15
+ "pre_test": "docker compose up -d && docker compose restart && npx wait-on http-get://localhost:1080/ping -t 20s",
16
+ "_test": "export FOO=BAR; ./bin/tuner.sh --base-iri http://localhost:1080/",
17
17
  "test": "npm run _test -- tests/*.n3 tests/**/*.n3",
18
18
  "prepack": "tsc",
19
19
  "release": "changeset publish"
@@ -1,8 +1,10 @@
1
+ PREFIX math: <http://www.w3.org/2000/10/swap/math#>
1
2
  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
2
3
  PREFIX list: <http://www.w3.org/2000/10/swap/list#>
3
4
  PREFIX tuner: <https://api-tuner.described.at/>
4
5
  prefix string: <http://www.w3.org/2000/10/swap/string#>
5
6
  prefix log: <http://www.w3.org/2000/10/swap/log#>
7
+ prefix file: <http://www.w3.org/2000/10/swap/file#>
6
8
 
7
9
  {
8
10
  ?expr tuner:assertThat ?msg .
@@ -74,22 +76,27 @@ prefix log: <http://www.w3.org/2000/10/swap/log#>
74
76
  } .
75
77
 
76
78
  {
77
- ?body tuner:jsonPath ( ?path ?expected ) .
79
+ ?res tuner:jsonPath ( ?path ?expected ) .
78
80
  } <= {
79
- ?body tuner:jsonPath ( ?path ?expected log:equalTo ) .
81
+ ?res tuner:jsonPath ( ?path ?expected log:equalTo ) .
80
82
  } .
81
83
 
82
84
  {
83
- ?body tuner:jsonPath ( ?path ?expected ?builtIn ) .
85
+ ?res tuner:jsonPath ( ?path ?expected ?builtIn ) .
84
86
  } <= {
85
- ?body log:rawType log:Literal .
86
- ( "echo " ?body " | bin/jsonpath.sh '" ?path "' " )!string:concatenation log:shell ?actualRaw .
87
+ ?res log:includes {
88
+ [] a tuner:Response ; tuner:body ?bodyPath .
89
+ } .
90
+ ( "cat " ?bodyPath " | " "bin/jsonpath.sh"!file:libPath " '" ?path "' " )!string:concatenation log:shell ?actualRaw .
87
91
 
88
92
  # remove surrounding quotes added by the shell
89
93
  ( ( ?actualRaw '^\"' "")!string:replace '\"$' "") string:replace ?actual .
90
94
 
95
+ ( ?actual ?builtIn ) math:normaliseLiteral ?actualNormalised .
96
+ ( ?expected ?builtIn ) math:normaliseLiteral ?expectedNormalised .
97
+
91
98
  (
92
- { ?actual ?builtIn ?expected }
99
+ { ?actualNormalised ?builtIn ?expectedNormalised }
93
100
  true
94
101
  {
95
102
  ("Expected JSON path '" ?path "' to satisfy '" ?builtIn " " ?expected "' but got '" ?actual "'")!string:concatenation^tuner:info .
@@ -117,8 +124,11 @@ prefix log: <http://www.w3.org/2000/10/swap/log#>
117
124
  ] .
118
125
  } .
119
126
 
127
+ ( ?actualValue ?builtIn ) math:normaliseLiteral ?actualNormalised .
128
+ ( ?value ?builtIn ) math:normaliseLiteral ?expectedNormalised .
129
+
120
130
  (
121
- { ?actualValue ?builtIn ?value }
131
+ { ?actualNormalised ?builtIn ?expectedNormalised }
122
132
  true
123
133
  {
124
134
  ("Expected header '" ?name "' '" ?value "' to satisfy '" ?builtIn "' but got '" ?actualValue "'")!string:concatenation^tuner:info .
@@ -34,8 +34,14 @@ prefix math: <http://www.w3.org/2000/10/swap/math#>
34
34
  ?literalBody </#body> ( ?curlArgs [] ) .
35
35
  } <= {
36
36
  ?literalBody log:rawType log:Literal .
37
+ () file:temp ?requestBodyFile .
38
+
39
+ # Save body to file so that it can be used in the curl command reliably
40
+ (
41
+ "echo '" ?literalBody "' > " ?requestBodyFile
42
+ )!string:concatenation!e:exec .
37
43
 
38
- ( " -d '" ?literalBody "'" ) string:concatenation ?curlArgs .
44
+ ( " --data-binary @" ?requestBodyFile ) string:concatenation ?curlArgs .
39
45
  } .
40
46
 
41
47
  {
package/rules/files.n3 CHANGED
@@ -15,7 +15,7 @@ prefix file: <http://www.w3.org/2000/10/swap/file#>
15
15
  } <= {
16
16
  ?uri log:uri ( "urn:rand:" ( 1000 )!e:random )!string:concatenation .
17
17
  # log:shell captures the traling newline
18
- ( "mktemp -t api-tuner -d 2>/dev/null || mktemp -d -t api-tuner.XXXXXXXX"!log:shell "\n" "" ) string:replace ?tempDir .
18
+ ( "mktemp -t api-tuner -d 2>/dev/null || mktemp -d -t api-tuner.XXXXXXXX"!log:shell ("\n") ("") ) string:replaceAll ?tempDir .
19
19
 
20
20
  (
21
21
  ?tempDir
package/rules/headers.n3 CHANGED
@@ -4,5 +4,5 @@ prefix string: <http://www.w3.org/2000/10/swap/string#>
4
4
  {
5
5
  (?fieldName ?fieldValue) tuner:headerArg ?curlArg .
6
6
  } <= {
7
- ( " -H '" ?fieldName ":" ?fieldValue "'" ) string:concatenation ?curlArg .
7
+ ( ' -H "' ?fieldName ":" ?fieldValue '"' ) string:concatenation ?curlArg .
8
8
  } .
package/rules/math.n3 ADDED
@@ -0,0 +1,19 @@
1
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
2
+ PREFIX log: <http://www.w3.org/2000/10/swap/log#>
3
+ prefix math: <http://www.w3.org/2000/10/swap/math#>
4
+ prefix string: <http://www.w3.org/2000/10/swap/string#>
5
+
6
+ # See https://github.com/eyereasoner/eye/issues/174#issuecomment-4405018796
7
+ {
8
+ ( ?value ?builtIn ) math:normaliseLiteral ?normalised
9
+ } <= {
10
+ (
11
+ {
12
+ ?builtIn!log:uri string:startsWith math:!log:uri
13
+ }
14
+ {
15
+ ( ?value xsd:decimal ) log:dtlit ?normalised
16
+ }
17
+ { ?value log:equalTo ?normalised }
18
+ ) log:ifThenElseIn ?SCOPE
19
+ } .
@@ -4,5 +4,5 @@ prefix string: <http://www.w3.org/2000/10/swap/string#>
4
4
  {
5
5
  (?name ?value) tuner:queryParamArg ?curlArg .
6
6
  } <= {
7
- ( " --url-query '" ?name "=" ?value "'" ) string:concatenation ?curlArg .
7
+ ( ' --url-query "' ?name "=" ?value '"' ) string:concatenation ?curlArg .
8
8
  } .
package/rules/requests.n3 CHANGED
@@ -55,7 +55,7 @@ prefix earl: <http://www.w3.org/ns/earl#>
55
55
  ) log:ifThenElseIn [] .
56
56
 
57
57
  (
58
- "curl -s -X " ?method " '" ?endpoint "'"
58
+ "curl -s -X " ?method ' "' ?endpoint '"'
59
59
  ?headersArgs
60
60
  ?bodyArgs
61
61
  ?queryParamArgs