Skip to content

Commit 2b5f78b

Browse files
fix(operators): marble testing
1 parent 3fb4fd0 commit 2b5f78b

14 files changed

+292
-161
lines changed

package-lock.json

Lines changed: 19 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/operators/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
},
2020
"dependencies": {
2121
"@rxjs-collection/observables": "*",
22+
"ansi-colors": "^4.1.3",
23+
"consola": "^3.2.3",
2224
"fast-equals": "5.0.1",
2325
"rxjs": "7.8.1"
2426
},

packages/operators/src/log.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
1-
import { Observable } from 'rxjs';
1+
import { bgGreen } from 'ansi-colors';
2+
import debug from 'debug';
3+
import { connectable, finalize, Observable, Subject } from 'rxjs';
24

3-
export const log = (active = true) => {
4-
if (active) {
5+
export const enableLog = tag => {
6+
debug.enable(tag);
7+
};
8+
9+
export const log = tag => {
10+
var logger = debug(tag);
11+
logger.log = console.log.bind(console);
12+
var error = debug(`${tag}:error`);
13+
14+
if (debug.enabled(tag)) {
515
return source => {
616
return new Observable(observer => {
717
return source.subscribe(
818
val => {
9-
console.log(val);
19+
logger(val);
1020
observer.next(val);
1121
},
1222
err => {
13-
console.error(err);
23+
error(err);
1424
observer.error(err);
1525
},
1626
() => {
17-
console.log('%ccomplete', 'color: green');
27+
logger(bgGreen.bold('Complete!'));
1828
observer.complete();
1929
}
2030
);
@@ -24,3 +34,15 @@ export const log = (active = true) => {
2434
return source => source;
2535
}
2636
};
37+
38+
export const logResult = (tag, observable) => {
39+
return new Promise(done => {
40+
connectable(
41+
observable.pipe(
42+
log(tag),
43+
finalize(() => done())
44+
),
45+
{ connector: () => new Subject() }
46+
).connect();
47+
});
48+
};

packages/operators/src/request/autoPagination.test.js

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { concatAll, concatMap, delay, from, map, of, toArray } from 'rxjs';
22
import { TestScheduler } from 'rxjs/testing';
3-
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
3+
import { afterAll, afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
44

5-
import { log } from '../log';
5+
import { log, logOutput, logResult } from '../log';
66
import { resolveJSON } from './response';
77

8-
describe('auto pagination - mocked', function () {
8+
describe('auto pagination - mocked', () => {
99
const testScheduler = new TestScheduler((actual, expected) => {
1010
expect(actual).to.eql(expected);
1111
});
1212

13-
beforeEach(function () {
13+
beforeEach(() => {
1414
vi.doMock('./request', importOriginal => ({
1515
request: () => source => source.pipe(concatMap(({ v, t }) => of(v).pipe(delay(t))))
1616
}));
@@ -25,6 +25,10 @@ describe('auto pagination - mocked', function () {
2525
vi.doUnmock('./request');
2626
});
2727

28+
afterAll(() => {
29+
vi.resetModules();
30+
});
31+
2832
test('classic testing', async () => {
2933
const { autoPagination } = await import('./autoPagination');
3034

@@ -76,47 +80,41 @@ describe('auto pagination - mocked', function () {
7680
autoPagination({
7781
resolveRoute: (conf, resp) =>
7882
((!resp || resp.next) && [triggerVal[resp?.next || 'a']]) || []
79-
})
83+
}),
84+
log('marble:result')
8085
)
8186
).toBe('---a----b--cd---e----', expectedVal);
8287
});
8388
});
8489
});
8590

86-
describe.skip('auto pagination - demo', function () {
87-
beforeEach(function () {
88-
vi.resetModules();
89-
});
90-
91-
test('sample testing', async function () {
91+
describe('auto pagination - demo', () => {
92+
test('sample testing', async () => {
9293
const { autoPagination } = await import('./autoPagination');
9394

94-
return new Promise(done => {
95-
return of(new URL('https://dummyjson.com/products'))
96-
.pipe(
97-
autoPagination({
98-
resolveRoute: async (url, resp) => {
99-
const data = (await resp?.json()) || { skip: -10, limit: 10 };
100-
101-
if (!data.total || data.total > data.skip + data.limit) {
102-
const newUrl = new URL(`${url}`);
103-
newUrl.searchParams.set('skip', data.skip + data.limit);
104-
newUrl.searchParams.set('limit', data.limit);
105-
newUrl.searchParams.set('select', 'title,price');
106-
return newUrl;
107-
}
95+
await logResult(
96+
'demo',
97+
of(new URL('https://dummyjson.com/products')).pipe(
98+
autoPagination({
99+
resolveRoute: async (url, resp) => {
100+
const data = (await resp?.json()) || { skip: -10, limit: 10 };
101+
102+
if (!data.total || data.total > data.skip + data.limit) {
103+
const newUrl = new URL(`${url}`);
104+
newUrl.searchParams.set('skip', data.skip + data.limit);
105+
newUrl.searchParams.set('limit', data.limit);
106+
newUrl.searchParams.set('select', 'title,price');
107+
return newUrl;
108108
}
109-
}),
110-
log(false),
111-
resolveJSON(),
112-
log(false),
113-
map(({ products }) => products),
114-
concatAll()
115-
)
116-
.subscribe({
117-
next: e => console.log(e),
118-
complete: () => done()
119-
});
120-
});
109+
}
110+
}),
111+
log('demo:response'),
112+
resolveJSON(),
113+
log('demo:response:json'),
114+
map(({ products }) => products),
115+
log('demo:response:result'),
116+
concatAll()
117+
)
118+
);
121119
});
122120
});

packages/operators/src/request/cache.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ export const cache = ttl => {
44
return source =>
55
source.pipe(
66
share({
7-
// TODO: check if a buffer size is neccessary
87
connector: () => new ReplaySubject(),
9-
// resetOnError: false,
108
resetOnComplete: () => timer(ttl),
11-
resetOnRefCountZero: false
9+
resetOnRefCountZero: () => timer(ttl)
1210
})
1311
);
1412
};

packages/operators/src/request/cache.test.js

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
11
import fetchMock from 'fetch-mock';
2-
import { defer, delay, from, interval, map, mapTo, of, tap, throttleTime } from 'rxjs';
2+
import { defer, delay, map, of, tap } from 'rxjs';
33
import { TestScheduler } from 'rxjs/testing';
44
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
55

66
import { cache } from './cache';
77
import { requestText } from './request';
88

9-
describe('cache - mocked', function () {
10-
beforeEach(function () {
9+
describe('cache - mocked', () => {
10+
const testScheduler = new TestScheduler((actual, expected) => {
11+
expect(actual).deep.equal(expected);
12+
});
13+
14+
beforeEach(() => {
1115
//
1216
});
1317

14-
afterEach(function () {
18+
afterEach(() => {
1519
//
1620
});
1721

18-
test.skip('cache resetted after 100ms', async function () {
22+
test('marble testing', () => {
23+
const initial = new Response('initial', { status: 200 });
24+
const updated = new Response('updated', { status: 200 });
25+
const orderedResponses = [initial, updated];
26+
27+
testScheduler.run(({ cold, expectObservable }) => {
28+
const stream = cold('a-----------', {
29+
a: () => orderedResponses.shift()
30+
}).pipe(
31+
map(fn => fn()),
32+
cache(2)
33+
);
34+
35+
const unsubA = '-^!';
36+
expectObservable(stream, unsubA).toBe('-a', { a: initial }, new Error());
37+
38+
const unsubB = '----^!';
39+
expectObservable(stream, unsubB).toBe('----a', { a: initial }, new Error());
40+
41+
const unsubC = '---------^--!';
42+
expectObservable(stream, unsubC).toBe('---------a', { a: updated }, new Error());
43+
});
44+
});
45+
46+
test('cache resetted after 100ms', async () => {
1947
let counter = 0;
2048
const a = of(counter).pipe(
2149
tap(e => console.log('U', e)),
@@ -39,8 +67,8 @@ describe('cache - mocked', function () {
3967
});
4068
});
4169

42-
describe('cache', function () {
43-
beforeEach(function () {
70+
describe('cache', () => {
71+
beforeEach(() => {
4472
let counter = 0;
4573
fetchMock.mockGlobal().get(
4674
'https://httpbin.org/my-url-fast',
@@ -53,11 +81,11 @@ describe('cache', function () {
5381
);
5482
});
5583

56-
afterEach(function () {
84+
afterEach(() => {
5785
fetchMock.unmockGlobal();
5886
});
5987

60-
test('cache resetted after 100ms', async function () {
88+
test('cache resetted after 100ms', async () => {
6189
const a = of('https://httpbin.org/my-url-fast').pipe(
6290
requestText(),
6391
tap(() => console.log('CHECK')),

packages/operators/src/request/concurrentRequest.test.js

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { concatAll, concatMap, delay, from, map, of, tap, toArray } from 'rxjs';
22
import { TestScheduler } from 'rxjs/testing';
3-
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
3+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
44

5-
import { log } from '../log';
5+
import { log, logResult } from '../log';
66
import { resolveJSON } from './response';
77

8-
describe('concurrent request - mocked', function () {
8+
describe('concurrent request - mocked', () => {
99
const testScheduler = new TestScheduler((actual, expected) => {
1010
expect(actual).to.eql(expected);
1111
});
1212

13-
beforeEach(function () {
13+
beforeEach(() => {
1414
vi.doMock('./request', importOriginal => ({
1515
request: () => source => source.pipe(concatMap(({ v, t }) => of(v).pipe(delay(t))))
1616
}));
@@ -20,6 +20,10 @@ describe('concurrent request - mocked', function () {
2020
vi.doUnmock('./request');
2121
});
2222

23+
afterAll(function () {
24+
vi.resetModules();
25+
});
26+
2327
test('classic testing', async () => {
2428
const { concurrentRequest } = await import('./concurrentRequest');
2529

@@ -63,15 +67,12 @@ describe('concurrent request - mocked', function () {
6367
});
6468
});
6569

66-
describe.skip('concurrent request - demo', function () {
67-
beforeAll(function () {
68-
vi.resetModules();
69-
});
70-
70+
describe('concurrent request - demo', () => {
7171
test('sample testing', async () => {
7272
const { concurrentRequest } = await import('./concurrentRequest');
7373

74-
await new Promise(done => {
74+
await logResult(
75+
'demo',
7576
of(
7677
new URL('https://dummyjson.com/products?limit=10&skip=0&select=title,price'),
7778
new URL('https://dummyjson.com/products?limit=10&skip=10&select=title,price'),
@@ -82,19 +83,15 @@ describe.skip('concurrent request - demo', function () {
8283
new URL('https://dummyjson.com/products?limit=10&skip=60&select=title,price'),
8384
new URL('https://dummyjson.com/products?limit=10&skip=70&select=title,price'),
8485
new URL('https://dummyjson.com/products?limit=10&skip=80&select=title,price')
86+
).pipe(
87+
concurrentRequest(4),
88+
log('demo:response'),
89+
resolveJSON(),
90+
log('demo:response:json'),
91+
map(({ products }) => products),
92+
log('demo:response:result'),
93+
concatAll()
8594
)
86-
.pipe(
87-
concurrentRequest(4),
88-
log(false),
89-
resolveJSON(),
90-
log(false),
91-
map(({ products }) => products),
92-
concatAll()
93-
)
94-
.subscribe({
95-
next: e => console.log(e),
96-
complete: () => done()
97-
});
98-
});
95+
);
9996
});
10097
});

0 commit comments

Comments
 (0)