Skip to content

Commit

Permalink
Merge branch 'release/2.2.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
vankeisb committed Sep 2, 2022
2 parents ed6bf71 + 92d6ae3 commit 49ff4c0
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 36 deletions.
2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tea-cup-core",
"version": "2.2.0",
"version": "2.2.1",
"description": "react-tea-cup core classes and utilities (Maybe etc)",
"author": "Rémi Van Keisbelck <[email protected]>",
"license": "MIT",
Expand Down
4 changes: 2 additions & 2 deletions samples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-scripts": "3.4.3",
"react-tea-cup": "2.2.0",
"tea-cup-core": "2.2.0"
"react-tea-cup": "2.2.1",
"tea-cup-core": "2.2.1"
},
"scripts": {
"start": "react-scripts start",
Expand Down
93 changes: 76 additions & 17 deletions samples/src/Samples/ProgramSample.test.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { mount } from 'enzyme';
import { Cmd, Dispatcher, Sub, Task } from 'tea-cup-core';
import { extendJest, ProgramProps, updateUntilIdle } from 'react-tea-cup';
import { Cmd, Dispatcher, noCmd, Port, Sub, Task } from 'tea-cup-core';
import { DevTools, extendJest, Program, ProgramProps, updateUntilIdle } from 'react-tea-cup';
import React from 'react';

extendJest(expect);

const init1: () => [number, Cmd<string>] = () => {
return [0, toCmd('go')];
};
// const toCmd = (msg: string) => Task.perform(Time.in(0), () => msg);
const toCmd = (msg: string) => Task.perform(Task.succeed(0), () => msg);

const view1: (dispatch: Dispatcher<string>, model: number) => React.ReactNode = (
dispatch: Dispatcher<string>,
model: number,
) => {
return <div className={'count'}>{model}</div>;
};
describe('Test Program using updateUntilIdle()', () => {
const init1: () => [number, Cmd<string>] = () => {
return [0, toCmd('go')];
};

const update1: (msg: string, model: number) => [number, Cmd<string>] = (msg: string, model: number) => {
return [model + 1, model < 5 ? toCmd('go') : Cmd.none()];
};
const view1: (dispatch: Dispatcher<string>, model: number) => React.ReactNode = (
dispatch: Dispatcher<string>,
model: number,
) => {
return <div className={'count'}>{model}</div>;
};

// const toCmd = (msg: string) => Task.perform(Time.in(0), () => msg);
const toCmd = (msg: string) => Task.perform(Task.succeed(0), () => msg);
const update1: (msg: string, model: number) => [number, Cmd<string>] = (msg: string, model: number) => {
return [model + 1, model < 5 ? toCmd('go') : Cmd.none()];
};

describe('Test Program', () => {
it('expect when program is idle', () => {
const props: ProgramProps<number, string> = {
init: init1,
Expand All @@ -38,3 +38,62 @@ describe('Test Program', () => {
});
});
});

describe('Test Program using DevTools', () => {
const init1: () => [ReadonlyArray<string>, Cmd<string>] = () => {
return noCmd([]);
};

const view1: (dispatch: Dispatcher<string>, model: ReadonlyArray<string>) => React.ReactNode = (
dispatch: Dispatcher<string>,
model: ReadonlyArray<string>,
) => {
return <div className={'history'}>{model.join(' ')}</div>;
};

const update1: (msg: string, model: ReadonlyArray<string>) => [ReadonlyArray<string>, Cmd<string>] = (
msg: string,
model: ReadonlyArray<string>,
) => {
return noCmd(model.concat([msg]));
};

const port1: Port<string> = new Port<string>();

it('stop dispatching when unmounted', () => {
const devTools = DevTools.init(window);
const props: ProgramProps<number, ReadonlyArray<string>> = {
init: init1,
view: view1,
update: update1,
subscriptions: () => port1.subscribe((msg) => msg),
devTools,
};

const wrapper = mount(<Program {...props} />);

expect(devTools.lastEvent().tag).toEqual('init');
expect(devTools.lastEvent().model).toEqual([]);
expect(devTools.lastModel()).toEqual([]);

port1.send('first');

expect(devTools.lastEvent().tag).toEqual('updated');
expect(devTools.lastEvent().msg).toEqual('first');
expect(devTools.lastModel()).toEqual(['first']);

port1.send('second');

expect(devTools.lastEvent().tag).toEqual('updated');
expect(devTools.lastEvent().msg).toEqual('second');
expect(devTools.lastModel()).toEqual(['first', 'second']);

wrapper.unmount();

port1.send('too-late');

expect(devTools.lastEvent().tag).toEqual('updated');
expect(devTools.lastEvent().msg).toEqual('second');
expect(devTools.lastModel()).toEqual(['first', 'second']);
});
});
4 changes: 2 additions & 2 deletions tea-cup/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-tea-cup",
"version": "2.2.0",
"version": "2.2.1",
"description": "Put some TEA in your React.",
"author": "Rémi Van Keisbelck <[email protected]>",
"license": "MIT",
Expand All @@ -22,7 +22,7 @@
"dependencies": {},
"peerDependencies": {
"react": "^16.7.0 || ^17.0.1",
"tea-cup-core": "^2.2.0"
"tea-cup-core": "^2.2.1"
},
"devDependencies": {
"@types/jsdom": "^16.2.5",
Expand Down
10 changes: 9 additions & 1 deletion tea-cup/src/TeaCup/Program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ export class Program<Model, Msg> extends Component<ProgramProps<Model, Msg>, nev
}

dispatch(msg: Msg) {
if (this.currentSub === undefined) {
return;
}
if (this.props.devTools && this.props.devTools.isPaused()) {
// do not process messages if we are paused
return;
Expand Down Expand Up @@ -89,7 +92,7 @@ export class Program<Model, Msg> extends Component<ProgramProps<Model, Msg>, nev
const d = this.dispatch.bind(this);

newSub.init(d);
prevSub && prevSub.release();
prevSub?.release();

// perform commands in a separate timout, to
// make sure that this dispatch is done
Expand All @@ -115,6 +118,11 @@ export class Program<Model, Msg> extends Component<ProgramProps<Model, Msg>, nev
}
}

componentWillUnmount() {
this.currentSub?.release();
this.currentSub = undefined;
}

componentDidMount() {
const { devTools } = this.props;
if (devTools) {
Expand Down
19 changes: 6 additions & 13 deletions tea-cup/src/TeaCup/Testing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,20 @@ export function updateUntilIdle<Model, Msg, T>(
fun: Trigger<Model, Msg, T>,
): Promise<[Model, T]> {
return new Promise((resolve) => {
fun(<Program {...testableProps(resolve, props, fun)} />);
let wrapper = fun(<Program {...testableProps(resolve, props, () => wrapper)} />);
});
}

function testableProps<Model, Msg, T>(
resolve: ResolveType<Model, T>,
props: ProgramProps<Model, Msg>,
fun: Trigger<Model, Msg, T>,
getWrapper: () => T,
) {
const tprops: ProgramProps<TestableModel<Model, Msg, T>, Msg> = {
init: initTestable(resolve, props.init),
view: viewTestable(props.view),
update: updateTestable(props.update),
subscriptions: suscriptionsTestable(props, fun),
subscriptions: subscriptionsTestable(props, getWrapper),
};
return tprops;
}
Expand Down Expand Up @@ -150,21 +150,14 @@ function updateTestable<Model, Msg, T>(
};
}

function suscriptionsTestable<Model, Msg, T>(
function subscriptionsTestable<Model, Msg, T>(
props: ProgramProps<Model, Msg>,
fun: Trigger<Model, Msg, T>,
getWrapper: () => T,
): ProgramProps<TestableModel<Model, Msg, T>, Msg>['subscriptions'] {
return (model: TestableModel<Model, Msg, T>) => {
const subs = props.subscriptions(model.model);
if (model.cmds.length === 0) {
const result = fun(
<Program
init={() => [model.model, Cmd.none()]}
update={(msg, model) => [model, Cmd.none()]}
view={(d, m) => props.view(d, m)}
subscriptions={(d) => Sub.none()}
/>,
);
const result = getWrapper();
model.resolve([model.model, result]);
return subs;
}
Expand Down

0 comments on commit 49ff4c0

Please sign in to comment.