├── .babelrc ├── .eslintrc ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── README.md ├── demo ├── .env.example ├── index.html ├── now.json └── src │ ├── Divider │ └── index.js │ ├── InnerContainer │ └── index.js │ ├── Items │ └── index.js │ ├── OuterContainer │ └── index.js │ ├── Title │ └── index.js │ ├── global.js │ └── index.js ├── media └── react-local-currency.png ├── package.json ├── src ├── api │ ├── get-rates.js │ └── ip-data.js ├── index.js └── utils │ ├── conversor.js │ └── request.js ├── tests ├── get-rates.mock.json ├── index.test.js └── ip-data.mock.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | presets: [ 3 | '@babel/preset-env', 4 | '@babel/preset-react' 5 | ], 6 | plugins: [ 7 | ['@babel/plugin-proposal-class-properties'], 8 | ['@babel/plugin-transform-runtime', { 'regenerator': true }] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["standard", "standard-react", "plugin:jest/recommended"], 3 | "parser": "babel-eslint" 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # Testing 9 | /coverage 10 | 11 | # Production 12 | /build 13 | /example 14 | /dist 15 | /demo/dist 16 | 17 | # Misc 18 | .DS_Store 19 | 20 | # Env 21 | .env 22 | .env.local 23 | 24 | # Log 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # Cache 30 | /.cache 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - 8 6 | 7 | before_install: 8 | - npm install codecov.io coveralls 9 | 10 | after_success: 11 | - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js 12 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 13 | 14 | branches: 15 | only: 16 | - master 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | [Node.js](http://nodejs.org/) >= 6 must be installed. 4 | 5 | ## Installation 6 | 7 | - Running `npm install` in the component's root directory will install everything you need for development. 8 | 9 | ## Demo Development Server 10 | 11 | - `npm start` will run a development server with the component's demo app at [http://localhost:3000](http://localhost:3000) with hot module reloading. 12 | 13 | ## Running Tests 14 | 15 | - `npm test` will run the tests once. 16 | 17 | - `npm run test:coverage` will run the tests and produce a coverage report in `coverage/`. 18 | 19 | - `npm run test:watch` will run the tests on every change. 20 | 21 | ## Building 22 | 23 | - `npm run build` will build the component for publishing to npm and also bundle the demo app. 24 | 25 | - `npm run clean` will delete built resources. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # React Local Currency 3 | 4 | [![Travis][build-badge]][build] [![npm package][npm-badge]][npm] [![Coveralls][codecov-badge]][codecov] 5 | 6 |

7 | Logo 8 |

9 | 10 | 11 | ## Installation 12 | 13 | First, install the component: 14 | 15 | ```bash 16 | yarn add react-local-currency 17 | ``` 18 | or 19 | ```bash 20 | npm i react-local-currency --save 21 | ``` 22 | 23 | ## Usage 24 | 25 | ```js 26 | import * as React from 'react' 27 | import LocalCurrency from 'react-local-currency' 28 | 29 | const ReactLocalCurrency = () => ( 30 | { 36 | if (error) return `Error! ${error.message}` 37 | 38 | if (loading) return 'Loading ...' 39 | 40 | if (!data) return null 41 | 42 | return ( 43 |
44 |

45 | My service price: 7 USD. 46 |

47 |

48 | My currency based on my IP: {`${data.currency}`} 49 |

50 |

51 | My local price is: {`${data.amount} ${data.currency}`} 52 |

53 |
54 | ) 55 | }} 56 | /> 57 | ) 58 | 59 | export default ReactLocalCurrency 60 | ``` 61 | 62 | To see a full example, look at the [demo](https://react-local-currency.unichat.io) and the [source](https://github.com/unichat-io/react-local-currency/tree/master/demo/src) 👩🏻‍💻 👨🏻‍💻 63 | 64 | ## Credits 65 | 66 | Thanks to [Nadia Ilustraciones](http://nadiailustraciones.com) for donating the logo! 67 | 68 | ## Authors 69 | 70 | - [Sebastián Lorenzo](https://github.com/slorenzo) 71 | 72 | ## Sponsored by 73 | 74 | - [UNICHAT](https://unichat.io) 75 | 76 | ## License 77 | 78 | MIT license. Copyright © 2018. 79 | 80 | [build-badge]: https://travis-ci.org/unichat-io/react-local-currency.svg?branch=master 81 | [build]: https://travis-ci.org/unichat-io/react-local-currency 82 | 83 | [npm-badge]: https://img.shields.io/npm/v/react-local-currency.svg 84 | [npm]: https://www.npmjs.org/package/react-local-currency 85 | 86 | [codecov-badge]: https://codecov.io/gh/unichat-io/react-local-currency/branch/master/graph/badge.svg 87 | [codecov]: https://codecov.io/gh/unichat-io/react-local-currency 88 | -------------------------------------------------------------------------------- /demo/.env.example: -------------------------------------------------------------------------------- 1 | REACT_IPDATA_API_KEY= 2 | REACT_APP_OXR_API_ID= -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Local Currency Demo 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /demo/now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "name": "react-local-currency-demo", 4 | "alias": [ 5 | "react-local-currency" 6 | ], 7 | "type": "static", 8 | "static": { 9 | "public": "dist", 10 | "rewrites": [ 11 | { 12 | "source": "**", 13 | "destination": "/index.html" 14 | } 15 | ] 16 | } 17 | } -------------------------------------------------------------------------------- /demo/src/Divider/index.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Divider = styled.hr` 4 | border: 0; 5 | background: #1A237E; 6 | box-shadow: 0px 0px 5px 1px #1A237E; 7 | ` 8 | 9 | export default Divider 10 | -------------------------------------------------------------------------------- /demo/src/InnerContainer/index.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Container = styled.main` 4 | width: max-content; 5 | padding: 30px; 6 | background-color: #3f51b5; 7 | color: white; 8 | border-radius: 5px; 9 | box-shadow: 0px 2px 10px 0px #1A237E; 10 | ` 11 | 12 | export default Container 13 | -------------------------------------------------------------------------------- /demo/src/Items/index.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Container = styled.div` 4 | margin: 40px 0; 5 | > h3 { 6 | font-weight: 200; 7 | } 8 | ` 9 | 10 | export default Container 11 | -------------------------------------------------------------------------------- /demo/src/OuterContainer/index.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const OuterContainer = styled.div` 4 | height: 100%; 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | background-color: #283593; 9 | ` 10 | 11 | export default OuterContainer 12 | -------------------------------------------------------------------------------- /demo/src/Title/index.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Title = styled.h1` 4 | font-weight: 200; 5 | ` 6 | 7 | export default Title 8 | -------------------------------------------------------------------------------- /demo/src/global.js: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components' 2 | 3 | const GlobalStyle = createGlobalStyle` 4 | html, body, #demo { 5 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 6 | height: 100%; 7 | margin: 0; 8 | font-size: 13px; 9 | } 10 | ` 11 | 12 | export default GlobalStyle 13 | -------------------------------------------------------------------------------- /demo/src/index.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { render } from 'react-dom' 3 | 4 | import LocalCurrency from '../../src' 5 | 6 | import Title from './Title' 7 | import Items from './Items' 8 | import OuterContainer from './OuterContainer' 9 | import InnerContainer from './InnerContainer' 10 | import Divider from './Divider' 11 | 12 | import GlobalStyles from './global' 13 | 14 | class ReactLocalCurrencyDemo extends React.Component { 15 | render () { 16 | return ( 17 | 18 | 19 | 20 | 21 | 22 | Shows the price of your services <br /> in the customer's currency <br /> 💶 💷 💵 💴 23 | 24 | 25 | { 31 | if (error) return `Error! ${error.message}` 32 | 33 | if (loading) return 'Loading ...' 34 | 35 | if (!data) return null 36 | 37 | return ( 38 | 39 |

