doc-detective-common 1.21.0-openapi.9 → 1.21.1-dev.0

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.
@@ -1,159 +1,199 @@
1
- {
2
- "title": "test",
3
- "type": "object",
4
- "description": "A Doc Detective test.",
5
- "properties": {
6
- "id": {
7
- "type": "string",
8
- "description": "Unique identifier for the test."
9
- },
10
- "description": {
11
- "type": "string",
12
- "description": "Description of the test."
13
- },
14
- "file": {
15
- "type": "string",
16
- "description": "Path to the file that the test is associated with."
17
- },
18
- "detectSteps": {
19
- "type": "boolean",
20
- "description": "Whether or not to detect steps in input files based on markup regex. Defaults to `true`."
21
- },
22
- "contexts": {
23
- "type": "array",
24
- "description": "Application/platform sets to run the test in. Overrides `contexts` defined at the config-level and spec-level.",
25
- "items": {
26
- "oneOf": [
27
- {
28
- "$ref": "context_v2.schema.json#"
29
- }
30
- ]
31
- }
32
- },
33
- "setup": {
34
- "type": "string",
35
- "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec."
36
- },
37
- "cleanup": {
38
- "type": "string",
39
- "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec."
40
- },
41
- "steps": {
42
- "description": "Actions to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails.",
43
- "type": "array",
44
- "minItems": 1,
45
- "items": {
46
- "anyOf": [
47
- { "$ref": "checkLink_v2.schema.json#" },
48
- { "$ref": "goTo_v2.schema.json#" },
49
- { "$ref": "httpRequest_v2.schema.json#" },
50
- { "$ref": "runShell_v2.schema.json#" },
51
- { "$ref": "saveScreenshot_v2.schema.json#" },
52
- { "$ref": "setVariables_v2.schema.json#" },
53
- { "$ref": "startRecording_v2.schema.json#" },
54
- { "$ref": "stopRecording_v2.schema.json#" },
55
- { "$ref": "typeKeys_v2.schema.json#" },
56
- { "$ref": "find_v2.schema.json#" },
57
- { "$ref": "wait_v2.schema.json#" }
58
- ]
59
- }
60
- }
61
- },
62
- "dynamicDefaults": {
63
- "id": "uuid"
64
- },
65
- "required": ["steps"],
66
- "additionalProperties": false,
67
- "examples": [
68
- {
69
- "steps": [
70
- {
71
- "action": "checkLink",
72
- "url": "https://www.duckduckgo.com"
73
- }
74
- ]
75
- },
76
- {
77
- "steps": [
78
- {
79
- "action": "goTo",
80
- "url": "https://www.duckduckgo.com"
81
- },
82
- {
83
- "action": "find",
84
- "selector": "[title=Search]",
85
- "click": true,
86
- "typeKeys": {
87
- "keys": ["shorthair cats", "$ENTER$"]
88
- }
89
- }
90
- ]
91
- },
92
- {
93
- "id": "Do all the things! - Test",
94
- "description": "This test includes every property across all actions.",
95
- "contexts": [
96
- {
97
- "app": {
98
- "name": "firefox",
99
- "path": "/usr/bin/firefox"
100
- },
101
- "platforms": ["linux"]
102
- }
103
- ],
104
- "setup": "setup.json",
105
- "cleanup": "cleanup.json",
106
- "steps": [
107
- {
108
- "action": "setVariables",
109
- "path": ".env"
110
- },
111
- {
112
- "action": "runShell",
113
- "command": "echo",
114
- "args": ["$USER"]
115
- },
116
- {
117
- "action": "checkLink",
118
- "url": "https://www.duckduckgo.com"
119
- },
120
- {
121
- "action": "httpRequest",
122
- "url": "https://reqres.in/api/users",
123
- "method": "post",
124
- "requestData": {
125
- "name": "morpheus",
126
- "job": "leader"
127
- },
128
- "responseData": {
129
- "name": "morpheus",
130
- "job": "leader"
131
- },
132
- "statusCodes": [200, 201]
133
- },
134
- {
135
- "action": "goTo",
136
- "url": "https://www.duckduckgo.com"
137
- },
138
- {
139
- "action": "find",
140
- "selector": "[title=Search]",
141
- "timeout": 10000,
142
- "matchText": "Search",
143
- "moveTo": true,
144
- "click": true,
145
- "typeKeys": {
146
- "keys": ["shorthair cat"]
147
- }
148
- },
149
- {
150
- "action": "typeKeys",
151
- "keys": ["$ENTER$"]
152
- },
153
- {
154
- "action": "saveScreenshot"
155
- }
156
- ]
157
- }
158
- ]
159
- }
1
+ {
2
+ "title": "test",
3
+ "type": "object",
4
+ "description": "A Doc Detective test.",
5
+ "properties": {
6
+ "id": {
7
+ "type": "string",
8
+ "description": "Unique identifier for the test."
9
+ },
10
+ "description": {
11
+ "type": "string",
12
+ "description": "Description of the test."
13
+ },
14
+ "file": {
15
+ "type": "string",
16
+ "description": "Path to the file that the test is associated with."
17
+ },
18
+ "detectSteps": {
19
+ "type": "boolean",
20
+ "description": "Whether or not to detect steps in input files based on markup regex. Defaults to `true`."
21
+ },
22
+ "contexts": {
23
+ "type": "array",
24
+ "description": "Application/platform sets to run the test in. Overrides `contexts` defined at the config-level and spec-level.",
25
+ "items": {
26
+ "oneOf": [
27
+ {
28
+ "$ref": "context_v2.schema.json#"
29
+ }
30
+ ]
31
+ }
32
+ },
33
+ "openApi": {
34
+ "type": "array",
35
+ "items": {
36
+ "allOf": [
37
+ {
38
+ "$ref": "openApi_v2.schema.json#"
39
+ },
40
+ {
41
+ "type": "object",
42
+ "properties": {
43
+ "operationId": {
44
+ "type": "null",
45
+ "$commment": "Only allow operationId at the step level."
46
+ }
47
+ },
48
+ "required": ["name", "descriptionPath"]
49
+ }
50
+ ]
51
+ }
52
+ },
53
+ "setup": {
54
+ "type": "string",
55
+ "description": "Path to a test specification to perform before this test, while maintaining this test's context. Useful for setting up testing environments. Only the `steps` property is used from the first test in the setup spec."
56
+ },
57
+ "cleanup": {
58
+ "type": "string",
59
+ "description": "Path to a test specification to perform after this test, while maintaining this test's context. Useful for cleaning up testing environments. Only the `steps` property is used from the first test in the cleanup spec."
60
+ },
61
+ "steps": {
62
+ "description": "Actions to perform as part of the test. Performed in the sequence defined. If one or more actions fail, the test fails.",
63
+ "type": "array",
64
+ "minItems": 1,
65
+ "items": {
66
+ "anyOf": [
67
+ { "$ref": "checkLink_v2.schema.json#" },
68
+ { "$ref": "goTo_v2.schema.json#" },
69
+ { "$ref": "httpRequest_v2.schema.json#" },
70
+ { "$ref": "runShell_v2.schema.json#" },
71
+ { "$ref": "saveScreenshot_v2.schema.json#" },
72
+ { "$ref": "setVariables_v2.schema.json#" },
73
+ { "$ref": "startRecording_v2.schema.json#" },
74
+ { "$ref": "stopRecording_v2.schema.json#" },
75
+ { "$ref": "typeKeys_v2.schema.json#" },
76
+ { "$ref": "find_v2.schema.json#" },
77
+ { "$ref": "wait_v2.schema.json#" }
78
+ ]
79
+ }
80
+ }
81
+ },
82
+ "dynamicDefaults": {
83
+ "id": "uuid"
84
+ },
85
+ "required": ["steps"],
86
+ "additionalProperties": false,
87
+ "examples": [
88
+ {
89
+ "steps": [
90
+ {
91
+ "action": "checkLink",
92
+ "url": "https://www.duckduckgo.com"
93
+ }
94
+ ]
95
+ },
96
+ {
97
+ "steps": [
98
+ {
99
+ "action": "goTo",
100
+ "url": "https://www.duckduckgo.com"
101
+ },
102
+ {
103
+ "action": "find",
104
+ "selector": "[title=Search]",
105
+ "click": true,
106
+ "typeKeys": {
107
+ "keys": ["shorthair cats", "$ENTER$"]
108
+ }
109
+ }
110
+ ]
111
+ },
112
+ {
113
+ "id": "Do all the things! - Test",
114
+ "description": "This test includes every property across all actions.",
115
+ "contexts": [
116
+ {
117
+ "app": {
118
+ "name": "firefox",
119
+ "path": "/usr/bin/firefox"
120
+ },
121
+ "platforms": ["linux"]
122
+ }
123
+ ],
124
+ "setup": "setup.json",
125
+ "cleanup": "cleanup.json",
126
+ "steps": [
127
+ {
128
+ "action": "setVariables",
129
+ "path": ".env"
130
+ },
131
+ {
132
+ "action": "runShell",
133
+ "command": "echo",
134
+ "args": ["$USER"]
135
+ },
136
+ {
137
+ "action": "checkLink",
138
+ "url": "https://www.duckduckgo.com"
139
+ },
140
+ {
141
+ "action": "httpRequest",
142
+ "url": "https://reqres.in/api/users",
143
+ "method": "post",
144
+ "requestData": {
145
+ "name": "morpheus",
146
+ "job": "leader"
147
+ },
148
+ "responseData": {
149
+ "name": "morpheus",
150
+ "job": "leader"
151
+ },
152
+ "statusCodes": [200, 201]
153
+ },
154
+ {
155
+ "action": "goTo",
156
+ "url": "https://www.duckduckgo.com"
157
+ },
158
+ {
159
+ "action": "find",
160
+ "selector": "[title=Search]",
161
+ "timeout": 10000,
162
+ "matchText": "Search",
163
+ "moveTo": true,
164
+ "click": true,
165
+ "typeKeys": {
166
+ "keys": ["shorthair cat"]
167
+ }
168
+ },
169
+ {
170
+ "action": "typeKeys",
171
+ "keys": ["$ENTER$"]
172
+ },
173
+ {
174
+ "action": "saveScreenshot"
175
+ }
176
+ ]
177
+ },
178
+ {
179
+ "openApi": [
180
+ {
181
+ "name": "Acme",
182
+ "descriptionPath": "https://www.acme.com/openapi.json",
183
+ "server": "https://api.acme.com"
184
+ }
185
+ ],
186
+ "steps": [
187
+ {
188
+ "action": "httpRequest",
189
+ "openApi": {
190
+ "operationId": "getUserById"
191
+ },
192
+ "requestParams": {
193
+ "id": 123
194
+ }
195
+ }
196
+ ]
197
+ }
198
+ ]
199
+ }
@@ -1,63 +1,63 @@
1
- {
2
- "title": "typeKeys",
3
- "type": "object",
4
- "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`.",
5
- "properties": {
6
- "id": {
7
- "type": "string",
8
- "description": "ID of the step."
9
- },
10
- "description": {
11
- "type": "string",
12
- "description": "Description of the step."
13
- },
14
- "action": {
15
- "type": "string",
16
- "const": "typeKeys",
17
- "description": "The action to perform."
18
- },
19
- "keys": {
20
- "description": "String of keys to enter.",
21
- "anyOf": [
22
- {
23
- "type": "string"
24
- },
25
- {
26
- "type": "array",
27
- "items": {
28
- "oneOf": [
29
- {
30
- "type": "string"
31
- }
32
- ]
33
- }
34
- }
35
- ]
36
- },
37
- "delay": {
38
- "type": "number",
39
- "description": "Delay in milliseconds between each key press. Only valid during a recording.",
40
- "default": 100
41
- }
42
- },
43
- "dynamicDefaults": {
44
- "id": "uuid"
45
- },
46
- "required": ["action", "keys"],
47
- "additionalProperties": false,
48
- "examples": [
49
- {
50
- "action": "typeKeys",
51
- "keys": "kittens"
52
- },
53
- {
54
- "action": "typeKeys",
55
- "keys": ["$ENTER$"]
56
- },
57
- {
58
- "action": "typeKeys",
59
- "keys": ["kittens","$ENTER$"],
60
- "delay": 500
61
- }
62
- ]
63
- }
1
+ {
2
+ "title": "typeKeys",
3
+ "type": "object",
4
+ "description": "Type keys. To type special keys, begin and end the string with `$` and use the special key's enum. For example, to type the Escape key, enter `$ESCAPE$`.",
5
+ "properties": {
6
+ "id": {
7
+ "type": "string",
8
+ "description": "ID of the step."
9
+ },
10
+ "description": {
11
+ "type": "string",
12
+ "description": "Description of the step."
13
+ },
14
+ "action": {
15
+ "type": "string",
16
+ "const": "typeKeys",
17
+ "description": "The action to perform."
18
+ },
19
+ "keys": {
20
+ "description": "String of keys to enter.",
21
+ "anyOf": [
22
+ {
23
+ "type": "string"
24
+ },
25
+ {
26
+ "type": "array",
27
+ "items": {
28
+ "oneOf": [
29
+ {
30
+ "type": "string"
31
+ }
32
+ ]
33
+ }
34
+ }
35
+ ]
36
+ },
37
+ "delay": {
38
+ "type": "number",
39
+ "description": "Delay in milliseconds between each key press. Only valid during a recording.",
40
+ "default": 100
41
+ }
42
+ },
43
+ "dynamicDefaults": {
44
+ "id": "uuid"
45
+ },
46
+ "required": ["action", "keys"],
47
+ "additionalProperties": false,
48
+ "examples": [
49
+ {
50
+ "action": "typeKeys",
51
+ "keys": "kittens"
52
+ },
53
+ {
54
+ "action": "typeKeys",
55
+ "keys": ["$ENTER$"]
56
+ },
57
+ {
58
+ "action": "typeKeys",
59
+ "keys": ["kittens","$ENTER$"],
60
+ "delay": 500
61
+ }
62
+ ]
63
+ }
@@ -0,0 +1,107 @@
1
+ const sinon = require("sinon");
2
+ const axios = require("axios");
3
+ const fs = require("fs");
4
+ const { readFile } = require("../src/files");
5
+
6
+ (async () => {
7
+ const { expect } = await import("chai");
8
+
9
+ describe("readFile", function () {
10
+ let axiosGetStub;
11
+ let fsReadFileStub;
12
+
13
+ beforeEach(function () {
14
+ axiosGetStub = sinon.stub(axios, "get");
15
+ fsReadFileStub = sinon.stub(fs.promises, "readFile");
16
+ });
17
+
18
+ afterEach(function () {
19
+ sinon.restore();
20
+ });
21
+
22
+ it("should read a remote JSON file", async function () {
23
+ const fileURL = "http://example.com/file.json";
24
+ const fileContent = '{"key": "value"}';
25
+ axiosGetStub.resolves({ data: fileContent });
26
+
27
+ const result = await readFile(fileURL);
28
+
29
+ expect(result).to.deep.equal({ key: "value" });
30
+ expect(axiosGetStub.calledOnceWith(fileURL)).to.be.true;
31
+ });
32
+
33
+ it("should read a remote YAML file", async function () {
34
+ const fileURL = "http://example.com/file.yaml";
35
+ const fileContent = "key: value";
36
+ axiosGetStub.resolves({ data: fileContent });
37
+
38
+ const result = await readFile(fileURL);
39
+
40
+ expect(result).to.deep.equal({ key: "value" });
41
+ expect(axiosGetStub.calledOnceWith(fileURL)).to.be.true;
42
+ });
43
+
44
+ it("should read a local JSON file", async function () {
45
+ const filePath = "/path/to/file.json";
46
+ const fileContent = '{"key": "value"}';
47
+ fsReadFileStub.resolves(fileContent);
48
+
49
+ const result = await readFile(filePath);
50
+
51
+ expect(result).to.deep.equal({ key: "value" });
52
+ expect(fsReadFileStub.calledOnceWith(filePath, "utf8")).to.be.true;
53
+ });
54
+
55
+ it("should read a local YAML file", async function () {
56
+ const filePath = "/path/to/file.yaml";
57
+ const fileContent = "key: value";
58
+ fsReadFileStub.resolves(fileContent);
59
+
60
+ const result = await readFile(filePath);
61
+
62
+ expect(result).to.deep.equal({ key: "value" });
63
+ expect(fsReadFileStub.calledOnceWith(filePath, "utf8")).to.be.true;
64
+ });
65
+
66
+ it("should return raw content for non-JSON/YAML files", async function () {
67
+ const filePath = "/path/to/file.txt";
68
+ const fileContent = "plain text content";
69
+ fsReadFileStub.resolves(fileContent);
70
+
71
+ const result = await readFile(filePath);
72
+
73
+ expect(result).to.equal(fileContent);
74
+ expect(fsReadFileStub.calledOnceWith(filePath, "utf8")).to.be.true;
75
+ });
76
+
77
+ it("should return null if remote file cannot be read", async function () {
78
+ const fileURL = "http://example.com/file.json";
79
+ axiosGetStub.rejects(new Error("Network error"));
80
+
81
+ const result = await readFile(fileURL);
82
+
83
+ expect(result).to.be.null;
84
+ expect(axiosGetStub.calledOnceWith(fileURL)).to.be.true;
85
+ });
86
+
87
+ it("should return null if local file cannot be found", async function () {
88
+ const filePath = "/path/to/nonexistent.json";
89
+ fsReadFileStub.rejects({ code: "ENOENT" });
90
+
91
+ const result = await readFile(filePath);
92
+
93
+ expect(result).to.be.null;
94
+ expect(fsReadFileStub.calledOnceWith(filePath, "utf8")).to.be.true;
95
+ });
96
+
97
+ it("should return null if local file read error occurs", async function () {
98
+ const filePath = "/path/to/file.json";
99
+ fsReadFileStub.rejects(new Error("Read error"));
100
+
101
+ const result = await readFile(filePath);
102
+
103
+ expect(result).to.be.null;
104
+ expect(fsReadFileStub.calledOnceWith(filePath, "utf8")).to.be.true;
105
+ });
106
+ });
107
+ })();
@@ -1,21 +1,31 @@
1
1
  const { validate, schemas } = require("../src/index");
