Skip to content

Commit e39a047

Browse files
committed
raw: testing a program
1 parent 92748d2 commit e39a047

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { mount, ReactWrapper } from 'enzyme';
2+
import { extendJest, Cmd, Sub, Task, Program, ProgramProps } from "react-tea-cup";
3+
import React, { ReactNode } from 'react';
4+
import { Dispatcher } from 'tea-cup-core';
5+
// import 'jest-enzyme';
6+
7+
extendJest(expect);
8+
9+
const init1: () => [number, Cmd<string>] = () => {
10+
return [0, toCmd('go')];
11+
}
12+
13+
const view1: (dispatch: Dispatcher<string>, model: number) => React.ReactNode = (dispatch: Dispatcher<string>, model: number) => {
14+
return (<div className={'count'}>{model}</div>);
15+
}
16+
17+
const update1: (msg: string, model: number) => [number, Cmd<string>] = (msg: string, model: number) => {
18+
return [model + 1, model < 5 ? toCmd('go') : Cmd.none()];
19+
}
20+
21+
// const toCmd = (msg: string) => Task.perform(Time.in(0), () => msg);
22+
const toCmd = (msg: string) => Task.perform(Task.succeed(0), () => msg);
23+
24+
describe('Test Program', () => {
25+
26+
it('first', () => {
27+
const props: ProgramProps<number, string> = {
28+
init: init1,
29+
view: view1,
30+
update: update1,
31+
subscriptions: () => Sub.none<string>()
32+
}
33+
return mountWhenIdle(props).then(([model, wrapper]) => {
34+
expect(model).toEqual(6)
35+
// expect(wrapper).toHaveHTML('')
36+
expect(wrapper.find('.count')).toHaveText('6')
37+
})
38+
})
39+
})
40+
41+
function mountWhenIdle<Model, Msg>(props: ProgramProps<Model, Msg>) {
42+
const testable = new Testable(props);
43+
// return Promise.resolve(mount(<Program {...testable.programProps} />));
44+
return testable.mountWhenIdle()
45+
}
46+
47+
class Testable<Model, Msg>{
48+
private resolve?: (idle: [Model, ReactWrapper<Program<Model, Msg>, ProgramProps<Model, Msg>, never>]) => void;
49+
private cmds: Cmd<Msg>[] = [];
50+
private dispatch?: Dispatcher<Msg>;
51+
private model?: Model;
52+
private viewed?: ReactNode;
53+
54+
constructor(private readonly props: ProgramProps<Model, Msg>) {
55+
}
56+
57+
get programProps() {
58+
const props: ProgramProps<Model, Msg> = {
59+
init: this.props.init,
60+
view: (dispatch: Dispatcher<Msg>, model: Model) => this.view(dispatch, model),
61+
update: (msg: Msg, model: Model) => this.update(msg, model),
62+
subscriptions: this.props.subscriptions
63+
}
64+
return props
65+
}
66+
67+
private view(dispatch: Dispatcher<Msg>, model: Model) {
68+
this.dispatch = dispatch;
69+
this.viewed = this.props.view(dispatch, model);
70+
return this.viewed;
71+
}
72+
73+
private update(msg: Msg, model: Model): [Model, Cmd<Msg>] {
74+
const [model1, cmd1] = this.props.update(msg, model);
75+
this.model = model1;
76+
this.cmds.push(cmd1);
77+
setTimeout(() => {
78+
this.process();
79+
}, 0);
80+
return [model1, Cmd.none()];
81+
}
82+
83+
private process() {
84+
this.cmds = this.cmds.filter(cmd => cmd.constructor.name !== 'CmdNone')
85+
if (this.cmds.length === 0) {
86+
this.resolve?.([this.model!, mount(<>{this.viewed}</>)]);
87+
return;
88+
}
89+
const first = this.cmds[0]
90+
this.cmds = this.cmds.slice(1)
91+
first.execute(this.dispatch!)
92+
}
93+
94+
mountWhenIdle(): Promise<[Model, ReactWrapper<Program<Model, Msg>, ProgramProps<Model, Msg>, never>]> {
95+
mount(<Program {...this.programProps} />)
96+
return new Promise(resolve => {
97+
this.resolve = resolve;
98+
});
99+
}
100+
}

0 commit comments

Comments
 (0)