Skip to content

Commit 4640bc9

Browse files
committed
fix(marbleassert): accept subscriptionlog array
1 parent e37c82e commit 4640bc9

File tree

3 files changed

+149
-72
lines changed

3 files changed

+149
-72
lines changed

spec/assert/marbleAssert-spec.ts

+73-32
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,103 @@
11
import { expect } from 'chai';
2-
import { SubscriptionLog } from 'rxjs/testing/SubscriptionLog';
32
import { marbleAssert } from '../../src/assert/marbleAssert';
43
import { parseObservableMarble as p } from '../../src/marbles/parseObservableMarble';
4+
import { subscribe } from '../../src/message/TestMessage';
55

66
describe('marbleAssert', () => {
77
it('should throw if source is neither array nor SubscriptionLog', () => {
88
expect(() => marbleAssert(1 as any)).to.throw();
99
});
1010

1111
describe('TestMessage', () => {
12-
it(`should throw if expected value isn't array`, () => {
13-
expect(() => marbleAssert([]).to.equal(new SubscriptionLog(0) as any)).to.throw();
12+
it('shoud pass empty', () => {
13+
marbleAssert(p('------')).to.equal(p('------'));
14+
marbleAssert([]).to.equal(p('------'));
15+
marbleAssert([]).to.equal([]);
1416
});
1517

1618
it('should pass observables', () => {
1719
const s = p('--a--b--');
1820
const e = p('--a--b--');
1921

20-
marbleAssert(s).to.equal(e);
22+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
2123
});
2224

2325
it('should pass observable with noop', () => {
2426
const s = p('--a- -b--');
2527
const e = p('--a- -b--');
2628

27-
marbleAssert(s).to.equal(e);
29+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
2830
});
2931

3032
it('should pass observable with groups', () => {
3133
const s = p('--(ab)-c-');
3234
const e = p('--(ab)-c--');
3335

34-
marbleAssert(s).to.equal(e);
36+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
3537
});
3638

3739
it('should pass observable with expand', () => {
3840
const s = p('--a-...3...-b--');
3941
const e = p('--a-----b--');
4042

41-
marbleAssert(s).to.equal(e);
43+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
4244
});
4345

4446
it('should pass observable with complete', () => {
4547
const s = p('a--b--|');
4648
const e = p('a--b--|');
4749

48-
marbleAssert(s).to.equal(e);
50+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
4951
});
5052

5153
it('should pass observable with synchronous group', () => {
5254
const s = p('(a|)');
5355
const e = p('(a|)');
5456

55-
marbleAssert(s).to.equal(e);
57+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
5658
});
5759

5860
it('should pass observable with error', () => {
5961
const s = p('--a--b--#');
6062
const e = p('--a--b--#');
6163

62-
marbleAssert(s).to.equal(e);
64+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
6365
});
6466

6567
it('should pass observable with custom value', () => {
6668
const s = p('--a--b--', { a: 1 });
6769
const e = p('--a--b--', { a: 1 });
6870

69-
marbleAssert(s).to.equal(e);
71+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
7072
});
7173

7274
it('should pass observable with custom error', () => {
7375
const s = p('--a--b--#', null, 1);
7476
const e = p('--a--b--#', null, 1);
7577

76-
marbleAssert(s).to.equal(e);
78+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
7779
});
7880

7981
it('should pass hot observable with subscription, without emit before sub', () => {
8082
const s = p('^--a--b--');
8183
const e = p('---a--b--');
8284

83-
marbleAssert(s).to.equal(e);
85+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
8486
});
8587

8688
it('should pass hot observable with subscription, emit before sub', () => {
8789
const s = p('-x--^--a--b--');
8890
const e = p('-x--^--a--b--');
8991

90-
marbleAssert(s).to.equal(e);
92+
expect(() => marbleAssert(s).to.equal(e)).to.not.throw();
93+
});
94+
95+
it('should assert empty source', () => {
96+
expect(() => marbleAssert([]).to.equal(p('----s'))).to.throw();
97+
});
98+
99+
it('should assert non-array expected', () => {
100+
expect(() => marbleAssert([]).to.equal('1' as any)).to.throw();
91101
});
92102

93103
it('should assert observables frame', () => {
@@ -176,65 +186,96 @@ describe('marbleAssert', () => {
176186
});
177187

178188
describe('SubscriptionLog', () => {
179-
it(`should throw if expected value isn't subscription log`, () => {
180-
expect(() => marbleAssert(new SubscriptionLog(0, 0)).to.equal([] as any)).to.throw();
181-
});
182-
183189
it('should pass if subscription matches', () => {
184-
const source = new SubscriptionLog(10);
190+
const source = [subscribe(10)];
185191

186192
expect(() => marbleAssert(source).to.equal(source)).to.not.throw();
187193
});
188194

189195
it('should pass if subscription with unsubscription matches', () => {
190-
const source = new SubscriptionLog(10, 45);
196+
const source = [subscribe(10, 45)];
191197

192198
expect(() => marbleAssert(source).to.equal(source)).to.not.throw();
193199
});
194200

195201
it('should pass if unsubscription matches', () => {
196-
const source = new SubscriptionLog(Number.POSITIVE_INFINITY, 20);
202+
const source = [subscribe(Number.POSITIVE_INFINITY, 20)];
197203

198204
expect(() => marbleAssert(source).to.equal(source)).to.not.throw();
199205
});
200206

201207
it('should pass if subscription is empty', () => {
202-
const source = new SubscriptionLog(Number.POSITIVE_INFINITY);
208+
const source = [subscribe(Number.POSITIVE_INFINITY)];
203209

204210
expect(() => marbleAssert(source).to.equal(source)).to.not.throw();
205211
});
206212

213+
it('should pass multiple subscriptions', () => {
214+
const source = [subscribe(10, 45), subscribe(20, 35)];
215+
216+
expect(() => marbleAssert(source).to.equal(source)).to.not.throw();
217+
});
218+
219+
it('should assert empty source', () => {
220+
expect(() => marbleAssert([]).to.equal([subscribe(10, 24)] as any)).to.throw();
221+
});
222+
223+
it('should assert non-array expected', () => {
224+
expect(() => marbleAssert([]).to.equal('1' as any)).to.throw();
225+
});
226+
207227
it('should assert if subscription unmatches', () => {
208-
const source = new SubscriptionLog(10);
209-
const expected = new SubscriptionLog(20);
228+
const source = [subscribe(10)];
229+
const expected = [subscribe(20)];
210230

211231
expect(() => marbleAssert(source).to.equal(expected)).to.throw();
212232
});
213233

214234
it('should assert if subscription with unsubscription unmatches', () => {
215-
const source = new SubscriptionLog(10, 45);
216-
const expected = new SubscriptionLog(12, 46);
235+
const source = [subscribe(10, 45)];
236+
const expected = [subscribe(12, 46)];
217237

218238
expect(() => marbleAssert(source).to.equal(expected)).to.throw();
219239
});
220240

221241
it('should assert if subscription unmatches with unsubscription', () => {
222-
const source = new SubscriptionLog(10, 45);
223-
const expected = new SubscriptionLog(12, 45);
242+
const source = [subscribe(10, 45)];
243+
const expected = [subscribe(12, 45)];
224244

225245
expect(() => marbleAssert(source).to.equal(expected)).to.throw();
226246
});
227247

228248
it('should assert if unsubscription with subscription unmatches', () => {
229-
const source = new SubscriptionLog(10, 45);
230-
const expected = new SubscriptionLog(10, 46);
249+
const source = [subscribe(10, 45)];
250+
const expected = [subscribe(10, 46)];
231251

232252
expect(() => marbleAssert(source).to.equal(expected)).to.throw();
233253
});
234254

235255
it('should assert if unsubscription unmatches', () => {
236-
const source = new SubscriptionLog(Number.POSITIVE_INFINITY, 20);
237-
const expected = new SubscriptionLog(Number.POSITIVE_INFINITY, 30);
256+
const source = [subscribe(Number.POSITIVE_INFINITY, 20)];
257+
const expected = [subscribe(Number.POSITIVE_INFINITY, 30)];
258+
259+
expect(() => marbleAssert(source).to.equal(expected)).to.throw();
260+
});
261+
262+
it('should assert same length multiple subscription', () => {
263+
const source = [subscribe(10, 45), subscribe(5, 35), subscribe(10, 46)];
264+
const expected = [subscribe(10, 46), subscribe(5, 35), subscribe(10, 45)];
265+
266+
expect(() => marbleAssert(source).to.equal(expected)).to.throw();
267+
});
268+
269+
it('should assert larger source multiple subscription', () => {
270+
const source = [subscribe(10, 45), subscribe(5, 35), subscribe(10, 46), subscribe(6, 35)];
271+
const expected = [subscribe(10, 46), subscribe(5, 35), subscribe(10, 45)];
272+
273+
expect(() => marbleAssert(source).to.equal(expected)).to.throw();
274+
});
275+
276+
it('should assert larger expected multiple subscription', () => {
277+
const source = [subscribe(10, 45), subscribe(5, 35), subscribe(10, 46)];
278+
const expected = [subscribe(10, 46), subscribe(5, 35), subscribe(10, 45), subscribe(6, 35)];
238279

239280
expect(() => marbleAssert(source).to.equal(expected)).to.throw();
240281
});

src/assert/marbleAssert.ts

+65-37
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,43 @@ import { TestMessage } from '../message/TestMessage';
55
import { constructObservableMarble } from './constructObservableMarble';
66
import { constructSubscriptionMarble } from './constructSubscriptionMarble';
77

8-
const toEqulAssert = toEqual.bind({ expand: false });
8+
const toEqualAssert = toEqual.bind({ expand: false });
9+
10+
const subscriptionMarbleAssert = (source: Array<SubscriptionLog>) => (expected: Array<SubscriptionLog>) => {
11+
const asserted = toEqualAssert(source, expected);
12+
13+
if (!asserted.pass) {
14+
const length = source.length > expected.length ? source.length : expected.length;
15+
let description = `
16+
${matcherHint(' to equal ')}
17+
`;
18+
19+
for (let idx = 0; idx < length; idx++) {
20+
const sourceMarble = !!source[idx]
21+
? constructSubscriptionMarble(source[idx])
22+
: { marbleString: '', frameString: '' };
23+
const expectedMarble = !!expected[idx]
24+
? constructSubscriptionMarble(expected[idx])
25+
: { marbleString: '', frameString: '' };
26+
27+
if (toEqualAssert(sourceMarble, expectedMarble).pass) {
28+
continue;
29+
}
30+
31+
description += `
32+
33+
${printReceived(`Source: ${sourceMarble.marbleString}`)}
34+
${printReceived(` ${sourceMarble.frameString}`)}
35+
${printExpected(`Expected: ${expectedMarble.marbleString}`)}
36+
${printExpected(` ${expectedMarble.frameString}`)}
37+
`;
38+
}
39+
description += `
40+
${asserted.message()}
41+
`;
42+
throw new Error(description);
43+
}
44+
};
945

1046
const observableMarbleAssert = <T = string>(source: Array<TestMessage<T>> | Readonly<Array<TestMessage<T>>>) => (
1147
expected: Array<TestMessage<T>> | Readonly<Array<TestMessage<T>>>
@@ -14,10 +50,17 @@ const observableMarbleAssert = <T = string>(source: Array<TestMessage<T>> | Read
1450
throw new Error('Expected value is not array');
1551
}
1652

53+
//polymorphic picks up observablemarbleassert first when empty array, manually falls back
54+
//if expected is subscriptionlog
55+
if ((expected as any).every((x: any) => x instanceof SubscriptionLog)) {
56+
subscriptionMarbleAssert(source as any)(expected as any);
57+
return;
58+
}
59+
1760
const sourceMarble = constructObservableMarble(source);
1861
const expectedMarble = constructObservableMarble(expected);
1962

20-
const asserted = toEqulAssert(source, expected);
63+
const asserted = toEqualAssert(source, expected);
2164

2265
if (!asserted.pass) {
2366
const description = `
@@ -30,49 +73,34 @@ ${asserted.message()}
3073
}
3174
};
3275

33-
const subscriptionMarbleAssert = (source: SubscriptionLog) => (expected: SubscriptionLog) => {
34-
if (!(expected instanceof SubscriptionLog)) {
35-
throw new Error('Expected value is not SubscriptionLog');
36-
}
37-
38-
const sourceMarble = constructSubscriptionMarble(source);
39-
const expectedMarble = constructSubscriptionMarble(expected);
40-
41-
const asserted = toEqulAssert(sourceMarble, expectedMarble);
42-
43-
if (!asserted.pass) {
44-
const description = `
45-
${matcherHint(' to equal ', JSON.stringify(source), JSON.stringify(expected))}
46-
47-
${printReceived(`Source: ${sourceMarble.marbleString}`)}
48-
${printReceived(` ${sourceMarble.frameString}`)}
49-
${printExpected(`Expected: ${expectedMarble.marbleString}`)}
50-
${printExpected(` ${expectedMarble.frameString}`)}
51-
`;
52-
53-
throw new Error(description);
54-
}
55-
};
56-
57-
function marbleAssert<T = void>(source: SubscriptionLog): { to: { equal(expected: SubscriptionLog): void } };
5876
function marbleAssert<T = string>(
59-
source: Array<TestMessage<T>> | Readonly<Array<TestMessage<T>>>
60-
): { to: { equal(expected: Array<TestMessage<T>> | Readonly<Array<TestMessage<T>>>): void } };
77+
source: Array<TestMessage<T | Array<TestMessage<T>>>> | Readonly<Array<TestMessage<T | Array<TestMessage<T>>>>>
78+
): {
79+
to: {
80+
equal(
81+
expected: TestMessage<T | Array<TestMessage<T>>> | Readonly<Array<TestMessage<T | Array<TestMessage<T>>>>>
82+
): void;
83+
};
84+
};
85+
function marbleAssert<T = void>(
86+
source: Array<SubscriptionLog>
87+
): { to: { equal(expected: Array<SubscriptionLog>): void } };
6188
function marbleAssert<T = string>(
62-
source: SubscriptionLog | Array<TestMessage<T>> | Readonly<Array<TestMessage<T>>>
89+
source:
90+
| Array<SubscriptionLog>
91+
| Array<TestMessage<T | Array<TestMessage<T>>>>
92+
| Readonly<Array<TestMessage<T | Array<TestMessage<T>>>>>
6393
): { to: { equal(expected: object): void } } {
6494
const isSourceArray = Array.isArray(source);
65-
const isSourceSubscription = source instanceof SubscriptionLog;
66-
67-
if (!isSourceArray && !isSourceSubscription) {
68-
throw new Error('Source is neither array nor SubscriptionLog, cannot assert');
95+
if (!isSourceArray) {
96+
throw new Error('Cannot assert non array');
6997
}
7098

99+
const isSourceSubscription = source.length > 0 && (source as Array<any>).every(v => v instanceof SubscriptionLog);
100+
71101
return {
72102
to: {
73-
equal: isSourceSubscription
74-
? subscriptionMarbleAssert(source as SubscriptionLog)
75-
: observableMarbleAssert(source as any)
103+
equal: isSourceSubscription ? subscriptionMarbleAssert(source as any) : observableMarbleAssert(source as any)
76104
}
77105
};
78106
}

src/index.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,18 @@ export interface RxSandbox {
6464
* better visualization against observable test messages.
6565
*
6666
*/
67-
marbleAssert(source: SubscriptionLog): { to: { equal(expected: SubscriptionLog): void } };
6867
marbleAssert<T = string>(
69-
source: Array<TestMessage<T>> | Readonly<Array<TestMessage<T>>>
70-
): { to: { equal(expected: Array<TestMessage<T>> | Readonly<Array<TestMessage<T>>>): void } };
68+
source: Array<TestMessage<T | Array<TestMessage<T>>>> | Readonly<Array<TestMessage<T | Array<TestMessage<T>>>>>
69+
): {
70+
to: {
71+
equal(
72+
expected:
73+
| Array<TestMessage<T | Array<TestMessage<T>>>>
74+
| Readonly<Array<TestMessage<T | Array<TestMessage<T>>>>>
75+
): void;
76+
};
77+
};
78+
marbleAssert(source: Array<SubscriptionLog>): { to: { equal(expected: Array<SubscriptionLog>): void } };
7179
}
7280

7381
const rxSandbox: RxSandbox = {

0 commit comments

Comments
 (0)