Skip to content

Commit

Permalink
Merge 69249ea into 91e24f4
Browse files Browse the repository at this point in the history
  • Loading branch information
filipeversehgi authored Apr 10, 2019
2 parents 91e24f4 + 69249ea commit fba0249
Show file tree
Hide file tree
Showing 21 changed files with 4,485 additions and 26 deletions.
12 changes: 12 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"presets": [
["@babel/preset-env",
{
"targets": {
"node": "current"
}
}],
"@babel/preset-react",
"@babel/preset-typescript"
]
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,6 @@ typings/

# next.js build output
.next

# dist
dist/
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ install:

script:
- npm test

after_script: "cat coverage/lcov.info | node_modules/coveralls/bin/coveralls.js"
- npm run coveralls
Empty file added .watchmanconfig
Empty file.
39 changes: 39 additions & 0 deletions __tests__/plug.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as React from 'react';
import { render, cleanup, waitForElement } from 'react-testing-library';
import 'jest-dom/extend-expect'
import { PluggedTestComponent } from '../lib/utils/example-plug';
import { setTotal10ChangedTrue } from '../lib/utils/example-store';

describe('Plug', () => {
afterEach(cleanup);

it('Renders', async done => {
const { getByTestId } = render(<PluggedTestComponent name="Test Testersson" />);

const nameNode = await waitForElement(() => getByTestId('name'))
const totalNode = await waitForElement(() => getByTestId('total'))
const changedNode = await waitForElement(() => getByTestId('changed'))

expect(nameNode).toHaveTextContent('Test Testersson');
expect(totalNode).toHaveTextContent('Total: 0');
expect(changedNode).toHaveTextContent(`The store wasn't changed`);
done();
})

it('Renders with new State', async done => {
setTotal10ChangedTrue();

const { getByTestId } = render(<PluggedTestComponent name="Test Testersson" />);

const nameNode = await waitForElement(() => getByTestId('name'))
const totalNode = await waitForElement(() => getByTestId('total'))
const changedNode = await waitForElement(() => getByTestId('changed'))

expect(nameNode).toHaveTextContent('Test Testersson');
expect(totalNode).toHaveTextContent('Total: 10');
expect(changedNode).toHaveTextContent(`The store was changed`);
done();
})
})


74 changes: 74 additions & 0 deletions __tests__/store.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { take, skip } from 'rxjs/operators';
import { state$, setTotal10ChangedTrue, setTotal20, getCurrentState, setTotalDouble } from '../lib/utils/example-store';

describe('Store', () => {
beforeAll(() => {
process.env = Object.assign(process.env, { isTesting: 'true' });
});

it('Creates a Store', async done => {
state$.pipe(
take(1)
).subscribe(data => {
expect(data).toEqual({
total: 0,
changed: false
});
done();
})
});

it('Update State', async done => {
state$.pipe(
skip(1),
take(1)
).subscribe(data => {
expect(data).toEqual({
total: 10,
changed: true
});
done();
});

setTotal10ChangedTrue();
});

it('Update State Partially', async done => {
state$.pipe(
skip(1),
take(1)
).subscribe(data => {
expect(data).toEqual({
total: 20,
changed: true
});
done();
})

setTotal20();
});

it('Retrieve current State', () => {
const currentState = getCurrentState();

expect(currentState).toEqual({
total: 20,
changed: true
});
});

it('Update State using Callback', async done => {
state$.pipe(
skip(1),
take(1)
).subscribe(data => {
expect(data).toEqual({
total: 40,
changed: true
});
done();
})

setTotalDouble();
});
})
1 change: 0 additions & 1 deletion dist/index.d.ts

This file was deleted.

6 changes: 0 additions & 6 deletions dist/index.js

This file was deleted.

17 changes: 17 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {
roots: [
"<rootDir>"
],
globals: {
'ts-jest': {
babelConfig: true
}
},
moduleFileExtensions: [
"ts",
"tsx",
"js",
"jsx",
"json"
],
}
8 changes: 6 additions & 2 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export function testLib(): string {
return `It's working!`;
import { plug } from "./plug";
import { createStore } from "./store";

export {
plug,
createStore
}
13 changes: 13 additions & 0 deletions lib/interfaces/plug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Observable } from "rxjs";

