Compare commits

...

136 Commits
master ... dev

Author SHA1 Message Date
a4d800c45e Disable react 2021-12-06 01:38:01 -08:00
80a0d762fb Add qr code to table 2021-11-27 00:21:55 -08:00
7a8db04640 Add ideas for new tests 2021-11-21 02:08:29 -08:00
e51b389328 Disable confirmation dialogs 2021-11-21 02:08:09 -08:00
3fba8ce18c Enable ajax loads 2021-11-20 07:46:32 -08:00
37c6c4489f Add sloppy ajax loading of game plays 2021-11-20 04:07:58 -08:00
e571f407ca Fix play order 2021-11-20 04:07:25 -08:00
ccfe047ff3 Fix Play Now button 2021-11-20 04:06:53 -08:00
d5a5daaea7 Fix display if player to beat is removed 2021-11-20 03:04:17 -08:00
b86d85584f Merge pull request 'Fix winner check' (#1) from fix-winner-check into master
Reviewed-on: #1
2021-11-20 02:31:40 -08:00
60890d78d7 Fix winner check 2021-11-20 01:48:58 -08:00
b646eeb48b Add auto play for bots 2021-11-20 00:09:01 -08:00
3d46e5b806 Add seat management fix new game button 2021-11-17 07:56:39 -08:00
3a09b9bcff Change selected card style 2021-11-17 07:54:43 -08:00
1a7ebce6b4 Update default secret values 2021-11-16 06:53:56 -08:00
7dc60fdfb8 Disabled control buttons when not in control 2021-11-15 18:54:38 -08:00
6a020618c3 Add about page with attributions 2021-11-13 17:29:01 -08:00
b52ba6be1a Update git repo url 2021-11-13 17:28:22 -08:00
c4a1b857a9 Update deploy config 2021-11-13 02:29:34 -08:00
91d0d5b8a6 Update deploy config 2021-11-13 01:26:53 -08:00
6330a6b4e1 Create button to remove bots 2021-11-10 22:14:43 -08:00
614a53b253 Method must return boolean, not nil 2021-11-10 21:36:11 -08:00
69e8e06975 Add Bot button respects seat occupied status 2021-11-10 21:24:15 -08:00
54b2e4bec6 Add more tests for Bots 2021-11-08 22:56:53 -08:00
86085206e4 Silence deprecation warnings because factory_girl 2021-11-08 22:13:41 -08:00
13730bf979 Avoid js driver 2021-11-08 21:49:31 -08:00
fe136d1764 Adds Bot button and start of Bot Players 2021-11-07 21:48:48 -08:00
6b5be166f8 Use spring in test env 2021-11-07 21:47:37 -08:00
a74eb11e32 Use spring gem to speed up dev testing 2021-11-06 23:09:16 -07:00
3ca6055f47 Fix failing tests 2021-11-05 22:37:14 -07:00
b4d028857a Test click confirm 2021-11-05 22:00:26 -07:00
4bf08ca446 Use case insensitive test for devise sessions 2021-11-05 21:47:02 -07:00
b84a833d10 Fix failing tests 2021-11-05 21:26:14 -07:00
b1017682bd Install capybara-screenshot gem 2021-11-05 21:02:11 -07:00
828a88020e Table must be created before game for test setup 2021-11-04 22:56:09 -07:00
97b42e31cb Fix test navigation 2021-11-03 06:41:15 -07:00
2cc50d88ba Dirty fix race condition 2021-11-03 01:07:09 -07:00
93d121238b Fix test game path 2021-11-02 20:27:29 -07:00
1e0eabcef6 Fix card labels 2021-11-02 19:47:51 -07:00
91b33a8c63 Install ci_reporter gem for Jenkins 2021-10-17 22:03:46 -07:00
18612e2efc Fix tests 2021-09-19 00:26:45 -07:00
5358752e26 Visit table path instead of game path 2021-09-19 00:24:45 -07:00
2b5a0b2ccc Move card data to checkbox 2021-09-19 00:21:28 -07:00
13f4d04ca0 Config dev email 2021-09-19 00:20:52 -07:00
2d2acffede Test helper find card by data 2021-09-19 00:19:53 -07:00
5e5be7ca9a Fix game helper setup include a table 2021-09-19 00:15:09 -07:00
c622da90bd Improve selected card UI 2021-09-19 00:13:58 -07:00
68339a3a0d Capybara test requires visible checkbox 2021-09-18 23:44:02 -07:00
92633e58ad Mark test as pending 2021-07-24 04:53:54 -07:00
501972870d Fix syntax errors 2021-07-24 02:15:33 -07:00
69ce3f6b4c Fix game tests 2021-07-16 23:24:42 -07:00
196174401e Mark test as pending 2021-07-16 21:27:42 -07:00
2134ea02ce Fix player count game validation 2021-07-08 23:47:37 -07:00
ef17b1f8f9 Bugfix spec test 2021-07-08 02:49:57 -07:00
e8a03473f7 Bugfix spec test 2021-07-08 01:33:16 -07:00
1e34a17bd2 Update specs 2021-07-07 23:14:13 -07:00
4f5d15fdab Add webdrivers and update gems 2021-07-07 23:13:33 -07:00
57c4b50c74 Update syntax of config 2021-07-07 23:02:39 -07:00
7086f156c0 Add card data attribute to inventory cards 2021-07-07 23:01:09 -07:00
d72ed9eeec Fix link route name 2021-07-07 23:00:21 -07:00
753acd9aee Fix nil argument bug 2021-07-07 22:42:43 -07:00
8685196ce9 Move to new domain 2021-02-05 05:47:35 -08:00
Jesse C. Fisher
5814f2fe4b Use sub folder in production 2020-08-17 00:33:15 -07:00
Jesse C. Fisher
a7b63fce83 Use sub folder in production 2020-08-17 00:10:16 -07:00
Jesse C. Fisher
0173aa76e6 Update git repo url 2020-08-17 00:05:45 -07:00
Jesse C. Fisher
d1fbff6372 Update env to system wide rbenv 2020-08-17 00:04:37 -07:00
Jesse C. Fisher
10be40b25c Use sub folder in production 2020-08-16 23:58:22 -07:00
Jesse C. Fisher
3886936080 Update gems 2019-11-10 01:52:13 -08:00
Jesse C. Fisher
9a5220bf1e Use image asset tag for cards 2019-11-06 15:10:16 -08:00
Jesse C. Fisher
3900abf27f Serve static in production 2019-11-06 14:49:39 -08:00
Jesse C. Fisher
b0ed575892 Add tutorial link to home screen 2019-11-06 04:53:17 -08:00
Jesse C. Fisher
2a501b3eec Redirect to ssl https 2019-11-05 23:44:09 -08:00
Jesse C. Fisher
ffca28a0c7 Update devise deprecated code 2019-11-05 23:30:25 -08:00
Jesse C. Fisher
71d86b9091 Remove upmin-admin gem 2019-11-05 23:03:36 -08:00
Jesse C. Fisher
ac596c79e1 Use player display_name 2019-11-04 05:06:38 -08:00
Jesse C. Fisher
51a03a089d Autoload game updates if not taking turn 2019-11-04 05:06:03 -08:00
Jesse C. Fisher
36f84bb1ac Fix New Game button 2019-11-04 03:54:06 -08:00
Jesse C. Fisher
b550531219 before filter debug 2019-10-29 07:24:43 -07:00
Jesse C. Fisher
f9050ee48a before filter debug 2019-10-29 07:23:37 -07:00
Jesse C. Fisher
54e4443ff4 Config deploy for production 2019-10-29 07:14:22 -07:00
Jesse C. Fisher
d8744e4c23 Config deploy for production 2019-10-29 07:07:38 -07:00
Jesse C. Fisher
48a1a89f20 Config deploy for production 2019-10-29 07:04:50 -07:00
Jesse C. Fisher
b2a459b51a Config deploy for production 2019-10-29 07:03:04 -07:00
Jesse C. Fisher
001a88737f Config deploy for production 2019-10-29 06:59:02 -07:00
Jesse C. Fisher
bc00ab5a3d Config deploy for production 2019-10-29 06:47:52 -07:00
Jesse C. Fisher
0fd46f5da2 Config deploy for production 2019-10-29 06:43:22 -07:00
Jesse C. Fisher
22d1f90684 Updat bin stub 2019-10-29 06:39:36 -07:00
Jesse C. Fisher
af6893b679 Config deploy for production 2019-10-29 06:32:21 -07:00
Jesse C. Fisher
392f580648 Update migrations 2019-10-29 06:12:08 -07:00
Jesse C. Fisher
4acb86c4c0 Config deploy for production 2019-10-29 05:33:55 -07:00
Jesse C. Fisher
6a6bfea612 Config deploy for production 2019-10-29 03:18:24 -07:00
Jesse C. Fisher
b6d87b63b4 Fix player count in table index, adds user_count to table 2019-10-29 03:10:40 -07:00
Jesse C. Fisher
cc4395e3c3 Start adding New Game button to table 2019-10-28 07:08:38 -07:00
Jesse C. Fisher
8159492c84 Disable rspec 2019-10-28 05:08:51 -07:00
Jesse C. Fisher
eafbe7693d Add double run bombs. Logic still incomplete. 2019-10-27 01:34:52 -07:00
Jesse C. Fisher
03c2f92397 Add card backs for other players inventory 2019-10-27 00:43:47 -07:00
Jesse C. Fisher
2554c46aaf Improve card style 2019-10-27 00:42:52 -07:00
Jesse C. Fisher
6f11e34298 Add style fir middle player inventory 2019-10-27 00:00:13 -07:00
Jesse C. Fisher
4c2fbf5843 Fix turn order 2019-10-26 06:17:55 -07:00
Jesse C. Fisher
8a8f324fac Fix active player id list 2019-10-26 05:40:59 -07:00
Jesse C. Fisher
c9c136f3f1 Add winner message 2019-10-26 05:31:12 -07:00
Jesse C. Fisher
adf30b8399 Imorove turn logic regress new end of game bugs 2019-10-26 05:21:20 -07:00
Jesse C. Fisher
0e45a8d621 Improve style 2019-10-26 05:20:15 -07:00
Jesse C. Fisher
f82590d31f Disable spring 2019-10-26 04:31:02 -07:00
Jesse C. Fisher
49885a3149 Clear Play To Beat when play is passed by all other players 2019-10-26 04:28:19 -07:00
Jesse C. Fisher
f15b7e2172 Improve style of play to beat 2019-10-26 04:24:34 -07:00
Jesse C. Fisher
57f8aaa938 Fix logic for next players turn 2019-10-26 02:18:39 -07:00
Jesse C. Fisher
4c52336fd4 Improve style of user selected cards 2019-10-26 01:54:09 -07:00
Jesse C. Fisher
8a325a31b1 Improve style of player taking turn 2019-10-26 01:52:52 -07:00
Jesse C. Fisher
76c61e1358 Add visual for player taking turn 2019-10-26 01:37:54 -07:00
Jesse C. Fisher
d01f4c7486 Add play to beat image ui 2019-10-26 01:36:58 -07:00
Jesse C. Fisher
0bd8f226d4 Add user count validation to start game 2019-10-26 00:41:32 -07:00
Jesse C. Fisher
666e3fb798 Update gems 2019-10-25 23:29:04 -07:00
Jesse C. Fisher
deb01bef12 Lock sprockets version to avoid config change 2019-10-25 23:28:30 -07:00
Jesse C. Fisher
1b40b6c7b3 Add win count column to user 2019-10-24 19:52:03 -07:00
Jesse C. Fisher
d01c0ccf10 Add confirm alert to pass or stand from seat 2019-10-24 19:51:28 -07:00
Jesse C. Fisher
96635964be Add seats 3 and 4 to tablé 2019-10-24 19:45:33 -07:00
Jesse C. Fisher
8d75df244d Fix sit stanđ seat player logic 2019-10-24 19:43:57 -07:00
Jesse C. Fisher
fba063cf4f Fix bug for player display_name without user 2019-10-24 19:40:04 -07:00
Jesse C. Fisher
37b36345af Add removal of soft_user token 2019-10-24 19:38:28 -07:00
Jesse C. Fisher
0cb3232f39 Remove unused code 2019-10-24 17:15:59 -07:00
Jesse C. Fisher
1085ed17a6 Fix missing record error with find_by 2019-10-24 17:15:04 -07:00
Jesse C. Fisher
77fa19dee7 Find first empty seat 2019-10-24 17:03:53 -07:00
Jesse C. Fisher
5ceee4bac4 Improve player hand style 2019-10-24 17:02:41 -07:00
Jesse C. Fisher
54156c2956 Add jquery reloading of table. Fix Play Now 2019-10-21 05:52:44 -07:00
Jesse C. Fisher
d6c58efe0c Toying with Play Now 2019-10-20 21:59:40 -07:00
Jesse C. Fisher
b23d044438 Auto refresh unless my turn 2019-10-20 21:57:26 -07:00
Jesse C. Fisher
59fe16033a Toying with stand from active game 2019-10-20 21:56:06 -07:00
Jesse C. Fisher
584f364964 Add play hand and pass function. 2 player game capable 2019-10-20 18:20:39 -07:00
Jesse C. Fisher
cf1e1b7493 Add style for player hand 2019-10-20 17:26:52 -07:00
Jesse C. Fisher
2a9c4a6a76 Adds top seat, player, controls 2019-10-20 16:55:12 -07:00
Jesse C. Fisher
ff63178547 Adds top seat, player, controls 2019-10-20 05:06:22 -07:00
Jesse C. Fisher
d28b412add Rewrite without react. Can sit stand at a table 2019-10-19 00:38:46 -07:00
Jesse C. Fisher
b8755a783b New dev url 2019-10-19 00:37:07 -07:00
Jesse C. Fisher
aafc0db112 Hide tutorial button 2019-10-18 21:12:03 -07:00
Jesse C. Fisher
917d02a4e5 Update capybara 2019-10-02 00:24:01 -07:00
109 changed files with 1592 additions and 778 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@
# Corrections? Improvements? Create a GitHub issue:
# http://github.com/RailsApps/rails-composer/issues
#----------------------------------------------------------------------------
/spec/reports/
# ctags
tags

View File

@ -4,12 +4,13 @@ require 'capistrano/setup'
# Includes default deployment tasks
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/puma'
install_plugin Capistrano::Puma # Default puma tasks
require 'capistrano/puma/workers'
require 'capistrano/puma/jungle'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/nginx'
# require 'capistrano/nginx'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/postgresql'
@ -19,7 +20,8 @@ require 'capistrano/postgresql'
# Includes tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git#
# https://github.com/capistrano/rvm
# https://github.com/capistrano/rbenv
# https://github.com/capistrano/chruby

16
Gemfile
View File

@ -1,6 +1,8 @@
source 'https://rubygems.org'
ruby '2.6.0'
gem 'rails', '5.2.2'
# TODO Upgrade sprockets
gem 'sprockets', '~> 3.7'
gem 'sass-rails' #, '~> 4.0.3'
gem 'uglifier' #, '>= 1.3.0'
gem 'coffee-rails' #, '~> 4.0.0'
@ -8,7 +10,6 @@ gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder' #, '~> 2.0'
gem 'sdoc', group: :doc #, '~> 0.4.0'
gem 'spring', group: :development
gem 'devise'
gem 'devise_invitable'
gem 'haml-rails'
@ -17,10 +18,10 @@ gem 'pg'
gem 'puma'
gem 'pundit'
gem 'simple_form'
gem 'upmin-admin'
gem 'dotenv-rails'
gem 'react-rails'
# gem 'react-rails-hot-loader'
gem 'ci_reporter_rspec'
group :development do
gem 'parallel_tests', group: :development
gem 'better_errors'
@ -30,7 +31,7 @@ group :development do
gem 'capistrano-bundler'
gem 'capistrano-rails'
gem 'capistrano-rails-console'
gem 'capistrano3-puma'
gem 'capistrano3-puma', '~> 3'
gem 'capistrano-rbenv'
gem 'capistrano-nginx', github: 'koenpunt/capistrano-nginx'
gem "capistrano-db-tasks", require: false
@ -47,21 +48,24 @@ group :development do
gem 'rb-fchange', require: false
gem 'rb-fsevent', require: false
gem 'rb-inotify', require: false
gem 'spring-commands-rspec'
# gem 'spring-commands-rspec'
gem 'guard-ctags-bundler'
end
group :development, :test, :staging do
group :development, :test do
gem 'factory_girl_rails'
gem 'faker'
gem 'pry-rails'
gem 'pry-rescue'
gem 'rspec-rails'
gem 'spring'
gem 'spring-commands-rspec'
end
group :test, :staging do
gem 'capybara'
gem 'database_cleaner'
gem "poltergeist"
gem 'launchy'
gem 'selenium-webdriver'
gem 'webdrivers'
gem 'simplecov', :require => false
end
gem 'capybara-screenshot', :group => :test

View File

@ -49,114 +49,125 @@ GEM
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
airbrussh (1.3.1)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
airbrussh (1.4.0)
sshkit (>= 1.6.1, != 1.7.0)
arel (9.0.0)
ast (2.4.0)
ast (2.4.2)
babel-source (5.8.35)
babel-transpiler (0.7.0)
babel-source (>= 4.0, < 6)
execjs (~> 2.0)
bcrypt (3.1.12)
better_errors (2.5.1)
bcrypt (3.1.16)
better_errors (2.9.1)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
binding_of_caller (0.8.0)
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
builder (3.2.3)
capistrano (3.11.0)
builder (3.2.4)
capistrano (3.16.0)
airbrussh (>= 1.0.0)
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
capistrano-bundler (1.5.0)
capistrano-bundler (2.0.1)
capistrano (~> 3.1)
capistrano-db-tasks (0.6)
capistrano (>= 3.0.0)
capistrano-postgresql (6.2.0)
capistrano (>= 3.0)
sshkit (>= 1.17.0)
capistrano-rails (1.4.0)
capistrano-rails (1.6.1)
capistrano (~> 3.1)
capistrano-bundler (~> 1.1)
capistrano-bundler (>= 1.1, < 3)
capistrano-rails-console (2.3.0)
capistrano (>= 3.5.0, < 4.0.0)
sshkit-interactive (~> 0.3.0)
capistrano-rbenv (2.1.4)
capistrano-rbenv (2.2.0)
capistrano (~> 3.1)
sshkit (~> 1.3)
capistrano3-puma (3.1.1)
capistrano (~> 3.7)
capistrano-bundler
puma (~> 3.4)
capybara (3.14.0)
capybara (3.36.0)
addressable
matrix
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (~> 1.2)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
chartkick (3.0.2)
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
cliver (0.3.2)
coderay (1.1.2)
coffee-rails (4.2.2)
capybara-screenshot (1.0.25)
capybara (>= 1.0, < 4)
launchy
childprocess (4.1.0)
ci_reporter (2.0.0)
builder (>= 2.1.2)
ci_reporter_rspec (1.0.0)
ci_reporter (~> 2.0)
rspec (>= 2.14, < 4)
coderay (1.1.3)
coffee-rails (5.0.0)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
railties (>= 5.2.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.1.4)
connection_pool (2.2.2)
crass (1.0.4)
database_cleaner (1.7.0)
debug_inspector (0.0.3)
devise (4.6.1)
concurrent-ruby (1.1.9)
connection_pool (2.2.5)
crass (1.0.6)
database_cleaner (2.0.1)
database_cleaner-active_record (~> 2.0.0)
database_cleaner-active_record (2.0.1)
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
debug_inspector (1.1.0)
devise (4.8.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 6.0)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise_invitable (2.0.0)
devise_invitable (2.0.5)
actionmailer (>= 5.0)
devise (>= 4.6)
diff-lcs (1.3)
docile (1.3.1)
dotenv (2.7.1)
dotenv-rails (2.7.1)
dotenv (= 2.7.1)
railties (>= 3.2, < 6.1)
em-websocket (0.5.1)
diff-lcs (1.4.4)
docile (1.4.0)
dotenv (2.7.6)
dotenv-rails (2.7.6)
dotenv (= 2.7.6)
railties (>= 3.2)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
erubi (1.8.0)
http_parser.rb (~> 0)
erubi (1.10.0)
erubis (2.7.0)
eventmachine (1.2.7)
execjs (2.7.0)
execjs (2.8.1)
factory_girl (4.9.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.9.0)
factory_girl (~> 4.9.0)
railties (>= 3.0.0)
faker (1.9.3)
i18n (>= 0.7)
ffi (1.10.0)
formatador (0.2.5)
globalid (0.4.2)
activesupport (>= 4.2.0)
guard (2.15.0)
faker (2.19.0)
i18n (>= 1.6, < 2)
ffi (1.15.4)
formatador (0.3.0)
globalid (0.5.2)
activesupport (>= 5.0)
guard (2.18.0)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
lumberjack (>= 1.0.12, < 2.0)
nenv (~> 0.1)
notiffany (~> 0.0)
pry (>= 0.9.12)
pry (>= 0.13.0)
shellany (~> 0.0)
thor (>= 0.18.1)
guard-bundler (2.2.1)
@ -179,103 +190,86 @@ GEM
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
haml (5.0.4)
haml (5.2.2)
temple (>= 0.8.0)
tilt
haml-rails (2.0.0)
haml-rails (2.0.1)
actionpack (>= 5.1)
activesupport (>= 5.1)
haml (>= 4.0.6, < 6.0)
html2haml (>= 1.0.1)
railties (>= 5.1)
high_voltage (3.1.0)
high_voltage (3.1.2)
html2haml (2.2.0)
erubis (~> 2.7.0)
haml (>= 4.0, < 6)
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
http_parser.rb (0.6.0)
http_parser.rb (0.8.0)
hub (1.12.4)
i18n (1.6.0)
i18n (1.8.11)
concurrent-ruby (~> 1.0)
interception (0.5)
jaro_winkler (1.5.2)
jbuilder (2.8.0)
activesupport (>= 4.2.0)
multi_json (>= 1.2)
jquery-rails (4.3.3)
jbuilder (2.11.2)
activesupport (>= 5.0.0)
jquery-rails (4.4.0)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (2.2.0)
kaminari (1.1.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.1.1)
kaminari-activerecord (= 1.1.1)
kaminari-core (= 1.1.1)
kaminari-actionview (1.1.1)
actionview
kaminari-core (= 1.1.1)
kaminari-activerecord (1.1.1)
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
launchy (2.4.3)
addressable (~> 2.3)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
loofah (2.2.3)
launchy (2.5.0)
addressable (~> 2.7)
listen (3.7.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.12.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lumberjack (1.0.13)
lumberjack (1.2.8)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.9.2)
mimemagic (0.3.3)
mini_mime (1.0.1)
mini_portile2 (2.4.0)
minitest (5.11.3)
multi_json (1.13.1)
matrix (0.4.2)
method_source (1.0.0)
mimemagic (0.3.10)
nokogiri (~> 1)
rake
mini_mime (1.1.2)
mini_portile2 (2.6.1)
minitest (5.14.4)
multi_json (1.15.0)
nenv (0.3.0)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (5.1.0)
nio4r (2.3.1)
nokogiri (1.10.1)
mini_portile2 (~> 2.4.0)
notiffany (0.1.1)
net-scp (3.0.0)
net-ssh (>= 2.6.5, < 7.0.0)
net-ssh (6.1.0)
nio4r (2.5.8)
nokogiri (1.12.5)
mini_portile2 (~> 2.6.1)
racc (~> 1.4)
notiffany (0.1.3)
nenv (~> 0.1)
shellany (~> 0.0)
orm_adapter (0.5.0)
parallel (1.14.0)
parallel_tests (2.28.0)
parallel (1.21.0)
parallel_tests (3.7.3)
parallel
parser (2.6.0.0)
ast (~> 2.4.0)
pg (1.1.4)
poltergeist (1.18.1)
capybara (>= 2.1, < 4)
cliver (~> 0.3.1)
websocket-driver (>= 0.2.0)
powerpack (0.1.2)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
parser (3.0.2.0)
ast (~> 2.4.1)
pg (1.2.3)
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
pry-rescue (1.5.0)
pry-rescue (1.5.2)
interception (>= 0.5)
pry (>= 0.12.0)
psych (3.1.0)
public_suffix (3.0.3)
puma (3.12.0)
pundit (2.0.1)
public_suffix (4.0.6)
puma (3.12.6)
pundit (2.1.1)
activesupport (>= 3.0.0)
rack (2.0.6)
racc (1.6.0)
rack (2.2.3)
rack-livereload (0.3.17)
rack
rack-test (1.1.0)
@ -296,8 +290,8 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
rails-html-sanitizer (1.4.2)
loofah (~> 2.3)
rails_layout (1.0.42)
railties (5.2.2)
actionpack (= 5.2.2)
@ -306,130 +300,123 @@ GEM
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (12.3.2)
ransack (2.1.1)
actionpack (>= 5.0)
activerecord (>= 5.0)
activesupport (>= 5.0)
i18n
rake (13.0.6)
rb-fchange (0.0.6)
ffi
rb-fsevent (0.10.3)
rb-inotify (0.10.0)
rb-fsevent (0.11.0)
rb-inotify (0.10.1)
ffi (~> 1.0)
rdoc (6.1.1)
react-rails (2.4.7)
rdoc (6.3.3)
react-rails (2.6.1)
babel-transpiler (>= 0.7.0)
connection_pool
execjs
railties (>= 3.2)
tilt
regexp_parser (1.3.0)
responders (2.4.1)
actionpack (>= 4.2.0, < 6.0)
railties (>= 4.2.0, < 6.0)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-core (3.8.0)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-rails (3.8.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.0)
rubocop (0.65.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5, != 2.5.1.1)
powerpack (~> 0.1)
psych (>= 3.1.0)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.4.0)
ruby-progressbar (1.10.0)
ruby_dep (1.5.0)
ruby_parser (3.12.0)
sexp_processor (~> 4.9)
rubyzip (1.2.2)
sass (3.7.3)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.0.7)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sdoc (1.0.0)
rdoc (>= 5.0)
selenium-webdriver (3.141.0)
childprocess (~> 0.5)
rubyzip (~> 1.2, >= 1.2.2)
sexp_processor (4.11.0)
shellany (0.0.1)
simple_form (4.1.0)
regexp_parser (2.1.1)
responders (3.0.1)
actionpack (>= 5.0)
activemodel (>= 5.0)
simplecov (0.16.1)
railties (>= 5.0)
rexml (3.2.5)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
rspec-mocks (~> 3.10.0)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-mocks (3.10.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-rails (5.0.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
railties (>= 5.2)
rspec-core (~> 3.10)
rspec-expectations (~> 3.10)
rspec-mocks (~> 3.10)
rspec-support (~> 3.10)
rspec-support (3.10.3)
rubocop (1.22.3)
parallel (~> 1.10)
parser (>= 3.0.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml
rubocop-ast (>= 1.12.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.13.0)
parser (>= 3.0.1.1)
ruby-progressbar (1.11.0)
ruby_parser (3.18.1)
sexp_processor (~> 4.16)
rubyzip (2.3.2)
sass-rails (6.0.0)
sassc-rails (~> 2.1, >= 2.1.1)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
sdoc (2.2.0)
rdoc (>= 5.0)
selenium-webdriver (4.0.3)
childprocess (>= 0.5, < 5.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2)
sexp_processor (4.16.0)
shellany (0.0.1)
simple_form (5.1.0)
actionpack (>= 5.2)
activemodel (>= 5.2)
simplecov (0.21.2)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
spring (2.0.2)
activesupport (>= 4.2)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.3)
spring (3.0.0)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets-rails (3.3.0)
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
sshkit (1.18.2)
sshkit (1.21.2)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
sshkit-interactive (0.3.0)
sshkit (~> 1.12)
temple (0.8.1)
thor (0.20.3)
temple (0.8.2)
thor (1.1.0)
thread_safe (0.3.6)
tilt (2.0.9)
turbolinks (5.2.0)
tilt (2.0.10)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (1.2.5)
tzinfo (1.2.9)
thread_safe (~> 0.1)
uglifier (4.1.20)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.4.1)
upmin-admin (0.1.3)
chartkick
haml (>= 3.0.0)
jquery-rails
kaminari
rails
ransack
sass-rails
warden (1.2.8)
rack (>= 2.0.6)
websocket-driver (0.7.0)
unicode-display_width (2.1.0)
warden (1.2.9)
rack (>= 2.0.9)
webdrivers (5.0.0)
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
selenium-webdriver (~> 4.0)
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
@ -447,8 +434,10 @@ DEPENDENCIES
capistrano-rails
capistrano-rails-console
capistrano-rbenv
capistrano3-puma
capistrano3-puma (~> 3)
capybara
capybara-screenshot
ci_reporter_rspec
coffee-rails
database_cleaner
devise
@ -470,7 +459,6 @@ DEPENDENCIES
launchy
parallel_tests
pg
poltergeist
pry-rails
pry-rescue
puma
@ -491,12 +479,13 @@ DEPENDENCIES
simplecov
spring
spring-commands-rspec
sprockets (~> 3.7)
turbolinks
uglifier
upmin-admin
webdrivers
RUBY VERSION
ruby 2.6.0p0
BUNDLED WITH
1.17.2
1.17.3

124
Guardfile
View File

@ -35,10 +35,10 @@ guard :bundler do
files.each { |file| watch(helper.real_path(file)) }
end
#guard 'rails', host: '127.0.0.1' do
# watch('Gemfile.lock')
# watch(%r{^(config|lib)/.*})
#end
guard 'rails', host: '0.0.0.0', port: 9913 do
watch('Gemfile.lock')
watch(%r{^(config|lib)/.*})
end
# Note: The cmd option is now required due to the increasing number of ways
@ -50,61 +50,61 @@ end
# * zeus: 'zeus rspec' (requires the server to be started separately)
# * 'just' rspec: 'rspec'
rspec_options = {
cmd: "bundle exec spring rspec",
all_after_pass: false,
failed_mode: :focus,
# run_all: {
# cmd: "bundle exec parallel_rspec -o '",
# cmd_additional_args: "'"
# }
}
guard :rspec, rspec_options do #, failed_mode: :focus
require "guard/rspec/dsl"
dsl = Guard::RSpec::Dsl.new(self)
notification :off
# Feel free to open issues for suggestions and improvements
# RSpec files
rspec = dsl.rspec
watch(rspec.spec_helper) { rspec.spec_dir }
watch(rspec.spec_support) { rspec.spec_dir }
watch(rspec.spec_files)
# Ruby files
ruby = dsl.ruby
dsl.watch_spec_files_for(ruby.lib_files)
# Rails files
rails = dsl.rails(view_extensions: %w(erb haml slim))
dsl.watch_spec_files_for(rails.app_files)
dsl.watch_spec_files_for(rails.views)
watch(rails.controllers) do |m|
[
rspec.spec.("routing/#{m[1]}_routing"),
rspec.spec.("controllers/#{m[1]}_controller"),
rspec.spec.("acceptance/#{m[1]}")
]
end
# Rails config changes
watch(rails.spec_helper) { rspec.spec_dir }
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
# Capybara features specs
watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
end
end
guard 'ctags-bundler', src_path: ["app", "lib", "spec/support"], project_file: "tags" do
watch(/^(app|lib|spec\/support)\/.*\.rb$/)
watch('Gemfile.lock')
end
#rspec_options = {
# cmd: "bundle exec rspec",
# all_after_pass: false,
# failed_mode: :focus,
## run_all: {
## cmd: "bundle exec parallel_rspec -o '",
## cmd_additional_args: "'"
## }
#}
#guard :rspec, rspec_options do #, failed_mode: :focus
# require "guard/rspec/dsl"
# dsl = Guard::RSpec::Dsl.new(self)
# notification :off
#
# # Feel free to open issues for suggestions and improvements
#
# # RSpec files
# rspec = dsl.rspec
# watch(rspec.spec_helper) { rspec.spec_dir }
# watch(rspec.spec_support) { rspec.spec_dir }
# watch(rspec.spec_files)
#
# # Ruby files
# ruby = dsl.ruby
# dsl.watch_spec_files_for(ruby.lib_files)
#
# # Rails files
# rails = dsl.rails(view_extensions: %w(erb haml slim))
# dsl.watch_spec_files_for(rails.app_files)
# dsl.watch_spec_files_for(rails.views)
#
# watch(rails.controllers) do |m|
# [
# rspec.spec.("routing/#{m[1]}_routing"),
# rspec.spec.("controllers/#{m[1]}_controller"),
# rspec.spec.("acceptance/#{m[1]}")
# ]
# end
#
# # Rails config changes
# watch(rails.spec_helper) { rspec.spec_dir }
# watch(rails.routes) { "#{rspec.spec_dir}/routing" }
# watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
#
# # Capybara features specs
# watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
#
# # Turnip features and steps
# watch(%r{^spec/acceptance/(.+)\.feature$})
# watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
# Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
# end
#end
#
#guard 'ctags-bundler', src_path: ["app", "lib", "spec/support"], project_file: "tags" do
# watch(/^(app|lib|spec\/support)\/.*\.rb$/)
# watch('Gemfile.lock')
#end

View File

@ -5,3 +5,12 @@
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks
require 'ci/reporter/rake/rspec'
# ...
# Rake code that creates a task called `:rspec`
# ...
task :rspec => 'ci:setup:rspec'
task :spec => 'ci:setup:rspec'

View File

@ -13,8 +13,18 @@
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require react
//= require react_ujs
// require react
// require react_ujs
//= require components
//= require qrcode.min.js
// require react-rails-hot-loader
//= require_tree .
// require_tree .
$(document).ready(function(){
setInterval(function() {
// $('#table-component').load("#{request.path} #table-component");
$('#play-to-beat').load("#{request.path} #play-to-beat");
$('#play-buttons').load("#{request.path} #play-buttons");
}, 2000);
});

View File

@ -0,0 +1,7 @@
$(document).ready(function(){
setInterval(function() {
if ( $('.taking-turn.player[data-soft-token=' + soft_token + ']').length < 1 ) {
$('#table-component').load(window.location.pathname +" #table-component");
}
}, 5000);
});

View File

@ -40,7 +40,7 @@ h1
header
font-size: 3vmin
margin-bottom: 10vmin
// margin-bottom: 10vmin
nav
padding: 1vmin
background: #222

View File

@ -27,9 +27,11 @@
//// Show Game#show
button
button,
input[type=submit]
font-size: 4vmin
#table-component,
#game-component-container-container
display: flex
flex-direction: column
@ -110,35 +112,73 @@ ol#cards-to-beat
flex-wrap: wrap
text-align: center
li
position: relative
margin-left: -21vmin
// Don't offset first card
&:first-of-type
margin-left: -4vmin
flex: 1 1 auto
//flex: 1 1 auto
text-align: center
display: inline-block
img
width: 6vmin
width: 16vmin
border: 1px solid black
border-radius: .3vmin
////// Inventory
.player form
.player
&.taking-turn
font-weight: bold
box-shadow: 0px 0px .5vmin 1vmin inset rgba(white,0.2)
ul#inventory
display: flex
flex-wrap: wrap
text-align: left
li
margin-left: -21vmin
// Don't offset first card
&:first-of-type
// margin-left: 0
margin-left: -4vmin
flex: 1 1 auto
input[type="checkbox"]
visibility: hidden
// Capybara test requires visible checkbox
// visibility: hidden
opacity: .000001
position: absolute
&:checked ~ img
box-shadow: 0px 0px 2px 6px cadetblue
box-shadow: 0px 0px 2px 5px #05adff, inset 0 0 2px 3px #056dff
margin-top: -2vmin
img
width: 6vmin
width: 26vmin
border: 1px solid black
border-radius: .3vmin
border-radius: 1.2vmin
transition: margin-top ease-out .10s
#mid
ul#inventory
margin-left: 8vmin
li
margin-left: -8vmin
// Don't offset first card
&:first-of-type
// margin-left: -0vmin
img
width: 16vmin
.inventory
text-align: left
.inventory
text-align: center
img
width: 6vmin
border: 1px solid black
border: 2px solid black
border-radius: .3vmin
margin-left: -2vmin
// Don't offset first card
&:first-of-type
// margin-left: 0vmin

View File

@ -0,0 +1,23 @@
#table-component, #table-component-container, .table
width: 100%
height: 100%
#table-controls
text-align: right
padding: 0 1em
#newgame
float: left
#qrcode
float: right
margin-top: -.5em
margin-right: 1em
transform: scale(10%)
transition: all 0.5s ease-in-out
width: 38px
height: 38px
&.full
margin-right: 2em
transform: scale(100%)
width: 384px
height: 384px

View File

@ -1,10 +0,0 @@
// Place all the styles related to the Tables controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
#table-component-container-container,
#table-component-container,
.table {
width: 100%;
height: 100%;
}

View File

@ -35,23 +35,27 @@ class GamesController < ApplicationController
# Player action: pass
# TODO: wtf do we need game params for? And why nest hand_type in it?
if params[:game]
if params[:game][:hand_type] == 'pass'
# if params[:game]
if params[:hand_type] == 'Pass'
@game.set_controlling_player 'next'
flash[:notice] = 'Successfully passed.'
# Clear play to beat if play returns to owner
if @game.play_to_beat.try(:player).try(:id) == @game.controlling_player_id
@game.play_to_beat_id = nil
end
@game.save
end
end
# Player action: play_hand
if params[:player_card_ids]
elsif params[:player_card_ids]
@cards_to_play = @game.controlling_player.try(:player_cards).order(:value).find(params[:player_card_ids])
# Instantiate the play
@play = @game.controlling_player.plays.new
@play.game_id = @game.id
# TODO Bug next player fails if inventory is empty
@next_player_id = @game.next_player_id
@play.player_cards << @cards_to_play
if @play.save
@game.set_controlling_player 'next'
@game.controlling_player_id = @next_player_id
@game.save
else
# TODO: Does anything need to happen here?
@ -74,8 +78,9 @@ class GamesController < ApplicationController
end
respond_to do |format|
format.html { redirect_to(@game) }
## TODO: Return status message of attempt to play_hand
# flash[:notice] = 'I hi'
format.html { redirect_to(@game.table) }
format.json { render json: @game }
end
@ -104,10 +109,12 @@ class GamesController < ApplicationController
def play_now
# First joinable game or create new game
@game = Game.play_now(current_user)
@seats = @game.seats.order(:position).map {|s| s.occupied? ? nil : s}
@seats.compact.last.sit(current_user)
redirect_to @game
@game = Game.play_now
@seats = @game.table.seats.order(:position).map {|s| s.occupied? ? nil : s}
# @seats = @game.table.seats
@seat = @seats.compact.last.sit(current_user)
@seat.save
redirect_to @game.table
end
def join
@ -123,12 +130,12 @@ class GamesController < ApplicationController
@game.errors.messages.each do |key, msg|
flash[key] = msg.join
end
redirect_to(@game)
redirect_to(@game.table)
return
end
flash[:notice] = 'Game started.'
redirect_to(@game)
redirect_to(@game.table)
end
def my_inventory

View File

@ -1,5 +1,7 @@
class SeatsController < ApplicationController
before_action :set_seat, only: [:show, :edit, :update, :destroy, :sit, :stand]
before_action :set_seat, only: [:show, :edit, :update, :destroy,
:sit, :stand, :add_bot, :remove_bot, :empty,
:remove_player]
respond_to :html, :json
@ -66,10 +68,38 @@ class SeatsController < ApplicationController
# POST /seats/1
def sit
@message = @seat.sit current_user
respond_to do |format|
if @seat.save
format.html { redirect_to @seat.table, notice: 'Seat was successfully sat in.' }
else
format.html { redirect_to @seat.table, notice: 'Failed to sit.' }
end
end
end
def stand
@message = @seat.stand current_user
redirect_to @seat.table, notice: @message
end
def add_bot
@message = @seat.add_bot
redirect_to @seat.table, notice: @message
end
def remove_bot
@message = @seat.remove_bot
redirect_to @seat.table, notice: @message
end
def empty
@message = @seat.empty
redirect_to @seat.table, notice: @message
end
def remove_player
@message = @seat.remove_player
redirect_to @seat.table, notice: @message
end
private

View File

@ -1,8 +1,26 @@
class TablesController < ApplicationController
before_action :set_table, only: [:show, :edit, :update, :destroy]
before_action :set_table, only: [:show, :edit, :update, :destroy, :new_game]
respond_to :html, :json
def play_now
# First empty seat
@seat = Seat.where(user_soft_token: nil).select{|s| !s.player.try("is_bot?")}.first
if @seat
@seat.sit current_user
else
@table = Table.create(title: "Table " + current_user.soft_token[0..4])
@seat = @table.seats.first
@seat.sit current_user
end
redirect_to @seat.table
# @game = Game.play_now(current_user)
# @table = @game.table
# @seats = @table.seats.order(:position).map {|s| s.occupied? ? nil : s}
# @seat = @seats.compact.last.sit(current_user)
end
# GET /tables
# GET /tables.json
def index
@ -12,6 +30,29 @@ class TablesController < ApplicationController
# GET /tables/1
# GET /tables/1.json
def show
# TODO refactor to ensure play for 2nd and 3rd place
if @game.controlling_player.try("is_bot?")
@game.controlling_player.auto_play
@game.save
@game.reload
end
end
def new_game
@game = @table.add_game
begin
@game.start
rescue
flash[:errors] = @game.errors
end
redirect_to @table
end
def tutorial
flash[:notice] = "Tutorial coming soon!"
redirect_to root_path
end
# GET /tables/new
@ -67,6 +108,8 @@ class TablesController < ApplicationController
# Use callbacks to share common setup or constraints between actions.
def set_table
@table = Table.find(params[:id])
@game = @table.current_game
@seats = @table.seats.order(:id)
end
# Never trust parameters from the scary internet, only allow the white list through.

View File

@ -40,7 +40,7 @@ class Users::RegistrationsController < Devise::RegistrationsController
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.for(:sign_up) << :soft_token
devise_parameter_sanitizer.permit(:sign_up, keys: [:soft_token])
end
# If you have extra params to permit, append them to the sanitizer.

View File

@ -6,8 +6,8 @@ class Game < ActiveRecord::Base
has_many :users, through: :players
has_many :player_cards, through: :players
has_many :plays, through: :players
has_one :controlling_player
belongs_to :play_to_beat
belongs_to :controlling_player, class_name: "Player", foreign_key: "controlling_player_id"
accepts_nested_attributes_for :players
#validates :title, presence: true
after_create :add_table
@ -45,19 +45,16 @@ class Game < ActiveRecord::Base
end
def winner
begin
self.players.find(self.winner_player_id)
rescue
nil
end
self.players.find_by_id(self.winner_player_id)
end
def validate_startable
@player_count = players.count
errors[:players] = 'Must be at least 2 players.' if @player_count < 2
errors[:players] = 'Must be less than 5 players.' if @player_count > 4
errors[:status] = 'Game already started...' if self.status.nil? == false
errors[:player_cards] = 'Cards already dealt...' unless player_cards.empty?
@user_count = players.where.not(soft_token: nil).count
errors.add(:players, 'Must be at least 2 players.') if @player_count < 2
errors.add(:players, 'Must be less than 5 players.') if @player_count > 4
errors.add(:status, 'Game already started...') if self.status.nil? == false
errors.add(:player_cards, 'Cards already dealt...') unless player_cards.empty?
fail StandardError, errors if errors.count > 0
return true
end
@ -83,6 +80,12 @@ class Game < ActiveRecord::Base
new_player = self.players.create(user: user, soft_token: user.soft_token)
end
def add_player_bot
# todo return if game is full
# return false unless self.joinable?(user)
new_player = self.players.create(is_bot: true)
end
def remove_player_from_user(user)
return false unless self.has_user? user
@ -93,7 +96,8 @@ class Game < ActiveRecord::Base
end
if @player
@player.destroy
@player.user_id = nil
@player.soft_token = nil
end
end
@ -119,7 +123,7 @@ class Game < ActiveRecord::Base
def full?
players.count >= 4
# players.count >= 4
end
def set_controlling_player(arg)
@ -127,24 +131,27 @@ class Game < ActiveRecord::Base
when 'next'
self.controlling_player_id = self.next_player_id
end
# Clear play to beat if play returns to owner
# if self.play_to_beat.try(:player).try(:id) == self.controlling_player_id
# self.play_to_beat_id = nil
# end
end
def joinable? user
!self.has_user?(user) && !self.full?
# !self.has_user?(user) && !self.full?
!self.full?
end
def player_ids_by_seat_order
player_ids = self.seats.order(:position).select {|s| s.player_id}.map {|s| s.player_id}
player_ids = self.seats.order(:position).select {|s| ( s.player.present? && s.player.inventory.count > 0) ? s.player_id : nil}.compact.map {|s| s.player_id}
end
def next_player_id
@controlling_player_index = self.player_ids_by_seat_order.index(controlling_player_id)
player_ids_by_seat_order[(@controlling_player_index + 1) % self.player_ids.length]
end
# The player whose turn it is
def controlling_player
self.players.find(self.controlling_player_id)
# TODO Fix bug
@controlling_player_index ||= 0
player_ids_by_seat_order[(@controlling_player_index + 1) % self.player_ids_by_seat_order.length]
end
# The user whose turn it is
@ -175,6 +182,14 @@ private
def add_table
self.table ||= Table.create current_game_id: self.id
self.seats = self.table.seats
self.seats.each do |seat|
# if (seat.user_id || seat.user_soft_token)
if (seat.occupied?)
new_player = self.players.create(user_id: seat.user_id, soft_token: seat.user_soft_token, is_bot: seat.player.is_bot)
seat.player = new_player
seat.save
end
end
self.save
end

View File

@ -14,9 +14,10 @@ class Play < ActiveRecord::Base
after_save :set_controlling_player
def check_for_winner
return if self.game.winner.present?
if self.game.over?
self.game.winner_player_id = self.player.id
self.game.status = "Player #{self.player.id} wins!"
self.game.status = "Player #{self.player.display_name} wins!"
self.game.save
end
end
@ -60,16 +61,18 @@ class Play < ActiveRecord::Base
# current player is not the player to beat
if (game.player_to_beat != player)
# valid bomb?
if (self.hand_type == 'bomb' && game.play_to_beat.try("play").try("hand_type") == 'single' && game.play_to_beat.try("play").try("player_cards")[0].try('rank') == '2')
# if (self.hand_type =~ /bomb|double run/ && game.play_to_beat.try("play").try("hand_type") == 'single' && game.play_to_beat.try("play").try("player_cards")[0].try('rank') == '2')
if (self.hand_type =~ /bomb|double run/)
@truths << true
return @truths
end
# hand_type match?
@truths << (self.hand_type == game.play_to_beat.try("play").try("hand_type")) if game.play_to_beat.try("play").try(:hand_type)
else
# hand_type match? allows partial match i.e. "triple run (suited)"
@truths << (self.hand_type.match game.play_to_beat.try("play").try("hand_type")) if game.play_to_beat.try("play").try(:hand_type)
# beats?
@truths << (self.beats? self.game.play_to_beat.try(:play))
end
end
end
if has_player_cards

View File

@ -1,4 +1,5 @@
class PlayToBeat < ActiveRecord::Base
belongs_to :game
belongs_to :play
has_one :player, through: :play
end

View File

@ -15,7 +15,10 @@ class Player < ActiveRecord::Base
end
def display_name
self.try(:user).try(:email) || "Guest#{self.soft_token[0..5]}"
return user.email if self.user
return "BotPlayer" if self.is_bot?
return ("Guest" + self.soft_token)[0..9] if self.soft_token
return "Empty"
end
def play_hand(cards)
@ -28,7 +31,65 @@ class Player < ActiveRecord::Base
return false unless self.game.controlling_player == self
self.game.set_controlling_player 'next'
# Clear play to beat if play returns to owner
if self.game.play_to_beat.try(:player).try(:id) == self.game.controlling_player_id
self.game.play_to_beat_id = nil
end
self.game.save
end
def runs
@runs = self.inventory.chunk_while {|i, j| i.rank.to_i+1 == j.rank.to_i }
end
def triple_runs
@triple_runs = self.runs.map{|r| r.length > 2 ? r : nil}.compact
end
def auto_play
# TODO not sure this return clause works
return false unless self.game.controlling_player == self
# If first play of game, play lowest card
if self.game.plays.empty?
@cards_to_play = [self.inventory[0]]
return self.play_hand @cards_to_play
end
# If open table
if !self.game.play_to_beat
@cards_to_play = self.inventory[0..0]
else
@cards_to_beat = self.game.play_to_beat.play.player_cards
case self.game.play_to_beat.play.hand_type
when "single"
@cards_to_play = self.inventory.where("value > #{@cards_to_beat.min.value}")[0..0]
when "double"
@doubles = self.inventory.group_by {|card| card.rank}.map{|c| c if c[1].length > 1}.compact
if @doubles.present?
if @doubles[0][1][0..1].max.value > @cards_to_beat.max.value
@cards_to_play = @doubles[0][1][0..1]
end
end
when "triple run"
@runs = self.inventory.chunk_while {|i, j| i.rank.to_i+1 == j.rank.to_i }
@triple_runs = @runs.map{|r| r.length > 2 ? r : nil}.compact
if @triple_runs.present?
@cards_to_play = @triple_runs[0][0..2]
end
end
end
if @cards_to_play.present?
if @cards_to_beat.present?
if (@cards_to_play.max_by{|c| c.value}.value > @cards_to_beat.max_by{|c| c.value}.value)
return self.play_hand @cards_to_play
end
else
return self.play_hand @cards_to_play
end
end
self.pass
end
end

View File

@ -6,36 +6,107 @@ class Seat < ActiveRecord::Base
def sit(current_user)
if self.occupied?
return "Error. Seat is occupied."
return self
else
# Stand up from any other seats at this table
current_user.stand_from(self.table)
self.reload
if self.player == nil
self.player_id = self.table.current_game.add_player_from_user(current_user).id
end
self.player.user_id = current_user.id
self.player.soft_token = current_user.soft_token
self.player.save
self.user_id = current_user.id
self.user_soft_token = current_user.soft_token
self.save
return "Successfully sat."
return self.save
end
end
def stand(current_user)
unless self.occupied_by?(current_user)
def stand(user)
unless self.occupied_by?(user)
return "Error. Seat not occupied by you."
else
self.table.current_game.remove_player_from_user(current_user)
# self.table.current_game.remove_player_from_user(user)
self.player.user = nil
self.player.soft_token = nil
self.player.save
self.user_id = nil
self.user_soft_token = nil
self.player_id = nil
# self.player_id = nil
self.save
return "Successfully stood up."
end
end
def add_bot
if self.occupied?
return "Failed to add Bot seat full"
else
# self.reload
if self.player == nil
# add player to game
@bot_player = self.table.current_game.players.new(is_bot: true)
# @bot_player = self.table.current_game.add_player_from_user(current_user).id
self.player = @bot_player
self.player.save
self.save
return "Added Bot"
else
self.player.is_bot = true
self.player.save
return "Added Bot"
end
return "Failed to add Bot"
end
end
def remove_bot
if !self.occupied?
return "Failed to remove Bot seat empty"
else
if self.player.is_bot?
self.player.is_bot = false
self.player.save
return "Removed Bot"
end
return "Failed to remove Bot"
end
end
def empty
self.player.user = nil
self.player.soft_token = nil
self.player.is_bot = false
self.player.save
self.user_id = nil
self.user_soft_token = nil
# self.player_id = nil
self.save
return "Successfully stood up."
end
def remove_player
if !self.player
return "No player to remove"
else
self.player.destroy
self.user_id = nil
self.user_soft_token = nil
# self.player_id = nil
self.save
return "Successfully removed player"
end
end
def occupied?
self.user_id.present? || self.user_soft_token.present?
self.user_id.present? || self.user_soft_token.present? || self.try("player").try("is_bot?") == true
end
def occupied_by? user

View File

@ -3,6 +3,7 @@ class Table < ActiveRecord::Base
has_many :seats
has_many :users, through: :seats
has_many :games
has_many :players, through: :games
#TODO: Deprecated current_game_id from database.
# Instead calculate with self.current_game
#
@ -12,10 +13,28 @@ class Table < ActiveRecord::Base
after_create :add_seats
after_create :add_game
# Returns the newest joinable table or creates a new table if none are found
# scope :play_now, lambda { |user|
# where(status:nil).joins("LEFT OUTER JOIN players ON players.table_id = tables.id").group("tables.id").having("count(players) < 4").last || Table.create(title: "Game " + user.soft_token[0..4])
# }
scope :play_now, lambda { |user|
# where(status:nil).joins("LEFT OUTER JOIN players ON players.game_id = games.id").group("games.id").having("count(players) < 4").last || Table.create(title: "Game " + user.soft_token[0..4])
where(game:nil).last || Table.create(title: "Table " + user.soft_token[0..4])
}
def user_count
self.seats.map{|s| s.occupied? ? s : nil}.compact.count
end
def current_game
self.games.last
end
def add_game
self.games.create
end
private
def add_seats
@ -24,7 +43,4 @@ class Table < ActiveRecord::Base
end
end
def add_game
self.games.create if self.current_game_id.blank?
end
end

View File

@ -25,6 +25,7 @@ class User < ActiveRecord::Base
end
def stand_from(table)
return if table == nil
@seats = []
if self.id
@seats << table.seats.where(user_id: self.id)
@ -33,11 +34,7 @@ class User < ActiveRecord::Base
@seats << table.seats.where(user_soft_token: self.soft_token)
end
@seats.flatten.each do |seat|
seat.try(:player).try(:destroy)
seat.user_id = nil
seat.player_id = nil
seat.user_soft_token = nil
seat.save
seat.stand(self)
end
end

View File

@ -1,47 +1,47 @@
#game-component-container-container= react_component 'Game', props = {id: @game.id, current_user: current_user}, html_options = {id: "game-component-container"}
-# #game-component-container-container= react_component 'Game', props = {id: @game.id, current_user: current_user}, html_options = {id: "game-component-container"}
-# TODO: Remove deprecated commented out code
-#%p
%b Status:
%p
= @game.status
-#%p
%p
%b Title:
= @game.title
-#- if @game.can_accomodate(current_user)
= link_to 'Join', game_join_path(@game)
- if @game.can_accomodate(current_user)
= link_to 'Join', join_game_path(@game)
-#- if @game.startable? && @game.already_has?(current_user)
= link_to 'Start', game_start_path(@game)
- if @game.startable? && @game.already_has?(current_user)
= link_to 'Start', start_game_path(@game)
-#.debug
= button_to 'Debug Start', game_start_path(@game), method: :get
= link_to 'Edit Game', edit_game_path(@game)
-#.players
.players
%b Players:
%ol
- @game.players.each do |player|
%li
// Show the users email TODO show username instead
= player.user.email
= player.display_name
// Show the user which player they are
= "Me" if player.user == current_user
// Show whose turn it is
- if @game.controlling_player_id
%strong= "My Turn " if @game.controlling_player == player
%strong= "Taking Turn " if @game.controlling_player == player
// Show the players' cards
- if player.user == current_user && player.inventory.empty? == false
-##inventory
-# TODO better logic, not in view
-#- unless @game.status == nil
-#.table
- unless @game.status == nil
.table
-# TODO better logic, not in view. Set play to beat = nil; instead of view logic
- if @game.play_to_beat && @game.player_to_beat != @game.controlling_player
- if @game.play_to_beat.play
@ -49,14 +49,14 @@
Hand to beat
%span.hand-type= @game.play_to_beat.play.hand_type
%div= @game.play_to_beat.play.to_s
-#- @game.play_to_beat.play.player_cards.each do |card|
- @game.play_to_beat.play.player_cards.each do |card|
= card.to_s
%span.player= @game.play_to_beat.play.player.user.email
%span.player= @game.play_to_beat.play.player.display_name
- else
%h1 Open table
.controls
- if @game.control_user == current_user
- if @game.controlling_user == current_user
// Play hand form
= form_for @game, :url => play_hand_game_path(@game), remote: true do |f|
// Provide id of current game

View File

@ -1,10 +1,11 @@
<!DOCTYPE html>
<html>
<!DOCTYPE html>
<head>
<title>ThirteenTienLen</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
<%= yield :head %>
</head>
<body>

View File

@ -5,3 +5,7 @@ This web application was created with
<%= link_to('Rails Composer', 'http://railsapps.github.io/rails-composer/') %>
from the <%= link_to('RailsApps project', 'http://railsapps.github.io/') %>.
</p>
<p>
The domain name address was obtained from Afraid.org
<%= link_to('Free DNS', 'https://freedns.afraid.org/') %>
</p>

View File

@ -0,0 +1,18 @@
#play-to-beat
%h4 Hand to beat:
- if @game.play_to_beat == nil
None
- else
%div.hand-type= @game.play_to_beat.play.hand_type.capitalize
%span= @game.play_to_beat.play.to_s
-# - @game.play_to_beat.play.player_cards.each do |card|
= card.to_s
%div= @game.play_to_beat.play.try("player").try("display_name")
%ol#cards-to-beat
- @game.play_to_beat.play.player_cards.reverse.each_with_index do |card, index|
%li{style: "z-index: #{100 - index};"}
-# TODO: Don't hard code face cards here
%img{alt: card.rank + ' ' + card.suit,
src: "#{image_path('cards/png/' + (card.rank.gsub('J','jack').gsub('Q','queen').gsub('K','king').gsub('A','ace') + '_of_' + card.suit.downcase + 's.png').gsub('11','jack').gsub('12','queen').gsub('13','king').gsub('14','ace').gsub('15','2'))}" }

View File

@ -0,0 +1,61 @@
- @game = seat.game
.seat{class: "position-#{@seats.index(seat) + 1}"}
.seat-controls
- if seat.occupied?
- if seat.player.is_bot?
-# = button_to remove_bot_seat_path(seat) do
- "- Bot"
- if seat.occupied_by? current_user
-# = button_to stand_seat_path(seat), :data => { :confirm => 'Are you sure you want to leave this seat?' } do
= button_to stand_seat_path(seat) do
- "Leave"
- else
-# = button_to empty_seat_path(seat), :data => { :confirm => 'Are you sure you want to empty this seat?' } do
= button_to empty_seat_path(seat) do
- "Empty"
- else
= button_to sit_seat_path(seat) do
- "Sit"
= button_to add_bot_seat_path(seat) do
- "+ Bot"
- if seat.player
-# = button_to remove_player_seat_path(seat), :data => { :confirm => 'Are you sure you want to remove this player?' } do
= button_to remove_player_seat_path(seat) do
- "Remove Player"
.player{id: "player-#{seat.player.id}", class: @game.controlling_player == seat.player ? "taking-turn" : "",
data: {soft_token: seat.player.soft_token} }
.user-name= seat.player.display_name
- if @game.started?
.inventory-count= seat.player.inventory.count
-# Show player controls if player is owned by current_user
- if seat.player.soft_token == current_user.soft_token
= form_for(@game,
url: play_hand_game_path(@game),
method: "post",
name: "player_controls_" + seat.player_id.to_s,
id: "player_controls_" + seat.player_id.to_s) do |f|
%ul#inventory
- seat.player.inventory.each do |card|
%li
%label
= check_box_tag 'player_card_ids[]',
card.id,
false,
data: {value: card.id, card_name: card.rank.gsub('11','J') .gsub('12','Q') .gsub('13','K') .gsub('14','A') .gsub('15','2') + ' ' + card.suit}
-# %input{form: "player_controls_" + card.player_id.to_s,
type: "checkbox",
name: "player_card_ids[]",
data: {value: card.id, card_name: card.rank.gsub('11','J') .gsub('12','Q') .gsub('13','K') .gsub('14','A') .gsub('15','2') + ' ' + card.suit}}
= image_tag('cards/png/' + (card.rank.gsub('J','jack').gsub('Q','queen').gsub('K','king').gsub('A','ace') + '_of_' + card.suit.downcase + 's.png').gsub('11','jack') .gsub('12','queen') .gsub('13','king') .gsub('14','ace') .gsub('15','2'))
- disabled = @game.controlling_player != seat.player
#play-buttons
%input{type: "submit", value: "Play Hand", name: "hand_type", disabled: disabled}
%input{type: "submit", value: "Pass", name: "hand_type", disabled: disabled}
- else
.inventory
- seat.player.inventory.count.times do |index|
= image_tag('cards/png/back-pink.png')

