ai-tests 2.0.2 → 2.1.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/.turbo/turbo-build.log +4 -5
- package/.turbo/turbo-test.log +4 -0
- package/CHANGELOG.md +9 -0
- package/package.json +2 -3
- package/src/assertions.js +383 -0
- package/src/cli.js +76 -0
- package/src/index.js +18 -0
- package/src/local.js +62 -0
- package/src/runner.js +214 -0
- package/src/types.js +4 -0
- package/src/worker.js +91 -0
- package/test/assertions.test.js +493 -0
- package/test/index.test.js +42 -0
- package/test/local.test.js +27 -0
- package/test/runner.test.js +315 -0
- package/test/worker.test.js +162 -0
- package/vitest.config.js +10 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { TestRunner, createRunner } from '../src/runner.js';
|
|
3
|
+
describe('TestRunner', () => {
|
|
4
|
+
let runner;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
runner = createRunner();
|
|
7
|
+
});
|
|
8
|
+
describe('createRunner()', () => {
|
|
9
|
+
it('creates a new TestRunner instance', () => {
|
|
10
|
+
expect(runner).toBeInstanceOf(TestRunner);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
describe('describe()', () => {
|
|
14
|
+
it('groups tests with a suite name', async () => {
|
|
15
|
+
runner.describe('math', () => {
|
|
16
|
+
runner.it('adds', () => { });
|
|
17
|
+
});
|
|
18
|
+
const results = await runner.run();
|
|
19
|
+
expect(results.tests[0].name).toBe('math > adds');
|
|
20
|
+
});
|
|
21
|
+
it('supports nested describes', async () => {
|
|
22
|
+
runner.describe('outer', () => {
|
|
23
|
+
runner.describe('inner', () => {
|
|
24
|
+
runner.it('test', () => { });
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
const results = await runner.run();
|
|
28
|
+
expect(results.tests[0].name).toBe('outer > inner > test');
|
|
29
|
+
});
|
|
30
|
+
it('restores previous suite after describe', async () => {
|
|
31
|
+
runner.describe('first', () => {
|
|
32
|
+
runner.it('test1', () => { });
|
|
33
|
+
});
|
|
34
|
+
runner.it('standalone', () => { });
|
|
35
|
+
const results = await runner.run();
|
|
36
|
+
expect(results.tests[0].name).toBe('first > test1');
|
|
37
|
+
expect(results.tests[1].name).toBe('standalone');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('it()', () => {
|
|
41
|
+
it('registers a test', async () => {
|
|
42
|
+
runner.it('my test', () => { });
|
|
43
|
+
const results = await runner.run();
|
|
44
|
+
expect(results.total).toBe(1);
|
|
45
|
+
expect(results.tests[0].name).toBe('my test');
|
|
46
|
+
});
|
|
47
|
+
it('test() is alias for it()', async () => {
|
|
48
|
+
runner.test('my test', () => { });
|
|
49
|
+
const results = await runner.run();
|
|
50
|
+
expect(results.total).toBe(1);
|
|
51
|
+
});
|
|
52
|
+
it('passes for successful tests', async () => {
|
|
53
|
+
runner.it('passes', () => {
|
|
54
|
+
// No error
|
|
55
|
+
});
|
|
56
|
+
const results = await runner.run();
|
|
57
|
+
expect(results.passed).toBe(1);
|
|
58
|
+
expect(results.failed).toBe(0);
|
|
59
|
+
});
|
|
60
|
+
it('fails for throwing tests', async () => {
|
|
61
|
+
runner.it('fails', () => {
|
|
62
|
+
throw new Error('test error');
|
|
63
|
+
});
|
|
64
|
+
const results = await runner.run();
|
|
65
|
+
expect(results.passed).toBe(0);
|
|
66
|
+
expect(results.failed).toBe(1);
|
|
67
|
+
expect(results.tests[0].error).toContain('test error');
|
|
68
|
+
});
|
|
69
|
+
it('supports async tests', async () => {
|
|
70
|
+
runner.it('async', async () => {
|
|
71
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
72
|
+
});
|
|
73
|
+
const results = await runner.run();
|
|
74
|
+
expect(results.passed).toBe(1);
|
|
75
|
+
});
|
|
76
|
+
it('catches async errors', async () => {
|
|
77
|
+
runner.it('async fail', async () => {
|
|
78
|
+
await Promise.reject(new Error('async error'));
|
|
79
|
+
});
|
|
80
|
+
const results = await runner.run();
|
|
81
|
+
expect(results.failed).toBe(1);
|
|
82
|
+
expect(results.tests[0].error).toContain('async error');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('skip()', () => {
|
|
86
|
+
it('marks test as skipped', async () => {
|
|
87
|
+
runner.skip('skipped test', () => {
|
|
88
|
+
throw new Error('should not run');
|
|
89
|
+
});
|
|
90
|
+
const results = await runner.run();
|
|
91
|
+
expect(results.total).toBe(1);
|
|
92
|
+
expect(results.skipped).toBe(1);
|
|
93
|
+
expect(results.passed).toBe(0);
|
|
94
|
+
expect(results.failed).toBe(0);
|
|
95
|
+
expect(results.tests[0].skipped).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
it('works without fn argument', async () => {
|
|
98
|
+
runner.skip('skipped');
|
|
99
|
+
const results = await runner.run();
|
|
100
|
+
expect(results.skipped).toBe(1);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('only()', () => {
|
|
104
|
+
it('runs only marked tests', async () => {
|
|
105
|
+
runner.it('normal', () => { });
|
|
106
|
+
runner.only('only', () => { });
|
|
107
|
+
const results = await runner.run();
|
|
108
|
+
expect(results.total).toBe(1);
|
|
109
|
+
expect(results.tests[0].name).toBe('only');
|
|
110
|
+
});
|
|
111
|
+
it('still includes skipped tests when only is used', async () => {
|
|
112
|
+
runner.it('normal', () => { });
|
|
113
|
+
runner.only('only', () => { });
|
|
114
|
+
runner.skip('skipped', () => { });
|
|
115
|
+
const results = await runner.run();
|
|
116
|
+
expect(results.total).toBe(2);
|
|
117
|
+
expect(results.tests.find(t => t.name === 'only')).toBeDefined();
|
|
118
|
+
expect(results.tests.find(t => t.name === 'skipped')).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('beforeEach()', () => {
|
|
122
|
+
it('runs before each test', async () => {
|
|
123
|
+
let count = 0;
|
|
124
|
+
runner.beforeEach(() => {
|
|
125
|
+
count++;
|
|
126
|
+
});
|
|
127
|
+
runner.it('test1', () => { });
|
|
128
|
+
runner.it('test2', () => { });
|
|
129
|
+
await runner.run();
|
|
130
|
+
expect(count).toBe(2);
|
|
131
|
+
});
|
|
132
|
+
it('hooks are scoped to describe blocks', async () => {
|
|
133
|
+
let count = 0;
|
|
134
|
+
runner.describe('suite', () => {
|
|
135
|
+
runner.beforeEach(() => {
|
|
136
|
+
count++;
|
|
137
|
+
});
|
|
138
|
+
runner.it('inside', () => { });
|
|
139
|
+
});
|
|
140
|
+
runner.it('outside', () => { });
|
|
141
|
+
await runner.run();
|
|
142
|
+
expect(count).toBe(1);
|
|
143
|
+
});
|
|
144
|
+
it('supports async hooks', async () => {
|
|
145
|
+
let value = 0;
|
|
146
|
+
runner.beforeEach(async () => {
|
|
147
|
+
await new Promise(resolve => setTimeout(resolve, 1));
|
|
148
|
+
value = 42;
|
|
149
|
+
});
|
|
150
|
+
runner.it('test', () => {
|
|
151
|
+
if (value !== 42)
|
|
152
|
+
throw new Error('hook did not run');
|
|
153
|
+
});
|
|
154
|
+
const results = await runner.run();
|
|
155
|
+
expect(results.passed).toBe(1);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe('afterEach()', () => {
|
|
159
|
+
it('runs after each test', async () => {
|
|
160
|
+
let count = 0;
|
|
161
|
+
runner.afterEach(() => {
|
|
162
|
+
count++;
|
|
163
|
+
});
|
|
164
|
+
runner.it('test1', () => { });
|
|
165
|
+
runner.it('test2', () => { });
|
|
166
|
+
await runner.run();
|
|
167
|
+
expect(count).toBe(2);
|
|
168
|
+
});
|
|
169
|
+
it('runs only for passing tests (current behavior)', async () => {
|
|
170
|
+
let count = 0;
|
|
171
|
+
runner.afterEach(() => {
|
|
172
|
+
count++;
|
|
173
|
+
});
|
|
174
|
+
runner.it('passing', () => { });
|
|
175
|
+
runner.it('failing', () => {
|
|
176
|
+
throw new Error('fail');
|
|
177
|
+
});
|
|
178
|
+
await runner.run();
|
|
179
|
+
// Currently afterEach only runs for passing tests
|
|
180
|
+
expect(count).toBe(1);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('beforeAll()', () => {
|
|
184
|
+
it('runs once before all tests', async () => {
|
|
185
|
+
let count = 0;
|
|
186
|
+
runner.beforeAll(() => {
|
|
187
|
+
count++;
|
|
188
|
+
});
|
|
189
|
+
runner.it('test1', () => { });
|
|
190
|
+
runner.it('test2', () => { });
|
|
191
|
+
await runner.run();
|
|
192
|
+
expect(count).toBe(1);
|
|
193
|
+
});
|
|
194
|
+
it('fails all tests if beforeAll throws', async () => {
|
|
195
|
+
runner.beforeAll(() => {
|
|
196
|
+
throw new Error('setup failed');
|
|
197
|
+
});
|
|
198
|
+
runner.it('test1', () => { });
|
|
199
|
+
runner.it('test2', () => { });
|
|
200
|
+
const results = await runner.run();
|
|
201
|
+
expect(results.failed).toBe(2);
|
|
202
|
+
expect(results.tests[0].error).toContain('beforeAll hook failed');
|
|
203
|
+
expect(results.tests[1].error).toContain('beforeAll hook failed');
|
|
204
|
+
});
|
|
205
|
+
it('supports async hooks', async () => {
|
|
206
|
+
let value = 0;
|
|
207
|
+
runner.beforeAll(async () => {
|
|
208
|
+
await new Promise(resolve => setTimeout(resolve, 1));
|
|
209
|
+
value = 42;
|
|
210
|
+
});
|
|
211
|
+
runner.it('test', () => {
|
|
212
|
+
if (value !== 42)
|
|
213
|
+
throw new Error('hook did not run');
|
|
214
|
+
});
|
|
215
|
+
const results = await runner.run();
|
|
216
|
+
expect(results.passed).toBe(1);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
describe('afterAll()', () => {
|
|
220
|
+
it('runs once after all tests', async () => {
|
|
221
|
+
let count = 0;
|
|
222
|
+
runner.afterAll(() => {
|
|
223
|
+
count++;
|
|
224
|
+
});
|
|
225
|
+
runner.it('test1', () => { });
|
|
226
|
+
runner.it('test2', () => { });
|
|
227
|
+
await runner.run();
|
|
228
|
+
expect(count).toBe(1);
|
|
229
|
+
});
|
|
230
|
+
it('runs even if tests fail', async () => {
|
|
231
|
+
let ran = false;
|
|
232
|
+
runner.afterAll(() => {
|
|
233
|
+
ran = true;
|
|
234
|
+
});
|
|
235
|
+
runner.it('failing', () => {
|
|
236
|
+
throw new Error('fail');
|
|
237
|
+
});
|
|
238
|
+
await runner.run();
|
|
239
|
+
expect(ran).toBe(true);
|
|
240
|
+
});
|
|
241
|
+
it('does not fail tests if afterAll throws', async () => {
|
|
242
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
243
|
+
runner.it('test', () => { });
|
|
244
|
+
runner.afterAll(() => {
|
|
245
|
+
throw new Error('cleanup failed');
|
|
246
|
+
});
|
|
247
|
+
const results = await runner.run();
|
|
248
|
+
expect(results.passed).toBe(1);
|
|
249
|
+
expect(results.failed).toBe(0);
|
|
250
|
+
consoleSpy.mockRestore();
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
describe('reset()', () => {
|
|
254
|
+
it('clears all tests', async () => {
|
|
255
|
+
runner.it('test', () => { });
|
|
256
|
+
runner.reset();
|
|
257
|
+
const results = await runner.run();
|
|
258
|
+
expect(results.total).toBe(0);
|
|
259
|
+
});
|
|
260
|
+
it('clears all hooks', async () => {
|
|
261
|
+
let count = 0;
|
|
262
|
+
runner.beforeEach(() => { count++; });
|
|
263
|
+
runner.afterEach(() => { count++; });
|
|
264
|
+
runner.beforeAll(() => { count++; });
|
|
265
|
+
runner.afterAll(() => { count++; });
|
|
266
|
+
runner.reset();
|
|
267
|
+
runner.it('test', () => { });
|
|
268
|
+
await runner.run();
|
|
269
|
+
expect(count).toBe(0);
|
|
270
|
+
});
|
|
271
|
+
it('clears current suite', async () => {
|
|
272
|
+
runner.describe('suite', () => {
|
|
273
|
+
runner.reset();
|
|
274
|
+
runner.it('test', () => { });
|
|
275
|
+
});
|
|
276
|
+
const results = await runner.run();
|
|
277
|
+
expect(results.tests[0].name).toBe('test');
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
describe('run()', () => {
|
|
281
|
+
it('returns correct totals', async () => {
|
|
282
|
+
runner.it('pass1', () => { });
|
|
283
|
+
runner.it('pass2', () => { });
|
|
284
|
+
runner.it('fail', () => { throw new Error(); });
|
|
285
|
+
runner.skip('skip', () => { });
|
|
286
|
+
const results = await runner.run();
|
|
287
|
+
expect(results.total).toBe(4);
|
|
288
|
+
expect(results.passed).toBe(2);
|
|
289
|
+
expect(results.failed).toBe(1);
|
|
290
|
+
expect(results.skipped).toBe(1);
|
|
291
|
+
});
|
|
292
|
+
it('tracks test durations', async () => {
|
|
293
|
+
runner.it('test', async () => {
|
|
294
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
295
|
+
});
|
|
296
|
+
const results = await runner.run();
|
|
297
|
+
expect(results.tests[0].duration).toBeGreaterThanOrEqual(10);
|
|
298
|
+
});
|
|
299
|
+
it('tracks total duration', async () => {
|
|
300
|
+
runner.it('test', async () => {
|
|
301
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
302
|
+
});
|
|
303
|
+
const results = await runner.run();
|
|
304
|
+
expect(results.duration).toBeGreaterThanOrEqual(10);
|
|
305
|
+
});
|
|
306
|
+
it('returns empty results for no tests', async () => {
|
|
307
|
+
const results = await runner.run();
|
|
308
|
+
expect(results.total).toBe(0);
|
|
309
|
+
expect(results.passed).toBe(0);
|
|
310
|
+
expect(results.failed).toBe(0);
|
|
311
|
+
expect(results.skipped).toBe(0);
|
|
312
|
+
expect(results.tests).toEqual([]);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
});
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { TestServiceCore, TestService } from '../src/worker.js';
|
|
3
|
+
import { Assertion } from '../src/assertions.js';
|
|
4
|
+
import { TestRunner } from '../src/runner.js';
|
|
5
|
+
describe('TestServiceCore', () => {
|
|
6
|
+
let service;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
service = new TestServiceCore();
|
|
9
|
+
});
|
|
10
|
+
describe('constructor', () => {
|
|
11
|
+
it('creates a new TestServiceCore instance', () => {
|
|
12
|
+
expect(service).toBeInstanceOf(TestServiceCore);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
describe('expect()', () => {
|
|
16
|
+
it('returns an Assertion', () => {
|
|
17
|
+
const assertion = service.expect(42);
|
|
18
|
+
expect(assertion).toBeInstanceOf(Assertion);
|
|
19
|
+
});
|
|
20
|
+
it('accepts optional message', () => {
|
|
21
|
+
const assertion = service.expect(42, 'custom message');
|
|
22
|
+
expect(assertion).toBeInstanceOf(Assertion);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe('should()', () => {
|
|
26
|
+
it('returns an Assertion', () => {
|
|
27
|
+
const assertion = service.should(42);
|
|
28
|
+
expect(assertion).toBeInstanceOf(Assertion);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('assert', () => {
|
|
32
|
+
it('returns chai assert object', () => {
|
|
33
|
+
expect(service.assert).toBeDefined();
|
|
34
|
+
expect(typeof service.assert.equal).toBe('function');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe('describe()', () => {
|
|
38
|
+
it('delegates to runner', async () => {
|
|
39
|
+
service.describe('suite', () => {
|
|
40
|
+
service.it('test', () => { });
|
|
41
|
+
});
|
|
42
|
+
const results = await service.run();
|
|
43
|
+
expect(results.tests[0].name).toBe('suite > test');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('it()', () => {
|
|
47
|
+
it('delegates to runner', async () => {
|
|
48
|
+
service.it('test', () => { });
|
|
49
|
+
const results = await service.run();
|
|
50
|
+
expect(results.total).toBe(1);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('test()', () => {
|
|
54
|
+
it('is alias for it', async () => {
|
|
55
|
+
service.test('test', () => { });
|
|
56
|
+
const results = await service.run();
|
|
57
|
+
expect(results.total).toBe(1);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('skip()', () => {
|
|
61
|
+
it('delegates to runner', async () => {
|
|
62
|
+
service.skip('skipped', () => { });
|
|
63
|
+
const results = await service.run();
|
|
64
|
+
expect(results.skipped).toBe(1);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('only()', () => {
|
|
68
|
+
it('delegates to runner', async () => {
|
|
69
|
+
service.it('normal', () => { });
|
|
70
|
+
service.only('only', () => { });
|
|
71
|
+
const results = await service.run();
|
|
72
|
+
expect(results.total).toBe(1);
|
|
73
|
+
expect(results.tests[0].name).toBe('only');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('beforeEach()', () => {
|
|
77
|
+
it('delegates to runner', async () => {
|
|
78
|
+
let count = 0;
|
|
79
|
+
service.beforeEach(() => { count++; });
|
|
80
|
+
service.it('test1', () => { });
|
|
81
|
+
service.it('test2', () => { });
|
|
82
|
+
await service.run();
|
|
83
|
+
expect(count).toBe(2);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe('afterEach()', () => {
|
|
87
|
+
it('delegates to runner', async () => {
|
|
88
|
+
let count = 0;
|
|
89
|
+
service.afterEach(() => { count++; });
|
|
90
|
+
service.it('test1', () => { });
|
|
91
|
+
service.it('test2', () => { });
|
|
92
|
+
await service.run();
|
|
93
|
+
expect(count).toBe(2);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('beforeAll()', () => {
|
|
97
|
+
it('delegates to runner', async () => {
|
|
98
|
+
let count = 0;
|
|
99
|
+
service.beforeAll(() => { count++; });
|
|
100
|
+
service.it('test1', () => { });
|
|
101
|
+
service.it('test2', () => { });
|
|
102
|
+
await service.run();
|
|
103
|
+
expect(count).toBe(1);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('afterAll()', () => {
|
|
107
|
+
it('delegates to runner', async () => {
|
|
108
|
+
let count = 0;
|
|
109
|
+
service.afterAll(() => { count++; });
|
|
110
|
+
service.it('test1', () => { });
|
|
111
|
+
service.it('test2', () => { });
|
|
112
|
+
await service.run();
|
|
113
|
+
expect(count).toBe(1);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('run()', () => {
|
|
117
|
+
it('returns test results', async () => {
|
|
118
|
+
service.it('pass', () => { });
|
|
119
|
+
service.it('fail', () => { throw new Error('fail'); });
|
|
120
|
+
const results = await service.run();
|
|
121
|
+
expect(results.total).toBe(2);
|
|
122
|
+
expect(results.passed).toBe(1);
|
|
123
|
+
expect(results.failed).toBe(1);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
describe('reset()', () => {
|
|
127
|
+
it('clears all tests and hooks', async () => {
|
|
128
|
+
service.it('test', () => { });
|
|
129
|
+
service.beforeEach(() => { });
|
|
130
|
+
service.reset();
|
|
131
|
+
const results = await service.run();
|
|
132
|
+
expect(results.total).toBe(0);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('createRunner()', () => {
|
|
136
|
+
it('returns a new TestRunner', () => {
|
|
137
|
+
const runner = service.createRunner();
|
|
138
|
+
expect(runner).toBeInstanceOf(TestRunner);
|
|
139
|
+
});
|
|
140
|
+
it('returns independent runner', async () => {
|
|
141
|
+
service.it('service test', () => { });
|
|
142
|
+
const runner = service.createRunner();
|
|
143
|
+
runner.it('runner test', () => { });
|
|
144
|
+
const serviceResults = await service.run();
|
|
145
|
+
const runnerResults = await runner.run();
|
|
146
|
+
expect(serviceResults.total).toBe(1);
|
|
147
|
+
expect(runnerResults.total).toBe(1);
|
|
148
|
+
expect(serviceResults.tests[0].name).toBe('service test');
|
|
149
|
+
expect(runnerResults.tests[0].name).toBe('runner test');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('TestService (WorkerEntrypoint)', () => {
|
|
154
|
+
it('exports TestService class', async () => {
|
|
155
|
+
const { default: TestServiceClass } = await import('../src/worker.js');
|
|
156
|
+
expect(TestServiceClass).toBeDefined();
|
|
157
|
+
expect(typeof TestServiceClass).toBe('function');
|
|
158
|
+
});
|
|
159
|
+
it('TestService has connect method in prototype', () => {
|
|
160
|
+
expect(typeof TestService.prototype.connect).toBe('function');
|
|
161
|
+
});
|
|
162
|
+
});
|