├── .babelrc ├── .editorconfig ├── .github └── workflows │ └── continuous-integration.yml ├── .gitignore ├── .mocharc.json ├── .nvmrc ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bower.json ├── content └── logo.gif ├── dist ├── cep-promise-browser.js ├── cep-promise-browser.min.js ├── cep-promise.js └── cep-promise.min.js ├── index.d.ts ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── cep-promise.js ├── errors │ ├── cep-promise.js │ └── service.js ├── services │ ├── brasilapi.js │ ├── correios-alt.js │ ├── correios.js │ ├── index.js │ ├── viacep.js │ └── widenet.js └── utils │ └── promise-any.js └── test ├── e2e └── cep-promise.spec.js └── unit ├── cep-promise-browser.spec.js ├── cep-promise-node.spec.js ├── cep-promise-providers.spec.js ├── cep-promise-timeout.spec.js └── fixtures ├── brasilapi-cep-05010000-found.json ├── brasilapi-cep-99999999-error.json ├── cep-aberto-05010000-found.json ├── cep-aberto-99999999-error.json ├── correios-alt-cep-05010000-found.json ├── correios-alt-cep-99999999-error.json ├── response-bad-xml.xml ├── response-cep-05010000-found.xml ├── response-cep-invalid-format.xml ├── response-cep-not-found.xml ├── response-unknown-format.xml ├── viacep-cep-05010000-found.json ├── viacep-cep-99999999-error.json ├── widenet-cep-05010000-found.json └── widenet-cep-99999999-error.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": [ 4 | [ 5 | "@babel/plugin-transform-runtime" 6 | ] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.github/workflows/continuous-integration.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | node: [ '10', '11', '12', '13', '14' ] 17 | name: Node ${{ matrix.node }} sample 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Setup node 21 | uses: actions/setup-node@v2 22 | with: 23 | node-version: ${{ matrix.node }} 24 | - run: npm install 25 | - run: npm test 26 | 27 | - name: Coveralls 28 | uses: coverallsapp/github-action@master 29 | with: 30 | github-token: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # MacOS .DS_Store 30 | .DS_Store 31 | 32 | #Allow only web browser to be versioned 33 | dist/* 34 | !dist/cep-promise*.js 35 | 36 | #Intellij Ide 37 | .idea 38 | 39 | #Yarn 40 | yarn.lock 41 | 42 | # Intelij IDE stuff 43 | .idea/ 44 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeout": 60000, 3 | "require": "@babel/register" 4 | } 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Como contribuir com o projeto 2 | 3 | - [Instalando o projeto](#instalando-o-projeto) 4 | - [Reportando Issues](#reportando-issues) 5 | - [Submetendo Pull Requests](#submetendo-pull-requests) 6 | 7 | ## Instalando o projeto 8 | 9 | Para abrir um pull-request, primeiramente crie um fork do projeto para a sua conta, então clone o projeto em sua maquina: 10 | 11 | `git clone git@github.com:seu-usuario/cep-promise.git` 12 | 13 | Em seguida baixe os modulos necessários com: 14 | 15 | `npm install` 16 | 17 | Agora pronto, você já pode começar a contribuir com o projeto! 18 | 19 | ## Reportando Issues 20 | 21 | Você pode criar uma issue [aqui](https://github.com/BrasilAPI/cep-promise/issues), mas, lembre-se de ser claro e informar o máximo de detalhes possíveis. 22 | 23 | ## Submetendo Pull Requests 24 | * Crie pull requests pequenos, para que a revisão seja feita mais facilmente 25 | * Inclua detalhes do que está sendo feito na descrição 26 | * Altera a documentação se for necessário 27 | * Verifique se todos os testes estão passando localmente 28 | * Não esqueça de verificar o build com as validações de teste coverage e build no travis-ci 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Filipe Deschamps 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

CEP Promise

6 | 7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Known Vulnerabilities 22 | 23 |

24 | 25 |

26 | Busca por CEP integrado diretamente aos serviços dos Correios, ViaCEP e WideNet (Node.js e Browser) 27 |

28 | 29 | ## Features 30 | 31 | * Sempre atualizado em tempo-real por se conectar diretamente aos serviços dos Correios, ViaCEP e WideNet. 32 | * Possui alta disponibilidade por usar vários serviços como fallback. 33 | * Sempre retorna a resposta mais rápida por fazer as consultas de forma concorrente. 34 | * Sem limites de uso (rate limits) conhecidos. 35 | * Interface de Promise extremamente simples. 36 | * Suporte ao Node.js `10.x`, `11.x`, `12.x`, `13.x`, `14.x` e `@stable`. 37 | * Suporte ao Node.js `4.x`, `5.x`, `6.x`, `7.x`, `8.x`, `9.x`, até cep-promise versão `3.0.9`. 38 | * Suporte ao Node.js `0.10.x` e `0.12.x` até cep-promise versão `2.0.8`. 39 | * 100% de code coverage com testes unitários e E2E. 40 | * Desenvolvido utilizando ES6. 41 | 42 | 43 | ## Como utilizar 44 | 45 | Teste e aprenda aqui. 46 | 47 | ### Realizando uma consulta 48 | 49 | Por ser multifornecedor, a biblioteca irá resolver a Promise com o fornecedor que **mais rápido** lhe responder. 50 | 51 | ``` js 52 | import cep from 'cep-promise' 53 | 54 | cep('05010000') 55 | .then(console.log) 56 | 57 | // { 58 | // "cep": "05010000", 59 | // "state": "SP", 60 | // "city": "São Paulo", 61 | // "street": "Rua Caiubí", 62 | // "neighborhood": "Perdizes", 63 | // } 64 | ``` 65 | 66 | 67 | ### Você também poderá passar o CEP como Inteiro 68 | 69 | Em muitos sistemas o CEP é utilizado erroneamente como um Inteiro (e com isto cortando todos os zeros à esquerda). Caso este seja o seu caso, não há problema, pois a biblioteca irá preencher os caracteres faltantes na String, por exemplo: 70 | 71 | ``` js 72 | import cep from 'cep-promise' 73 | 74 | // enviando sem ter um zero à esquerda do CEP "05010000" 75 | cep(5010000) 76 | .then(console.log) 77 | 78 | // { 79 | // "cep": "05010000", 80 | // "state": "SP", 81 | // "city": "São Paulo", 82 | // "street": "Rua Caiubí", 83 | // "neighborhood": "Perdizes", 84 | // } 85 | ``` 86 | 87 | ### Quando o CEP não é encontrado 88 | 89 | Neste caso será retornado um `"service_error"` e por ser multifornecedor, a biblioteca irá rejeitar a Promise apenas quando tiver a resposta negativa de todos os fornecedores. 90 | 91 | ``` js 92 | import cep from 'cep-promise' 93 | 94 | cep('99999999') 95 | .catch(console.log) 96 | 97 | // { 98 | // name: 'CepPromiseError', 99 | // message: 'Todos os serviços de CEP retornaram erro.', 100 | // type: 'service_error', 101 | // errors: [{ 102 | // message: 'CEP NAO ENCONTRADO', 103 | // service: 'correios' 104 | // }, { 105 | // message: 'CEP não encontrado na base do ViaCEP.', 106 | // service: 'viacep' 107 | // }] 108 | // } 109 | 110 | ``` 111 | 112 | ### Quando o CEP possui um formato inválido 113 | 114 | Neste caso será retornado um `"validation_error"` e a biblioteca irá rejeitar imediatamente a Promise, sem chegar a consultar nenhum fornecedor. 115 | 116 | ``` js 117 | import cep from 'cep-promise' 118 | 119 | cep('123456789123456789') 120 | .catch(console.log) 121 | 122 | // { 123 | // name: 'CepPromiseError', 124 | // message: 'CEP deve conter exatamente 8 caracteres.', 125 | // type: 'validation_error', 126 | // errors: [{ 127 | // message: 'CEP informado possui mais do que 8 caracteres.', 128 | // service: 'cep_validation' 129 | // }] 130 | // } 131 | ``` 132 | ### Options 133 | - `timeout`: Timeout em milisegundos das consultas em cada serviço. O tempo total poderá ser maior devido a limites no paralelismo. 134 | - `providers`: Lista de providers a serem usados na consulta. Default é usar todos os providers disponíveis. 135 | 136 | ```js 137 | import cep from 'cep-promise' 138 | cep('5010000', { timeout: 5000, providers: ['brasilapi'] }) 139 | .then(console.log) 140 | 141 | ``` 142 | 143 | ### Instalação 144 | 145 | #### Browser usando CDN 146 | ``` 147 | 148 | ``` 149 | 150 | #### npm 151 | 152 | ``` 153 | $ npm install --save cep-promise 154 | ``` 155 | 156 | #### Bower 157 | 158 | ``` 159 | $ bower install --save cep-promise 160 | ``` 161 | #### yarn 162 | 163 | ``` 164 | $ yarn add cep-promise 165 | ``` 166 | 167 | #### Angular 2 168 | 169 | ``` ts 170 | import * as cep from 'cep-promise' 171 | 172 | cep('05010000') 173 | .then(console.log) 174 | ``` 175 | 176 | ## Como contribuir 177 | 178 | Leia nosso guia de contribuição [aqui](CONTRIBUTING.md) 179 | 180 | ## Contribuidores 181 | 182 | 183 | 184 | ## Autor 185 | 186 | | [
@filipedeschamps](https://github.com/filipedeschamps) | 187 | | :---: | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cep-promise", 3 | "version": "2.0.5", 4 | "description": "Busca por CEP integrado diretamente aos serviços dos Correios e ViaCEP", 5 | "main": "dist/cep-promise.js", 6 | "authors": [ 7 | "Filipe Deschamps" 8 | ], 9 | "license": "MIT", 10 | "homepage": "https://github.com/filipedeschamps/cep-promise", 11 | "ignore": [ 12 | "**/.*", 13 | "node_modules", 14 | "src", 15 | "test" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /content/logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrasilAPI/cep-promise/43fbb0004dee5b0f89af5df6399fc37aca151a6d/content/logo.gif -------------------------------------------------------------------------------- /dist/cep-promise-browser.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 3 | typeof define === 'function' && define.amd ? define(factory) : 4 | (global = global || self, global.cep = factory()); 5 | }(this, (function () { 'use strict'; 6 | 7 | function _typeof(obj) { 8 | "@babel/helpers - typeof"; 9 | 10 | if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 11 | _typeof = function (obj) { 12 | return typeof obj; 13 | }; 14 | } else { 15 | _typeof = function (obj) { 16 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 17 | }; 18 | } 19 | 20 | return _typeof(obj); 21 | } 22 | 23 | function _classCallCheck(instance, Constructor) { 24 | if (!(instance instanceof Constructor)) { 25 | throw new TypeError("Cannot call a class as a function"); 26 | } 27 | } 28 | 29 | function _inherits(subClass, superClass) { 30 | if (typeof superClass !== "function" && superClass !== null) { 31 | throw new TypeError("Super expression must either be null or a function"); 32 | } 33 | 34 | subClass.prototype = Object.create(superClass && superClass.prototype, { 35 | constructor: { 36 | value: subClass, 37 | writable: true, 38 | configurable: true 39 | } 40 | }); 41 | if (superClass) _setPrototypeOf(subClass, superClass); 42 | } 43 | 44 | function _getPrototypeOf(o) { 45 | _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 46 | return o.__proto__ || Object.getPrototypeOf(o); 47 | }; 48 | return _getPrototypeOf(o); 49 | } 50 | 51 | function _setPrototypeOf(o, p) { 52 | _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 53 | o.__proto__ = p; 54 | return o; 55 | }; 56 | 57 | return _setPrototypeOf(o, p); 58 | } 59 | 60 | function _isNativeReflectConstruct() { 61 | if (typeof Reflect === "undefined" || !Reflect.construct) return false; 62 | if (Reflect.construct.sham) return false; 63 | if (typeof Proxy === "function") return true; 64 | 65 | try { 66 | Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); 67 | return true; 68 | } catch (e) { 69 | return false; 70 | } 71 | } 72 | 73 | function _construct(Parent, args, Class) { 74 | if (_isNativeReflectConstruct()) { 75 | _construct = Reflect.construct; 76 | } else { 77 | _construct = function _construct(Parent, args, Class) { 78 | var a = [null]; 79 | a.push.apply(a, args); 80 | var Constructor = Function.bind.apply(Parent, a); 81 | var instance = new Constructor(); 82 | if (Class) _setPrototypeOf(instance, Class.prototype); 83 | return instance; 84 | }; 85 | } 86 | 87 | return _construct.apply(null, arguments); 88 | } 89 | 90 | function _isNativeFunction(fn) { 91 | return Function.toString.call(fn).indexOf("[native code]") !== -1; 92 | } 93 | 94 | function _wrapNativeSuper(Class) { 95 | var _cache = typeof Map === "function" ? new Map() : undefined; 96 | 97 | _wrapNativeSuper = function _wrapNativeSuper(Class) { 98 | if (Class === null || !_isNativeFunction(Class)) return Class; 99 | 100 | if (typeof Class !== "function") { 101 | throw new TypeError("Super expression must either be null or a function"); 102 | } 103 | 104 | if (typeof _cache !== "undefined") { 105 | if (_cache.has(Class)) return _cache.get(Class); 106 | 107 | _cache.set(Class, Wrapper); 108 | } 109 | 110 | function Wrapper() { 111 | return _construct(Class, arguments, _getPrototypeOf(this).constructor); 112 | } 113 | 114 | Wrapper.prototype = Object.create(Class.prototype, { 115 | constructor: { 116 | value: Wrapper, 117 | enumerable: false, 118 | writable: true, 119 | configurable: true 120 | } 121 | }); 122 | return _setPrototypeOf(Wrapper, Class); 123 | }; 124 | 125 | return _wrapNativeSuper(Class); 126 | } 127 | 128 | function _assertThisInitialized(self) { 129 | if (self === void 0) { 130 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 131 | } 132 | 133 | return self; 134 | } 135 | 136 | function _possibleConstructorReturn(self, call) { 137 | if (call && (typeof call === "object" || typeof call === "function")) { 138 | return call; 139 | } 140 | 141 | return _assertThisInitialized(self); 142 | } 143 | 144 | function _createSuper(Derived) { 145 | var hasNativeReflectConstruct = _isNativeReflectConstruct(); 146 | 147 | return function _createSuperInternal() { 148 | var Super = _getPrototypeOf(Derived), 149 | result; 150 | 151 | if (hasNativeReflectConstruct) { 152 | var NewTarget = _getPrototypeOf(this).constructor; 153 | 154 | result = Reflect.construct(Super, arguments, NewTarget); 155 | } else { 156 | result = Super.apply(this, arguments); 157 | } 158 | 159 | return _possibleConstructorReturn(this, result); 160 | }; 161 | } 162 | 163 | function _toConsumableArray(arr) { 164 | return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); 165 | } 166 | 167 | function _arrayWithoutHoles(arr) { 168 | if (Array.isArray(arr)) return _arrayLikeToArray(arr); 169 | } 170 | 171 | function _iterableToArray(iter) { 172 | if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); 173 | } 174 | 175 | function _unsupportedIterableToArray(o, minLen) { 176 | if (!o) return; 177 | if (typeof o === "string") return _arrayLikeToArray(o, minLen); 178 | var n = Object.prototype.toString.call(o).slice(8, -1); 179 | if (n === "Object" && o.constructor) n = o.constructor.name; 180 | if (n === "Map" || n === "Set") return Array.from(o); 181 | if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); 182 | } 183 | 184 | function _arrayLikeToArray(arr, len) { 185 | if (len == null || len > arr.length) len = arr.length; 186 | 187 | for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; 188 | 189 | return arr2; 190 | } 191 | 192 | function _nonIterableSpread() { 193 | throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 194 | } 195 | 196 | function _createForOfIteratorHelper(o, allowArrayLike) { 197 | var it; 198 | 199 | if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { 200 | if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { 201 | if (it) o = it; 202 | var i = 0; 203 | 204 | var F = function () {}; 205 | 206 | return { 207 | s: F, 208 | n: function () { 209 | if (i >= o.length) return { 210 | done: true 211 | }; 212 | return { 213 | done: false, 214 | value: o[i++] 215 | }; 216 | }, 217 | e: function (e) { 218 | throw e; 219 | }, 220 | f: F 221 | }; 222 | } 223 | 224 | throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 225 | } 226 | 227 | var normalCompletion = true, 228 | didErr = false, 229 | err; 230 | return { 231 | s: function () { 232 | it = o[Symbol.iterator](); 233 | }, 234 | n: function () { 235 | var step = it.next(); 236 | normalCompletion = step.done; 237 | return step; 238 | }, 239 | e: function (e) { 240 | didErr = true; 241 | err = e; 242 | }, 243 | f: function () { 244 | try { 245 | if (!normalCompletion && it.return != null) it.return(); 246 | } finally { 247 | if (didErr) throw err; 248 | } 249 | } 250 | }; 251 | } 252 | 253 | var CepPromiseError = /*#__PURE__*/function (_Error) { 254 | _inherits(CepPromiseError, _Error); 255 | 256 | var _super = _createSuper(CepPromiseError); 257 | 258 | function CepPromiseError() { 259 | var _this; 260 | 261 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, 262 | message = _ref.message, 263 | type = _ref.type, 264 | errors = _ref.errors; 265 | 266 | _classCallCheck(this, CepPromiseError); 267 | 268 | _this = _super.call(this); 269 | _this.name = 'CepPromiseError'; 270 | _this.message = message; 271 | _this.type = type; 272 | _this.errors = errors; 273 | return _this; 274 | } 275 | 276 | return CepPromiseError; 277 | }( /*#__PURE__*/_wrapNativeSuper(Error)); 278 | 279 | function fetch (e, n) { 280 | return n = n || {}, new Promise(function (t, r) { 281 | var s = new XMLHttpRequest(), 282 | o = [], 283 | u = [], 284 | i = {}, 285 | a = function a() { 286 | return { 287 | ok: 2 == (s.status / 100 | 0), 288 | statusText: s.statusText, 289 | status: s.status, 290 | url: s.responseURL, 291 | text: function text() { 292 | return Promise.resolve(s.responseText); 293 | }, 294 | json: function json() { 295 | return Promise.resolve(JSON.parse(s.responseText)); 296 | }, 297 | blob: function blob() { 298 | return Promise.resolve(new Blob([s.response])); 299 | }, 300 | clone: a, 301 | headers: { 302 | keys: function keys() { 303 | return o; 304 | }, 305 | entries: function entries() { 306 | return u; 307 | }, 308 | get: function get(e) { 309 | return i[e.toLowerCase()]; 310 | }, 311 | has: function has(e) { 312 | return e.toLowerCase() in i; 313 | } 314 | } 315 | }; 316 | }; 317 | 318 | for (var l in s.open(n.method || "get", e, !0), s.onload = function () { 319 | s.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, function (e, n, t) { 320 | o.push(n = n.toLowerCase()), u.push([n, t]), i[n] = i[n] ? i[n] + "," + t : t; 321 | }), t(a()); 322 | }, s.onerror = r, s.withCredentials = "include" == n.credentials, n.headers) { 323 | s.setRequestHeader(l, n.headers[l]); 324 | } 325 | 326 | s.send(n.body || null); 327 | }); 328 | } 329 | 330 | var ServiceError = /*#__PURE__*/function (_Error) { 331 | _inherits(ServiceError, _Error); 332 | 333 | var _super = _createSuper(ServiceError); 334 | 335 | function ServiceError() { 336 | var _this; 337 | 338 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, 339 | message = _ref.message, 340 | service = _ref.service; 341 | 342 | _classCallCheck(this, ServiceError); 343 | 344 | _this = _super.call(this); 345 | _this.name = 'ServiceError'; 346 | _this.message = message; 347 | _this.service = service; 348 | return _this; 349 | } 350 | 351 | return ServiceError; 352 | }( /*#__PURE__*/_wrapNativeSuper(Error)); 353 | 354 | function fetchCorreiosService(cepWithLeftPad, configurations) { 355 | var url = 'https://apps.correios.com.br/SigepMasterJPA/AtendeClienteService/AtendeCliente'; 356 | var options = { 357 | method: 'POST', 358 | body: "\n\n \n \n \n ".concat(cepWithLeftPad, "\n \n \n"), 359 | headers: { 360 | 'Content-Type': 'text/xml;charset=UTF-8', 361 | 'cache-control': 'no-cache' 362 | }, 363 | timeout: configurations.timeout || 30000 364 | }; 365 | return fetch(url, options).then(analyzeAndParseResponse)["catch"](throwApplicationError); 366 | } 367 | 368 | function analyzeAndParseResponse(response) { 369 | if (response.ok) { 370 | return response.text().then(parseSuccessXML).then(extractValuesFromSuccessResponse); 371 | } 372 | 373 | return response.text().then(parseAndextractErrorMessage).then(throwCorreiosError); 374 | } 375 | 376 | function parseSuccessXML(xmlString) { 377 | try { 378 | var _xmlString$replace$ma; 379 | 380 | var returnStatement = (_xmlString$replace$ma = xmlString.replace(/\r?\n|\r/g, '').match(/(.*)<\/return>/)[0]) !== null && _xmlString$replace$ma !== void 0 ? _xmlString$replace$ma : ''; 381 | var cleanReturnStatement = returnStatement.replace('', '').replace('', ''); 382 | var parsedReturnStatement = cleanReturnStatement.split(/'); 384 | 385 | if (splittenExp.length > 1 && splittenExp[1].length) { 386 | result[splittenExp[0]] = splittenExp[1]; 387 | } 388 | 389 | return result; 390 | }, {}); 391 | return parsedReturnStatement; 392 | } catch (e) { 393 | throw new Error('Não foi possível interpretar o XML de resposta.'); 394 | } 395 | } 396 | 397 | function parseAndextractErrorMessage(xmlString) { 398 | try { 399 | var _xmlString$match$; 400 | 401 | var returnStatement = (_xmlString$match$ = xmlString.match(/(.*)<\/faultstring>/)[0]) !== null && _xmlString$match$ !== void 0 ? _xmlString$match$ : ''; 402 | var cleanReturnStatement = returnStatement.replace('', '').replace('', ''); 403 | return cleanReturnStatement; 404 | } catch (e) { 405 | throw new Error('Não foi possível interpretar o XML de resposta.'); 406 | } 407 | } 408 | 409 | function throwCorreiosError(translatedErrorMessage) { 410 | throw new Error(translatedErrorMessage); 411 | } 412 | 413 | function extractValuesFromSuccessResponse(xmlObject) { 414 | return { 415 | cep: xmlObject.cep, 416 | state: xmlObject.uf, 417 | city: xmlObject.cidade, 418 | neighborhood: xmlObject.bairro, 419 | street: xmlObject.end, 420 | service: 'correios' 421 | }; 422 | } 423 | 424 | function throwApplicationError(error) { 425 | var serviceError = new ServiceError({ 426 | message: error.message, 427 | service: 'correios' 428 | }); 429 | 430 | if (error.name === 'FetchError') { 431 | serviceError.message = 'Erro ao se conectar com o serviço dos Correios.'; 432 | } 433 | 434 | throw serviceError; 435 | } 436 | 437 | function fetchCorreiosAltAPIService(cepWithLeftPad, configurations) { 438 | var url = 'https://buscacepinter.correios.com.br/app/endereco/carrega-cep-endereco.php'; 439 | var options = { 440 | method: 'POST', 441 | mode: 'cors', 442 | headers: { 443 | 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 444 | 'Referer': 'https://buscacepinter.correios.com.br/app/endereco/index.php', 445 | 'Referrer-Policy': 'strict-origin-when-cross-origin' 446 | }, 447 | body: "endereco=".concat(cepWithLeftPad, "&tipoCEP=ALL"), 448 | timeout: configurations.timeout || 30000 449 | }; 450 | return fetch(url, options).then(parseResponse).then(extractCepValuesFromResponse)["catch"](throwApplicationError$1); 451 | } 452 | 453 | function parseResponse(response) { 454 | return response.json().then(function (result) { 455 | if (result.total === 0 || result.erro || result.dados[0].cep === "") { 456 | throw new Error('CEP não encontrado na base dos Correios.'); 457 | } 458 | 459 | return result; 460 | }); 461 | } 462 | 463 | function extractCepValuesFromResponse(response) { 464 | var firstCep = response.dados[0]; 465 | return { 466 | cep: firstCep.cep, 467 | state: firstCep.uf, 468 | city: firstCep.localidade, 469 | neighborhood: firstCep.bairro, 470 | street: firstCep.logradouroDNEC, 471 | service: 'correios-alt' 472 | }; 473 | } 474 | 475 | function throwApplicationError$1(error) { 476 | var serviceError = new ServiceError({ 477 | message: error.message, 478 | service: 'correios-alt' 479 | }); 480 | 481 | if (error.name === 'FetchError') { 482 | serviceError.message = 'Erro ao se conectar com o serviço dos Correios Alt.'; 483 | } 484 | 485 | throw serviceError; 486 | } 487 | 488 | function fetchViaCepService(cepWithLeftPad, configurations) { 489 | var url = "https://viacep.com.br/ws/".concat(cepWithLeftPad, "/json/"); 490 | var options = { 491 | method: 'GET', 492 | mode: 'cors', 493 | headers: { 494 | 'content-type': 'application/json;charset=utf-8' 495 | }, 496 | timeout: configurations.timeout || 30000 497 | }; 498 | 499 | if (typeof window == 'undefined') { 500 | options.headers['user-agent'] = 'cep-promise'; 501 | } 502 | 503 | return fetch(url, options).then(analyzeAndParseResponse$1).then(checkForViaCepError).then(extractCepValuesFromResponse$1)["catch"](throwApplicationError$2); 504 | } 505 | 506 | function analyzeAndParseResponse$1(response) { 507 | if (response.ok) { 508 | return response.json(); 509 | } 510 | 511 | throw Error('Erro ao se conectar com o serviço ViaCEP.'); 512 | } 513 | 514 | function checkForViaCepError(responseObject) { 515 | if (responseObject.erro === true) { 516 | throw new Error('CEP não encontrado na base do ViaCEP.'); 517 | } 518 | 519 | return responseObject; 520 | } 521 | 522 | function extractCepValuesFromResponse$1(responseObject) { 523 | return { 524 | cep: responseObject.cep.replace('-', ''), 525 | state: responseObject.uf, 526 | city: responseObject.localidade, 527 | neighborhood: responseObject.bairro, 528 | street: responseObject.logradouro, 529 | service: 'viacep' 530 | }; 531 | } 532 | 533 | function throwApplicationError$2(error) { 534 | var serviceError = new ServiceError({ 535 | message: error.message, 536 | service: 'viacep' 537 | }); 538 | 539 | if (error.name === 'FetchError') { 540 | serviceError.message = 'Erro ao se conectar com o serviço ViaCEP.'; 541 | } 542 | 543 | throw serviceError; 544 | } 545 | 546 | function fetchWideNetService(cepWithLeftPad, configurations) { 547 | var cepWithDash = "".concat(cepWithLeftPad.slice(0, 5), "-").concat(cepWithLeftPad.slice(5)); 548 | var url = "https://cdn.apicep.com/file/apicep/".concat(cepWithDash, ".json"); 549 | var options = { 550 | method: 'GET', 551 | mode: 'cors', 552 | headers: { 553 | accept: 'application/json' 554 | }, 555 | timeout: configurations.timeout || 30000 556 | }; 557 | return fetch(url, options).then(analyzeAndParseResponse$2).then(checkForWideNetError).then(extractCepValuesFromResponse$2)["catch"](throwApplicationError$3); 558 | } 559 | 560 | function analyzeAndParseResponse$2(response) { 561 | if (response.ok) { 562 | return response.json(); 563 | } 564 | 565 | throw Error('Erro ao se conectar com o serviço WideNet.'); 566 | } 567 | 568 | function checkForWideNetError(object) { 569 | if (object.ok === false || object.status !== 200) { 570 | throw new Error('CEP não encontrado na base do WideNet.'); 571 | } 572 | 573 | return object; 574 | } 575 | 576 | function extractCepValuesFromResponse$2(object) { 577 | return { 578 | cep: object.code.replace('-', ''), 579 | state: object.state, 580 | city: object.city, 581 | neighborhood: object.district, 582 | street: object.address, 583 | service: 'widenet' 584 | }; 585 | } 586 | 587 | function throwApplicationError$3(error) { 588 | var serviceError = new ServiceError({ 589 | message: error.message, 590 | service: 'widenet' 591 | }); 592 | 593 | if (error.name === 'FetchError') { 594 | serviceError.message = 'Erro ao se conectar com o serviço WideNet.'; 595 | } 596 | 597 | throw serviceError; 598 | } 599 | 600 | function fetchBrasilAPIService(cepWithLeftPad, configurations) { 601 | var url = "https://brasilapi.com.br/api/cep/v1/".concat(cepWithLeftPad); 602 | var options = { 603 | method: 'GET', 604 | mode: 'cors', 605 | headers: { 606 | 'content-type': 'application/json;charset=utf-8' 607 | }, 608 | timeout: configurations.timeout || 30000 609 | }; 610 | return fetch(url, options).then(parseResponse$1).then(extractCepValuesFromResponse$3)["catch"](throwApplicationError$4); 611 | } 612 | 613 | function parseResponse$1(response) { 614 | if (response.ok === false || response.status !== 200) { 615 | throw new Error('CEP não encontrado na base do BrasilAPI.'); 616 | } 617 | 618 | return response.json(); 619 | } 620 | 621 | function extractCepValuesFromResponse$3(response) { 622 | return { 623 | cep: response.cep, 624 | state: response.state, 625 | city: response.city, 626 | neighborhood: response.neighborhood, 627 | street: response.street, 628 | service: 'brasilapi' 629 | }; 630 | } 631 | 632 | function throwApplicationError$4(error) { 633 | var serviceError = new ServiceError({ 634 | message: error.message, 635 | service: 'brasilapi' 636 | }); 637 | 638 | if (error.name === 'FetchError') { 639 | serviceError.message = 'Erro ao se conectar com o serviço BrasilAPI.'; 640 | } 641 | 642 | throw serviceError; 643 | } 644 | 645 | function getAvailableServices() { 646 | var isBrowser = typeof window !== 'undefined'; 647 | 648 | if (isBrowser) { 649 | return { 650 | viacep: fetchViaCepService, 651 | widenet: fetchWideNetService, 652 | brasilapi: fetchBrasilAPIService 653 | }; 654 | } 655 | 656 | return { 657 | correios: fetchCorreiosService, 658 | 'correios-alt': fetchCorreiosAltAPIService, 659 | viacep: fetchViaCepService, 660 | widenet: fetchWideNetService, 661 | brasilapi: fetchBrasilAPIService 662 | }; 663 | } 664 | 665 | var reverse = function reverse(promise) { 666 | return new Promise(function (resolve, reject) { 667 | return Promise.resolve(promise).then(reject, resolve); 668 | }); 669 | }; 670 | 671 | Promise.any = function (iterable) { 672 | return reverse(Promise.all(_toConsumableArray(iterable).map(reverse))); 673 | }; 674 | 675 | var Promise$1 = Promise; 676 | 677 | var CEP_SIZE = 8; 678 | function cepPromise (cepRawValue) { 679 | var configurations = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 680 | return Promise$1.resolve(cepRawValue).then(validateInputType).then(function (cepRawValue) { 681 | configurations.providers = configurations.providers ? configurations.providers : []; 682 | validateProviders(configurations.providers); 683 | return cepRawValue; 684 | }).then(removeSpecialCharacters).then(validateInputLength).then(leftPadWithZeros).then(function (cepWithLeftPad) { 685 | return fetchCepFromServices(cepWithLeftPad, configurations); 686 | })["catch"](handleServicesError)["catch"](throwApplicationError$5); 687 | } 688 | 689 | function validateProviders(providers) { 690 | var availableProviders = Object.keys(getAvailableServices()); 691 | 692 | if (!Array.isArray(providers)) { 693 | throw new CepPromiseError({ 694 | message: 'Erro ao inicializar a instância do CepPromise.', 695 | type: 'validation_error', 696 | errors: [{ 697 | message: 'O parâmetro providers deve ser uma lista.', 698 | service: 'providers_validation' 699 | }] 700 | }); 701 | } 702 | 703 | var _iterator = _createForOfIteratorHelper(providers), 704 | _step; 705 | 706 | try { 707 | for (_iterator.s(); !(_step = _iterator.n()).done;) { 708 | var provider = _step.value; 709 | 710 | if (!availableProviders.includes(provider)) { 711 | throw new CepPromiseError({ 712 | message: 'Erro ao inicializar a instância do CepPromise.', 713 | type: 'validation_error', 714 | errors: [{ 715 | message: "O provider \"".concat(provider, "\" \xE9 inv\xE1lido. Os providers dispon\xEDveis s\xE3o: [\"").concat(availableProviders.join('", "'), "\"]."), 716 | service: 'providers_validation' 717 | }] 718 | }); 719 | } 720 | } 721 | } catch (err) { 722 | _iterator.e(err); 723 | } finally { 724 | _iterator.f(); 725 | } 726 | } 727 | 728 | function validateInputType(cepRawValue) { 729 | var cepTypeOf = _typeof(cepRawValue); 730 | 731 | if (cepTypeOf === 'number' || cepTypeOf === 'string') { 732 | return cepRawValue; 733 | } 734 | 735 | throw new CepPromiseError({ 736 | message: 'Erro ao inicializar a instância do CepPromise.', 737 | type: 'validation_error', 738 | errors: [{ 739 | message: 'Você deve chamar o construtor utilizando uma String ou um Number.', 740 | service: 'cep_validation' 741 | }] 742 | }); 743 | } 744 | 745 | function removeSpecialCharacters(cepRawValue) { 746 | return cepRawValue.toString().replace(/\D+/g, ''); 747 | } 748 | 749 | function leftPadWithZeros(cepCleanValue) { 750 | return '0'.repeat(CEP_SIZE - cepCleanValue.length) + cepCleanValue; 751 | } 752 | 753 | function validateInputLength(cepWithLeftPad) { 754 | if (cepWithLeftPad.length <= CEP_SIZE) { 755 | return cepWithLeftPad; 756 | } 757 | 758 | throw new CepPromiseError({ 759 | message: "CEP deve conter exatamente ".concat(CEP_SIZE, " caracteres."), 760 | type: 'validation_error', 761 | errors: [{ 762 | message: "CEP informado possui mais do que ".concat(CEP_SIZE, " caracteres."), 763 | service: 'cep_validation' 764 | }] 765 | }); 766 | } 767 | 768 | function fetchCepFromServices(cepWithLeftPad, configurations) { 769 | var providersServices = getAvailableServices(); 770 | 771 | if (configurations.providers.length === 0) { 772 | return Promise$1.any(Object.values(providersServices).map(function (provider) { 773 | return provider(cepWithLeftPad, configurations); 774 | })); 775 | } 776 | 777 | return Promise$1.any(configurations.providers.map(function (provider) { 778 | return providersServices[provider](cepWithLeftPad, configurations); 779 | })); 780 | } 781 | 782 | function handleServicesError(aggregatedErrors) { 783 | if (aggregatedErrors.length !== undefined) { 784 | throw new CepPromiseError({ 785 | message: 'Todos os serviços de CEP retornaram erro.', 786 | type: 'service_error', 787 | errors: aggregatedErrors 788 | }); 789 | } 790 | 791 | throw aggregatedErrors; 792 | } 793 | 794 | function throwApplicationError$5(_ref) { 795 | var message = _ref.message, 796 | type = _ref.type, 797 | errors = _ref.errors; 798 | throw new CepPromiseError({ 799 | message: message, 800 | type: type, 801 | errors: errors 802 | }); 803 | } 804 | 805 | return cepPromise; 806 | 807 | }))); 808 | -------------------------------------------------------------------------------- /dist/cep-promise-browser.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e=e||self).cep=r()}(this,function(){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function a(e,r){if(!(e instanceof r))throw new TypeError("Cannot call a class as a function")}function e(e,r){if("function"!=typeof r&&null!==r)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(r&&r.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),r&&i(e,r)}function o(e){return(o=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function i(e,r){return(i=Object.setPrototypeOf||function(e,r){return e.__proto__=r,e})(e,r)}function c(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function s(e,r,t){return(s=c()?Reflect.construct:function(e,r,t){var n=[null];n.push.apply(n,r);var o=new(Function.bind.apply(e,n));return t&&i(o,t.prototype),o}).apply(null,arguments)}function r(e){var n="function"==typeof Map?new Map:void 0;return(r=function(e){if(null===e||(r=e,-1===Function.toString.call(r).indexOf("[native code]")))return e;var r;if("function"!=typeof e)throw new TypeError("Super expression must either be null or a function");if(void 0!==n){if(n.has(e))return n.get(e);n.set(e,t)}function t(){return s(e,arguments,o(this).constructor)}return t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),i(t,e)})(e)}function u(e,r){return!r||"object"!=typeof r&&"function"!=typeof r?function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(e):r}function n(t){var n=c();return function(){var e,r=o(t);return u(this,n?(e=o(this).constructor,Reflect.construct(r,arguments,e)):r.apply(this,arguments))}}function p(e){return function(e){if(Array.isArray(e))return l(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||f(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function f(e,r){if(e){if("string"==typeof e)return l(e,r);var t=Object.prototype.toString.call(e).slice(8,-1);return"Object"===t&&e.constructor&&(t=e.constructor.name),"Map"===t||"Set"===t?Array.from(e):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?l(e,r):void 0}}function l(e,r){(null==r||r>e.length)&&(r=e.length);for(var t=0,n=new Array(r);t\n\n \n \n \n '.concat(e,"\n \n \n"),headers:{"Content-Type":"text/xml;charset=UTF-8","cache-control":"no-cache"},timeout:r.timeout||3e4}).then(y).catch(P)}function y(e){return e.ok?e.text().then(b).then(E):e.text().then(g).then(w)}function b(e){try{var r;return(null!==(r=e.replace(/\r?\n|\r/g,"").match(/(.*)<\/return>/)[0])&&void 0!==r?r:"").replace("","").replace("","").split(/");return 1(.*)<\/faultstring>/)[0])&&void 0!==r?r:"").replace("","").replace("","")}catch(e){throw new Error("Não foi possível interpretar o XML de resposta.")}}function w(e){throw new Error(e)}function E(e){return{cep:e.cep,state:e.uf,city:e.cidade,neighborhood:e.bairro,street:e.end,service:"correios"}}function P(e){var r=new m({message:e.message,service:"correios"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço dos Correios."),r}function C(e,r){return h("https://buscacepinter.correios.com.br/app/endereco/carrega-cep-endereco.php",{method:"POST",mode:"cors",headers:{"content-type":"application/x-www-form-urlencoded; charset=UTF-8",Referer:"https://buscacepinter.correios.com.br/app/endereco/index.php","Referrer-Policy":"strict-origin-when-cross-origin"},body:"endereco=".concat(e,"&tipoCEP=ALL"),timeout:r.timeout||3e4}).then(S).then(j).catch(x)}function S(e){return e.json().then(function(e){if(0===e.total||e.erro||""===e.dados[0].cep)throw new Error("CEP não encontrado na base dos Correios.");return e})}function j(e){var r=e.dados[0];return{cep:r.cep,state:r.uf,city:r.localidade,neighborhood:r.bairro,street:r.logradouroDNEC,service:"correios-alt"}}function x(e){var r=new m({message:e.message,service:"correios-alt"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço dos Correios Alt."),r}function O(e,r){var t="https://viacep.com.br/ws/".concat(e,"/json/"),n={method:"GET",mode:"cors",headers:{"content-type":"application/json;charset=utf-8"},timeout:r.timeout||3e4};return"undefined"==typeof window&&(n.headers["user-agent"]="cep-promise"),h(t,n).then(A).then(T).then(_).catch(R)}function A(e){if(e.ok)return e.json();throw Error("Erro ao se conectar com o serviço ViaCEP.")}function T(e){if(!0===e.erro)throw new Error("CEP não encontrado na base do ViaCEP.");return e}function _(e){return{cep:e.cep.replace("-",""),state:e.uf,city:e.localidade,neighborhood:e.bairro,street:e.logradouro,service:"viacep"}}function R(e){var r=new m({message:e.message,service:"viacep"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço ViaCEP."),r}function F(e,r){var t="".concat(e.slice(0,5),"-").concat(e.slice(5));return h("https://cdn.apicep.com/file/apicep/".concat(t,".json"),{method:"GET",mode:"cors",headers:{accept:"application/json"},timeout:r.timeout||3e4}).then(L).then(k).then(N).catch(I)}function L(e){if(e.ok)return e.json();throw Error("Erro ao se conectar com o serviço WideNet.")}function k(e){if(!1===e.ok||200!==e.status)throw new Error("CEP não encontrado na base do WideNet.");return e}function N(e){return{cep:e.code.replace("-",""),state:e.state,city:e.city,neighborhood:e.district,street:e.address,service:"widenet"}}function I(e){var r=new m({message:e.message,service:"widenet"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço WideNet."),r}function M(e,r){return h("https://brasilapi.com.br/api/cep/v1/".concat(e),{method:"GET",mode:"cors",headers:{"content-type":"application/json;charset=utf-8"},timeout:r.timeout||3e4}).then(B).then(z).catch(D)}function B(e){if(!1===e.ok||200!==e.status)throw new Error("CEP não encontrado na base do BrasilAPI.");return e.json()}function z(e){return{cep:e.cep,state:e.state,city:e.city,neighborhood:e.neighborhood,street:e.street,service:"brasilapi"}}function D(e){var r=new m({message:e.message,service:"brasilapi"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço BrasilAPI."),r}function H(){return"undefined"!=typeof window?{viacep:O,widenet:F,brasilapi:M}:{correios:v,"correios-alt":C,viacep:O,widenet:F,brasilapi:M}}function U(t){return new Promise(function(e,r){return Promise.resolve(t).then(r,e)})}Promise.any=function(e){return U(Promise.all(p(e).map(U)))};var V=Promise,q=8;function G(e){var r=t(e);if("number"===r||"string"===r)return e;throw new d({message:"Erro ao inicializar a instância do CepPromise.",type:"validation_error",errors:[{message:"Você deve chamar o construtor utilizando uma String ou um Number.",service:"cep_validation"}]})}function W(e){return e.toString().replace(/\D+/g,"")}function X(e){return"0".repeat(q-e.length)+e}function J(e){if(e.length<=q)return e;throw new d({message:"CEP deve conter exatamente ".concat(q," caracteres."),type:"validation_error",errors:[{message:"CEP informado possui mais do que ".concat(q," caracteres."),service:"cep_validation"}]})}function $(e){if(void 0!==e.length)throw new d({message:"Todos os serviços de CEP retornaram erro.",type:"service_error",errors:e});throw e}function K(e){var r=e.message,t=e.type,n=e.errors;throw new d({message:r,type:t,errors:n})}return function(e){var o=1=e.length?{done:!0}:{done:!1,value:e[n++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,c=!0,a=!1;return{s:function(){t=e[Symbol.iterator]()},n:function(){var e=t.next();return c=e.done,e},e:function(e){a=!0,i=e},f:function(){try{c||null==t.return||t.return()}finally{if(a)throw i}}}}(e);try{for(n.s();!(t=n.n()).done;){var o=t.value;if(!r.includes(o))throw new d({message:"Erro ao inicializar a instância do CepPromise.",type:"validation_error",errors:[{message:'O provider "'.concat(o,'" é inválido. Os providers disponíveis são: ["').concat(r.join('", "'),'"].'),service:"providers_validation"}]})}}catch(e){n.e(e)}finally{n.f()}}(o.providers),e}).then(W).then(J).then(X).then(function(e){return r=e,t=o,n=H(),0!==t.providers.length?V.any(t.providers.map(function(e){return n[e](r,t)})):V.any(Object.values(n).map(function(e){return e(r,t)}));var r,t,n}).catch($).catch(K)}}); -------------------------------------------------------------------------------- /dist/cep-promise.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('node-fetch')) : 3 | typeof define === 'function' && define.amd ? define(['node-fetch'], factory) : 4 | (global = global || self, global.cep = factory(global.fetch)); 5 | }(this, (function (fetch) { 'use strict'; 6 | 7 | fetch = fetch && Object.prototype.hasOwnProperty.call(fetch, 'default') ? fetch['default'] : fetch; 8 | 9 | function _typeof(obj) { 10 | "@babel/helpers - typeof"; 11 | 12 | if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 13 | _typeof = function (obj) { 14 | return typeof obj; 15 | }; 16 | } else { 17 | _typeof = function (obj) { 18 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 19 | }; 20 | } 21 | 22 | return _typeof(obj); 23 | } 24 | 25 | function _classCallCheck(instance, Constructor) { 26 | if (!(instance instanceof Constructor)) { 27 | throw new TypeError("Cannot call a class as a function"); 28 | } 29 | } 30 | 31 | function _inherits(subClass, superClass) { 32 | if (typeof superClass !== "function" && superClass !== null) { 33 | throw new TypeError("Super expression must either be null or a function"); 34 | } 35 | 36 | subClass.prototype = Object.create(superClass && superClass.prototype, { 37 | constructor: { 38 | value: subClass, 39 | writable: true, 40 | configurable: true 41 | } 42 | }); 43 | if (superClass) _setPrototypeOf(subClass, superClass); 44 | } 45 | 46 | function _getPrototypeOf(o) { 47 | _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 48 | return o.__proto__ || Object.getPrototypeOf(o); 49 | }; 50 | return _getPrototypeOf(o); 51 | } 52 | 53 | function _setPrototypeOf(o, p) { 54 | _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 55 | o.__proto__ = p; 56 | return o; 57 | }; 58 | 59 | return _setPrototypeOf(o, p); 60 | } 61 | 62 | function _isNativeReflectConstruct() { 63 | if (typeof Reflect === "undefined" || !Reflect.construct) return false; 64 | if (Reflect.construct.sham) return false; 65 | if (typeof Proxy === "function") return true; 66 | 67 | try { 68 | Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); 69 | return true; 70 | } catch (e) { 71 | return false; 72 | } 73 | } 74 | 75 | function _construct(Parent, args, Class) { 76 | if (_isNativeReflectConstruct()) { 77 | _construct = Reflect.construct; 78 | } else { 79 | _construct = function _construct(Parent, args, Class) { 80 | var a = [null]; 81 | a.push.apply(a, args); 82 | var Constructor = Function.bind.apply(Parent, a); 83 | var instance = new Constructor(); 84 | if (Class) _setPrototypeOf(instance, Class.prototype); 85 | return instance; 86 | }; 87 | } 88 | 89 | return _construct.apply(null, arguments); 90 | } 91 | 92 | function _isNativeFunction(fn) { 93 | return Function.toString.call(fn).indexOf("[native code]") !== -1; 94 | } 95 | 96 | function _wrapNativeSuper(Class) { 97 | var _cache = typeof Map === "function" ? new Map() : undefined; 98 | 99 | _wrapNativeSuper = function _wrapNativeSuper(Class) { 100 | if (Class === null || !_isNativeFunction(Class)) return Class; 101 | 102 | if (typeof Class !== "function") { 103 | throw new TypeError("Super expression must either be null or a function"); 104 | } 105 | 106 | if (typeof _cache !== "undefined") { 107 | if (_cache.has(Class)) return _cache.get(Class); 108 | 109 | _cache.set(Class, Wrapper); 110 | } 111 | 112 | function Wrapper() { 113 | return _construct(Class, arguments, _getPrototypeOf(this).constructor); 114 | } 115 | 116 | Wrapper.prototype = Object.create(Class.prototype, { 117 | constructor: { 118 | value: Wrapper, 119 | enumerable: false, 120 | writable: true, 121 | configurable: true 122 | } 123 | }); 124 | return _setPrototypeOf(Wrapper, Class); 125 | }; 126 | 127 | return _wrapNativeSuper(Class); 128 | } 129 | 130 | function _assertThisInitialized(self) { 131 | if (self === void 0) { 132 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 133 | } 134 | 135 | return self; 136 | } 137 | 138 | function _possibleConstructorReturn(self, call) { 139 | if (call && (typeof call === "object" || typeof call === "function")) { 140 | return call; 141 | } 142 | 143 | return _assertThisInitialized(self); 144 | } 145 | 146 | function _createSuper(Derived) { 147 | var hasNativeReflectConstruct = _isNativeReflectConstruct(); 148 | 149 | return function _createSuperInternal() { 150 | var Super = _getPrototypeOf(Derived), 151 | result; 152 | 153 | if (hasNativeReflectConstruct) { 154 | var NewTarget = _getPrototypeOf(this).constructor; 155 | 156 | result = Reflect.construct(Super, arguments, NewTarget); 157 | } else { 158 | result = Super.apply(this, arguments); 159 | } 160 | 161 | return _possibleConstructorReturn(this, result); 162 | }; 163 | } 164 | 165 | function _toConsumableArray(arr) { 166 | return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); 167 | } 168 | 169 | function _arrayWithoutHoles(arr) { 170 | if (Array.isArray(arr)) return _arrayLikeToArray(arr); 171 | } 172 | 173 | function _iterableToArray(iter) { 174 | if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); 175 | } 176 | 177 | function _unsupportedIterableToArray(o, minLen) { 178 | if (!o) return; 179 | if (typeof o === "string") return _arrayLikeToArray(o, minLen); 180 | var n = Object.prototype.toString.call(o).slice(8, -1); 181 | if (n === "Object" && o.constructor) n = o.constructor.name; 182 | if (n === "Map" || n === "Set") return Array.from(o); 183 | if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); 184 | } 185 | 186 | function _arrayLikeToArray(arr, len) { 187 | if (len == null || len > arr.length) len = arr.length; 188 | 189 | for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; 190 | 191 | return arr2; 192 | } 193 | 194 | function _nonIterableSpread() { 195 | throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 196 | } 197 | 198 | function _createForOfIteratorHelper(o, allowArrayLike) { 199 | var it; 200 | 201 | if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { 202 | if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { 203 | if (it) o = it; 204 | var i = 0; 205 | 206 | var F = function () {}; 207 | 208 | return { 209 | s: F, 210 | n: function () { 211 | if (i >= o.length) return { 212 | done: true 213 | }; 214 | return { 215 | done: false, 216 | value: o[i++] 217 | }; 218 | }, 219 | e: function (e) { 220 | throw e; 221 | }, 222 | f: F 223 | }; 224 | } 225 | 226 | throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 227 | } 228 | 229 | var normalCompletion = true, 230 | didErr = false, 231 | err; 232 | return { 233 | s: function () { 234 | it = o[Symbol.iterator](); 235 | }, 236 | n: function () { 237 | var step = it.next(); 238 | normalCompletion = step.done; 239 | return step; 240 | }, 241 | e: function (e) { 242 | didErr = true; 243 | err = e; 244 | }, 245 | f: function () { 246 | try { 247 | if (!normalCompletion && it.return != null) it.return(); 248 | } finally { 249 | if (didErr) throw err; 250 | } 251 | } 252 | }; 253 | } 254 | 255 | var CepPromiseError = /*#__PURE__*/function (_Error) { 256 | _inherits(CepPromiseError, _Error); 257 | 258 | var _super = _createSuper(CepPromiseError); 259 | 260 | function CepPromiseError() { 261 | var _this; 262 | 263 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, 264 | message = _ref.message, 265 | type = _ref.type, 266 | errors = _ref.errors; 267 | 268 | _classCallCheck(this, CepPromiseError); 269 | 270 | _this = _super.call(this); 271 | _this.name = 'CepPromiseError'; 272 | _this.message = message; 273 | _this.type = type; 274 | _this.errors = errors; 275 | return _this; 276 | } 277 | 278 | return CepPromiseError; 279 | }( /*#__PURE__*/_wrapNativeSuper(Error)); 280 | 281 | var ServiceError = /*#__PURE__*/function (_Error) { 282 | _inherits(ServiceError, _Error); 283 | 284 | var _super = _createSuper(ServiceError); 285 | 286 | function ServiceError() { 287 | var _this; 288 | 289 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, 290 | message = _ref.message, 291 | service = _ref.service; 292 | 293 | _classCallCheck(this, ServiceError); 294 | 295 | _this = _super.call(this); 296 | _this.name = 'ServiceError'; 297 | _this.message = message; 298 | _this.service = service; 299 | return _this; 300 | } 301 | 302 | return ServiceError; 303 | }( /*#__PURE__*/_wrapNativeSuper(Error)); 304 | 305 | function fetchCorreiosService(cepWithLeftPad, configurations) { 306 | var url = 'https://apps.correios.com.br/SigepMasterJPA/AtendeClienteService/AtendeCliente'; 307 | var options = { 308 | method: 'POST', 309 | body: "\n\n \n \n \n ".concat(cepWithLeftPad, "\n \n \n"), 310 | headers: { 311 | 'Content-Type': 'text/xml;charset=UTF-8', 312 | 'cache-control': 'no-cache' 313 | }, 314 | timeout: configurations.timeout || 30000 315 | }; 316 | return fetch(url, options).then(analyzeAndParseResponse)["catch"](throwApplicationError); 317 | } 318 | 319 | function analyzeAndParseResponse(response) { 320 | if (response.ok) { 321 | return response.text().then(parseSuccessXML).then(extractValuesFromSuccessResponse); 322 | } 323 | 324 | return response.text().then(parseAndextractErrorMessage).then(throwCorreiosError); 325 | } 326 | 327 | function parseSuccessXML(xmlString) { 328 | try { 329 | var _xmlString$replace$ma; 330 | 331 | var returnStatement = (_xmlString$replace$ma = xmlString.replace(/\r?\n|\r/g, '').match(/(.*)<\/return>/)[0]) !== null && _xmlString$replace$ma !== void 0 ? _xmlString$replace$ma : ''; 332 | var cleanReturnStatement = returnStatement.replace('', '').replace('', ''); 333 | var parsedReturnStatement = cleanReturnStatement.split(/'); 335 | 336 | if (splittenExp.length > 1 && splittenExp[1].length) { 337 | result[splittenExp[0]] = splittenExp[1]; 338 | } 339 | 340 | return result; 341 | }, {}); 342 | return parsedReturnStatement; 343 | } catch (e) { 344 | throw new Error('Não foi possível interpretar o XML de resposta.'); 345 | } 346 | } 347 | 348 | function parseAndextractErrorMessage(xmlString) { 349 | try { 350 | var _xmlString$match$; 351 | 352 | var returnStatement = (_xmlString$match$ = xmlString.match(/(.*)<\/faultstring>/)[0]) !== null && _xmlString$match$ !== void 0 ? _xmlString$match$ : ''; 353 | var cleanReturnStatement = returnStatement.replace('', '').replace('', ''); 354 | return cleanReturnStatement; 355 | } catch (e) { 356 | throw new Error('Não foi possível interpretar o XML de resposta.'); 357 | } 358 | } 359 | 360 | function throwCorreiosError(translatedErrorMessage) { 361 | throw new Error(translatedErrorMessage); 362 | } 363 | 364 | function extractValuesFromSuccessResponse(xmlObject) { 365 | return { 366 | cep: xmlObject.cep, 367 | state: xmlObject.uf, 368 | city: xmlObject.cidade, 369 | neighborhood: xmlObject.bairro, 370 | street: xmlObject.end, 371 | service: 'correios' 372 | }; 373 | } 374 | 375 | function throwApplicationError(error) { 376 | var serviceError = new ServiceError({ 377 | message: error.message, 378 | service: 'correios' 379 | }); 380 | 381 | if (error.name === 'FetchError') { 382 | serviceError.message = 'Erro ao se conectar com o serviço dos Correios.'; 383 | } 384 | 385 | throw serviceError; 386 | } 387 | 388 | function fetchCorreiosAltAPIService(cepWithLeftPad, configurations) { 389 | var url = 'https://buscacepinter.correios.com.br/app/endereco/carrega-cep-endereco.php'; 390 | var options = { 391 | method: 'POST', 392 | mode: 'cors', 393 | headers: { 394 | 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 395 | 'Referer': 'https://buscacepinter.correios.com.br/app/endereco/index.php', 396 | 'Referrer-Policy': 'strict-origin-when-cross-origin' 397 | }, 398 | body: "endereco=".concat(cepWithLeftPad, "&tipoCEP=ALL"), 399 | timeout: configurations.timeout || 30000 400 | }; 401 | return fetch(url, options).then(parseResponse).then(extractCepValuesFromResponse)["catch"](throwApplicationError$1); 402 | } 403 | 404 | function parseResponse(response) { 405 | return response.json().then(function (result) { 406 | if (result.total === 0 || result.erro || result.dados[0].cep === "") { 407 | throw new Error('CEP não encontrado na base dos Correios.'); 408 | } 409 | 410 | return result; 411 | }); 412 | } 413 | 414 | function extractCepValuesFromResponse(response) { 415 | var firstCep = response.dados[0]; 416 | return { 417 | cep: firstCep.cep, 418 | state: firstCep.uf, 419 | city: firstCep.localidade, 420 | neighborhood: firstCep.bairro, 421 | street: firstCep.logradouroDNEC, 422 | service: 'correios-alt' 423 | }; 424 | } 425 | 426 | function throwApplicationError$1(error) { 427 | var serviceError = new ServiceError({ 428 | message: error.message, 429 | service: 'correios-alt' 430 | }); 431 | 432 | if (error.name === 'FetchError') { 433 | serviceError.message = 'Erro ao se conectar com o serviço dos Correios Alt.'; 434 | } 435 | 436 | throw serviceError; 437 | } 438 | 439 | function fetchViaCepService(cepWithLeftPad, configurations) { 440 | var url = "https://viacep.com.br/ws/".concat(cepWithLeftPad, "/json/"); 441 | var options = { 442 | method: 'GET', 443 | mode: 'cors', 444 | headers: { 445 | 'content-type': 'application/json;charset=utf-8' 446 | }, 447 | timeout: configurations.timeout || 30000 448 | }; 449 | 450 | if (typeof window == 'undefined') { 451 | options.headers['user-agent'] = 'cep-promise'; 452 | } 453 | 454 | return fetch(url, options).then(analyzeAndParseResponse$1).then(checkForViaCepError).then(extractCepValuesFromResponse$1)["catch"](throwApplicationError$2); 455 | } 456 | 457 | function analyzeAndParseResponse$1(response) { 458 | if (response.ok) { 459 | return response.json(); 460 | } 461 | 462 | throw Error('Erro ao se conectar com o serviço ViaCEP.'); 463 | } 464 | 465 | function checkForViaCepError(responseObject) { 466 | if (responseObject.erro === true) { 467 | throw new Error('CEP não encontrado na base do ViaCEP.'); 468 | } 469 | 470 | return responseObject; 471 | } 472 | 473 | function extractCepValuesFromResponse$1(responseObject) { 474 | return { 475 | cep: responseObject.cep.replace('-', ''), 476 | state: responseObject.uf, 477 | city: responseObject.localidade, 478 | neighborhood: responseObject.bairro, 479 | street: responseObject.logradouro, 480 | service: 'viacep' 481 | }; 482 | } 483 | 484 | function throwApplicationError$2(error) { 485 | var serviceError = new ServiceError({ 486 | message: error.message, 487 | service: 'viacep' 488 | }); 489 | 490 | if (error.name === 'FetchError') { 491 | serviceError.message = 'Erro ao se conectar com o serviço ViaCEP.'; 492 | } 493 | 494 | throw serviceError; 495 | } 496 | 497 | function fetchWideNetService(cepWithLeftPad, configurations) { 498 | var cepWithDash = "".concat(cepWithLeftPad.slice(0, 5), "-").concat(cepWithLeftPad.slice(5)); 499 | var url = "https://cdn.apicep.com/file/apicep/".concat(cepWithDash, ".json"); 500 | var options = { 501 | method: 'GET', 502 | mode: 'cors', 503 | headers: { 504 | accept: 'application/json' 505 | }, 506 | timeout: configurations.timeout || 30000 507 | }; 508 | return fetch(url, options).then(analyzeAndParseResponse$2).then(checkForWideNetError).then(extractCepValuesFromResponse$2)["catch"](throwApplicationError$3); 509 | } 510 | 511 | function analyzeAndParseResponse$2(response) { 512 | if (response.ok) { 513 | return response.json(); 514 | } 515 | 516 | throw Error('Erro ao se conectar com o serviço WideNet.'); 517 | } 518 | 519 | function checkForWideNetError(object) { 520 | if (object.ok === false || object.status !== 200) { 521 | throw new Error('CEP não encontrado na base do WideNet.'); 522 | } 523 | 524 | return object; 525 | } 526 | 527 | function extractCepValuesFromResponse$2(object) { 528 | return { 529 | cep: object.code.replace('-', ''), 530 | state: object.state, 531 | city: object.city, 532 | neighborhood: object.district, 533 | street: object.address, 534 | service: 'widenet' 535 | }; 536 | } 537 | 538 | function throwApplicationError$3(error) { 539 | var serviceError = new ServiceError({ 540 | message: error.message, 541 | service: 'widenet' 542 | }); 543 | 544 | if (error.name === 'FetchError') { 545 | serviceError.message = 'Erro ao se conectar com o serviço WideNet.'; 546 | } 547 | 548 | throw serviceError; 549 | } 550 | 551 | function fetchBrasilAPIService(cepWithLeftPad, configurations) { 552 | var url = "https://brasilapi.com.br/api/cep/v1/".concat(cepWithLeftPad); 553 | var options = { 554 | method: 'GET', 555 | mode: 'cors', 556 | headers: { 557 | 'content-type': 'application/json;charset=utf-8' 558 | }, 559 | timeout: configurations.timeout || 30000 560 | }; 561 | return fetch(url, options).then(parseResponse$1).then(extractCepValuesFromResponse$3)["catch"](throwApplicationError$4); 562 | } 563 | 564 | function parseResponse$1(response) { 565 | if (response.ok === false || response.status !== 200) { 566 | throw new Error('CEP não encontrado na base do BrasilAPI.'); 567 | } 568 | 569 | return response.json(); 570 | } 571 | 572 | function extractCepValuesFromResponse$3(response) { 573 | return { 574 | cep: response.cep, 575 | state: response.state, 576 | city: response.city, 577 | neighborhood: response.neighborhood, 578 | street: response.street, 579 | service: 'brasilapi' 580 | }; 581 | } 582 | 583 | function throwApplicationError$4(error) { 584 | var serviceError = new ServiceError({ 585 | message: error.message, 586 | service: 'brasilapi' 587 | }); 588 | 589 | if (error.name === 'FetchError') { 590 | serviceError.message = 'Erro ao se conectar com o serviço BrasilAPI.'; 591 | } 592 | 593 | throw serviceError; 594 | } 595 | 596 | function getAvailableServices() { 597 | var isBrowser = typeof window !== 'undefined'; 598 | 599 | if (isBrowser) { 600 | return { 601 | viacep: fetchViaCepService, 602 | widenet: fetchWideNetService, 603 | brasilapi: fetchBrasilAPIService 604 | }; 605 | } 606 | 607 | return { 608 | correios: fetchCorreiosService, 609 | 'correios-alt': fetchCorreiosAltAPIService, 610 | viacep: fetchViaCepService, 611 | widenet: fetchWideNetService, 612 | brasilapi: fetchBrasilAPIService 613 | }; 614 | } 615 | 616 | var reverse = function reverse(promise) { 617 | return new Promise(function (resolve, reject) { 618 | return Promise.resolve(promise).then(reject, resolve); 619 | }); 620 | }; 621 | 622 | Promise.any = function (iterable) { 623 | return reverse(Promise.all(_toConsumableArray(iterable).map(reverse))); 624 | }; 625 | 626 | var Promise$1 = Promise; 627 | 628 | var CEP_SIZE = 8; 629 | function cepPromise (cepRawValue) { 630 | var configurations = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 631 | return Promise$1.resolve(cepRawValue).then(validateInputType).then(function (cepRawValue) { 632 | configurations.providers = configurations.providers ? configurations.providers : []; 633 | validateProviders(configurations.providers); 634 | return cepRawValue; 635 | }).then(removeSpecialCharacters).then(validateInputLength).then(leftPadWithZeros).then(function (cepWithLeftPad) { 636 | return fetchCepFromServices(cepWithLeftPad, configurations); 637 | })["catch"](handleServicesError)["catch"](throwApplicationError$5); 638 | } 639 | 640 | function validateProviders(providers) { 641 | var availableProviders = Object.keys(getAvailableServices()); 642 | 643 | if (!Array.isArray(providers)) { 644 | throw new CepPromiseError({ 645 | message: 'Erro ao inicializar a instância do CepPromise.', 646 | type: 'validation_error', 647 | errors: [{ 648 | message: 'O parâmetro providers deve ser uma lista.', 649 | service: 'providers_validation' 650 | }] 651 | }); 652 | } 653 | 654 | var _iterator = _createForOfIteratorHelper(providers), 655 | _step; 656 | 657 | try { 658 | for (_iterator.s(); !(_step = _iterator.n()).done;) { 659 | var provider = _step.value; 660 | 661 | if (!availableProviders.includes(provider)) { 662 | throw new CepPromiseError({ 663 | message: 'Erro ao inicializar a instância do CepPromise.', 664 | type: 'validation_error', 665 | errors: [{ 666 | message: "O provider \"".concat(provider, "\" \xE9 inv\xE1lido. Os providers dispon\xEDveis s\xE3o: [\"").concat(availableProviders.join('", "'), "\"]."), 667 | service: 'providers_validation' 668 | }] 669 | }); 670 | } 671 | } 672 | } catch (err) { 673 | _iterator.e(err); 674 | } finally { 675 | _iterator.f(); 676 | } 677 | } 678 | 679 | function validateInputType(cepRawValue) { 680 | var cepTypeOf = _typeof(cepRawValue); 681 | 682 | if (cepTypeOf === 'number' || cepTypeOf === 'string') { 683 | return cepRawValue; 684 | } 685 | 686 | throw new CepPromiseError({ 687 | message: 'Erro ao inicializar a instância do CepPromise.', 688 | type: 'validation_error', 689 | errors: [{ 690 | message: 'Você deve chamar o construtor utilizando uma String ou um Number.', 691 | service: 'cep_validation' 692 | }] 693 | }); 694 | } 695 | 696 | function removeSpecialCharacters(cepRawValue) { 697 | return cepRawValue.toString().replace(/\D+/g, ''); 698 | } 699 | 700 | function leftPadWithZeros(cepCleanValue) { 701 | return '0'.repeat(CEP_SIZE - cepCleanValue.length) + cepCleanValue; 702 | } 703 | 704 | function validateInputLength(cepWithLeftPad) { 705 | if (cepWithLeftPad.length <= CEP_SIZE) { 706 | return cepWithLeftPad; 707 | } 708 | 709 | throw new CepPromiseError({ 710 | message: "CEP deve conter exatamente ".concat(CEP_SIZE, " caracteres."), 711 | type: 'validation_error', 712 | errors: [{ 713 | message: "CEP informado possui mais do que ".concat(CEP_SIZE, " caracteres."), 714 | service: 'cep_validation' 715 | }] 716 | }); 717 | } 718 | 719 | function fetchCepFromServices(cepWithLeftPad, configurations) { 720 | var providersServices = getAvailableServices(); 721 | 722 | if (configurations.providers.length === 0) { 723 | return Promise$1.any(Object.values(providersServices).map(function (provider) { 724 | return provider(cepWithLeftPad, configurations); 725 | })); 726 | } 727 | 728 | return Promise$1.any(configurations.providers.map(function (provider) { 729 | return providersServices[provider](cepWithLeftPad, configurations); 730 | })); 731 | } 732 | 733 | function handleServicesError(aggregatedErrors) { 734 | if (aggregatedErrors.length !== undefined) { 735 | throw new CepPromiseError({ 736 | message: 'Todos os serviços de CEP retornaram erro.', 737 | type: 'service_error', 738 | errors: aggregatedErrors 739 | }); 740 | } 741 | 742 | throw aggregatedErrors; 743 | } 744 | 745 | function throwApplicationError$5(_ref) { 746 | var message = _ref.message, 747 | type = _ref.type, 748 | errors = _ref.errors; 749 | throw new CepPromiseError({ 750 | message: message, 751 | type: type, 752 | errors: errors 753 | }); 754 | } 755 | 756 | return cepPromise; 757 | 758 | }))); 759 | -------------------------------------------------------------------------------- /dist/cep-promise.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r(require("node-fetch")):"function"==typeof define&&define.amd?define(["node-fetch"],r):(e=e||self).cep=r(e.fetch)}(this,function(i){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function a(e,r){if(!(e instanceof r))throw new TypeError("Cannot call a class as a function")}function e(e,r){if("function"!=typeof r&&null!==r)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(r&&r.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),r&&c(e,r)}function n(e){return(n=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function c(e,r){return(c=Object.setPrototypeOf||function(e,r){return e.__proto__=r,e})(e,r)}function s(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function u(e,r,t){return(u=s()?Reflect.construct:function(e,r,t){var o=[null];o.push.apply(o,r);var n=new(Function.bind.apply(e,o));return t&&c(n,t.prototype),n}).apply(null,arguments)}function r(e){var o="function"==typeof Map?new Map:void 0;return(r=function(e){if(null===e||(r=e,-1===Function.toString.call(r).indexOf("[native code]")))return e;var r;if("function"!=typeof e)throw new TypeError("Super expression must either be null or a function");if(void 0!==o){if(o.has(e))return o.get(e);o.set(e,t)}function t(){return u(e,arguments,n(this).constructor)}return t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),c(t,e)})(e)}function p(e,r){return!r||"object"!=typeof r&&"function"!=typeof r?function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(e):r}function o(t){var o=s();return function(){var e,r=n(t);return p(this,o?(e=n(this).constructor,Reflect.construct(r,arguments,e)):r.apply(this,arguments))}}function f(e){return function(e){if(Array.isArray(e))return d(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||l(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(e,r){if(e){if("string"==typeof e)return d(e,r);var t=Object.prototype.toString.call(e).slice(8,-1);return"Object"===t&&e.constructor&&(t=e.constructor.name),"Map"===t||"Set"===t?Array.from(e):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?d(e,r):void 0}}function d(e,r){(null==r||r>e.length)&&(r=e.length);for(var t=0,o=new Array(r);t\n\n \n \n \n '.concat(e,"\n \n \n"),headers:{"Content-Type":"text/xml;charset=UTF-8","cache-control":"no-cache"},timeout:r.timeout||3e4};return i("https://apps.correios.com.br/SigepMasterJPA/AtendeClienteService/AtendeCliente",t).then(y).catch(P)}function y(e){return e.ok?e.text().then(b).then(E):e.text().then(g).then(w)}function b(e){try{var r;return(null!==(r=e.replace(/\r?\n|\r/g,"").match(/(.*)<\/return>/)[0])&&void 0!==r?r:"").replace("","").replace("","").split(/");return 1(.*)<\/faultstring>/)[0])&&void 0!==r?r:"").replace("","").replace("","")}catch(e){throw new Error("Não foi possível interpretar o XML de resposta.")}}function w(e){throw new Error(e)}function E(e){return{cep:e.cep,state:e.uf,city:e.cidade,neighborhood:e.bairro,street:e.end,service:"correios"}}function P(e){var r=new m({message:e.message,service:"correios"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço dos Correios."),r}function j(e,r){var t={method:"POST",mode:"cors",headers:{"content-type":"application/x-www-form-urlencoded; charset=UTF-8",Referer:"https://buscacepinter.correios.com.br/app/endereco/index.php","Referrer-Policy":"strict-origin-when-cross-origin"},body:"endereco=".concat(e,"&tipoCEP=ALL"),timeout:r.timeout||3e4};return i("https://buscacepinter.correios.com.br/app/endereco/carrega-cep-endereco.php",t).then(C).then(S).catch(O)}function C(e){return e.json().then(function(e){if(0===e.total||e.erro||""===e.dados[0].cep)throw new Error("CEP não encontrado na base dos Correios.");return e})}function S(e){var r=e.dados[0];return{cep:r.cep,state:r.uf,city:r.localidade,neighborhood:r.bairro,street:r.logradouroDNEC,service:"correios-alt"}}function O(e){var r=new m({message:e.message,service:"correios-alt"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço dos Correios Alt."),r}function x(e,r){var t="https://viacep.com.br/ws/".concat(e,"/json/"),o={method:"GET",mode:"cors",headers:{"content-type":"application/json;charset=utf-8"},timeout:r.timeout||3e4};return"undefined"==typeof window&&(o.headers["user-agent"]="cep-promise"),i(t,o).then(A).then(_).then(T).catch(F)}function A(e){if(e.ok)return e.json();throw Error("Erro ao se conectar com o serviço ViaCEP.")}function _(e){if(!0===e.erro)throw new Error("CEP não encontrado na base do ViaCEP.");return e}function T(e){return{cep:e.cep.replace("-",""),state:e.uf,city:e.localidade,neighborhood:e.bairro,street:e.logradouro,service:"viacep"}}function F(e){var r=new m({message:e.message,service:"viacep"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço ViaCEP."),r}function R(e,r){var t="".concat(e.slice(0,5),"-").concat(e.slice(5)),o="https://cdn.apicep.com/file/apicep/".concat(t,".json"),n={method:"GET",mode:"cors",headers:{accept:"application/json"},timeout:r.timeout||3e4};return i(o,n).then(I).then(N).then(k).catch(M)}function I(e){if(e.ok)return e.json();throw Error("Erro ao se conectar com o serviço WideNet.")}function N(e){if(!1===e.ok||200!==e.status)throw new Error("CEP não encontrado na base do WideNet.");return e}function k(e){return{cep:e.code.replace("-",""),state:e.state,city:e.city,neighborhood:e.district,street:e.address,service:"widenet"}}function M(e){var r=new m({message:e.message,service:"widenet"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço WideNet."),r}function z(e,r){var t="https://brasilapi.com.br/api/cep/v1/".concat(e),o={method:"GET",mode:"cors",headers:{"content-type":"application/json;charset=utf-8"},timeout:r.timeout||3e4};return i(t,o).then(B).then(D).catch(L)}function B(e){if(!1===e.ok||200!==e.status)throw new Error("CEP não encontrado na base do BrasilAPI.");return e.json()}function D(e){return{cep:e.cep,state:e.state,city:e.city,neighborhood:e.neighborhood,street:e.street,service:"brasilapi"}}function L(e){var r=new m({message:e.message,service:"brasilapi"});throw"FetchError"===e.name&&(r.message="Erro ao se conectar com o serviço BrasilAPI."),r}function V(){return"undefined"!=typeof window?{viacep:x,widenet:R,brasilapi:z}:{correios:v,"correios-alt":j,viacep:x,widenet:R,brasilapi:z}}function G(t){return new Promise(function(e,r){return Promise.resolve(t).then(r,e)})}Promise.any=function(e){return G(Promise.all(f(e).map(G)))};var U=Promise,W=8;function q(e){var r=t(e);if("number"===r||"string"===r)return e;throw new h({message:"Erro ao inicializar a instância do CepPromise.",type:"validation_error",errors:[{message:"Você deve chamar o construtor utilizando uma String ou um Number.",service:"cep_validation"}]})}function X(e){return e.toString().replace(/\D+/g,"")}function H(e){return"0".repeat(W-e.length)+e}function J(e){if(e.length<=W)return e;throw new h({message:"CEP deve conter exatamente ".concat(W," caracteres."),type:"validation_error",errors:[{message:"CEP informado possui mais do que ".concat(W," caracteres."),service:"cep_validation"}]})}function $(e){if(void 0!==e.length)throw new h({message:"Todos os serviços de CEP retornaram erro.",type:"service_error",errors:e});throw e}function K(e){var r=e.message,t=e.type,o=e.errors;throw new h({message:r,type:t,errors:o})}return function(e){var n=1=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(e){throw e},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,c=!0,a=!1;return{s:function(){t=e[Symbol.iterator]()},n:function(){var e=t.next();return c=e.done,e},e:function(e){a=!0,i=e},f:function(){try{c||null==t.return||t.return()}finally{if(a)throw i}}}}(e);try{for(o.s();!(t=o.n()).done;){var n=t.value;if(!r.includes(n))throw new h({message:"Erro ao inicializar a instância do CepPromise.",type:"validation_error",errors:[{message:'O provider "'.concat(n,'" é inválido. Os providers disponíveis são: ["').concat(r.join('", "'),'"].'),service:"providers_validation"}]})}}catch(e){o.e(e)}finally{o.f()}}(n.providers),e}).then(X).then(J).then(H).then(function(e){return r=e,t=n,o=V(),0!==t.providers.length?U.any(t.providers.map(function(e){return o[e](r,t)})):U.any(Object.values(o).map(function(e){return e(r,t)}));var r,t,o}).catch($).catch(K)}}); -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "cep-promise" { 2 | /** Represents the result of a CEP search */ 3 | export interface CEP { 4 | /** The retrieved CEP number */ 5 | cep: string; 6 | /** The state associated with the CEP */ 7 | state: string; 8 | /** The city associated with the CEP */ 9 | city: string; 10 | /** The street associated with the CEP */ 11 | street: string; 12 | /** The neighborhood associated with the CEP */ 13 | neighborhood: string; 14 | /** The provider which returned the result */ 15 | service: string; 16 | } 17 | 18 | /** 19 | * Available providers: 20 | * 21 | * | Provider | Browser | Node.js | 22 | * | ------------ | ------- | ------- | 23 | * | brasilapi | ✅ | ✅ | 24 | * | viacep | ✅ | ✅ | 25 | * | widenet | ✅ | ✅ | 26 | * | correios | ❌ | ✅ | 27 | * | correios-alt | ❌ | ✅ | 28 | */ 29 | export const AvailableProviders: { 30 | /** Supported in both **Node.js** and **Browser** environments. */ 31 | readonly brasilapi: "brasilapi"; 32 | /** Supported in both **Node.js** and **Browser** environments. */ 33 | readonly viacep: "viacep"; 34 | /** Supported in both **Node.js** and **Browser** environments. */ 35 | readonly widenet: "widenet"; 36 | /** Supported only in **Node.js** environment. */ 37 | readonly correios: "correios"; 38 | /** Supported only in **Node.js** environment. */ 39 | readonly correiosAlt: "correios-alt"; 40 | }; 41 | 42 | /** Configuration options to customize the CEP search, by selecting specific providers and/or setting a timeout */ 43 | export interface Configurations { 44 | /** Specifies the providers to be used for CEP searches, otherwise all available providers will be used. 45 | * 46 | * --- 47 | * 48 | * Available providers: 49 | * 50 | * | Provider | Browser | Node.js | 51 | * | ------------ | ------- | ------- | 52 | * | brasilapi | ✅ | ✅ | 53 | * | viacep | ✅ | ✅ | 54 | * | widenet | ✅ | ✅ | 55 | * | correios | ❌ | ✅ | 56 | * | correios-alt | ❌ | ✅ | 57 | */ 58 | providers?: (typeof AvailableProviders)[keyof typeof AvailableProviders][]; 59 | /** Timeout (in milliseconds) after which the CEP search will be cancelled. */ 60 | timeout?: number; 61 | } 62 | 63 | /** 64 | * Searches for CEP directly integrated with the services of Correios, ViaCEP, and WideNet (Node.js and Browser). 65 | * 66 | * --- 67 | * 68 | * @param cep The CEP (postal code) to search for. 69 | * @param configurations Optional configurations to customize the CEP search. 70 | * @returns A promise that resolves with the CEP details. 71 | */ 72 | export function cep( 73 | cep: string | number, 74 | configurations?: Configurations 75 | ): Promise; 76 | 77 | export default cep; 78 | } 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cep-promise", 3 | "version": "4.4.1", 4 | "description": "Busca por CEP integrado diretamente aos serviços dos Correios e ViaCEP", 5 | "main": "dist/cep-promise.min.js", 6 | "module": "dist/cep-promise.min.js", 7 | "types": "./index.d.ts", 8 | "scripts": { 9 | "dev": "nodemon --watch src/ --exec \"npm run build\"", 10 | "test": "npm run coverage", 11 | "coverage": "babel-node node_modules/.bin/babel-istanbul cover _mocha -- test/**/*.spec.js", 12 | "test-unit": "mocha test/unit/**/*.spec.js", 13 | "test-unit-watch": "mocha --watch test/unit/**/*.spec.js", 14 | "test-e2e": "mocha test/e2e/**/*.spec.js", 15 | "test-e2e-watch": "mocha --watch test/e2e/**/*.spec.js", 16 | "lint-check": "standard", 17 | "lint-fix": "standard --fix", 18 | "build-browser": "rollup -c && uglifyjs dist/cep-promise-browser.js -cm -o dist/cep-promise-browser.min.js", 19 | "build-node": "rollup -c && uglifyjs dist/cep-promise.js -cm -o dist/cep-promise.min.js", 20 | "build": "npm run build-browser && npm run build-node", 21 | "prepublishOnly": "npm run build" 22 | }, 23 | "browser": "dist/cep-promise-browser.min.js", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/BrasilAPI/cep-promise.git" 27 | }, 28 | "author": "Filipe Deschamps", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/BrasilAPI/cep-promise/issues" 32 | }, 33 | "keywords": [ 34 | "cep", 35 | "correios", 36 | "zipcode", 37 | "zip", 38 | "promise", 39 | "viacep", 40 | "brasilapi", 41 | "widenet", 42 | "apicep" 43 | ], 44 | "homepage": "https://github.com/BrasilAPI/cep-promise", 45 | "devDependencies": { 46 | "@babel/cli": "7.10.5", 47 | "@babel/core": "7.11.1", 48 | "@babel/node": "7.10.5", 49 | "@babel/plugin-transform-runtime": "^7.11.0", 50 | "@babel/preset-env": "7.11.0", 51 | "@babel/register": "7.10.5", 52 | "babel-core": "7.0.0-bridge.0", 53 | "babel-eslint": "10.1.0", 54 | "babel-istanbul": "0.12.2", 55 | "chai": "4.2.0", 56 | "chai-as-promised": "7.1.1", 57 | "chai-subset": "1.6.0", 58 | "mocha": "8.1.1", 59 | "nock": "13.0.2", 60 | "nodemon": "2.0.4", 61 | "rollup": "2.20.0", 62 | "rollup-plugin-babel": "4.4.0", 63 | "rollup-plugin-commonjs": "10.1.0", 64 | "rollup-plugin-node-resolve": "5.2.0", 65 | "rollup-plugin-replace": "2.2.0", 66 | "standard": "14.3.4", 67 | "uglify-js": "3.10.0" 68 | }, 69 | "standard": { 70 | "parser": "babel-eslint", 71 | "globals": [ 72 | "describe", 73 | "it", 74 | "afterEach" 75 | ] 76 | }, 77 | "dependencies": { 78 | "node-fetch": "2.6.7", 79 | "unfetch": "4.1.0" 80 | }, 81 | "files": [ 82 | "dist", 83 | "index.d.ts" 84 | ] 85 | } 86 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import resolve from 'rollup-plugin-node-resolve' 4 | import replace from 'rollup-plugin-replace' 5 | 6 | const input = 'src/cep-promise.js' 7 | const defaultPlugins = [ 8 | babel({ 9 | babelrc: false, 10 | presets: [['@babel/preset-env', { modules: false }]] 11 | }) 12 | ] 13 | 14 | export default [ 15 | { 16 | input, 17 | plugins: [].concat(defaultPlugins, [ 18 | commonjs() 19 | ]), 20 | output: { 21 | file: 'dist/cep-promise.js', 22 | format: 'umd', 23 | name: 'cep' 24 | } 25 | }, 26 | { 27 | input, 28 | plugins: [ 29 | replace({ 30 | 'node-fetch': 'unfetch', 31 | }) 32 | ].concat(defaultPlugins, [ 33 | resolve({ 34 | browser: true 35 | }), 36 | commonjs() 37 | ]), 38 | context: 'window', 39 | output: { 40 | file: 'dist/cep-promise-browser.js', 41 | format: 'umd', 42 | name: 'cep' 43 | } 44 | } 45 | ] 46 | 47 | -------------------------------------------------------------------------------- /src/cep-promise.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import CepPromiseError from './errors/cep-promise.js' 4 | import { getAvailableServices } from './services/index.js' 5 | import Promise from './utils/promise-any.js' 6 | 7 | const CEP_SIZE = 8 8 | 9 | export default function (cepRawValue, configurations = {}) { 10 | return Promise.resolve(cepRawValue) 11 | .then(validateInputType) 12 | .then(cepRawValue => { 13 | configurations.providers = configurations.providers ? configurations.providers : [] 14 | validateProviders(configurations.providers) 15 | 16 | return cepRawValue 17 | }) 18 | .then(removeSpecialCharacters) 19 | .then(validateInputLength) 20 | .then(leftPadWithZeros) 21 | .then((cepWithLeftPad) => { 22 | return fetchCepFromServices(cepWithLeftPad, configurations) 23 | }) 24 | .catch(handleServicesError) 25 | .catch(throwApplicationError) 26 | } 27 | 28 | function validateProviders (providers) { 29 | const availableProviders = Object.keys(getAvailableServices()) 30 | 31 | if (!Array.isArray(providers)) { 32 | throw new CepPromiseError({ 33 | message: 'Erro ao inicializar a instância do CepPromise.', 34 | type: 'validation_error', 35 | errors: [ 36 | { 37 | message: 38 | 'O parâmetro providers deve ser uma lista.', 39 | service: 'providers_validation' 40 | } 41 | ] 42 | }) 43 | } 44 | 45 | for (const provider of providers) { 46 | if (!availableProviders.includes(provider)) { 47 | throw new CepPromiseError({ 48 | message: 'Erro ao inicializar a instância do CepPromise.', 49 | type: 'validation_error', 50 | errors: [ 51 | { 52 | message: 53 | `O provider "${provider}" é inválido. Os providers disponíveis são: ["${availableProviders.join('", "')}"].`, 54 | service: 'providers_validation' 55 | } 56 | ] 57 | }) 58 | } 59 | } 60 | } 61 | 62 | function validateInputType (cepRawValue) { 63 | const cepTypeOf = typeof cepRawValue 64 | 65 | if (cepTypeOf === 'number' || cepTypeOf === 'string') { 66 | return cepRawValue 67 | } 68 | 69 | throw new CepPromiseError({ 70 | message: 'Erro ao inicializar a instância do CepPromise.', 71 | type: 'validation_error', 72 | errors: [ 73 | { 74 | message: 75 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 76 | service: 'cep_validation' 77 | } 78 | ] 79 | }) 80 | } 81 | 82 | function removeSpecialCharacters (cepRawValue) { 83 | return cepRawValue.toString().replace(/\D+/g, '') 84 | } 85 | 86 | function leftPadWithZeros (cepCleanValue) { 87 | return '0'.repeat(CEP_SIZE - cepCleanValue.length) + cepCleanValue 88 | } 89 | 90 | function validateInputLength (cepWithLeftPad) { 91 | if (cepWithLeftPad.length <= CEP_SIZE) { 92 | return cepWithLeftPad 93 | } 94 | 95 | throw new CepPromiseError({ 96 | message: `CEP deve conter exatamente ${CEP_SIZE} caracteres.`, 97 | type: 'validation_error', 98 | errors: [ 99 | { 100 | message: `CEP informado possui mais do que ${CEP_SIZE} caracteres.`, 101 | service: 'cep_validation' 102 | } 103 | ] 104 | }) 105 | } 106 | 107 | function fetchCepFromServices (cepWithLeftPad, configurations) { 108 | const providersServices = getAvailableServices() 109 | 110 | if (configurations.providers.length === 0) { 111 | return Promise.any( 112 | Object.values(providersServices).map(provider => provider(cepWithLeftPad, configurations)) 113 | ) 114 | } 115 | 116 | return Promise.any( 117 | configurations.providers.map(provider => { 118 | return providersServices[provider](cepWithLeftPad, configurations) 119 | }) 120 | ) 121 | } 122 | 123 | function handleServicesError (aggregatedErrors) { 124 | if (aggregatedErrors.length !== undefined) { 125 | throw new CepPromiseError({ 126 | message: 'Todos os serviços de CEP retornaram erro.', 127 | type: 'service_error', 128 | errors: aggregatedErrors 129 | }) 130 | } 131 | throw aggregatedErrors 132 | } 133 | 134 | function throwApplicationError ({ message, type, errors }) { 135 | throw new CepPromiseError({ message, type, errors }) 136 | } 137 | -------------------------------------------------------------------------------- /src/errors/cep-promise.js: -------------------------------------------------------------------------------- 1 | class CepPromiseError extends Error { 2 | constructor ({ message, type, errors } = {}) { 3 | super() 4 | 5 | this.name = 'CepPromiseError' 6 | this.message = message 7 | this.type = type 8 | this.errors = errors 9 | } 10 | } 11 | 12 | export default CepPromiseError 13 | -------------------------------------------------------------------------------- /src/errors/service.js: -------------------------------------------------------------------------------- 1 | class ServiceError extends Error { 2 | constructor ({ message, service } = {}) { 3 | super() 4 | 5 | this.name = 'ServiceError' 6 | this.message = message 7 | this.service = service 8 | } 9 | } 10 | 11 | export default ServiceError 12 | -------------------------------------------------------------------------------- /src/services/brasilapi.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import fetch from 'node-fetch' 4 | import ServiceError from '../errors/service.js' 5 | 6 | export default function fetchBrasilAPIService (cepWithLeftPad, configurations) { 7 | const url = `https://brasilapi.com.br/api/cep/v1/${cepWithLeftPad}` 8 | const options = { 9 | method: 'GET', 10 | mode: 'cors', 11 | headers: { 12 | 'content-type': 'application/json;charset=utf-8' 13 | }, 14 | timeout: configurations.timeout || 30000 15 | } 16 | 17 | return fetch(url, options) 18 | .then(parseResponse) 19 | .then(extractCepValuesFromResponse) 20 | .catch(throwApplicationError) 21 | } 22 | 23 | function parseResponse (response) { 24 | if (response.ok === false || response.status !== 200) { 25 | throw new Error('CEP não encontrado na base do BrasilAPI.') 26 | } 27 | 28 | return response.json() 29 | } 30 | 31 | function extractCepValuesFromResponse (response) { 32 | return { 33 | cep: response.cep, 34 | state: response.state, 35 | city: response.city, 36 | neighborhood: response.neighborhood, 37 | street: response.street, 38 | service: 'brasilapi' 39 | } 40 | } 41 | 42 | function throwApplicationError (error) { 43 | const serviceError = new ServiceError({ 44 | message: error.message, 45 | service: 'brasilapi' 46 | }) 47 | 48 | if (error.name === 'FetchError') { 49 | serviceError.message = 'Erro ao se conectar com o serviço BrasilAPI.' 50 | } 51 | 52 | throw serviceError 53 | } 54 | -------------------------------------------------------------------------------- /src/services/correios-alt.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import fetch from 'node-fetch' 4 | import ServiceError from '../errors/service.js' 5 | 6 | export default function fetchCorreiosAltAPIService( 7 | cepWithLeftPad, 8 | configurations 9 | ) { 10 | const url = 'https://buscacepinter.correios.com.br/app/endereco/carrega-cep-endereco.php' 11 | const options = { 12 | method: 'POST', 13 | mode: 'cors', 14 | headers: { 15 | 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 16 | 'Referer': 'https://buscacepinter.correios.com.br/app/endereco/index.php', 17 | 'Referrer-Policy': 'strict-origin-when-cross-origin' 18 | }, 19 | body: `endereco=${cepWithLeftPad}&tipoCEP=ALL`, 20 | timeout: configurations.timeout || 30000 21 | } 22 | 23 | return fetch(url, options) 24 | .then(parseResponse) 25 | .then(extractCepValuesFromResponse) 26 | .catch(throwApplicationError) 27 | } 28 | 29 | function parseResponse(response) { 30 | return response.json().then(result => { 31 | if (result.total === 0 || result.erro || result.dados[0].cep === "") { 32 | throw new Error('CEP não encontrado na base dos Correios.') 33 | } 34 | return result 35 | }) 36 | } 37 | 38 | function extractCepValuesFromResponse(response) { 39 | const firstCep = response.dados[0] 40 | return { 41 | cep: firstCep.cep, 42 | state: firstCep.uf, 43 | city: firstCep.localidade, 44 | neighborhood: firstCep.bairro, 45 | street: firstCep.logradouroDNEC, 46 | service: 'correios-alt' 47 | } 48 | } 49 | 50 | function throwApplicationError(error) { 51 | const serviceError = new ServiceError({ 52 | message: error.message, 53 | service: 'correios-alt' 54 | }) 55 | 56 | if (error.name === 'FetchError') { 57 | serviceError.message = 'Erro ao se conectar com o serviço dos Correios Alt.' 58 | } 59 | 60 | throw serviceError 61 | } 62 | -------------------------------------------------------------------------------- /src/services/correios.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import fetch from 'node-fetch' 4 | import ServiceError from '../errors/service.js' 5 | 6 | export default function fetchCorreiosService (cepWithLeftPad, configurations) { 7 | const url = 'https://apps.correios.com.br/SigepMasterJPA/AtendeClienteService/AtendeCliente' 8 | const options = { 9 | method: 'POST', 10 | body: `\n\n \n \n \n ${cepWithLeftPad}\n \n \n`, 11 | headers: { 12 | 'Content-Type': 'text/xml;charset=UTF-8', 13 | 'cache-control': 'no-cache' 14 | }, 15 | timeout: configurations.timeout || 30000 16 | } 17 | 18 | return fetch(url, options) 19 | .then(analyzeAndParseResponse) 20 | .catch(throwApplicationError) 21 | } 22 | 23 | function analyzeAndParseResponse (response) { 24 | if (response.ok) { 25 | return response.text() 26 | .then(parseSuccessXML) 27 | .then(extractValuesFromSuccessResponse) 28 | } 29 | 30 | return response.text() 31 | .then(parseAndextractErrorMessage) 32 | .then(throwCorreiosError) 33 | } 34 | 35 | function parseSuccessXML (xmlString) { 36 | try { 37 | const returnStatement = xmlString.replace(/\r?\n|\r/g, '').match(/(.*)<\/return>/)[0] ?? '' 38 | const cleanReturnStatement = returnStatement.replace('', '').replace('', '') 39 | const parsedReturnStatement = cleanReturnStatement 40 | .split(/ { 42 | const splittenExp = exp.split('>') 43 | if (splittenExp.length > 1 && splittenExp[1].length) { 44 | result[splittenExp[0]] = splittenExp[1] 45 | } 46 | return result 47 | }, {}) 48 | 49 | return parsedReturnStatement 50 | } catch (e) { 51 | throw new Error('Não foi possível interpretar o XML de resposta.') 52 | } 53 | } 54 | 55 | function parseAndextractErrorMessage (xmlString) { 56 | try { 57 | const returnStatement = xmlString.match(/(.*)<\/faultstring>/)[0] ?? '' 58 | const cleanReturnStatement = returnStatement.replace('', '').replace('', '') 59 | return cleanReturnStatement 60 | } catch (e) { 61 | throw new Error('Não foi possível interpretar o XML de resposta.') 62 | } 63 | } 64 | 65 | function throwCorreiosError (translatedErrorMessage) { 66 | throw new Error(translatedErrorMessage) 67 | } 68 | 69 | function extractValuesFromSuccessResponse (xmlObject) { 70 | return { 71 | cep: xmlObject.cep, 72 | state: xmlObject.uf, 73 | city: xmlObject.cidade, 74 | neighborhood: xmlObject.bairro, 75 | street: xmlObject.end, 76 | service: 'correios' 77 | } 78 | } 79 | 80 | function throwApplicationError (error) { 81 | const serviceError = new ServiceError({ 82 | message: error.message, 83 | service: 'correios' 84 | }) 85 | 86 | if (error.name === 'FetchError') { 87 | serviceError.message = 'Erro ao se conectar com o serviço dos Correios.' 88 | } 89 | 90 | throw serviceError 91 | } 92 | -------------------------------------------------------------------------------- /src/services/index.js: -------------------------------------------------------------------------------- 1 | import Correios from './correios' 2 | import CorreiosAlt from './correios-alt' 3 | import ViaCep from './viacep' 4 | import WideNet from './widenet' 5 | import BrasilAPI from './brasilapi.js' 6 | 7 | export function getAvailableServices () { 8 | const isBrowser = typeof window !== 'undefined' 9 | 10 | if (isBrowser) { 11 | return { 12 | viacep: ViaCep, 13 | widenet: WideNet, 14 | brasilapi: BrasilAPI 15 | } 16 | } 17 | 18 | return { 19 | correios: Correios, 20 | 'correios-alt': CorreiosAlt, 21 | viacep: ViaCep, 22 | widenet: WideNet, 23 | brasilapi: BrasilAPI 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/services/viacep.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import fetch from 'node-fetch' 4 | import ServiceError from '../errors/service.js' 5 | 6 | export default function fetchViaCepService (cepWithLeftPad, configurations) { 7 | const url = `https://viacep.com.br/ws/${cepWithLeftPad}/json/` 8 | const options = { 9 | method: 'GET', 10 | mode: 'cors', 11 | headers: { 12 | 'content-type': 'application/json;charset=utf-8' 13 | }, 14 | timeout: configurations.timeout || 30000 15 | } 16 | 17 | if (typeof window == 'undefined') { 18 | options.headers['user-agent'] = 'cep-promise' 19 | } 20 | 21 | return fetch(url, options) 22 | .then(analyzeAndParseResponse) 23 | .then(checkForViaCepError) 24 | .then(extractCepValuesFromResponse) 25 | .catch(throwApplicationError) 26 | } 27 | 28 | function analyzeAndParseResponse (response) { 29 | if (response.ok) { 30 | return response.json() 31 | } 32 | 33 | throw Error('Erro ao se conectar com o serviço ViaCEP.') 34 | } 35 | 36 | function checkForViaCepError (responseObject) { 37 | if (responseObject.erro === true) { 38 | throw new Error('CEP não encontrado na base do ViaCEP.') 39 | } 40 | 41 | return responseObject 42 | } 43 | 44 | function extractCepValuesFromResponse (responseObject) { 45 | return { 46 | cep: responseObject.cep.replace('-', ''), 47 | state: responseObject.uf, 48 | city: responseObject.localidade, 49 | neighborhood: responseObject.bairro, 50 | street: responseObject.logradouro, 51 | service: 'viacep' 52 | } 53 | } 54 | 55 | function throwApplicationError (error) { 56 | const serviceError = new ServiceError({ 57 | message: error.message, 58 | service: 'viacep' 59 | }) 60 | 61 | if (error.name === 'FetchError') { 62 | serviceError.message = 'Erro ao se conectar com o serviço ViaCEP.' 63 | } 64 | 65 | throw serviceError 66 | } 67 | -------------------------------------------------------------------------------- /src/services/widenet.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import fetch from 'node-fetch' 4 | import ServiceError from '../errors/service.js' 5 | 6 | export default function fetchWideNetService(cepWithLeftPad, configurations) { 7 | const cepWithDash = `${cepWithLeftPad.slice(0, 5)}-${cepWithLeftPad.slice(5)}` 8 | const url = `https://cdn.apicep.com/file/apicep/${cepWithDash}.json` 9 | const options = { 10 | method: 'GET', 11 | mode: 'cors', 12 | headers: { 13 | accept: 'application/json' 14 | }, 15 | timeout: configurations.timeout || 30000 16 | } 17 | 18 | return fetch(url, options) 19 | .then(analyzeAndParseResponse) 20 | .then(checkForWideNetError) 21 | .then(extractCepValuesFromResponse) 22 | .catch(throwApplicationError) 23 | } 24 | 25 | function analyzeAndParseResponse(response) { 26 | if (response.ok) { 27 | return response.json() 28 | } 29 | 30 | throw Error('Erro ao se conectar com o serviço WideNet.') 31 | } 32 | 33 | function checkForWideNetError(object) { 34 | if (object.ok === false || object.status !== 200) { 35 | throw new Error('CEP não encontrado na base do WideNet.') 36 | } 37 | 38 | return object 39 | } 40 | 41 | function extractCepValuesFromResponse(object) { 42 | return { 43 | cep: object.code.replace('-', ''), 44 | state: object.state, 45 | city: object.city, 46 | neighborhood: object.district, 47 | street: object.address, 48 | service: 'widenet' 49 | } 50 | } 51 | 52 | function throwApplicationError(error) { 53 | const serviceError = new ServiceError({ 54 | message: error.message, 55 | service: 'widenet' 56 | }) 57 | 58 | if (error.name === 'FetchError') { 59 | serviceError.message = 'Erro ao se conectar com o serviço WideNet.' 60 | } 61 | 62 | throw serviceError 63 | } 64 | -------------------------------------------------------------------------------- /src/utils/promise-any.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const reverse = (promise) => new Promise((resolve, reject) => Promise.resolve(promise).then(reject, resolve)) 4 | 5 | Promise.any = (iterable) => reverse(Promise.all([...iterable].map(reverse))) 6 | 7 | export default Promise 8 | -------------------------------------------------------------------------------- /test/e2e/cep-promise.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import chai from 'chai' 4 | import chaiAsPromised from 'chai-as-promised' 5 | import chaiSubset from 'chai-subset' 6 | import nock from 'nock' 7 | 8 | import cep from '../../src/cep-promise.js' 9 | import CepPromiseError from '../../src/errors/cep-promise.js' 10 | 11 | chai.use(chaiAsPromised) 12 | chai.use(chaiSubset) 13 | 14 | let expect = chai.expect 15 | 16 | describe('[e2e] cep-promise', () => { 17 | before(() => { 18 | nock.enableNetConnect() 19 | }) 20 | 21 | describe('when invoked with a valid "05010000" string', () => { 22 | it('should fulfill with correct address', () => cep('05010000') 23 | .then(address => { 24 | expect(address).to.deep.equal({ 25 | cep: '05010000', 26 | state: 'SP', 27 | city: 'São Paulo', 28 | neighborhood: 'Perdizes', 29 | street: 'Rua Caiubi', 30 | service: address.service 31 | })}) 32 | ) 33 | }) 34 | 35 | describe('when invoked with a valid 05010000 number', () => { 36 | it('should fulfill with correct address', async () => { 37 | const address = await cep(5010000) 38 | 39 | expect(address).to.deep.equal({ 40 | cep: '05010000', 41 | state: 'SP', 42 | city: 'São Paulo', 43 | neighborhood: 'Perdizes', 44 | street: 'Rua Caiubi', 45 | service: address.service 46 | }) 47 | }) 48 | }) 49 | 50 | describe('when invoked with an inexistent "99999999" CEP', () => { 51 | it('should reject with "service_error"', () => { 52 | return cep('99999999').catch(error => { 53 | return expect(error) 54 | .to.be.an.instanceOf(CepPromiseError) 55 | .and.containSubset({ 56 | name: 'CepPromiseError', 57 | message: 'Todos os serviços de CEP retornaram erro.', 58 | type: 'service_error', 59 | errors: [ 60 | { 61 | message: 'CEP INVÁLIDO', 62 | service: 'correios' 63 | }, 64 | { 65 | message: 'Erro ao se conectar com o serviço dos Correios Alt.', 66 | service: 'correios-alt' 67 | }, 68 | { 69 | message: 'CEP não encontrado na base do ViaCEP.', 70 | service: 'viacep' 71 | }, 72 | { 73 | service: 'widenet' 74 | }, 75 | { 76 | name: 'ServiceError', 77 | message: 'CEP não encontrado na base do BrasilAPI.', 78 | service: 'brasilapi' 79 | } 80 | ] 81 | }) 82 | }) 83 | }) 84 | }) 85 | 86 | describe('when invoked with an invalid "123456789" CEP', () => { 87 | it('should reject with "validation_error"', () => { 88 | return cep('123456789').catch(error => { 89 | return expect(error) 90 | .to.be.an.instanceOf(CepPromiseError) 91 | .and.containSubset({ 92 | name: 'CepPromiseError', 93 | message: 'CEP deve conter exatamente 8 caracteres.', 94 | type: 'validation_error', 95 | errors: [ 96 | { 97 | service: 'cep_validation', 98 | message: 'CEP informado possui mais do que 8 caracteres.' 99 | } 100 | ] 101 | }) 102 | }) 103 | }) 104 | }) 105 | }) 106 | -------------------------------------------------------------------------------- /test/unit/cep-promise-browser.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import chai from 'chai' 4 | import chaiAsPromised from 'chai-as-promised' 5 | import chaiSubset from 'chai-subset' 6 | import nock from 'nock' 7 | import path from 'path' 8 | 9 | import cep from '../../src/cep-promise.js' 10 | import CepPromiseError from '../../src/errors/cep-promise.js' 11 | 12 | chai.use(chaiAsPromised) 13 | chai.use(chaiSubset) 14 | 15 | let expect = chai.expect 16 | 17 | describe('[unit] cep-promise for browser', () => { 18 | before(() => { 19 | // Mock browser behavior 20 | global.window = {} 21 | nock.disableNetConnect() 22 | }) 23 | 24 | describe('when imported', () => { 25 | it('should return a Function', () => { 26 | expect(cep).to.be.a('function') 27 | }) 28 | }) 29 | 30 | describe('when invoked', () => { 31 | it('should return a Promise', () => { 32 | nock('https://viacep.com.br') 33 | .get('/ws/05010000/json/') 34 | .replyWithFile( 35 | 200, 36 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 37 | ) 38 | 39 | nock('https://cdn.apicep.com') 40 | .get('/file/apicep/05010-000.json') 41 | .replyWithFile( 42 | 200, 43 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 44 | ) 45 | 46 | nock('https://brasilapi.com.br/') 47 | .get('/api/cep/v1/05010000') 48 | .replyWithFile( 49 | 200, 50 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 51 | ) 52 | 53 | const cepPromise = cep('05010000') 54 | expect(cepPromise.then).to.be.a('function') 55 | expect(cepPromise.catch).to.be.a('function') 56 | }) 57 | }) 58 | 59 | describe('when invoked without arguments', () => { 60 | it('should reject with "validation_error"', () => { 61 | return cep().catch(error => { 62 | return expect(error) 63 | .to.be.an.instanceOf(CepPromiseError) 64 | .and.containSubset({ 65 | name: 'CepPromiseError', 66 | message: 'Erro ao inicializar a instância do CepPromise.', 67 | type: 'validation_error', 68 | errors: [ 69 | { 70 | message: 71 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 72 | service: 'cep_validation' 73 | } 74 | ] 75 | }) 76 | }) 77 | }) 78 | }) 79 | 80 | describe('when invoked with an Array', () => { 81 | it('should reject with "validation_error"', () => { 82 | return cep([1, 2, 3]).catch(error => { 83 | return expect(error) 84 | .to.be.an.instanceOf(CepPromiseError) 85 | .and.containSubset({ 86 | name: 'CepPromiseError', 87 | message: 'Erro ao inicializar a instância do CepPromise.', 88 | type: 'validation_error', 89 | errors: [ 90 | { 91 | message: 92 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 93 | service: 'cep_validation' 94 | } 95 | ] 96 | }) 97 | }) 98 | }) 99 | }) 100 | 101 | describe('when invoked with an Object', () => { 102 | it('should reject with "validation_error"', () => { 103 | return cep({ nintendo: true, ps: false, xbox: false }).catch(error => { 104 | return expect(error) 105 | .to.be.an.instanceOf(CepPromiseError) 106 | .and.containSubset({ 107 | name: 'CepPromiseError', 108 | message: 'Erro ao inicializar a instância do CepPromise.', 109 | type: 'validation_error', 110 | errors: [ 111 | { 112 | message: 113 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 114 | service: 'cep_validation' 115 | } 116 | ] 117 | }) 118 | }) 119 | }) 120 | }) 121 | 122 | describe('when invoked with an Function', () => { 123 | it('should reject with "validation_error"', () => { 124 | return cep(function zelda() { 125 | return 'link' 126 | }).catch(error => { 127 | return expect(error) 128 | .to.be.an.instanceOf(CepPromiseError) 129 | .and.containSubset({ 130 | name: 'CepPromiseError', 131 | message: 'Erro ao inicializar a instância do CepPromise.', 132 | type: 'validation_error', 133 | errors: [ 134 | { 135 | message: 136 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 137 | service: 'cep_validation' 138 | } 139 | ] 140 | }) 141 | }) 142 | }) 143 | }) 144 | 145 | describe('when invoked with a valid "05010000" String', () => { 146 | it('should fulfill with correct address', () => { 147 | nock('https://viacep.com.br') 148 | .get('/ws/05010000/json/') 149 | .replyWithFile( 150 | 200, 151 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 152 | ) 153 | 154 | nock('https://cdn.apicep.com') 155 | .get('/file/apicep/05010-000.json') 156 | .replyWithFile( 157 | 200, 158 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 159 | ) 160 | 161 | nock('https://brasilapi.com.br/') 162 | .get('/api/cep/v1/05010000') 163 | .replyWithFile( 164 | 200, 165 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 166 | ) 167 | 168 | return cep('05010000') 169 | .then(address => expect(address).to.deep.equal({ 170 | cep: '05010000', 171 | state: 'SP', 172 | city: 'São Paulo', 173 | neighborhood: 'Perdizes', 174 | street: 'Rua Caiubi', 175 | service: address.service 176 | }) 177 | ) 178 | }) 179 | }) 180 | 181 | describe('when invoked with a valid 5010000 Number', () => { 182 | it('should fulfill with correct address', () => { 183 | nock('https://viacep.com.br') 184 | .get('/ws/05010000/json/') 185 | .replyWithFile( 186 | 200, 187 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 188 | ) 189 | 190 | nock('https://cdn.apicep.com') 191 | .get('/file/apicep/05010-000.json') 192 | .replyWithFile( 193 | 200, 194 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 195 | ) 196 | 197 | nock('https://brasilapi.com.br/') 198 | .get('/api/cep/v1/05010000') 199 | .replyWithFile( 200 | 200, 201 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 202 | ) 203 | 204 | return cep(5010000) 205 | .then(address => expect(address).to.deep.equal({ 206 | cep: '05010000', 207 | state: 'SP', 208 | city: 'São Paulo', 209 | neighborhood: 'Perdizes', 210 | street: 'Rua Caiubi', 211 | service: address.service 212 | }) 213 | ) 214 | }) 215 | }) 216 | 217 | describe('Should succeed only with viacep service', () => { 218 | it('should fulfill with correct address', () => { 219 | nock('https://viacep.com.br') 220 | .get('/ws/05010000/json/') 221 | .replyWithFile( 222 | 200, 223 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 224 | ) 225 | 226 | nock('https://cdn.apicep.com') 227 | .get('/file/apicep/05010-000.json') 228 | .replyWithFile( 229 | 200, 230 | path.join(__dirname, '/fixtures/widenet-cep-99999999-error.json') 231 | ) 232 | 233 | nock('https://brasilapi.com.br/') 234 | .get('/api/cep/v1/99999999') 235 | .replyWithFile( 236 | 404, 237 | path.join(__dirname, '/fixtures/brasilapi-cep-99999999-error.json') 238 | ) 239 | 240 | return cep('05010000') 241 | .then(address => expect(address).to.deep.equal({ 242 | cep: '05010000', 243 | state: 'SP', 244 | city: 'São Paulo', 245 | neighborhood: 'Perdizes', 246 | street: 'Rua Caiubi', 247 | service: 'viacep' 248 | }) 249 | ) 250 | }) 251 | }) 252 | 253 | describe('Should succeed only with widenet service', () => { 254 | it('should fulfill with correct address', () => { 255 | nock('https://viacep.com.br') 256 | .get('/ws/05010000/json/') 257 | .replyWithFile( 258 | 200, 259 | path.join(__dirname, '/fixtures/viacep-cep-99999999-error.json') 260 | ) 261 | 262 | nock('https://cdn.apicep.com') 263 | .get('/file/apicep/05010-000.json') 264 | .replyWithFile( 265 | 200, 266 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 267 | ) 268 | 269 | nock('https://brasilapi.com.br/') 270 | .get('/api/cep/v1/99999999') 271 | .replyWithFile( 272 | 404, 273 | path.join(__dirname, '/fixtures/brasilapi-cep-99999999-error.json') 274 | ) 275 | 276 | return cep('5010000') 277 | .then(address => expect(address).to.deep.equal({ 278 | cep: '05010000', 279 | state: 'SP', 280 | city: 'São Paulo', 281 | neighborhood: 'Perdizes', 282 | street: 'Rua Caiubi', 283 | service: 'widenet' 284 | })) 285 | }) 286 | }) 287 | 288 | describe('Should succeed only with brasilapi service', () => { 289 | it('should fulfill with correct address', () => { 290 | nock('https://viacep.com.br') 291 | .get('/ws/05010000/json/') 292 | .replyWithFile( 293 | 200, 294 | path.join(__dirname, '/fixtures/viacep-cep-99999999-error.json') 295 | ) 296 | 297 | nock('https://cdn.apicep.com') 298 | .get('/file/apicep/05010-000.json') 299 | .replyWithFile( 300 | 200, 301 | path.join(__dirname, '/fixtures/widenet-cep-99999999-error.json') 302 | ) 303 | 304 | nock('https://brasilapi.com.br/') 305 | .get('/api/cep/v1/05010000') 306 | .replyWithFile( 307 | 200, 308 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 309 | ) 310 | 311 | return cep('5010000') 312 | .then(address => expect(address).to.deep.equal({ 313 | cep: '05010000', 314 | state: 'SP', 315 | city: 'São Paulo', 316 | neighborhood: 'Perdizes', 317 | street: 'Rua Caiubi', 318 | service: 'brasilapi' 319 | })) 320 | }) 321 | }) 322 | 323 | describe('when invoked with an inexistent "99999999" CEP', () => { 324 | it('should reject with "service_error"', () => { 325 | nock('https://viacep.com.br') 326 | .get('/ws/99999999/json/') 327 | .replyWithFile( 328 | 200, 329 | path.join(__dirname, '/fixtures/viacep-cep-99999999-error.json') 330 | ) 331 | 332 | nock('https://cdn.apicep.com') 333 | .get('/file/apicep/99999-999.json') 334 | .replyWithFile( 335 | 200, 336 | path.join(__dirname, '/fixtures/widenet-cep-99999999-error.json') 337 | ) 338 | 339 | nock('https://brasilapi.com.br/') 340 | .get('/api/cep/v1/99999999') 341 | .replyWithFile( 342 | 404, 343 | path.join(__dirname, '/fixtures/brasilapi-cep-99999999-error.json') 344 | ) 345 | 346 | return cep('99999999').catch(error => { 347 | return expect(error) 348 | .to.be.an.instanceOf(CepPromiseError) 349 | .and.containSubset({ 350 | name: 'CepPromiseError', 351 | message: 'Todos os serviços de CEP retornaram erro.', 352 | type: 'service_error', 353 | errors: [ 354 | { 355 | message: 'CEP não encontrado na base do ViaCEP.', 356 | service: 'viacep' 357 | }, 358 | { 359 | message: 'CEP não encontrado na base do WideNet.', 360 | service: 'widenet' 361 | } 362 | ] 363 | }) 364 | }) 365 | }) 366 | }) 367 | 368 | describe('when invoked with an invalid "123456789" CEP', () => { 369 | it('should reject with "validation_error"', () => { 370 | return cep('123456789').catch(error => { 371 | return expect(error) 372 | .to.be.an.instanceOf(CepPromiseError) 373 | .and.containSubset({ 374 | name: 'CepPromiseError', 375 | message: 'CEP deve conter exatamente 8 caracteres.', 376 | type: 'validation_error', 377 | errors: [ 378 | { 379 | service: 'cep_validation', 380 | message: 'CEP informado possui mais do que 8 caracteres.' 381 | } 382 | ] 383 | }) 384 | }) 385 | }) 386 | }) 387 | 388 | describe('when http request fails both for all services with bad response', () => { 389 | it('should reject with "service_error"', () => { 390 | nock('https://viacep.com.br') 391 | .get('/ws/05010000/json/') 392 | .reply(400, '

Bad Request (400)

') 393 | 394 | nock('https://cdn.apicep.com') 395 | .get('/file/apicep/05010-000.json') 396 | .reply(400, '

Bad Request (400)

') 397 | 398 | nock('https://brasilapi.com.br/') 399 | .get('/api/cep/v1/05010000') 400 | .reply(400, '

Bad Request (400)

') 401 | 402 | return cep('05010000').catch(error => { 403 | return expect(error) 404 | .to.be.an.instanceOf(CepPromiseError) 405 | .and.containSubset({ 406 | name: 'CepPromiseError', 407 | message: 'Todos os serviços de CEP retornaram erro.', 408 | type: 'service_error', 409 | errors: [ 410 | { 411 | message: 'Erro ao se conectar com o serviço ViaCEP.', 412 | service: 'viacep' 413 | }, 414 | { 415 | message: 'Erro ao se conectar com o serviço WideNet.', 416 | service: 'widenet' 417 | }, 418 | { 419 | name: 'ServiceError', 420 | message: 'CEP não encontrado na base do BrasilAPI.', 421 | service: 'brasilapi' 422 | } 423 | ] 424 | }) 425 | }) 426 | }) 427 | }) 428 | 429 | afterEach(() => { 430 | nock.cleanAll() 431 | }) 432 | 433 | after(() => { 434 | delete global.window 435 | }) 436 | }) 437 | -------------------------------------------------------------------------------- /test/unit/cep-promise-node.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import chai from 'chai' 4 | import chaiAsPromised from 'chai-as-promised' 5 | import chaiSubset from 'chai-subset' 6 | import nock from 'nock' 7 | import path from 'path' 8 | 9 | import cep from '../../src/cep-promise.js' 10 | import CepPromiseError from '../../src/errors/cep-promise.js' 11 | 12 | chai.use(chaiAsPromised) 13 | chai.use(chaiSubset) 14 | 15 | let expect = chai.expect 16 | 17 | describe('[unit] cep-promise for node', () => { 18 | before(() => { 19 | nock.disableNetConnect() 20 | }) 21 | 22 | describe('when imported', () => { 23 | it('should return a Function', () => { 24 | expect(cep).to.be.a('function') 25 | }) 26 | }) 27 | 28 | describe('when invoked', () => { 29 | it('should return a Promise', () => { 30 | nock('https://apps.correios.com.br') 31 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 32 | .replyWithFile( 33 | 200, 34 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 35 | ) 36 | 37 | nock('https://buscacepinter.correios.com.br') 38 | .post('/app/endereco/carrega-cep-endereco.php') 39 | .replyWithFile( 40 | 200, 41 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 42 | ) 43 | 44 | nock('https://viacep.com.br') 45 | .get('/ws/05010000/json/') 46 | .replyWithFile( 47 | 200, 48 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 49 | ) 50 | 51 | nock('https://cdn.apicep.com') 52 | .get('/file/apicep/05010-000.json') 53 | .replyWithFile( 54 | 200, 55 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 56 | ) 57 | 58 | nock('https://brasilapi.com.br/') 59 | .get('/api/cep/v1/05010000') 60 | .replyWithFile( 61 | 200, 62 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 63 | ) 64 | 65 | const cepPromise = cep('05010000') 66 | expect(cepPromise.then).to.be.a('function') 67 | expect(cepPromise.catch).to.be.a('function') 68 | }) 69 | }) 70 | 71 | describe('when invoked without arguments', () => { 72 | it('should reject with "validation_error"', () => { 73 | return cep().catch(error => { 74 | return expect(error) 75 | .to.be.an.instanceOf(CepPromiseError) 76 | .and.containSubset({ 77 | name: 'CepPromiseError', 78 | message: 'Erro ao inicializar a instância do CepPromise.', 79 | type: 'validation_error', 80 | errors: [ 81 | { 82 | message: 83 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 84 | service: 'cep_validation' 85 | } 86 | ] 87 | }) 88 | }) 89 | }) 90 | }) 91 | 92 | describe('when invoked with an Array', () => { 93 | it('should reject with "validation_error"', () => { 94 | return cep([1, 2, 3]).catch(error => { 95 | return expect(error) 96 | .to.be.an.instanceOf(CepPromiseError) 97 | .and.containSubset({ 98 | name: 'CepPromiseError', 99 | message: 'Erro ao inicializar a instância do CepPromise.', 100 | type: 'validation_error', 101 | errors: [ 102 | { 103 | message: 104 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 105 | service: 'cep_validation' 106 | } 107 | ] 108 | }) 109 | }) 110 | }) 111 | }) 112 | 113 | describe('when invoked with an Object', () => { 114 | it('should reject with "validation_error"', () => { 115 | return cep({ nintendo: true, ps: false, xbox: false }).catch(error => { 116 | return expect(error) 117 | .to.be.an.instanceOf(CepPromiseError) 118 | .and.containSubset({ 119 | name: 'CepPromiseError', 120 | message: 'Erro ao inicializar a instância do CepPromise.', 121 | type: 'validation_error', 122 | errors: [ 123 | { 124 | message: 125 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 126 | service: 'cep_validation' 127 | } 128 | ] 129 | }) 130 | }) 131 | }) 132 | }) 133 | 134 | describe('when invoked with an Function', () => { 135 | it('should reject with "validation_error"', () => { 136 | return cep(function zelda() { 137 | return 'link' 138 | }).catch(error => { 139 | return expect(error) 140 | .to.be.an.instanceOf(CepPromiseError) 141 | .and.containSubset({ 142 | name: 'CepPromiseError', 143 | message: 'Erro ao inicializar a instância do CepPromise.', 144 | type: 'validation_error', 145 | errors: [ 146 | { 147 | message: 148 | 'Você deve chamar o construtor utilizando uma String ou um Number.', 149 | service: 'cep_validation' 150 | } 151 | ] 152 | }) 153 | }) 154 | }) 155 | }) 156 | 157 | describe('when invoked with a valid "05010000" String', () => { 158 | it('should fulfill with correct address', () => { 159 | nock('https://apps.correios.com.br') 160 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 161 | .replyWithFile( 162 | 200, 163 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 164 | ) 165 | 166 | nock('https://buscacepinter.correios.com.br') 167 | .post('/app/endereco/carrega-cep-endereco.php') 168 | .replyWithFile( 169 | 200, 170 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 171 | ) 172 | 173 | nock('https://viacep.com.br') 174 | .get('/ws/05010000/json/') 175 | .replyWithFile( 176 | 200, 177 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 178 | ) 179 | 180 | nock('https://cdn.apicep.com') 181 | .get('/file/apicep/05010-000.json') 182 | .replyWithFile( 183 | 200, 184 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 185 | ) 186 | 187 | nock('https://brasilapi.com.br/') 188 | .get('/api/cep/v1/05010000') 189 | .replyWithFile( 190 | 200, 191 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 192 | ) 193 | 194 | return cep('05010000') 195 | .then(address => expect(address).to.deep.equal({ 196 | cep: '05010000', 197 | state: 'SP', 198 | city: 'São Paulo', 199 | neighborhood: 'Perdizes', 200 | street: 'Rua Caiubi', 201 | service: address.service 202 | }) 203 | ) 204 | }) 205 | }) 206 | 207 | describe('when invoked with a valid 5010000 Number', () => { 208 | it('should fulfill with correct address', () => { 209 | nock('https://apps.correios.com.br') 210 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 211 | .replyWithFile( 212 | 200, 213 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 214 | ) 215 | 216 | nock('https://buscacepinter.correios.com.br') 217 | .post('/app/endereco/carrega-cep-endereco.php') 218 | .replyWithFile( 219 | 200, 220 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 221 | ) 222 | 223 | nock('https://viacep.com.br') 224 | .get('/ws/05010000/json/') 225 | .replyWithFile( 226 | 200, 227 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 228 | ) 229 | 230 | nock('https://cdn.apicep.com') 231 | .get('/file/apicep/05010-000.json') 232 | .replyWithFile( 233 | 200, 234 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 235 | ) 236 | 237 | nock('https://brasilapi.com.br/') 238 | .get('/api/cep/v1/05010000') 239 | .replyWithFile( 240 | 200, 241 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 242 | ) 243 | 244 | return cep(5010000) 245 | .then(address => expect(address).to.deep.equal({ 246 | cep: '05010000', 247 | state: 'SP', 248 | city: 'São Paulo', 249 | neighborhood: 'Perdizes', 250 | street: 'Rua Caiubi', 251 | service: address.service 252 | }) 253 | ) 254 | }) 255 | }) 256 | 257 | describe('Should succeed only with correios service', () => { 258 | it('should fulfill with correct address', () => { 259 | nock('https://apps.correios.com.br') 260 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 261 | .replyWithFile( 262 | 200, 263 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 264 | ) 265 | 266 | nock('https://buscacepinter.correios.com.br') 267 | .post('/app/endereco/carrega-cep-endereco.php') 268 | .replyWithFile( 269 | 200, 270 | path.join(__dirname, '/fixtures/correios-alt-cep-99999999-error.json') 271 | ) 272 | 273 | nock('https://viacep.com.br') 274 | .get('/ws/05010000/json/') 275 | .replyWithFile( 276 | 200, 277 | path.join(__dirname, '/fixtures/viacep-cep-99999999-error.json') 278 | ) 279 | 280 | nock('https://cep.widenet.host') 281 | .get('/file/apicep/05010-000.json') 282 | .replyWithFile( 283 | 200, 284 | path.join(__dirname, '/fixtures/widenet-cep-99999999-error.json') 285 | ) 286 | 287 | nock('https://brasilapi.com.br/') 288 | .get('/api/cep/v1/99999999') 289 | .replyWithFile( 290 | 404, 291 | path.join(__dirname, '/fixtures/brasilapi-cep-99999999-error.json') 292 | ) 293 | 294 | 295 | return cep('05010000') 296 | .then(address => expect(address).to.deep.equal({ 297 | cep: '05010000', 298 | state: 'SP', 299 | city: 'São Paulo', 300 | neighborhood: 'Perdizes', 301 | street: 'Rua Caiubi', 302 | service: 'correios' 303 | }) 304 | ) 305 | }) 306 | }) 307 | 308 | describe('Should succeed only with correios-alt service', () => { 309 | it('should fulfill with correct address', () => { 310 | nock('https://apps.correios.com.br') 311 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 312 | .replyWithFile( 313 | 500, 314 | path.join(__dirname, '/fixtures/response-unknown-format.xml') 315 | ) 316 | 317 | nock('https://buscacepinter.correios.com.br') 318 | .post('/app/endereco/carrega-cep-endereco.php') 319 | .replyWithFile( 320 | 200, 321 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 322 | ) 323 | 324 | nock('https://viacep.com.br') 325 | .get('/ws/05010000/json/') 326 | .replyWithFile( 327 | 200, 328 | path.join(__dirname, '/fixtures/viacep-cep-99999999-error.json') 329 | ) 330 | 331 | nock('https://cdn.apicep.com') 332 | .get('/file/apicep/05010-000.json') 333 | .replyWithFile( 334 | 200, 335 | path.join(__dirname, '/fixtures/widenet-cep-99999999-error.json') 336 | ) 337 | 338 | nock('https://brasilapi.com.br/') 339 | .get('/api/cep/v1/99999999') 340 | .replyWithFile( 341 | 404, 342 | path.join(__dirname, '/fixtures/brasilapi-cep-99999999-error.json') 343 | ) 344 | 345 | 346 | return cep('05010000') 347 | .then(address => expect(address).to.deep.equal({ 348 | cep: '05010000', 349 | state: 'SP', 350 | city: 'São Paulo', 351 | neighborhood: 'Perdizes', 352 | street: 'Rua Caiubi', 353 | service: 'correios-alt' 354 | }) 355 | ) 356 | }) 357 | }) 358 | 359 | describe('Should succeed only with viacep service', () => { 360 | it('should fulfill with correct address', () => { 361 | nock('https://apps.correios.com.br') 362 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 363 | .replyWithFile( 364 | 500, 365 | path.join(__dirname, '/fixtures/response-unknown-format.xml') 366 | ) 367 | 368 | nock('https://buscacepinter.correios.com.br') 369 | .post('/app/endereco/carrega-cep-endereco.php') 370 | .replyWithFile( 371 | 200, 372 | path.join(__dirname, '/fixtures/correios-alt-cep-99999999-error.json') 373 | ) 374 | 375 | nock('https://viacep.com.br') 376 | .get('/ws/05010000/json/') 377 | .replyWithFile( 378 | 200, 379 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 380 | ) 381 | 382 | nock('https://cdn.apicep.com') 383 | .get('/file/apicep/05010-000.json') 384 | .replyWithFile( 385 | 200, 386 | path.join(__dirname, '/fixtures/widenet-cep-99999999-error.json') 387 | ) 388 | 389 | nock('https://brasilapi.com.br/') 390 | .get('/api/cep/v1/99999999') 391 | .replyWithFile( 392 | 404, 393 | path.join(__dirname, '/fixtures/brasilapi-cep-99999999-error.json') 394 | ) 395 | 396 | return cep('05010000') 397 | .then(address => expect(address).to.deep.equal({ 398 | cep: '05010000', 399 | state: 'SP', 400 | city: 'São Paulo', 401 | neighborhood: 'Perdizes', 402 | street: 'Rua Caiubi', 403 | service: 'viacep' 404 | }) 405 | ) 406 | }) 407 | }) 408 | 409 | describe('Should succeed only with widenet service', () => { 410 | it('should fulfill with correct address', () => { 411 | nock('https://apps.correios.com.br') 412 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 413 | .replyWithFile( 414 | 500, 415 | path.join(__dirname, '/fixtures/response-unknown-format.xml') 416 | ) 417 | 418 | nock('https://buscacepinter.correios.com.br') 419 | .post('/app/endereco/carrega-cep-endereco.php') 420 | .replyWithFile( 421 | 200, 422 | path.join(__dirname, '/fixtures/correios-alt-cep-99999999-error.json') 423 | ) 424 | 425 | nock('https://viacep.com.br') 426 | .get('/ws/05010000/json/') 427 | .replyWithFile( 428 | 200, 429 | path.join(__dirname, '/fixtures/viacep-cep-99999999-error.json') 430 | ) 431 | 432 | nock('https://cdn.apicep.com') 433 | .get('/file/apicep/05010-000.json') 434 | .replyWithFile( 435 | 200, 436 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 437 | ) 438 | 439 | nock('https://brasilapi.com.br/') 440 | .get('/api/cep/v1/99999999') 441 | .replyWithFile( 442 | 404, 443 | path.join(__dirname, '/fixtures/brasilapi-cep-99999999-error.json') 444 | ) 445 | 446 | return cep('5010000') 447 | .then(address => expect(address).to.deep.equal({ 448 | cep: '05010000', 449 | state: 'SP', 450 | city: 'São Paulo', 451 | neighborhood: 'Perdizes', 452 | street: 'Rua Caiubi', 453 | service: 'widenet' 454 | })) 455 | }) 456 | }) 457 | 458 | describe('Should succeed only with brasilapi service', () => { 459 | it('should fulfill with correct address', () => { 460 | nock('https://apps.correios.com.br') 461 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 462 | .replyWithFile( 463 | 500, 464 | path.join(__dirname, '/fixtures/response-unknown-format.xml') 465 | ) 466 | 467 | nock('https://buscacepinter.correios.com.br') 468 | .post('/app/endereco/carrega-cep-endereco.php') 469 | .replyWithFile( 470 | 200, 471 | path.join(__dirname, '/fixtures/correios-alt-cep-99999999-error.json') 472 | ) 473 | 474 | nock('https://viacep.com.br') 475 | .get('/ws/05010000/json/') 476 | .replyWithFile( 477 | 200, 478 | path.join(__dirname, '/fixtures/viacep-cep-99999999-error.json') 479 | ) 480 | 481 | nock('https://cdn.apicep.com') 482 | .get('/file/apicep/05010-000.json') 483 | .replyWithFile( 484 | 200, 485 | path.join(__dirname, '/fixtures/widenet-cep-99999999-error.json') 486 | ) 487 | 488 | nock('https://brasilapi.com.br/') 489 | .get('/api/cep/v1/05010000') 490 | .replyWithFile( 491 | 200, 492 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 493 | ) 494 | 495 | return cep('5010000') 496 | .then(address => expect(address).to.deep.equal({ 497 | cep: '05010000', 498 | state: 'SP', 499 | city: 'São Paulo', 500 | neighborhood: 'Perdizes', 501 | street: 'Rua Caiubi', 502 | service: 'brasilapi' 503 | })) 504 | }) 505 | }) 506 | 507 | describe('when its not possible to parse the returned XML and then succeed to one failover service', () => { 508 | it('should fulfill with correct address', () => { 509 | nock('https://apps.correios.com.br') 510 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 511 | .replyWithFile( 512 | 200, 513 | path.join(__dirname, '/fixtures/response-bad-xml.xml') 514 | ) 515 | 516 | nock('https://buscacepinter.correios.com.br') 517 | .post('/app/endereco/carrega-cep-endereco.php') 518 | .replyWithFile( 519 | 200, 520 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 521 | ) 522 | 523 | nock('https://viacep.com.br') 524 | .get('/ws/05010000/json/') 525 | .replyWithFile( 526 | 200, 527 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 528 | ) 529 | 530 | nock('https://cdn.apicep.com') 531 | .get('/file/apicep/05010-000.json') 532 | .replyWithFile( 533 | 200, 534 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 535 | ) 536 | 537 | nock('https://brasilapi.com.br/') 538 | .get('/api/cep/v1/05010000') 539 | .replyWithFile( 540 | 200, 541 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 542 | ) 543 | 544 | return cep('5010000') 545 | .then(address => expect(address).to.deep.equal({ 546 | cep: '05010000', 547 | state: 'SP', 548 | city: 'São Paulo', 549 | neighborhood: 'Perdizes', 550 | street: 'Rua Caiubi', 551 | service: address.service 552 | })) 553 | }) 554 | }) 555 | 556 | describe('when http request to Correios fails and then succeed to the failover service', () => { 557 | it('should fulfill with correct address', () => { 558 | nock('https://apps.correios.com.br') 559 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 560 | .replyWithError( 561 | 'getaddrinfo ENOTFOUND apps.correios.com.br apps.correios.com.br:443' 562 | ) 563 | 564 | nock('https://buscacepinter.correios.com.br') 565 | .post('/app/endereco/carrega-cep-endereco.php') 566 | .replyWithFile( 567 | 200, 568 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 569 | ) 570 | 571 | nock('https://viacep.com.br') 572 | .get('/ws/05010000/json/') 573 | .replyWithFile( 574 | 200, 575 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 576 | ) 577 | 578 | nock('https://cdn.apicep.com') 579 | .get('/file/apicep/05010-000.json') 580 | .replyWithFile( 581 | 200, 582 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 583 | ) 584 | 585 | nock('https://brasilapi.com.br/') 586 | .get('/api/cep/v1/05010000') 587 | .replyWithFile( 588 | 200, 589 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 590 | ) 591 | 592 | return cep('5010000') 593 | .then(address => expect(address).to.deep.equal({ 594 | cep: '05010000', 595 | state: 'SP', 596 | city: 'São Paulo', 597 | neighborhood: 'Perdizes', 598 | street: 'Rua Caiubi', 599 | service: address.service 600 | })) 601 | }) 602 | }) 603 | 604 | describe('when invoked with an inexistent "99999999" CEP', () => { 605 | it('should reject with "service_error"', () => { 606 | nock('https://apps.correios.com.br') 607 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 608 | .replyWithFile( 609 | 500, 610 | path.join(__dirname, '/fixtures/response-cep-not-found.xml') 611 | ) 612 | 613 | nock('https://buscacepinter.correios.com.br') 614 | .post('/app/endereco/carrega-cep-endereco.php') 615 | .replyWithFile( 616 | 200, 617 | path.join(__dirname, '/fixtures/correios-alt-cep-99999999-error.json') 618 | ) 619 | 620 | nock('https://viacep.com.br') 621 | .get('/ws/99999999/json/') 622 | .replyWithFile( 623 | 200, 624 | path.join(__dirname, '/fixtures/viacep-cep-99999999-error.json') 625 | ) 626 | 627 | nock('https://cdn.apicep.com') 628 | .get('/file/apicep/99999-999.json') 629 | .replyWithFile( 630 | 200, 631 | path.join(__dirname, '/fixtures/widenet-cep-99999999-error.json') 632 | ) 633 | 634 | nock('https://brasilapi.com.br/') 635 | .get('/api/cep/v1/99999999') 636 | .replyWithFile( 637 | 404, 638 | path.join(__dirname, '/fixtures/brasilapi-cep-99999999-error.json') 639 | ) 640 | 641 | return cep('99999999').catch(error => { 642 | return expect(error) 643 | .to.be.an.instanceOf(CepPromiseError) 644 | .and.containSubset({ 645 | name: 'CepPromiseError', 646 | message: 'Todos os serviços de CEP retornaram erro.', 647 | type: 'service_error', 648 | errors: [ 649 | { 650 | message: 'CEP NAO ENCONTRADO', 651 | service: 'correios' 652 | }, 653 | { 654 | message: 'CEP não encontrado na base dos Correios.', 655 | service: 'correios-alt' 656 | }, 657 | { 658 | message: 'CEP não encontrado na base do ViaCEP.', 659 | service: 'viacep' 660 | }, 661 | { 662 | message: 'CEP não encontrado na base do WideNet.', 663 | service: 'widenet' 664 | } 665 | ] 666 | }) 667 | }) 668 | }) 669 | }) 670 | 671 | describe('when invoked with an invalid "123456789" CEP', () => { 672 | it('should reject with "validation_error"', () => { 673 | return cep('123456789').catch(error => { 674 | return expect(error) 675 | .to.be.an.instanceOf(CepPromiseError) 676 | .and.containSubset({ 677 | name: 'CepPromiseError', 678 | message: 'CEP deve conter exatamente 8 caracteres.', 679 | type: 'validation_error', 680 | errors: [ 681 | { 682 | service: 'cep_validation', 683 | message: 'CEP informado possui mais do que 8 caracteres.' 684 | } 685 | ] 686 | }) 687 | }) 688 | }) 689 | }) 690 | 691 | describe('when http request fails both for primary and secondary service with bad response', () => { 692 | it('should reject with "service_error"', () => { 693 | nock('https://apps.correios.com.br') 694 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 695 | .replyWithError( 696 | 'getaddrinfo ENOTFOUND apps.correios.com.br apps.correios.com.br:443' 697 | ) 698 | 699 | nock('https://buscacepinter.correios.com.br') 700 | .post('/app/endereco/carrega-cep-endereco.php') 701 | .reply(400, '

Bad Request (400)

') 702 | 703 | nock('https://viacep.com.br') 704 | .get('/ws/05010000/json/') 705 | .reply(400, '

Bad Request (400)

') 706 | 707 | nock('https://cdn.apicep.com') 708 | .get('/file/apicep/05010-000.json') 709 | .reply(400, '

Bad Request (400)

') 710 | 711 | nock('https://brasilapi.com.br/') 712 | .get('/api/cep/v1/05010000') 713 | .reply(400, '

Bad Request (400)

') 714 | 715 | return cep('05010000').catch(error => { 716 | return expect(error) 717 | .to.be.an.instanceOf(CepPromiseError) 718 | .and.containSubset({ 719 | name: 'CepPromiseError', 720 | message: 'Todos os serviços de CEP retornaram erro.', 721 | type: 'service_error', 722 | errors: [ 723 | { 724 | message: 'Erro ao se conectar com o serviço dos Correios.', 725 | service: 'correios' 726 | }, 727 | { 728 | message: 'Erro ao se conectar com o serviço dos Correios Alt.', 729 | service: 'correios-alt' 730 | }, 731 | { 732 | message: 'Erro ao se conectar com o serviço ViaCEP.', 733 | service: 'viacep' 734 | }, 735 | { 736 | message: 'Erro ao se conectar com o serviço WideNet.', 737 | service: 'widenet' 738 | }, 739 | { 740 | name: 'ServiceError', 741 | message: 'CEP não encontrado na base do BrasilAPI.', 742 | service: 'brasilapi' 743 | } 744 | ] 745 | }) 746 | }) 747 | }) 748 | }) 749 | 750 | describe('when http request has unformatted xml and alternatives services fails', () => { 751 | it('should reject with "service_error"', () => { 752 | nock('https://apps.correios.com.br') 753 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 754 | .replyWithFile( 755 | 200, 756 | path.join(__dirname, '/fixtures/response-bad-xml.xml') 757 | ) 758 | 759 | nock('https://buscacepinter.correios.com.br') 760 | .post('/app/endereco/carrega-cep-endereco.php') 761 | .reply(200, {erro:true}) 762 | 763 | nock('https://viacep.com.br') 764 | .get('/ws/05010000/json/') 765 | .reply(400, '

Bad Request (400)

') 766 | 767 | nock('https://cdn.apicep.com') 768 | .get('/file/apicep/05010-000.json') 769 | .reply(400, '

Bad Request (400)

') 770 | 771 | nock('https://brasilapi.com.br/') 772 | .get('/api/cep/v1/05010000') 773 | .reply(400, '

Bad Request (400)

') 774 | 775 | return cep('05010000').catch(error => { 776 | return expect(error) 777 | .to.be.an.instanceOf(CepPromiseError) 778 | .and.containSubset({ 779 | name: 'CepPromiseError', 780 | message: 'Todos os serviços de CEP retornaram erro.', 781 | type: 'service_error', 782 | errors: [ 783 | { 784 | message: 'Não foi possível interpretar o XML de resposta.', 785 | service: 'correios' 786 | }, 787 | { 788 | message: 'CEP não encontrado na base dos Correios.', 789 | service: 'correios-alt' 790 | }, 791 | { 792 | message: 'Erro ao se conectar com o serviço ViaCEP.', 793 | service: 'viacep' 794 | }, 795 | { 796 | message: 'Erro ao se conectar com o serviço WideNet.', 797 | service: 'widenet' 798 | }, 799 | { 800 | name: 'ServiceError', 801 | message: 'CEP não encontrado na base do BrasilAPI.', 802 | service: 'brasilapi' 803 | } 804 | ] 805 | }) 806 | }) 807 | }) 808 | }) 809 | 810 | describe('when http request fails both for primary and secondary service with error', () => { 811 | it('should reject with "service_error"', () => { 812 | nock('https://apps.correios.com.br') 813 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 814 | .replyWithError( 815 | 'getaddrinfo ENOTFOUND apps.correios.com.br apps.correios.com.br:443' 816 | ) 817 | 818 | nock('https://buscacepinter.correios.com.br') 819 | .post('/app/endereco/carrega-cep-endereco.php') 820 | .reply(200, {erro:true}) 821 | 822 | nock('https://viacep.com.br') 823 | .get('/ws/05010000/json/') 824 | .replyWithError( 825 | 'getaddrinfo ENOTFOUND apps.correios.com.br apps.correios.com.br:443' 826 | ) 827 | 828 | nock('https://cdn.apicep.com') 829 | .get('/file/apicep/05010-000.json') 830 | .replyWithError( 831 | 'getaddrinfo ENOTFOUND apps.correios.com.br apps.correios.com.br:443' 832 | ) 833 | 834 | nock('https://brasilapi.com.br/') 835 | .get('/api/cep/v1/05010000') 836 | .replyWithError( 837 | 'getaddrinfo ENOTFOUND apps.correios.com.br apps.correios.com.br:443' 838 | ) 839 | 840 | return cep('05010000').catch(error => { 841 | return expect(error) 842 | .to.be.an.instanceOf(CepPromiseError) 843 | .and.containSubset({ 844 | name: 'CepPromiseError', 845 | message: 'Todos os serviços de CEP retornaram erro.', 846 | type: 'service_error', 847 | errors: [ 848 | { 849 | message: 'Erro ao se conectar com o serviço dos Correios.', 850 | service: 'correios' 851 | }, 852 | { 853 | message: 'CEP não encontrado na base dos Correios.', 854 | service: 'correios-alt' 855 | }, 856 | { 857 | message: 'Erro ao se conectar com o serviço ViaCEP.', 858 | service: 'viacep' 859 | }, 860 | { 861 | message: 'Erro ao se conectar com o serviço WideNet.', 862 | service: 'widenet' 863 | }, 864 | { 865 | message: 'Erro ao se conectar com o serviço BrasilAPI.', 866 | service: 'brasilapi' 867 | } 868 | ] 869 | }) 870 | }) 871 | }) 872 | }) 873 | 874 | afterEach(() => { 875 | nock.cleanAll() 876 | }) 877 | }) 878 | -------------------------------------------------------------------------------- /test/unit/cep-promise-providers.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import chai from 'chai' 4 | import chaiSubset from 'chai-subset' 5 | import nock from 'nock' 6 | import path from 'path' 7 | 8 | import cep from '../../src/cep-promise.js' 9 | import CepPromiseError from '../../src/errors/cep-promise.js' 10 | import { getAvailableServices } from '../../src/services/index.js' 11 | 12 | chai.use(chaiSubset) 13 | 14 | let expect = chai.expect 15 | 16 | describe('when invoked with providers parameter', () => { 17 | before(() => { 18 | nock.disableNetConnect() 19 | }) 20 | 21 | describe('and the providers param is a string', () => { 22 | it('should reject with "validation_error"', () => { 23 | return cep('05010000', { providers: 'viacep' }).catch(error => { 24 | return expect(error) 25 | .to.be.an.instanceOf(CepPromiseError) 26 | .and.containSubset({ 27 | name: 'CepPromiseError', 28 | message: 'Erro ao inicializar a instância do CepPromise.', 29 | type: 'validation_error', 30 | errors: [ 31 | { 32 | service: 'providers_validation', 33 | message: 'O parâmetro providers deve ser uma lista.' 34 | } 35 | ] 36 | }) 37 | }) 38 | }) 39 | }) 40 | 41 | describe('and the providers param is a integer', () => { 42 | it('should reject with "validation_error"', () => { 43 | return cep('05010000', { providers: 123 }).catch(error => { 44 | return expect(error) 45 | .to.be.an.instanceOf(CepPromiseError) 46 | .and.containSubset({ 47 | name: 'CepPromiseError', 48 | message: 'Erro ao inicializar a instância do CepPromise.', 49 | type: 'validation_error', 50 | errors: [ 51 | { 52 | service: 'providers_validation', 53 | message: 'O parâmetro providers deve ser uma lista.' 54 | } 55 | ] 56 | }) 57 | }) 58 | }) 59 | }) 60 | 61 | describe('and the providers param is a object', () => { 62 | it('should reject with "validation_error"', () => { 63 | return cep('05010000', { providers: {} }).catch(error => { 64 | return expect(error) 65 | .to.be.an.instanceOf(CepPromiseError) 66 | .and.containSubset({ 67 | name: 'CepPromiseError', 68 | message: 'Erro ao inicializar a instância do CepPromise.', 69 | type: 'validation_error', 70 | errors: [ 71 | { 72 | service: 'providers_validation', 73 | message: 'O parâmetro providers deve ser uma lista.' 74 | } 75 | ] 76 | }) 77 | }) 78 | }) 79 | }) 80 | 81 | describe('and the providers param is a function', () => { 82 | it('should reject with "validation_error"', () => { 83 | return cep('05010000', { providers: () => () => { } }).catch(error => { 84 | return expect(error) 85 | .to.be.an.instanceOf(CepPromiseError) 86 | .and.containSubset({ 87 | name: 'CepPromiseError', 88 | message: 'Erro ao inicializar a instância do CepPromise.', 89 | type: 'validation_error', 90 | errors: [ 91 | { 92 | service: 'providers_validation', 93 | message: 'O parâmetro providers deve ser uma lista.' 94 | } 95 | ] 96 | }) 97 | }) 98 | }) 99 | }) 100 | 101 | describe('and the providers param is a invalid array', () => { 102 | it('should reject with "validation_error"', () => { 103 | const availableProviders = Object.keys(getAvailableServices()) 104 | 105 | return cep('05010000', { providers: [123, 'viacep'] }).catch(error => { 106 | return expect(error) 107 | .to.be.an.instanceOf(CepPromiseError) 108 | .and.containSubset({ 109 | message: 'Erro ao inicializar a instância do CepPromise.', 110 | type: 'validation_error', 111 | errors: [ 112 | { 113 | message: 114 | `O provider "123" é inválido. Os providers disponíveis são: ["${availableProviders.join('", "')}"].`, 115 | service: 'providers_validation' 116 | } 117 | ] 118 | }) 119 | }) 120 | }) 121 | }) 122 | 123 | describe('and the providers param is [\'viacep\']', () => { 124 | it('should call only viacep service', () => { 125 | const correiosMock = nock('https://apps.correios.com.br') 126 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 127 | .replyWithFile( 128 | 200, 129 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 130 | ) 131 | 132 | const correiosAltMock = nock('https://buscacepinter.correios.com.br') 133 | .post('/app/endereco/carrega-cep-endereco.php') 134 | .replyWithFile( 135 | 200, 136 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 137 | ) 138 | 139 | const viaCepMock = nock('https://viacep.com.br') 140 | .get('/ws/05010000/json/') 141 | .replyWithFile( 142 | 200, 143 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 144 | ) 145 | 146 | const wideNetMock = nock('https://cdn.apicep.com') 147 | .get('/file/apicep/05010-000.json') 148 | .replyWithFile( 149 | 200, 150 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 151 | ) 152 | 153 | return cep('05010000', { providers: ['viacep'] }) 154 | .then(address => { 155 | expect(address).to.deep.equal({ 156 | cep: '05010000', 157 | state: 'SP', 158 | city: 'São Paulo', 159 | neighborhood: 'Perdizes', 160 | street: 'Rua Caiubi', 161 | service: 'viacep' 162 | }) 163 | 164 | expect(viaCepMock.isDone()).to.be.equal(true) 165 | expect(correiosMock.isDone()).to.be.equal(false) 166 | expect(correiosAltMock.isDone()).to.be.equal(false) 167 | expect(wideNetMock.isDone()).to.be.equal(false) 168 | }) 169 | }) 170 | }) 171 | 172 | describe('and the providers param is [\'widenet\']', () => { 173 | it('should call only widenet service', () => { 174 | const correiosMock = nock('https://apps.correios.com.br') 175 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 176 | .replyWithFile( 177 | 200, 178 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 179 | ) 180 | 181 | const correiosAltMock = nock('https://buscacepinter.correios.com.br') 182 | .post('/app/endereco/carrega-cep-endereco.php') 183 | .replyWithFile( 184 | 200, 185 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 186 | ) 187 | 188 | const viaCepMock = nock('https://viacep.com.br') 189 | .get('/ws/05010000/json/') 190 | .replyWithFile( 191 | 200, 192 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 193 | ) 194 | 195 | const wideNetMock = nock('https://cdn.apicep.com') 196 | .get('/file/apicep/05010-000.json') 197 | .replyWithFile( 198 | 200, 199 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 200 | ) 201 | 202 | return cep('05010000', { providers: ['widenet'] }) 203 | .then(address => { 204 | expect(address).to.deep.equal({ 205 | cep: '05010000', 206 | state: 'SP', 207 | city: 'São Paulo', 208 | neighborhood: 'Perdizes', 209 | street: 'Rua Caiubi', 210 | service: 'widenet' 211 | }) 212 | 213 | expect(wideNetMock.isDone()).to.be.equal(true) 214 | expect(viaCepMock.isDone()).to.be.equal(false) 215 | expect(correiosMock.isDone()).to.be.equal(false) 216 | expect(correiosAltMock.isDone()).to.be.equal(false) 217 | }) 218 | }) 219 | }) 220 | 221 | describe('and the providers param is [\'correios\']', () => { 222 | it('should call only correios service', () => { 223 | const correiosMock = nock('https://apps.correios.com.br') 224 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 225 | .replyWithFile( 226 | 200, 227 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 228 | ) 229 | 230 | const correiosAltMock = nock('https://buscacepinter.correios.com.br') 231 | .post('/app/endereco/carrega-cep-endereco.php') 232 | .replyWithFile( 233 | 200, 234 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 235 | ) 236 | 237 | const viaCepMock = nock('https://viacep.com.br') 238 | .get('/ws/05010000/json/') 239 | .replyWithFile( 240 | 200, 241 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 242 | ) 243 | 244 | const wideNetMock = nock('https://cdn.apicep.com') 245 | .get('/file/apicep/05010-000.json') 246 | .replyWithFile( 247 | 200, 248 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 249 | ) 250 | 251 | return cep('05010000', { providers: ['correios'] }) 252 | .then(address => { 253 | expect(address).to.deep.equal({ 254 | cep: '05010000', 255 | state: 'SP', 256 | city: 'São Paulo', 257 | neighborhood: 'Perdizes', 258 | street: 'Rua Caiubi', 259 | service: 'correios' 260 | }) 261 | 262 | expect(correiosMock.isDone()).to.be.equal(true) 263 | expect(correiosAltMock.isDone()).to.be.equal(false) 264 | expect(viaCepMock.isDone()).to.be.equal(false) 265 | expect(wideNetMock.isDone()).to.be.equal(false) 266 | }) 267 | }) 268 | }) 269 | 270 | describe('and the providers param is [\'correios-alt\']', () => { 271 | it('should call only correios service', () => { 272 | const correiosMock = nock('https://apps.correios.com.br') 273 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 274 | .replyWithFile( 275 | 200, 276 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 277 | ) 278 | 279 | const correiosAltMock = nock('https://buscacepinter.correios.com.br') 280 | .post('/app/endereco/carrega-cep-endereco.php') 281 | .replyWithFile( 282 | 200, 283 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 284 | ) 285 | 286 | const viaCepMock = nock('https://viacep.com.br') 287 | .get('/ws/05010000/json/') 288 | .replyWithFile( 289 | 200, 290 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 291 | ) 292 | 293 | const wideNetMock = nock('https://cep.widenet.host') 294 | .get('/file/apicep/05010-000.json') 295 | .replyWithFile( 296 | 200, 297 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 298 | ) 299 | 300 | return cep('05010000', { providers: ['correios-alt']}) 301 | .then(address => { 302 | expect(address).to.deep.equal({ 303 | cep: '05010000', 304 | state: 'SP', 305 | city: 'São Paulo', 306 | neighborhood: 'Perdizes', 307 | street: 'Rua Caiubi', 308 | service: 'correios-alt' 309 | }) 310 | 311 | expect(correiosMock.isDone()).to.be.equal(false) 312 | expect(correiosAltMock.isDone()).to.be.equal(true) 313 | expect(viaCepMock.isDone()).to.be.equal(false) 314 | expect(wideNetMock.isDone()).to.be.equal(false) 315 | }) 316 | }) 317 | }) 318 | 319 | describe('and the providers param is [\'brasilapi\']', () => { 320 | it('should call only brasilapi service', () => { 321 | const correiosMock = nock('https://apps.correios.com.br') 322 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 323 | .replyWithFile( 324 | 200, 325 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 326 | ) 327 | 328 | const correiosAltMock = nock('https://buscacepinter.correios.com.br') 329 | .post('/app/endereco/carrega-cep-endereco.php') 330 | .replyWithFile( 331 | 200, 332 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 333 | ) 334 | 335 | const viaCepMock = nock('https://viacep.com.br') 336 | .get('/ws/05010000/json/') 337 | .replyWithFile( 338 | 200, 339 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 340 | ) 341 | 342 | const wideNetMock = nock('https://cdn.apicep.com') 343 | .get('/file/apicep/05010-000.json') 344 | .replyWithFile( 345 | 200, 346 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 347 | ) 348 | 349 | const brasilAPIMock = nock('https://brasilapi.com.br/') 350 | .get('/api/cep/v1/05010000') 351 | .replyWithFile( 352 | 200, 353 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 354 | ) 355 | 356 | return cep('05010000', { providers: ['brasilapi'] }) 357 | .then(address => { 358 | expect(address).to.deep.equal({ 359 | cep: '05010000', 360 | state: 'SP', 361 | city: 'São Paulo', 362 | neighborhood: 'Perdizes', 363 | street: 'Rua Caiubi', 364 | service: 'brasilapi' 365 | }) 366 | 367 | expect(correiosMock.isDone()).to.be.equal(false) 368 | expect(correiosAltMock.isDone()).to.be.equal(false) 369 | expect(viaCepMock.isDone()).to.be.equal(false) 370 | expect(wideNetMock.isDone()).to.be.equal(false) 371 | expect(brasilAPIMock.isDone()).to.be.equal(true) 372 | }) 373 | }) 374 | }) 375 | 376 | describe('and the providers param is [\'correios, viacep\']', () => { 377 | it('should call only correios and viacep services', () => { 378 | const correiosMock = nock('https://apps.correios.com.br') 379 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 380 | .replyWithFile( 381 | 200, 382 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 383 | ) 384 | 385 | const correiosAltMock = nock('https://buscacepinter.correios.com.br') 386 | .post('/app/endereco/carrega-cep-endereco.php') 387 | .replyWithFile( 388 | 200, 389 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 390 | ) 391 | 392 | const viaCepMock = nock('https://viacep.com.br') 393 | .get('/ws/05010000/json/') 394 | .replyWithFile( 395 | 200, 396 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 397 | ) 398 | 399 | const wideNetMock = nock('https://cdn.apicep.com') 400 | .get('/file/apicep/05010-000.json') 401 | .replyWithFile( 402 | 200, 403 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 404 | ) 405 | 406 | return cep('05010000', { providers: ['correios', 'viacep'] }) 407 | .then(address => { 408 | expect(address).to.deep.equal({ 409 | cep: '05010000', 410 | state: 'SP', 411 | city: 'São Paulo', 412 | neighborhood: 'Perdizes', 413 | street: 'Rua Caiubi', 414 | service: address.service 415 | }) 416 | 417 | expect(viaCepMock.isDone()).to.be.equal(true) 418 | expect(correiosMock.isDone()).to.be.equal(true) 419 | expect(correiosAltMock.isDone()).to.be.equal(false) 420 | expect(wideNetMock.isDone()).to.be.equal(false) 421 | }) 422 | }) 423 | }) 424 | 425 | describe('and the providers param is []', () => { 426 | it('should call all services', () => { 427 | const correiosMock = nock('https://apps.correios.com.br') 428 | .post('/SigepMasterJPA/AtendeClienteService/AtendeCliente') 429 | .replyWithFile( 430 | 200, 431 | path.join(__dirname, '/fixtures/response-cep-05010000-found.xml') 432 | ) 433 | 434 | const correiosAltMock = nock('https://buscacepinter.correios.com.br') 435 | .post('/app/endereco/carrega-cep-endereco.php') 436 | .replyWithFile( 437 | 200, 438 | path.join(__dirname, '/fixtures/correios-alt-cep-05010000-found.json') 439 | ) 440 | 441 | const viaCepMock = nock('https://viacep.com.br') 442 | .get('/ws/05010000/json/') 443 | .replyWithFile( 444 | 200, 445 | path.join(__dirname, '/fixtures/viacep-cep-05010000-found.json') 446 | ) 447 | 448 | const wideNetMock = nock('https://cdn.apicep.com') 449 | .get('/file/apicep/05010-000.json') 450 | .replyWithFile( 451 | 200, 452 | path.join(__dirname, '/fixtures/widenet-cep-05010000-found.json') 453 | ) 454 | 455 | return cep('05010000', { providers: [] }) 456 | .then(address => { 457 | expect(address).to.deep.equal({ 458 | cep: '05010000', 459 | state: 'SP', 460 | city: 'São Paulo', 461 | neighborhood: 'Perdizes', 462 | street: 'Rua Caiubi', 463 | service: address.service 464 | }) 465 | 466 | expect(viaCepMock.isDone()).to.be.equal(true) 467 | expect(correiosMock.isDone()).to.be.equal(true) 468 | expect(correiosAltMock.isDone()).to.be.equal(true) 469 | expect(wideNetMock.isDone()).to.be.equal(true) 470 | }) 471 | }) 472 | }) 473 | 474 | afterEach(() => { 475 | nock.cleanAll() 476 | }) 477 | }) 478 | -------------------------------------------------------------------------------- /test/unit/cep-promise-timeout.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import chai from 'chai' 4 | import chaiSubset from 'chai-subset' 5 | import nock from 'nock' 6 | import path from 'path' 7 | 8 | import cep from '../../src/cep-promise.js' 9 | import CepPromiseError from '../../src/errors/cep-promise.js' 10 | 11 | chai.use(chaiSubset) 12 | 13 | let expect = chai.expect 14 | 15 | describe('when invoked with timeout parameter', () => { 16 | before(() => { 17 | nock.disableNetConnect() 18 | }) 19 | 20 | describe('and the providers exceed the timeout', () => { 21 | it('should reject with "service_error"', () => { 22 | nock('https://brasilapi.com.br/') 23 | .get('/api/cep/v1/05010000') 24 | .delay(3) 25 | .replyWithFile( 26 | 200, 27 | path.join(__dirname, '/fixtures/brasilapi-cep-05010000-found.json') 28 | ) 29 | return cep('05010000', {timeout: 1, providers: ['brasilapi']}) 30 | .then(() => expect(true).to.be.equal(false)) 31 | .catch(error => { 32 | return expect(error) 33 | .to.be.an.instanceOf(CepPromiseError) 34 | .and.containSubset({ 35 | name: 'CepPromiseError', 36 | message: 'Todos os serviços de CEP retornaram erro.', 37 | type: 'service_error', 38 | errors: [ 39 | { 40 | message: 'Erro ao se conectar com o serviço BrasilAPI.', 41 | service: 'brasilapi' 42 | } 43 | ] 44 | }) 45 | }) 46 | 47 | }) 48 | }) 49 | 50 | afterEach(() => { 51 | nock.cleanAll() 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /test/unit/fixtures/brasilapi-cep-05010000-found.json: -------------------------------------------------------------------------------- 1 | { 2 | "cep": "05010000", 3 | "state": "SP", 4 | "city": "São Paulo", 5 | "neighborhood": "Perdizes", 6 | "street": "Rua Caiubi" 7 | } -------------------------------------------------------------------------------- /test/unit/fixtures/brasilapi-cep-99999999-error.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CepPromiseError", 3 | "message": "Todos os serviços de CEP retornaram erro.", 4 | "type": "service_error", 5 | "errors": [ 6 | { 7 | "name": "ServiceError", 8 | "message": "CEP INVÁLIDO", 9 | "service": "correios" 10 | }, 11 | { 12 | "name": "ServiceError", 13 | "message": "CEP não encontrado na base do ViaCEP.", 14 | "service": "viacep" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /test/unit/fixtures/cep-aberto-05010000-found.json: -------------------------------------------------------------------------------- 1 | { 2 | "altitude": null, 3 | "bairro": "Perdizes", 4 | "cep": "05010000", 5 | "latitude": null, 6 | "longitude": null, 7 | "logradouro": "Rua Caiubi", 8 | "cidade": "São Paulo", 9 | "ddd": 11, 10 | "ibge": "3550308", 11 | "estado": "SP" 12 | } -------------------------------------------------------------------------------- /test/unit/fixtures/cep-aberto-99999999-error.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /test/unit/fixtures/correios-alt-cep-05010000-found.json: -------------------------------------------------------------------------------- 1 | { 2 | "erro": false, 3 | "mensagem": "DADOS LOCALIZADOS COM SUCESSO.", 4 | "total": 1, 5 | "dados": [ 6 | { 7 | "uf": "SP", 8 | "localidade": "São Paulo", 9 | "locNoSem": "", 10 | "locNu": "96681", 11 | "localidadeSubordinada": "", 12 | "logradouroDNEC": "Rua Caiubi", 13 | "logradouroTextoAdicional": "", 14 | "logradouroTexto": "", 15 | "bairro": "Perdizes", 16 | "baiNu": "", 17 | "nomeUnidade": "", 18 | "cep": "05010000", 19 | "tipoCep": "2", 20 | "numeroLocalidade": "96681", 21 | "situacao": "", 22 | "faixasCaixaPostal": [], 23 | "faixasCep": [] 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /test/unit/fixtures/correios-alt-cep-99999999-error.json: -------------------------------------------------------------------------------- 1 | { 2 | "erro": false, 3 | "mensagem": "DADOS LOCALIZADOS COM SUCESSO.", 4 | "total": 1, 5 | "dados": [ 6 | { 7 | "uf": "", 8 | "localidade": "", 9 | "locNoSem": "", 10 | "locNu": "", 11 | "localidadeSubordinada": "", 12 | "logradouroDNEC": "O CEP 99999-999 NAO FOI ENCONTRADO", 13 | "logradouroTextoAdicional": "", 14 | "logradouroTexto": "", 15 | "bairro": "", 16 | "baiNu": "", 17 | "nomeUnidade": "", 18 | "cep": "", 19 | "tipoCep": "", 20 | "numeroLocalidade": "", 21 | "situacao": "", 22 | "faixasCaixaPostal": [], 23 | "faixasCep": [] 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /test/unit/fixtures/response-bad-xml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /test/unit/fixtures/response-cep-05010000-found.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Perdizes 6 | 05010000 7 | São Paulo 8 | 9 | 10 | Rua Caiubi 11 | 0 12 | SP 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/unit/fixtures/response-cep-invalid-format.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | soap:Server 5 | BUSCA DEFINIDA COMO EXATA, 0 CEP DEVE TER 8 DIGITOS 6 | 7 | BUSCA DEFINIDA COMO EXATA, 0 CEP DEVE TER 8 DIGITOS 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/unit/fixtures/response-cep-not-found.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | soap:Server 5 | CEP NAO ENCONTRADO 6 | 7 | CEP NAO ENCONTRADO 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/unit/fixtures/response-unknown-format.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9.7/10 5 | 9.2/10 6 | 5/5 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/unit/fixtures/viacep-cep-05010000-found.json: -------------------------------------------------------------------------------- 1 | { 2 | "cep": "05010-000", 3 | "logradouro": "Rua Caiubi", 4 | "complemento": "", 5 | "bairro": "Perdizes", 6 | "localidade": "São Paulo", 7 | "uf": "SP", 8 | "unidade": "", 9 | "ibge": "3550308", 10 | "gia": "1004" 11 | } -------------------------------------------------------------------------------- /test/unit/fixtures/viacep-cep-99999999-error.json: -------------------------------------------------------------------------------- 1 | { 2 | "erro": true 3 | } -------------------------------------------------------------------------------- /test/unit/fixtures/widenet-cep-05010000-found.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": 200, 3 | "ok": true, 4 | "code": "05010-000", 5 | "state": "SP", 6 | "city": "São Paulo", 7 | "district": "Perdizes", 8 | "address": "Rua Caiubi", 9 | "statusText": "ok" 10 | } 11 | -------------------------------------------------------------------------------- /test/unit/fixtures/widenet-cep-99999999-error.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": 404, 3 | "ok": false, 4 | "message": "CEP não encontrado", 5 | "statusText": "not_found" 6 | } 7 | --------------------------------------------------------------------------------