@api-client/core 0.3.5 → 0.3.6

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.
Files changed (68) hide show
  1. package/build/browser.d.ts +2 -0
  2. package/build/browser.js +8 -0
  3. package/build/browser.js.map +1 -1
  4. package/build/index.d.ts +10 -1
  5. package/build/index.js +19 -1
  6. package/build/index.js.map +1 -1
  7. package/build/src/lib/fs/Fs.d.ts +52 -0
  8. package/build/src/lib/fs/Fs.js +245 -0
  9. package/build/src/lib/fs/Fs.js.map +1 -0
  10. package/build/src/lib/timers/Timers.d.ts +5 -0
  11. package/build/src/lib/timers/Timers.js +10 -0
  12. package/build/src/lib/timers/Timers.js.map +1 -0
  13. package/build/src/mocking/ProjectMock.d.ts +13 -0
  14. package/build/src/mocking/ProjectMock.js +16 -0
  15. package/build/src/mocking/ProjectMock.js.map +1 -0
  16. package/build/src/mocking/lib/Request.d.ts +32 -0
  17. package/build/src/mocking/lib/Request.js +63 -0
  18. package/build/src/mocking/lib/Request.js.map +1 -0
  19. package/build/src/mocking/lib/Response.d.ts +33 -0
  20. package/build/src/mocking/lib/Response.js +79 -0
  21. package/build/src/mocking/lib/Response.js.map +1 -0
  22. package/build/src/runtime/node/BaseRunner.d.ts +21 -0
  23. package/build/src/runtime/node/BaseRunner.js +27 -0
  24. package/build/src/runtime/node/BaseRunner.js.map +1 -0
  25. package/build/src/runtime/node/ProjectParallelRunner.d.ts +81 -0
  26. package/build/src/runtime/node/ProjectParallelRunner.js +173 -0
  27. package/build/src/runtime/node/ProjectParallelRunner.js.map +1 -0
  28. package/build/src/runtime/node/ProjectRequestRunner.d.ts +125 -0
  29. package/build/src/runtime/node/ProjectRequestRunner.js +185 -0
  30. package/build/src/runtime/node/ProjectRequestRunner.js.map +1 -0
  31. package/build/src/runtime/node/ProjectRunner.d.ts +164 -62
  32. package/build/src/runtime/node/ProjectRunner.js +191 -146
  33. package/build/src/runtime/node/ProjectRunner.js.map +1 -1
  34. package/build/src/runtime/node/ProjectRunnerWorker.d.ts +1 -0
  35. package/build/src/runtime/node/ProjectRunnerWorker.js +58 -0
  36. package/build/src/runtime/node/ProjectRunnerWorker.js.map +1 -0
  37. package/build/src/runtime/node/ProjectSerialRunner.d.ts +11 -0
  38. package/build/src/runtime/node/ProjectSerialRunner.js +34 -0
  39. package/build/src/runtime/node/ProjectSerialRunner.js.map +1 -0
  40. package/build/src/runtime/reporters/ProjectRunCliReporter.d.ts +7 -0
  41. package/build/src/runtime/reporters/ProjectRunCliReporter.js +73 -0
  42. package/build/src/runtime/reporters/ProjectRunCliReporter.js.map +1 -0
  43. package/build/src/runtime/reporters/Reporter.d.ts +62 -0
  44. package/build/src/runtime/reporters/Reporter.js +98 -0
  45. package/build/src/runtime/reporters/Reporter.js.map +1 -0
  46. package/build/src/testing/TestCliHelper.d.ts +23 -0
  47. package/build/src/testing/TestCliHelper.js +71 -0
  48. package/build/src/testing/TestCliHelper.js.map +1 -0
  49. package/build/src/testing/getPort.d.ts +52 -0
  50. package/build/src/testing/getPort.js +169 -0
  51. package/build/src/testing/getPort.js.map +1 -0
  52. package/package.json +2 -1
  53. package/src/lib/fs/Fs.ts +258 -0
  54. package/src/lib/timers/Timers.ts +9 -0
  55. package/src/mocking/LegacyInterfaces.ts +1 -1
  56. package/src/mocking/ProjectMock.ts +20 -0
  57. package/src/mocking/lib/Request.ts +85 -0
  58. package/src/mocking/lib/Response.ts +101 -0
  59. package/src/runtime/node/BaseRunner.ts +29 -0
  60. package/src/runtime/node/ProjectParallelRunner.ts +234 -0
  61. package/src/runtime/node/ProjectRequestRunner.ts +281 -0
  62. package/src/runtime/node/ProjectRunner.ts +279 -186
  63. package/src/runtime/node/ProjectRunnerWorker.ts +62 -0
  64. package/src/runtime/node/ProjectSerialRunner.ts +36 -0
  65. package/src/runtime/reporters/ProjectRunCliReporter.ts +79 -0
  66. package/src/runtime/reporters/Reporter.ts +142 -0
  67. package/src/testing/TestCliHelper.ts +76 -0
  68. package/src/testing/getPort.ts +212 -0
