diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 937359802..62c227002 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -65,7 +65,7 @@ jobs:
run: docker-compose up -d selenium
- name: Run specs (capybara)
- run: docker-compose run --rm -e RAILS_ENV=test -e COVERAGE=true -e FEATURES=true -e SELENIUM_URL web bundle exec rspec
+ run: docker-compose run --rm -e RAILS_ENV=test -e COVERAGE=true -e FEATURES=true -e SELENIUM_URL web bundle exec rspec --format=documentation
- name: Run specs (cucumber)
run: docker-compose run --rm -e RAILS_ENV=test -e COVERAGE=true -e SELENIUM_URL web bundle exec cucumber
@@ -78,6 +78,13 @@ jobs:
path: resultset.*.json
retention-days: 1
+ - uses: actions/upload-artifact@v3
+ if: ${{ failure() }}
+ with:
+ name: capybara_screenshots
+ path: tmp/capybara/*
+ retention-days: 7
+
analysis:
runs-on: ubuntu-latest
needs:
@@ -94,7 +101,7 @@ jobs:
- uses: actions/download-artifact@v3
with:
name: integration_tests_coverage
- - run: docker-compose run --no-deps --rm web rake coverage:report
+ - run: docker-compose run --no-deps --rm web bundle exec rails coverage:report
- uses: actions/upload-artifact@v3
with:
diff --git a/.ruby-version b/.ruby-version
index bc4abe86d..b0f6bf0cd 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.3.8
+2.4.10
diff --git a/Dockerfile b/Dockerfile
index 562973cdb..7b9745aba 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM instedd/nginx-rails:2.3
+FROM ruby:2.4
# Cleanup expired Let's Encrypt CA (Sept 30, 2021)
RUN sed -i '/^mozilla\/DST_Root_CA_X3/s/^/!/' /etc/ca-certificates.conf && update-ca-certificates -f
@@ -17,35 +17,38 @@ RUN curl -L https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/
dpkg -i wkhtmltopdf.deb && \
rm -f wkhtmltopdf.deb
-## Create a user for the web app.
-RUN \
- addgroup --gid 9999 app && \
- adduser --uid 9999 --gid 9999 --disabled-password --gecos "Application" app && \
- usermod -L app
+# Create a user for the web app.
+RUN addgroup --gid 9999 app && \
+ adduser --uid 9999 --gid 9999 --disabled-password --gecos "Application" app && \
+ usermod -L app
+
+# Application directory
+RUN mkdir /app
+WORKDIR /app
+# Configuration
ARG gemfile=Gemfile
ENV BUNDLE_GEMFILE=${gemfile}
ENV POIROT_STDOUT true
ENV POIROT_SUPPRESS_RAILS_LOG true
-ENV PUMA_OPTIONS "--preload -w 4"
+ENV PUMA_OPTIONS "--preload -w 4 -p 3000"
ENV NNDD_VERSION "cdx-0.11-pre7"
+ENV RAILS_ENV=production
# Install gem bundle
COPY Gemfile* cdx.gemspec cdx-api-elasticsearch.gemspec /app/
COPY deps/ /app/deps/
-
RUN bundle install --jobs 8 --deployment --without development test
# Install the application
ADD . /app
# Precompile assets
-RUN bundle exec rake assets:precompile RAILS_ENV=production
+RUN bundle exec rake assets:precompile RAILS_ENV=${RAILS_ENV}
# Download NNDD
-RUN \
- mkdir -p /app/public/ && \
- curl -L https://github.com/instedd/notifiable-diseases/releases/download/$NNDD_VERSION/nndd.tar.gz | tar -xzv -C /app/public/
+RUN mkdir -p /app/public/ && \
+ curl -L https://github.com/instedd/notifiable-diseases/releases/download/$NNDD_VERSION/nndd.tar.gz | tar -xzv -C /app/public/
# Configure NNDD
RUN /app/docker/config-nndd
@@ -53,5 +56,5 @@ RUN /app/docker/config-nndd
# Set permissions for tmp and log directories
RUN mkdir -p /app/tmp /app/log && chown -R app:app /app/tmp /app/log
-# Add config files
-ADD docker/web-run /etc/service/web/run
+EXPOSE 3000
+CMD ["/app/docker/web-run"]
diff --git a/Dockerfile-dev b/Dockerfile-dev
index 5911e0cba..ca7aef1b1 100644
--- a/Dockerfile-dev
+++ b/Dockerfile-dev
@@ -1,4 +1,4 @@
-FROM ruby:2.3
+FROM ruby:2.4
# ENV POIROT_STDOUT true
# ENV POIROT_SUPPRESS_RAILS_LOG true
@@ -32,12 +32,12 @@ RUN \
imagemagick \
ghostscript \
libgs-dev \
- mysql-client \
+ default-mysql-client \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ARG TARGETARCH
# wkhtmltopdf
-RUN curl -L https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.stretch_${TARGETARCH}.deb --output wkhtmltopdf.deb && \
+RUN curl -L https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_${TARGETARCH}.deb --output wkhtmltopdf.deb && \
dpkg -i wkhtmltopdf.deb && \
rm -f wkhtmltopdf.deb
diff --git a/Dockerfile.selenium b/Dockerfile.selenium
index 9c0115770..65f95576b 100644
--- a/Dockerfile.selenium
+++ b/Dockerfile.selenium
@@ -1,15 +1,8 @@
FROM alpine
-RUN apk add firefox-esr
+RUN echo "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
+RUN apk add firefox-esr geckodriver
RUN ln -sf /usr/bin/firefox-esr /usr/bin/firefox
-# FIXME: can't upgrade to 0.30 because Geckodriver only starts on loopback
-RUN apk add curl && \
- curl -L https://github.com/mozilla/geckodriver/releases/download/v0.29.1/geckodriver-v0.29.1-linux64.tar.gz | tar -C /usr/local/bin -zx && \
- apk del curl
-
EXPOSE 4444
EXPOSE 5900
-
-ENTRYPOINT ["geckodriver", "--host", "0.0.0.0"]
-
diff --git a/Gemfile b/Gemfile
index d36719329..c7d4ac7d9 100644
--- a/Gemfile
+++ b/Gemfile
@@ -22,10 +22,10 @@ gem 'mysql2', '~> 0.3'
gem 'elasticsearch', '~> 1.0'
# Models
-gem 'encryptor', '~> 1.3'
+gem 'encryptor', '~> 2.0'
gem 'kaminari', '~> 0.16'
gem 'paperclip', git: 'https://github.com/instedd/paperclip', branch: 'fix/v4.3.6-no-mimemagic'
-gem 'paranoia', '<= 2.4.2' # last version to support ruby 2.2
+gem 'paranoia', '< 2.5.0' # last version to support ruby 2.4 / rails 5.0
gem 'premailer-rails', '< 1.10' # 1.10 requires Rails.application.assets_manifest
# Views
@@ -38,7 +38,7 @@ gem 'wicked_pdf', '~> 2.1'
# Authentication
# gem 'bcrypt-ruby', '~> 3.1.2'
gem 'devise', '~> 4.0.0'
-gem 'devise-security', '<= 0.12.0' # last version to support ruby 2.2
+gem 'devise-security', '< 0.15.0' # last version to support ruby 2.4
gem 'devise_invitable', '~> 1.5'
gem 'doorkeeper', '~> 4.2.0'
gem 'omniauth', '~> 1.2'
@@ -54,12 +54,12 @@ gem 'dotiw', '~> 3.0'
gem 'faker', '< 1.9.2' # NOTE: kept until we upgrade to ruby 2.5+ then we can upgrade to ffaker 2.20 to replace Faker::Number
gem 'ffaker', '< 2.12.0'
gem 'guid', '~> 0.1'
-gem 'nokogiri', '~> 1.6', '< 1.10.0' # last version to support ruby 2.2
+gem 'nokogiri', '~> 1.6', '< 1.11.0' # last version to support ruby 2.4
gem 'oj', '~> 2.12', '< 2.17.3' # NOTE: 2.17.3 will stringify Time as a Float then load a BigDecimal...
gem 'poirot_rails', git: 'https://github.com/instedd/poirot_rails.git', branch: 'master'
gem 'rails-i18n', '~> 5.0'
gem 'rchardet', '~> 1.6'
-gem 'rest-client', '~> 1.8' # NOTE: only used for a single HTTP call
+gem 'rest-client', '~> 2.1' # NOTE: only used for a single HTTP call + Nuntium (SMS) + LocationService
gem 'rubyzip', '>= 1.0.0'
gem 'rqrcode', '~> 0.10' # required by Barby::QRCode
@@ -98,7 +98,7 @@ gem 'jquery-rails', '~> 4.0'
gem 'jquery-turbolinks', '~> 2.1.0'
gem 'leaflet-rails', '~> 0.7.4'
gem 'lodash-rails', '~> 3.10.1'
-gem 'react-rails', '~> 1.3.2'
+gem 'react-rails', '~> 1.6.2' # NOTE: required for JSX templates
source 'https://rails-assets.org' do
gem 'rails-assets-urijs', '~> 1.17.0'
@@ -111,16 +111,16 @@ group :development do
gem 'spring-commands-parallel-tests'
gem 'spring-commands-rspec'
gem 'spring-watcher-listen', '~> 2.0.0'
- gem 'web-console', '< 4.0' # last version to support ruby 2.2
+ gem 'web-console', '< 4.0' # last version to support ruby 2.4 / rails 5
end
group :development, :test do
- gem 'pry-byebug', '< 2.7.0' # last version to support ruby 2.2
+ gem 'pry-byebug', '< 3.10.0' # last version to support ruby 2.4
gem 'pry-rescue'
gem 'pry-stack_explorer'
- gem 'parallel_tests', '~> 2.32.0' # last version to support ruby 2.2
- gem 'parallel', '~> 1.19.2' # TODO: remove after upgrading ruby and parallel_tests
+ gem 'parallel_tests', '~> 3.5.1' # last version to support ruby 2.4
+ gem 'parallel', '~> 1.20.0' # TODO: remove after upgrading ruby and parallel_tests
end
group :test do
@@ -133,12 +133,12 @@ group :test do
gem 'rails-controller-testing'
gem 'simplecov', require: false
gem 'timecop', '~> 0.8'
- gem 'webmock', '~> 1.23.0', require: false # a spec fails with 1.24.x
+ gem 'webmock', '~> 2.3.1', require: false
# integration tests
- gem 'capybara', '~> 2.4'
+ gem 'capybara', '~> 3.29.0' # limited by site_prism 3.6
gem 'capybara-screenshot', '~> 1.0'
gem 'cucumber-rails', '~> 1.5', require: false
- gem 'selenium-webdriver', '< 4.0'
- gem 'site_prism', '~> 2.17'
+ gem 'selenium-webdriver'
+ gem 'site_prism', '~> 3.6.0' # last version to support ruby 2.4
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 2904a888c..01671475d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -37,11 +37,11 @@ GIT
GIT
remote: https://github.com/instedd/ruby-location_service.git
- revision: 830800eec4c4c7874dd6eb9ace576460fba7ba1e
+ revision: 736ca8174c37e1eda94f5573d614a92b6d742ab9
branch: master
specs:
location_service (0.1.0)
- rest-client (~> 1.6)
+ rest-client (~> 2.0)
GIT
remote: https://github.com/manastech/rails-view_components.git
@@ -102,8 +102,8 @@ GEM
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
- addressable (2.8.0)
- public_suffix (>= 2.0.2, < 5.0)
+ addressable (2.8.1)
+ public_suffix (>= 2.0.2, < 6.0)
arel (7.1.4)
aws-sdk (1.67.0)
aws-sdk-v1 (= 1.67.0)
@@ -117,7 +117,7 @@ GEM
backports (3.23.0)
barby (0.6.8)
base58 (0.2.3)
- bcrypt (3.1.16)
+ bcrypt (3.1.18)
bert (1.1.6)
bertrpc (1.3.1)
bert (>= 1.1.0, < 2.0.0)
@@ -125,22 +125,19 @@ GEM
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
builder (3.2.4)
- byebug (3.5.1)
- columnize (~> 0.8)
- debugger-linecache (~> 1.2)
- slop (~> 3.6)
- capybara (2.18.0)
+ byebug (11.1.3)
+ capybara (3.29.0)
addressable
mini_mime (>= 0.1.3)
- nokogiri (>= 1.3.3)
- rack (>= 1.0.0)
- rack-test (>= 0.5.4)
- xpath (>= 2.0, < 4.0)
+ nokogiri (~> 1.8)
+ rack (>= 1.6.0)
+ rack-test (>= 0.6.3)
+ regexp_parser (~> 1.5)
+ xpath (~> 3.2)
capybara-screenshot (1.0.26)
capybara (>= 1.0, < 4)
launchy
- childprocess (0.9.0)
- ffi (~> 1.0, >= 1.0.11)
+ childprocess (3.0.0)
chronic (0.10.2)
chunky_png (1.4.0)
climate_control (0.2.0)
@@ -154,8 +151,7 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.12.2)
- columnize (0.9.0)
- concurrent-ruby (1.1.9)
+ concurrent-ruby (1.1.10)
config (1.7.2)
activesupport (>= 3.0)
deep_merge (~> 1.2, >= 1.2.1)
@@ -164,7 +160,7 @@ GEM
crack (0.4.5)
rexml
crass (1.0.6)
- css_parser (1.7.1)
+ css_parser (1.12.0)
addressable
csv_builder (2.1.3)
actionpack (>= 3.0.0)
@@ -182,10 +178,10 @@ GEM
cucumber-tag_expressions (~> 1.1.0)
gherkin (~> 5.0)
cucumber-expressions (6.0.1)
- cucumber-rails (1.7.0)
- capybara (>= 2.3.0, < 4)
+ cucumber-rails (1.8.0)
+ capybara (>= 2.12, < 4)
cucumber (>= 3.0.2, < 4)
- mime-types (>= 1.17, < 4)
+ mime-types (>= 2.0, < 4)
nokogiri (~> 1.8)
railties (>= 4.2, < 7)
cucumber-tag_expressions (1.1.1)
@@ -194,7 +190,6 @@ GEM
railties (>= 3.1.0)
database_cleaner (1.99.0)
debug_inspector (1.1.0)
- debugger-linecache (1.2.0)
deep_merge (1.2.2)
devise (4.0.3)
bcrypt (~> 3.0)
@@ -219,33 +214,35 @@ GEM
i18n
dropzonejs-rails (0.8.5)
rails (> 3.1)
- dry-configurable (0.7.0)
+ dry-configurable (0.11.6)
concurrent-ruby (~> 1.0)
- dry-container (0.6.0)
+ dry-core (~> 0.4, >= 0.4.7)
+ dry-equalizer (~> 0.2)
+ dry-container (0.7.2)
concurrent-ruby (~> 1.0)
dry-configurable (~> 0.1, >= 0.1.3)
dry-core (0.4.9)
concurrent-ruby (~> 1.0)
- dry-equalizer (0.2.2)
- dry-inflector (0.1.2)
- dry-logic (0.4.2)
- dry-container (~> 0.2, >= 0.2.6)
+ dry-equalizer (0.3.0)
+ dry-inflector (0.2.0)
+ dry-logic (0.6.1)
+ concurrent-ruby (~> 1.0)
dry-core (~> 0.2)
dry-equalizer (~> 0.2)
- dry-types (0.13.4)
+ dry-types (0.14.1)
concurrent-ruby (~> 1.0)
dry-container (~> 0.3)
dry-core (~> 0.4, >= 0.4.4)
dry-equalizer (~> 0.2)
dry-inflector (~> 0.1, >= 0.1.2)
- dry-logic (~> 0.4, >= 0.4.2)
- dry-validation (0.12.3)
+ dry-logic (~> 0.5, >= 0.5)
+ dry-validation (0.13.3)
concurrent-ruby (~> 1.0)
dry-configurable (~> 0.1, >= 0.1.3)
dry-core (~> 0.2, >= 0.2.1)
dry-equalizer (~> 0.2)
- dry-logic (~> 0.4.2)
- dry-types (~> 0.13.1)
+ dry-logic (~> 0.5, >= 0.5.0)
+ dry-types (~> 0.14.0)
elasticsearch (1.1.3)
elasticsearch-api (= 1.1.3)
elasticsearch-transport (= 1.1.3)
@@ -254,21 +251,21 @@ GEM
elasticsearch-transport (1.1.3)
faraday
multi_json
- encryptor (1.3.0)
+ encryptor (2.0.0)
erubis (2.7.0)
et-orbi (1.2.7)
tzinfo
- execjs (2.7.0)
+ execjs (2.8.1)
faker (1.9.1)
i18n (>= 0.7)
- faraday (0.17.5)
+ faraday (0.17.6)
multipart-post (>= 1.2, < 3)
ffaker (2.11.0)
- ffi (1.12.2)
+ ffi (1.15.5)
filewatcher (0.3.6)
trollop (~> 2.0)
- fugit (1.5.2)
- et-orbi (~> 1.1, >= 1.1.8)
+ fugit (1.7.2)
+ et-orbi (~> 1, >= 1.2.7)
raabro (~> 1.4)
gherkin (5.1.0)
globalid (0.4.2)
@@ -289,21 +286,22 @@ GEM
railties (>= 4.0.1)
hashdiff (1.0.1)
hashie (5.0.0)
- html2haml (2.2.0)
+ html2haml (2.3.0)
erubis (~> 2.7.0)
- haml (>= 4.0, < 6)
+ haml (>= 4.0)
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
htmlentities (4.3.4)
- http-cookie (1.0.4)
+ http-accept (1.7.0)
+ http-cookie (1.0.5)
domain_name (~> 0.5)
- i18n (1.5.1)
+ i18n (1.12.0)
concurrent-ruby (~> 1.0)
interception (0.5)
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
- jquery-rails (4.4.0)
+ jquery-rails (4.5.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
@@ -315,10 +313,10 @@ GEM
kaminari (0.17.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
- launchy (2.4.3)
- addressable (~> 2.3)
+ launchy (2.5.0)
+ addressable (~> 2.7)
leaflet-rails (0.7.7)
- letter_opener (1.8.0)
+ letter_opener (1.8.1)
launchy (>= 2.2, < 3)
libv8-node (15.14.0.1)
listen (3.0.8)
@@ -326,39 +324,41 @@ GEM
rb-inotify (~> 0.9, >= 0.9.7)
lodash-rails (3.10.1)
railties (>= 3.1)
- loofah (2.15.0)
+ loofah (2.19.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
machinist (2.0)
mail (2.7.1)
mini_mime (>= 0.1.1)
method_source (1.0.0)
- mime-types (2.99.3)
+ mime-types (3.4.1)
+ mime-types-data (~> 3.2015)
+ mime-types-data (3.2022.0105)
mini_mime (1.1.2)
mini_portile2 (2.4.0)
mini_racer (0.4.0)
libv8-node (~> 15.14.0.0)
minitest (5.15.0)
multi_json (1.15.0)
- multi_test (0.1.2)
+ multi_test (1.1.0)
multi_xml (0.6.0)
- multipart-post (2.1.1)
- mysql2 (0.5.3)
+ multipart-post (2.2.3)
+ mysql2 (0.5.4)
netrc (0.11.0)
- nio4r (2.3.1)
- nokogiri (1.9.1)
+ nio4r (2.5.8)
+ nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
nuntium_api (0.21)
json
rest-client
- oauth2 (1.4.9)
+ oauth2 (1.4.11)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
- rack (>= 1.2, < 3)
+ rack (>= 1.2, < 4)
oj (2.17.2)
- omniauth (1.9.1)
+ omniauth (1.9.2)
hashie (>= 3.4.6)
rack (>= 1.6.2, < 3)
omniauth-google-oauth2 (0.8.2)
@@ -366,39 +366,39 @@ GEM
oauth2 (~> 1.1)
omniauth (~> 1.1)
omniauth-oauth2 (>= 1.6)
- omniauth-oauth2 (1.7.2)
- oauth2 (~> 1.4)
+ omniauth-oauth2 (1.7.3)
+ oauth2 (>= 1.4, < 3)
omniauth (>= 1.9, < 3)
orm_adapter (0.5.0)
- parallel (1.19.2)
- parallel_tests (2.32.0)
+ parallel (1.20.1)
+ parallel_tests (3.5.2)
parallel
- paranoia (2.4.2)
- activerecord (>= 4.0, < 6.1)
- premailer (1.11.1)
+ paranoia (2.4.3)
+ activerecord (>= 4.0, < 6.2)
+ premailer (1.12.1)
addressable
css_parser (>= 1.6.0)
htmlentities (>= 4.0.0)
premailer-rails (1.9.7)
actionmailer (>= 3, < 6)
premailer (~> 1.7, >= 1.7.9)
- pry (0.14.1)
+ pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
- pry-byebug (2.0.0)
- byebug (~> 3.4)
- pry (~> 0.10)
+ pry-byebug (3.9.0)
+ byebug (~> 11.0)
+ pry (~> 0.13.0)
pry-rescue (1.5.2)
interception (>= 0.5)
pry (>= 0.12.0)
pry-stack_explorer (0.4.12)
binding_of_caller (~> 0.7)
pry (~> 0.13)
- public_suffix (3.1.1)
+ public_suffix (4.0.7)
puma (3.12.6)
raabro (1.4.0)
- rack (2.1.4)
- rack-protection (2.2.0)
+ rack (2.1.4.1)
+ rack-protection (2.2.2)
rack
rack-test (0.6.3)
rack (>= 1.0)
@@ -422,8 +422,8 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
- rails-html-sanitizer (1.4.2)
- loofah (~> 2.3)
+ rails-html-sanitizer (1.4.4)
+ loofah (~> 2.19, >= 2.19.1)
rails-i18n (5.1.3)
i18n (>= 0.7, < 2)
railties (>= 5.0, < 6)
@@ -434,11 +434,11 @@ GEM
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.5.0)
- rb-fsevent (0.11.1)
+ rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rchardet (1.8.0)
- react-rails (1.3.3)
+ react-rails (1.6.2)
babel-transpiler (>= 0.7.0)
coffee-script-source (~> 1.8)
connection_pool
@@ -448,15 +448,17 @@ GEM
recaptcha (4.9.0)
json
redis (3.3.5)
+ regexp_parser (1.8.2)
request_store (1.5.1)
rack (>= 1.4)
- responders (2.4.1)
- actionpack (>= 4.2.0, < 6.0)
- railties (>= 4.2.0, < 6.0)
- rest-client (1.8.0)
+ responders (3.0.1)
+ actionpack (>= 5.0)
+ railties (>= 5.0)
+ rest-client (2.1.0)
+ http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
- mime-types (>= 1.16, < 3.0)
- netrc (~> 0.7)
+ mime-types (>= 1.16, < 4.0)
+ netrc (~> 0.8)
rexml (3.2.5)
rqrcode (0.10.1)
chunky_png (~> 1.0)
@@ -483,10 +485,10 @@ GEM
rspec-mocks (~> 3.9.0)
rspec-support (~> 3.9.0)
rspec-support (3.9.4)
- ruby_parser (3.18.1)
+ ruby_parser (3.19.1)
sexp_processor (~> 4.16)
- rubyzip (1.3.0)
- rufus-scheduler (3.8.1)
+ rubyzip (2.3.2)
+ rufus-scheduler (3.8.2)
fugit (~> 1.1, >= 1.1.6)
sass (3.7.4)
sass-listen (~> 4.0.0)
@@ -499,12 +501,12 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
- selenium-webdriver (3.141.0)
- childprocess (~> 0.5)
- rubyzip (~> 1.2, >= 1.2.2)
+ selenium-webdriver (3.142.7)
+ childprocess (>= 0.5, < 4.0)
+ rubyzip (>= 1.2.2)
sentry-raven (2.13.0)
faraday (>= 0.7.6, < 1.0)
- sexp_processor (4.16.0)
+ sexp_processor (4.16.1)
sidekiq (4.2.10)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
@@ -513,17 +515,16 @@ GEM
sidekiq-cron (0.6.3)
rufus-scheduler (>= 3.3.0)
sidekiq (>= 4.2.1)
- simplecov (0.17.1)
+ simplecov (0.18.5)
docile (~> 1.1)
- json (>= 1.8, < 3)
- simplecov-html (~> 0.10.0)
- simplecov-html (0.10.2)
- site_prism (2.17.1)
- addressable (~> 2.4)
- capybara (>= 2.15, < 3.6)
- slop (3.6.0)
- spring (2.0.2)
- activesupport (>= 4.2)
+ simplecov-html (~> 0.11)
+ simplecov-html (0.12.3)
+ site_prism (3.6)
+ addressable (~> 2.5)
+ capybara (>= 3.8, <= 3.29)
+ site_prism-all_there (>= 0.3.1, < 1.0)
+ site_prism-all_there (0.3.2)
+ spring (2.1.1)
spring-commands-parallel-tests (1.0.1)
spring (>= 0.9.1)
spring-commands-rspec (1.0.4)
@@ -540,27 +541,27 @@ GEM
sprockets (>= 3.0.0)
thor (1.2.1)
thread_safe (0.3.6)
- tilt (2.0.10)
+ tilt (2.0.11)
timecop (0.9.5)
trollop (2.9.10)
turbolinks (2.5.4)
coffee-rails
- tzinfo (1.2.9)
+ tzinfo (1.2.10)
thread_safe (~> 0.1)
uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
unf (0.1.4)
unf_ext
- unf_ext (0.0.8)
- warden (1.2.7)
- rack (>= 1.0)
+ unf_ext (0.0.8.2)
+ warden (1.2.9)
+ rack (>= 2.0.9)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
- webmock (1.23.0)
+ webmock (2.3.2)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
@@ -569,9 +570,9 @@ GEM
websocket-extensions (0.1.5)
whenever (1.0.0)
chronic (>= 0.6.3)
- wicked_pdf (2.1.0)
+ wicked_pdf (2.6.3)
activesupport
- xpath (3.1.0)
+ xpath (3.2.0)
nokogiri (~> 1.8)
PLATFORMS
@@ -581,7 +582,7 @@ DEPENDENCIES
aws-sdk (~> 1.6)
barby (~> 0.6)
base58 (~> 0.1)
- capybara (~> 2.4)
+ capybara (~> 3.29.0)
capybara-screenshot (~> 1.0)
cdx!
cdx-api-elasticsearch!
@@ -592,13 +593,13 @@ DEPENDENCIES
d3_rails (~> 3.5.6)
database_cleaner (~> 1.99)
devise (~> 4.0.0)
- devise-security (<= 0.12.0)
+ devise-security (< 0.15.0)
devise_invitable (~> 1.5)
doorkeeper (~> 4.2.0)
dotiw (~> 3.0)
dropzonejs-rails (~> 0.8.4)
elasticsearch (~> 1.0)
- encryptor (~> 1.3)
+ encryptor (~> 2.0)
faker (< 1.9.2)
ffaker (< 2.12.0)
geojson_import!
@@ -618,18 +619,18 @@ DEPENDENCIES
machinist (~> 2.0)
mini_racer
mysql2 (~> 0.3)
- nokogiri (~> 1.6, < 1.10.0)
+ nokogiri (~> 1.6, < 1.11.0)
nuntium_api (~> 0.21)
oj (~> 2.12, < 2.17.3)
omniauth (~> 1.2)
omniauth-google-oauth2 (~> 0.2)
paperclip!
- parallel (~> 1.19.2)
- parallel_tests (~> 2.32.0)
- paranoia (<= 2.4.2)
+ parallel (~> 1.20.0)
+ parallel_tests (~> 3.5.1)
+ paranoia (< 2.5.0)
poirot_rails!
premailer-rails (< 1.10)
- pry-byebug (< 2.7.0)
+ pry-byebug (< 3.10.0)
pry-rescue
pry-stack_explorer
puma (~> 3.0)
@@ -640,21 +641,21 @@ DEPENDENCIES
rails-i18n (~> 5.0)
rake (~> 10.5.0)
rchardet (~> 1.6)
- react-rails (~> 1.3.2)
+ react-rails (~> 1.6.2)
recaptcha
- rest-client (~> 1.8)
+ rest-client (~> 2.1)
rqrcode (~> 0.10)
rspec (~> 3.3)
rspec-collection_matchers (~> 1.1)
rspec-rails (~> 3.3)
rubyzip (>= 1.0.0)
sass-rails (~> 5.0, < 5.0.8)
- selenium-webdriver (< 4.0)
+ selenium-webdriver
sentry-raven (~> 2.13)
sidekiq (~> 4.2)
sidekiq-cron (~> 0.3)
simplecov
- site_prism (~> 2.17)
+ site_prism (~> 3.6.0)
spring
spring-commands-parallel-tests
spring-commands-rspec
@@ -665,7 +666,7 @@ DEPENDENCIES
uglifier (~> 2.7)
view_components!
web-console (< 4.0)
- webmock (~> 1.23.0)
+ webmock (~> 2.3.1)
whenever (~> 1.0)
wicked_pdf (~> 2.1)
diff --git a/app/assets/javascripts/box_selector.js.jsx b/app/assets/javascripts/box_selector.js.jsx
index 05f6f1ff9..4ef2fe969 100644
--- a/app/assets/javascripts/box_selector.js.jsx
+++ b/app/assets/javascripts/box_selector.js.jsx
@@ -40,8 +40,7 @@ var BoxSelector = React.createClass({
}
- const listItems = this.state.boxes.map(renderBox)
- return ({ listItems });
+ return this.state.boxes.map(renderBox)
},
removeBox: function(box) {
@@ -178,13 +177,6 @@ var BoxSelector = React.createClass({
)
},
- renderError: function() {
- let error = this.state.error;
- return (
- { error }
- )
- },
-
render: function() {
return (
@@ -193,13 +185,13 @@ var BoxSelector = React.createClass({
{this.renderBoxes()}
-
- {this.renderError()}
+ {this.state.error}
diff --git a/app/assets/javascripts/cdx_console_logs.js b/app/assets/javascripts/cdx_console_logs.js
new file mode 100644
index 000000000..4d546a8b6
--- /dev/null
+++ b/app/assets/javascripts/cdx_console_logs.js
@@ -0,0 +1,24 @@
+(function() {
+ var originals = {};
+ window.__cdx_logs = [];
+
+ function capture_logs(name) {
+ originals[name] = window.console[name];
+
+ window.console[name] = function () {
+ var args = Array.prototype.map.call(arguments, function (x) {
+ return x.toString();
+ });
+ window.__cdx_logs.push([name.toUpperCase()].concat(args));
+
+ return originals[name].apply(null, arguments);
+ }
+ }
+
+ capture_logs("debug");
+ capture_logs("error");
+ capture_logs("info");
+ capture_logs("log");
+ capture_logs("trace");
+ capture_logs("warn");
+})();
diff --git a/app/assets/javascripts/components/bar_chart.js.jsx b/app/assets/javascripts/components/bar_chart.js.jsx
index 9f8cc1207..f3dd8b2b5 100644
--- a/app/assets/javascripts/components/bar_chart.js.jsx
+++ b/app/assets/javascripts/components/bar_chart.js.jsx
@@ -7,17 +7,10 @@ var BarChart = React.createClass({
}
},
- componentDidMount: function() {
- if (!this.props.width) {
- this.setProps({
- width: this.refs.svg.getDOMNode().clientWidth
- })
- }
- },
-
render: function() {
- if (this.props.width) {
- var chartWidth = this.props.width - this.props.margin.left - this.props.margin.right,
+ var width = this.props.width || (this.refs.svg && this.refs.svg.clientWidth);
+ if (width) {
+ var chartWidth = width - this.props.margin.left - this.props.margin.right,
chartHeight = this.props.height - this.props.margin.top - this.props.margin.bottom;
var x = d3.scale.ordinal()
@@ -31,7 +24,7 @@ var BarChart = React.createClass({
.orient("bottom");
var rotateLabels = function(dom) {
- d3.select(dom.getDOMNode()).selectAll("text")
+ d3.select(ReactDOM.findDOMNode(dom)).selectAll("text")
.attr("y", 0)
.attr("x", 9)
.attr("dy", ".35em")
@@ -50,8 +43,8 @@ var BarChart = React.createClass({
}
var svgProps = {}
- if (this.props.width) {
- svgProps.viewBox = "0 0 " + this.props.width + " " + this.props.height
+ if (width) {
+ svgProps.viewBox = "0 0 " + width + " " + this.props.height
}
return (
@@ -60,7 +53,7 @@ var BarChart = React.createClass({
height={this.props.height}
ref="svg"
{...svgProps} >
- { this.props.width ?
+ { width ?
{/* Bars */}
@@ -82,12 +75,12 @@ var BarChart = React.createClass({
{/* X Axis */}
+ ref={function(ref) { if (ref) { d3.select(ref).call(xAxis); rotateLabels(ref); }}} />
{/* Y Axis */}
+ ref={function(ref) { if (ref) { d3.select(ref).call(yAxis) }}} >
{this.props.y_label}
diff --git a/app/assets/javascripts/components/cdx_select.js.jsx b/app/assets/javascripts/components/cdx_select.js.jsx
index 6c33547ee..017dc044a 100644
--- a/app/assets/javascripts/components/cdx_select.js.jsx
+++ b/app/assets/javascripts/components/cdx_select.js.jsx
@@ -9,7 +9,7 @@ var CdxSelect = React.createClass({
window.setTimeout(function(){
// this is deferred so a new input with the new value
// is rendered by the time the change event is triggered
- $('input:hidden', this.getDOMNode()).trigger('change');
+ $('input:hidden', ReactDOM.findDOMNode(this)).trigger('change');
}.bind(this), 0);
if(this.props.onChange) {
this.props.onChange(newValue, this);
diff --git a/app/assets/javascripts/components/encounter_form.js.jsx b/app/assets/javascripts/components/encounter_form.js.jsx
index f82d0043f..9a07194d5 100644
--- a/app/assets/javascripts/components/encounter_form.js.jsx
+++ b/app/assets/javascripts/components/encounter_form.js.jsx
@@ -37,7 +37,7 @@ var BaseEncounterForm = {
},
validateAndSetManualEntry: function (event) {
- var sampleId = React.findDOMNode(this.refs.manualSampleEntry).value;
+ var sampleId = ReactDOM.findDOMNode(this.refs.manualSampleEntry).value;
if(this.state.encounter.new_samples.filter(function(el){return el.entity_id == sampleId}).length > 0) {
// Error handling as done in the ajax responses
alert("This sample has already been added");
diff --git a/app/assets/javascripts/components/location_select.js.jsx b/app/assets/javascripts/components/location_select.js.jsx
index 1a1803fc5..ddb9b4b4a 100644
--- a/app/assets/javascripts/components/location_select.js.jsx
+++ b/app/assets/javascripts/components/location_select.js.jsx
@@ -65,7 +65,7 @@ var LocationSelect = React.createClass({
window.setTimeout(function(){
// this is deferred so a new input with the new value
// is rendered by the time the change event is triggered
- $('input:hidden', this.getDOMNode()).trigger('change');
+ $('input:hidden', ReactDOM.getDOMNode(this)).trigger('change');
}.bind(this), 0);
var _this = this;
diff --git a/app/assets/javascripts/components/modal.js.jsx.erb b/app/assets/javascripts/components/modal.js.jsx.erb
index 7ee8d24a0..1fe74363b 100644
--- a/app/assets/javascripts/components/modal.js.jsx.erb
+++ b/app/assets/javascripts/components/modal.js.jsx.erb
@@ -16,7 +16,7 @@ var Modal = React.createClass({
},
hideOnOuterClick: function(event) {
- if (this.getDOMNode() == event.target)
+ if (ReactDOM.findDOMNode(this) == event.target)
this.hide();
},
diff --git a/app/assets/javascripts/components/pie_chart.js.jsx b/app/assets/javascripts/components/pie_chart.js.jsx
index bdc0f2699..060c4d1d4 100644
--- a/app/assets/javascripts/components/pie_chart.js.jsx
+++ b/app/assets/javascripts/components/pie_chart.js.jsx
@@ -7,20 +7,15 @@ var PieChart = React.createClass({
}
},
- componentDidMount: function() {
- if (!this.props.width) {
- this.setProps({
- width: this.refs.svg.getDOMNode().clientWidth
- })
- }
- },
-
buildColorScale: function () {
return d3.scale.ordinal().range(this.props.colors);
},
componentDidMount: function () {
- var svg = d3.select(this.refs.svg.getDOMNode());
+ if (!this.state) this.state = {};
+ this.state.width = this.props.width || (this.refs.svg && this.refs.svg.clientWidth);
+
+ var svg = d3.select(this.refs.svg);
var data = this.props.data;
var total = _.sum(data, 'value');
@@ -91,7 +86,7 @@ var PieChart = React.createClass({
},
render: function() {
- var radius = Math.min(this.props.width || this.props.height, this.props.height) / 2;
+ var radius = Math.min((this.state && this.state.width) || this.props.height, this.props.height) / 2;
var color = this.buildColorScale();
@@ -108,8 +103,8 @@ var PieChart = React.createClass({
.rangePoints([-25 * (this.props.data.length - 1) / 2, 25 * (this.props.data.length - 1) / 2]);
var svgProps = {}
- if (this.props.width) {
- svgProps.viewBox = "0 0 " + this.props.width + " " + this.props.height
+ if (this.state && this.state.width) {
+ svgProps.viewBox = "0 0 " + this.state.width + " " + this.props.height
}
return (
diff --git a/app/models/concerns/resource.rb b/app/models/concerns/resource.rb
index ba278529e..61a234044 100644
--- a/app/models/concerns/resource.rb
+++ b/app/models/concerns/resource.rb
@@ -49,7 +49,7 @@ def supports_condition?(key)
end
def supports_identifier?(key)
- key.blank? || key.kind_of?(Fixnum) || key.strip.match(/\A\d+\z/)
+ key.blank? || key.kind_of?(Integer) || key.strip.match(/\A\d+\z/)
end
def resource_name_prefix
diff --git a/app/models/message_encryption.rb b/app/models/message_encryption.rb
index 232013d9e..af36e584d 100644
--- a/app/models/message_encryption.rb
+++ b/app/models/message_encryption.rb
@@ -1,16 +1,17 @@
module MessageEncryption
require 'securerandom'
+ ALGORITHM = "aes-256-cbc" # TODO: migrate to aes-256-gcm (default in encryptor 2.x)
DEFAULT_IV = "\xD7\xCA\xD5\x9D\x1D\xC0I\x01Sf\xC8\xFBa\x88\xE1\x03"
DEFAULT_SALT = "1403203711"
def self.encrypt string
- Encryptor.encrypt string, :key => secret_key, :iv => iv, :salt => salt unless string.blank?
+ Encryptor.encrypt string, :algorithm => ALGORITHM, :key => secret_key, :iv => iv, :salt => salt unless string.blank?
end
def self.decrypt string
unless string.blank?
- Encryptor.decrypt(string, :key => secret_key, :iv => iv, :salt => salt)
+ Encryptor.decrypt(string, :algorithm => ALGORITHM, :key => secret_key, :iv => iv, :salt => salt)
else
''
end
@@ -26,8 +27,8 @@ def self.secure_random length
def self.reencrypt(string, old_key:, old_iv: DEFAULT_IV, old_salt: DEFAULT_SALT, new_key:, new_iv: DEFAULT_IV, new_salt: DEFAULT_SALT)
return '' if string.blank?
- plain = Encryptor.decrypt(string, :key => old_key, :iv => old_iv, :salt => old_salt)
- Encryptor.encrypt(plain, :key => new_key, :iv => new_iv, :salt => new_salt) unless plain.blank?
+ plain = Encryptor.decrypt(string, :algorithm => ALGORITHM, :key => old_key, :iv => old_iv, :salt => old_salt)
+ Encryptor.encrypt(plain, :algorithm => ALGORITHM, :key => new_key, :iv => new_iv, :salt => new_salt) unless plain.blank?
end
private
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index a1ea5f1d8..31d42afa8 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -4,6 +4,7 @@
%title Connected Diagnostics Platform
= Gon::Base.render_data({})
= stylesheet_link_tag "application", :media => "all"
+ = javascript_include_tag "cdx_console_logs" if Rails.env.test? && defined?(Capybara) && ENV["BROWSER"] != "chrome"
= javascript_include_tag "application"
= csrf_meta_tags
%body{class: @body_class}
diff --git a/app/views/layouts/clean.haml b/app/views/layouts/clean.haml
index 3843468db..38d0eba79 100644
--- a/app/views/layouts/clean.haml
+++ b/app/views/layouts/clean.haml
@@ -4,6 +4,7 @@
%title Connected Diagnostics Platform
= Gon::Base.render_data({})
= stylesheet_link_tag "application", :media => "all"
+ = javascript_include_tag "cdx_console_logs" if Rails.env.test? && defined?(Capybara) && ENV["BROWSER"] != "chrome"
= javascript_include_tag "application"
= csrf_meta_tags
%body.devise{class: @body_class}
diff --git a/app/views/layouts/devise.haml b/app/views/layouts/devise.haml
index 15a49c61f..79599c88e 100644
--- a/app/views/layouts/devise.haml
+++ b/app/views/layouts/devise.haml
@@ -4,6 +4,7 @@
%title Connected Diagnostics Platform
= Gon::Base.render_data({})
= stylesheet_link_tag "application", :media => "all"
+ = javascript_include_tag "cdx_console_logs" if Rails.env.test? && defined?(Capybara) && ENV["BROWSER"] != "chrome"
= javascript_include_tag "application"
= csrf_meta_tags
%body.devise{class: @body_class}
diff --git a/docker-compose.yml b/docker-compose.yml
index 409a3cc9f..301dadafc 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -27,11 +27,14 @@ services:
- elasticsearch
- redis
command: /bin/sh -c './bin/rails s -b 0.0.0.0'
+ extra_hosts:
+ - "host.docker.internal:host-gateway"
selenium:
build:
context: .
dockerfile: Dockerfile.selenium
+ command: ['/usr/bin/geckodriver', '--host', '0.0.0.0']
working_dir: /src
volumes:
- .:/src # we mount the source to be able to attach fixture files
diff --git a/docker/web-run b/docker/web-run
index 8e68c5e72..ad9635a98 100755
--- a/docker/web-run
+++ b/docker/web-run
@@ -1,4 +1,4 @@
#!/bin/bash
source /etc/envvars
cd /app
-exec su -p -c "bundle exec whenever --update-crontab && bundle exec puma $PUMA_OPTIONS -e $RAILS_ENV -b unix:///app/tmp/app.sock" app
+exec su -p -c "bundle exec whenever --update-crontab && bundle exec puma $PUMA_OPTIONS -e $RAILS_ENV" app
diff --git a/features/support/page_objects/cdx_page_helper.rb b/features/support/page_objects/cdx_page_helper.rb
index 9b7fd0300..1a0237e46 100644
--- a/features/support/page_objects/cdx_page_helper.rb
+++ b/features/support/page_objects/cdx_page_helper.rb
@@ -2,7 +2,9 @@ module CdxPageHelper
# source: https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara
def wait_for_ajax
Timeout.timeout(Capybara.default_max_wait_time) do
- loop until finished_all_ajax_requests?
+ until finished_all_ajax_requests?
+ sleep 0.01
+ end
end
end
diff --git a/features/support/page_objects/cdx_select.rb b/features/support/page_objects/cdx_select.rb
index 469da5a7e..1de17ca02 100644
--- a/features/support/page_objects/cdx_select.rb
+++ b/features/support/page_objects/cdx_select.rb
@@ -40,13 +40,18 @@ def options
def select_elem
@select_elem ||= begin
- elem = root_element
+ if root_element[:class].split(/\s+/).include?("Select")
+ root_element
+ else
+ # search until a parent's descendant matches '.Select' (very slow)
+ parent = root_element
- while elem.all(".Select").empty?
- elem = elem.find(:xpath, '..')
- end
+ until element = parent.first(".Select", minimum: 0, maximum: 1)
+ parent = parent.find(:xpath, "..")
+ end
- elem.find(".Select")
+ element
+ end
end
end
end
diff --git a/frontend_dependencies.txt b/frontend_dependencies.txt
new file mode 100644
index 000000000..5db3b8d74
--- /dev/null
+++ b/frontend_dependencies.txt
@@ -0,0 +1,3 @@
+react v0.14
+react-select v0.7.0
+react-input-autosize v0.6.0
diff --git a/spec/lib/sms_spec.rb b/spec/lib/sms_spec.rb
index fb0b3268d..d9253d3cc 100644
--- a/spec/lib/sms_spec.rb
+++ b/spec/lib/sms_spec.rb
@@ -3,13 +3,15 @@
describe "SMS" do
before(:each) do
- stub_request(:get, "https://CDx%2FCDx-Dev:cdx123cdx@nuntium.instedd.org/CDx/CDx-Dev/send_ao?body=welcome%20mr%20smith&from=sms://442393162302&to=sms://123444").
- with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}).
- to_return(:status => 200, :body => "{'id'=>'2051719', 'guid'=>'69abea50-840e-50a0-77f9-547b38b2943e', 'token'=>'76beefab-9686-cd17-a3bc-d79dec6e0544'}", :headers => {})
+ authorization = Base64.urlsafe_encode64("CDx/CDx-Dev:cdx123cdx")
- stub_request(:get, "https://CDx%2FCDx-Dev:cdx123cdx@nuntium.instedd.org/CDx/CDx-Dev/send_ao?body=welcome%20mr%20smith&from=sms://442393162302&to=sms://456777").
- with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}).
- to_return(:status => 200, :body => "{'id'=>'2051719', 'guid'=>'69abea50-840e-50a0-77f9-547b38b2943e', 'token'=>'76beefab-9686-cd17-a3bc-d79dec6e0544'}", :headers => {})
+ stub_request(:get, "https://nuntium.instedd.org/CDx/CDx-Dev/send_ao?body=welcome%20mr%20smith&from=sms://442393162302&to=sms://123444")
+ .with(:headers => {'Authorization' => "Basic #{authorization}", 'Content-Type'=>'application/json'})
+ .to_return(:status => 200, :body => "{'id'=>'2051719', 'guid'=>'69abea50-840e-50a0-77f9-547b38b2943e', 'token'=>'76beefab-9686-cd17-a3bc-d79dec6e0544'}", :headers => {})
+
+ stub_request(:get, "https://nuntium.instedd.org/CDx/CDx-Dev/send_ao?body=welcome%20mr%20smith&from=sms://442393162302&to=sms://456777")
+ .with(:headers => {'Authorization' => "Basic #{authorization}", 'Content-Type'=>'application/json'})
+ .to_return(:status => 200, :body => "{'id'=>'2051719', 'guid'=>'69abea50-840e-50a0-77f9-547b38b2943e', 'token'=>'76beefab-9686-cd17-a3bc-d79dec6e0544'}", :headers => {})
end
context "sms operation" do
diff --git a/spec/models/subscriber_spec.rb b/spec/models/subscriber_spec.rb
index 426d1d77e..e6364a5b6 100644
--- a/spec/models/subscriber_spec.rb
+++ b/spec/models/subscriber_spec.rb
@@ -42,7 +42,7 @@
fields = ["test.assays", "patient.gender"]
url = "http://subscriber/cdp_trigger"
subscriber = Subscriber.make! fields: fields, url: url, filter: filter, verb: 'GET'
- callback_query = "http://subscriber/cdp_trigger?patient%5Bgender%5D=male&test%5Bassays%5D%5B0%5D%5Bcondition%5D=mtb&test%5Bassays%5D%5B1%5D%5Bname%5D=mtb&test%5Bassays%5D%5B2%5D%5Bresult%5D=positive"
+ callback_query = "http://subscriber/cdp_trigger?patient%5Bgender%5D=male&test%5Bassays%5D%5B0%5D%5Bcondition%5D=mtb&test%5Bassays%5D%5B0%5D%5Bname%5D=mtb&test%5Bassays%5D%5B0%5D%5Bresult%5D=positive"
callback_request = stub_request(:get, callback_query).to_return(status: 200, body: "", headers: {})
perform_enqueued_jobs { submit_test }
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 3d1fb622b..c87a88a1e 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -24,7 +24,10 @@
Dir[Rails.root.join("features/support/page_objects/*.rb")].each {|f| require f}
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
-WebMock.disable_net_connect!(:allow_localhost => true, allow: ALLOWED_WEBMOCK_HOSTS.compact)
+WebMock.disable_net_connect!(
+ allow_localhost: true,
+ allow: ALLOWED_WEBMOCK_HOSTS.compact
+)
# This is to make machinist work with Rails 4
class ActiveRecord::Reflection::AssociationReflection
diff --git a/spec/support/blueprints.rb b/spec/support/blueprints.rb
index 8a58bd8e6..72880e147 100644
--- a/spec/support/blueprints.rb
+++ b/spec/support/blueprints.rb
@@ -8,6 +8,44 @@
'bCAzqtIUUJOMKz4lHn5Os/d8temlYskaKQ1n+FuX5qJXNr1SW8euH72fjQndu78DCwVNwnnrG+nEe3a9m2QwL5xn'+
'X8f1ohAZ9IG41hwIOvB5UcrFenqYIpMPBCCOnizUcyIFJhegJDWh2oWlBo041emGOX3VCRjtGug3 fbulgarelli@Manass-MacBook-2.local'
+# NOTE: fixes compatibility with Ruby 2.4 (Fixnum is deprecated, use Integer)
+module Machinist
+ class Lathe
+ protected
+
+ def make_attribute(attribute, args, &block) #:nodoc:
+ count = args.shift if args.first.is_a?(Integer)
+ if count
+ Array.new(count) { make_one_value(attribute, args, &block) }
+ else
+ make_one_value(attribute, args, &block)
+ end
+ end
+ end
+
+ module Machinable
+ private
+
+ def decode_args_to_make(*args) #:nodoc:
+ shift_arg = lambda {|klass| args.shift if args.first.is_a?(klass) }
+ count = shift_arg[Integer]
+ name = shift_arg[Symbol] || :master
+ attributes = shift_arg[Hash] || {}
+ raise ArgumentError.new("Couldn't understand arguments") unless args.empty?
+
+ @blueprints ||= {}
+ blueprint = @blueprints[name]
+ raise NoBlueprintError.new(self, name) unless blueprint
+
+ if count.nil?
+ yield(blueprint, attributes)
+ else
+ Array.new(count) { yield(blueprint, attributes) }
+ end
+ end
+ end
+end
+
User.blueprint do
email { FFaker::Internet.email }
password { FFaker::Internet.password }
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index a7405955d..40c060714 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -23,6 +23,15 @@
config.server_port = ENV["SERVER_PORT"].to_i
end
+# Resolve domain name as IP (mainly for geckodriver to accept any connections)
+begin
+ selenium_uri = URI(ENV["SELENIUM_URL"])
+ selenium_uri.host = Addrinfo.tcp(selenium_uri.host, selenium_uri.port).ip_address
+ ENV["SELENIUM_URL"] = selenium_uri.to_s
+rescue SocketError
+ STDERR.puts "WARNING: can't reach selenium server on #{ENV["SELENIUM_URL"]}"
+end
+
if defined?(ALLOWED_WEBMOCK_HOSTS)
ALLOWED_WEBMOCK_HOSTS << /http:\/\/#{Capybara.server_host}:#{Capybara.server_port}/
ALLOWED_WEBMOCK_HOSTS << /^#{Regexp.escape(ENV["SELENIUM_URL"])}/
@@ -51,12 +60,6 @@
# quickly in the DOM after submitting a form for example, by introducing an
# implicit 5 seconds timeout to continuously retry the finder.
#
-# We must also tell SitePrism to respect this implicit wait time.
-#
# WARNING: this also affects matchers that want to verify that an element
# doesn't exist, in which case you should override the wait time!
-Capybara.default_max_wait_time = 5
-
-SitePrism.configure do |config|
- config.use_implicit_waits = true
-end
+Capybara.default_max_wait_time = 2
diff --git a/spec/support/feature_spec_helpers.rb b/spec/support/feature_spec_helpers.rb
index 5bc61a50f..9265b8c93 100644
--- a/spec/support/feature_spec_helpers.rb
+++ b/spec/support/feature_spec_helpers.rb
@@ -4,6 +4,19 @@ module FeatureSpecHelpers
included do
metadata[:js] = true
metadata[:elasticsearch] = true
+
+ after(:each) do
+ next unless session = Capybara.current_session
+
+ if session.driver.respond_to?(:log)
+ session.driver.browser.manage.logs.get(:browser)
+ .each { |log| puts "JS: #{log.level} #{log.message}" }
+ else
+ # geckodriver doesn't implement the log interface (sigh)
+ session.execute_script("return window.__cdx_logs;")
+ &.each { |log| puts "JS: #{log.join(" ")}" }
+ end
+ end
end
def process(args = {})
diff --git a/vendor/assets/javascripts/react-input-autosize.js b/vendor/assets/javascripts/react-input-autosize.js
index 121b1aed6..d321998d8 100755
--- a/vendor/assets/javascripts/react-input-autosize.js
+++ b/vendor/assets/javascripts/react-input-autosize.js
@@ -4,6 +4,7 @@
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = (window.React);
+var ReactDOM = (window.ReactDOM);
var sizerStyle = { position: 'absolute', visibility: 'hidden', height: 0, width: 0, overflow: 'scroll', whiteSpace: 'nowrap' };
@@ -42,27 +43,27 @@ var AutosizeInput = React.createClass({
if (!this.isMounted() || !window.getComputedStyle) {
return;
}
- var inputStyle = window.getComputedStyle(React.findDOMNode(this.refs.input));
- var widthNode = React.findDOMNode(this.refs.sizer);
+ var inputStyle = window.getComputedStyle(ReactDOM.findDOMNode(this.refs.input));
+ var widthNode = ReactDOM.findDOMNode(this.refs.sizer);
widthNode.style.fontSize = inputStyle.fontSize;
widthNode.style.fontFamily = inputStyle.fontFamily;
widthNode.style.letterSpacing = inputStyle.letterSpacing;
if (this.props.placeholder) {
- var placeholderNode = React.findDOMNode(this.refs.placeholderSizer);
+ var placeholderNode = ReactDOM.findDOMNode(this.refs.placeholderSizer);
placeholderNode.style.fontSize = inputStyle.fontSize;
placeholderNode.style.fontFamily = inputStyle.fontFamily;
placeholderNode.style.letterSpacing = inputStyle.letterSpacing;
}
},
updateInputWidth: function updateInputWidth() {
- if (!this.isMounted() || typeof React.findDOMNode(this.refs.sizer).scrollWidth === 'undefined') {
+ if (!this.isMounted() || typeof ReactDOM.findDOMNode(this.refs.sizer).scrollWidth === 'undefined') {
return;
}
var newInputWidth;
if (this.props.placeholder) {
- newInputWidth = Math.max(React.findDOMNode(this.refs.sizer).scrollWidth, React.findDOMNode(this.refs.placeholderSizer).scrollWidth) + 2;
+ newInputWidth = Math.max(ReactDOM.findDOMNode(this.refs.sizer).scrollWidth, ReactDOM.findDOMNode(this.refs.placeholderSizer).scrollWidth) + 2;
} else {
- newInputWidth = React.findDOMNode(this.refs.sizer).scrollWidth + 2;
+ newInputWidth = ReactDOM.findDOMNode(this.refs.sizer).scrollWidth + 2;
}
if (newInputWidth < this.props.minWidth) {
newInputWidth = this.props.minWidth;
@@ -77,10 +78,10 @@ var AutosizeInput = React.createClass({
return this.refs.input;
},
focus: function focus() {
- React.findDOMNode(this.refs.input).focus();
+ ReactDOM.findDOMNode(this.refs.input).focus();
},
select: function select() {
- React.findDOMNode(this.refs.input).select();
+ ReactDOM.findDOMNode(this.refs.input).select();
},
render: function render() {
var escapedValue = (this.props.value || '').replace(/\&/g, '&').replace(/ /g, ' ').replace(/\/g, '>');
@@ -107,4 +108,4 @@ var AutosizeInput = React.createClass({
module.exports = AutosizeInput;
},{}]},{},[1])(1)
-});
\ No newline at end of file
+});
diff --git a/vendor/assets/javascripts/react-select.js b/vendor/assets/javascripts/react-select.js
index e132f6992..3611bef49 100755
--- a/vendor/assets/javascripts/react-select.js
+++ b/vendor/assets/javascripts/react-select.js
@@ -70,6 +70,7 @@ module.exports = Option;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
+var ReactDOM = (typeof window !== "undefined" ? window['ReactDOM'] : typeof global !== "undefined" ? global['ReactDOM'] : null);
var Input = (typeof window !== "undefined" ? window['AutosizeInput'] : typeof global !== "undefined" ? global['AutosizeInput'] : null);
var classes = (typeof window !== "undefined" ? window['classNames'] : typeof global !== "undefined" ? global['classNames'] : null);
var Value = require('./Value');
@@ -192,8 +193,8 @@ var Select = React.createClass({
if (!_this.state.isOpen) {
return;
}
- var menuElem = React.findDOMNode(_this.refs.selectMenuContainer);
- var controlElem = React.findDOMNode(_this.refs.control);
+ var menuElem = ReactDOM.findDOMNode(_this.refs.selectMenuContainer);
+ var controlElem = ReactDOM.findDOMNode(_this.refs.control);
var eventOccuredOutsideMenu = _this.clickedOutsideElement(menuElem, event);
var eventOccuredOutsideControl = _this.clickedOutsideElement(controlElem, event);
@@ -273,8 +274,8 @@ var Select = React.createClass({
}
if (this._focusedOptionReveal) {
if (this.refs.focused && this.refs.menu) {
- var focusedDOM = React.findDOMNode(this.refs.focused);
- var menuDOM = React.findDOMNode(this.refs.menu);
+ var focusedDOM = ReactDOM.findDOMNode(this.refs.focused);
+ var menuDOM = ReactDOM.findDOMNode(this.refs.menu);
var focusedRect = focusedDOM.getBoundingClientRect();
var menuRect = menuDOM.getBoundingClientRect();
@@ -420,7 +421,7 @@ var Select = React.createClass({
getInputNode: function getInputNode() {
var input = this.refs.input;
- return this.props.searchable ? input : React.findDOMNode(input);
+ return this.props.searchable ? input : ReactDOM.findDOMNode(input);
},
fireChangeEvent: function fireChangeEvent(newState) {
@@ -979,7 +980,7 @@ var Select = React.createClass({
module.exports = Select;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./Option":1,"./SingleValue":3,"./Value":4}],3:[function(require,module,exports){
+},{"./Option":1,"./SingleValue":3,"./Value":4,"react-dom":undefined}],3:[function(require,module,exports){
(function (global){
'use strict';
@@ -1098,4 +1099,4 @@ module.exports = Value;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}]},{},[2])(2)
-});
\ No newline at end of file
+});