@opra/testing 0.3.0 → 0.5.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.
Files changed (72) hide show
  1. package/cjs/{expect/api-expect-array.js → api-expect/api-expect-collection.js} +48 -44
  2. package/cjs/{expect → api-expect}/api-expect-error.js +3 -4
  3. package/cjs/api-expect/api-expect-object.js +54 -0
  4. package/cjs/{expect → api-expect}/api-expect-operation-result.js +14 -6
  5. package/cjs/{expect → api-expect}/api-expect.js +30 -23
  6. package/cjs/constants.js +4 -0
  7. package/cjs/index.js +3 -22
  8. package/cjs/{expect/jest-extend → jest-extend}/common.extend.js +23 -22
  9. package/cjs/test-client.js +34 -0
  10. package/cjs/{expect/utils → utils}/object-matches.util.js +0 -0
  11. package/esm/api-expect/api-expect-collection.d.ts +19 -0
  12. package/esm/{expect/api-expect-array.js → api-expect/api-expect-collection.js} +46 -42
  13. package/esm/{expect → api-expect}/api-expect-error.d.ts +3 -3
  14. package/esm/{expect → api-expect}/api-expect-error.js +3 -4
  15. package/esm/api-expect/api-expect-object.d.ts +11 -0
  16. package/esm/api-expect/api-expect-object.js +49 -0
  17. package/esm/api-expect/api-expect-operation-result.d.ts +11 -0
  18. package/esm/{expect → api-expect}/api-expect-operation-result.js +14 -6
  19. package/esm/{expect → api-expect}/api-expect.d.ts +8 -7
  20. package/esm/{expect → api-expect}/api-expect.js +30 -23
  21. package/esm/constants.d.ts +1 -0
  22. package/esm/constants.js +1 -0
  23. package/esm/index.d.ts +2 -6
  24. package/esm/index.js +2 -19
  25. package/esm/{expect/jest-extend → jest-extend}/common.extend.d.ts +2 -2
  26. package/esm/{expect/jest-extend → jest-extend}/common.extend.js +22 -22
  27. package/esm/test-client.d.ts +22 -0
  28. package/esm/test-client.js +29 -0
  29. package/esm/{expect/utils → utils}/object-matches.util.d.ts +0 -0
  30. package/esm/{expect/utils → utils}/object-matches.util.js +0 -0
  31. package/package.json +6 -4
  32. package/cjs/api-response.js +0 -22
  33. package/cjs/expect/api-expect-object.js +0 -76
  34. package/cjs/expect/utils/print-errors.util.js +0 -15
  35. package/cjs/testers/base-operation-tester.js +0 -24
  36. package/cjs/testers/base-tester.js +0 -23
  37. package/cjs/testers/entity-create-tester.js +0 -43
  38. package/cjs/testers/entity-delete-many-tester.js +0 -27
  39. package/cjs/testers/entity-delete-tester.js +0 -24
  40. package/cjs/testers/entity-get-tester.js +0 -46
  41. package/cjs/testers/entity-search-tester.js +0 -75
  42. package/cjs/testers/entity-tester.js +0 -72
  43. package/cjs/testers/entity-update-many-tester.js +0 -31
  44. package/cjs/testers/entity-update-tester.js +0 -46
  45. package/esm/api-response.d.ts +0 -12
  46. package/esm/api-response.js +0 -18
  47. package/esm/expect/api-expect-array.d.ts +0 -17
  48. package/esm/expect/api-expect-object.d.ts +0 -12
  49. package/esm/expect/api-expect-object.js +0 -71
  50. package/esm/expect/api-expect-operation-result.d.ts +0 -9
  51. package/esm/expect/utils/print-errors.util.d.ts +0 -1
  52. package/esm/expect/utils/print-errors.util.js +0 -11
  53. package/esm/testers/base-operation-tester.d.ts +0 -8
  54. package/esm/testers/base-operation-tester.js +0 -20
  55. package/esm/testers/base-tester.d.ts +0 -13
  56. package/esm/testers/base-tester.js +0 -19
  57. package/esm/testers/entity-create-tester.d.ts +0 -17
  58. package/esm/testers/entity-create-tester.js +0 -38
  59. package/esm/testers/entity-delete-many-tester.d.ts +0 -14
  60. package/esm/testers/entity-delete-many-tester.js +0 -22
  61. package/esm/testers/entity-delete-tester.d.ts +0 -14
  62. package/esm/testers/entity-delete-tester.js +0 -19
  63. package/esm/testers/entity-get-tester.d.ts +0 -18
  64. package/esm/testers/entity-get-tester.js +0 -41
  65. package/esm/testers/entity-search-tester.d.ts +0 -22
  66. package/esm/testers/entity-search-tester.js +0 -70
  67. package/esm/testers/entity-tester.d.ts +0 -24
  68. package/esm/testers/entity-tester.js +0 -68
  69. package/esm/testers/entity-update-many-tester.d.ts +0 -16
  70. package/esm/testers/entity-update-many-tester.js +0 -26
  71. package/esm/testers/entity-update-tester.d.ts +0 -19
  72. package/esm/testers/entity-update-tester.js +0 -41