2
+ const assert = require("assert");
2
3
 
3
4
  // Loop through JSON schemas
4
5
  for (const [key, value] of Object.entries(schemas)) {
5
- test(`${key} schema has one or more examples`, () => {
6
- // Schema needs one or more examples
7
- expect(value.examples).toBeTruthy();
8
- expect(value.examples.length).toBeGreaterThanOrEqual(1);
9
- });
10
- // Loop through and validate schema examples
11
- value.examples.forEach((example, index) => {
12
- test(`${key} example with index ${index} passes validation`, () => {
13
- const validityCheck = validate(key, example);
14
- if (validityCheck.errors != "") {
15
- console.log(key);
16
- console.log(validityCheck.errors);
17
- }
18
- expect(validityCheck.valid).toBe(true);
6
+ describe(`${key} schema`, function () {
7
+ it("should have one or more examples", function () {
8
+ // Schema needs one or more examples
9
+ assert(value.examples);
10
+ assert(value.examples.length >= 1);
11
+ });
12
+
13
+ // Loop through and validate schema examples
14
+ value.examples.forEach((example, index) => {
15
+ it(`example with index ${index} passes validation`, function () {
16
+ try {
17
+ const validityCheck = validate(key, example);
18
+ assert.ok(
19
+ validityCheck.valid,
20
+ true,
21
+ `Validation failed for ${key}, example ${index}: ${validityCheck.errors}`
22
+ );
23
+ } catch (error) {
24
+ assert.fail(
25
+ `Unexpected error during validation of ${key}, example ${index}: ${error.message}`
26
+ );
27
+ }
28
+ });
19
29
  });
20
30
  });
21
31
  }