Skip to content

Commit

Permalink
feat(providers): add basic and redux [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael A Tomcal authored Sep 15, 2020
1 parent 0c7ff61 commit 55e5393
Show file tree
Hide file tree
Showing 16 changed files with 559 additions and 47 deletions.
7 changes: 6 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"presets": ["amex"]
"presets": ["amex"],
"plugins": [
[
"@babel/transform-runtime"
]
]
}
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"extends": "amex",
"rules": {
"unicorn/prevent-abbreviations": "off"
}
},
"ignorePatterns": ["examples/**"]
}
123 changes: 123 additions & 0 deletions __tests__/FetchyeProvider.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2020 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import React, { useContext, useEffect } from 'react';
import { render } from '@testing-library/react';
import * as actions from '../src/cache/actions';
import { FetchyeContext } from '../src/FetchyeContext';
import { FetchyeProvider } from '../src/FetchyeProvider';

global.fetch = () => {};

describe('FetchyeProvider', () => {
it('should create fetchye context with global fetch', () => {
let contextResult;
render(
<FetchyeProvider>
{React.createElement(() => {
contextResult = useContext(FetchyeContext);
return <fake-element />;
})}
</FetchyeProvider>
);
expect(contextResult.fetchClient).toEqual(global.fetch);
});
it('should create fetchye context with custom fetch', () => {
const fakeFetchClient = jest.fn();
render(
<FetchyeProvider fetchClient={fakeFetchClient}>
{React.createElement(() => {
const { fetchClient } = useContext(FetchyeContext);
fetchClient();
return <fake-element />;
})}
</FetchyeProvider>
);
expect(fakeFetchClient).toHaveBeenCalled();
});
it('should receive loading action and return loading state', () => {
let res;
render(
<FetchyeProvider>
{React.createElement(() => {
const { dispatch, useFetchyeSelector } = useContext(FetchyeContext);
useEffect(() => {
dispatch(actions.loadingAction({ hash: 'abc123' }));
}, [dispatch]);
res = useFetchyeSelector('abc123');
return <fake-element />;
})}
</FetchyeProvider>
);
expect(res).toMatchInlineSnapshot(`
Object {
"current": Object {
"data": undefined,
"error": undefined,
"loading": true,
},
}
`);
});
it('should receive data action and return data state', () => {
let res;
render(
<FetchyeProvider>
{React.createElement(() => {
const { dispatch, useFetchyeSelector } = useContext(FetchyeContext);
useEffect(() => {
dispatch(actions.setAction({ hash: 'abc123', value: 'fakeData' }));
}, [dispatch]);
res = useFetchyeSelector('abc123');
return <fake-element />;
})}
</FetchyeProvider>
);
expect(res).toMatchInlineSnapshot(`
Object {
"current": Object {
"data": "fakeData",
"error": undefined,
"loading": false,
},
}
`);
});
it('should receive error action and return error state', () => {
let res;
render(
<FetchyeProvider>
{React.createElement(() => {
const { dispatch, useFetchyeSelector } = useContext(FetchyeContext);
useEffect(() => {
dispatch(actions.errorAction({ hash: 'abc123', error: 'fake error' }));
}, [dispatch]);
res = useFetchyeSelector('abc123');
return <fake-element />;
})}
</FetchyeProvider>
);
expect(res).toMatchInlineSnapshot(`
Object {
"current": Object {
"data": undefined,
"error": "fake error",
"loading": false,
},
}
`);
});
});
87 changes: 87 additions & 0 deletions __tests__/FetchyeReduxProvider.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2020 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import React, { useContext } from 'react';
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { SimpleCache } from '../src/cache';
import { FetchyeContext } from '../src/FetchyeContext';
import { FetchyeReduxProvider } from '../src/FetchyeReduxProvider';

const store = createStore((state) => state, { initialState: {} });

global.fetch = () => {};

describe('FetchyeReduxProvider', () => {
it('should create fetchye context with global fetch', () => {
let contextResult;
render(
<Provider store={store}>
<FetchyeReduxProvider cache={SimpleCache()}>
{React.createElement(() => {
contextResult = useContext(FetchyeContext);
return <fake-element />;
})}
</FetchyeReduxProvider>
</Provider>
);
expect(contextResult).toMatchInlineSnapshot(`
Object {
"cache": Object {
"cacheSelector": [Function],
"getCacheByKey": [Function],
"reducer": [Function],
},
"defaultFetcher": [Function],
"dispatch": [Function],
"fetchClient": [Function],
"useFetchyeSelector": [Function],
}
`);
});
it('should create fetchye context with custom fetch', () => {
const fakeFetchClient = jest.fn();
render(
<Provider store={store}>
<FetchyeReduxProvider cache={SimpleCache()} fetchClient={fakeFetchClient}>
{React.createElement(() => {
const { fetchClient } = useContext(FetchyeContext);
fetchClient();
return <fake-element />;
})}
</FetchyeReduxProvider>
</Provider>
);
expect(fakeFetchClient).toHaveBeenCalled();
});
it('should call cacheSelector within useFetchyeSelector', () => {
const fakeCacheSelector = jest.fn((state) => state);
const cache = SimpleCache({ cacheSelector: fakeCacheSelector });
render(
<Provider store={store}>
<FetchyeReduxProvider cache={cache}>
{React.createElement(() => {
const { useFetchyeSelector } = useContext(FetchyeContext);
useFetchyeSelector();
return <fake-element />;
})}
</FetchyeReduxProvider>
</Provider>
);
expect(fakeCacheSelector).toHaveBeenCalled();
});
});
34 changes: 34 additions & 0 deletions __tests__/defaultEqualityChecker.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { defaultEqualityChecker } from '../src/defaultEqualityChecker';