40 | My service price: 7 USD. 41 |

42 |

43 | My currency based on my IP: {`${data.currency}`} 44 |

45 |

46 | My local price is: {`${data.amount} ${data.currency}`} 47 |

48 |
49 | ) 50 | }} 51 | /> 52 |
53 |
54 |
55 | ) 56 | } 57 | } 58 | 59 | render(, document.querySelector('#demo')) 60 | -------------------------------------------------------------------------------- /media/react-local-currency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unichat-io/react-local-currency/dad089dd5980f9d76bed6ab01d4e271ea2a7bc80/media/react-local-currency.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-local-currency", 3 | "version": "1.1.0", 4 | "description": "💶 💷 Shows the price of your services in the customer's currency 💵 💴", 5 | "main": "dist/react-local-currency.js", 6 | "umd:main": "dist/react-local-currency.umd.js", 7 | "module": "dist/react-local-currency.m.js", 8 | "source": "src/index.js", 9 | "files": [ 10 | "dist/", 11 | "README.md" 12 | ], 13 | "scripts": { 14 | "example": "parcel ./demo/index.html --out-dir example", 15 | "build": "microbundle -o dist/ --sourcemap false --compress false --external url-join urlJoin", 16 | "dev": "microbundle watch -o dist/ --sourcemap false --compress false --external url-join urlJoin", 17 | "eslint": "eslint ./src && eslint ./demo", 18 | "test": "jest", 19 | "coverage": "jest --coverage", 20 | "snapshots": "jest -u", 21 | "prepublishOnly": "npm run build" 22 | }, 23 | "dependencies": { 24 | "money": "github:ducdigital/money.js", 25 | "url-join": "^4.0.0" 26 | }, 27 | "peerDependencies": { 28 | "react": "16.x" 29 | }, 30 | "jest": { 31 | "testPathIgnorePatterns": [ 32 | "/node_modules/", 33 | "/demo/", 34 | "/example/", 35 | "/dist/", 36 | "/media/" 37 | ], 38 | "automock": false, 39 | "verbose": true, 40 | "testRegex": "\\.test\\.js$", 41 | "testURL": "http://localhost/" 42 | }, 43 | "devDependencies": { 44 | "@babel/core": "^7.2.2", 45 | "@babel/plugin-proposal-class-properties": "^7.3.0", 46 | "@babel/plugin-transform-runtime": "^7.2.0", 47 | "@babel/preset-env": "^7.3.1", 48 | "@babel/preset-react": "^7.0.0", 49 | "babel-eslint": "^10.0.1", 50 | "enzyme": "^3.8.0", 51 | "enzyme-adapter-react-16": "^1.8.0", 52 | "eslint": "^5.12.1", 53 | "eslint-config-standard": "^12.0.0", 54 | "eslint-config-standard-react": "^7.0.2", 55 | "eslint-plugin-import": "^2.16.0", 56 | "eslint-plugin-jest": "^22.1.3", 57 | "eslint-plugin-node": "^8.0.1", 58 | "eslint-plugin-promise": "^4.0.1", 59 | "eslint-plugin-react": "^7.12.4", 60 | "eslint-plugin-standard": "^4.0.0", 61 | "fetch-mock": "^7.3.0", 62 | "jest": "^24.0.0", 63 | "microbundle": "^0.9.0", 64 | "parcel-bundler": "^1.11.0", 65 | "prop-types": "^15.6.2", 66 | "react": "^16.7.0", 67 | "react-dom": "^16.7.0", 68 | "styled-components": "^4.1.3" 69 | }, 70 | "author": "Sebastián Lorenzo ", 71 | "homepage": "", 72 | "license": "MIT", 73 | "repository": "https://github.com/unichat-io/react-local-currency", 74 | "keywords": [ 75 | "react-component", 76 | "currency", 77 | "currencies", 78 | "money", 79 | "exchange", 80 | "convert" 81 | ] 82 | } 83 | -------------------------------------------------------------------------------- /src/api/get-rates.js: -------------------------------------------------------------------------------- 1 | const getRates = (OXR_API_ID, base) => { 2 | const url = `https://openexchangerates.org/api/latest.json?base=${base}&app_id=${OXR_API_ID}` 3 | 4 | return fetch(url, { method: 'GET' }) // eslint-disable-line 5 | } 6 | 7 | export default getRates 8 | -------------------------------------------------------------------------------- /src/api/ip-data.js: -------------------------------------------------------------------------------- 1 | import urlJoin from 'url-join' 2 | 3 | const ipdata = (ip, apiKey) => { 4 | const url = urlJoin('https://api.ipdata.co/', `?api-key=${apiKey}`) 5 | 6 | return fetch(url, { method: 'GET' }) // eslint-disable-line 7 | } 8 | 9 | export default ipdata 10 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | import getRates from './api/get-rates' 5 | import ipdata from './api/ip-data' 6 | 7 | import conversor from './utils/conversor' 8 | import { checkHttpStatus, parseJSON } from './utils/request' 9 | 10 | class LocalCurrency extends React.PureComponent { 11 | static displayName = 'LocalCurrency' 12 | 13 | static propTypes = { 14 | accept: PropTypes.array, 15 | amount: PropTypes.number.isRequired, 16 | base: PropTypes.string.isRequired, 17 | IPDATA_API_KEY: PropTypes.string.isRequired, 18 | OXR_API_ID: PropTypes.string.isRequired, 19 | children: PropTypes.func, 20 | render: PropTypes.func 21 | }; 22 | 23 | static defaultProps = { 24 | children: null, 25 | render: null, 26 | accept: [] 27 | } 28 | 29 | state = { 30 | data: null, 31 | loading: true, 32 | error: null 33 | } 34 | 35 | async componentDidMount () { 36 | const { OXR_API_ID, amount, base } = this.props 37 | 38 | try { 39 | const { currency } = await this.getDataFromIPData() 40 | 41 | const r = await getRates(OXR_API_ID, base) 42 | .then(checkHttpStatus) 43 | .then(parseJSON) 44 | 45 | const fxInstance = conversor(r) 46 | 47 | this.setState({ 48 | data: { 49 | amount: fxInstance(amount).from(base).to(currency.code), 50 | currency: currency.code 51 | }, 52 | loading: null, 53 | error: null 54 | }) 55 | } catch (error) { 56 | this.setState({ 57 | error, 58 | loading: null 59 | }) 60 | } 61 | } 62 | 63 | async getDataFromIPData () { 64 | const { IPDATA_API_KEY, accept } = this.props 65 | 66 | const { currency, threat } = await ipdata(null, IPDATA_API_KEY) 67 | .then(checkHttpStatus) 68 | .then(parseJSON) 69 | 70 | if (threat.is_tor || threat.is_proxy || threat.is_anonymous) { 71 | throw new Error('Unable to find the customer\'s currency') 72 | } 73 | 74 | if (!accept.lenght && accept.includes(currency)) { 75 | throw new Error('Invalid currency') 76 | } 77 | 78 | return { currency } 79 | } 80 | 81 | render () { 82 | const { children, render } = this.props 83 | 84 | if (children) { 85 | return children(this.state) 86 | } 87 | if (render) { 88 | return render(this.state) 89 | } 90 | 91 | console.error( 92 | 'Component LocalCurrency:', 93 | 'no children or render prop are present' 94 | ) 95 | 96 | return null 97 | } 98 | } 99 | 100 | export default LocalCurrency 101 | -------------------------------------------------------------------------------- /src/utils/conversor.js: -------------------------------------------------------------------------------- 1 | import * as fx from 'money' 2 | 3 | const conversor = ({ rates, base }) => { 4 | const fxInstance = fx.factory() 5 | fxInstance.rates = rates 6 | fxInstance.base = base 7 | 8 | return fxInstance 9 | } 10 | 11 | export default conversor 12 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | const checkHttpStatus = (response) => { 2 | if (response.status >= 200 && response.status < 300) { 3 | return response 4 | } 5 | const error = new Error(response.statusText) 6 | error.response = response 7 | throw error 8 | } 9 | 10 | const parseJSON = response => response.json() 11 | 12 | export { 13 | checkHttpStatus, 14 | parseJSON 15 | } 16 | -------------------------------------------------------------------------------- /tests/get-rates.mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "timestamp": 1543158004, 3 | "base": "USD", 4 | "rates": { 5 | "AED": 3.673175, 6 | "AFN": 76.0855, 7 | "ALL": 109.825382, 8 | "AMD": 484.137923, 9 | "ANG": 1.775895, 10 | "AOA": 310.4535, 11 | "ARS": 37.564, 12 | "AUD": 1.381788, 13 | "AWG": 1.800506, 14 | "AZN": 1.7025, 15 | "BAM": 1.724308, 16 | "BBD": 2, 17 | "BDT": 83.929782, 18 | "BGN": 1.726675, 19 | "BHD": 0.377162, 20 | "BIF": 1784.000614, 21 | "BMD": 1, 22 | "BND": 1.375544, 23 | "BOB": 6.913367, 24 | "BRL": 3.83135, 25 | "BSD": 1, 26 | "BTC": 0.00026174781, 27 | "BTN": 70.624959, 28 | "BWP": 10.554971, 29 | "BYN": 2.108284, 30 | "BZD": 2.016658, 31 | "CAD": 1.323951, 32 | "CDF": 1644.261765, 33 | "CHF": 0.997195, 34 | "CLF": 0.024214, 35 | "CLP": 674.718354, 36 | "CNH": 6.945373, 37 | "CNY": 6.94837, 38 | "COP": 3190.8, 39 | "CRC": 601.086612, 40 | "CUC": 1, 41 | "CUP": 25.75, 42 | "CVE": 97.55025, 43 | "CZK": 22.86915, 44 | "DJF": 178, 45 | "DKK": 6.582197, 46 | "DOP": 49.93479, 47 | "DZD": 118.67, 48 | "EGP": 17.892, 49 | "ERN": 14.99759, 50 | "ETB": 27.946453, 51 | "EUR": 0.88164, 52 | "FJD": 2.111099, 53 | "FKP": 0.77991, 54 | "GBP": 0.77991, 55 | "GEL": 2.653677, 56 | "GGP": 0.77991, 57 | "GHS": 4.902385, 58 | "GIP": 0.77991, 59 | "GMD": 49.555, 60 | "GNF": 9085.381617, 61 | "GTQ": 7.718767, 62 | "GYD": 209.319266, 63 | "HKD": 7.82575, 64 | "HNL": 24.395916, 65 | "HRK": 6.5575, 66 | "HTG": 73.323442, 67 | "HUF": 284.42, 68 | "IDR": 14540, 69 | "ILS": 3.73425, 70 | "IMP": 0.77991, 71 | "INR": 70.604, 72 | "IQD": 1191, 73 | "IRR": 42495.428797, 74 | "ISK": 123.720231, 75 | "JEP": 0.77991, 76 | "JMD": 125.976131, 77 | "JOD": 0.709504, 78 | "JPY": 112.95, 79 | "KES": 102.58, 80 | "KGS": 68.708449, 81 | "KHR": 4047.461927, 82 | "KMF": 434.62122, 83 | "KPW": 900, 84 | "KRW": 1133.85, 85 | "KWD": 0.304256, 86 | "KYD": 0.833771, 87 | "KZT": 366.357352, 88 | "LAK": 8544.631351, 89 | "LBP": 1513.596726, 90 | "LKR": 179.68559, 91 | "LRD": 158.049825, 92 | "LSL": 13.86, 93 | "LYD": 1.395132, 94 | "MAD": 9.513262, 95 | "MDL": 17.1885, 96 | "MGA": 3620, 97 | "MKD": 54.235464, 98 | "MMK": 1600.799201, 99 | "MNT": 2489.666667, 100 | "MOP": 8.064407, 101 | "MRO": 357, 102 | "MRU": 36.57, 103 | "MUR": 34.550198, 104 | "MVR": 15.450044, 105 | "MWK": 724.019018, 106 | "MXN": 20.4115, 107 | "MYR": 4.197449, 108 | "MZN": 60.500323, 109 | "NAD": 13.860293, 110 | "NGN": 364, 111 | "NIO": 32.3905, 112 | "NOK": 8.596975, 113 | "NPR": 113.105282, 114 | "NZD": 1.474492, 115 | "OMR": 0.384996, 116 | "PAB": 1, 117 | "PEN": 3.377985, 118 | "PGK": 3.370749, 119 | "PHP": 52.399, 120 | "PKR": 134.43, 121 | "PLN": 3.7853, 122 | "PYG": 5930.926074, 123 | "QAR": 3.64275, 124 | "RON": 4.109993, 125 | "RSD": 104.38, 126 | "RUB": 66.2125, 127 | "RWF": 890.104418, 128 | "SAR": 3.7519, 129 | "SBD": 7.99389, 130 | "SCR": 13.676927, 131 | "SDG": 47.633916, 132 | "SEK": 9.093394, 133 | "SGD": 1.375298, 134 | "SHP": 0.77991, 135 | "SLL": 8390, 136 | "SOS": 578.79812, 137 | "SRD": 7.458, 138 | "SSP": 130.2634, 139 | "STD": 21050.59961, 140 | "STN": 21.6, 141 | "SVC": 8.746825, 142 | "SYP": 514.993439, 143 | "SZL": 13.860418, 144 | "THB": 33.0755, 145 | "TJS": 9.424641, 146 | "TMT": 3.499986, 147 | "TND": 2.916373, 148 | "TOP": 2.29206, 149 | "TRY": 5.287506, 150 | "TTD": 6.74333, 151 | "TWD": 30.942037, 152 | "TZS": 2300.1, 153 | "UAH": 27.763611, 154 | "UGX": 3738.744588, 155 | "USD": 1, 156 | "UYU": 32.531043, 157 | "UZS": 8281.619259, 158 | "VEF": 248487.642241, 159 | "VES": 77.02285, 160 | "VND": 23263.302672, 161 | "VUV": 110.226271, 162 | "WST": 2.610819, 163 | "XAF": 578.317929, 164 | "XAG": 0.06998147, 165 | "XAU": 0.00081755, 166 | "XCD": 2.70255, 167 | "XDR": 0.718712, 168 | "XOF": 578.317929, 169 | "XPD": 0.0008913, 170 | "XPF": 105.207637, 171 | "XPT": 0.00118908, 172 | "YER": 250.349279, 173 | "ZAR": 13.858315, 174 | "ZMW": 11.880976, 175 | "ZWL": 322.355011 176 | } 177 | } -------------------------------------------------------------------------------- /tests/index.test.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import expect from 'expect' 3 | import Enzyme, { shallow } from 'enzyme' 4 | import Adapter from 'enzyme-adapter-react-16' 5 | 6 | import fetchMock from 'fetch-mock' 7 | 8 | import LocalCurrency from '../src' 9 | 10 | Enzyme.configure({ adapter: new Adapter() }) 11 | 12 | const noop = () => undefined 13 | const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms)) 14 | 15 | describe('React Local Currency', () => { 16 | beforeAll(() => { 17 | fetchMock.mock('https://openexchangerates.org/api/latest.json?base=USD&app_id=test', require('./get-rates.mock.json')) 18 | fetchMock.mock('https://api.ipdata.co/?api-key=test', require('./ip-data.mock.json')) 19 | }) 20 | 21 | it('It renders without breaking using render as property', () => { 22 | const wrapper = shallow( 23 | 30 | ) 31 | 32 | expect(wrapper.length).toBe(1) 33 | }) 34 | 35 | it('It renders without breaking using render as children elements', () => { 36 | const wrapper = shallow( 37 | 43 | {() =>
} 44 | 45 | ) 46 | 47 | expect(wrapper.length).toBe(1) 48 | }) 49 | 50 | it('It renders breaking - Wrong initialize ', () => { 51 | const wrapper = shallow( 52 | 58 | ) 59 | 60 | expect(wrapper.isEmptyRender()).toBe(true) 61 | }) 62 | 63 | it('Initialize sets initial state', async () => { 64 | const wrapper = shallow( 65 | 72 | ) 73 | 74 | expect(wrapper.state().loading).toBe(true) 75 | expect(wrapper.state().error).toBe(null) 76 | expect(wrapper.state().data).toBe(null) 77 | }) 78 | 79 | it('It should convert USD to ARS', async () => { 80 | const wrapper = shallow( 81 | 88 | ) 89 | 90 | await wait(100) 91 | 92 | expect(wrapper.state().loading).toBe(null) 93 | expect(wrapper.state().error).toBe(null) 94 | expect(wrapper.state().data.currency).toBe('ARS') 95 | expect(wrapper.state().data.amount).toBe(262.948) 96 | }) 97 | }) 98 | -------------------------------------------------------------------------------- /tests/ip-data.mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "currency": { 3 | "name": "Argentine Peso", 4 | "code": "ARS", 5 | "symbol": "AR$", 6 | "native": "$", 7 | "plural": "Argentine pesos" 8 | }, 9 | "threat": { 10 | "is_tor": false, 11 | "is_proxy": false, 12 | "is_anonymous": false, 13 | "is_known_attacker": false, 14 | "is_known_abuser": false, 15 | "is_threat": false, 16 | "is_bogon": false 17 | } 18 | } --------------------------------------------------------------------------------