View File

View File

@ -6,7 +6,7 @@
- @tables.each do |table|
.table
.title= link_to table.title, table
.player-count= "#{table.users.count} Players"
.player-count= "#{table.user_count} Players"
- if policy(table).update?
.owner-controls

View File

@ -3,4 +3,57 @@
= link_to 'Edit', edit_table_path(@table)
= link_to 'Destroy', game, :method => :delete, :data => { :confirm => 'Are you sure?' }
#table-component-container-container= react_component 'Table', props = {url: "#{table_path @table}"}, html_options = {id: "table-component-container"}
-# #table-component-container-container= react_component 'Table', props = {url: "#{table_path @table}"}, html_options = {id: "table-component-container"}
#table-component
%p= @table.title
- if @game.already_has?(current_user)
- if @game.startable?
= button_to 'Start', start_game_path(@game)
-# - if @game.winner_player_id || @game.nil?
-# = button_to 'New Game', new_game_table_path(@table)
-# - if @game && !@game.startable?
#table-controls
#newgame= button_to 'New Game', new_game_table_path(@table)
#qrcode
:javascript
function gen_qrcode(){
var qrcode = new QRCode(document.getElementById("qrcode"), {
text: "#{request.original_url}",
width: 384,
height: 384,
colorDark : "#000000",
colorLight : "#ffffff00",
correctLevel : QRCode.CorrectLevel.H
});
}
gen_qrcode();
$('#qrcode').on('click', function(e) {
$('#qrcode').toggleClass("full");
e.preventDefault();
});
#game-component
- if @game.winner_player_id
%h1= @game.status
#playerList
#top
= render "seat", seat: @seats[0]
#mid
= render "seat", seat: @seats[3]
= render "play_to_beat"
= render "seat", seat: @seats[1]
#bot
= render "seat", seat: @seats[2]
:javascript
var soft_token = "#{current_user.soft_token}";
-# = javascript_include_tag 'table-loader'

