Skip to content
This repository has been archived by the owner on Jun 15, 2023. It is now read-only.

Commit

Permalink
Fix default resolver implementation + add contributing guide
Browse files Browse the repository at this point in the history
This resolves #1
  • Loading branch information
raibima committed Apr 30, 2018
1 parent b212f17 commit 6de069a
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 22 deletions.
15 changes: 15 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Contributing

Thanks for your interest in contributing to this project!

## Project setup

1. Fork and clone the repo
2. Run `yarn` to install dependencies
3. Create a branch for your PR with `git checkout -b pr/your-branch-name`

## Committing and Pushing changes

Please make sure to run the tests before you commit your changes. You can run `yarn test` which will build the binaries (ensuring no compile-time errors), and run all test suites (ensuring no run-time regressions).

[issues]: https://github.com/traveloka/react-accio/issues
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,33 @@ componentDidMount() {

## Writing a resolver

TODO
When you buy a car, you get a working vehicle already assembled and preconfigured for you by the manufacturer. But sometimes you want more powers out of it, so instead of buying a new car (which would cost you another fortune) you can just replace the engine with a superior one, leaving the body, interior, and everything else the same. Accio works the same way, it allows you to replace the built-in resolver with a custom one that is more suitable to your use cases. Think of an Accio resolver as the engine in the car analogy, i.e., **if you want more control over how you fetch data from the network (e.g., use `axios` instead of `window.fetch`) just write your own custom resolver**.

Accio resolver has the following typedef:
```js
type Resolver = (
url: string,
fetchOptions: Object,
context: Object
) => Promise<any>;
```

Resolver arguments are given based on the following rules:
1. url => Accio `url` prop
2. fetchOptions => any Accio prop that is not:
- 'children',
- 'url',
- 'context',
- 'defer',
- 'ignoreCache',
- 'onComplete',
- 'onError',
- 'onShowLoading',
- 'onStartFetching',
- 'timeout',
- '_cache'
3. context => Accio `context` prop

## Contributing

TODO
See [CONTRIBUTING.md](CONTRIBUTING.md)
82 changes: 72 additions & 10 deletions src/__tests__/Accio.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import 'dom-testing-library/extend-expect'
import 'dom-testing-library/extend-expect';

import React from 'react';
import ReactDOM from 'react-dom';
import defaultResolver from '../defaults/resolver';

import { Accio, AccioCacheProvider } from '../index';
import { render, wait, Simulate } from 'react-testing-library';
Expand All @@ -10,7 +11,9 @@ const renderAccio = fetchState => (
<div>
{fetchState.loading && <div data-testid="loading" />}
{fetchState.error && <div data-testid="error" />}
{fetchState.response && <div data-testid="response">{JSON.stringify(fetchState.response)}</div>}
{fetchState.response && (
<div data-testid="response">{JSON.stringify(fetchState.response)}</div>
)}
</div>
);

Expand Down Expand Up @@ -46,7 +49,9 @@ beforeEach(() => {

describe('<Accio />', () => {
test('Basic use', async () => {
const { getByTestId } = render(<Accio {...basicProps}>{renderAccio}</Accio>);
const { getByTestId } = render(
<Accio {...basicProps}>{renderAccio}</Accio>
);

expect(getByTestId('loading')).toBeInTheDOM();

Expand Down Expand Up @@ -87,7 +92,12 @@ describe('<Accio />', () => {
const onStartFetching = jest.fn();

render(
<Accio {...basicProps} onStartFetching={onStartFetching} onShowLoading={onShowLoading} onComplete={onComplete}>
<Accio
{...basicProps}
onStartFetching={onStartFetching}
onShowLoading={onShowLoading}
onComplete={onComplete}
>
{renderAccio}
</Accio>
);
Expand Down Expand Up @@ -127,11 +137,7 @@ describe('<Accio />', () => {
const resolverSpy = jest.spyOn(Accio.defaults, 'resolver');
const { getByText } = render(
<Accio {...basicProps} defer>
{({ trigger }) => (
<button onClick={trigger}>
Go!
</button>
)}
{({ trigger }) => <button onClick={trigger}>Go!</button>}
</Accio>
);
expect(resolverSpy).not.toHaveBeenCalled();
Expand Down Expand Up @@ -225,6 +231,62 @@ describe('<Accio />', () => {
});

expect(errorCount.resolver).toBe(notFunctionTypes.length);
expect(errorCount.method).toBe(notFunctionTypes.length + unsupportedMethods.length);
expect(errorCount.method).toBe(
notFunctionTypes.length + unsupportedMethods.length
);
});
});

describe('Accio.defaults.resolver', () => {
beforeEach(() => {
Accio.defaults.resolver = defaultResolver;

window.fetch = jest.fn((url, options) => {
return Promise.resolve({
json: () => {
if (url === basicProps.url) {
return Promise.resolve({
data: {
foo: 'bar',
},
});
}
return Promise.resolve({});
},
});
return Promise.resolve();
});
});

it('should behave correctly', async () => {
const { getByTestId } = render(
<Accio {...basicProps}>
{fetchProps => (
<div>
{fetchProps.response && (
<div data-testid="responseContainer">
{fetchProps.response.data.foo}
</div>
)}
</div>
)}
</Accio>
);

await wait(() => {
expect(getByTestId('responseContainer')).toHaveTextContent('bar');
});
});

it('should pass down url to window.fetch 1st argument as well as fetchOptions to window.fetch 2nd argument', () => {
render(<Accio {...basicProps}>{() => null}</Accio>);

expect(window.fetch).toHaveBeenCalledWith(
basicProps.url,
expect.objectContaining({
body: {},
method: 'GET',
})
);
});
});
12 changes: 2 additions & 10 deletions src/defaults/resolver.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import to from '../utils/to';

// default resolver
export default async function resolver(url, data) {
const [err, res] = await to(
fetch(url, {
body: JSON.stringify(data),
method: 'post',
headers: {
'Content-Type': 'application/json',
},
})
);
export default async function resolver(url, fetchOptions) {
const [err, res] = await to(fetch(url, fetchOptions));
if (err) {
throw new Error('Accio error: ' + err.message);
}
Expand Down

0 comments on commit 6de069a

Please sign in to comment.