@opra/testing 0.5.0 → 0.7.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.
- package/cjs/api-expect/api-expect-collection.js +16 -16
- package/cjs/api-expect/api-expect-object.js +2 -3
- package/cjs/api-expect/api-expect.js +1 -0
- package/cjs/test-client.js +40 -17
- package/cjs/utils/is-absolute-url.util.js +9 -0
- package/esm/api-expect/api-expect-collection.d.ts +4 -4
- package/esm/api-expect/api-expect-collection.js +4 -4
- package/esm/api-expect/api-expect-error.d.ts +3 -3
- package/esm/api-expect/api-expect-object.d.ts +3 -3
- package/esm/api-expect/api-expect-object.js +2 -2
- package/esm/api-expect/api-expect-operation-result.d.ts +3 -3
- package/esm/api-expect/api-expect.d.ts +3 -3
- package/esm/api-expect/api-expect.js +1 -0
- package/esm/test-client.d.ts +10 -12
- package/esm/test-client.js +41 -17
- package/esm/utils/is-absolute-url.util.d.ts +1 -0
- package/esm/utils/is-absolute-url.util.js +5 -0
- package/package.json +7 -6
- package/cjs/constants.js +0 -4
- package/esm/constants.d.ts +0 -1
- package/esm/constants.js +0 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.convertFilter = exports.ApiExpectCollection = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const lodash_1 =
|
|
5
|
+
const lodash_1 = require("lodash");
|
|
6
6
|
const rule_judgment_1 = tslib_1.__importDefault(require("rule-judgment"));
|
|
7
|
-
const
|
|
7
|
+
const common_1 = require("@opra/common");
|
|
8
8
|
class ApiExpectCollection {
|
|
9
9
|
response;
|
|
10
10
|
_isNot;
|
|
@@ -21,7 +21,7 @@ class ApiExpectCollection {
|
|
|
21
21
|
}
|
|
22
22
|
toMatch(expected) {
|
|
23
23
|
try {
|
|
24
|
-
const v = lodash_1.
|
|
24
|
+
const v = (0, lodash_1.omitBy)(expected, lodash_1.isNil);
|
|
25
25
|
for (const item of this.response.data) {
|
|
26
26
|
this._expect(item).toMatchObject(v);
|
|
27
27
|
}
|
|
@@ -133,10 +133,10 @@ class ApiExpectCollection {
|
|
|
133
133
|
}
|
|
134
134
|
exports.ApiExpectCollection = ApiExpectCollection;
|
|
135
135
|
function convertFilter(str) {
|
|
136
|
-
const ast = typeof str === 'string' ? (0,
|
|
136
|
+
const ast = typeof str === 'string' ? (0, common_1.parseFilter)(str) : str;
|
|
137
137
|
if (!ast)
|
|
138
138
|
return;
|
|
139
|
-
if (ast instanceof
|
|
139
|
+
if (ast instanceof common_1.ComparisonExpression) {
|
|
140
140
|
const left = convertFilter(ast.left);
|
|
141
141
|
const right = convertFilter(ast.right);
|
|
142
142
|
switch (ast.op) {
|
|
@@ -160,29 +160,29 @@ function convertFilter(str) {
|
|
|
160
160
|
throw new Error(`ComparisonExpression operator (${ast.op}) not implemented yet`);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
if (ast instanceof
|
|
163
|
+
if (ast instanceof common_1.QualifiedIdentifier) {
|
|
164
164
|
return ast.value;
|
|
165
165
|
}
|
|
166
|
-
if (ast instanceof
|
|
167
|
-
ast instanceof
|
|
168
|
-
ast instanceof
|
|
169
|
-
ast instanceof
|
|
170
|
-
ast instanceof
|
|
171
|
-
ast instanceof
|
|
166
|
+
if (ast instanceof common_1.NumberLiteral ||
|
|
167
|
+
ast instanceof common_1.StringLiteral ||
|
|
168
|
+
ast instanceof common_1.BooleanLiteral ||
|
|
169
|
+
ast instanceof common_1.NullLiteral ||
|
|
170
|
+
ast instanceof common_1.DateLiteral ||
|
|
171
|
+
ast instanceof common_1.TimeLiteral) {
|
|
172
172
|
return ast.value;
|
|
173
173
|
}
|
|
174
|
-
if (ast instanceof
|
|
174
|
+
if (ast instanceof common_1.ArrayExpression) {
|
|
175
175
|
return ast.items.map(convertFilter);
|
|
176
176
|
}
|
|
177
|
-
if (ast instanceof
|
|
177
|
+
if (ast instanceof common_1.LogicalExpression) {
|
|
178
178
|
if (ast.op === 'or')
|
|
179
179
|
return { $or: ast.items.map(convertFilter) };
|
|
180
180
|
return { $and: ast.items.map(convertFilter) };
|
|
181
181
|
}
|
|
182
|
-
if (ast instanceof
|
|
182
|
+
if (ast instanceof common_1.ArrayExpression) {
|
|
183
183
|
return ast.items.map(convertFilter);
|
|
184
184
|
}
|
|
185
|
-
if (ast instanceof
|
|
185
|
+
if (ast instanceof common_1.ParenthesesExpression) {
|
|
186
186
|
return convertFilter(ast.expression);
|
|
187
187
|
}
|
|
188
188
|
throw new Error(`${ast.kind} is not implemented yet`);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ApiExpectObject = void 0;
|
|
4
|
-
const
|
|
5
|
-
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
6
5
|
class ApiExpectObject {
|
|
7
6
|
response;
|
|
8
7
|
_isNot;
|
|
@@ -15,7 +14,7 @@ class ApiExpectObject {
|
|
|
15
14
|
}
|
|
16
15
|
toMatch(expected) {
|
|
17
16
|
try {
|
|
18
|
-
const v = lodash_1.
|
|
17
|
+
const v = (0, lodash_1.omitBy)(expected, lodash_1.isNil);
|
|
19
18
|
this._expect(this.response.data).toMatchObject(v);
|
|
20
19
|
}
|
|
21
20
|
catch (e) {
|
package/cjs/test-client.js
CHANGED
|
@@ -1,27 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpraTestClient = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const http_1 = require("http");
|
|
5
|
+
const url_1 = require("url");
|
|
6
6
|
const client_1 = require("@opra/client");
|
|
7
|
+
const common_1 = require("@opra/common");
|
|
7
8
|
const api_expect_js_1 = require("./api-expect/api-expect.js");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
const is_absolute_url_util_js_1 = require("./utils/is-absolute-url.util.js");
|
|
10
|
+
class OpraTestClient extends client_1.OpraHttpClient {
|
|
11
|
+
_server;
|
|
12
|
+
constructor(app, options) {
|
|
13
|
+
super('/', options);
|
|
14
|
+
this._server = app instanceof http_1.Server ? app : (0, http_1.createServer)(app);
|
|
13
15
|
}
|
|
14
16
|
// @ts-ignore
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
async _fetch(urlString, req) {
|
|
18
|
+
const resp = await new Promise((resolve, reject) => {
|
|
19
|
+
urlString = (0, is_absolute_url_util_js_1.isAbsoluteUrl)(urlString) ? urlString : (0, common_1.joinPath)('http://opra.test', urlString);
|
|
20
|
+
const url = new url_1.URL(urlString);
|
|
21
|
+
// Set protocol to HTTP
|
|
22
|
+
url.protocol = 'http';
|
|
23
|
+
// Apply original host to request header
|
|
24
|
+
const headers = req.headers = (req.headers || {});
|
|
25
|
+
if (url.host !== 'opra.test' && headers?.host == null)
|
|
26
|
+
headers.host = url.host;
|
|
27
|
+
new Promise((subResolve) => {
|
|
28
|
+
if (this._server.listening)
|
|
29
|
+
subResolve();
|
|
30
|
+
else
|
|
31
|
+
this._server.listen(0, '127.0.0.1', () => subResolve());
|
|
32
|
+
}).then(() => {
|
|
33
|
+
const address = this._server.address();
|
|
34
|
+
url.host = '127.0.0.1';
|
|
35
|
+
url.port = address.port.toString();
|
|
36
|
+
return super._fetch(url.toString(), req);
|
|
37
|
+
}).then(res => {
|
|
38
|
+
if (!this._server.listening)
|
|
39
|
+
return resolve(res);
|
|
40
|
+
this._server.close(() => resolve(res));
|
|
41
|
+
}).then()
|
|
42
|
+
.catch(error => {
|
|
43
|
+
if (!this._server.listening)
|
|
44
|
+
return reject(error);
|
|
45
|
+
this._server.close(() => reject(error));
|
|
46
|
+
});
|
|
47
|
+
});
|
|
25
48
|
resp.expect = new api_expect_js_1.ApiExpect(resp);
|
|
26
49
|
return resp;
|
|
27
50
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isAbsoluteUrl = void 0;
|
|
4
|
+
const url_1 = require("url");
|
|
5
|
+
const isAbsoluteUrl = (urlString) => {
|
|
6
|
+
const url = new url_1.URL(urlString, 'http://opra.test/');
|
|
7
|
+
return url.host !== 'opra.test';
|
|
8
|
+
};
|
|
9
|
+
exports.isAbsoluteUrl = isAbsoluteUrl;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Expression } from '@opra/
|
|
1
|
+
import { HttpResponse } from '@opra/client';
|
|
2
|
+
import { Expression } from '@opra/common';
|
|
3
3
|
export declare class ApiExpectCollection {
|
|
4
|
-
readonly response:
|
|
4
|
+
readonly response: HttpResponse;
|
|
5
5
|
protected _isNot: boolean;
|
|
6
|
-
constructor(response:
|
|
6
|
+
constructor(response: HttpResponse, _isNot?: boolean);
|
|
7
7
|
get not(): ApiExpectCollection;
|
|
8
8
|
forEach(callbackfn: (v: any) => void): this;
|
|
9
9
|
toMatch<T extends {}>(expected: T): this;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { isNil, omitBy } from 'lodash';
|
|
2
2
|
import ruleJudgment from 'rule-judgment';
|
|
3
|
-
import {
|
|
3
|
+
import { ArrayExpression, BooleanLiteral, ComparisonExpression, DateLiteral, LogicalExpression, NullLiteral, NumberLiteral, ParenthesesExpression, parseFilter, QualifiedIdentifier, StringLiteral, TimeLiteral } from '@opra/common';
|
|
4
4
|
export class ApiExpectCollection {
|
|
5
5
|
response;
|
|
6
6
|
_isNot;
|
|
@@ -17,7 +17,7 @@ export class ApiExpectCollection {
|
|
|
17
17
|
}
|
|
18
18
|
toMatch(expected) {
|
|
19
19
|
try {
|
|
20
|
-
const v =
|
|
20
|
+
const v = omitBy(expected, isNil);
|
|
21
21
|
for (const item of this.response.data) {
|
|
22
22
|
this._expect(item).toMatchObject(v);
|
|
23
23
|
}
|
|
@@ -128,7 +128,7 @@ export class ApiExpectCollection {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
export function convertFilter(str) {
|
|
131
|
-
const ast = typeof str === 'string' ?
|
|
131
|
+
const ast = typeof str === 'string' ? parseFilter(str) : str;
|
|
132
132
|
if (!ast)
|
|
133
133
|
return;
|
|
134
134
|
if (ast instanceof ComparisonExpression) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HttpResponse } from '@opra/client';
|
|
2
2
|
import { ApiExpectObject } from './api-expect-object.js';
|
|
3
3
|
export declare class ApiExpectError extends ApiExpectObject {
|
|
4
|
-
readonly response:
|
|
5
|
-
constructor(response:
|
|
4
|
+
readonly response: HttpResponse;
|
|
5
|
+
constructor(response: HttpResponse);
|
|
6
6
|
toContainDetail(...matching: any[]): void;
|
|
7
7
|
}
|
|
8
8
|
declare global {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HttpResponse } from '@opra/client';
|
|
2
2
|
export declare class ApiExpectObject {
|
|
3
|
-
readonly response:
|
|
3
|
+
readonly response: HttpResponse;
|
|
4
4
|
protected _isNot: boolean;
|
|
5
|
-
constructor(response:
|
|
5
|
+
constructor(response: HttpResponse, _isNot?: boolean);
|
|
6
6
|
get not(): ApiExpectObject;
|
|
7
7
|
toMatch<T extends {}>(expected: T): this;
|
|
8
8
|
toHaveFields(fields: string[]): this;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { isNil, omitBy } from 'lodash';
|
|
2
2
|
export class ApiExpectObject {
|
|
3
3
|
response;
|
|
4
4
|
_isNot;
|
|
@@ -11,7 +11,7 @@ export class ApiExpectObject {
|
|
|
11
11
|
}
|
|
12
12
|
toMatch(expected) {
|
|
13
13
|
try {
|
|
14
|
-
const v =
|
|
14
|
+
const v = omitBy(expected, isNil);
|
|
15
15
|
this._expect(this.response.data).toMatchObject(v);
|
|
16
16
|
}
|
|
17
17
|
catch (e) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HttpResponse } from '@opra/client';
|
|
2
2
|
export declare class ApiExpectOperationResult {
|
|
3
|
-
readonly response:
|
|
3
|
+
readonly response: HttpResponse;
|
|
4
4
|
protected _isNot: boolean;
|
|
5
|
-
constructor(response:
|
|
5
|
+
constructor(response: HttpResponse, _isNot?: boolean);
|
|
6
6
|
get not(): ApiExpectOperationResult;
|
|
7
7
|
toBeAffectedExact(expected: number): this;
|
|
8
8
|
toBeAffectedMin(expected: number): this;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HttpResponse } from '@opra/client';
|
|
2
2
|
import { ApiExpectCollection } from './api-expect-collection.js';
|
|
3
3
|
import { ApiExpectError } from './api-expect-error.js';
|
|
4
4
|
import { ApiExpectObject } from './api-expect-object.js';
|
|
5
5
|
import { ApiExpectOperationResult } from './api-expect-operation-result.js';
|
|
6
6
|
export declare class ApiExpect {
|
|
7
|
-
readonly response:
|
|
7
|
+
readonly response: HttpResponse;
|
|
8
8
|
protected _isNot: boolean;
|
|
9
|
-
constructor(response:
|
|
9
|
+
constructor(response: HttpResponse, _isNot?: boolean);
|
|
10
10
|
get not(): ApiExpect;
|
|
11
11
|
toSuccess(status?: number): this;
|
|
12
12
|
toFail(status?: number): ApiExpectError;
|
package/esm/test-client.d.ts
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { AxiosRequestConfig } from 'axios';
|
|
3
2
|
import { IncomingMessage, Server, ServerResponse } from 'http';
|
|
4
3
|
import { Type } from 'ts-gems';
|
|
5
|
-
import {
|
|
6
|
-
import { SingletonNode } from '@opra/client/src/services/singleton-node';
|
|
7
|
-
import { OpraDocument } from '@opra/schema/src/index';
|
|
4
|
+
import { BatchRequest, HttpCollectionService, HttpRequest, HttpResponse, HttpSingletonService, OpraHttpClient, OpraHttpClientOptions } from '@opra/client';
|
|
8
5
|
import { ApiExpect } from './api-expect/api-expect.js';
|
|
9
6
|
declare type RequestListener = (req: IncomingMessage, res: ServerResponse) => void;
|
|
10
7
|
declare type Handler = RequestListener | Server;
|
|
11
|
-
declare type
|
|
8
|
+
export declare type TestHttpResponse<T = any> = HttpResponse<T> & {
|
|
12
9
|
expect: ApiExpect;
|
|
13
10
|
};
|
|
14
|
-
export declare class OpraTestClient extends
|
|
15
|
-
|
|
16
|
-
constructor(app:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
export declare class OpraTestClient extends OpraHttpClient {
|
|
12
|
+
protected _server: Server;
|
|
13
|
+
constructor(app: Server | RequestListener, options?: OpraHttpClientOptions);
|
|
14
|
+
batch<TResponse extends TestHttpResponse = TestHttpResponse>(requests: HttpRequest[]): BatchRequest<TResponse>;
|
|
15
|
+
collection<T = any, TResponse extends TestHttpResponse<T> = TestHttpResponse<T>>(name: string): HttpCollectionService<T, TResponse>;
|
|
16
|
+
singleton<T = any, TResponse extends TestHttpResponse<T> = TestHttpResponse<T>>(name: string): HttpSingletonService<T, TResponse>;
|
|
17
|
+
protected _fetch<TResponse extends TestHttpResponse = TestHttpResponse>(urlString: string, req: RequestInit): Promise<TResponse>;
|
|
18
|
+
static create<T extends OpraTestClient>(this: Type<T>, app: Handler, options?: OpraHttpClientOptions): Promise<T>;
|
|
21
19
|
}
|
|
22
20
|
export {};
|
package/esm/test-client.js
CHANGED
|
@@ -1,23 +1,47 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { createServer, Server } from 'http';
|
|
2
|
+
import { URL } from 'url';
|
|
3
|
+
import { OpraHttpClient, } from '@opra/client';
|
|
4
|
+
import { joinPath } from '@opra/common';
|
|
3
5
|
import { ApiExpect } from './api-expect/api-expect.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { isAbsoluteUrl } from './utils/is-absolute-url.util.js';
|
|
7
|
+
export class OpraTestClient extends OpraHttpClient {
|
|
8
|
+
_server;
|
|
9
|
+
constructor(app, options) {
|
|
10
|
+
super('/', options);
|
|
11
|
+
this._server = app instanceof Server ? app : createServer(app);
|
|
9
12
|
}
|
|
10
13
|
// @ts-ignore
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
async _fetch(urlString, req) {
|
|
15
|
+
const resp = await new Promise((resolve, reject) => {
|
|
16
|
+
urlString = isAbsoluteUrl(urlString) ? urlString : joinPath('http://opra.test', urlString);
|
|
17
|
+
const url = new URL(urlString);
|
|
18
|
+
// Set protocol to HTTP
|
|
19
|
+
url.protocol = 'http';
|
|
20
|
+
// Apply original host to request header
|
|
21
|
+
const headers = req.headers = (req.headers || {});
|
|
22
|
+
if (url.host !== 'opra.test' && headers?.host == null)
|
|
23
|
+
headers.host = url.host;
|
|
24
|
+
new Promise((subResolve) => {
|
|
25
|
+
if (this._server.listening)
|
|
26
|
+
subResolve();
|
|
27
|
+
else
|
|
28
|
+
this._server.listen(0, '127.0.0.1', () => subResolve());
|
|
29
|
+
}).then(() => {
|
|
30
|
+
const address = this._server.address();
|
|
31
|
+
url.host = '127.0.0.1';
|
|
32
|
+
url.port = address.port.toString();
|
|
33
|
+
return super._fetch(url.toString(), req);
|
|
34
|
+
}).then(res => {
|
|
35
|
+
if (!this._server.listening)
|
|
36
|
+
return resolve(res);
|
|
37
|
+
this._server.close(() => resolve(res));
|
|
38
|
+
}).then()
|
|
39
|
+
.catch(error => {
|
|
40
|
+
if (!this._server.listening)
|
|
41
|
+
return reject(error);
|
|
42
|
+
this._server.close(() => reject(error));
|
|
43
|
+
});
|
|
44
|
+
});
|
|
21
45
|
resp.expect = new ApiExpect(resp);
|
|
22
46
|
return resp;
|
|
23
47
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isAbsoluteUrl: (urlString: string) => boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Opra testing package",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,17 +25,18 @@
|
|
|
25
25
|
"clean:cover": "rimraf ../../coverage/testing"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@opra/
|
|
29
|
-
"@opra/
|
|
30
|
-
"@opra/client": "^0.5.0",
|
|
28
|
+
"@opra/client": "^0.7.0",
|
|
29
|
+
"@opra/common": "^0.7.0",
|
|
31
30
|
"ansi-colors": "^4.1.3",
|
|
32
31
|
"lodash": "^4.17.21",
|
|
33
|
-
"rule-judgment": "^1.1.5"
|
|
34
|
-
"supertest": "^6.3.0"
|
|
32
|
+
"rule-judgment": "^1.1.5"
|
|
35
33
|
},
|
|
36
34
|
"devDependencies": {
|
|
37
35
|
"@types/supertest": "^2.0.12"
|
|
38
36
|
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"axios": "^1.2.1"
|
|
39
|
+
},
|
|
39
40
|
"type": "module",
|
|
40
41
|
"types": "esm/index.d.ts",
|
|
41
42
|
"exports": {
|
package/cjs/constants.js
DELETED
package/esm/constants.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const expectSymbolTag: unique symbol;
|
package/esm/constants.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const expectSymbolTag = Symbol('opra.test.expect');
|