View File

@ -4,4 +4,5 @@
#main-menu
= link_to 'Play Now', play_now_path
= link_to 'Browse Tables', tables_path
= link_to 'Tutorial', '#'
= link_to 'Tutorial', tutorial_path
= link_to 'About', page_path('about')

View File

@ -1,3 +1,105 @@
#!/usr/bin/env ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
load Gem.bin_path('bundler', 'bundle')
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'bundle' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require "rubygems"
m = Module.new do
module_function
def invoked_as_script?
File.expand_path($0) == File.expand_path(__FILE__)
end
def env_var_version
ENV["BUNDLER_VERSION"]
end
def cli_arg_version
return unless invoked_as_script? # don't want to hijack other binstubs
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
bundler_version = nil
update_index = nil
ARGV.each_with_index do |a, i|
if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
bundler_version = a
end
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
bundler_version = $1 || ">= 0.a"
update_index = i
end
bundler_version
end
def gemfile
gemfile = ENV["BUNDLE_GEMFILE"]
return gemfile if gemfile && !gemfile.empty?
File.expand_path("../../Gemfile", __FILE__)
end
def lockfile
lockfile =
case File.basename(gemfile)
when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
else "#{gemfile}.lock"
end
File.expand_path(lockfile)
end
def lockfile_version
return unless File.file?(lockfile)
lockfile_contents = File.read(lockfile)
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
Regexp.last_match(1)
end
def bundler_version
@bundler_version ||= begin
env_var_version || cli_arg_version ||
lockfile_version || "#{Gem::Requirement.default}.a"
end
end
def load_bundler!
ENV["BUNDLE_GEMFILE"] ||= gemfile
# must dup string for RG < 1.8 compatibility
activate_bundler(bundler_version.dup)
end
def activate_bundler(bundler_version)
if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
bundler_version = "< 2"
end
gem_error = activation_error_handling do
gem "bundler", bundler_version
end
return if gem_error.nil?
require_error = activation_error_handling do
require "bundler/version"
end
return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
exit 42
end
def activation_error_handling
yield
nil
rescue StandardError, LoadError => e
e
end
end
m.load_bundler!
if m.invoked_as_script?
load Gem.bin_path("bundler", "bundle")
end

