Context
Using Ruby, I'm trying to get the content of the last artifact that is a result of a SimpleCov coverage report.
I'm able so far to retrieve the last artifact with this code (using an Access Token) :
module Ci
class Circle
# more code
def artifacts
#artifacts = self.class.get("/project/github/#{#user}/#{#project}/latest/artifacts?circle-token=#{ENV['CI_ACCESS_TOKEN']}")
self
end
# more code
end
end
Then, I'm retrieving the index page which I want to get the content from, with this code:
def report
artifacts = JSON.parse(#artifacts.parsed_response)
artifacts.each do |response|
url = response['url']
return url if url.end_with? '.html'
end
nil
end
Problem
I want to get the content of the coverage page, located at https://3-57932222-gh.circle-artifacts.com/0//tmp/circle-artifacts.64VZY8w/coverage/index.html, but when logged out, it shows Must be log in. I've tried to check the CircleCI documentation but were not able to find out how to pass an access token to this page in order to get it's content from the command line (where I'm obviously not log in). Ideas?
Related
def linkdin_login(company_name,username,password):
driver.get('https://linkedin.com/')
driver.find_element(By.XPATH,'//*[#id="session_key"]').send_keys(username)
driver.find_element(By.XPATH,'//*[#id="session_password"]').send_keys(password)
driver.find_element(By.XPATH,"//button[#class='sign-in-form__submit-button']").click()
#def company_info(company_name):
element = driver.find_element(By.CSS_SELECTOR,"#global-nav-typeahead > input")
element.send_keys(company_name)
element.send_keys(Keys.ENTER)
driver.implicitly_wait(10) # seconds
driver.get(driver.find_element(By.CSS_SELECTOR,".search-nec__hero-kcard-v2 > a:nth-child(1)").get_attribute("href"))
driver.implicitly_wait(10)
people()
by the above code i am logging into LinkedIn and fetching the LinkedIn page of the some companies after getting the page I am trying to get the employee data by using people function show below
def people():
driver.implicitly_wait(10)
driver.get(driver.find_element(By.XPATH,"/html/body/div[5]/div[3]/div/div[2]/div/div[2]/main/div[1]/section/div/div[2]/div[1]/div[2]/div/a").get_attribute("href"))
driver.implicitly_wait(10)
people = driver.find_element(By.XPATH,"/html/body/div[4]/div[3]/div[2]/div/div[1]/main/div/div/div[2]/div/ul")
people_data = people.find_elements(By.TAG_NAME,"li")
for i in people_data:
print(i.text)
in this function i am trying to access the link to employees data
that is where the problem lies
the line 2 of people function i trying to get the link the problem is due to some reason sometimes i am getting the link(not to frequently!!) but most of the time i am getting the error saying Xpath not found
i didn't know how to attach a html page so i am attaching the link
([https://www.linkedin.com/company/google/](https://www.stackoverflow.com/)
1. I tried implicit wait assuming that the program is trying to access the Xpath during loading of the page
Ruby Newbie here! I am re-writing automated unit tests. The problem is that there are too many 'test users' that get changed and used by others. So the goal is to make a list of test users for each repository, and have them referenced in a specific file rather than hard-coding the email/password logins. I am unable to figure out how to have:
1. the .feature file with the test
2. the steps.rb with the steps for the test
3. a final user.rb file that holds class/instance variables (I don't care which I use, it just has to be able to be referenced by all the tests I will be re-writing).
I've tried referencing the email/password details from the steps.rb file in these ways:
* Then('User enters \”([^\”]*)\”$”')
* Then('User enters ')
* Then('User enters '/valid_user_email>')
I've tried defining the email/password in user.rb in these ways:
* #valid_user_email = 'user#url.com'
* puts 'valid_user_email' = 'user#url.com'
* = 'user#url.com'
Currently the login.feature file is:
Feature: Login and Logout of MySE
Scenario: Login and Logout of MySE
Given I enter the email address of an existing account
Then User enters valid_user_email in the email field
The login_steps.rb file looks like:
Given('I enter the email address of an existing account') do
visit "user/profiles"
expect(page).to have_content('Welcome')
end
Then('User enters valid_user_email in the email field') do
fill_in 'user_login', with: #valid_user_email
click_on('Next')
end
And finally, the user.rb file looks like:
class Credentials
def valid_user_email
#valid_user_email = "user#url.com"
end
def valid_user_password
puts "Testttttt01"
end
end
I can successfully upload a single file using a Mechanize form like this:
def add_attachment(form, attachments)
attachments.each_with_index do |attachment, i|
form.file_uploads.first.file_name = attachment[:path]
end
end
where form is a mechanize form. But if attachments has more than one element, the last one overwrites the previous ones. This is obviously because I'm using the first accessor which always returns the same element of the file_uploads array.
To fix this, I tried this, which results an error, because there is only one element in this array.
def add_attachment(form, attachments)
attachments.each_with_index do |attachment, i|
form.file_uploads[i].file_name = attachment[:path]
end
end
If I try to create a new file_upload object, it also doesn't work:
def add_attachment(form, attachments)
attachments.each_with_index do |attachment, i|
form.file_uploads[i] ||= Mechanize::Form::FileUpload.new(form, attachment[:path])
form.file_uploads[i].file_name = attachment[:path]
end
end
Any idea how I can upload multiple files using Mechanize?
So, I solved this issue, but not exactly how I imagined it would work out.
The site I was trying to upload files to was a Redmine project. Redmine is using JQueryUI for the file uploader, which confused me, since Mechanize doesn't use Javascipt. But, it turns out that Redmine degrades nicely if Javascript is disabled and I could take advantage of this.
When Javascript is disabled, only one file at time can be uploaded in the edit form, but going to the 'edit' url for the issue that was just created gives the chance to upload a second file. My solution was to simply attach a file, upload the form and then click the 'Update' link on the resulting page, which presented a page with a new form and another upload field, which I could then use to attach the next file to. I did this for all attachments but the last, so that the form processing could be completed and then uploaded for a final time. Here is the relavant bit of code:
def add_attachment(agent,form, attachments)
attachments.each_with_index do |attachment, i|
form.file_uploads.first.file_name = attachment[:path]
if i < attachments.length - 1
submit_form(agent, form)
agent.page.links_with(text: 'Update').first.click
form = get_form(agent)
end
end
form
end
I used the following
form.file_uploads[0].file_name = "path to the first file that to be uploaded" form.file_uploads[1].file_name = "path to the second file that to be uploaded" form.file_uploads[2].file_name = "path to the third file that to be uploaded".
and worked fine. Hope this helps.
I have written a Jekyll plugin to display the number of pageviews on a page by calling the Google Analytics API using the garb gem. The only trouble with my approach is that it makes a call to the API for each page, slowing down build time and also potentially hitting the user call limits on the API.
It would be possible to return all the data in a single call and store it locally, and then look up the pageview count from each page, but my Jekyll/Ruby-fu isn't up to scratch. I do not know how to write the plugin to run once to get all the data and store it locally where my current function could then access it, rather than calling the API page by page.
Basically my code is written as a liquid block that can be put into my page layout:
class GoogleAnalytics < Liquid::Block
def initialize(tag_name, markup, tokens)
super # options that appear in block (between tag and endtag)
#options = markup # optional optionss passed in by opening tag
end
def render(context)
path = super
# Read in credentials and authenticate
cred = YAML.load_file("/home/cboettig/.garb_auth.yaml")
Garb::Session.api_key = cred[:api_key]
token = Garb::Session.login(cred[:username], cred[:password])
profile = Garb::Management::Profile.all.detect {|p| p.web_property_id == cred[:ua]}
# place query, customize to modify results
data = Exits.results(profile,
:filters => {:page_path.eql => path},
:start_date => Chronic.parse("2011-01-01"))
data.first.pageviews
end
Full version of my plugin is here
How can I move all the calls to the API to some other function and make sure jekyll runs that once at the start, and then adjust the tag above to read that local data?
EDIT Looks like this can be done with a Generator and writing the data to a file. See example on this branch Now I just need to figure out how to subset the results: https://github.com/Sija/garb/issues/22
To store the data, I had to:
Write a Generator class (see Jekyll wiki plugins) to call the API.
Convert data to a hash (for easy lookup by path, see 5):
result = Hash[data.collect{|row| [row.page_path, [row.exits, row.pageviews]]}]
Write the data hash to a JSON file.
Read in the data from the file in my existing Liquid block class.
Note that the block tag works from the _includes dir, while the generator works from the root directory.
Match the page path, easy once the data is converted to a hash:
result[path][1]
Code for the full plugin, showing how to create the generator and write files, etc, here
And thanks to Sija on GitHub for help on this.
I am using the Watir Splash framework to test a web application, and I have setup two page classes. The first is the "Login" page which is detailed here:
module App
module Page
class Login < WatirSplash::Page::Base
url "http://[removed].com"
def login_btn
modify button(:id => 'btnLogin'), :click => lambda {redirect_to VehicleSelection}
end
The other page class is the "Vehicle Selection" page. I have used the modify method as shown in the documentation here to ensure that the vehicle selection page object is available for RSpec after a successful login.
But what happens if the login failed? I have some test cases that deliberately feed incorrect information into the login form to ensure that the authentication is working properly. RSpec would need the methods defined in the "Login" class to access the correct elements to complete the test case. In this case, the way that I have specified the method a "VehicleSeleciton" object will be returned regardless. (or so it appears)
Any help is appreciated. Also, I'm open to other suggestions for testing frameworks, especially if there is more example code for me to reference.
Below are a couple of approaches I have tried. I was not using the WatirSplash framework, but the same concepts applied (though the attempted WatirSplash example code might not be 100% accurate).
Solution 1: Do return page objects
My personal preference is to not have page objects returning page objects. Instead, I find it easier to read/work with explicit initializations of each page object within the test. Alister Scott discussed this in his blog.
Your tests would then look like:
#For login successful tests
page = App::Page::Login.new
page.login_btn.click
page = App::Page::VehicleSelection.new #The VehicleSelection page is explicitly initialized
page.validate_page #or whatever you want to do with the page
#For login failed tests
page = App::Page::Login.new
page.login_btn.click
page.validate_page #or whatever you want to do with the page
Solution 2: Create multiple methods for login
Another solution, would be to create two login methods - one for successful login and one for unsuccessful login.
The page object could be:
module App
module Page
class Login < WatirSplash::Page::Base
url "http://[removed].com"
def login(user, password)
#Do whatever code to input name and password and then click the button
#Then redirect to the VehicleSelection page since that is where you will want to go most often
redirect_to VehicleSelection
end
def login_failed(user, password)
login(user, password)
#Return the Login page (instead of the VehicleSelection page).
redirect_to Login
end
end
end
end
With the tests being:
#For login successful tests
login_page = App::Page::Login.new
vehicle_page = login_page.login(user, password)
vehicle_page.validate_page #or whatever you want to do with the Vehicle Selection page
#For login failed tests
login_page = App::Page::Login.new
login_page.login_failed(user, password)
login_page.validate_page #or whatever you want to do with the Login page
Solution 3: Make the button know where it is going
Another solution, would be to have the login button know which page to redirect to.
The page object could be:
module App
module Page
class Login < WatirSplash::Page::Base
url "http://[removed].com"
def login_btn(login_successful=true)
if login_successful
modify button(:id => 'btnLogin'), :click => lambda {redirect_to VehicleSelection}
else
modify button(:id => 'btnLogin'), :click => lambda {redirect_to Login}
end
end
end
end
end
With the tests being:
#For login successful tests
login_page= App::Page::Login.new
vehicle_page = login_page.login_btn.click
vehicle_page.validate_page #or whatever you want to do with the Vehicle Selection page
#For login failed tests
login_page= App::Page::Login.new
login_page.login_btn(false).click
login_page.validate_page #or whatever you want to do with the Login page
Thanks for trying out my gem WatirSplash. I would have written something in the lines of solution #2 - e.g. create two separate methods for successful login and failed login. Using #modify is not needed in either method, like Justin did.
Also, i'd suggest you to use my other gem test-page instead, which is more or less the same, as Page Objects in WatirSplash, but it is extracted into separate gem - WatirSplash will be deprecated in the long term due to all of its parts being exctracted into separate gems giving better control of which functionality is needed in each project.