Skip to content

Commit 01cfbb3

Browse files
committed
feat(fakeSchedulers): Support fake timers.
In Jasmine - with Angular's zone.js - and in Jest.
1 parent bc06f8c commit 01cfbb3

File tree

7 files changed

+216
-96
lines changed

7 files changed

+216
-96
lines changed

fixtures/jasmine/passing-spec.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,18 @@
44
*/
55
/*tslint:disable:object-literal-sort-keys*/
66

7-
import { of } from "rxjs";
8-
import { map, tap } from "rxjs/operators";
7+
import "zone.js";
8+
import "zone.js/dist/long-stack-trace-zone";
9+
import "zone.js/dist/proxy.js";
10+
import "zone.js/dist/sync-test";
11+
import "zone.js/dist/jasmine-patch";
12+
import "zone.js/dist/async-test";
13+
import "zone.js/dist/fake-async-test";
14+
15+
import { of, timer } from "rxjs";
16+
import { delay, map, tap } from "rxjs/operators";
917
import { cases, DoneFunction, marbles, observe } from "../../dist/jasmine";
18+
import { fakeSchedulers } from "../../dist/jasmine/angular";
1019

1120
interface TestContext {
1221
myVariable: number;
@@ -107,3 +116,24 @@ describe("observe", () => {
107116
tap(value => expect(value).toEqual("pass"))
108117
)));
109118
});
119+
120+
describe("fakeSchedulers", () => {
121+
122+
it("should support a timer", fakeSchedulers(tick => {
123+
let received: number | undefined;
124+
timer(100).subscribe(value => received = value);
125+
tick(50);
126+
expect(received).not.toBeDefined();
127+
tick(50);
128+
expect(received).toBe(0);
129+
}));
130+
131+
it("should support delay", fakeSchedulers(tick => {
132+
let received: number | undefined;
133+
of(1).pipe(delay(100)).subscribe(value => received = value);
134+
tick(50);
135+
expect(received).not.toBeDefined();
136+
tick(50);
137+
expect(received).toBe(1);
138+
}));
139+
});

fixtures/jest/passing-spec.ts

Lines changed: 121 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -4,100 +4,128 @@
44
*/
55
/*tslint:disable:object-literal-sort-keys*/
66

