rails-jsdom 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ module RailsJsdom
2
+ class TurboStreamDeliveries # :nodoc:
3
+ def initialize
4
+ @delivered = {}
5
+ end
6
+
7
+ def undelivered_messages(session, streams)
8
+ previously_delivered = @delivered.fetch(session, {})
9
+ @delivered[session] = streams.to_h { |stream| [ stream, broadcasts(stream).size ] }
10
+ streams.flat_map { |stream| new_messages(stream, previously_delivered) }
11
+ end
12
+
13
+ private
14
+
15
+ def new_messages(stream, previously_delivered)
16
+ sent = broadcasts(stream)
17
+ unseen = sent.drop(previously_delivered.fetch(stream, sent.size))
18
+ unseen.map { |payload| ActiveSupport::JSON.decode(payload) }.grep(String)
19
+ end
20
+
21
+ def broadcasts(stream)
22
+ ActionCable.server.pubsub.broadcasts(stream)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,4 @@
1
+ module RailsJsdom
2
+ # The version of the rails-jsdom gem.
3
+ VERSION = "0.1.0".freeze
4
+ end
@@ -0,0 +1,83 @@
1
+ require "json"
2
+ require "open3"
3
+ require_relative "rails_jsdom/version"
4
+
5
+ # Browserless interaction tests for Rails apps built with Stimulus, Turbo and
6
+ # importmap.
7
+ #
8
+ # Write tests with RailsJsdom::TestCase. Its helpers are documented in
9
+ # RailsJsdom::TestHelper.
10
+ module RailsJsdom
11
+ # Raised when an action fails in the page: an element is not found or
12
+ # matches more than once, a JavaScript error or unexpected dialog occurs, or
13
+ # the Node process exits.
14
+ class Error < StandardError; end
15
+
16
+ # :stopdoc:
17
+
18
+ RUNNER = File.expand_path("rails_jsdom/runner.js", __dir__)
19
+ REMOTE = %r{\A[a-z][a-z0-9+.-]*://}i
20
+ HIDDEN_SELECTOR = "[hidden], template, script, style, noscript, dialog:not([open]), [style*='display: none'], [style*='display:none']".freeze
21
+ TIMER_HORIZON = 1000
22
+
23
+ class << self
24
+ def bridge
25
+ bridges[Process.pid] ||= Bridge.new(command: [ "node", RUNNER ], setup: setup, logger: Rails.logger)
26
+ end
27
+
28
+ def setup
29
+ {
30
+ command: "setup",
31
+ root: Rails.root.to_s,
32
+ controllers: Rails.root.join("app/javascript/controllers").to_s,
33
+ modules: modules,
34
+ stubs: remote_modules,
35
+ directories: directories,
36
+ horizon: TIMER_HORIZON,
37
+ hidden: HIDDEN_SELECTOR
38
+ }
39
+ end
40
+
41
+ def modules
42
+ packages.reject { |_name, path| path.match?(REMOTE) }.transform_values { |path| Rails.application.assets.load_path.find(path)&.path&.to_s }
43
+ end
44
+
45
+ def remote_modules
46
+ packages.select { |_name, path| path.match?(REMOTE) }.keys
47
+ end
48
+
49
+ def directories
50
+ Rails.application.importmap.directories.values.to_h { |directory| [ directory.under, Rails.root.join(directory.dir).to_s ] }
51
+ end
52
+
53
+ def keys(keys)
54
+ keys.map { |key| key.is_a?(Array) ? key_entry(key.last).merge(modifiers: key[0...-1].map(&:to_s)) : key_entry(key) }
55
+ end
56
+
57
+ def document(html)
58
+ "<!DOCTYPE html><html><head></head><body>#{html}</body></html>"
59
+ end
60
+
61
+ private
62
+
63
+ def key_entry(key)
64
+ key.is_a?(Symbol) ? { key: key.to_s } : { text: key.to_s }
65
+ end
66
+
67
+ def packages
68
+ Rails.application.importmap.packages.transform_values(&:path)
69
+ end
70
+
71
+ def bridges
72
+ @bridges ||= {}
73
+ end
74
+ end
75
+ end
76
+
77
+ require_relative "rails_jsdom/bridge"
78
+ require_relative "rails_jsdom/query"
79
+ require_relative "rails_jsdom/turbo_stream_deliveries"
80
+ require_relative "rails_jsdom/element"
81
+ require_relative "rails_jsdom/test_helper"
82
+ require_relative "rails_jsdom/page"
83
+ require_relative "rails_jsdom/test_case"
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-jsdom
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jake Howerton
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: actioncable
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: actionpack
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: importmap-rails
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: nokogiri
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '1.15'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '1.15'
68
+ - !ruby/object:Gem::Dependency
69
+ name: propshaft
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '1.0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '1.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: turbo-rails
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '2.0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '2.0'
96
+ description: rails-jsdom runs your real Rails pages, Stimulus controllers and Turbo
97
+ in a persistent Node + jsdom process, routing page fetches back into Rails in-process.
98
+ Interaction tests read like system tests without Capybara, a server or a browser.
99
+ email:
100
+ - jake.howerton@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files:
104
+ - CHANGELOG.md
105
+ - LICENSE
106
+ - README.md
107
+ files:
108
+ - CHANGELOG.md
109
+ - LICENSE
110
+ - README.md
111
+ - lib/generators/rails_jsdom/install/install_generator.rb
112
+ - lib/rails_jsdom.rb
113
+ - lib/rails_jsdom/bridge.rb
114
+ - lib/rails_jsdom/element.rb
115
+ - lib/rails_jsdom/page.rb
116
+ - lib/rails_jsdom/query.rb
117
+ - lib/rails_jsdom/runner.js
118
+ - lib/rails_jsdom/runtime.js
119
+ - lib/rails_jsdom/test_case.rb
120
+ - lib/rails_jsdom/test_helper.rb
121
+ - lib/rails_jsdom/turbo_stream_deliveries.rb
122
+ - lib/rails_jsdom/version.rb
123
+ homepage: https://github.com/jakehow/rails-jsdom
124
+ licenses:
125
+ - MIT
126
+ metadata:
127
+ homepage_uri: https://github.com/jakehow/rails-jsdom
128
+ source_code_uri: https://github.com/jakehow/rails-jsdom
129
+ documentation_uri: https://jakehow.github.io/rails-jsdom/
130
+ changelog_uri: https://github.com/jakehow/rails-jsdom/blob/main/CHANGELOG.md
131
+ bug_tracker_uri: https://github.com/jakehow/rails-jsdom/issues
132
+ rubygems_mfa_required: 'true'
133
+ post_install_message: 'rails-jsdom: set up interaction tests in your app with `bin/rails
134
+ generate rails_jsdom:install`.'
135
+ rdoc_options:
136
+ - "--main"
137
+ - README.md
138
+ - "--markup"
139
+ - markdown
140
+ - "--title"
141
+ - rails-jsdom
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '3.3'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubygems_version: 4.0.20
156
+ specification_version: 4
157
+ summary: Browserless Stimulus and Turbo interaction tests for Rails, on jsdom.
158
+ test_files: []