Skip to content

Commit 9dd698e

Browse files
committed
use program to test program
1 parent e39a047 commit 9dd698e

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

samples/src/Samples/Program.test.tsx

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { mount, ReactWrapper } from 'enzyme';
22
import { extendJest, Cmd, Sub, Task, Program, ProgramProps } from "react-tea-cup";
33
import React, { ReactNode } from 'react';
44
import { Dispatcher } from 'tea-cup-core';
5+
import { view } from './Counter';
56
// import 'jest-enzyme';
67

78
extendJest(expect);
@@ -36,6 +37,20 @@ describe('Test Program', () => {
3637
expect(wrapper.find('.count')).toHaveText('6')
3738
})
3839
})
40+
41+
it('alternative', () => {
42+
const props: ProgramProps<number, string> = {
43+
init: init1,
44+
view: view1,
45+
update: update1,
46+
subscriptions: () => Sub.none<string>()
47+
}
48+
return updateUntilIdle(props).then(([model, wrapper]) => {
49+
expect(model).toEqual(6)
50+
// expect(wrapper).toHaveHTML('')
51+
expect(wrapper.find('.count')).toHaveText('6')
52+
})
53+
})
3954
})
4055

4156
function mountWhenIdle<Model, Msg>(props: ProgramProps<Model, Msg>) {
@@ -44,6 +59,88 @@ function mountWhenIdle<Model, Msg>(props: ProgramProps<Model, Msg>) {
4459
return testable.mountWhenIdle()
4560
}
4661

62+
type WrapperType<Model, Msg> = ReactWrapper<Program<Model, Msg>, ProgramProps<Model, Msg>, never>
63+
type ResolveType<Model, Msg> = (idle: [Model, WrapperType<Model, Msg>]) => void;
64+
65+
function updateUntilIdle<Model, Msg>(props: ProgramProps<Model, Msg>): Promise<[Model, WrapperType<Model, Msg>]> {
66+
return new Promise(resolve => {
67+
mount(<Program {...testableProps(resolve, props)} />)
68+
})
69+
}
70+
71+
function testableProps<Model, Msg>(resolve: ResolveType<Model, Msg>, props: ProgramProps<Model, Msg>) {
72+
const props2: ProgramProps<TestableModel<Model, Msg>, Msg> = {
73+
init: initTestable(resolve, props.init),
74+
view: viewTestable(props.view),
75+
update: updateTestable((props.update)),
76+
subscriptions: suscriptionsTestable(props)
77+
}
78+
return props2
79+
}
80+
81+
type TestableModel<Model, Msg> = {
82+
readonly resolve: ResolveType<Model, Msg>;
83+
readonly cmds: Cmd<Msg>[];
84+
readonly model: Model;
85+
}
86+
87+
function initTestable<Model, Msg>(resolve: ResolveType<Model, Msg>, init: ProgramProps<Model, Msg>['init']): ProgramProps<TestableModel<Model, Msg>, Msg>['init'] {
88+
const mac = init();
89+
return () => [{
90+
resolve,
91+
cmds: [mac[1]],
92+
model: mac[0]
93+
}, Cmd.none()];
94+
}
95+
96+
function viewTestable<Model, Msg>(view: ProgramProps<Model, Msg>['view']): ProgramProps<TestableModel<Model, Msg>, Msg>['view'] {
97+
return (dispatch: Dispatcher<Msg>, model: TestableModel<Model, Msg>) => view(dispatch, model.model);
98+
}
99+
100+
function updateTestable<Model, Msg>(update: ProgramProps<Model, Msg>['update']): ProgramProps<TestableModel<Model, Msg>, Msg>['update'] {
101+
return (msg: Msg, model: TestableModel<Model, Msg>) => {
102+
const [model1, cmd1] = update(msg, model.model);
103+
const cmds = [cmd1].filter(cmd => cmd.constructor.name !== 'CmdNone')
104+
return [{
105+
...model,
106+
cmds,
107+
model: model1,
108+
}, Cmd.none()];
109+
}
110+
}
111+
112+
function suscriptionsTestable<Model, Msg>(props: ProgramProps<Model, Msg>): ProgramProps<TestableModel<Model, Msg>, Msg>['subscriptions'] {
113+
return (model: TestableModel<Model, Msg>) => {
114+
const subs = props.subscriptions(model.model);
115+
if (model.cmds.length === 0) {
116+
const wrapper: WrapperType<Model, Msg> = mount(<Program
117+
init={() => [model.model, Cmd.none()]}
118+
update={(msg, model) => [model, Cmd.none()]}
119+
view={(d, m) => props.view(d, m)}
120+
subscriptions={(d) => Sub.none()}
121+
/>)
122+
model.resolve([model.model, wrapper]);
123+
return subs;
124+
}
125+
return Sub.batch([new TestableSub(model.cmds), subs]);
126+
}
127+
}
128+
129+
class TestableSub<Msg> extends Sub<Msg> {
130+
constructor(private readonly cmds: readonly Cmd<Msg>[]) {
131+
super();
132+
}
133+
134+
protected onInit(): void {
135+
setTimeout(() => {
136+
if (this.dispatcher !== undefined) {
137+
const d = this.dispatcher.bind(this);
138+
this.cmds.map(cmd => cmd.execute(d));
139+
}
140+
}, 0)
141+
}
142+
}
143+
47144
class Testable<Model, Msg>{
48145
private resolve?: (idle: [Model, ReactWrapper<Program<Model, Msg>, ProgramProps<Model, Msg>, never>]) => void;
49146
private cmds: Cmd<Msg>[] = [];

0 commit comments

Comments
 (0)