View File

@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
@ -6,11 +8,22 @@
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
bundle_binstub = File.expand_path("../bundle", __FILE__)
load Gem.bin_path('puma', 'puma')
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end
require "rubygems"
require "bundler/setup"
load Gem.bin_path("puma", "puma")

View File

@ -1,4 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
@ -6,11 +8,22 @@
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
bundle_binstub = File.expand_path("../bundle", __FILE__)
load Gem.bin_path('puma', 'pumactl')
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end
require "rubygems"
require "bundler/setup"
load Gem.bin_path("puma", "pumactl")

View File

@ -1,4 +1,9 @@
#!/usr/bin/env ruby
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
if ENV['RAILS_ENV'] == 'development'
ENV['PORT'] = '9012'
end

View File

@ -1,4 +1,9 @@
#!/usr/bin/env ruby
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
require_relative '../config/boot'
require 'rake'
Rake.application.run

View File

@ -5,6 +5,11 @@
# The application 'rspec' is installed as part of a gem, and
# this file is here to facilitate running it.
#
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",

View File

@ -1,16 +0,0 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'sass-convert' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('sass', 'sass-convert')

View File

@ -1,16 +1,17 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'spring' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
# This file loads Spring without using Bundler, in order to be fast.
# It gets overwritten when you run the `spring binstub` command.
require 'rubygems'
require 'bundler/setup'
unless defined?(Spring)
require 'rubygems'
require 'bundler'
load Gem.bin_path('spring', 'spring')
lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
spring = lockfile.specs.detect { |spec| spec.name == 'spring' }
if spring
Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
gem 'spring', spring.version
require 'spring/binstub'
end
end

