diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..fdd17efdc --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/node_modules +readme.md diff --git a/.tokens b/.tokens new file mode 100644 index 000000000..f8897f28d --- /dev/null +++ b/.tokens @@ -0,0 +1,2 @@ +xoxb-22472064529-JAIGuEXDPHAcHAJo0ibisUEY +xoxb-22472064529-JAIGuEXDPHAcHAJo0ibisUEY diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..26715583c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - 0.12.0 diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..b0f3127b5 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,23 @@ +--- +# Bug Report +--- +## Nature of bug +Choose an Email ? +_____ + +Choose a password +****** + +Describe why you want to register +____ +_____ + +Gender +male/female + +Which of these features will you need? +[+] simplicity +[-] Don't know +[-] complete + +[ok] \ No newline at end of file diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..fa07ea18f --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ +--- +# Issue Report +--- + +- [ ] a task list item +- [ ] list syntax required +- [ ] normal **formatting**, @mentions, #1234 refs +- [ ] incomplete +- [x] completed \ No newline at end of file diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..ac33ae1ce --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +node bot.js diff --git a/bot.js b/bot.js index 227944a9f..db9e310ae 100755 --- a/bot.js +++ b/bot.js @@ -63,6 +63,7 @@ This bot demonstrates many of the core features of Botkit: -> http://howdy.ai/botkit +Test line ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ @@ -73,6 +74,7 @@ if (!process.env.token) { var Botkit = require('./lib/Botkit.js'); var os = require('os'); +var botmath = require('./botmath.js'); var controller = Botkit.slackbot({ debug: true, @@ -88,7 +90,7 @@ controller.hears(['hello','hi'],'direct_message,direct_mention,mention',function bot.api.reactions.add({ timestamp: message.ts, channel: message.channel, - name: 'robot_face', + name: 'robot_face' },function(err, res) { if (err) { bot.botkit.log('Failed to add emoji reaction :(',err); @@ -121,6 +123,37 @@ controller.hears(['call me (.*)'],'direct_message,direct_mention,mention',functi }); }); +controller.hears(['prime (.*)'], 'direct_message,direct_mention,mention', function(bot, message) { + var matches = message.text.match(/prime (.*)/i); + var number = parseInt(matches[1]); + var primes = nextTenPrimes(number); + var primes = lastTenPrimes(number); + if (number >=0){ + if(isPrime(number)) { + bot.reply(message, 'number is a prime'); + } else { + + //bot.reply(message, 'number is not a prime, next 10 primes are ' + primes.toString()); + + bot.reply(message, 'number is not a prime, last 10 primes are ' + primes.toString()); + } + } + + + +}); + +controller.hears(['prime.'], 'direct_message,direct_mention,mention', function(bot, message) { + + var i = message.text.lastIndexOf('.'); + if (i != -1) { + bot.reply(message, '2, 3, 5, 7, 11, 13, 17, 19, 23, 29'); + + } +}); + + + controller.hears(['what is my name','who am i'],'direct_message,direct_mention,mention',function(bot, message) { controller.storage.users.get(message.user,function(err, user) { @@ -132,6 +165,16 @@ controller.hears(['what is my name','who am i'],'direct_message,direct_mention,m }); }); +controller.hears(['who made you'], 'direct_message,direct_mention,mention', function(bot, message) { + controller.storage.users.get(message.user,function(err, user) { + if (user && user.name) { + bot.reply(message,'You made me - master ' + user.name + '!!'); + } else { + bot.reply(message,'I don\'t know yet!.'); + } + }); +}); + controller.hears(['shutdown'],'direct_message,direct_mention,mention',function(bot, message) { @@ -169,6 +212,12 @@ controller.hears(['uptime','identify yourself','who are you','what is your name' }); +controller.hears(['how old are you'],'direct_message,direct_mention,mention',function(bot, message) { + + bot.reply(message,':robot_face: I am a bot named <@' + bot.identity.name + '>. I am ' + uptime + ' old'); + +}); + function formatUptime(uptime) { var unit = 'second'; if (uptime > 60) { @@ -186,3 +235,52 @@ function formatUptime(uptime) { uptime = uptime + ' ' + unit; return uptime; } + + +function isPrime(n) { + if (isNaN(n) || !isFinite(n) || n%1 || n<2) return false; + if (n%2==0) return (n==2); + var m=Math.sqrt(n); + for (var i=3;i<=m;i+=2) { + if (n%i==0) return false; + } + return true; +} + +function nextTenPrimes(n) { + var primes = []; + + do{ + if(isPrime(n)){ + primes.push(n); + } + n++; + }while(primes.length <10) + return primes; +} + +function lastTenPrimes(n) { + var primes = []; + + do{ + if(isPrime(n)){ + primes.push(n); + } + n--; + if(n < 1) break; + }while(primes.length <10) + return primes; +} + +controller.hears('what is (.*) \\+ (.*)',['direct_message', 'direct_mention', 'mention'],function(bot,message) { + + var num1 = message.match[1]; + var num2 = message.match[2]; + + if (num1 != null && num2 != null) { + return bot.reply(message, num1 + ' + ' + num2 + ' = ' + botmath.sum(num1, num2)); + } +}); + +module.exports.isPrime = isPrime; +module.exports.lastTenPrimes = lastTenPrimes; diff --git a/botmath.js b/botmath.js new file mode 100644 index 000000000..ec4c913da --- /dev/null +++ b/botmath.js @@ -0,0 +1,5 @@ +var sum = function (num1, num2) { + return parseFloat(num1) + parseFloat(num2); +} + +module.exports.sum = sum; \ No newline at end of file diff --git a/package.json b/package.json index 69a5959a8..c24644ad1 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "eventemitter2": "0.4.14", "express": "^4.13.3", "jfs": "^0.2.6", + "mocha": "^2.4.5", "mustache": "^2.2.1", "request": "^2.67.0", "ws": "^1.0.0" @@ -21,6 +22,9 @@ "tape": "^4.4.0", "winston": "^2.1.1" }, + "scripts": { + "test": "mocha tests/*.js" + }, "repository": { "type": "git", "url": "https://github.com/juhovan/botkit.git" diff --git a/readme.md b/readme.md index 60fa8dc18..f5f11ea9c 100755 --- a/readme.md +++ b/readme.md @@ -45,7 +45,7 @@ npm install --production 2) First make a bot integration inside of your Slack channel. Go here: -https://my.slack.com/services/new/bot + Enter a name for your bot. Make it something fun and friendly, but avoid a single task specific name. diff --git a/tests/botmathTest.js b/tests/botmathTest.js new file mode 100644 index 000000000..908258c99 --- /dev/null +++ b/tests/botmathTest.js @@ -0,0 +1,16 @@ +var assert = require('assert'); +var bothmath = require('../botmath.js'); + +describe('botmath', function() { + describe('sum', function () { + it('should return sum of 2 values', function () { + assert.equal(-2, bothmath.sum(-2, 0)); + assert.equal(1, bothmath.sum(-1, 2)); + assert.equal(6.5, bothmath.sum(3.5, 3)); + assert.equal(1337, bothmath.sum(1338.2, -1.2)); + }) + it('should return NaN if both values are not numeric', function () { + assert.ok(isNaN(bothmath.sum(1335, 'a'))); + }); + }); +}); diff --git a/tests/lastTenPrimesTest.js b/tests/lastTenPrimesTest.js new file mode 100644 index 000000000..2d4e4b17e --- /dev/null +++ b/tests/lastTenPrimesTest.js @@ -0,0 +1,15 @@ +/** + * Created by olegba on 24/02/16. + */ +var assert = require('assert'); +var bot = require('../bot.js'); +var lastTenPrimes = bot.lastTenPrimes; + + +describe('Is prime', function() { + it('should return an array of last ten prime numbers when the value is not a prime, or less then ten values', function () { + assert.deepEqual([19,17,13,11,7,5,3,2], lastTenPrimes(20)); + assert.deepEqual([31,29,23,19,17,13,11,7,5,3], lastTenPrimes(33)); + assert.deepEqual([], lastTenPrimes(1)); + }); +}); diff --git a/tests/primeTest.js b/tests/primeTest.js new file mode 100644 index 000000000..7742f34b4 --- /dev/null +++ b/tests/primeTest.js @@ -0,0 +1,15 @@ +/** + * Created by olegba on 23/02/16. + */ +var assert = require('assert'); +var bot = require('../bot.js'); +var isPrime = bot.isPrime; + + +describe('Is prime', function() { + it('should return false when the value is not a prime number or true if the number is prime', function () { + assert.equal(false, isPrime(8)); + assert.equal(true, isPrime(7)); + assert.equal(false, isPrime(0)); + }); +}); diff --git a/tests/test.js b/tests/test.js new file mode 100644 index 000000000..3adacb0da --- /dev/null +++ b/tests/test.js @@ -0,0 +1,10 @@ +var assert = require('assert'); + +describe('Array', function() { + describe('#indexOf()', function () { + it('should return -1 when the value is not present', function () { + assert.equal(-1, [1,2,3].indexOf(5)); + assert.equal(-1, [1,2,3].indexOf(0)); + }); + }); +}); diff --git a/text.txt b/text.txt new file mode 100644 index 000000000..07edee7f6 --- /dev/null +++ b/text.txt @@ -0,0 +1 @@ +Line of text \ No newline at end of file diff --git a/weather/.editorconfig b/weather/.editorconfig new file mode 100644 index 000000000..b966b3bb3 --- /dev/null +++ b/weather/.editorconfig @@ -0,0 +1,16 @@ +# See editorconfig.org + +root = true + +[*] + +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = false + +[*.md] + +trim_trailing_whitespace = false \ No newline at end of file diff --git a/weather/.gitattributes b/weather/.gitattributes new file mode 100644 index 000000000..6a0ab8be1 --- /dev/null +++ b/weather/.gitattributes @@ -0,0 +1,17 @@ +* text=auto + +*.png binary +*.jpg binary +*.gif binary +*.ico binary + +*.txt text +*.md text +*.html text +*.css text +*.js text +*.json text + +*.bat text +*.sh text +*.exe binary \ No newline at end of file diff --git a/weather/.gitignore b/weather/.gitignore new file mode 100644 index 000000000..b283d0045 --- /dev/null +++ b/weather/.gitignore @@ -0,0 +1,14 @@ +node_modules/ +npm-debug.log + +.DS_Store +.idea + +*.log +*.heapsnapshot +.coverrun +.coverdata +dump.rdb +xunit.xml + +sources/ \ No newline at end of file diff --git a/weather/.jshintrc b/weather/.jshintrc new file mode 100644 index 000000000..f1d07d58e --- /dev/null +++ b/weather/.jshintrc @@ -0,0 +1,28 @@ +{ + "node": true, + "browser": false, + "esnext": true, + "strict": true, + "unused": true, + "undef": true, + "quotmark": "single", + "indent": 2, + "eqeqeq": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "sub": true, + + "globals": { + }, + + "predef": [ + "describe", + "it", + "before", + "beforeEach", + "after", + "afterEach" + ] +} \ No newline at end of file diff --git a/weather/.travis.yml b/weather/.travis.yml new file mode 100644 index 000000000..b5b40f730 --- /dev/null +++ b/weather/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "0.12" + - "0.10" + - "iojs" \ No newline at end of file diff --git a/weather/CHANGELOG.md b/weather/CHANGELOG.md new file mode 100644 index 000000000..87469cb01 --- /dev/null +++ b/weather/CHANGELOG.md @@ -0,0 +1,21 @@ +## Changelog + +### 1.0.2 (2015-03-15) + +* Misc. updates + +### 1.0.1 (2014-12-12) + +* Change request url + +### 1.0.0 (2014-07-04) + +* Stable release + +### 0.1.1 (2014-06-05) + +* Add image url + +### 0.1.0 (2014-06-04) + +* Initial release \ No newline at end of file diff --git a/weather/LICENSE.txt b/weather/LICENSE.txt new file mode 100644 index 000000000..798227937 --- /dev/null +++ b/weather/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Fatih Cetinkaya (http://github.com/cmfatih/weather) + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/weather/README.md b/weather/README.md new file mode 100644 index 000000000..349152ecc --- /dev/null +++ b/weather/README.md @@ -0,0 +1,125 @@ +## Weather + +[![NPM][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] + +Weather is a module for obtaining weather information. + +### Installation + +``` +npm install weather-js +``` + +### Usage + +```javascript +var weather = require('weather-js'); + +// Options: +// search: location name or zipcode +// degreeType: F or C + +weather.find({search: 'San Francisco, CA', degreeType: 'F'}, function(err, result) { + if(err) console.log(err); + + console.log(JSON.stringify(result, null, 2)); +}); +/* +[ + { + "location": { + "name": "San Francisco, CA", + "zipcode": "94109", + "lat": "37.7835152", + "long": "-122.4169334", + "timezone": "-7", + "alert": "", + "degreetype": "F", + "imagerelativeurl": "http://wst.s-msn.com/i/en-us/" + }, + "current": { + "temperature": "65", + "skycode": "30", + "skytext": "Partly Cloudy", + "date": "2014-06-05", + "observationtime": "13:53:00", + "observationpoint": "Oakland, Metro Oakland International Airport", + "feelslike": "65", + "humidity": "63", + "winddisplay": "16 mph NW", + "day": "Thursday", + "shortday": "Thu", + "windspeed": "16", + "imageUrl": "http://wst.s-msn.com/i/en-us/law/30.gif" + }, + "forecast": [ + { + "low": "53", + "high": "66", + "skycodeday": "28", + "skytextday": "Mostly Cloudy", + "date": "2014-06-05", + "day": "Thursday", + "shortday": "Thu", + "precip": "0" + }, + { + "low": "53", + "high": "66", + "skycodeday": "30", + "skytextday": "Partly Cloudy", + "date": "2014-06-06", + "day": "Friday", + "shortday": "Fri", + "precip": "0" + }, + { + "low": "54", + "high": "70", + "skycodeday": "30", + "skytextday": "Partly Cloudy", + "date": "2014-06-07", + "day": "Saturday", + "shortday": "Sat", + "precip": "0" + }, + { + "low": "54", + "high": "74", + "skycodeday": "34", + "skytextday": "Mostly Sunny", + "date": "2014-06-08", + "day": "Sunday", + "shortday": "Sun", + "precip": "0" + }, + { + "low": "54", + "high": "69", + "skycodeday": "30", + "skytextday": "Partly Cloudy", + "date": "2014-06-09", + "day": "Monday", + "shortday": "Mon", + "precip": "0" + } + ] + } +] +*/ +``` + +### Notes + +* It uses `weather.service.msn.com` + +### License + +Licensed under The MIT License (MIT) +For the full copyright and license information, please view the LICENSE.txt file. + +[npm-url]: http://npmjs.org/package/weather-js +[npm-image]: https://badge.fury.io/js/weather-js.png + +[travis-url]: https://travis-ci.org/cmfatih/weather +[travis-image]: https://travis-ci.org/cmfatih/weather.svg?branch=master \ No newline at end of file diff --git a/weather/lib/weather.js b/weather/lib/weather.js new file mode 100644 index 000000000..b7da87173 --- /dev/null +++ b/weather/lib/weather.js @@ -0,0 +1,115 @@ +/* + * Weather + * Copyright (c) 2014 Fatih Cetinkaya (http://github.com/cmfatih/weather) + * For the full copyright and license information, please view the LICENSE.txt file. + */ + +/* jslint node: true */ +'use strict'; + +var request = require('request'), + qs = require('querystring'), + xml2JS = require('xml2js'); + +// Init the module +exports = module.exports = (function() { + + var xmlParser = new xml2JS.Parser({charkey: 'C$', attrkey: 'A$', explicitArray: true}), + defLang = 'en-US', + defDegreeType = 'F', + defTimeout = 10000, + findUrl = 'http://weather.service.msn.com/find.aspx', + find; // finds and gets weather information - function + + find = function find(options, callback) { + + if(typeof callback !== 'function') + callback = function callback(err, result) { return err || result; }; + + if(!options || typeof options !== 'object') + return callback('Invalid options!'); + + if(!options.search) + return callback('Missing search input!'); + + var result, + lang = options.lang || defLang, + degreeType = options.degreeType || defDegreeType, + timeout = options.timeout || defTimeout, + search = qs.escape(''+options.search), + reqUrl = findUrl + '?src=outlook&weadegreetype=' + (''+degreeType) + '&culture=' + (''+lang) + '&weasearchstr=' + search; + + request.get({url: reqUrl, timeout: timeout}, function(err, res, body) { + + if(err) return callback(err); + if(res.statusCode !== 200) return callback('Request failed (' + res.statusCode + ')'); + + xmlParser.parseString(body, function(err, resultJSON) { + if(err) return callback(err); + + if(!resultJSON.weatherdata || !resultJSON.weatherdata.weather) + return callback('Unexpected error! Invalid content.'); + + if(resultJSON.weatherdata.weather['A$'] && resultJSON.weatherdata.weather['A$'].errormessage) + return callback(resultJSON.weatherdata.weather['A$'].errormessage); + + if(!(resultJSON.weatherdata.weather instanceof Array)) { + return callback('Unexpected error! Missing weather info.'); + } + + var weatherLen = resultJSON.weatherdata.weather.length, + weatherItem; + for(var i = 0; i < weatherLen; i++) { + + if(typeof resultJSON.weatherdata.weather[i]['A$'] !== 'object') + continue; + + weatherItem = { + location: { + name: resultJSON.weatherdata.weather[i]['A$']['weatherlocationname'], + zipcode: resultJSON.weatherdata.weather[i]['A$']['zipcode'], + lat: resultJSON.weatherdata.weather[i]['A$']['lat'], + long: resultJSON.weatherdata.weather[i]['A$']['long'], + timezone: resultJSON.weatherdata.weather[i]['A$']['timezone'], + alert: resultJSON.weatherdata.weather[i]['A$']['alert'], + degreetype: resultJSON.weatherdata.weather[i]['A$']['degreetype'], + imagerelativeurl: resultJSON.weatherdata.weather[i]['A$']['imagerelativeurl'] + //url: resultJSON.weatherdata.weather[i]['A$']['url'], + //code: resultJSON.weatherdata.weather[i]['A$']['weatherlocationcode'], + //entityid: resultJSON.weatherdata.weather[i]['A$']['entityid'], + //encodedlocationname: resultJSON.weatherdata.weather[i]['A$']['encodedlocationname'] + }, + current: null, + forecast: null + }; + + if(resultJSON.weatherdata.weather[i]['current'] instanceof Array && resultJSON.weatherdata.weather[i]['current'].length > 0) { + if(typeof resultJSON.weatherdata.weather[i]['current'][0]['A$'] === 'object') { + weatherItem.current = resultJSON.weatherdata.weather[i]['current'][0]['A$']; + + weatherItem.current.imageUrl = weatherItem.location.imagerelativeurl + 'law/' + weatherItem.current.skycode + '.gif'; + } + } + + if(resultJSON.weatherdata.weather[i]['forecast'] instanceof Array) { + weatherItem.forecast = []; + for(var k = 0; k < resultJSON.weatherdata.weather[i]['forecast'].length; k++) { + if(typeof resultJSON.weatherdata.weather[i]['forecast'][k]['A$'] === 'object') + weatherItem.forecast.push(resultJSON.weatherdata.weather[i]['forecast'][k]['A$']); + } + } + + if(!result) result = []; + result.push(weatherItem); + } + + return callback(undefined, result); + }); + }); + }; + + // Return + return { + find: find + }; +})(); \ No newline at end of file diff --git a/weather/package.json b/weather/package.json new file mode 100644 index 000000000..a1aabaa24 --- /dev/null +++ b/weather/package.json @@ -0,0 +1,39 @@ +{ + "name": "weather-js", + "version": "1.0.2", + "description": "Weather is a module for obtaining weather information.", + "keywords": [ + "weather", + "forecast" + ], + "homepage": "http://github.com/cmfatih/weather", + "repository": { + "type": "git", + "url": "https://github.com/cmfatih/weather.git" + }, + "bugs": { + "url": "http://github.com/cmfatih/weather/issues" + }, + "license": "MIT", + "private": false, + "author": { + "name": "cmfatih", + "url": "http://github.com/cmfatih" + }, + "contributors": [], + "main": "lib/weather.js", + "scripts": { + "test": "node node_modules/mocha/bin/mocha --reporter spec test/test-all.js" + }, + "engines": [ + "node >= 0.10.0" + ], + "dependencies": { + "request": "2.x", + "xml2js": "0.4.x" + }, + "devDependencies": { + "mocha": "2.2.x", + "chai": "2.1.x" + } +} \ No newline at end of file diff --git a/weather/test/test-all.js b/weather/test/test-all.js new file mode 100644 index 000000000..b97490119 --- /dev/null +++ b/weather/test/test-all.js @@ -0,0 +1,88 @@ +/* jslint node: true */ +/* global describe: false, it: false */ +'use strict'; + +var weather = require('../'), + expect = require('chai').expect; + +// Tests + +describe('weather', function() { + + // find + describe('find()', function() { + it('should find a location with weather information', function(done) { + weather.find({search: 'San Francisco, CA', degreeType: 'F'}, function(err, result) { + if(err) return done(err); + + expect(err).to.be.equal(undefined); + + expect(result).to.be.a('array'); + expect(result).to.have.property('length').to.be.equal(1); + expect(result[0]).to.be.a('object'); + + expect(result[0]).to.have.property('location').to.be.a('object'); + expect(result[0]['location']).to.have.property('name', 'San Francisco, CA'); + expect(result[0]['location']).to.have.property('zipcode', '94109'); + expect(result[0]['location']).to.have.property('lat', '37.7835152'); + expect(result[0]['location']).to.have.property('long', '-122.4169334'); + expect(result[0]['location']).to.have.property('timezone').to.be.a('string'); + expect(result[0]['location']).to.have.property('alert').to.be.a('string'); + expect(result[0]['location']).to.have.property('degreetype', 'F'); + expect(result[0]['location']).to.have.property('imagerelativeurl').to.be.a('string'); + + expect(result[0]).to.have.property('current').to.be.a('object'); + expect(result[0]['current']).to.have.property('temperature'); + expect(result[0]['current']).to.have.property('temperature'); + expect(result[0]['current']).to.have.property('temperature'); + expect(result[0]['current']).to.have.property('skycode'); + expect(result[0]['current']).to.have.property('skytext'); + expect(result[0]['current']).to.have.property('date'); + expect(result[0]['current']).to.have.property('observationtime'); + expect(result[0]['current']).to.have.property('observationpoint'); + expect(result[0]['current']).to.have.property('feelslike'); + expect(result[0]['current']).to.have.property('humidity'); + expect(result[0]['current']).to.have.property('winddisplay'); + expect(result[0]['current']).to.have.property('day'); + expect(result[0]['current']).to.have.property('shortday'); + expect(result[0]['current']).to.have.property('windspeed'); + expect(result[0]['current']).to.have.property('imageUrl'); + + expect(result[0]).to.have.property('forecast').to.be.a('array'); + expect(result[0]['forecast']).to.have.property('length').to.be.above(0); + expect(result[0]['forecast'][0]).to.be.a('object'); + expect(result[0]['forecast'][0]).to.have.property('low'); + expect(result[0]['forecast'][0]).to.have.property('high'); + expect(result[0]['forecast'][0]).to.have.property('skycodeday'); + expect(result[0]['forecast'][0]).to.have.property('skytextday'); + expect(result[0]['forecast'][0]).to.have.property('date'); + expect(result[0]['forecast'][0]).to.have.property('day'); + expect(result[0]['forecast'][0]).to.have.property('shortday'); + expect(result[0]['forecast'][0]).to.have.property('precip'); + + done(); + }); + }); + + it('should find multiple locations with weather information', function(done) { + weather.find({search: 'San Francisco', degreeType: 'F'}, function(err, result) { + if(err) return done(err); + + expect(err).to.be.equal(undefined); + expect(result).to.be.a('array'); + expect(result).to.have.property('length').to.be.above(1); + done(); + }); + }); + + it('should fail to find a location (missing options)', function(done) { + weather.find(null, function(err, result) { + if(!err) return done('No error!'); + + expect(result).to.be.equal(undefined); + done(); + }); + }); + }); + +}); \ No newline at end of file