Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have been writing my Rails application with Cucumber in TDD mode: Tests first, then the code. Now my application needs an API. What I like about cucumber is, that I can specify my tests in plain English, so even managers understand what's going on.
Is there any way I can do this for my JSON-API?
YES! This is totally possible. Have you checked out the Cucumber Book by the Pragmatic Programmer series?
Here's a quick example:
Feature: Addresses
In order to complete the information on the place
I need an address
Scenario: Addresses
Given the system knows about the following addresses:
[INSERT TABLE HERE or GRAB FROM DATABASE]
When client requests GET /addresses
Then the response should be JSON:
"""
[
{"venue": "foo", "address": "bar"},
{ more stuff }
]
"""
STEP DEFINITION:
Given(/^the system knows about the following addresses:$/) do |addresses|
# table is a Cucumber::Ast::Table
File.open('addresses.json', 'w') do |io|
io.write(addresses.hashes.to_json)
end
end
When(/^client requests GET (.*)$/) do |path|
#last_response = HTTParty.get('local host url goes here' + path)
end
Then /^the response should be JSON:$/ do |json|
JSON.parse(#last_response.body).should == JSON.parse(json)
end
ENV File:
require File.join(File.dirname(__FILE__), '..', '..', 'address_app')
require 'rack/test'
require 'json'
require 'sinatra'
require 'cucumber'
require 'httparty'
require 'childprocess'
require 'timeout'
server = ChildProcess.build("rackup", "--port", "9000")
server.start
Timeout.timeout(3) do
loop do
begin
HTTParty.get('local host here')
break
rescue Errno::ECONNREFUSED => try_again
sleep 0.1
end
end
end
at_exit do
server.stop
end
You can definitely achieve this. You can write step definitions to assert/verify your json responses. Something like this
Given a username and password
When I try to login via the API
Then I should get logged in
While this works, this just tests the API ( controllers/actions ) work or not, ie more like "functional" testing, not Acceptance testing. As such you are not going to test the API consumer itself.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
As I'm trying to fetch data and have the scraped data saved to the database under seeds.rb, I realized the same data would't overwrite itself. And as a result I got multiple repetitive data in the database.
The goal is to update the existing data with new info instead of creating new ones.
Here's how I fetch the data:
seed.rb
require 'uri'
require 'net/http'
require 'openssl'
require 'json'
url = URI("https://google-flights-search.p.rapidapi.com/search?departure_airport_code=HND&arrival_airport_code=TPE&departure_date=2022-02-17&flight_class=Economy")
http = Net::HTTP.new(url.host, url.port)
http.read_timeout = 300
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
request["x-rapidapi-host"] = ENV["x-rapidapi-host"]
request["x-rapidapi-key"] = ENV["x-rapidapi-key"]
response = http.request(request)
dep_hash = JSON.parse(response.read_body)
I planned to only show the cheapest flight and save it to the database, and expected every time I run rails db:seed the data would be updated and overwritten. (as I set the ticket_id to be the same)
dep_flight_data = dep_hash["flights"]
tempPrice = 10000
depHash= {}
for flight in dep_flight_data
if flight["price"]< tempPrice
tempPrice = flight["price"]
depHash = flight
end
end
dep_ticket_id = (depHash["departure_airport_code"]+depHash["arrival_airport_code"]+ depHash["departure_date"]).split('/').join
Ticket.create(
ticket_id: dep_ticket_id,
departure: depHash["departure_airport_code"],
arrival: depHash["arrival_airport_code"],
departure_date: depHash["departure_date"],
ticket_amount: (depHash["price"]*28)
)
current seed data as below:
Is there any way I can update the seeds file correctly?
Any guides are much appreciated!
Instead of just adding all found tickets into the database you need to check if a similar ticket already exists before creating a new one.
This can be done by changing
Ticket.create(
ticket_id: dep_ticket_id,
departure: depHash["departure_airport_code"],
arrival: depHash["arrival_airport_code"],
departure_date: depHash["departure_date"],
ticket_amount: (depHash["price"]*28)
)
to
Ticket
.create_with(
departure: depHash["departure_airport_code"],
arrival: depHash["arrival_airport_code"],
departure_date: depHash["departure_date"],
ticket_amount: (depHash["price"]*28)
)
.find_or_create_by(ticket_id: dep_ticket_id)
See docs for find_or_create_by
I am a beginner programmer. I recently built an application that uses the iex-ruby-client gem to pull stock quotes for me that I enter into a webpage form. It worked perfectly.
However, in early June, IEX changed their API so that you have to have a publishable token from the IEX cloud console. I got my publishable token from IEX cloud console.
The updated gem docs (https://github.com/dblock/iex-ruby-client) say that I have to "Configure" the application now. I simply don't know how or where I would implement the configuration code. Here is the suggested code from the gem documentation. I just don't know where to put it.
Configure IEX::Api.configure do |config|
config.publishable_token = 'token' # defaults to
ENV['IEX_API_PUBLISHABLE_TOKEN']
config.endpoint = 'https://sandbox.iexapis.com/v1' # defaults to
'https://cloud.iexapis.com/v1'
end
The documents also state, "You can also configure an instance of a client directly."
client = IEX::Api::Client.new(
publishable_token: 'token',
endpoint: 'https://sandbox.iexapis.com/v1'
)
I am adding extra code to clarify what I have done based on the response here. Here is my new config/initializers/iex-ruby-client.rb file (token info isn't the real one).
IEX::Api.configure do |config|
config.publishable_token = 'pk_3b38fsdadfsafjsdalfjdsakfjlda12f519'
config.endpoint = 'https://sandbox.iexapis.com/v1'
end
Here is the relevant method in the controller where I require the library:
def index
require 'iex-ruby-client'
if params[:id] == ""
#nothing = "You forgot to enter a symbol ;)."
elsif
if params[:id]
begin
#stock = IEX::Resources::Quote.get(params[:id])
#company = IEX::Resources::Company.get(params[:id])
rescue StandardError
#error = "That stock symbol doesn't seem to exist. Please enter
another symbol."
end
end
end
end
So I have created the config file and required the gem at the top of the method, but I am still getting an error. I'm sure there is some flaw in my implementation of this token requirement. If you have any additional suggestions, I welcome them. But if this is too much to ask on Stack Overflow, I understand. Thanks.
Well, you clearly have two choices:
use initializer by creating a config file(i.e: iex_client.rb) under the directory /config/initializers and add:
Configure IEX::Api.configure do |config|
config.publishable_token = 'token' # defaults to
ENV['IEX_API_PUBLISHABLE_TOKEN']
config.endpoint = 'https://sandbox.iexapis.com/v1' # defaults to
'https://cloud.iexapis.com/v1'
end
just use the client object wherever you want like this:
client = IEX::Api::Client.new(
publishable_token: 'token',
endpoint: 'https://sandbox.iexapis.com/v1'
)
You probably need to replace token with a correct one. You also need to make sure to require the library wherever you wanna use it.
After unsuccessfully attempting to configure the IEX-ruby-client gem (as described in my question here on stack overflow), I switched over to the stock_quote gem. That gem is built off of the same IEX API, and I had no problems configuring the app with a stock_quote.rb file saved inside config/initializers.
I'm looking at the testing docs for Savon here and i don't understand what's going on. I'm fairly new to testing with mocks and stubbing and maybe that's the issue. Here is the example:
require "spec_helper"
# require the helper module
require "savon/mock/spec_helper"
describe AuthenticationService do
# include the helper module
include Savon::SpecHelper
# set Savon in and out of mock mode
before(:all) { savon.mock! }
after(:all) { savon.unmock! }
describe "#authenticate" do
it "authenticates the user with the service" do
message = { username: "luke", password: "secret" }
fixture = File.read("spec/fixtures/authentication_service/authenticate.xml")
# set up an expectation
savon.expects(:authenticate).with(message: message).returns(fixture)
# call the service
service = AuthenticationService.new
response = service.authenticate(message)
expect(response).to be_successful
end
end
end
I understand that we set up an expectation with the fixture i.e. what the response should be.
We then call the service and get a response. My questions are:
1. Is a real call being made?
2. Is this response a real response??
3. Can someone try to explain this overall for me please?
Cheers
No remote request would be made. Since you have mocked authenticate, the response will be short-circuited to your designated value. However, some other preliminary requests might be expected to happen first, like a GET for the WSDL.
hi I'm create test use cucumber in my rails apps. in my step scenario I used http basic authenticate, so far it pass the basic authenticate, but when I wanna to call method on controller and post some params, I had problem :
first I use this code in step but failed not cross to method on controller :
post some_admin_url, #params
second I used this code, and failed also, the error is when running the URI.parse redirect to "www.example.com" I want to go "localhost:3000/admin", so I can match the data :
Net::HTTP.post_form(URI.parse(some_admin_url), {'from' => '2005-01-01','to' => '2005-03-31'}) { |i| }
FUTURE :
#selenium
Scenario: Admin want to activate user
Given one user logged in as admin
And admin page
STEPS :
Given /^one user logged in as admin$/ do
create_user_admin
visit '/user_sessions/new'
fill_in 'user_session[login]', :with=>'siadmin'
fill_in 'user_session[password]', :with=>'12345'
click_button 'Anmelden'
end
Given /^admin page$/ do
require "net/http"
require "uri"
uri = URI.parse(user_action_admin_users_url)<br/>
http = Net::HTTP.new(uri.host, uri.port)<br/>
request = Net::HTTP::Get.new(uri.request_uri)<br/>
request.basic_auth("username", "password")<br/>
response = http.request(request)<br/>
end
enter code here
HELP !!!
THANKS
fl00r's answer probably works, but wouldn't catch redirects.
If you want to catch redirects you have to change this in a higher level. For some test frameworks there is a way to set the default host.
Using Capybara we did that:
Capybara.default_host = "subdomain.yourapp.local"
Now we actually use a Rack middleware (in test env only :), that changes changes the env[HTTP_HOST] transparently for the application, so we don't have to care about which testframework / browser driver we use.
What framework do you use?
uname="myapp"
Capybara.default_host = "http://#{uname}.mywebsite.com:3000"
Capybara.server_port = 3000 # could be any of your choice
Capybara.app_host = "http://#{uname}.mywebsite.com:#{Capybara.server_port}"
OR
request.host="www.myapp.com"
,when you are extending ActionController::TestCase
try to change url to path
post some_admin_path, #params
or
post "http://localhost:3000/#{some_admin_url}", #params
is any possible & simple way to make a twitter bot that will reply to some tweets (depend on search terms) in certain time interval. can anyone help me.
for example twitter.com/shastribot
Thanks
If you like Ruby, then I suggest using the Twitter gem: https://github.com/jnunemaker/twitter
It makes things very easy.
You could then write a script that checks whether there are any replies to the bot and if there are any new ones sends out a message. Then set it up as a cron job running as often as you think is necessary.
There's also the Twitter Bot interface to Twitter, I haven't used it myself but might be worth a look: http://integrum.rubyforge.org/twitter_bot/
You should try tweebot. It's python micro framework for twitter bots. This lib provides built-in blocks (like Filters, Selectors and Actions) that you can combine to achieve your requirements. For example, next code demonstrates how-to create canonical implementation of "retweet" bot (more examples).
# Next code demonstrates how to create simple twitter bot that select all
# friends' tweets with your mentiones and retweet they.
import tweebot as twb
def main():
# Step 1. setup context configuration
repeater = twb.Context({
'app_name' : 'repeater',
'username' : '<YOUR ACCOUNT NAME>',
'consumer_key' : '<YOUR CONSUMER KEY>',
'consumer_secret' : '<YOUR CONSUMER SECRET>',
'access_key' : '<YOUR ACCESS KEY>',
'access_secret' : '<YOUR ACCESS SECRET>',
'timeout' : 10 * 60, # 10 min, ensure twitter api limits
'history_file' : 'history.json', # don't repeat answered tweets
})
# Step 2. enable pretty logging (stdout by default)
twb.enable_logging(repeater)
# Step 3. setup chain Selector->Filters->Action
chain = (
# Select recently tweets with current user mentions.
twb.SearchMentions(),
# Apply several filters to selected tweets:
twb.MultiPart.And(
# exclude answered, blocked and own tweets
twb.BaseFilter,
# then leave only friends tweets (friends list will be cached)
twb.UsersFilter.Friends(),
# and finally, exclude tweets with invalid content
twb.BadTweetFilter),
# And now, retweet remain tweets
twb.ReplyRetweet)
# Step 4. start processing
repeater.start_forever(*chain)
if __name__ == '__main__':
main()
Ruby's twitter gem is a very good one. You can make use of twitter API to see the available methods.
You can start with a Twitter::REST::Client like following:
twitter_client = Twitter::REST::Client.new do |config|
config.consumer_key = "YOUR_CONSUMER_KEY"
config.consumer_secret = "YOUR_CONSUMER_SECRET"
config.access_token = "YOUR_ACCESS_TOKEN"
config.access_token_secret = "YOUR_ACCESS_SECRET"
end
Then you can you use your twitter_client for various purpose. For example you can post a tweet to your profile using this:
twitter_client.update("I am posting this tweet from my Ruby program")
You can get a list of all tweets by providing the twitter username like this:
twitter_client.user_timeline("YOUR_TWITTER_USER_NAME").each do |tweet|
puts tweet.text
end
For searching for tweets, take a look at this.