View File

@ -2,6 +2,9 @@ require File.expand_path('../boot', __FILE__)
require 'rails/all'
# todo unsilence deprecation warnings. Silenced for factory_girl
ActiveSupport::Deprecation.silenced = true
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

View File

@ -1,5 +1,5 @@
set :application, "thirteen_tien_len_#{fetch(:stage)}"
set :repo_url, 'git@bitbucket.org:jessecfisher/thirteen-tien-len.git'
set :repo_url, 'git@git.chefzeppelin.com:jesse/thirteen-tien-len.git'
# If you want to import assets, you can change default asset dir (default = system)
# This directory must be in your shared directory on the server
@ -9,31 +9,44 @@ set :assets_dir, %w(public/assets public/system)
#set :branch, proc { `git rev-parse --abbrev-ref stash`.chomp }
#ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }
set :deploy_to, "/home/jesse/web/thirteen-tien-len_#{fetch(:stage)}"
set :deploy_to, "/home/jesse/srv/thirteen-tien-len_#{fetch(:stage)}"
# set :scm, :git
# set :format, :pretty
# set :log_level, :debug
# set :pty, true
set :linked_files, %w{config/database.yml .env}
# set :linked_files, %w{config/database.yml .env}
append :linked_files, "puma.rb"
# append :linked_files, "config/master.key"
append :linked_files, "config/database.yml"
append :linked_files, ".env"
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/lift-calculator}
set :rbenv_type, :user # or :system, depends on your rbenv setup
set :rbenv_ruby, '2.3.0'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_type, :system # or :system, depends on your rbenv setup
# set :rbenv_ruby, '2.6.0'
set :rbenv_ruby, File.read('.ruby-version').strip
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
append :rbenv_map_bins, 'puma', 'pumactl'
set :rbenv_roles, :all # default value
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
set :default_env, {
'PATH' => 'PATH=/usr/local/rbenv/bin:./bin:$PATH:./bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/core_perl'
}
# set :keep_releases, 5
set :nginx_path, '/etc/nginx' # directory containing sites-available and sites-enabled
set :nginx_template, 'config/deploy/nginx_conf.erb' # configuration template
set :rbenv_custom_path, "/usr/local/rbenv"
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_custom_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_custom_path)}/bin/rbenv exec"
# set :nginx_path, '/etc/nginx' # directory containing sites-available and sites-enabled
# set :nginx_template, 'config/deploy/nginx_conf.erb' # configuration template
#set :nginx_server_name, 'example.com' # optional, defaults to :application
#set :nginx_upstream, 'example-app' # optional, defaults to :application
set :nginx_listen, 80 # optional, default is not set
set :nginx_roles, :all
# set :nginx_listen, 80 # optional, default is not set
# set :nginx_roles, :all
## postgresql
set :pg_user, "thirteen_tien_len_#{fetch(:stage)}"

View File

@ -1,15 +1,15 @@
set :stage, :production
set :nginx_server_name, 'tienlen.ga' # optional, defaults to :application
set :nginx_server_name, '13.24x7.hk' # optional, defaults to :application
# Simple Role Syntax
# ==================
# Supports bulk-adding hosts to roles, the primary
# server in each group is considered to be the first
# unless any hosts have the primary property set.
role :app, %w{jesse@tienlen.ga}
role :web, %w{jesse@tienlen.ga}
role :db, %w{jesse@tienlen.ga}
role :app, %w{jesse@13.24x7.hk}
# Supports bulk-adding hosts to roles, the primary
role :web, %w{jesse@13.24x7.hk}
role :db, %w{jesse@13.24x7.hk}
# Extended Server Syntax
# ======================
@ -17,7 +17,7 @@ role :db, %w{jesse@tienlen.ga}
# definition into the server list. The second argument
# something that quacks like a hash can be used to set
# extended properties on the server.
server 'tienlen.ga', user: 'jesse', roles: %w{web app db}, my_property: :my_value
server '13.24x7.hk', user: 'jesse', roles: %w{web app db}, my_property: :my_value
# you can set custom ssh options
# it's possible to pass any option but you need to keep in mind that net/ssh understand limited list of options

View File

@ -38,8 +38,8 @@ Rails.application.configure do
password: Rails.application.secrets.email_provider_password
}
# ActionMailer Config
config.action_mailer.default_url_options = { host: 'localhost:3000' }
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { host: 'grandpo.ohbah.com:3000' }
config.action_mailer.delivery_method = :sendmail
config.action_mailer.raise_delivery_errors = true
# Send email in development mode?
config.action_mailer.perform_deliveries = true
@ -54,4 +54,5 @@ Rails.application.configure do
# Add Rack::LiveReload to the bottom of the middleware stack with the default options.
config.middleware.insert_after ActionDispatch::Static, Rack::LiveReload
BetterErrors::Middleware.allow_ip! '10.0.0.0/16'
end

View File

@ -22,7 +22,7 @@ Rails.application.configure do
# config.action_dispatch.rack_cache = true
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
config.serve_static_assets = true
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
@ -95,4 +95,7 @@ Rails.application.configure do
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
# config.relative_url_root = "/13"
# config.action_controller.relative_url_root = '/13'
end

View File

@ -5,7 +5,7 @@ Rails.application.configure do
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
config.cache_classes = false
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that

View File

@ -6,3 +6,4 @@ Rails.application.config.assets.version = '1.0'
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# Rails.application.config.assets.precompile += %w( search.js )
Rails.application.config.assets.precompile += %w( table-loader.js )

View File

@ -8,8 +8,8 @@ module DevisePermittedParameters
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
devise_parameter_sanitizer.for(:account_update) << :name
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
end

View File

@ -1,24 +0,0 @@
# config/initializers/upmin.rb
# Extends the Upmin ApplicationController to limit access to users with an admin role.
# Depends on Devise for authentication plus role-based authorization.
# Be sure to restart your server when you modify this file.
module AdminOnly
extend ActiveSupport::Concern
included do
before_action :authenticate_user!
before_action :admin_only
end
private
def admin_only
unless current_user.admin?
redirect_to :back, alert: 'Access denied.'
end
rescue ActionController::RedirectBackError
redirect_to '/', alert: 'Access denied.'
end
end
Upmin::ApplicationController.send :include, AdminOnly

View File

@ -0,0 +1,66 @@
upstream thirteen_production {
server unix:///home/jesse/srv/thirteen-tien-len_production/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
server_name 13.whitewizardweb.com 13.24x7.hk 13.mounthoodlodge.com 13.my.to;
root /home/jesse/srv/thirteen-tien-len_production/current/public;
access_log /home/jesse/srv/thirteen-tien-len_production/shared/log/nginx.access.log;
try_files $uri @app;
location @app {
proxy_pass http://thirteen_production;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_next_upstream error timeout invalid_header http_502;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
}
# listen 443 ssl; # managed by Certbot
# ssl_certificate /etc/letsencrypt/live/13dev.quaff.top/fullchain.pem; # managed by Certbot
# ssl_certificate_key /etc/letsencrypt/live/13dev.quaff.top/privkey.pem; # managed by Certbot
# include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/13.24x7.hk/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/13.24x7.hk/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
listen 80;
listen [::]:80;
server_name 13.whitewizardweb.com;
return 301 https://13.whitewizardweb.com$request_uri;
}
server {
if ($host = 13.24x7.hk) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name 13.whitewizardweb.com 13.24x7.hk 13.mounthoodlodge.com 13.my.to;
return 404; # managed by Certbot
}

