Enable selenium service in devcontainer for system tests (#1340)

Co-authored-by: Pedro J. Aramburu <pedro@joakin.dev>
This commit is contained in:
Pedro J. Aramburu
2026-04-06 09:15:57 -03:00
committed by GitHub
parent 246cd00cbb
commit 616c363b3e
8 changed files with 72 additions and 6 deletions

View File

@@ -4,7 +4,8 @@
"service": "app", "service": "app",
"runServices": [ "runServices": [
"db", "db",
"redis" "redis",
"selenium"
], ],
"workspaceFolder": "/workspace", "workspaceFolder": "/workspace",
"containerEnv": { "containerEnv": {

View File

@@ -10,6 +10,7 @@ x-rails-env: &rails_env
POSTGRES_PASSWORD: postgres POSTGRES_PASSWORD: postgres
BUNDLE_PATH: /bundle BUNDLE_PATH: /bundle
REDIS_URL: redis://redis:6379/1 REDIS_URL: redis://redis:6379/1
SELENIUM_REMOTE_URL: http://selenium:4444
services: services:
app: app:
@@ -28,6 +29,7 @@ services:
depends_on: depends_on:
- db - db
- redis - redis
- selenium
worker: worker:
build: build:
@@ -59,6 +61,14 @@ services:
environment: environment:
<<: *db_env <<: *db_env
selenium:
image: selenium/standalone-chromium:latest
ports:
- "4444:4444"
- "7900:7900"
shm_size: 2gb
restart: unless-stopped
volumes: volumes:
postgres-data: postgres-data:
redis-data: redis-data:

View File

@@ -16,7 +16,7 @@ Purpose: provide short, actionable guidance so Copilot suggestions match project
### Testing ### Testing
- `bin/rails test` - Run all tests - `bin/rails test` - Run all tests
- `bin/rails test:db` - Run tests with database reset - `bin/rails test:db` - Run tests with database reset
- `bin/rails test:system` - Run system tests only (use sparingly - they take longer) - `DISABLE_PARALLELIZATION=true bin/rails test:system` - Run system tests only (use sparingly - they take longer)
- `bin/rails test test/models/account_test.rb` - Run specific test file - `bin/rails test test/models/account_test.rb` - Run specific test file
- `bin/rails test test/models/account_test.rb:42` - Run specific test at line - `bin/rails test test/models/account_test.rb:42` - Run specific test at line
@@ -37,7 +37,7 @@ Purpose: provide short, actionable guidance so Copilot suggestions match project
- `bin/setup` - Initial project setup (installs dependencies, prepares database) - `bin/setup` - Initial project setup (installs dependencies, prepares database)
## Pre-PR workflow (run locally before opening PR) ## Pre-PR workflow (run locally before opening PR)
- Tests: bin/rails test (all), bin/rails test:system (when applicable) - Tests: bin/rails test (all), DISABLE_PARALLELIZATION=true bin/rails test:system (when applicable)
- Linters: bin/rubocop -f github -a; bundle exec erb_lint ./app/**/*.erb -a - Linters: bin/rubocop -f github -a; bundle exec erb_lint ./app/**/*.erb -a
- Security: bin/brakeman --no-pager - Security: bin/brakeman --no-pager

View File

@@ -12,10 +12,19 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
### Testing ### Testing
- `bin/rails test` - Run all tests - `bin/rails test` - Run all tests
- `bin/rails test:db` - Run tests with database reset - `bin/rails test:db` - Run tests with database reset
- `bin/rails test:system` - Run system tests only (use sparingly - they take longer) - `DISABLE_PARALLELIZATION=true bin/rails test:system` - Run system tests only (use sparingly - they take longer)
- `bin/rails test test/models/account_test.rb` - Run specific test file - `bin/rails test test/models/account_test.rb` - Run specific test file
- `bin/rails test test/models/account_test.rb:42` - Run specific test at line - `bin/rails test test/models/account_test.rb:42` - Run specific test at line
#### System Tests in the Dev Container
When running inside the Dev Container, the `SELENIUM_REMOTE_URL` environment variable is automatically set to the bundled `selenium/standalone-chromium` service. System tests will connect to that remote browser — no local Chrome installation is required.
```bash
DISABLE_PARALLELIZATION=true bin/rails test:system
```
To watch the browser live, open `http://localhost:7900` or `http://localhost:4444` in your host browser (password: `secret`).
### Linting & Formatting ### Linting & Formatting
- `bin/rubocop` - Run Ruby linter - `bin/rubocop` - Run Ruby linter
- `npm run lint` - Check JavaScript/TypeScript code - `npm run lint` - Check JavaScript/TypeScript code
@@ -38,7 +47,7 @@ ALWAYS run these commands before opening a pull request:
1. **Tests** (Required): 1. **Tests** (Required):
- `bin/rails test` - Run all tests (always required) - `bin/rails test` - Run all tests (always required)
- `bin/rails test:system` - Run system tests (only when applicable, they take longer) - `DISABLE_PARALLELIZATION=true bin/rails test:system` - Run system tests (only when applicable, they take longer)
2. **Linting** (Required): 2. **Linting** (Required):
- `bin/rubocop -f github -a` - Ruby linting with auto-correct - `bin/rubocop -f github -a` - Ruby linting with auto-correct

View File

@@ -24,6 +24,9 @@ In general, _full features_ that get us closer to [our 🔜 Vision](https://gith
To get setup for local development, you have two options: To get setup for local development, you have two options:
1. [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) with VSCode (see the `.devcontainer` folder) 1. [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) with VSCode (see the `.devcontainer` folder)
- A `selenium/standalone-chrome` service is included in the Dev Container setup, so **system tests work out of the box** — no local Chrome required.
- Run system tests: `DISABLE_PARALLELIZATION=true bin/rails test:system`
- Watch the browser live at `http://localhost:7900` or `http://localhost:4444` (password: `secret`)
2. Local Development 2. Local Development
- [Mac Setup Guide](https://github.com/we-promise/sure/wiki/Mac-Dev-Setup-Guide) - [Mac Setup Guide](https://github.com/we-promise/sure/wiki/Mac-Dev-Setup-Guide)
- [Linux Setup Guide](https://github.com/we-promise/sure/wiki/Linux-Dev-Setup-Guide) - [Linux Setup Guide](https://github.com/we-promise/sure/wiki/Linux-Dev-Setup-Guide)

View File

@@ -1,11 +1,38 @@
require "test_helper" require "test_helper"
require "socket"
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
setup do setup do
Capybara.default_max_wait_time = 5 Capybara.default_max_wait_time = 5
if ENV["SELENIUM_REMOTE_URL"].present?
server_port = ENV.fetch("CAPYBARA_SERVER_PORT", 30_000 + (Process.pid % 1000)).to_i
app_host = ENV["CAPYBARA_APP_HOST"].presence || IPSocket.getaddress(Socket.gethostname)
Capybara.server_host = "0.0.0.0"
Capybara.server_port = server_port
Capybara.always_include_port = true
Capybara.app_host = "http://#{app_host}:#{server_port}"
end
end end
if ENV["SELENIUM_REMOTE_URL"].present?
Capybara.register_driver :selenium_remote_chrome do |app|
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument("--window-size=1400,1400")
Capybara::Selenium::Driver.new(
app,
browser: :remote,
url: ENV["SELENIUM_REMOTE_URL"],
capabilities: options
)
end
driven_by :selenium_remote_chrome, screen_size: [ 1400, 1400 ]
else
driven_by :selenium, using: ENV["CI"].present? ? :headless_chrome : ENV.fetch("E2E_BROWSER", :chrome).to_sym, screen_size: [ 1400, 1400 ] driven_by :selenium, using: ENV["CI"].present? ? :headless_chrome : ENV.fetch("E2E_BROWSER", :chrome).to_sym, screen_size: [ 1400, 1400 ]
end
private private

View File

@@ -60,6 +60,7 @@ class SettingsTest < ApplicationSystemTestCase
click_button "Generate new code" click_button "Generate new code"
assert_selector 'span[data-clipboard-target="source"]', visible: true, count: 1 # invite code copy widget assert_selector 'span[data-clipboard-target="source"]', visible: true, count: 1 # invite code copy widget
copy_button = find('button[data-action="clipboard#copy"]', match: :first) # Find the first copy button (adjust if needed) copy_button = find('button[data-action="clipboard#copy"]', match: :first) # Find the first copy button (adjust if needed)
page.execute_script("Object.defineProperty(navigator, 'clipboard', { value: { writeText: () => Promise.resolve() }, writable: true, configurable: true })") # Mock clipboard API due to browser security restrictions in tests
copy_button.click copy_button.click
assert_selector 'span[data-clipboard-target="iconSuccess"]', visible: true, count: 1 # text copied and icon changed to checkmark assert_selector 'span[data-clipboard-target="iconSuccess"]', visible: true, count: 1 # text copied and icon changed to checkmark
end end

View File

@@ -23,11 +23,26 @@ require "minitest/autorun"
require "mocha/minitest" require "mocha/minitest"
require "aasm/minitest" require "aasm/minitest"
require "webmock/minitest" require "webmock/minitest"
require "uri"
VCR.configure do |config| VCR.configure do |config|
config.cassette_library_dir = "test/vcr_cassettes" config.cassette_library_dir = "test/vcr_cassettes"
config.hook_into :webmock config.hook_into :webmock
config.ignore_localhost = true config.ignore_localhost = true
config.ignore_request do |request|
selenium_remote_url = ENV["SELENIUM_REMOTE_URL"]
next false if selenium_remote_url.blank?
request_uri = URI(request.uri)
selenium_uri = URI(selenium_remote_url)
request_uri.host.present? &&
selenium_uri.host.present? &&
request_uri.host == selenium_uri.host &&
request_uri.port == selenium_uri.port
rescue URI::InvalidURIError
false
end
config.default_cassette_options = { erb: true } config.default_cassette_options = { erb: true }
config.filter_sensitive_data("<OPENAI_ACCESS_TOKEN>") { ENV["OPENAI_ACCESS_TOKEN"] } config.filter_sensitive_data("<OPENAI_ACCESS_TOKEN>") { ENV["OPENAI_ACCESS_TOKEN"] }
config.filter_sensitive_data("<OPENAI_ORGANIZATION_ID>") { ENV["OPENAI_ORGANIZATION_ID"] } config.filter_sensitive_data("<OPENAI_ORGANIZATION_ID>") { ENV["OPENAI_ORGANIZATION_ID"] }