export type TStream = (stream: any) => Observable<any>;

export interface ILifecycle {
componentDidMount: () => void;
componentWillUnmount: () => void;
}

export interface IPlugState {
hasEmmited: boolean;
innerData?: any;
}
8 changes: 8 additions & 0 deletions lib/interfaces/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Observable } from 'rxjs';

export interface IStore<T> {
state$: Observable<T>;
updateState(request: Function | Partial<T>): void;
stateInjector<T>(func: Function): () => T;
getCurrentState(): T;
}
51 changes: 51 additions & 0 deletions lib/plug.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from 'react';
import { Component } from 'react';
import { Subscription } from 'rxjs';
import { TStream, ILifecycle, IPlugState } from './interfaces/plug';


export const plug = <T extends {}>(stream: TStream, lifecycleHooks: Partial<ILifecycle> = {},
) => (WrappedComponent: any) =>
class PluggedComponent extends Component<T, IPlugState> {

_streamSubscription!: Subscription;

constructor(props: any) {
super(props);

this.state = {
hasEmmited: false,
};
}

public componentDidMount() {
this._streamSubscription = stream(this.props).subscribe((data: any) =>
this.setState({
hasEmmited: true,
innerData: data,
}),
);

if (lifecycleHooks.componentDidMount) {
lifecycleHooks.componentDidMount();
}
}

public componentWillUnmount() {
this._streamSubscription.unsubscribe();

if (lifecycleHooks.componentWillUnmount) {
lifecycleHooks.componentWillUnmount();
}
}

public render() {
const { hasEmmited, innerData } = this.state;

if (hasEmmited) {
return <WrappedComponent {...innerData} />;
}

return null;
}
}
34 changes: 34 additions & 0 deletions lib/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { IStore } from './interfaces/store';
import { BehaviorSubject } from 'rxjs';
import { clone } from './utils/clone';

function createStore<IState>(initialState: IState): IStore<IState> {
const behavior$ = new BehaviorSubject<IState>(clone(initialState));
const updateState = (request: any) => {
const isFunction = request instanceof Function;
const currentState = clone(behavior$.getValue());
const newKeys = isFunction ? request(currentState) : request;

behavior$.next({
...(currentState as any),
...newKeys
});
};

function stateInjector<T>(func: Function): () => T {
return (): T => func(behavior$.getValue());
}

const getCurrentState = (): any => behavior$.getValue();

const state$ = behavior$.asObservable();

return {
state$,
stateInjector,
updateState,
getCurrentState,
};
}

export { createStore };
1 change: 1 addition & 0 deletions lib/utils/clone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const clone = (target: any) => JSON.parse(JSON.stringify(target));
40 changes: 40 additions & 0 deletions lib/utils/example-plug.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from 'react';
import { plug } from "../../lib";
import { map, combineLatest } from "rxjs/operators";
import { of, Observable } from "rxjs";
import { IStore, state$ } from './example-store';

interface IProp {
name: string;
}

const TestComponent = (props: IStore & IProp) => {
const { total, changed, name } = props;
return (
<div>
<h1 data-testid="name">{name}</h1>
<p data-testid="total">Total: {total}</p>
<p data-testid="changed">The store was{changed ? '' : `n't`} changed.</p>
</div>
)
}

const stream = (props: IProp): Observable<IStore & IProp> => {
return of(props).pipe(
combineLatest(state$),
map(([props, state]) => {
const data: IStore & IProp = {
name: props.name,
...state
}
return data;
})
);
}


const PluggedTestComponent = plug<IProp>(stream)(TestComponent);

export {
PluggedTestComponent,
}
33 changes: 33 additions & 0 deletions lib/utils/example-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createStore } from "../../lib";

export interface IStore {
total: number;
changed: boolean;
}

const initialState: IStore = {
total: 0,
changed: false
}

const { updateState, getCurrentState, state$ } = createStore(initialState);

const setTotal10ChangedTrue = () => updateState({
total: 10, changed: true
});

const setTotal20 = () => updateState({
total: 20
});

const setTotalDouble = () => updateState((state: any) => ({
total: state.total * 2
}));

export {
state$,
getCurrentState,
setTotal10ChangedTrue,
setTotal20,
setTotalDouble
}
Loading

0 comments on commit fba0249

Please sign in to comment.