View File

@ -1,9 +1,9 @@
upstream 13dev {
server localhost:9012;
server localhost:9913;
}
server {
server_name 13dev.quaff.top;
server_name 13dev.owlwphant.icu;
root /home/jesse/web/thirteen-tien-len/public;
access_log /home/jesse/web/thirteen-tien-len/log/nginx.log;
@ -27,11 +27,11 @@ server {
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/13dev.quaff.top/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/13dev.quaff.top/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# listen 443 ssl; # managed by Certbot
# ssl_certificate /etc/letsencrypt/live/13dev.quaff.top/fullchain.pem; # managed by Certbot
# ssl_certificate_key /etc/letsencrypt/live/13dev.quaff.top/privkey.pem; # managed by Certbot
# include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

View File

@ -1,13 +1,32 @@
Rails.application.routes.draw do
resources :players
resources :tables do
member do
post 'new_game'
post 'end_game'
end
resources :seats do
member do
patch 'sit'
patch 'stand'
end
end
resources :games
resources :games do
# member do
# post :join
# end
end
end
resources :seats do
member do
post 'sit'
post 'stand'
post 'add_bot'
post 'remove_bot'
post 'empty'
post 'remove_player'
end
end
resources :games do
@ -15,7 +34,7 @@ Rails.application.routes.draw do
get 'my-inventory'
post 'start'
post 'join'
patch 'play_hand'
post 'play_hand'
end
resources :seats do
member do
@ -25,9 +44,9 @@ Rails.application.routes.draw do
end
end
mount Upmin::Engine => '/admin'
root to: 'visitors#index'
get '/play-now', to: 'games#play_now', as: 'play_now'
get '/play-now', to: 'tables#play_now', as: 'play_now'
get '/tutorial', to: 'tables#tutorial', as: 'tutorial'
devise_for :users, controllers: { registrations: "users/registrations" }
resources :users
get '/loaderio-456644f4db1fcd1e8578be882d2fc476.txt', to: redirect('/assets/loaderio-456644f4db1fcd1e8578be882d2fc476.txt')

View File

@ -12,12 +12,12 @@
development:
admin_name: Wizard of Hearts
admin_email: jesse@quaff.top
admin_email: jesse@chefzeppelin.com
admin_password: changeme
admin_soft_token: SeedToken
email_provider_username: <%= ENV["GMAIL_USERNAME"] %>
email_provider_password: <%= ENV["GMAIL_PASSWORD"] %>
domain_name: 13dev.quaff.top
domain_name: localhost
secret_key_base: 31b41a9c65cd195a147284c28603ad690792213a13157935f4de1fb232ce3283a44ec52f4d5e9a3c0df041e4b19536d739246616d26d147081dc1c906288771d
test:

View File

@ -1,4 +1,4 @@
class DeviseCreateUsers < ActiveRecord::Migration
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
def change
create_table(:users) do |t|
## Database authenticatable

View File

@ -1,4 +1,4 @@
class AddNameToUsers < ActiveRecord::Migration
class AddNameToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :name, :string
end

View File

@ -1,4 +1,4 @@
class AddConfirmableToUsers < ActiveRecord::Migration
class AddConfirmableToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :confirmation_token, :string
add_column :users, :confirmed_at, :datetime

View File

@ -1,4 +1,4 @@
class AddRoleToUsers < ActiveRecord::Migration
class AddRoleToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :role, :integer
end

View File

@ -1,4 +1,4 @@
class DeviseInvitableAddToUsers < ActiveRecord::Migration
class DeviseInvitableAddToUsers < ActiveRecord::Migration[5.2]
def up
change_table :users do |t|
t.string :invitation_token

View File

@ -1,4 +1,4 @@
class CreateGames < ActiveRecord::Migration
class CreateGames < ActiveRecord::Migration[5.2]
def change
create_table :games do |t|
t.string :title

View File

@ -1,4 +1,4 @@
class CreatePlayers < ActiveRecord::Migration
class CreatePlayers < ActiveRecord::Migration[5.2]
def change
create_table :players do |t|
t.references :game, index: true

View File

@ -1,4 +1,4 @@
class CreatePlayerCards < ActiveRecord::Migration
class CreatePlayerCards < ActiveRecord::Migration[5.2]
def change
create_table :player_cards do |t|
t.references :player, index: true

View File

@ -1,4 +1,4 @@
class AddStatusToGames < ActiveRecord::Migration
class AddStatusToGames < ActiveRecord::Migration[5.2]
def change
add_column :games, :status, :string
end

View File

@ -1,4 +1,4 @@
class AddAttrsToPlayerCards < ActiveRecord::Migration
class AddAttrsToPlayerCards < ActiveRecord::Migration[5.2]
def change
add_column :player_cards, :value, :integer
add_column :player_cards, :rank, :string

View File

@ -1,4 +1,4 @@
class AddControlPlayerIdToGame < ActiveRecord::Migration
class AddControlPlayerIdToGame < ActiveRecord::Migration[5.2]
def change
add_column :games, :control_player_id, :integer
end

View File

@ -1,4 +1,4 @@
class CreatePlays < ActiveRecord::Migration
class CreatePlays < ActiveRecord::Migration[5.2]
def change
create_table :plays do |t|
t.references :game, index: true

View File

@ -1,4 +1,4 @@
class AddPlayIdToPlayerCard < ActiveRecord::Migration
class AddPlayIdToPlayerCard < ActiveRecord::Migration[5.2]
def change
add_column :player_cards, :play_id, :integer
end

View File

@ -1,4 +1,4 @@
class AddPlayToBeatToGame < ActiveRecord::Migration
class AddPlayToBeatToGame < ActiveRecord::Migration[5.2]
def change
add_reference :games, :play_to_beat, index: true
end

View File

@ -1,4 +1,4 @@
class PlayToBeat < ActiveRecord::Migration
class PlayToBeat < ActiveRecord::Migration[5.2]
def change
create_table :play_to_beats do |t|
t.integer :game_id

View File

@ -1,4 +1,4 @@
class AddWinnerPlayerIdToGame < ActiveRecord::Migration
class AddWinnerPlayerIdToGame < ActiveRecord::Migration[5.2]
def change
add_column :games, :winner_player_id, :integer
end

View File

@ -1,4 +1,4 @@
class RenameControlPlayerIdToControllingPlayerId < ActiveRecord::Migration
class RenameControlPlayerIdToControllingPlayerId < ActiveRecord::Migration[5.2]
def change
rename_column :games, :control_player_id, :controlling_player_id
end

View File

@ -1,4 +1,4 @@
class CreateTables < ActiveRecord::Migration
class CreateTables < ActiveRecord::Migration[5.2]
def change
create_table :tables do |t|
t.string :title

View File

@ -1,4 +1,4 @@
class CreateSeats < ActiveRecord::Migration
class CreateSeats < ActiveRecord::Migration[5.2]
def change
create_table :seats do |t|
t.references :table, index: true

View File

@ -1,4 +1,4 @@
class AddCurrentGameIdToTable < ActiveRecord::Migration
class AddCurrentGameIdToTable < ActiveRecord::Migration[5.2]
def change
add_column :tables, :current_game_id, :integer
end

View File

@ -1,4 +1,4 @@
class AddTableIdToGames < ActiveRecord::Migration
class AddTableIdToGames < ActiveRecord::Migration[5.2]
def change
add_column :games, :table_id, :integer
end

View File

@ -1,4 +1,4 @@
class AddSoftTokenToUsersAndPlayers < ActiveRecord::Migration
class AddSoftTokenToUsersAndPlayers < ActiveRecord::Migration[5.2]
def change
add_column :users, :soft_token, :string
add_column :players, :soft_token, :string

View File

@ -1,4 +1,4 @@
class AddPositionToSeats < ActiveRecord::Migration
class AddPositionToSeats < ActiveRecord::Migration[5.2]
def change
add_column :seats, :position, :integer
end

View File

@ -1,4 +1,4 @@
class AddUserSoftTokenToSeats < ActiveRecord::Migration
class AddUserSoftTokenToSeats < ActiveRecord::Migration[5.2]
def change
add_column :seats, :user_soft_token, :string
end

View File

@ -1,4 +1,4 @@
class AddGameIdToSeats < ActiveRecord::Migration
class AddGameIdToSeats < ActiveRecord::Migration[5.2]
def change
add_column :seats, :game_id, :integer
end

View File

@ -1,4 +1,4 @@
class AddPlayerIdToSeat < ActiveRecord::Migration
class AddPlayerIdToSeat < ActiveRecord::Migration[5.2]
def change
add_column :seats, :player_id, :integer
end

View File

@ -0,0 +1,5 @@
class AddWinCountToUser < ActiveRecord::Migration[5.2]
def change
add_column :users, :win_count, :integer, default: 0
end
end

View File

@ -0,0 +1,5 @@
class AddIsBotToPlayer < ActiveRecord::Migration[5.2]
def change
add_column :players, :is_bot, :boolean, default: false
end
end

View File

@ -1,4 +1,3 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
@ -11,12 +10,12 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160222131306) do
ActiveRecord::Schema.define(version: 2021_11_08_045859) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "games", force: true do |t|
create_table "games", force: :cascade do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
@ -25,18 +24,17 @@ ActiveRecord::Schema.define(version: 20160222131306) do
t.integer "play_to_beat_id"
t.integer "winner_player_id"
t.integer "table_id"
t.index ["play_to_beat_id"], name: "index_games_on_play_to_beat_id"
end
add_index "games", ["play_to_beat_id"], name: "index_games_on_play_to_beat_id", using: :btree
create_table "play_to_beats", force: true do |t|
create_table "play_to_beats", force: :cascade do |t|
t.integer "game_id"
t.integer "play_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "player_cards", force: true do |t|
create_table "player_cards", force: :cascade do |t|
t.integer "player_id"
t.integer "card_id"
t.datetime "created_at"
@ -45,33 +43,31 @@ ActiveRecord::Schema.define(version: 20160222131306) do
t.string "rank"
t.string "suit"
t.integer "play_id"
t.index ["card_id"], name: "index_player_cards_on_card_id"
t.index ["player_id"], name: "index_player_cards_on_player_id"
end
add_index "player_cards", ["card_id"], name: "index_player_cards_on_card_id", using: :btree
add_index "player_cards", ["player_id"], name: "index_player_cards_on_player_id", using: :btree
create_table "players", force: true do |t|
create_table "players", force: :cascade do |t|
t.integer "game_id"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "soft_token"
t.boolean "is_bot", default: false
t.index ["game_id"], name: "index_players_on_game_id"
t.index ["user_id"], name: "index_players_on_user_id"
end
add_index "players", ["game_id"], name: "index_players_on_game_id", using: :btree
add_index "players", ["user_id"], name: "index_players_on_user_id", using: :btree
create_table "plays", force: true do |t|
create_table "plays", force: :cascade do |t|
t.integer "game_id"
t.integer "player_id"
t.datetime "created_at"
t.datetime "updated_at"
t.index ["game_id"], name: "index_plays_on_game_id"
t.index ["player_id"], name: "index_plays_on_player_id"
end
add_index "plays", ["game_id"], name: "index_plays_on_game_id", using: :btree
add_index "plays", ["player_id"], name: "index_plays_on_player_id", using: :btree
create_table "seats", force: true do |t|
create_table "seats", force: :cascade do |t|
t.integer "table_id"
t.integer "user_id"
t.datetime "created_at"
@ -80,19 +76,18 @@ ActiveRecord::Schema.define(version: 20160222131306) do
t.string "user_soft_token"
t.integer "game_id"
t.integer "player_id"
t.index ["table_id"], name: "index_seats_on_table_id"
t.index ["user_id"], name: "index_seats_on_user_id"
end
add_index "seats", ["table_id"], name: "index_seats_on_table_id", using: :btree
add_index "seats", ["user_id"], name: "index_seats_on_user_id", using: :btree
create_table "tables", force: true do |t|
create_table "tables", force: :cascade do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "current_game_id"
end
create_table "users", force: true do |t|
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: ""
t.string "reset_password_token"
@ -120,12 +115,12 @@ ActiveRecord::Schema.define(version: 20160222131306) do
t.string "invited_by_type"
t.integer "invitations_count", default: 0
t.string "soft_token"
t.integer "win_count", default: 0
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
t.index ["invitations_count"], name: "index_users_on_invitations_count"
t.index ["invited_by_id"], name: "index_users_on_invited_by_id"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree
add_index "users", ["invitations_count"], name: "index_users_on_invitations_count", using: :btree
add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end

View File

@ -2,11 +2,31 @@
# As a user
# I want to add a bot to a table
# So I can play against the computer
feature 'Add bot', type: :feature, js: true do
feature 'Add bot', type: :feature do
before(:each) do
@table = FactoryGirl.create :table
visit table_path @table
end
# Scenario: User can add a bot if there is room at the table
# Given I can edit the table
# When I see the table with an empty seat
# Then I see a button to add a bot
scenario 'visitor can add a bot if the seat is empty' do
@button = page.find_button('+ Bot', match: :first).click
expect(page).to have_content "BotPlayer"
end
scenario 'visitor can not add a bot if the seat is occupied by bot' do
@button = page.find_button('+ Bot', match: :first).click
page.assert_selector('button', text: '+ Bot', count: 3)
end
scenario 'visitor can not add a bot if the seat is occupied by visitor' do
@button = page.find_button('Sit', match: :first).click
page.assert_selector('button', text: '+ Bot', count: 3)
end
scenario 'user can add a bot if the table is not full' do
skip "To be implemented"
#signin('test@example.com', 'please123')

View File

@ -0,0 +1,35 @@
# Feature: Bot takes turns
# As a player
# I want bots to take turns
# So I can play against the computer
feature 'Bot takes turn', type: :feature do
before(:each) do
@table = FactoryGirl.create :table
@game = @table.current_game
visit table_path @table
end
scenario 'bot player passes' do
@button = page.find_button('+ Bot', match: :first).click
expect(page).to have_content "BotPlayer"
@button = page.find_button('Sit', match: :first).click
click_button "Start"
click_button 'Pass'
expect(page).to have_content "Bot is passes"
end
scenario 'bot player plays single' do
@button = page.find_button('+ Bot', match: :first).click
expect(page).to have_content "BotPlayer"
@button = page.find_button('Sit', match: :first).click
click_button "Start"
@game = @table.current_game
if @game.controlling_player.soft_token == page.current_user.soft_token
@card_to_play = @game.controlling_player.inventory.first
find("[data-card-name='#{@card_to_play.to_s}']").click
click_button 'Play Hand'
end
expect(@game.play_to_beat.player.is_bot?).to eq true
expect(@game.play_to_beat.hand_type).to eq "single"
end
end

View File

@ -0,0 +1,22 @@
# Feature: Remove bot from seat
# As a user
# I want to remove a bot from a sea
feature 'Remove bot', type: :feature do
before(:each) do
@table = FactoryGirl.create :table
visit table_path @table
end
# Scenario: Visitor can remove a bot from seat
# Given I can edit the table
# When I see the seat with a bot
# Then I see a button to remove a bot
scenario 'visitor can remove a bot from a seat' do
@button = page.find_button('+ Bot', match: :first).click
page.assert_selector('button', text: '+ Bot', count: 3)
expect(page).to have_content "BotPlayer"
@button = page.find_button('- Bot', match: :first).click
expect(page).to have_content "Removed Bot"
page.assert_selector('button', text: '+ Bot', count: 4)
end
end

View File

@ -1,18 +1,16 @@
require 'rails_helper'
RSpec.feature "EndOfGames", type: :feature, js: true do
RSpec.feature "EndOfGames", type: :feature do
# Given I am in a started game
before(:each) do
before(:all) do
# If test is unable to click correct card, use wider window
# page.driver.browser.manage.window.resize_to(1640, 1090)
@game = setup_game
@game.reload
@player = @game.controlling_player
signin(@player.user.email,'password')
visit table_path @game.table
end
# And it is my turn
# And I play my last cards
# Then I win the game
scenario 'I win the game' do
# Play lowest card
# Other players always pass
# Play next lowest card
@ -39,14 +37,39 @@ RSpec.feature "EndOfGames", type: :feature, js: true do
@game.reload
end
end
end
# And it is my turn
# And I play my last cards
# Then I win the game
scenario 'I win the game' do
# After I play my last card(s)
# Expect that I am the winner
@game.reload
expect(@game.winner).to eq @player
click_button "New Game"
expect(page).to have_content "Game started"
end
scenario 'I start a new game at the same table' do
click_button "New Game"
expect(page).to have_content "Game started"
end
describe 'I lose the game' do
pending
# Another player plays their last card(s)
# Expect that they are the winner
end
describe 'I win 2nd place' do
pending
# Another player plays their last card(s)
# Expect that they are the winner
end
describe 'Play to beat clears appropriately' do
pending
# Another player plays their last card(s)
# Expect that they are the winner
end

View File

@ -2,7 +2,7 @@
# As a visitor
# I want to quickly join a game
# So I can play
feature 'Play now', :devise, js: true do
feature 'Play now', :devise do
# Scenario: Visitor can play now
# Given I am not signed in
# When I click Play Now
@ -16,6 +16,7 @@ feature 'Play now', :devise, js: true do
end
it 'creates and joins a new game' do
#TODO: Fix race condition
sleep 2
expect(page).to have_content "Hand to beat"
#Game title derived from visitor soft_token
expect(page).to have_content "#{Game.last.players.first.soft_token[0..4]}"
@ -26,25 +27,30 @@ feature 'Play now', :devise, js: true do
context 'visitor joins an existing game' do
before do
FactoryGirl.create :game
@game = Game.last
FactoryGirl.create :table
@table = Table.last
visit root_path
expect(Game.all.count).to eq 1
# expect(Game.all.count).to eq 1
click_link 'Play Now'
end
it 'shows and starts the game' do
#TODO: Deprecated it shows the game title
#expect(page).to have_content "Test Game"
expect(page).to have_content "Hand to beat"
# expect(page).to have_content "Hand to beat"
# TODO fix race condition
sleep 8
#it 'is located at the correct url' do
expect(current_path).to eq game_path(@game)
expect(page).to have_current_path(table_path(@table))
expect(page).to have_content "Guest"
expect(current_path).to eq table_path(@table)
#it 'shows the visitor as a player' do
@game = Game.last
@player = @game.players.last
@playerComponent = page.find("#player-1")
@playerComponent = page.find_all(".seat").first
#TODO: have_content @player.display_name
expect(@playerComponent.text).to have_content("Guest#{@player.soft_token[0..5]}")
expect(@playerComponent).to have_content("Guest#{@player.soft_token[0..4]}")
#it 'shows other players' do
# Add another player
@ -61,8 +67,7 @@ feature 'Play now', :devise, js: true do
visit current_path
visit current_path
visit current_path
expect(page).to have_content 'Inventory'
expect(Game.all.count).to eq 1
expect(page).to have_content 'Hand to beat'
end
end
end

View File

@ -2,13 +2,13 @@ require 'rails_helper'
include Warden::Test::Helpers
Warden.test_mode!
feature 'Play a hand', type: :feature, js: true do
feature 'Play a hand', type: :feature do
before(:each) do
@game = setup_game
@game.reload
@player = @game.controlling_player
signin(@player.user.email,'password')
visit game_path @game
visit table_path @game.table
end
after(:each) do
@ -32,13 +32,12 @@ feature 'Play a hand', type: :feature, js: true do
# Play the highest card
@card_to_play = @player.inventory.last
find_card(@card_to_play).click
#click_button 'Play Hand'
click_button "play_hand_button_#{@player.id}"
click_button 'Play Hand'
# No play to beat, because play was invalid
expect(@game.play_to_beat).to eq(nil)
# TODO: This scenario is causing other scenarios to fail unless we slow down here
sleep 1
# sleep 1
# TODO: Flash messages
#expect(page).to have_content "First hand must contain the lowest card: #{@game.lowest_card.to_s}"
end
@ -49,9 +48,10 @@ feature 'Play a hand', type: :feature, js: true do
# Then I see the hand to beat is this play
scenario 'first play contains lowest card' do
@card_to_play = @game.lowest_card
# If test can't click card enable js and click coordinates
# find_card(@card_to_play).click(x: 0, y: 0)
find_card(@card_to_play).click
#click_button 'Play Hand'
click_button "play_hand_button_#{@player.id}"
click_button 'Play Hand'
expect(cards_to_beat).to eq @game.lowest_card.to_s
end
@ -63,6 +63,7 @@ feature 'Play a hand', type: :feature, js: true do
# Store initial state of players inventory
@player_inventory = @player.inventory.join(' ')
@card_to_play = @player.inventory.first
expect(page).to have_css("#inventory [data-card-name='#{@card_to_play.to_s}']")
find_card(@card_to_play).click
click_button 'Play Hand'
#wait_for_ajax
@ -70,8 +71,7 @@ feature 'Play a hand', type: :feature, js: true do
# Played hand is rendered
expect(cards_to_beat).to eq @game.lowest_card.to_s
# Player inventory is rendered without played cards
#TODO: Deprecated have_content for inventory. Write new expectation.
expect(page.find("#player_controls_#{@player.id}")).to_not have_content(@card_to_play.to_s)
expect(page).not_to have_css("#inventory [data-card-name='#{@card_to_play.to_s}']")
end
# Scenario: Invalid cards do not leave the players inventory
@ -89,16 +89,15 @@ feature 'Play a hand', type: :feature, js: true do
@cards_to_play << @player.inventory.first
# Select each card to play
@cards_to_play.map {|card| find("[data-card-name='#{card.to_s}'] ~ img").click }
#click_button 'Play Hand'
click_button "play_hand_button_#{@player.id}"
@cards_to_play.map {|card| find("[data-card-name='#{card.to_s}']").click }
click_button 'Play Hand'
# Played hand is rendered
# TODO: Flash messages
#expect(page).to have_content("Invalid pair")
expect(page).to have_content("Invalid pair")
# Player inventory is rendered with played cards
@initial_player_inventory.each do |card|
expect(page).to have_selector("[data-card-name='#{card.to_s}'] ~ img")
expect(page).to have_css("#inventory input[data-card-name='#{card.to_s}']")
end
# TODO: This scenario is causing other scenarios to fail unless we slow down here
sleep 1
@ -123,7 +122,7 @@ feature 'Play a hand', type: :feature, js: true do
click_button 'Play Hand'
expect(page).to have_content "Hand to beat"
expect(cards_to_beat).to eq @card_to_play.to_s
expect(page).to have_selector("#player-#{@next_player_id}.has-control")
expect(page).to have_selector("#player-#{@next_player_id}.taking-turn")
end
# Scenario: Player can not play an invalid hand on their turn
@ -134,17 +133,16 @@ feature 'Play a hand', type: :feature, js: true do
#@game.reload
@cards_to_play = [@game.controlling_player.player_cards.order(:value).first.to_s, @game.controlling_player.player_cards.order(:value).last.to_s]
@cards_to_play.each do |card|
find("[data-card-name='#{card.to_s}'] ~ img").click
find("[data-card-name='#{card.to_s}']").click
end
#click_button 'Play Hand'
click_button "play_hand_button_#{@player.id}"
click_button 'Play Hand'
# controlling_player plays an invalid hand
# expect invalid hand message
#:TODO: Flash messages
#expect(page).to have_content("Invalid pair.")
# expect inventory to remain unchanged
@game.controlling_player.inventory.each do |card|
expect(page).to have_selector("[data-card-name='#{card.to_s}'] ~ img")
expect(page).to have_selector("[data-card-name='#{card.to_s}']")
end
# TODO: This scenario is causing other scenarios to fail unless we slow down here
sleep 1
@ -161,26 +159,28 @@ feature 'Play a hand', type: :feature, js: true do
@non_controlling_player = @game.players.where.not(id: @game.controlling_player_id).first
login_as(@non_controlling_player.user, scope: :user)
visit game_path @game
#expect(page).to_not have_button 'Play Hand'
elem = page.find "input#play_hand_button_#{@non_controlling_player.id}"
expect(elem.disabled?).to be true
# TODO: Submit a POST request
expect(page).to_not have_button 'Play Hand'
# click_button 'Play Hand'
# expect(page).to have_content "not your turn"
end
# Scenario: Player can pass when it is their turn
# Given I am the active player
# When I pass
# Then I see an successful pass message
# scenario 'active player can pass', js: true do
scenario 'active player can pass' do
@current_user = @game.controlling_player
#click_button 'Pass'
click_button "pass_hand_button_#{@player.id}"
# accept_confirm do
click_button 'Pass'
# end
# click_button "pass_hand_button_#{@player.id}"
## TODO: Flash messages
#expect(page).to have_content 'Successfully passed.'
expect(page).to have_content 'Successfully passed.'
# Expect active player should rotate
#expect(page).to_not have_button 'Play Hand'
elem = page.find "input#play_hand_button_#{@player.id}"
expect(elem.disabled?).to be false
# expect(page).to_not have_button 'Play Hand'
# elem = page.find "input#play_hand_button_#{@player.id}"
# expect(elem.disabled?).to be false
@new_controlling_player = @game.controlling_player
expect(@game.controlling_player).to_not eq(@controlling_player)
@ -197,9 +197,9 @@ feature 'Play a hand', type: :feature, js: true do
@game.reload
@player = @game.controlling_player
@card_to_play = @player.inventory.first
find("[data-card-name='#{@card_to_play.to_s}'] ~ img").click
#click_button 'Play Hand'
click_button "play_hand_button_#{@player.id}"
find("[data-card-name='#{@card_to_play.to_s}']").click
click_button 'Play Hand'
# click_button "play_hand_button_#{@player.id}"
#TODO: Fix race condition
sleep 4
@ -212,13 +212,11 @@ feature 'Play a hand', type: :feature, js: true do
@game.controlling_player_id = @player.id
@game.save
@game.reload
visit game_path @game
visit table_path @game.table
# Expect active player should rotate
#expect(page).to have_button 'Play Hand'
expect(page).to have_button "play_hand_button_#{@player.id}"
#expect(@game.player_to_beat).to eq(@game.controlling_player)
expect(page).to have_content 'Hand to beat: None'
expect(page).to have_button 'Play Hand'
expect(@game.player_to_beat).to eq(@game.controlling_player)
expect(page).to have_content "Hand to beat:\nNone"
end
# Scenario: Player wins the game
@ -227,10 +225,13 @@ feature 'Play a hand', type: :feature, js: true do
# And I am the first player to do so
# Then I see a 1st place winner message
scenario 'first place winner' do
@card_to_play = @player.inventory.first
@player.inventory[1..12].map{|card| card.destroy}
# play last card
pending "TBD"
find_card(@card_to_play).click
click_button 'Play Hand'
expect(@player.inventory.count).to eq 0
expect(page).to have_content "Winner: #{@player.display_name}"
expect(page).to have_content "Player #{@player.display_name} wins!"
end

View File

@ -2,7 +2,7 @@
# As a visitor
# I want to sit in a seat
# So I can be at a table and play a game
feature 'Seats', :devise, js: true do
feature 'Seats', :devise do
context "As a visitor" do
before(:each) do
@table = FactoryGirl.create :table
@ -15,43 +15,45 @@ feature 'Seats', :devise, js: true do
end
it 'sit button is disabled for unavailable seats' do
@sit_buttons = page.find_all('button', text: 'Sit')
expect(@sit_buttons.length).to eq 4
@button = page.find_button('Sit', match: :first)
@button.click
expect(page).to have_content "Guest"
expect(@button.disabled?).to eq true
@sit_buttons = page.find_all('button', text: 'Sit')
expect(@sit_buttons.length).to eq 3
end
it 'has a stand button if current user is seated' do
@button = page.find_button('Sit', match: :first)
@button.click
expect(page).to have_content "Guest"
@buttons = page.find_all('button', text: 'Stand')
@buttons = page.find_all('button', text: 'Leave')
expect(@buttons.length).to eq 1
end
scenario 'table seats match up with game seats' do
click_button 'Sit', match: :first
expect(page).to have_content "Guest"
expect(page.find(:css, ".game-seat.position-1")).to have_content "Guest"
expect(page.find(:css, ".seat.position-1 .player")).to have_content "Guest"
click_button 'Sit', match: :first
expect(page).to have_content "Guest"
expect(page.find(:css, ".game-seat.position-2")).to have_content "Guest"
expect(page.find(:css, ".seat.position-2 .player")).to have_content "Guest"
end
#TODO: User can only occupy one seat per table
scenario 'visitor changes seats' do
click_button 'Sit', match: :first
expect(page).to have_content "Guest"
expect(page.find(:css, ".game-seat.position-1")).to have_content "Guest"
expect(page.find(:css, ".seat.position-1")).to have_content "Guest"
click_button 'Sit', match: :first
expect(page).to have_content "Guest"
expect(page.find(:css, ".game-seat.position-2")).to have_content "Guest"
expect(page.find(:css, ".seat.position-2")).to have_content "Guest"
expect(page.text.scan('Guest').count).to eq 1
end
scenario 'visitor can join the current game' do
click_button 'Sit', match: :first
sleep 3
expect(page).to have_content "Guest"
expect(page.text.scan('Guest').count).to eq 1
end
@ -60,12 +62,15 @@ feature 'Seats', :devise, js: true do
find_all(:button, "Sit")
end
scenario 'visitor can leave the current game' do
# scenario 'visitor can leave the current game', js: true do
scenario 'seated visitor can leave the current game' do
click_button 'Sit', match: :first
expect(page).to have_content 'Guest'
expect(page.text.scan('Guest').count).to eq 1
click_button 'Stand', match: :first
expect(page.find('.game-seat.position-1')).to have_content 'Sit'
# accept_confirm do
click_button 'Leave', match: :first
# end
expect(page.find('.seat.position-1')).to have_content 'Sit'
expect(sit_buttons.length).to eq 4
expect(page.text.scan('Guest').count).to eq 0
end
@ -81,27 +86,24 @@ feature 'Seats', :devise, js: true do
end
scenario 'user can sit at the table' do
#TODO: Fix race condition
expect(page).to have_content "Sit"
click_button 'Sit', match: :first
expect(page).to have_content @user.email
end
scenario 'user can join the current game' do
expect(page).to have_content "Sit"
click_button 'Sit', match: :first
expect(page).to have_content @user.email
expect(page.text.scan(@user.email).count).to eq 1
end
# scenario 'user can leave the current game', js: true do
scenario 'user can leave the current game' do
expect(page).to have_content "Sit"
click_button 'Sit', match: :first
expect(page).to have_content @user.email
expect(page.text.scan(@user.email).count).to eq 1
click_button 'Stand', match: :first
expect(page).to have_content "Sit"
sleep 1
# accept_confirm do
click_button 'Leave', match: :first
# end
expect(page.text.scan(@user.email).count).to eq 0
end

View File

@ -8,7 +8,7 @@ feature 'Table index', :devise do
# Given I am not signed in
# When I click browse tables
# Then I see an index of tables
scenario 'I can see all the tables', js: true do
scenario 'I can see all the tables' do
5.times { FactoryGirl.create :table }
visit root_path
click_link 'Browse Tables'
@ -24,7 +24,7 @@ feature 'Table index', :devise do
# Given I am signed in
# When I click browse tables
# Then I see an index of tables
scenario 'I can see all the tables', js: true do
scenario 'I can see all the tables' do
@user = FactoryGirl.create :user
signin(@user.email,'password')

View File

@ -10,23 +10,26 @@ feature 'Table show', :devise do
click_link @table.title
end
scenario 'visitor can sit at the table', js: true do
scenario 'visitor can sit at the table' do
click_button 'Sit', match: :first
expect(page).to have_content "Guest"
end
scenario 'visitor can join the current game', js: true do
scenario 'visitor can join the current game' do
click_button 'Sit', match: :first
expect(page).to have_content "Guest"
expect(page.text.scan('Guest').count).to eq 1
end
scenario 'visitor can leave the current game', js: true do
# scenario 'visitor can leave the current game', js: true do
scenario 'visitor can leave the current game' do
click_button 'Sit', match: :first
expect(page).to have_content "Guest"
expect(page.text.scan('Guest').count).to eq 1
# accept_confirm do
click_button 'Stand', match: :first
expect(page.find('.game-seat.position-1')).to have_content "Sit"
# end
expect(page.find('.seat.position-1')).to have_content "Sit"
expect(page.text.scan('Guest').count).to eq 0
end
@ -40,27 +43,30 @@ feature 'Table show', :devise do
visit table_path @table
end
scenario 'user can sit at the table', js: true do
scenario 'user can sit at the table' do
#TODO: Fix race condition
expect(page).to have_content "Sit"
click_button 'Sit', match: :first
expect(page).to have_content @user.email
end
scenario 'user can join the current game', js: true do
scenario 'user can join the current game' do
expect(page).to have_content "Sit"
click_button 'Sit', match: :first
expect(page).to have_content @user.email
expect(page.text.scan(@user.email).count).to eq 1
end
scenario 'user can leave the current game', js: true do
# scenario 'user can leave the current game', js: true do
scenario 'user can leave the current game' do
expect(page).to have_content "Sit"
click_button 'Sit', match: :first
expect(page).to have_content @user.email
expect(page.text.scan(@user.email).count).to eq 1
# accept_confirm do
click_button 'Stand', match: :first
expect(page.find('.game-seat.position-1')).to have_content "Sit"
# end
expect(page.find('.seat.position-1')).to have_content "Sit"
expect(page.text.scan(@user.email).count).to eq 0
end

View File

@ -13,18 +13,18 @@ feature 'Table show', :devise do
# Given I am not signed in
# When I visit a table
# Then I see the table attributes
scenario 'visitor can see the table', js: true do
expect(page).to have_selector "#table-#{@table.id} > h1", @table.title
scenario 'visitor can see the table' do
expect(page).to have_text @table.title
end
scenario 'visitor can see the seats', js: true do
scenario 'visitor can see the seats' do
#TODO: Race condition exists without have_content
expect(page).to have_content "Sit"
expect(page).to have_button "Sit"
@seat_count = page.find_all(".seat").length
expect(@seat_count).to eq @table.seats.count
end
scenario 'visitor can see the current game', js: true do
scenario 'visitor can see the current game' do
#TODO: Write a better expectation
expect(page).to have_content "Hand to beat"
end
@ -43,14 +43,14 @@ feature 'Table show', :devise do
# Given I am signed in
# When I click a table
# Then I see the table attributes
scenario 'user can see the table', js: true do
scenario 'user can see the table' do
expect(page).to have_content "Sign out"
expect(page).to have_selector "#table-#{@table.id} > h1", @table.title
expect(page).to have_content @table.title
expect(current_path).to eq table_path(@table)
end
scenario 'user can see the current game', js: true do
expect(page).to have_content "Sit"
scenario 'user can see the current game' do
expect(page).to have_button "Sit"
end
end

View File

@ -9,8 +9,7 @@ feature 'Sign in', :devise do
# Then I see an invalid credentials message
scenario 'user cannot sign in if not registered' do
signin('test@example.com', 'password')
expect(page).to have_content
I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'email'
expect(page).to have_content(/#{I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'email'}/i)
end
# Scenario: User can sign in with valid credentials
@ -21,7 +20,7 @@ feature 'Sign in', :devise do
scenario 'user can sign in with valid credentials' do
user = FactoryGirl.create(:user)
signin(user.email, user.password)
expect(page).to have_content I18n.t 'devise.sessions.signed_in'
expect(page).to have_content(/#{I18n.t 'devise.sessions.signed_in'}/i)
end
# Scenario: User cannot sign in with wrong email
@ -32,8 +31,7 @@ feature 'Sign in', :devise do
scenario 'user cannot sign in with wrong email' do
user = FactoryGirl.create(:user)
signin('invalid@email.com', user.password)
expect(page).to have_content
I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'email'
expect(page).to have_content(/#{I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'email'}/i)
end
# Scenario: User cannot sign in with wrong password
@ -44,7 +42,6 @@ feature 'Sign in', :devise do
scenario 'user cannot sign in with wrong password' do
user = FactoryGirl.create(:user)
signin(user.email, 'invalidpass')
expect(page).to have_content
I18n.t 'devise.failure.invalid', authentication_keys: 'email'
expect(page).to have_content(/#{I18n.t 'devise.failure.invalid', authentication_keys: 'email'}/i)
end
end

View File

@ -2,7 +2,7 @@ require 'rails_helper'
include Warden::Test::Helpers
Warden.test_mode!
feature 'Join a game', type: :feature, js: true do
feature 'Join a game', type: :feature do
# before(:each) do
# @game = setup_game
# @game.reload
@ -24,7 +24,7 @@ feature 'Join a game', type: :feature, js: true do
@game = FactoryGirl.create :game
@user = FactoryGirl.create :user
login_as(@user, scope: :user)
visit game_path @game
visit table_path @game.table
click_button "Sit", match: :first
expect(page).to have_content @user.display_name
end
@ -37,7 +37,7 @@ feature 'Join a game', type: :feature, js: true do
@game = FactoryGirl.create :game
@user = FactoryGirl.create :user
login_as(@user, scope: :user)
visit game_path @game
visit table_path @game.table
click_button "Sit", match: :first
expect(page).to have_content @user.display_name
click_button "Sit", match: :first

View File

@ -2,13 +2,11 @@ require 'rails_helper'
include Warden::Test::Helpers
Warden.test_mode!
feature 'Play a hand', type: :feature, js: true do
feature 'Play a hand', type: :feature do
before(:each) do
@game = setup_visitor_game
visit game_path @game
visit table_path @game.table
click_button "Sit", match: :first
#TODO: Fix race condition
sleep 2
click_button "Start"
@game.reload
end
@ -18,14 +16,10 @@ feature 'Play a hand', type: :feature, js: true do
end
scenario 'player can see their own 13 card faces' do
#TODO: Fix race condition
sleep 2
expect(page.find_all("#inventory img").length).to eq(13)
end
scenario 'player can see other players 13 card backs' do
#TODO: Remove race condition
sleep 2
inventories = page.find_all(".inventory")
inventories.each do |inventory|
#TODO: This test should verify that other players card fronts are NOT seen

View File

@ -7,18 +7,19 @@ feature 'Join game', :devise do
# Given I am not signed in
# When I visit a joinable game
# Then I see a join button
scenario 'visitor can join a game', js: true do
visit new_game_path
fill_in 'game_title', with: 'Test Game'
click_button 'Create Game'
scenario 'visitor can join a game' do
visit new_table_path
fill_in 'table_title', with: 'Test Game'
click_button 'Create Table'
puts current_path
expect(page).to have_button("Sit")
click_button 'Sit', match: :first
#TODO: Fix this asynchronous race condition
visit current_path
@game = Game.find(current_path.split('/').last)
@player = @game.players.last
@playerComponent = page.find("#player-1")
expect(@playerComponent.text).to have_content("Guest#{@player.soft_token[0..5]}")
@table = Table.find(current_path.split('/').last)
@player = @table.current_game.players.last
@playerComponent = page.find_all(".seat").first
expect(@playerComponent.text).to have_content("Guest#{@player.soft_token[0..4]}")
end
scenario 'visitor can join a game in progress' do

View File

@ -17,17 +17,16 @@ feature 'Navigation links', :devise do
# Given I am a visitor
# When I click a navigation link
# Then I see the proper web page
scenario 'follow navigation links', js: :true do
# scenario 'follow navigation links', js: :true do
scenario 'follow navigation links' do
visit root_path
@links = {
'Play Now': '"/games/1"',
'Play Now': '"/tables/1"',
'Browse Tables': 'tables_path',
#'Tutorial': 'tutorial_path'
}
@links.each do |link|
click_link link[0]
#TODO: Remove race condition
sleep 1
expect(page.current_path).to eq(eval(link[1]))
visit root_path
end

View File

@ -17,14 +17,15 @@ feature 'Sign Up', :devise do
# Scenario: Visitor joins a game and then signs up
# Given I am not signed in
# When I join a game and then sign up
# Then I should see myself in that game
scenario 'visitor joins a game and then signs up', js: true do
visit new_game_path
fill_in 'game_title', with: 'Test Game'
click_button 'Create Game'
# Then I should see my registered name
scenario 'visitor joins a game and then signs up' do
pending
visit new_table_path
fill_in 'table_title', with: 'Test Game'
click_button 'Create Table'
click_button 'Sit', match: :first
sign_up_with('test@example.com', 'please123', 'please123')
visit games_path
visit tables_path
click_link 'Test Game'
expect(page).to have_content('test@example.com')
end

View File

@ -2,7 +2,8 @@ require 'rails_helper'
RSpec.describe Game, type: :model do
before(:each) do
@game = FactoryGirl.create(:game)
@table = FactoryGirl.create :table
@game = @table.current_game
@user1 = FactoryGirl.create(:user)
@user2 = FactoryGirl.create(:user)
end
@ -13,10 +14,6 @@ RSpec.describe Game, type: :model do
it { should respond_to(:play_to_beat) }
it { should respond_to(:winner) }
it '#title returns a string' do
expect(@game.title).to match 'Test Game'
end
it 'has a winner' do
# Start the game
@player1 = @user1.sit_in(@game.seats.first)
@ -29,6 +26,7 @@ RSpec.describe Game, type: :model do
@player.play_hand [card]
@game.reload
while (@game.controlling_player != @player) do
break if @game.over?
@game.controlling_player.pass
@game.reload
end

View File

@ -1,3 +1,4 @@
RSpec.describe Play, type: :model do
before(:each) do
@game = setup_game
@ -24,11 +25,11 @@ RSpec.describe Play, type: :model do
end
it '#player_cards returns a PlayerCard collection' do
expect(@play.player_cards.class).to eq(PlayerCard::ActiveRecord_Associations_CollectionProxy)
expect(@play.player_cards.class.to_s).to eq("PlayerCard::ActiveRecord_Associations_CollectionProxy")
end
it '#hand returns a PlayerCard collection' do
expect(@play.hand.class).to eq(PlayerCard::ActiveRecord_Associations_CollectionProxy)
expect(@play.hand.class.to_s).to eq("PlayerCard::ActiveRecord_Associations_CollectionProxy")
end
it '#hand_type returns a string' do
@ -362,14 +363,15 @@ RSpec.describe Play, type: :model do
@diamond3 = PlayerCard.new(rank: "3", suit: "Diamond", value: 3)
@heart3 = PlayerCard.new(rank: "3", suit: "Heart", value: 4)
@cards_to_play = [@spade3, @club3, @diamond3, @heart3]
@play = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: @cards_to_beat)
@play = Play.new(game_id: @game.id, player_id: @game.controlling_player_id, player_cards: @cards_to_play)
expect(@play.hand_type).to eq('bomb')
#TODO: Refactor this test to only test the @play.beats? method
#TODO: Move other expectations to another test
#TODO: Test every validation of a play
#TODO: Refactor @play.valid? method
expect(@play.beats? @play_to_beat).to eq(false)
#TODO: Refactor @play.valid? method to account for beats?
pending('#EXPECT invalid play Refactor @play.valid? method to account for beats?')
expect(@play.valid?).to eq(false)
end

Some files were not shown because too many files have changed in this diff Show More