@@ -0,0 +1,258 @@
1
+ import { writeFile, mkdir, rm, readdir, stat, access, readFile, copyFile as fsCopyFile } from 'fs/promises';
2
+ import { constants } from 'fs';
3
+ import { join, dirname } from 'path';
4
+
5
+ export interface JsonReadOptions {
6
+ /**
7
+ * Whether it should throw an error when a reading error occurs.
8
+ */
9
+ throws?: boolean;
10
+ }
11
+
12
+ // function statPromise(filePath: string): Promise<fsSync.Stats> {
13
+ // return new Promise((resolve, reject) => {
14
+ // fsSync.stat(filePath, (err, stats) => {
15
+ // if (err) {
16
+ // reject(err);
17
+ // } else {
18
+ // resolve(stats);
19
+ // }
20
+ // });
21
+ // });
22
+ // }
23
+
24
+ /**
25
+ * Checks whether a file exists in the location.
26
+ */
27
+ export async function pathExists(filePath: string): Promise<boolean> {
28
+ // return new Promise((resolve) => {
29
+ // fsSync.stat(filePath, (err, stats) => {
30
+ // if (err) {
31
+ // resolve(false);
32
+ // } else {
33
+ // resolve(true);
34
+ // }
35
+ // });
36
+ // });
37
+ try {
38
+ await stat(filePath);
39
+ return true;
40
+ } catch (e) {
41
+ return false;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Tests a user's permissions for the file or directory specified by filePath.
47
+ * @param filePath The path to test
48
+ * @returns True when the path can be read by the current user.
49
+ */
50
+ export async function canRead(filePath: string): Promise<boolean> {
51
+ const exists = await pathExists(filePath);
52
+ if (!exists) {
53
+ return false;
54
+ }
55
+
56
+ // return new Promise((resolve) => {
57
+ // fsSync.access(filePath, constants.R_OK, (err) => {
58
+ // if (err) {
59
+ // resolve(false);
60
+ // } else {
61
+ // resolve(true);
62
+ // }
63
+ // });
64
+ // });
65
+ try {
66
+ await access(filePath, constants.R_OK);
67
+ return true;
68
+ } catch (e) {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Tests a user's permissions for the file or directory specified by filePath.
75
+ * @param filePath The path to test
76
+ * @returns True when the path can be written to by the current user.
77
+ */
78
+ export async function canWrite(filePath: string): Promise<boolean> {
79
+ const exists = await pathExists(filePath);
80
+ if (!exists) {
81
+ return false;
82
+ }
83
+ // return new Promise((resolve) => {
84
+ // fsSync.access(filePath, constants.W_OK, (err) => {
85
+ // if (err) {
86
+ // resolve(false);
87
+ // } else {
88
+ // resolve(true);
89
+ // }
90
+ // });
91
+ // });
92
+ try {
93
+ await access(filePath, constants.W_OK);
94
+ return true;
95
+ } catch (e) {
96
+ return false;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Reads the contents of a JSON file.
102
+ *
103
+ * @param filePath The path to the JSON file to read.
104
+ * @returns The contents of the file. When `throws` options is not set and error occurs then it returns an empty file.
105
+ */
106
+ export async function readJson(filePath: string, opts: JsonReadOptions={}): Promise<unknown> {
107
+ const readable = await canRead(filePath);
108
+ if (!readable) {
109
+ if (opts.throws) {
110
+ throw new Error(`Unable to read file: ${filePath}. Access is denied.`);
111
+ }
112
+ return {};
113
+ }
114
+ // return new Promise((resolve, reject) => {
115
+ // fsSync.readFile(filePath, 'utf8', (err, contents) => {
116
+ // if (err) {
117
+ // reject(err);
118
+ // } else {
119
+ // let data = {};
120
+ // try {
121
+ // data = JSON.parse(contents);
122
+ // } catch (e) {
123
+ // if (opts.throws) {
124
+ // const err = new Error(`Invalid JSON contents for file: ${filePath}.`);
125
+ // reject(err);
126
+ // return;
127
+ // }
128
+ // }
129
+ // resolve(data);
130
+ // }
131
+ // });
132
+ // });
133
+ const contents = await readFile(filePath, 'utf8');
134
+ let data = {};
135
+ try {
136
+ data = JSON.parse(contents);
137
+ } catch (e) {
138
+ if (opts.throws) {
139
+ throw new Error(`Invalid JSON contents for file: ${filePath}.`);
140
+ }
141
+ }
142
+ return data;
143
+ }
144
+
145
+ /**
146
+ * Writes the contents to the file.
147
+ *
148
+ * @param filePath The file to write to. It replaces the contents.
149
+ * @param contents The contents to write.
150
+ */
151
+ export async function writeJson(filePath: string, contents: string|any): Promise<void> {
152
+ const destParent = dirname(filePath);
153
+ await ensureDir(destParent);
154
+ const parentWritable = await canWrite(destParent);
155
+ if (!parentWritable) {
156
+ throw new Error(`Unable to write to location: ${parentWritable}. Access is denied.`);
157
+ }
158
+ const data = typeof contents === 'string' ? contents : JSON.stringify(contents);
159
+ await writeFile(filePath, data);
160
+ }
161
+
162
+ /**
163
+ * Ensures the directory exists.
164
+ */
165
+ export async function ensureDir(dirPath: string): Promise<void> {
166
+ const readable = await canRead(dirPath);
167
+ if (readable) {
168
+ return;
169
+ }
170
+ await mkdir(dirPath, { recursive: true });
171
+ }
172
+
173
+ /**
174
+ * Removes contents of the directory, leaving the directory in the filesystem.
175
+ */
176
+ export async function emptyDir(dirPath: string): Promise<void> {
177
+ const exists = await pathExists(dirPath);
178
+ if (!exists) {
179
+ return;
180
+ }
181
+ const writeable = await canWrite(dirPath);
182
+ if (!writeable) {
183
+ throw new Error(`Unable to clear directory: ${dirPath}. Access is denied.`);
184
+ }
185
+ const items = await readdir(dirPath, 'utf8');
186
+ for (const item of items) {
187
+ const file = join(dirPath, item);
188
+ await rm(file, { recursive: true });
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Copies a file
194
+ */
195
+ async function copyFile(source: string, dest: string): Promise<void> {
196
+ const destParent = dirname(dest);
197
+ await ensureDir(destParent);
198
+ await fsCopyFile(source, dest);
199
+ }
200
+
201
+ // /**
202
+ // * Copies a file
203
+ // * @param {string} source
204
+ // * @param {string} dest
205
+ // * @returns {Promise<void>}
206
+ // */
207
+ // async function copyFile(source, dest) {
208
+ // const destParent = dirname(dest);
209
+ // await ensureDir(destParent);
210
+ // return new Promise((resolve, reject) => {
211
+ // fsSync.copyFile(source, dest, (err) => {
212
+ // if (err) {
213
+ // reject(err);
214
+ // } else {
215
+ // resolve();
216
+ // }
217
+ // });
218
+ // });
219
+ // }
220
+
221
+ /**
222
+ * Copies a directory and its contents.
223
+ */
224
+ async function copyDirectory(source: string, dest: string): Promise<void> {
225
+ await ensureDir(dest);
226
+ // const entries = fsSync.readdirSync(source, { withFileTypes: true, encoding: 'utf8' });
227
+ const entries = await readdir(source, { withFileTypes: true, encoding: 'utf8' });
228
+ for (const entry of entries) {
229
+ const srcFile = join(source, entry.name);
230
+ const destFile = join(dest, entry.name);
231
+ const srcStat = await stat(srcFile);
232
+ if (srcStat.isDirectory()) {
233
+ await copyDirectory(srcFile, destFile);
234
+ } else {
235
+ await copyFile(srcFile, destFile);
236
+ }
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Copies a file or a directory to the destination location.
242
+ * It creates the destination folder when missing.
243
+ *
244
+ * @param source The source file or folder.
245
+ * @param dest The destination file or folder.
246
+ */
247
+ export async function copy(source: string, dest: string): Promise<void> {
248
+ const existing = await pathExists(source);
249
+ if (!existing) {
250
+ throw new Error(`Specified path does not exist: ${source}`);
251
+ }
252
+ const srcStat = await stat(source);
253
+ if (srcStat.isDirectory()) {
254
+ await copyDirectory(source, dest);
255
+ } else {
256
+ await copyFile(source, dest);
257
+ }
258
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Awaits the set number of milliseconds before resolving the promise.
3
+ * @param timeout The number of milliseconds to wait.
4
+ */
5
+ export function sleep(timeout = 0): Promise<void> {
6
+ return new Promise((resolve) => {
7
+ setTimeout(() => resolve(), timeout);
8
+ });
9
+ }
@@ -1,4 +1,4 @@
1
- import { DataMockInit, HarTimingInit, HttpRequestInit, HttpResponseRedirectStatusInit } from '@pawel-up/data-mock/types'
1
+ import { DataMockInit, HarTimingInit, HttpResponseRedirectStatusInit } from '@pawel-up/data-mock/types'
2
2
 
3
3
  export interface ArcDataMockInit extends DataMockInit {
4
4
  }
@@ -0,0 +1,20 @@
1
+ import { DataMock, DataMockInit } from '@pawel-up/data-mock';
2
+ import { Request } from './lib/Request.js';
3
+ import { Response } from './lib/Response.js';
4
+
5
+ export { IRequestLogInit } from './lib/Request.js';
6
+ export { IArcResponseInit } from './lib/Response.js';
7
+
8
+ export class ProjectMock extends DataMock {
9
+ projectRequest: Request;
10
+ response: Response;
11
+
12
+ /**
13
+ * @param init The library init options.
14
+ */
15
+ constructor(init?: DataMockInit) {
16
+ super(init);
17
+ this.projectRequest = new Request(init);
18
+ this.response = new Response(init);
19
+ }
20
+ }
@@ -0,0 +1,85 @@
1
+ import { Http, Types, Lorem, Time, DataMockInit, HttpRequestInit } from '@pawel-up/data-mock';
2
+ // import { randomValue } from '@pawel-up/data-mock/src/lib/Http.js';
3
+ import { IHttpRequest, Kind as HttpRequestKind } from '../../models/HttpRequest.js';
4
+ import { IRequest, Kind as RequestKind } from '../../models/Request.js';
5
+ import { ISentRequest } from '../../models/SentRequest.js';
6
+ import { IRequestLog } from '../../models/RequestLog.js';
7
+ import { IArcResponseInit, Response } from './Response.js';
8
+
9
+ export interface IRequestLogInit {
10
+ request?: HttpRequestInit;
11
+ response?: IArcResponseInit;
12
+ /**
13
+ * When set it ignores size information
14
+ */
15
+ noSize?: boolean;
16
+ /**
17
+ * Adds redirects to the request
18
+ */
19
+ redirects?: boolean;
20
+ noResponse?: boolean;
21
+ noRequest?: boolean;
22
+ }
23
+
24
+ export class Request {
25
+ types: Types;
26
+ lorem: Lorem;
27
+ time: Time;
28
+ http: Http;
29
+ response: Response;
30
+
31
+ constructor(init: DataMockInit={}) {
32
+ this.types = new Types(init.seed);
33
+ this.lorem = new Lorem(init);
34
+ this.time = new Time(init);
35
+ this.http = new Http(init);
36
+ this.response = new Response(init);
37
+ }
38
+
39
+ request(init?: HttpRequestInit): IRequest {
40
+ return {
41
+ kind: RequestKind,
42
+ expects: this.httpRequest(init),
43
+ info: {
44
+ name: this.lorem.words(2),
45
+ description: this.lorem.paragraph(),
46
+ },
47
+ }
48
+ }
49
+
50
+ httpRequest(init?: HttpRequestInit): IHttpRequest {
51
+ const request = this.http.request(init);
52
+ return {
53
+ kind: HttpRequestKind,
54
+ ...request,
55
+ }
56
+ }
57
+
58
+ sentRequest(init?: HttpRequestInit): ISentRequest {
59
+ const start = this.time.timestamp();
60
+ return {
61
+ startTime: start,
62
+ endTime: this.time.timestamp({ min: start + 1 }),
63
+ ...this.httpRequest(init),
64
+ };
65
+ }
66
+
67
+ log(init: IRequestLogInit = {}): IRequestLog {
68
+ const result: IRequestLog = {
69
+ kind: 'ARC#ResponseLog',
70
+ };
71
+ if (!init.noRequest) {
72
+ result.request = this.sentRequest(init.request);
73
+ }
74
+ if (!init.noResponse) {
75
+ result.response = this.response.arcResponse(init.response);
76
+ }
77
+ if (init.redirects) {
78
+ result.redirects = this.response.redirects();
79
+ }
80
+ if (!init.noSize) {
81
+ result.size = this.response.size();
82
+ }
83
+ return result;
84
+ }
85
+ }
@@ -0,0 +1,101 @@
1
+ import { Http, Har, Types, Lorem, Time, DataMockInit, HttpResponseInit, HarTimingInit, Internet } from '@pawel-up/data-mock';
2
+ import { IHttpResponse, Kind as HttpResponseKind } from '../../models/HttpResponse.js';
3
+ import { IArcResponse, Kind as ArcResponseKind } from '../../models/ArcResponse.js';
4
+ import { IRequestsSize } from '../../models/RequestsSize.js';
5
+ import { IResponseRedirect, Kind as ResponseRedirectKind } from '../../models/ResponseRedirect.js';
6
+
7
+ export interface IArcResponseInit extends HttpResponseInit, HarTimingInit {
8
+ /**
9
+ * When set it does not generate a response payload.
10
+ */
11
+ noBody?: boolean;
12
+ /**
13
+ * The first number of the status group. Other 2 are auto generated
14
+ */
15
+ statusGroup?: number;
16
+ /**
17
+ * Whether to generate timings object
18
+ */
19
+ timings?: boolean;
20
+ }
21
+
22
+ export class Response {
23
+ types: Types;
24
+ lorem: Lorem;
25
+ time: Time;
26
+ http: Http;
27
+ har: Har;
28
+ internet: Internet;
29
+
30
+ constructor(init: DataMockInit={}) {
31
+ this.types = new Types(init.seed);
32
+ this.lorem = new Lorem(init);
33
+ this.time = new Time(init);
34
+ this.http = new Http(init);
35
+ this.har = new Har(init);
36
+ this.internet = new Internet(init);
37
+ }
38
+
39
+ response(init: IArcResponseInit = {}): IHttpResponse {
40
+ const ct = init.noBody ? undefined : this.http.headers.contentType();
41
+ const body = init.noBody ? undefined : this.http.payload.payload(ct);
42
+ const headers = this.http.headers.headers('response', { mime: ct });
43
+ const statusGroup = init.statusGroup ? init.statusGroup : this.types.number({ min: 2, max: 5 });
44
+ const sCode = this.types.number({ min: 0, max: 99 }).toString();
45
+ const code = Number(`${statusGroup}${sCode.padStart(2, '0')}`);
46
+ const status = this.lorem.word();
47
+ const result: IHttpResponse = {
48
+ kind: HttpResponseKind,
49
+ status: code,
50
+ statusText: status,
51
+ headers,
52
+ };
53
+ if (!init.noBody) {
54
+ result.payload = body;
55
+ }
56
+ return result;
57
+ }
58
+
59
+ arcResponse(init: IArcResponseInit={}): IArcResponse {
60
+ const base = this.response(init);
61
+ const length = this.types.number({ min: 10, max: 4000 });
62
+ const result: IArcResponse = {
63
+ ...base,
64
+ kind: ArcResponseKind,
65
+ loadingTime: length,
66
+ };
67
+ if (init.timings) {
68
+ result.timings = this.har.timing(init);
69
+ }
70
+ return result;
71
+ }
72
+
73
+ size(): IRequestsSize {
74
+ const result: IRequestsSize = {
75
+ request: this.types.number({ min: 10 }),
76
+ response: this.types.number({ min: 10 }),
77
+ };
78
+ return result;
79
+ }
80
+
81
+ redirect(init?: IArcResponseInit): IResponseRedirect {
82
+ const start = this.time.timestamp();
83
+ const end = this.time.timestamp({ min: start + 1 })
84
+ const info: IResponseRedirect = {
85
+ kind: ResponseRedirectKind,
86
+ startTime: start,
87
+ endTime: end,
88
+ url: this.internet.uri(),
89
+ response: this.response({ ...init, statusGroup: 3}),
90
+ };
91
+ return info;
92
+ }
93
+
94
+ redirects(size=1, init?: IArcResponseInit): IResponseRedirect[] {
95
+ const result: IResponseRedirect[] = [];
96
+ for (let i = 0; i < size; i++) {
97
+ result.push(this.redirect(init));
98
+ }
99
+ return result;
100
+ }
101
+ }
@@ -0,0 +1,29 @@
1
+ import { EventEmitter } from 'events';
2
+ import { IProjectExecutionIteration, IProjectExecutionLog } from '../reporters/Reporter.js';
3
+
4
+ export abstract class BaseRunner extends EventEmitter {
5
+ /**
6
+ * Iteration start time.
7
+ */
8
+ protected startTime?: number;
9
+ /**
10
+ * Iteration end time.
11
+ */
12
+ protected endTime?: number;
13
+ /**
14
+ * A list of already executed iterations.
15
+ */
16
+ protected executed: IProjectExecutionIteration[] = [];
17
+
18
+ /**
19
+ * Creates the report of the execution.
20
+ */
21
+ protected async createReport(): Promise<IProjectExecutionLog> {
22
+ const log: IProjectExecutionLog = {
23
+ started: this.startTime as number,
24
+ ended: this.endTime as number,
25
+ iterations: this.executed,
26
+ };
27
+ return log;
28
+ }
29
+ }