7-
import { of } from "rxjs";
8-
import { map, tap } from "rxjs/operators";
9-
import { cases, DoneFunction, marbles, observe } from "../../dist/jest";
10-
11-
test("it should handle white space in marble diagrams correctly", marbles((m) => {
12-
13-
const values = {
14-
a: 1,
15-
b: 2,
16-
c: 3,
17-
d: 4
18-
};
19-
20-
const source = m.cold(" --a-b-c-|", values);
21-
const expected = m.cold("--b-c-d-|", values);
22-
23-
const destination = source.pipe(map((value) => value + 1));
24-
25-
m.expect(destination).toBeObservable(expected);
26-
}));
27-
28-
test("it should support marble tests", marbles((m) => {
29-
30-
const values = {
31-
a: 1,
32-
b: 2,
33-
c: 3,
34-
d: 4
35-
};
36-
37-
const source = m.hot("--^-a-b-c-|", values);
38-
const subs = "^-------!";
39-
const expected = m.cold("--b-c-d-|", values);
40-
41-
const destination = source.pipe(map((value) => value + 1));
42-
43-
m.expect(destination).toBeObservable(expected);
44-
m.expect(source).toHaveSubscriptions(subs);
45-
}));
46-
47-
test("it should support a done callback", marbles<DoneFunction>((m, done) => {
48-
49-
const values = {
50-
a: 1,
51-
b: 2,
52-
c: 3,
53-
d: 4
54-
};
55-
56-
const source = m.hot("--^-a-b-c-|", values);
57-
const subs = "^-------!";
58-
const expected = m.cold("--b-c-d-|", values);
59-
60-
const destination = source.pipe(map((value) => value + 1));
61-
62-
m.expect(destination).toBeObservable(expected);
63-
m.expect(source).toHaveSubscriptions(subs);
64-
m.flush();
65-
66-
expect(done).toBeInstanceOf(Function);
67-
expect(done.fail).toBeInstanceOf(Function);
68-
setTimeout(done, 0);
69-
}));
70-
71-
cases("should support cases", (m, c) => {
72-
73-
const values = {
74-
a: 1,
75-
b: 2,
76-
c: 3,
77-
d: 4
78-
};
79-
80-
const source = m.hot(c.s, values);
81-
const expected = m.cold(c.e, values);
82-
const destination = source.pipe(map((value) => value + 1));
83-
84-
m.expect(destination).toBeObservable(expected);
85-
}, {
86-
"non-empty": {
87-
s: "-a-b-c-|",
88-
e: "-b-c-d-|"
89-
},
90-
"empty": {
91-
s: "-|",
92-
e: "-|"
93-
}
7+
import { of, timer } from "rxjs";
8+
import { delay, map, tap } from "rxjs/operators";
9+
import { cases, DoneFunction, fakeSchedulers, marbles, observe } from "../../dist/jest";
10+
11+
describe("marbles", () => {
12+
13+
test("it should handle white space in marble diagrams correctly", marbles((m) => {
14+
15+
const values = {
16+
a: 1,
17+
b: 2,
18+
c: 3,
19+
d: 4
20+
};
21+
22+
const source = m.cold(" --a-b-c-|", values);
23+
const expected = m.cold("--b-c-d-|", values);
24+
25+
const destination = source.pipe(map((value) => value + 1));
26+
27+
m.expect(destination).toBeObservable(expected);
28+
}));
29+
30+
test("it should support marble tests", marbles((m) => {
31+
32+
const values = {
33+
a: 1,
34+
b: 2,
35+
c: 3,
36+
d: 4
37+
};
38+
39+
const source = m.hot("--^-a-b-c-|", values);
40+
const subs = "^-------!";
41+
const expected = m.cold("--b-c-d-|", values);
42+
43+
const destination = source.pipe(map((value) => value + 1));
44+
45+
m.expect(destination).toBeObservable(expected);
46+
m.expect(source).toHaveSubscriptions(subs);
47+
}));
48+
49+
test("it should support a done callback", marbles<DoneFunction>((m, done) => {
50+
51+
const values = {
52+
a: 1,
53+
b: 2,
54+
c: 3,
55+
d: 4
56+
};
57+
58+
const source = m.hot("--^-a-b-c-|", values);
59+
const subs = "^-------!";
60+
const expected = m.cold("--b-c-d-|", values);
61+
62+
const destination = source.pipe(map((value) => value + 1));
63+
64+
m.expect(destination).toBeObservable(expected);
65+
m.expect(source).toHaveSubscriptions(subs);
66+
m.flush();
67+
68+
expect(done).toBeInstanceOf(Function);
69+
expect(done.fail).toBeInstanceOf(Function);
70+
setTimeout(done, 0);
71+
}));
72+
73+
cases("should support cases", (m, c) => {
74+
75+
const values = {
76+
a: 1,
77+
b: 2,
78+
c: 3,
79+
d: 4
80+
};
81+
82+
const source = m.hot(c.s, values);
83+
const expected = m.cold(c.e, values);
84+
const destination = source.pipe(map((value) => value + 1));
85+
86+
m.expect(destination).toBeObservable(expected);
87+
}, {
88+
"non-empty": {
89+
s: "-a-b-c-|",
90+
e: "-b-c-d-|"
91+
},
92+
"empty": {
93+
s: "-|",
94+
e: "-|"
95+
}
96+
});
97+
98+
test("it should support promises", marbles((m) => {
99+
return Promise.resolve("pass").then((value) => expect(value).toEqual("pass"));
100+
}));
94101
});
95102

96-
test("it should support promises", marbles((m) => {
103+
describe("observe", () => {
97104

98-
return Promise.resolve("pass").then((value) => expect(value).toEqual("pass"));
99-
}));
105+
test("it should support observe", observe(() => of("pass").pipe(
106+
tap(value => expect(value).toEqual("pass"))
107+
)));
108+
});
100109

101-
test("it should support observe", observe(() => of("pass").pipe(
102-
tap(value => expect(value).toEqual("pass"))
103-
)));
110+
describe("fakeSchedulers", () => {
111+
112+
beforeEach(() => jest.useFakeTimers());
113+
114+
test("it should support a timer", fakeSchedulers(advance => {
115+
let received: number | undefined;
116+
timer(100).subscribe(value => received = value);
117+
advance(50);
118+
expect(received).not.toBeDefined();
119+
advance(50);
120+
expect(received).toBe(0);
121+
}));
122+
123+
test("it should support delay", fakeSchedulers(advance => {
124+
let received: number | undefined;
125+
of(1).pipe(delay(100)).subscribe(value => received = value);
126+
advance(50);
127+
expect(received).not.toBeDefined();
128+
advance(50);
129+
expect(received).toBe(1);
130+
}));
131+
});

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
},
1010
"description": "An RxJS marble testing library for any test framework",
1111
"devDependencies": {
12+
"@angular/core": "^6.0.4",
1213
"@types/chai": "^4.1.2",
1314
"@types/jasmine": "^2.5.53",
1415
"@types/jest": "^23.0.0",
@@ -31,7 +32,8 @@
3132
"typescript": "~2.9.1",
3233
"webpack": "^4.0.0",
3334
"webpack-cli": "^3.0.0",
34-
"webpack-rxjs-externals": "^2.0.0"
35+
"webpack-rxjs-externals": "^2.0.0",
36+
"zone.js": "~0.8.26"
3537
},
3638
"es2015": "./dist/esm2015/index.js",
3739
"homepage": "https://github.com/cartant/rxjs-marbles",

source/jasmine/angular.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @license Use of this source code is governed by an MIT-style license that
3+
* can be found in the LICENSE file at https://github.com/cartant/rxjs-marbles
4+
*/
5+
6+
import { fakeAsync, tick } from "@angular/core/testing";
7+
import { asyncScheduler } from "rxjs";
8+
9+
export function fakeSchedulers(
10+
fakeTest: (tick: (milliseconds: number) => void) => void
11+
): () => void {
12+
return fakeAsync(() => {
13+
try {
14+
let fakeTime = 0;
15+
asyncScheduler.now = () => fakeTime;
16+
fakeTest(milliseconds => {
17+
fakeTime += milliseconds;
18+
tick(milliseconds);
19+
});
20+
} finally {
21+
delete asyncScheduler.now;
22+
}
23+
});
24+
}

source/jest/fake.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @license Use of this source code is governed by an MIT-style license that
3+
* can be found in the LICENSE file at https://github.com/cartant/rxjs-marbles
4+
*/
5+
6+
import { asyncScheduler } from "rxjs";
7+
8+
declare const jest: any;
9+
10+
export function fakeSchedulers(
11+
fakeTest: (advance: (milliseconds: number) => void) => void
12+
): () => void {
13+
return () => {
14+
try {
15+
let fakeTime = 0;
16+
asyncScheduler.now = () => fakeTime;
17+
fakeTest(milliseconds => {
18+
fakeTime += milliseconds;
19+
jest.advanceTimersByTime(milliseconds);
20+
});
21+
} finally {
22+
delete asyncScheduler.now;
23+
}
24+
};
25+
}

source/jest/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export * from "../configuration";
1212
export * from "../context";
1313
export * from "../expect";
1414
export { MarblesFunction } from "../marbles";
15+
export * from "./fake";
1516
export * from "./observe";
1617

1718
declare const describe: Function;

yarn.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
# yarn lockfile v1
33

44

5+
"@angular/core@^6.0.4":
6+
version "6.0.4"
7+
resolved "https://registry.yarnpkg.com/@angular/core/-/core-6.0.4.tgz#80b19624493126b6c7e3a180a33dee92c84b4bd6"
8+
dependencies:
9+
tslib "^1.9.0"
10+
511
"@ava/babel-plugin-throws-helper@^2.0.0":
612
version "2.0.0"
713
resolved "https://registry.yarnpkg.com/@ava/babel-plugin-throws-helper/-/babel-plugin-throws-helper-2.0.0.tgz#2fc1fe3c211a71071a4eca7b8f7af5842cd1ae7c"
@@ -6020,3 +6026,7 @@ yargs@~3.10.0:
60206026
cliui "^2.1.0"
60216027
decamelize "^1.0.0"
60226028
window-size "0.1.0"
6029+
6030+
zone.js@~0.8.26:
6031+
version "0.8.26"
6032+
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.26.tgz#7bdd72f7668c5a7ad6b118148b4ea39c59d08d2d"

0 commit comments

Comments
 (0)