@@ -1,75 +1,73 @@
1
1
  import _ from 'lodash';
2
2
  import ruleJudgment from 'rule-judgment';
3
3
  import { $parse, ArrayExpression, BooleanLiteral, ComparisonExpression, DateLiteral, LogicalExpression, NullLiteral, NumberLiteral, ParenthesesExpression, QualifiedIdentifier, StringLiteral, TimeLiteral } from '@opra/url';
4
- export class ApiExpectArray {
4
+ export class ApiExpectCollection {
5
5
  response;
6
- constructor(response) {
6
+ _isNot;
7
+ constructor(response, _isNot = false) {
7
8
  this.response = response;
9
+ this._isNot = _isNot;
8
10
  }
9
- toMatch(expected) {
10
- try {
11
- const v = _.omitBy(expected, _.isNil);
12
- for (const item of this.response.body) {
13
- expect(item).toMatchObject(v);
14
- }
15
- }
16
- catch (e) {
17
- Error.captureStackTrace(e, this.toMatch);
18
- throw e;
19
- }
20
- return this;
11
+ get not() {
12
+ return new ApiExpectCollection(this.response, !this._isNot);
21
13
  }
22
- toContainAllKeys(keys) {
23
- try {
24
- for (const item of this.response.body) {
25
- expect(item).toContainAllKeys(keys);
26
- }
27
- }
28
- catch (e) {
29
- Error.captureStackTrace(e, this.toContainAllKeys);
30
- throw e;
31
- }
14
+ forEach(callbackfn) {
15
+ this.response.data.forEach(callbackfn);
32
16
  return this;
33
17
  }
34
- toContainKeys(keys) {
18
+ toMatch(expected) {
35
19
  try {
36
- for (const item of this.response.body) {
37
- expect(item).toContainKeys(keys);
20
+ const v = _.omitBy(expected, _.isNil);
21
+ for (const item of this.response.data) {
22
+ this._expect(item).toMatchObject(v);
38
23
  }
39
24
  }
40
25
  catch (e) {
41
- Error.captureStackTrace(e, this.toContainKeys);
26
+ Error.captureStackTrace(e, this.toMatch);
42
27
  throw e;
43
28
  }
44
29
  return this;
45
30
  }
46
- notToContainKeys(keys) {
31
+ toHaveFields(keys) {
47
32
  try {
48
- for (const item of this.response.body) {
49
- expect(item).not.toContainKeys(keys);
33
+ for (const item of this.response.data) {
34
+ this._expect(item).toHaveFields(keys);
50
35
  }
51
36
  }
52
37
  catch (e) {
53
- Error.captureStackTrace(e, this.notToContainKeys);
38
+ Error.captureStackTrace(e, this.toHaveFields);
54
39
  throw e;
55
40
  }
56
41
  return this;
57
42
  }
58
- toHaveProperty(keyPath, value) {
43
+ toHaveFieldsOnly(keys) {
59
44
  try {
60
- for (const item of this.response.body) {
61
- expect(item).toHaveProperty(keyPath, value);
45
+ for (const item of this.response.data) {
46
+ this._expect(item).toHaveFieldsOnly(keys);
62
47
  }
63
48
  }
64
49
  catch (e) {
65
- Error.captureStackTrace(e, this.toHaveProperty);
50
+ Error.captureStackTrace(e, this.toHaveFieldsOnly);
66
51
  throw e;
67
52
  }
68
53
  return this;
69
54
  }
55
+ //
56
+ // toHaveProperty(keyPath, value?): this {
57
+ // try {
58
+ // for (const item of this.response.data) {
59
+ // this._expect(item).toHaveProperty(keyPath, value);
60
+ // }
61
+ //
62
+ // } catch (e: any) {
63
+ // Error.captureStackTrace(e, this.toHaveProperty);
64
+ // throw e;
65
+ // }
66
+ // return this;
67
+ // }
70
68
  toBeSortedBy(...fields) {
71
69
  try {
72
- expect(this.response.body).toBeSortedBy(fields);
70
+ this._expect(this.response.data).toBeSortedBy(fields);
73
71
  }
74
72
  catch (e) {
75
73
  Error.captureStackTrace(e, this.toBeSortedBy);
@@ -81,9 +79,9 @@ export class ApiExpectArray {
81
79
  const f = convertFilter(filter);
82
80
  if (f) {
83
81
  const j = ruleJudgment(f);
84
- const filtered = this.response.body.filter(j);
82
+ const filtered = this.response.data.filter(j);
85
83
  try {
86
- expect(this.response.body).toStrictEqual(filtered);
84
+ this._expect(this.response.data).toStrictEqual(filtered);
87
85
  }
88
86
  catch (e) {
89
87
  Error.captureStackTrace(e, this.toBeFilteredBy);
@@ -94,7 +92,7 @@ export class ApiExpectArray {
94
92
  }
95
93
  toHaveExactItems(expected) {
96
94
  try {
97
- expect(this.response.body).toHaveLength(expected);
95
+ this._expect(this.response.data).toHaveLength(expected);
98
96
  }
99
97
  catch (e) {
100
98
  Error.captureStackTrace(e, this.toHaveExactItems);
@@ -104,7 +102,7 @@ export class ApiExpectArray {
104
102
  }
105
103
  toHaveMaxItems(expected) {
106
104
  try {
107
- expect(this.response.body.length).toBeLessThanOrEqual(expected);
105
+ this._expect(this.response.data.length).toBeLessThanOrEqual(expected);
108
106
  }
109
107
  catch (e) {
110
108
  Error.captureStackTrace(e, this.toHaveMaxItems);
@@ -114,7 +112,7 @@ export class ApiExpectArray {
114
112
  }
115
113
  toHaveMinItems(expected) {
116
114
  try {
117
- expect(this.response.body.length).toBeGreaterThanOrEqual(expected);
115
+ this._expect(this.response.data.length).toBeGreaterThanOrEqual(expected);
118
116
  }
119
117
  catch (e) {
120
118
  Error.captureStackTrace(e, this.toHaveMinItems);
@@ -122,6 +120,12 @@ export class ApiExpectArray {
122
120
  }
123
121
  return this;
124
122
  }
123
+ _expect(expected) {
124
+ const out = expect(expected);
125
+ if (this._isNot)
126
+ return out.not;
127
+ return out;
128
+ }
125
129
  }
126
130
  export function convertFilter(str) {
127
131
  const ast = typeof str === 'string' ? $parse(str) : str;
@@ -1,8 +1,8 @@
1
- import type { ApiResponse } from '../api-response';
1
+ import { ClientResponse } from '@opra/client';
2
2
  import { ApiExpectObject } from './api-expect-object.js';
3
3
  export declare class ApiExpectError extends ApiExpectObject {
4
- readonly response: ApiResponse;
5
- constructor(response: ApiResponse);
4
+ readonly response: ClientResponse;
5
+ constructor(response: ClientResponse);
6
6
  toContainDetail(...matching: any[]): void;
7
7
  }
8
8
  declare global {
@@ -1,6 +1,6 @@
1
1
  import matcherUtils from 'jest-matcher-utils';
2
+ import { objectMatches } from '../utils/object-matches.util.js';
2
3
  import { ApiExpectObject } from './api-expect-object.js';
3
- import { objectMatches } from './utils/object-matches.util.js';
4
4
  export class ApiExpectError extends ApiExpectObject {
5
5
  response;
6
6
  constructor(response) {
@@ -9,9 +9,8 @@ export class ApiExpectError extends ApiExpectObject {
9
9
  }
10
10
  toContainDetail(...matching) {
11
11
  try {
12
- expect(this.response.body['@@Schema']).toStrictEqual('Opra:Exception');
13
- expect(this.response.body.issues).toBeDefined();
14
- expect(this.response.body.issues).apiErrorDetailToContain(matching);
12
+ expect(this.response.data.issues).toBeDefined();
13
+ expect(this.response.data.issues).apiErrorDetailToContain(matching);
15
14
  }
16
15
  catch (e) {
17
16
  Error.captureStackTrace(e, this.toContainDetail);
@@ -0,0 +1,11 @@
1
+ import { ClientResponse } from '@opra/client';
2
+ export declare class ApiExpectObject {
3
+ readonly response: ClientResponse;
4
+ protected _isNot: boolean;
5
+ constructor(response: ClientResponse, _isNot?: boolean);
6
+ get not(): ApiExpectObject;
7
+ toMatch<T extends {}>(expected: T): this;
8
+ toHaveFields(fields: string[]): this;
9
+ toHaveFieldsOnly(fields: string[]): this;
10
+ protected _expect(expected: any): jest.Matchers<any>;
11
+ }
@@ -0,0 +1,49 @@
1
+ import _ from 'lodash';
2
+ export class ApiExpectObject {
3
+ response;
4
+ _isNot;
5
+ constructor(response, _isNot = false) {
6
+ this.response = response;
7
+ this._isNot = _isNot;
8
+ }
9
+ get not() {
10
+ return new ApiExpectObject(this.response, !this._isNot);
11
+ }
12
+ toMatch(expected) {
13
+ try {
14
+ const v = _.omitBy(expected, _.isNil);
15
+ this._expect(this.response.data).toMatchObject(v);
16
+ }
17
+ catch (e) {
18
+ Error.captureStackTrace(e, this.toMatch);
19
+ throw e;
20
+ }
21
+ return this;
22
+ }
23
+ toHaveFields(fields) {
24
+ try {
25
+ this._expect(this.response.data).toHaveFields(fields);
26
+ }
27
+ catch (e) {
28
+ Error.captureStackTrace(e, this.toHaveFields);
29
+ throw e;
30
+ }
31
+ return this;
32
+ }
33
+ toHaveFieldsOnly(fields) {
34
+ try {
35
+ this._expect(this.response.data).toHaveFieldsOnly(fields);
36
+ }
37
+ catch (e) {
38
+ Error.captureStackTrace(e, this.toHaveFieldsOnly);
39
+ throw e;
40
+ }
41
+ return this;
42
+ }
43
+ _expect(expected) {
44
+ const out = expect(expected);
45
+ if (this._isNot)
46
+ return out.not;
47
+ return out;
48
+ }
49
+ }
@@ -0,0 +1,11 @@
1
+ import { ClientResponse } from '@opra/client';
2
+ export declare class ApiExpectOperationResult {
3
+ readonly response: ClientResponse;
4
+ protected _isNot: boolean;
5
+ constructor(response: ClientResponse, _isNot?: boolean);
6
+ get not(): ApiExpectOperationResult;
7
+ toBeAffectedExact(expected: number): this;
8
+ toBeAffectedMin(expected: number): this;
9
+ toBeAffectedMax(expected: number): this;
10
+ protected _expect(expected: any): jest.Matchers<any>;
11
+ }
@@ -1,14 +1,16 @@
1
1
  export class ApiExpectOperationResult {
2
2
  response;
3
- constructor(response) {
3
+ _isNot;
4
+ constructor(response, _isNot = false) {
4
5
  this.response = response;
6
+ this._isNot = _isNot;
5
7
  }
6
- get body() {
7
- return this.response.body;
8
+ get not() {
9
+ return new ApiExpectOperationResult(this.response, !this._isNot);
8
10
  }
9
11
  toBeAffectedExact(expected) {
10
12
  try {
11
- expect(this.response.body.affected).toStrictEqual(expected);
13
+ this._expect(this.response.data.affected).toStrictEqual(expected);
12
14
  }
13
15
  catch (e) {
14
16
  Error.captureStackTrace(e, this.toBeAffectedExact);
@@ -18,7 +20,7 @@ export class ApiExpectOperationResult {
18
20
  }
19
21
  toBeAffectedMin(expected) {
20
22
  try {
21
- expect(this.response.body.affected).toBeGreaterThanOrEqual(expected);
23
+ this._expect(this.response.data.affected).toBeGreaterThanOrEqual(expected);
22
24
  }
23
25
  catch (e) {
24
26
  Error.captureStackTrace(e, this.toBeAffectedMin);
@@ -28,7 +30,7 @@ export class ApiExpectOperationResult {
28
30
  }
29
31
  toBeAffectedMax(expected) {
30
32
  try {
31
- expect(this.response.body.affected).toBeLessThanOrEqual(expected);
33
+ this._expect(this.response.data.affected).toBeLessThanOrEqual(expected);
32
34
  }
33
35
  catch (e) {
34
36
  Error.captureStackTrace(e, this.toBeAffectedMax);
@@ -36,4 +38,10 @@ export class ApiExpectOperationResult {
36
38
  }
37
39
  return this;
38
40
  }
41
+ _expect(expected) {
42
+ const out = expect(expected);
43
+ if (this._isNot)
44
+ return out.not;
45
+ return out;
46
+ }
39
47
  }
@@ -1,16 +1,17 @@
1
- import './jest-extend/common.extend.js';
2
- import type { ApiResponse } from '../api-response';
3
- import { ApiExpectArray } from './api-expect-array.js';
1
+ import { ClientResponse } from '@opra/client';
2
+ import { ApiExpectCollection } from './api-expect-collection.js';
4
3
  import { ApiExpectError } from './api-expect-error.js';
5
4
  import { ApiExpectObject } from './api-expect-object.js';
6
5
  import { ApiExpectOperationResult } from './api-expect-operation-result.js';
7
6
  export declare class ApiExpect {
8
- readonly response: ApiResponse;
9
- constructor(response: ApiResponse);
10
- get body(): any;
7
+ readonly response: ClientResponse;
8
+ protected _isNot: boolean;
9
+ constructor(response: ClientResponse, _isNot?: boolean);
10
+ get not(): ApiExpect;
11
11
  toSuccess(status?: number): this;
12
12
  toFail(status?: number): ApiExpectError;
13
13
  toReturnOperationResult(): ApiExpectOperationResult;
14
14
  toReturnObject(): ApiExpectObject;
15
- toReturnArray(): ApiExpectArray;
15
+ toReturnCollection(): ApiExpectCollection;
16
+ protected _expect(expected: any): jest.Matchers<any>;
16
17
  }
@@ -1,21 +1,22 @@
1
- import './jest-extend/common.extend.js';
2
- import { ApiExpectArray } from './api-expect-array.js';
1
+ import { ApiExpectCollection } from './api-expect-collection.js';
3
2
  import { ApiExpectError } from './api-expect-error.js';
4
3
  import { ApiExpectObject } from './api-expect-object.js';
5
4
  import { ApiExpectOperationResult } from './api-expect-operation-result.js';
6
5
  export class ApiExpect {
7
6
  response;
8
- constructor(response) {
7
+ _isNot;
8
+ constructor(response, _isNot = false) {
9
9
  this.response = response;
10
+ this._isNot = _isNot;
10
11
  }
11
- get body() {
12
- return this.response.body;
12
+ get not() {
13
+ return new ApiExpect(this.response, !this._isNot);
13
14
  }
14
15
  toSuccess(status = 200) {
15
- let msg = ';';
16
+ let msg = '';
16
17
  try {
17
- msg = 'Response "status" is not valid';
18
- expect(this.response.status).toStrictEqual(status);
18
+ msg = 'Unexpected "status" returned';
19
+ this._expect(this.response.status).toStrictEqual(status);
19
20
  }
20
21
  catch (e) {
21
22
  if (msg)
@@ -26,7 +27,7 @@ export class ApiExpect {
26
27
  return this;
27
28
  }
28
29
  toFail(status = 400) {
29
- let msg = ';';
30
+ let msg = '';
30
31
  try {
31
32
  msg = 'Response "status" does not match';
32
33
  if (status) {
@@ -37,8 +38,8 @@ export class ApiExpect {
37
38
  expect(this.response.status).toBeLessThanOrEqual(599);
38
39
  }
39
40
  msg = 'Api did not returned "errors"';
40
- expect(this.response.body.errors).toBeArray();
41
- expect(this.response.body.errors.length).toBeGreaterThan(0);
41
+ expect(this.response.data.errors).toBeArray();
42
+ expect(this.response.data.errors.length).toBeGreaterThan(0);
42
43
  }
43
44
  catch (e) {
44
45
  if (msg)
@@ -49,26 +50,26 @@ export class ApiExpect {
49
50
  return new ApiExpectError(this.response);
50
51
  }
51
52
  toReturnOperationResult() {
52
- let msg = ';';
53
+ let msg = '';
53
54
  try {
54
55
  msg = '"body" is empty';
55
- expect(this.response.body).toBeDefined();
56
+ expect(this.response.data).toBeDefined();
56
57
  msg = '"operation" property is empty';
57
- expect(this.response.body.operation).toBeDefined();
58
+ expect(this.response.data.operation).toBeDefined();
58
59
  }
59
60
  catch (e) {
60
61
  if (msg)
61
62
  e.message = msg + '\n\n' + e.message;
62
- Error.captureStackTrace(e, this.toReturnObject);
63
+ Error.captureStackTrace(e, this.toReturnOperationResult);
63
64
  throw e;
64
65
  }
65
66
  return new ApiExpectOperationResult(this.response);
66
67
  }
67
68
  toReturnObject() {
68
- let msg = ';';
69
+ let msg = '';
69
70
  try {
70
71
  msg = '"body" is empty';
71
- expect(this.response.body).toBeDefined();
72
+ expect(this.response.data).toBeDefined();
72
73
  }
73
74
  catch (e) {
74
75
  if (msg)
@@ -78,20 +79,26 @@ export class ApiExpect {
78
79
  }
79
80
  return new ApiExpectObject(this.response);
80
81
  }
81
- toReturnArray() {
82
- let msg = ';';
82
+ toReturnCollection() {
83
+ let msg = '';
83
84
  try {
84
85
  msg = '"body" is empty';
85
- expect(this.response.body).toBeDefined();
86
+ expect(this.response.data).toBeDefined();
86
87
  msg = '"body" is not an array';
87
- expect(this.response.body).toBeArray();
88
+ expect(this.response.data).toBeArray();
88
89
  }
89
90
  catch (e) {
90
91
  if (msg)
91
92
  e.message = msg + '\n\n' + e.message;
92
- Error.captureStackTrace(e, this.toReturnArray);
93
+ Error.captureStackTrace(e, this.toReturnCollection);
93
94
  throw e;
94
95
  }
95
- return new ApiExpectArray(this.response);
96
+ return new ApiExpectCollection(this.response);
97
+ }
98
+ _expect(expected) {
99
+ const out = expect(expected);
100
+ if (this._isNot)
101
+ return out.not;
102
+ return out;
96
103
  }
97
104
  }
@@ -0,0 +1 @@
1
+ export declare const expectSymbolTag: unique symbol;
@@ -0,0 +1 @@
1
+ export const expectSymbolTag = Symbol('opra.test.expect');
package/esm/index.d.ts CHANGED
@@ -1,6 +1,2 @@
1
- import { BaseTester, OpraTesterParams } from './testers/base-tester.js';
2
- import { OpraEntityTester } from './testers/entity-tester.js';
3
- export declare function opraTestClient(app: any, options?: Partial<Omit<OpraTesterParams, 'app'>>): OpraTester;
4
- export declare class OpraTester extends BaseTester {
5
- entity(path: string): OpraEntityTester;
6
- }
1
+ import './jest-extend/common.extend.js';
2
+ export * from './test-client.js';
package/esm/index.js CHANGED
@@ -1,19 +1,2 @@
1
- import { BaseTester } from './testers/base-tester.js';
2
- import { OpraEntityTester } from './testers/entity-tester.js';
3
- export function opraTestClient(app, options) {
4
- return new OpraTester({
5
- app,
6
- ...options,
7
- prefix: options?.prefix || '',
8
- headers: options?.headers || {}
9
- });
10
- }
11
- export class OpraTester extends BaseTester {
12
- entity(path) {
13
- return new OpraEntityTester({
14
- ...this._params,
15
- headers: { ...this._params.headers },
16
- path
17
- });
18
- }
19
- }
1
+ import './jest-extend/common.extend.js';
2
+ export * from './test-client.js';
@@ -1,8 +1,8 @@
1
1
  declare global {
2
2
  namespace jest {
3
3
  interface Matchers<R> {
4
- toContainKeys(expected: string[]): any;
5
- toContainAllKeys(expected: string[]): any;
4
+ toHaveFields(expected: string[]): any;
5
+ toHaveFieldsOnly(expected: string[]): any;
6
6
  toBeArray(): any;
7
7
  toBeSorted(compareFn?: (a: any, b: any) => number): any;
8
8
  toBeSortedBy(properties: string[]): any;
@@ -1,30 +1,30 @@
1
+ import colors from "ansi-colors";
1
2
  import { matcherHint, printExpected, printReceived } from 'jest-matcher-utils';
2
3
  expect.extend({
3
- toContainKeys(received, expected) {
4
- if (typeof received === 'object') {
5
- const keys = Array.isArray(expected) ? expected : Object.keys(expected);
6
- const additionalKeys = Object.keys(received).filter(x => !keys.includes(x));
7
- if (!Object.keys(received).find(x => keys.includes(x))) {
8
- return {
9
- pass: false,
10
- message: () => `Object contains unexpected additional keys (${additionalKeys})`
11
- };
12
- }
4
+ toHaveFields(received, expected) {
5
+ const expectedKeys = (Array.isArray(expected) ? expected : Object.keys(expected)).map(x => x.toLowerCase());
6
+ const objectKeys = Object.keys(received).map(x => x.toLowerCase());
7
+ const filteredKeys = expectedKeys.filter(x => !objectKeys.includes(x));
8
+ const pass = !filteredKeys.length === !this.isNot;
9
+ if (!pass) {
10
+ const message = () => `Expects keys to${this.isNot ? ' not' : ''} contain: ${colors.yellow('' + expectedKeys)}\n` +
11
+ `${this.isNot ? 'Unsolicited' : 'Missing'} fields: ${colors.yellow('' + filteredKeys)}\n`;
12
+ return { message, pass: !!this.isNot };
13
13
  }
14
- return { actual: received, pass: true, message: () => '' };
14
+ return { actual: received, pass: !this.isNot, message: () => '' };
15
15
  },
16
- toContainAllKeys(received, expected) {
17
- if (typeof received === 'object') {
18
- const keys = Array.isArray(expected) ? expected : Object.keys(expected);
19
- const additionalKeys = Object.keys(received).filter(x => !keys.includes(x));
20
- if (additionalKeys.length) {
21
- return {
22
- pass: false,
23
- message: () => `Object contains unexpected additional keys (${additionalKeys})`
24
- };
25
- }
16
+ toHaveFieldsOnly(received, expected) {
17
+ const expectedKeys = (Array.isArray(expected) ? expected : Object.keys(expected)).map(x => x.toLowerCase());
18
+ const objectKeys = Object.keys(received).map(x => x.toLowerCase());
19
+ const filteredKeys = objectKeys.filter(x => !expectedKeys.includes(x));
20
+ const pass = !filteredKeys.length === !this.isNot;
21
+ if (!pass) {
22
+ const message = () => `${!this.isNot ? 'Do not expects' : 'Expects'} additional keys other than: ${colors.yellow('' + expectedKeys)}\n` +
23
+ (filteredKeys ? `Additional keys received: ${colors.yellow('' + filteredKeys)}\n` :
24
+ 'No additional keys received\n');
25
+ return { message, pass };
26
26
  }
27
- return { actual: received, pass: true, message: () => '' };
27
+ return { actual: received, pass: !this.isNot, message: () => '' };
28
28
  },
29
29
  toBeArray(received) {
30
30
  if (Array.isArray(received)) {
@@ -0,0 +1,22 @@
1
+ /// <reference types="node" />
2
+ import { AxiosRequestConfig } from 'axios';
3
+ import { IncomingMessage, Server, ServerResponse } from 'http';
4
+ import { Type } from 'ts-gems';
5
+ import { ClientResponse, CollectionNode, OpraClient, OpraClientOptions } from '@opra/client';
6
+ import { SingletonNode } from '@opra/client/src/services/singleton-node';
7
+ import { OpraDocument } from '@opra/schema/src/index';
8
+ import { ApiExpect } from './api-expect/api-expect.js';
9
+ declare type RequestListener = (req: IncomingMessage, res: ServerResponse) => void;
10
+ declare type Handler = RequestListener | Server;
11
+ declare type OpraTestResponse<T = any> = ClientResponse<T> & {
12
+ expect: ApiExpect;
13
+ };
14
+ export declare class OpraTestClient extends OpraClient {
15
+ constructor(app: Handler, options?: OpraClientOptions);
16
+ constructor(app: Handler, metadata: OpraDocument, options?: OpraClientOptions);
17
+ collection<T = any, TResponse extends OpraTestResponse<T> = OpraTestResponse<T>>(name: string): CollectionNode<T, TResponse>;
18
+ singleton<T = any, TResponse extends OpraTestResponse<T> = OpraTestResponse<T>>(name: string): SingletonNode<T, TResponse>;
19
+ protected _send<TResponse extends OpraTestResponse>(req: AxiosRequestConfig): Promise<TResponse>;
20
+ static create<T extends OpraTestClient>(this: Type<T>, app: Handler, options?: OpraClientOptions): Promise<T>;
21
+ }
22
+ export {};
@@ -0,0 +1,29 @@
1
+ import * as axiosist from 'axiosist';
2
+ import { OpraClient } from '@opra/client';
3
+ import { ApiExpect } from './api-expect/api-expect.js';
4
+ export class OpraTestClient extends OpraClient {
5
+ constructor(app, arg1, arg2) {
6
+ super('/', arg1, arg2);
7
+ this._axios.defaults.adapter = axiosist.createAdapter(app);
8
+ this._axios.defaults.validateStatus = () => true;
9
+ }
10
+ // @ts-ignore
11
+ collection(name) {
12
+ return super.collection(name);
13
+ }
14
+ // @ts-ignore
15
+ singleton(name) {
16
+ return super.singleton(name);
17
+ }
18
+ // @ts-ignore
19
+ async _send(req) {
20
+ const resp = (await super._send(req));
21
+ resp.expect = new ApiExpect(resp);
22
+ return resp;
23
+ }
24
+ static async create(app, options) {
25
+ const client = new this(app, options);
26
+ await client.init();
27
+ return client;
28
+ }
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/testing",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Opra testing package",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -25,11 +25,13 @@
25
25
  "clean:cover": "rimraf ../../coverage/testing"
26
26
  },
27
27
  "dependencies": {
28
- "@opra/schema": "^0.3.0",
29
- "@opra/url": "^0.3.0",
28
+ "@opra/schema": "^0.5.0",
29
+ "@opra/url": "^0.5.0",
30
+ "@opra/client": "^0.5.0",
31
+ "ansi-colors": "^4.1.3",
30
32
  "lodash": "^4.17.21",
31
33
  "rule-judgment": "^1.1.5",
32
- "supertest": "^6.2.4"
34
+ "supertest": "^6.3.0"
33
35
  },
34
36
  "devDependencies": {
35
37
  "@types/supertest": "^2.0.12"