const fakeSliceOfState = {
loading: true,
data: { fake: 'data' },
error: new Error('stuff'),
};

describe('defaultEqualityChecker', () => {
it('should return true when a and b are equal', () => {
expect(defaultEqualityChecker(fakeSliceOfState, fakeSliceOfState)).toEqual(true);
});
it('should return false when a.error and b.error arent equal', () => {
const b = {
...fakeSliceOfState,
error: new Error('changed'),
};
expect(defaultEqualityChecker(fakeSliceOfState, b)).toEqual(false);
});
it('should return false when a.data and b.data arent equal', () => {
const b = {
...fakeSliceOfState,
data: { fake: 'new data' },
};
expect(defaultEqualityChecker(fakeSliceOfState, b)).toEqual(false);
});
it('should return false when a.loading and b.loading arent equal', () => {
const b = {
...fakeSliceOfState,
loading: false,
};
expect(defaultEqualityChecker(fakeSliceOfState, b)).toEqual(false);
});
});
1 change: 1 addition & 0 deletions __tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe('index', () => {
it('should return public methods', () => {
expect(Object.keys(fetchye).sort()).toMatchInlineSnapshot(`
Array [
"FetchyeProvider",
"makeServerFetchye",
"useFetchye",
]
Expand Down
68 changes: 59 additions & 9 deletions __tests__/makeServerFetchye.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@

import { createStore } from 'redux';
import { makeServerFetchye } from '../src/makeServerFetchye';
import reducer from '../src/cache/immutable/reducer';
import { SimpleCache } from '../src/cache';

const store = createStore(reducer, reducer(undefined, { type: '' }));
const cache = SimpleCache();
const store = createStore(cache.reducer, cache.reducer(undefined, { type: '' }));

global.console.error = jest.fn();

Expand All @@ -43,7 +44,7 @@ describe('makeServerFetchye', () => {
}));
const fetchyeRes = await makeServerFetchye({
store,
cacheSelector: (state) => state,
cache,
fetchClient,
})('http://example.com');

Expand All @@ -59,7 +60,56 @@ describe('makeServerFetchye', () => {
"ok": true,
"status": 200,
},
"error": undefined,
"error": null,
}
`);
});
it('should return data in success state when using default cache', async () => {
const fetchClient = jest.fn(async () => ({
...defaultPayload,
}));
const fetchyeRes = await makeServerFetchye({
store,
fetchClient,
})('http://example.com');

expect(fetchyeRes).toMatchInlineSnapshot(`
Object {
"data": Object {
"body": Object {
"fakeData": true,
},
"headers": Object {
"content-type": "application/json",
},
"ok": true,
"status": 200,
},
"error": null,
}
`);
});
it('should return data in success state if no cache and no store provided', async () => {
const fetchClient = jest.fn(async () => ({
...defaultPayload,
}));
const fetchyeRes = await makeServerFetchye({
fetchClient,
})('http://example.com');

expect(fetchyeRes).toMatchInlineSnapshot(`
Object {
"data": Object {
"body": Object {
"fakeData": true,
},
"headers": Object {
"content-type": "application/json",
},
"ok": true,
"status": 200,
},
"error": null,
}
`);
});
Expand All @@ -69,7 +119,7 @@ describe('makeServerFetchye', () => {
});
const fetchyeRes = await makeServerFetchye({
store,
cacheSelector: (state) => state,
cache,
fetchClient,
})('http://example.com/one');

Expand All @@ -82,8 +132,8 @@ describe('makeServerFetchye', () => {
`);
expect(fetchyeRes).toMatchInlineSnapshot(`
Object {
"data": undefined,
"error": [Error: fake error],
"data": null,
"error": "Error: fake error",
}
`);
});
Expand All @@ -93,7 +143,7 @@ describe('makeServerFetchye', () => {
}));
const fetchye = makeServerFetchye({
store,
cacheSelector: (state) => state,
cache,
fetchClient,
});
await fetchye('http://example.com/two');
Expand All @@ -112,7 +162,7 @@ describe('makeServerFetchye', () => {
"ok": true,
"status": 200,
},
"error": undefined,
"error": null,
}
`);
});
Expand Down
3 changes: 0 additions & 3 deletions __tests__/queryHelpers.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,4 @@ describe('coerceSsrField', () => {
it('should return null if undefined', () => {
expect(coerceSsrField(undefined)).toEqual(null);
});
it('should pass through field if not error or undefined', () => {
expect(coerceSsrField('field')).toEqual('field');
});
});
Loading

0 comments on commit 55e5393

Please sign in to comment.