Skip to content

Instantly share code, notes, and snippets.

@zdennis
Last active June 29, 2018 17:43
Show Gist options
  • Save zdennis/fd88506e66f573fd746d6c71f885c479 to your computer and use it in GitHub Desktop.
Save zdennis/fd88506e66f573fd746d6c71f885c479 to your computer and use it in GitHub Desktop.
Mutually Human Blog Post: Rails 5 API + Angular 5/6 + Capybara Code Snippets Part 2
> gem install -r rails -v 5.2.0
Successfully installed rails-5.2.0
1 gem installed
> git add . &&
git commit -m "Generating the Angular app
ng new frontend
cd frontend
npm install
ng serve --open"
> mkdir -p spec/features && touch spec/features/welcome_spec.rb
require 'rails_helper'
describe 'Welcome page', type: :feature, js: :true do
it 'loads the Angular app' do
visit '/'
expect(page).to have_content('Welcome to app!')
end
end
> bundle exec rspec spec/features/welcome_spec.rb
/Users/zdennis/.rbenv/libexec/rbenv exec bundle exec rspec spec/features/welcome_spec.rb
/Users/zdennis/source/playground/my-great-new-app/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /Users/zdennis/source/playground/my-great-new-app/config/application.rb to limit the frameworks that will be loaded.
F
Failures:
1) Welcome page loads the Angular app
Failure/Error: visit '/'
RuntimeError:
Capybara not loaded, please add it to your Gemfile:
gem "capybara"
# ./spec/features/welcome_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.00619 seconds (files took 1.83 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/features/welcome_spec.rb:4 # Welcome page loads the Angular app
/Users/zdennis/source/playground/my-great-new-app/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter
> bundle exec rake db:create:all db:migrate
Created database 'db/development.sqlite3'
Database 'db/test.sqlite3' already exists
Created database 'db/production.sqlite3'
> bundle exec rspec spec/features/welcome_spec.rb
/Users/zdennis/.rbenv/libexec/rbenv exec bundle exec rspec spec/features/welcome_spec.rb
F
Failures:
1) Welcome page loads the Angular app
Failure/Error: visit '/'
RuntimeError:
Capybara not loaded, please add it to your Gemfile:
gem "capybara"
# ./spec/features/welcome_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.0065 seconds (files took 2.15 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/features/welcome_spec.rb:4 # Welcome page loads the Angular app
RuntimeError:
Capybara not loaded, please add it to your Gemfile:
gem "capybara"
# ./spec/features/welcome_spec.rb:5:in `block (2 levels) in <top (required)>
group :test do
gem 'capybara'
gem 'capybara_spa'
gem 'selenium-webdriver'
gem 'chromedriver-helper'
end
> mkdir -p spec/support &&
spec/support/capybara.rb
require 'capybara/rails'
require 'capybara_spa'
require 'selenium/webdriver'
# capybara.rb is responsible for configuring Capybara.
#
# It sets up two different JS drivers:
#
# * :chrome
# * :headless_chrome
#
# It hard codes an assumption that the Rails app runs on port 3001.
#
FrontendServer = CapybaraSpa::Server::NgStaticServer.new(
build_path: File.dirname(__FILE__) + '/../../frontend/dist/frontend',
http_server_bin_path: File.dirname(__FILE__) + '/../../frontend/node_modules/.bin/angular-http-server',
# log_file: File.dirname(__FILE__) + '/../../log/angular-process.log',
pid_file: File.dirname(__FILE__) + '/../../tmp/angular-process.pid'
)
RSpec.configure do |config|
config.before(:each) do |example|
if self.class.metadata[:js]
begin
FrontendServer.start unless FrontendServer.started?
rescue CapybaraSpa::Server::Error => ex
# When an exception is raised it is being swallowed
# so print it out and forcefully fail so the developer
# see its.
STDERR.puts ex.message, ex.backtrace.join("\n")
exit!
end
end
end
end
# This env var comes from the heroku-buildpack-google-chrome
chrome_bin = ENV.fetch('GOOGLE_CHROME_SHIM', nil)
# This env var comes from chromedriver_linux, e.g. TravisCI
chrome_bin ||= ENV.fetch('CHROME_BIN', nil)
chrome_options = {}
chrome_options[:binary] = chrome_bin if chrome_bin
# Give us access to browser console logs, see spec/support/browser_logging.rb
logging_preferences = { browser: 'ALL' }
Capybara.register_driver :chrome do |app|
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
chromeOptions: chrome_options,
loggingPrefs: logging_preferences
)
Capybara::Selenium::Driver.new(
app,
browser: :chrome,
desired_capabilities: capabilities
)
end
Capybara.register_driver :headless_chrome do |app|
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
chromeOptions: chrome_options.merge(args: %w(headless disable-gpu)),
loggingPrefs: logging_preferences
)
Capybara::Selenium::Driver.new(
app,
browser: :chrome,
desired_capabilities: capabilities
)
end
Capybara.app_host = "http://localhost:#{FrontendServer.port}"
Capybara.always_include_port = true
Capybara.default_max_wait_time = 10
Capybara.javascript_driver = :chrome
Capybara.server = :puma
Capybara.server_port = 3001
> rails new my-great-new-app --api --skip-test
[output suppressed]
> bundle exec rspec spec/features/welcome_spec.rb
Failures:
1) Welcome page loads the Angular app
Failure/Error: raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
ActionController::RoutingError:
No route matches [GET] "/"
Dir[Rails.root.join('spec/support/**/*.rb')].each { |file| load file }
# Add additional requires below this line. Rails is not loaded until this point!
> bundle exec rspec spec/features/welcome_spec.rb
angular-http-server not found! Make sure it's installed via npm:
To the project:
npm install --save-dev angular-http-server
Or globally:
npm install -g angular-http-server
[output suppressed]
cd frontend &&
npm install --save-dev angular-http-server &&
cd ..
```shell
> bundle exec rspec spec/features/welcome_spec.rb
E.g. ng build --aot --environment integration-tests --target=development --output-path=public/app/
/Users/zdennis/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/capybara_spa-0.4.0/lib/capybara_spa/server/ng_static_server.rb:118:in `check_ng_app_requirements!'
[output suppressed]
> cd frontend &&
ng build &&
cd ..
> bundle exec rspec spec/features/welcome_spec.rb
/Users/zdennis/.rbenv/libexec/rbenv exec bundle exec rspec spec/features/welcome_spec.rb
Capybara starting Puma...
* Version 3.11.4 , codename: Love Song
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:3001
Path specified: frontend
Using frontend/index.html
Listening on 5001
Route dummy, replacing with index.html
Sending frontend/runtime.js with Content-Type application/javascript
Sending frontend/polyfills.js with Content-Type application/javascript
Sending frontend/styles.js with Content-Type application/javascript
Sending frontend/vendor.js with Content-Type application/javascript
Sending frontend/main.js with Content-Type application/javascript
Sending frontend/favicon.ico with Content-Type image/x-icon
Route dummy, replacing with index.html
Sending frontend/runtime.js with Content-Type application/javascript
Sending frontend/polyfills.js with Content-Type application/javascript
Sending frontend/styles.js with Content-Type application/javascript
Sending frontend/vendor.js with Content-Type application/javascript
Sending frontend/main.js with Content-Type application/javascript
.
~~
Finished in 2.33 seconds (files took 2.12 seconds to load)
1 example, 0 failures
# log_file: File.dirname(__FILE__) + '/../../log/angular-process.log',
> bundle exec rspec spec/features/welcome_spec.rb
Capybara starting Puma...
* Version 3.11.4 , codename: Love Song
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:3001
.
Finished in 2.85 seconds (files took 2.33 seconds to load)
1 example, 0 failures
> cd my-great-new-app/
# For Rails in one terminal
bundle exec rails s
# For Angular in another terminal
cd frontend/ && ng serve
<div *ngFor="let message of messages">
{{message}}
</div>
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
messages = [] as Array<string>;
title = 'app';
constructor(private http: HttpClient) {
}
ngOnInit() {
const url = `${environment.apiUrl}/welcome_messages`;
this.http.get(url).subscribe((messages: Array<string>) => {
this.messages = messages;
});
}
}
ℹ 「wdm」: Compiling...
92% after chunk asset optimization SourceMapDevToolPlugin vendor.js generate SourceMap
ERROR in src/app/app.component.ts(18,32): error TS2339: Property 'apiUrl' does not exist on type '{ production: boolean; }'.
export const environment = {
apiUrl: 'http://localhost:3000',
production: false
};
Date: 2018-06-07T20:17:16.619Z - Hash: be71334b50647c17295d - Time: 3502ms
3 unchanged chunks
chunk {main} main.js, main.js.map (main) 11.8 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 3.38 MB [initial] [rendered]
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
Date: 2018-06-07T20:20:47.242Z - Hash: 8d1c9312895824cdd7ba - Time: 161ms
4 unchanged chunks
chunk {main} main.js, main.js.map (main) 11.8 kB [initial] [rendered]
ℹ 「wdm」: Compiled successfully.
Error: StaticInjectorError(AppModule)[AppComponent -> HttpClient]:
StaticInjectorError(Platform: core)[AppComponent -> HttpClient]:
NullInjectorError: No provider for HttpClient!
at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:979)
at resolveToken (core.js:1232)
at tryResolveToken (core.js:1182)
at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1077)
at resolveToken (core.js:1232)
at tryResolveToken (core.js:1182)
at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1077)
at resolveNgModuleDep (core.js:9217)
at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:9911)
at resolveDep (core.js:10276)
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
GET http://localhost:3000/welcome_messages 404 (Not Found)
Failed to load http://localhost:3000/welcome_messages: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 404.
core.js:1598 ERROR HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: null, ok: false, …}
> git init . &&
git add . &&
git commit -m "Initial creation of the app
rails new favorite-books --api --skip-test"
ActionController::RoutingError (No route matches [GET] "/welcome_messages"):
> bundle exec rails g resource WelcomeMessage message:string
> bundle exec rake db:migrate
> bundle exec rails s
ActionController::RoutingError (No route matches [GET] "/welcome_messages"):
AbstractController::ActionNotFound (The action 'index' could not be found for WelcomeMessagesController)
class WelcomeMessagesController < ApplicationController
def index
render json: WelcomeMessage.all.map(&:message)
end
end
> bundle exec rails console
Running via Spring preloader in process 79286
Loading development environment (Rails 5.2.0)
>> WelcomeMessage.create!(message: 'Hallo there!')
=> #<WelcomeMessage id: 1, message: "Hallo there!", created_at: "2018-06-07 15:19:52", updated_at: "2018-06-07 15:19:52">
>> exit
Failed to load http://localhost:3000/welcome_messages: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'rack-cors'
end
> echo "gem 'rspec-rails', group: :test" >> Gemfile &&
bundle &&
bundle exec rails generate rspec:install &&
git add . &&
git commit -m "Adding rspec-rails to project
rails generate rspec:install"
# Be sure to restart your server when you modify this file.
# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
# Read more: https://github.com/cyu/rack-cors
if Rails.env.development?
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
end
> bundle exec rails s
it 'shows a list of welcome messages' do
WelcomeMessage.create!([
{ message: 'Top of the morning to you' },
{ message: 'Good day' }
])
visit '/'
expect(page).to have_content('Top of the morning to you')
expect(page).to have_content('Good day')
end
> bundle exec rspec spec/features/welcome_spec.rb:9
Run options: include {:locations=>{"./spec/features/welcome_spec.rb"=>[9]}}
Capybara starting Puma...
* Version 3.11.4 , codename: Love Song
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:3001
F
Failures:
1) Welcome page shows a list of welcome messages
Failure/Error: expect(page).to have_content('Top of the morning to you')
expected to find text "Top of the morning to you" in "Welcome to app!\nHere are some links to help you start:\nTour of Heroes\nCLI Documentation\nAngular blog"
# ./spec/features/welcome_spec.rb:17:in `block (2 levels) in <top (required)>'
Finished in 12.38 seconds (files took 0.93442 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/features/welcome_spec.rb:9 # Welcome page shows a list of welcome messages
> bundle exec rspec spec/features/welcome_spec.rb:9
> cd frontend &&
ng build &&
cd ..
> bundle exec rspec spec/features/welcome_spec.rb:9
Run options: include {:locations=>{"./spec/features/welcome_spec.rb"=>[9]}}
Capybara starting Puma...
* Version 3.11.4 , codename: Love Song
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:3001
F
Failures:
1) Welcome page shows a list of welcome messages
Failure/Error: expect(page).to have_content('Top of the morning to you')
expected to find text "Top of the morning to you" in "Welcome to app!\nHallo there!\nHere are some links to help you start:\nTour of Heroes\nCLI Documentation\nAngular blog"
# ./spec/features/welcome_spec.rb:18:in `block (2 levels) in <top (required)>'
Finished in 1 minute 3.06 seconds (files took 1.74 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/features/welcome_spec.rb:9 # Welcome page shows a list of welcome messages
Started GET "/welcome_messages" for 127.0.0.1 at 2018-06-07 13:38:24 -0400
Processing by WelcomeMessagesController#index as HTML
WelcomeMessage Load (0.2ms) SELECT "welcome_messages".* FROM "welcome_messages"
↳ app/controllers/welcome_messages_controller.rb:3
Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.2ms)
"configurations": {
"e2e": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.e2e.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
}
}
> cp src/environments/environment.{,e2e.}ts
> bundle exec rspec spec
/Users/zdennis/.rbenv/libexec/rbenv exec bundle exec rspec spec
No examples found.
Finished in 0.00042 seconds (files took 0.14595 seconds to load)
0 examples, 0 failures
> ng build --configuration e2e
> bundle exec rspec spec/features/welcome_spec.rb:9
Run options: include {:locations=>{"./spec/features/welcome_spec.rb"=>[9]}}
Capybara starting Puma...
* Version 3.11.4 , codename: Love Song
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:3001
F
Failures:
1) Welcome page shows a list of welcome messages
Failure/Error: expect(page).to have_content('Top of the morning to you')
expected to find text "Top of the morning to you" in "Welcome to app!\nHere are some links to help you start:\nTour of Heroes\nCLI Documentation\nAngular blog"
# ./spec/features/welcome_spec.rb:17:in `block (2 levels) in <top (required)>'
Finished in 13.97 seconds (files took 0.9674 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/features/welcome_spec.rb:9 # Welcome page shows a list of welcome messages
if Rails.env.development? || Rails.env.test?
> bundle exec rspec spec/features/welcome_spec.rb:9
Run options: include {:locations=>{"./spec/features/welcome_spec.rb"=>[9]}}
Capybara starting Puma...
* Version 3.11.4 , codename: Love Song
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:3001
.
Finished in 2.85 seconds (files took 1.01 seconds to load)
1 example, 0 failures
> bundle exec rspec spec/features/welcome_spec.rb
Capybara starting Puma...
* Version 3.11.4 , codename: Love Song
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:3001
..
Finished in 2.33 seconds (files took 0.92025 seconds to load)
2 examples, 0 failures
> ng new frontend
[output suppressed]
error: unknown option `--silent'
Package install failed, see above.
> npm install -g yarn
> cd frontend &&
npm install &&
ng serve --open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment