diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..db7fd04 --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["es2015"], + "plugins": ["babel-plugin-add-module-exports"] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..49ab08b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +charset = utf-8 + +[{package.json}] +indent_style = space +indent_size = 2 diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..901b593 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,9 @@ +{ + "node": true, + "mocha": true, + "esversion": 6, + "globalstrict": false, + "asi": true, + "curly": true, + "trailing": true +} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..2ee4664 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +dist +tests +.editorconfig +.jshintrc +.DS_Store diff --git a/LICENSE.md b/LICENSE.md index acb5a46..ea3131b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Gabriel Oliveira +Copyright (c) 2016 Gabriel Oliveira Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index beeec43..4ebaa9d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,276 @@ -# rastrear-pacote +# tracking-correios -Módulo para consultar o status do rastreio de pacotes do Correios. +Módulo para consulta do rastreio de pacotes do Correios. Consulta diretamento a API do Correios (SRO). + +## Instalação + +Requer `Node.js` e `npm` instalados. + +```sh +$ npm install --save tracking-correios +``` + +Depois importe no seu código: + +```js +// via require do Node.js +const TrackingCorreios = require('tracking-correios') + +// ou via ES6 +import TrackingCorreios from 'tracking-correios' +``` + +## Consulta de eventos do código de rastreio + +Para consultas de um único código: + +```js +// passando como string +TrackingCorreios.track( 'DU897123996BR' ) + .then(console.log) + +// ou como Array +TrackingCorreios.track( [ 'DU897123996BR' ] ) + .then(console.log) + +/* +{ + "numero":"DU897123996BR", + "sigla":"DU", + "nome":"ENCOMENDA E-SEDEX", + "categoria":"E-SEDEX", + "evento": [ { + "tipo":"BDE", + "status":"01", + "data":"12/12/2016", + "hora":"19:06", + "descricao":"Objeto entregue ao destinatário", + "recebedor":"", + "documento":"", + "comentario":"", + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "uf":"SP" + }, { ... }, { ... }, { ... } + ] +} +*/ +``` + +Exemplo de código válido, porém sem rastreio + +Para consultas de vários códigos simultâneos: + +```js +TrackingCorreios.track([ 'DU897123996BR', 'PN273603577BR', 'DU910139445BR' ]) + .then(console.log) + +/* +[ { numero: 'DU897123996BR', + sigla: 'DU', + nome: 'ENCOMENDA E-SEDEX', + categoria: 'E-SEDEX', + evento: [ {...}, [Object], [Object], [Object], [Object], [Object] ] }, + { numero: 'PN273603577BR', + sigla: 'PN', + nome: 'ENCOMENDA PAC (ETIQ LOGICA)', + categoria: 'ENCOMENDA PAC', + evento: [ [Object], [Object], [Object], [Object], [Object], [Object] ] }, + { numero: 'DU910139445BR', + sigla: 'DU', + nome: 'ENCOMENDA E-SEDEX', + categoria: 'E-SEDEX', + evento: [ [Object], [Object], [Object], [Object], [Object] ] } ] +*/ +``` + +O método `track` validará automaticamente os objetos, removendo os inválidos: + +```js +TrackingCorreios.track([ 'DU897123996BR', 'invalido' ]) + .then(console.log) + +/* +{ "numero":"DU897123996BR", + "sigla":"DU", + "nome":"ENCOMENDA E-SEDEX", + "categoria":"E-SEDEX", + "evento": [...] +} +*/ +``` + +Se não tiver nenhum objeto válido a Promise rejeitará com `TrackingError`: + +```js +TrackingCorreios.track('invalido') + .catch(console.log) + +/* +{ [TrackingError: Erro ao validar os objetos.] + name: 'TrackingError', + message: 'Erro ao validar os objetos.', + type: 'validation_error', + errors: + [ { message: 'Nenhum objeto válido para pesquisa.', + service: 'objects_validation' } ] } +*/ +``` + +O método `track` retorna uma Promise, portanto o tratamento de erros deve ser feito pelo `.catch`. Exemplo de API fora do ar: + +```js +TrackingCorreios.track('DU897123996BR') + .then(console.log) + .catch(console.log) + +/* +{ [TrackingError: Erro ao se conectar ao o serviço dos Correios.] + name: 'TrackingError', + message: 'Erro ao se conectar com o serviço dos Correios.', + type: 'system', + errors: + [ { message: 'Ocorreu um erro ao se conectar ao serviço dos Correios: request to https://webservice.correios.com.br/service/rastro failed, reason: connect ECONNREFUSED webservice.correios.com.br', + service: 'service_error' } ] } +*/ +``` + +Pode também passar um objeto de configuração como segundo parâmetro. + +```js +// Valores padrão: +TrackingCorreios.track('DU897123996BR', { + username: undefined, + password: undefined, + type: "L", + result: "T", + language: "101", + limit: 5000 + }) +``` + +Os parâmetros `username`, `password`, `type`, `result` e `language` serão enviados a API dos Correios. + +O parâmetro `limit` indica a quantidade máxima de objetos a ser enviado por requisição. Se passar 8 mil objetos e o limite for 5 mil, o módulo fará duas requisições. Se passar mil objetos e o limite for 1, fará mil requisições. + +As requisições não são paralelas, serão realizadas uma após a outra. A Promise só resolverá quando todas as requisições terminarem. + +## Validação de objetos + +Esse módulo expõe três métodos auxiliares para validação de objetos. + +* `isValid`: verifica se o tracking é válido seguindo as regras do Correios. +* `filter`: retorna somente os objetos válidos. +* `validate`: retorna um objeto com os itens válidos e inválidos. + +Exemplos: + +`isValid`: + +```js +TrackingCorreios.isValid('DU897123996BR') +> true + +TrackingCorreios.isValid(['DU897123996BR']) +> false + +TrackingCorreios.isValid('AAAAA') +> false + +TrackingCorreios.isValid() +> false +``` + +Verifica um único objeto por vez. Valida as iniciais também com as conhecidas do correios (veja [category](#categoria-do-objeto)). Retorna um `boolean`. + +------------ + +`filter`: + +```js +TrackingCorreios.filter( 'DU897123996BR' ) +> [ 'DU897123996BR' ] + +TrackingCorreios.filter( [ 'DU897123996BR' ] ) +> [ 'DU897123996BR' ] + +TrackingCorreios.filter( [ 'DU897123996BR', 'PN273603577BR', 'DU910139445BR' ] ) +> [ 'DU897123996BR', 'PN273603577BR', 'DU910139445BR' ] + +TrackingCorreios.filter([ 'DU897123996BR', 'invalid' ]) +> [ 'DU897123996BR' ] + +TrackingCorreios.filter([ 'invalid', 'AAAA' ]) +> [ ] + +TrackingCorreios.filter( { } ) +> [ ] +``` + +Sempre retornará um Array, independente se houver ou não itens válidos. + +------------ + +`validate`: + +```js +TrackingCorreios.validate( 'DU897123996BR' ) +> { valid: [ 'DU897123996BR' ], invalid: [ ] } + +TrackingCorreios.validate( [ 'DU897123996BR' ] ) +> { valid: [ 'DU897123996BR' ], invalid: [ ] } + +TrackingCorreios.validate( [ 'DU897123996BR', 'PN273603577BR', 'DU910139445BR' ] ) +> { + valid: [ 'DU897123996BR', 'PN273603577BR', 'DU910139445BR' ], + invalid: [ ] + } + +TrackingCorreios.validate([ 'DU897123996BR', 'invalid' ]) +> { + valid: [ 'DU897123996BR' ], + invalid: [ 'invalid' ] + } + +TrackingCorreios.validate([ 'invalid', 'AAAA' ]) +> { + valid: [ ], + invalid: [ 'invalid', 'AAAA' ] + } + +TrackingCorreios.validate( { } ) +> { + valid: [ ], + invalid: [ { } ] + } +``` + +Sempre retornará um objeto com os campos `valid` e `invalid`. + +## Categoria do Objeto + +O módulo expõe um método para retornar a categoria do objeto: `category`. Exemplo: + +```js +TrackingCorreios.category('DU897123996BR') +> 'e-SEDEX' + +TrackingCorreios.category(['PN273603577BR']) +> 'PAC' + +TrackingCorreios.category(['AA123123123BR']) +> undefined + +TrackingCorreios.category('AAAAA') +> undefined + +TrackingCorreios.category() +> undefined +``` + +Se não for um código de rastreio válido, retornará `undefined`. + +# Inspiração + +Arquitetura inspirada no módulo [cep-promise](https://github.com/filipedeschamps/cep-promise) de Filipe Deschamps. Queria aprender mais sobre encadeamento de Promises, funções pequenas e vários outros assuntos que ele aborda [nesse vídeo](https://www.youtube.com/watch?v=gB5Gej0O400), por isso decidi desenvolver esse módulo. diff --git a/package.json b/package.json new file mode 100644 index 0000000..967a3b0 --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "tracking-correios", + "version": "1.0.0", + "description": "Módulo para consulta do rastreio de pacotes do Correios", + "main": "dist/track.js", + "scripts": { + "test": "npm run test-unit && npm run test-e2e", + "test-e2e": "mocha tests/e2e/*.spec.js --timeout 15000", + "test-unit": "mocha tests/unit/*.spec.js", + "build": "babel src --out-dir dist", + "prepublish": "npm run build" + }, + "author": "Gabriel Oliveira", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/gabrielboliveira/tracking-correios.git" + }, + "bugs": { + "url": "https://github.com/gabrielboliveira/tracking-correios/issues" + }, + "dependencies": { + "bluebird": "^3.4.6", + "isomorphic-fetch": "^2.2.1", + "lodash.assignin": "^4.2.0", + "lodash.chunk": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.filter": "^4.6.0", + "lodash.flatten": "^4.4.0", + "lodash.get": "^4.4.2", + "xml2js": "^0.4.17" + }, + "devDependencies": { + "babel-cli": "^6.18.0", + "babel-plugin-add-module-exports": "^0.2.1", + "babel-preset-es2015": "^6.18.0", + "chai": "^3.5.0", + "chai-as-promised": "^6.0.0", + "chai-subset": "^1.3.0", + "mocha": "^3.2.0", + "nock": "^9.0.2" + } +} diff --git a/src/errors/tracking.js b/src/errors/tracking.js new file mode 100644 index 0000000..8896ad0 --- /dev/null +++ b/src/errors/tracking.js @@ -0,0 +1,11 @@ +function TrackingError (options = {}) { + this.name = 'TrackingError' + this.message = options.message + this.type = options.type + this.errors = options.errors +} + +TrackingError.prototype = Object.create(Error.prototype) +TrackingError.prototype.constructor = TrackingError + +module.exports = TrackingError diff --git a/src/services/correios.js b/src/services/correios.js new file mode 100644 index 0000000..9582462 --- /dev/null +++ b/src/services/correios.js @@ -0,0 +1,164 @@ +'use strict' + +const Promise = require("bluebird") + +const fetch = require('isomorphic-fetch') +fetch.Promise = Promise + +const _extend = require('lodash.assignin') +const _get = require('lodash.get') +const _chunk = require('lodash.chunk') +const _flatten = require('lodash.flatten') + +const xml2js = require('xml2js') + +const Helpers = require('../utils/helpers') + +const TrackingError = require('../errors/tracking') + +const parseXMLString = xml2js.parseString + +const url = 'https://webservice.correios.com.br/service/rastro' + +function fetchTracking (objects, configParams) { + + return new Promise( (resolve, reject) => { + + Promise.resolve(objects) + .then(fetchFromCorreios) + .then(parseFetchOutput) + .then(resolvePromise) + .catch(rejectWithError) + + function fetchFromCorreios (objects) { + let callsChunked = _chunk(objects, configParams.limit) + + return Promise.map(callsChunked, fetchFromAPI) + } + + function fetchFromAPI (objects) { + const options = { + method: 'POST', + body: createSOAPEnvelope(objects), + mode: 'no-cors', + headers: { + 'Content-Type': 'text/xml; charset=utf-8', + 'cache-control': 'no-cache' + } + } + + return fetch(url, options) + } + + function parseFetchOutput(responses) { + return Promise.all(responses.map(parseSingleFetch)) + .then(mergeAllResponses) + } + + function mergeAllResponses (responses) { + return _flatten(responses) + } + + function parseSingleFetch (response) { + if (response.ok) { + return response.text() + .then(parseXML) + .then(extractSuccessObject) + } + + return response.text() + .then(parseXML) + .then(extractErrorObject) + .then(throwErrorObject) + } + + function parseXML (text) { + return new Promise( (resolve, reject) => { + parseXMLString(text, (err, object) => { + if(!err) { + resolve(object) + } else { + reject(new TrackingError({ + message: 'Não foi possível interpretar o XML de resposta.', + type: 'service_error', + errors: [{ + message: 'Ocorreu um erro ao tratar o XML retornado pela API dos Correios.', + service: 'parsing_error' + }] + })) + } + }) + }) + } + + function getSubObject (object, stringToSearch) { + return _get(object, stringToSearch).map(Helpers.expand) + } + + function extractSuccessObject (object) { + return getSubObject(object, 'soapenv:Envelope.soapenv:Body[0].ns2:buscaEventosListaResponse[0].return[0].objeto') + } + + function extractErrorObject (object) { + return getSubObject(object, 'soapenv:Envelope.soapenv:Body[0].soapenv:Fault[0].faultstring[0]') + } + + function throwErrorObject (faultString) { + throw new TrackingError({ + message: 'Erro no serviço do Correios.', + type: 'service_error', + errors: [{ + message: `O serviço do Correios retornou o seguinte erro: ${ faultString }`, + service: 'service_error' + }] + }) + } + + function createSOAPEnvelope (objects) { + let envelope = `\n\n \n \n \n` + + if(configParams.username && configParams.password) { + envelope += ` ${configParams.username}\n ${configParams.password}\n` + } + + envelope += ` ${ configParams.type }\n ${ configParams.result }\n ${ configParams.language }\n` + + objects.forEach((object) => { + envelope += ` ${ object }\n` + }) + + envelope += ` \n \n` + return envelope + } + + function resolvePromise (objects) { + if(objects && objects.length === 1) { + objects = objects[0] + } + resolve(objects) + } + + function rejectWithError (error = {}) { + const trackingError = new TrackingError({ + message: error.message, + type: error.type, + errors: error.errors + }) + + if (error.name === 'FetchError') { + trackingError.message = 'Erro ao se conectar ao o serviço dos Correios.' + trackingError.errors = [{ + message: `Ocorreu um erro ao se conectar ao serviço dos Correios: ${ error.message }`, + service: 'service_error' + }] + } + + reject(trackingError) + } + }) + +} + +module.exports = { + fetchTracking +} diff --git a/src/track.js b/src/track.js new file mode 100644 index 0000000..ed21330 --- /dev/null +++ b/src/track.js @@ -0,0 +1,120 @@ +'use strict' + +const Promise = require("bluebird") + +const _filter = require('lodash.filter') +const _extend = require('lodash.assignin') +const _difference = require('lodash.difference') + +const CorreiosAPI = require('./services/correios') + +const TrackingError = require('./errors/tracking') + +const TrackingHelpers = require('./utils/tracking-helpers') + +const Helpers = require('./utils/helpers') + +const MAX_OBJECTS_CORREIOS = 5000 + +function track (objects, configParams = {}) { + + // default params + configParams = _extend({ + username: undefined, + password: undefined, + type: "L", + result: "T", + language: "101", + limit: 5000 + }, configParams) + + return new Promise( (resolve, reject) => { + + Promise.resolve( { objects, configParams } ) + .then(validateParams) + .then(filterObjects) + .then(validateObjects) + .then(fetchFromCorreios) + .then(resolvePromise) + .catch(rejectWithError) + + function resolvePromise (objects) { + resolve(objects) + } + + function rejectWithError (error) { + reject(new TrackingError({ + message: error.message, + type: error.type, + errors: error.errors + })) + } + + function validateParams (params) { + if ( params.configParams.type && params.configParams.result && + params.configParams.language && params.configParams.limit > 0 && + params.configParams.limit <= MAX_OBJECTS_CORREIOS) + { + return params + } + + throw new TrackingError({ + message: 'Erro ao validar os parâmetros.', + type: 'validation_error', + errors: [{ + message: 'Type, result e language não podem ser undefined.', + service: 'param_validation' + }] + }) + } + + function filterObjects (params) { + params.objects = Helpers.arrayOf(params.objects) + + params.objects = filter(params.objects) + + return params + } + + function validateObjects (params) { + if (params.objects.length > 0) { + return params + } + + throw new TrackingError({ + message: 'Erro ao validar os objetos.', + type: 'validation_error', + errors: [{ + message: 'Nenhum objeto válido para pesquisa.', + service: 'objects_validation' + }] + }) + } + + function fetchFromCorreios (params) { + return CorreiosAPI.fetchTracking(params.objects, params.configParams) + } + }) +} + +function validate (objects) { + objects = Helpers.arrayOf(objects) + let filtered = filter (objects) + return { + valid: filtered, + invalid: _difference(objects, filtered) + } +} + +function filter (objects) { + objects = Helpers.arrayOf(objects) + return _filter (objects, TrackingHelpers.isValid) +} + +module.exports = { + track, + validate, + isValid: TrackingHelpers.isValid, + category: TrackingHelpers.category, + filter +} diff --git a/src/utils/helpers.js b/src/utils/helpers.js new file mode 100644 index 0000000..48a24b0 --- /dev/null +++ b/src/utils/helpers.js @@ -0,0 +1,31 @@ +function expand (item) { + if (Array.isArray(item)) { + if (item.length === 1) { + return expand(item[0]) + } + return item.map(expand) + } else if(isObject(item)) { + for(let key in item) { + item[key] = expand(item[key]) + } + } else if (isString(item)) { + item = item.trim() + } + return item +} + +function isObject (item) { + return item === Object(item) +} + +function isString (item) { + return typeof item === 'string' || item instanceof String +} + +function arrayOf (item) { + return Array.isArray(item) ? item : ( item !== undefined ? [ item ] : [] ) +} + +module.exports = { + expand, isObject, isString, arrayOf +} diff --git a/src/utils/tracking-helpers.js b/src/utils/tracking-helpers.js new file mode 100644 index 0000000..6328f8a --- /dev/null +++ b/src/utils/tracking-helpers.js @@ -0,0 +1,270 @@ +const Helpers = require('./helpers') + +const validInitials = { + 'AL': 'Agentes de leitura', + 'AR': 'Avisos de recebimento', + 'AS': 'PAC - Ação Social', + 'CA': 'Encomenda Internacional - Colis', + 'CB': 'Encomenda Internacional - Colis', + 'CC': 'Encomenda Internacional - Colis', + 'CD': 'Encomenda Internacional - Colis', + 'CE': 'Encomenda Internacional - Colis', + 'CF': 'Encomenda Internacional - Colis', + 'CG': 'Encomenda Internacional - Colis', + 'CH': 'Encomenda Internacional - Colis', + 'CI': 'Encomenda Internacional - Colis', + 'CJ': 'Encomenda Internacional - Colis', + 'CK': 'Encomenda Internacional - Colis', + 'CL': 'Encomenda Internacional - Colis', + 'CM': 'Encomenda Internacional - Colis', + 'CN': 'Encomenda Internacional - Colis', + 'CO': 'Encomenda Internacional - Colis', + 'CP': 'Encomenda Internacional - Colis', + 'CQ': 'Encomenda Internacional - Colis', + 'CR': 'Carta registrada sem Valor Declarado', + 'CS': 'Encomenda Internacional - Colis', + 'CT': 'Encomenda Internacional - Colis', + 'CU': 'Encomenda internacional - Colis', + 'CV': 'Encomenda Internacional - Colis', + 'CW': 'Encomenda Internacional - Colis', + 'CX': 'Encomenda internacional - Colis ou Selo Lacre para Caixetas', + 'CY': 'Encomenda Internacional - Colis', + 'CZ': 'Encomenda Internacional - Colis', + 'DA': 'SEDEX ou Remessa Expressa com AR Digital', + 'DB': 'SEDEX ou Remessa Expressa com AR Digital (Bradesco)', + 'DC': 'Remessa Expressa CRLV/CRV/CNH e Notificações', + 'DD': 'Devolução de documentos', + 'DE': 'Remessa Expressa Talão/Cartão com AR', + 'DF': 'e-SEDEX', + 'DG': 'SEDEX', + 'DI': 'SEDEX ou Remessa Expressa com AR Digital (Itaú)', + 'DJ': 'SEDEX', + 'DK': 'PAC Extra Grande', + 'DL': 'SEDEX', + 'DM': 'e-SEDEX', + 'DN': 'SEDEX', + 'DO': 'SEDEX ou Remessa Expressa com AR Digital (Itaú)', + 'DP': 'SEDEX Pagamento na Entrega', + 'DQ': 'SEDEX ou Remessa Expressa com AR Digital (Santander)', + 'DR': 'Remessa Expressa com AR Digital (Santander)', + 'DS': 'SEDEX ou Remessa Expressa com AR Digital (Santander)', + 'DT': 'Remessa econômica com AR Digital (DETRAN)', + 'DU': 'e-SEDEX', + 'DV': 'SEDEX c/ AR digital', + 'DW': 'Encomenda SEDEX (Etiqueta Lógica)', + 'DX': 'SEDEX 10', + 'EA': 'Encomenda Internacional - EMS', + 'EB': 'Encomenda Internacional - EMS', + 'EC': 'PAC', + 'ED': 'Packet Express', + 'EE': 'Encomenda Internacional - EMS', + 'EF': 'Encomenda Internacional - EMS', + 'EG': 'Encomenda Internacional - EMS', + 'EH': 'Encomenda Internacional - EMS ou Encomenda com AR Digital', + 'EI': 'Encomenda Internacional - EMS', + 'EJ': 'Encomenda Internacional - EMS', + 'EK': 'Encomenda Internacional - EMS', + 'EL': 'Encomenda Internacional - EMS', + 'EN': 'Encomenda Internacional - EMS', + 'EO': 'Encomenda Internacional - EMS', + 'EP': 'Encomenda Internacional - EMS', + 'EQ': 'Encomenda de serviço não expressa (ECT)', + 'ER': 'Objeto registrado', + 'ES': 'e-SEDEX ou EMS', + 'ET': 'Encomenda Internacional - EMS', + 'EU': 'Encomenda Internacional - EMS', + 'EV': 'Encomenda Internacional - EMS', + 'EW': 'Encomenda Internacional - EMS', + 'EX': 'Encomenda Internacional - EMS', + 'EY': 'Encomenda Internacional - EMS', + 'EZ': 'Encomenda Internacional - EMS', + 'FA': 'FAC registrado', + 'FE': 'Encomenda FNDE', + 'FF': 'Objeto registrado (DETRAN)', + 'FH': 'FAC registrado com AR Digital', + 'FM': 'FAC monitorado', + 'FR': 'FAC registrado', + 'IA': 'Logística Integrada (agendado / avulso)', + 'IC': 'Logística Integrada (a cobrar)', + 'ID': 'Logística Integrada (devolução de documento)', + 'IE': 'Logística Integrada (Especial)', + 'IF': 'CPF', + 'II': 'Logística Integrada (ECT)', + 'IK': 'Logística Integrada com Coleta Simultânea', + 'IM': 'Logística Integrada (Medicamentos)', + 'IN': 'Correspondência e EMS recebido do Exterior', + 'IP': 'Logística Integrada (Programada)', + 'IR': 'Impresso Registrado', + 'IS': 'Logística integrada standard (medicamentos)', + 'IT': 'Remessa Expressa Medicamentos / Logística Integrada Termolábil', + 'IU': 'Logística Integrada (urgente)', + 'IX': 'EDEI Expresso', + 'JA': 'Remessa econômica com AR Digital', + 'JB': 'Remessa econômica com AR Digital', + 'JC': 'Remessa econômica com AR Digital', + 'JD': 'Remessa econômica Talão/Cartão', + 'JE': 'Remessa econômica com AR Digital', + 'JF': 'Remessa econômica com AR Digital', + 'JG': 'Objeto registrado urgente/prioritário', + 'JH': 'Objeto registrado urgente / prioritário', + 'JI': 'Remessa econômica Talão/Cartão', + 'JJ': 'Objeto registrado (Justiça)', + 'JK': 'Remessa econômica Talão/Cartão', + 'JL': 'Objeto registrado', + 'JM': 'Mala Direta Postal Especial', + 'JN': 'Objeto registrado econômico', + 'JO': 'Objeto registrado urgente', + 'JP': 'Receita Federal', + 'JQ': 'Remessa econômica com AR Digital', + 'JR': 'Objeto registrado urgente / prioritário', + 'JS': 'Objeto registrado', + 'JT': 'Objeto Registrado Urgente', + 'JV': 'Remessa Econômica (c/ AR DIGITAL)', + 'LA': 'SEDEX com Logística Reversa Simultânea em Agência', + 'LB': 'e-SEDEX com Logística Reversa Simultânea em Agência', + 'LC': 'Objeto Internacional (Prime)', + 'LE': 'Logística Reversa Econômica', + 'LF': 'Objeto Internacional (Prime)', + 'LI': 'Objeto Internacional (Prime)', + 'LJ': 'Objeto Internacional (Prime)', + 'LK': 'Objeto Internacional (Prime)', + 'LM': 'Objeto Internacional (Prime)', + 'LN': 'Objeto Internacional (Prime)', + 'LP': 'PAC com Logística Reversa Simultânea em Agência', + 'LS': 'SEDEX Logística Reversa', + 'LV': 'Logística Reversa Expressa', + 'LX': 'Packet Standard / Econômica', + 'LZ': 'Objeto Internacional (Prime)', + 'MA': 'Serviços adicionais do Telegrama', + 'MB': 'Telegrama (balcão)', + 'MC': 'Telegrama (Fonado)', + 'MD': 'SEDEX Mundi (Documento interno)', + 'ME': 'Telegrama', + 'MF': 'Telegrama (Fonado)', + 'MK': 'Telegrama (corporativo)', + 'ML': 'Fecha Malas (Rabicho)', + 'MM': 'Telegrama (Grandes clientes)', + 'MP': 'Telegrama (Pré-pago)', + 'MR': 'AR digital', + 'MS': 'Encomenda Saúde', + 'MT': 'Telegrama (Telemail)', + 'MY': 'Telegrama internacional (entrante)', + 'MZ': 'Telegrama (Correios Online)', + 'NE': 'Tele Sena resgatada', + 'NX': 'EDEI Econômico (não urgente)', + 'PA': 'Passaporte', + 'PB': 'PAC', + 'PC': 'PAC a Cobrar', + 'PD': 'PAC', + 'PE': 'PAC', + 'PF': 'Passaporte', + 'PG': 'PAC', + 'PH': 'PAC', + 'PI': 'PAC', + 'PJ': 'PAC', + 'PK': 'PAC Extra Grande', + 'PL': 'PAC', + 'PN': 'PAC', + 'PR': 'Reembolso Postal', + 'QQ': 'Objeto de teste (SIGEP Web)', + 'RA': 'Objeto registrado / prioritário', + 'RB': 'Carta registrada', + 'RC': 'Carta registrada com Valor Declarado', + 'RD': 'Remessa econômica ou objeto registrado (DETRAN)', + 'RE': 'Objeto registrado econômico', + 'RF': 'Receita Federal', + 'RG': 'Objeto registrado', + 'RH': 'Objeto registrado com AR Digital', + 'RI': 'Objeto registrado internacional prioritário', + 'RJ': 'Objeto registrado', + 'RK': 'Objeto registrado', + 'RL': 'Objeto registrado', + 'RM': 'Objeto registrado urgente', + 'RN': 'Objeto registrado (SIGEPWEB ou Agência)', + 'RO': 'Objeto registrado', + 'RP': 'Reembolso Postal', + 'RQ': 'Objeto registrado', + 'RR': 'Objeto registrado', + 'RS': 'Objeto registrado', + 'RT': 'Remessa econômica Talão/Cartão', + 'RU': 'Objeto registrado (ECT)', + 'RV': 'Remessa econômica CRLV/CRV/CNH e Notificações com AR Digital', + 'RW': 'Objeto internacional', + 'RX': 'Objeto internacional', + 'RY': 'Remessa econômica Talão/Cartão com AR Digital', + 'RZ': 'Objeto registrado', + 'SA': 'SEDEX', + 'SB': 'SEDEX 10', + 'SC': 'SEDEX a cobrar', + 'SD': 'SEDEX ou Remessa Expressa (DETRAN)', + 'SE': 'SEDEX', + 'SF': 'SEDEX', + 'SG': 'SEDEX', + 'SH': 'SEDEX com AR Digital / SEDEX ou AR Digital', + 'SI': 'SEDEX', + 'SJ': 'SEDEX Hoje', + 'SK': 'SEDEX', + 'SL': 'SEDEX', + 'SM': 'SEDEX 12', + 'SN': 'SEDEX', + 'SO': 'SEDEX', + 'SP': 'SEDEX Pré-franqueado', + 'SQ': 'SEDEX', + 'SR': 'SEDEX', + 'SS': 'SEDEX', + 'ST': 'Remessa Expressa Talão/Cartão', + 'SU': 'Encomenda de serviço expressa (ECT)', + 'SV': 'Remessa Expressa CRLV/CRV/CNH e Notificações com AR Digital', + 'SW': 'e-SEDEX', + 'SX': 'SEDEX 10', + 'SY': 'Remessa Expressa Talão/Cartão com AR Digital', + 'SZ': 'SEDEX', + 'TC': 'Objeto para treinamento', + 'TE': 'Objeto para treinamento', + 'TS': 'Objeto para treinamento', + 'VA': 'Encomendas com valor declarado', + 'VC': 'Encomendas', + 'VD': 'Encomendas com valor declarado', + 'VE': 'Encomendas', + 'VF': 'Encomendas com valor declarado', + 'VV': 'Objeto internacional', + 'XA': 'Aviso de chegada (internacional)', + 'XM': 'SEDEX Mundi', + 'XR': 'Encomenda SUR Postal Expresso', + 'XX': 'Encomenda SUR Postal 24 horas' +} + +function matchesPattern (object) { + return /^([A-Z]{2}[0-9]{9}[A-Z]{2}){1}$/.test(object) +} + +function category(object) { + if ( !matchesPattern(object) || !Helpers.isString(object) ) { + return undefined + } + let initials = object.substr(0, 2) + let objectCategory + switch (initials) { + + case 'EM': + let final = object.substr(object.length - 2, 2) + objectCategory = "Encomenda Internacional - EMS Importação" + if (final === "BR") { + objectCategory = "Encomenda Internacional - SEDEX Mundi" + } + break + + default: + objectCategory = validInitials[initials] + + } + return objectCategory +} + +function isValid (object) { + return category(object) !== undefined +} + +module.exports = { + category, isValid +} diff --git a/tests/e2e/track.spec.js b/tests/e2e/track.spec.js new file mode 100644 index 0000000..b793abc --- /dev/null +++ b/tests/e2e/track.spec.js @@ -0,0 +1,86 @@ +'use strict' + +const chai = require('chai') +const chaiAsPromised = require('chai-as-promised') +const chaiSubset = require('chai-subset') + +const Tracking = require('../../src/track') +const TrackingError = require('../../src/errors/tracking') + +chai.use(chaiAsPromised) +chai.use(chaiSubset) + +const expect = chai.expect + +describe('tracking-correios (E2E)', () => { + + describe('when invoked with valid tracking number', () => { + describe('with one', () => { + let testFile = require('../responses/valid-one.json') + it('should fulfill with correct tracking information (string)', (done) => { + expect(Tracking.track('DU897123996BR')).to.eventually.deep.equal(testFile).notify(done) + }) + it('should fulfill with correct tracking information (array)', (done) => { + expect(Tracking.track(['DU897123996BR'])).to.eventually.deep.equal(testFile).notify(done) + }) + }) + + describe('with "n"', () => { + let testFile = require('../responses/valid-two.json') + it('should fulfill with correct tracking information', (done) => { + expect(Tracking.track(['DU897123996BR', 'PN273603577BR'])).to.eventually.deep.equal(testFile).notify(done) + }) + }) + }) + + describe('when invoked with invalid tracking number', () => { + it('should reject with a validation_error type with empty call', () => { + return Tracking.track() + .catch((error) => { + return expect(error) + .to.be.an.instanceOf(TrackingError) + .and.containSubset({ + name: 'TrackingError', + message: 'Erro ao validar os objetos.', + type: 'validation_error', + errors: [{ + message: 'Nenhum objeto válido para pesquisa.', + service: 'objects_validation' + }] + }) + }) + }) + it('should reject with a validation_error type (one)', () => { + return Tracking.track(['AB123123ABCBR']) + .catch((error) => { + return expect(error) + .to.be.an.instanceOf(TrackingError) + .and.containSubset({ + name: 'TrackingError', + message: 'Erro ao validar os objetos.', + type: 'validation_error', + errors: [{ + message: 'Nenhum objeto válido para pesquisa.', + service: 'objects_validation' + }] + }) + }) + }) + it('should reject with a validation_error type (several)', () => { + return Tracking.track(['AB123123ABCBR', 'ABCD', '123123123', 'BR', '%$@!$!', 'AB1231234564BR', 'ABR123123123BR', 'AB231234564ABB']) + .catch((error) => { + return expect(error) + .to.be.an.instanceOf(TrackingError) + .and.containSubset({ + name: 'TrackingError', + message: 'Erro ao validar os objetos.', + type: 'validation_error', + errors: [{ + message: 'Nenhum objeto válido para pesquisa.', + service: 'objects_validation' + }] + }) + }) + }) + }) +}) diff --git a/tests/responses/valid-one.json b/tests/responses/valid-one.json new file mode 100644 index 0000000..d7f3556 --- /dev/null +++ b/tests/responses/valid-one.json @@ -0,0 +1,99 @@ +{ + "numero":"DU897123996BR", + "sigla":"DU", + "nome":"ENCOMENDA E-SEDEX", + "categoria":"E-SEDEX", + "evento":[ + { + "tipo":"BDE", + "status":"01", + "data":"12/12/2016", + "hora":"19:06", + "descricao":"Objeto entregue ao destinatário", + "recebedor":"", + "documento":"", + "comentario":"", + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "uf":"SP" + }, + { + "tipo":"OEC", + "status":"01", + "data":"12/12/2016", + "hora":"10:30", + "descricao":"Objeto saiu para entrega ao destinatário", + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "uf":"SP" + }, + { + "tipo":"RO", + "status":"01", + "data":"12/12/2016", + "hora":"04:34", + "descricao":"Objeto encaminhado", + "local":"CTCE BAURU", + "codigo":"17034970", + "cidade":"Bauru", + "uf":"SP", + "destino":{ + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "bairro":"Distrito Industrial", + "uf":"SP" + } + }, + { + "tipo":"RO", + "status":"01", + "data":"08/12/2016", + "hora":"21:13", + "descricao":"Objeto encaminhado", + "local":"CTCE LONDRINA", + "codigo":"86066970", + "cidade":"LONDRINA", + "uf":"PR", + "destino":{ + "local":"CTCE BAURU", + "codigo":"17034970", + "cidade":"Bauru", + "bairro":"Distrito Industrial", + "uf":"SP" + } + }, + { + "tipo":"RO", + "status":"01", + "data":"08/12/2016", + "hora":"13:37", + "descricao":"Objeto encaminhado", + "local":"AGF JARDIM ALVORADA", + "codigo":"87030981", + "cidade":"Maringa", + "uf":"PR", + "destino":{ + "local":"CTCE LONDRINA", + "codigo":"86066970", + "cidade":"LONDRINA", + "bairro":"JARDIM COLUMBIA", + "uf":"PR" + } + }, + { + "tipo":"PO", + "status":"09", + "data":"07/12/2016", + "hora":"17:37", + "descricao":"Objeto postado após o horário limite da agência", + "detalhe":"Objeto sujeito a encaminhamento no próximo dia útil", + "local":"AGF JARDIM ALVORADA", + "codigo":"87030981", + "cidade":"Maringa", + "uf":"PR" + } + ] +} diff --git a/tests/responses/valid-two.json b/tests/responses/valid-two.json new file mode 100644 index 0000000..e82a230 --- /dev/null +++ b/tests/responses/valid-two.json @@ -0,0 +1,199 @@ +[ + { + "numero":"DU897123996BR", + "sigla":"DU", + "nome":"ENCOMENDA E-SEDEX", + "categoria":"E-SEDEX", + "evento":[ + { + "tipo":"BDE", + "status":"01", + "data":"12/12/2016", + "hora":"19:06", + "descricao":"Objeto entregue ao destinatário", + "recebedor":"", + "documento":"", + "comentario":"", + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "uf":"SP" + }, + { + "tipo":"OEC", + "status":"01", + "data":"12/12/2016", + "hora":"10:30", + "descricao":"Objeto saiu para entrega ao destinatário", + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "uf":"SP" + }, + { + "tipo":"RO", + "status":"01", + "data":"12/12/2016", + "hora":"04:34", + "descricao":"Objeto encaminhado", + "local":"CTCE BAURU", + "codigo":"17034970", + "cidade":"Bauru", + "uf":"SP", + "destino":{ + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "bairro":"Distrito Industrial", + "uf":"SP" + } + }, + { + "tipo":"RO", + "status":"01", + "data":"08/12/2016", + "hora":"21:13", + "descricao":"Objeto encaminhado", + "local":"CTCE LONDRINA", + "codigo":"86066970", + "cidade":"LONDRINA", + "uf":"PR", + "destino":{ + "local":"CTCE BAURU", + "codigo":"17034970", + "cidade":"Bauru", + "bairro":"Distrito Industrial", + "uf":"SP" + } + }, + { + "tipo":"RO", + "status":"01", + "data":"08/12/2016", + "hora":"13:37", + "descricao":"Objeto encaminhado", + "local":"AGF JARDIM ALVORADA", + "codigo":"87030981", + "cidade":"Maringa", + "uf":"PR", + "destino":{ + "local":"CTCE LONDRINA", + "codigo":"86066970", + "cidade":"LONDRINA", + "bairro":"JARDIM COLUMBIA", + "uf":"PR" + } + }, + { + "tipo":"PO", + "status":"09", + "data":"07/12/2016", + "hora":"17:37", + "descricao":"Objeto postado após o horário limite da agência", + "detalhe":"Objeto sujeito a encaminhamento no próximo dia útil", + "local":"AGF JARDIM ALVORADA", + "codigo":"87030981", + "cidade":"Maringa", + "uf":"PR" + } + ] + }, + { + "numero":"PN273603577BR", + "sigla":"PN", + "nome":"ENCOMENDA PAC (ETIQ LOGICA)", + "categoria":"ENCOMENDA PAC", + "evento":[ + { + "tipo":"BDE", + "status":"01", + "data":"28/10/2016", + "hora":"18:24", + "descricao":"Objeto entregue ao destinatário", + "recebedor":"", + "documento":"", + "comentario":"", + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "uf":"SP" + }, + { + "tipo":"OEC", + "status":"01", + "data":"28/10/2016", + "hora":"11:29", + "descricao":"Objeto saiu para entrega ao destinatário", + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "uf":"SP" + }, + { + "tipo":"RO", + "status":"01", + "data":"27/10/2016", + "hora":"13:02", + "descricao":"Objeto encaminhado", + "local":"CTCE BAURU", + "codigo":"17034970", + "cidade":"Bauru", + "uf":"SP", + "destino":{ + "local":"CEE BAURU", + "codigo":"17034972", + "cidade":"Bauru", + "bairro":"Distrito Industrial", + "uf":"SP" + } + }, + { + "tipo":"DO", + "status":"01", + "data":"26/10/2016", + "hora":"19:08", + "descricao":"Objeto encaminhado", + "local":"AGF OZANAN", + "codigo":"13215971", + "cidade":"Jundiai", + "uf":"SP", + "destino":{ + "local":"CTE CAMPINAS", + "codigo":"13050971", + "cidade":"INDAIATUBA", + "bairro":"HELVETIA", + "uf":"SP" + } + }, + { + "tipo":"RO", + "status":"01", + "data":"26/10/2016", + "hora":"14:34", + "descricao":"Objeto encaminhado", + "local":"CTE CAMPINAS", + "codigo":"13050971", + "cidade":"INDAIATUBA", + "uf":"SP", + "destino":{ + "local":"CTCE BAURU", + "codigo":"17034970", + "cidade":"Bauru", + "bairro":"Distrito Industrial", + "uf":"SP" + } + }, + { + "tipo":"PO", + "status":"01", + "data":"25/10/2016", + "hora":"16:35", + "descricao":"Objeto postado", + "local":"AGF OZANAN", + "codigo":"13215971", + "cidade":"Jundiai", + "uf":"SP" + } + ] + } +] diff --git a/tests/unit/fixtures/response-valid-one.xml b/tests/unit/fixtures/response-valid-one.xml new file mode 100644 index 0000000..2deffa1 --- /dev/null +++ b/tests/unit/fixtures/response-valid-one.xml @@ -0,0 +1,110 @@ + + + pid=36263,requestid=2cb01ac165f9c688f949b4a985e0531286a43f3af2e7fbe9 + + + + + 2.0 + 1 + + DU897123996BR + DU + ENCOMENDA E-SEDEX + E-SEDEX + + BDE + 01 + 12/12/2016 + 19:06 + Objeto entregue ao destinatário + + + + CEE BAURU + 17034972 + Bauru + SP + + + OEC + 01 + 12/12/2016 + 10:30 + Objeto saiu para entrega ao destinatário + CEE BAURU + 17034972 + Bauru + SP + + + RO + 01 + 12/12/2016 + 04:34 + Objeto encaminhado + CTCE BAURU + 17034970 + Bauru + SP + + CEE BAURU + 17034972 + Bauru + Distrito Industrial + SP + + + + RO + 01 + 08/12/2016 + 21:13 + Objeto encaminhado + CTCE LONDRINA + 86066970 + LONDRINA + PR + + CTCE BAURU + 17034970 + Bauru + Distrito Industrial + SP + + + + RO + 01 + 08/12/2016 + 13:37 + Objeto encaminhado + AGF JARDIM ALVORADA + 87030981 + Maringa + PR + + CTCE LONDRINA + 86066970 + LONDRINA + JARDIM COLUMBIA + PR + + + + PO + 09 + 07/12/2016 + 17:37 + Objeto postado após o horário limite da agência + Objeto sujeito a encaminhamento no próximo dia útil + AGF JARDIM ALVORADA + 87030981 + Maringa + PR + + + + + + diff --git a/tests/unit/fixtures/response-valid-two.xml b/tests/unit/fixtures/response-valid-two.xml new file mode 100644 index 0000000..8f18a28 --- /dev/null +++ b/tests/unit/fixtures/response-valid-two.xml @@ -0,0 +1,206 @@ + + + pid=130635,requestid=abd12a3d40122ab62b34d9e70d5c29eecbe835bf7b91d67e + + + + + 2.0 + 2 + + DU897123996BR + DU + ENCOMENDA E-SEDEX + E-SEDEX + + BDE + 01 + 12/12/2016 + 19:06 + Objeto entregue ao destinatário + + + + CEE BAURU + 17034972 + Bauru + SP + + + OEC + 01 + 12/12/2016 + 10:30 + Objeto saiu para entrega ao destinatário + CEE BAURU + 17034972 + Bauru + SP + + + RO + 01 + 12/12/2016 + 04:34 + Objeto encaminhado + CTCE BAURU + 17034970 + Bauru + SP + + CEE BAURU + 17034972 + Bauru + Distrito Industrial + SP + + + + RO + 01 + 08/12/2016 + 21:13 + Objeto encaminhado + CTCE LONDRINA + 86066970 + LONDRINA + PR + + CTCE BAURU + 17034970 + Bauru + Distrito Industrial + SP + + + + RO + 01 + 08/12/2016 + 13:37 + Objeto encaminhado + AGF JARDIM ALVORADA + 87030981 + Maringa + PR + + CTCE LONDRINA + 86066970 + LONDRINA + JARDIM COLUMBIA + PR + + + + PO + 09 + 07/12/2016 + 17:37 + Objeto postado após o horário limite da agência + Objeto sujeito a encaminhamento no próximo dia útil + AGF JARDIM ALVORADA + 87030981 + Maringa + PR + + + + PN273603577BR + PN + ENCOMENDA PAC (ETIQ LOGICA) + ENCOMENDA PAC + + BDE + 01 + 28/10/2016 + 18:24 + Objeto entregue ao destinatário + + + + CEE BAURU + 17034972 + Bauru + SP + + + OEC + 01 + 28/10/2016 + 11:29 + Objeto saiu para entrega ao destinatário + CEE BAURU + 17034972 + Bauru + SP + + + RO + 01 + 27/10/2016 + 13:02 + Objeto encaminhado + CTCE BAURU + 17034970 + Bauru + SP + + CEE BAURU + 17034972 + Bauru + Distrito Industrial + SP + + + + DO + 01 + 26/10/2016 + 19:08 + Objeto encaminhado + AGF OZANAN + 13215971 + Jundiai + SP + + CTE CAMPINAS + 13050971 + INDAIATUBA + HELVETIA + SP + + + + RO + 01 + 26/10/2016 + 14:34 + Objeto encaminhado + CTE CAMPINAS + 13050971 + INDAIATUBA + SP + + CTCE BAURU + 17034970 + Bauru + Distrito Industrial + SP + + + + PO + 01 + 25/10/2016 + 16:35 + Objeto postado + AGF OZANAN + 13215971 + Jundiai + SP + + + + + + diff --git a/tests/unit/track.spec.js b/tests/unit/track.spec.js new file mode 100644 index 0000000..9d7990f --- /dev/null +++ b/tests/unit/track.spec.js @@ -0,0 +1,249 @@ +'use strict' + +const chai = require('chai') +const chaiAsPromised = require('chai-as-promised') +const chaiSubset = require('chai-subset') + +const nock = require('nock') +const path = require('path') + +const Tracking = require('../../src/track') +const TrackingError = require('../../src/errors/tracking') + +chai.use(chaiAsPromised) +chai.use(chaiSubset) + +const expect = chai.expect + +describe('tracking-correios (unit)', () => { + + describe('when imported', () => { + it('should return an object', () => { + expect(Tracking).to.be.a('object') + }) + it('should return a "track" method', () => { + expect(Tracking.track).to.be.a('function') + }) + it('should return a "validate" method', () => { + expect(Tracking.validate).to.be.a('function') + }) + it('should return a "isValid" method', () => { + expect(Tracking.isValid).to.be.a('function') + }) + it('should return a "filter" method', () => { + expect(Tracking.filter).to.be.a('function') + }) + }) + + describe('when "track" invoked', () => { + it('should return a Promise', () => { + nock('http://webservice.correios.com.br') + .post('/service/rastro') + .replyWithFile(200, path.join(__dirname, '/fixtures/response-valid-one.xml')) + + const trackingCorreios = Tracking.track('DU897123996BR') + expect(trackingCorreios.then).to.be.a('function') + expect(trackingCorreios.catch).to.be.a('function') + }) + + describe('with one valid tracking number', () => { + let testFile = require('../responses/valid-one.json') + it('should fulfill with correct tracking information using simple string', () => { + nock('http://webservice.correios.com.br') + .post('/service/rastro') + .replyWithFile(200, path.join(__dirname, '/fixtures/response-valid-one.xml')) + + return expect(Tracking.track('DU897123996BR')).to.eventually.deep.equal(testFile) + }) + it('should fulfill with correct tracking information using array', () => { + nock('http://webservice.correios.com.br') + .post('/service/rastro') + .replyWithFile(200, path.join(__dirname, '/fixtures/response-valid-one.xml')) + + return expect(Tracking.track(['DU897123996BR'])).to.eventually.deep.equal(testFile) + }) + }) + + describe('with two valid tracking numbers', () => { + let testFile = require('../responses/valid-two.json') + it('should fulfill with correct tracking information using array', () => { + nock('http://webservice.correios.com.br') + .post('/service/rastro') + .replyWithFile(200, path.join(__dirname, '/fixtures/response-valid-two.xml')) + + return expect(Tracking.track(['DU897123996BR', 'PN273603577BR'])).to.eventually.deep.equal(testFile) + }) + }) + }) + + describe('when "validate" invoked', () => { + it('should return an object', () => { + expect(Tracking.validate('DU897123996BR')).to.be.a('object') + }) + + describe('with no parameters', () => { + it('should return valid and invalid unfilled', () => { + return expect(Tracking.validate()) + .to.deep.equal({ + "valid": [], + "invalid": [] + }) + }) + }) + + describe('with empty string as parameter', () => { + it('should return valid and invalid unfilled', () => { + return expect(Tracking.validate("")) + .to.deep.equal({ + "valid": [], + "invalid": [""] + }) + }) + }) + + describe('with one valid tracking numbers', () => { + it('should return valid object filled and invalid unfilled (string)', () => { + return expect(Tracking.validate('DU897123996BR')) + .to.deep.equal({ + "valid": ['DU897123996BR'], + "invalid": [] + }) + }) + it('should return valid object filled and invalid unfilled (array)', () => { + return expect(Tracking.validate(['DU897123996BR'])) + .to.deep.equal({ + "valid": ['DU897123996BR'], + "invalid": [] + }) + }) + }) + + describe('with "n" valid tracking numbers', () => { + it('should return valid object filled and invalid unfilled', () => { + return expect(Tracking.validate(['DU897123996BR', 'PN273603577BR', 'PN306956971BR'])) + .to.deep.equal({ + "valid": ['DU897123996BR', 'PN273603577BR', 'PN306956971BR'], + "invalid": [] + }) + }) + }) + + describe('with 1 valid and 1 invalid tracking numbers', () => { + it('should return valid object filled with valid and invalid filled with invalid', () => { + return expect(Tracking.validate(['DU897123996BR', 'ABC' ])) + .to.deep.equal({ + "valid": ['DU897123996BR'], + "invalid": ['ABC'] + }) + }) + }) + + describe('with "n" valid and 1 invalid tracking numbers', () => { + it('should return valid object filled with valid and invalid filled with invalid', () => { + return expect(Tracking.validate(['DU897123996BR', 'PN273603577BR', 'PN306956971BR', 'ABC' ])) + .to.deep.equal({ + "valid": ['DU897123996BR', 'PN273603577BR', 'PN306956971BR'], + "invalid": ['ABC'] + }) + }) + }) + + describe('with 1 valid and "n" invalid tracking numbers', () => { + it('should return valid object filled with valid and invalid filled with invalid', () => { + return expect(Tracking.validate(['DU897123996BR', 'AABBBCCCC', 'ASDQ@!#!%!123', 'ABC' ])) + .to.deep.equal({ + "valid": ['DU897123996BR'], + "invalid": ['AABBBCCCC', 'ASDQ@!#!%!123', 'ABC'] + }) + }) + }) + + describe('with "n" valid and "n" invalid tracking numbers', () => { + it('should return valid object filled with valid and invalid filled with invalid', () => { + return expect(Tracking.validate(['DU897123996BR', 'PN273603577BR', 'PN306956971BR', 'AABBBCCCC', 'ASDQ@!#!%!123', 'ABC' ])) + .to.deep.equal({ + "valid": ['DU897123996BR', 'PN273603577BR', 'PN306956971BR'], + "invalid": ['AABBBCCCC', 'ASDQ@!#!%!123', 'ABC'] + }) + }) + }) + }) + + describe('when "isValid" invoked', () => { + it('should return a boolean', () => { + expect(Tracking.isValid('DU897123996BR')).to.be.a('boolean') + }) + + describe('with empty value', () => { + it('should return false', () => { + expect(Tracking.isValid()) + .to.deep.equal(false) + }) + }) + + describe('with valid object', () => { + it('should return true', () => { + expect(Tracking.isValid('DU897123996BR')) + .to.deep.equal(true) + }) + }) + + describe('with invalid object (wrong initials)', () => { + it('should return false', () => { + expect(Tracking.isValid('AA123123123BR')) + .to.deep.equal(false) + }) + }) + + describe('with invalid object (wrong format)', () => { + it('should return false (simple)', () => { + expect(Tracking.isValid('AAAAA')) + .to.deep.equal(false) + }) + it('should return false (complex)', () => { + expect(Tracking.isValid('AAA123123123BR')) + .to.deep.equal(false) + }) + }) + + describe('with invalid object (not string)', () => { + it('should return false (array)', () => { + expect(Tracking.isValid([])) + .to.deep.equal(false) + }) + it('should return false (object)', () => { + expect(Tracking.isValid({})) + .to.deep.equal(false) + }) + }) + }) + + describe('when "filter" invoked', () => { + it('should return an array', () => { + expect(Tracking.filter('DU897123996BR')).to.be.a('array') + }) + + describe('with valid objects', () => { + it('should return array filled (one)', () => { + expect(Tracking.filter('DU897123996BR')) + .to.deep.equal(['DU897123996BR']) + }) + it('should return array filled ("n")', () => { + expect(Tracking.filter(['DU897123996BR', 'PN273603577BR', 'PN306956971BR'])) + .to.deep.equal(['DU897123996BR', 'PN273603577BR', 'PN306956971BR']) + }) + }) + + describe('with invalid objects', () => { + it('should return array unfilled (one)', () => { + expect(Tracking.filter('AAAAA')) + .to.deep.equal([]) + }) + it('should return array unfilled ("n")', () => { + expect(Tracking.filter(['AB123123ABCBR', 'ABCD', '123123123', 'BR', '%$@!$!', 'AB1231234564BR', 'ABR123123123BR', 'AB231234564ABB'])) + .to.deep.equal([]) + }) + }) + }) + +})