Skip to content

Commit 71cdbcf

Browse files
dblockCopilot
andcommitted
Provide collision-free framework test fabricators
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 976a7c6 commit 71cdbcf

8 files changed

Lines changed: 130 additions & 8 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### 2.3.0 (Next)
44

55
* [#188](https://github.com/slack-ruby/slack-ruby-bot-server/pull/188): Reduce the database CI matrices from 22 to 12 jobs while retaining representative legacy ORM majors and modern Ruby/Grape 3/4 coverage - [@dblock](https://github.com/dblock), [@Copilot](https://github.com/apps/copilot-swe-agent).
6+
* [#189](https://github.com/slack-ruby/slack-ruby-bot-server/pull/189): Add a prefixed Team fabricator entry point and preserve application-defined `:team` fabricators in the legacy RSpec helper - [@dblock](https://github.com/dblock), [@Copilot](https://github.com/apps/copilot-swe-agent).
67
* [#186](https://github.com/slack-ruby/slack-ruby-bot-server/pull/186): Document persisted custom Team attributes for both adapters and Rails concern loading/reloading - [@dblock](https://github.com/dblock), [@Copilot](https://github.com/apps/copilot-swe-agent).
78
* [#183](https://github.com/slack-ruby/slack-ruby-bot-server/pull/183): Add a `config.server_pages` block to configure page middleware options centrally without changing the installed library's defaults - [@dblock](https://github.com/dblock), [@Copilot](https://github.com/apps/copilot-swe-agent).
89
* [#184](https://github.com/slack-ruby/slack-ruby-bot-server/pull/184): Add a configurable API application and separately mountable team read/registration endpoints, preserving the default API while supporting custom routes and registration-only applications - [@dblock](https://github.com/dblock), [@Copilot](https://github.com/apps/copilot-swe-agent).

‎README.md‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Build a complete Slack bot service with Slack button integration, in Ruby.
3535
- [HTML Templates](#html-templates)
3636
- [Page Middleware Configuration](#page-middleware-configuration)
3737
- [Access Tokens](#access-tokens)
38+
- [Testing](#testing)
3839
- [Sample Bots Using Slack Ruby Bot Server](#sample-bots-using-slack-ruby-bot-server)
3940
- [Copyright & License](#copyright--license)
4041

@@ -459,6 +460,28 @@ Without a block, the framework preserves the installed library's defaults and ex
459460

460461
By default the implementation of [Team](lib/slack-ruby-bot-server/models/team) stores the value of the token with all the requested OAuth scopes in both `token` and `activated_user_access_token` (for backwards compatibility), along with `oauth_version` and `oauth_scope`. If a legacy Slack bot integration `bot_access_token` is present, it is stored as `token`, and `activated_user_access_token` is the token that has all the requested OAuth scopes.
461462

463+
## Testing
464+
465+
The optional test helpers use [Fabrication](https://fabricationgem.org/) and Faker. Add `fabrication` and `faker` to your application's test dependencies; neither is a runtime dependency of this gem.
466+
467+
To use the framework's installation defaults without reserving your application's `:team` fabricator name, load the prefixed-only helper:
468+
469+
```ruby
470+
require 'slack-ruby-bot-server/rspec/fabricators'
471+
472+
team = Fabricate(:slack_ruby_bot_server_team)
473+
```
474+
475+
This fabricator creates the existing `::Team` model with unique token/team ID sequences and a generated name. Applications can register their own `:team` before or after this helper, or inherit the framework defaults:
476+
477+
```ruby
478+
Fabricator(:team, from: :slack_ruby_bot_server_team) do
479+
name { 'My application team' }
480+
end
481+
```
482+
483+
The existing `require 'slack-ruby-bot-server/rspec'` remains supported. It loads the prefixed fabricator and registers the legacy `:team` alias only when no `:team` definition already exists. If your application defines `:team` later, replace the legacy require with `slack-ruby-bot-server/rspec/fabricators`; loading both entry points still opts into the legacy alias.
484+
462485
## Sample Bots Using Slack Ruby Bot Server
463486

464487
* [slack-ruby-bot-server-events-sample](https://github.com/slack-ruby/slack-ruby-bot-server-events-sample), a generic sample

‎UPGRADING.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@ Upgrading Slack-Ruby-Bot-Server
33

44
### Upgrading to >= 2.3.0
55

6+
#### Recommended Test Helper Migration
7+
8+
If your application defines its own `:team` fabricator, replace `require 'slack-ruby-bot-server/rspec'` with `require 'slack-ruby-bot-server/rspec/fabricators'`. This is recommended, not required: the new entry point registers only `:slack_ruby_bot_server_team`, leaving `:team` available regardless of whether your application's fabricator is loaded before or after the helper.
9+
10+
Use `Fabricate(:slack_ruby_bot_server_team)` for the framework defaults, or inherit them in your application's fabricator:
11+
12+
```ruby
13+
require 'slack-ruby-bot-server/rspec/fabricators'
14+
15+
Fabricator(:team, from: :slack_ruby_bot_server_team) do
16+
name { 'My application team' }
17+
end
18+
```
19+
20+
The legacy helper remains supported and registers `:team` only if no definition already exists. Replace the old require rather than adding the new one alongside it; loading both still opts into the legacy alias and can conflict with a `:team` definition loaded later.
21+
622
#### Status Checks and Inactive Installations
723

824
`GET /api/status` now pings only active installations. When Slack returns `account_inactive` or `invalid_auth`, the installation is deactivated through `Service#deactivate!`, and the endpoint returns HTTP `200` with `ping: { "ok": false, "error": "account_inactive" }` (or `"invalid_auth"`). The active-team count reflects that deactivation. Monitoring should inspect the failed `ping` as well as the HTTP status.

‎lib/slack-ruby-bot-server/rspec.rb‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
require 'slack-ruby-bot-server'
2-
require 'fabrication'
3-
require 'faker'
1+
require_relative 'rspec/fabricators'
42
require_relative 'rspec/fabricators/team'
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
require 'slack-ruby-bot-server'
2+
require 'fabrication'
3+
require 'faker'
4+
require_relative 'fabricators/slack_ruby_bot_server_team'
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fabricator(:slack_ruby_bot_server_team, class_name: 'Team') do
2+
token { Fabricate.sequence(:team_token) { |i| "abc-#{i}" } }
3+
team_id { Fabricate.sequence(:team_id) { |i| "T#{i}" } }
4+
name { Faker::Lorem.word }
5+
end
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
Fabricator(:team) do
2-
token { Fabricate.sequence(:team_token) { |i| "abc-#{i}" } }
3-
team_id { Fabricate.sequence(:team_id) { |i| "T#{i}" } }
4-
name { Faker::Lorem.word }
5-
end
1+
require_relative 'slack_ruby_bot_server_team'
2+
3+
Fabricator(:team, from: :slack_ruby_bot_server_team) unless Fabrication.manager[:team]
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
require 'spec_helper'
2+
require 'open3'
3+
require 'rbconfig'
4+
5+
describe 'RSpec fabricators' do
6+
let(:application_fabricator) do
7+
<<~RUBY
8+
Fabricator(:team, class_name: 'Team') do
9+
name { 'Application team' }
10+
token { 'application-token' }
11+
team_id { 'TAPPLICATION' }
12+
end
13+
RUBY
14+
end
15+
16+
def fabricator_names_after(code)
17+
script = <<~RUBY
18+
require 'logger'
19+
Bundler.require
20+
require 'fabrication'
21+
require 'json'
22+
if defined?(ActiveRecord::Base)
23+
ActiveRecord::Base.establish_connection(ENV.fetch('DATABASE_URL'))
24+
end
25+
#{code}
26+
puts JSON.generate(
27+
application: Fabricate.build(:team).name,
28+
framework: Fabricate.build(:slack_ruby_bot_server_team, name: 'Framework team').name
29+
)
30+
RUBY
31+
output, error, status = Open3.capture3(RbConfig.ruby, '-Ilib', '-rbundler/setup', '-e', script)
32+
expect(status.success?).to be(true), "#{output}\n#{error}"
33+
JSON.parse(output.lines.last)
34+
end
35+
36+
it 'persists framework installations with unique credentials independently of the legacy name' do
37+
first = Fabricate(:slack_ruby_bot_server_team)
38+
second = Fabricate(:slack_ruby_bot_server_team)
39+
expect(Team.find(first.id).token).to eq first.token
40+
expect(first.token).not_to eq second.token
41+
expect(first.team_id).not_to eq second.team_id
42+
end
43+
44+
it 'keeps the legacy helper working without an application fabricator' do
45+
names = fabricator_names_after("require 'slack-ruby-bot-server/rspec'")
46+
expect(names['application']).not_to be_empty
47+
expect(names['framework']).to eq 'Framework team'
48+
end
49+
50+
it 'preserves an application fabricator registered before the legacy helper' do
51+
names = fabricator_names_after(<<~RUBY)
52+
#{application_fabricator}
53+
require 'slack-ruby-bot-server/rspec'
54+
RUBY
55+
expect(names).to eq('application' => 'Application team', 'framework' => 'Framework team')
56+
end
57+
58+
it 'allows applications to inherit and customize framework defaults' do
59+
names = fabricator_names_after(<<~RUBY)
60+
require 'slack-ruby-bot-server/rspec/fabricators'
61+
Fabricator(:team, from: :slack_ruby_bot_server_team) do
62+
name { 'Application team' }
63+
end
64+
RUBY
65+
expect(names).to eq('application' => 'Application team', 'framework' => 'Framework team')
66+
end
67+
68+
%w[before after].each do |order|
69+
it "allows an application fabricator #{order} the prefixed-only helper" do
70+
setup = [application_fabricator, "require 'slack-ruby-bot-server/rspec/fabricators'"]
71+
setup.reverse! if order == 'after'
72+
expect(fabricator_names_after(setup.join("\n"))).to eq(
73+
'application' => 'Application team', 'framework' => 'Framework team'
74+
)
75+
end
76+
end
77+
end

0 commit comments

Comments
 (0)