From c9d0977a9e8adc7ac9d399a184e7d185a2437450 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Sun, 23 Aug 2026 11:43:09 -0400 Subject: [PATCH] feat: add devcontainer --- .devcontainer/Dockerfile | 7 ++++++ .devcontainer/compose.yaml | 27 +++++++++++++++++++++ .devcontainer/devcontainer-lock.json | 24 +++++++++++++++++++ .devcontainer/devcontainer.json | 35 ++++++++++++++++++++++++++++ test/application_system_test_case.rb | 11 ++++++++- 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/compose.yaml create mode 100644 .devcontainer/devcontainer-lock.json create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..0d6f7da --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,7 @@ +# Make sure RUBY_VERSION matches the Ruby version in .ruby-version +ARG RUBY_VERSION=4.0.0 +FROM ghcr.io/rails/devcontainer/images/ruby:$RUBY_VERSION + +# Ensure binding is always 0.0.0.0 +# Binds the server to all IP addresses of the container, so it can be accessed from outside the container. +ENV BINDING="0.0.0.0" diff --git a/.devcontainer/compose.yaml b/.devcontainer/compose.yaml new file mode 100644 index 0000000..7824cac --- /dev/null +++ b/.devcontainer/compose.yaml @@ -0,0 +1,27 @@ +name: "endsideout" + +services: + rails-app: + build: + context: .. + dockerfile: .devcontainer/Dockerfile + + volumes: + - ../../endsideout:/workspaces/endsideout:cached + + # Overrides default command so things don't shut down after the process ends. + command: sleep infinity + + # Uncomment the next line to use a non-root user for all processes. + # user: vscode + + # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. + # (Adding the "ports" property to this file will not forward from a Codespace.) + depends_on: + - selenium + + selenium: + image: selenium/standalone-chromium + restart: unless-stopped + + diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 0000000..57fff0e --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,24 @@ +{ + "features": { + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { + "version": "1.10.0", + "resolved": "ghcr.io/devcontainers/features/docker-outside-of-docker@sha256:c2c2cf829505ead8e4892c88c31b6594ae94a2bbb209e16e1fac456c1a3a624e", + "integrity": "sha256:c2c2cf829505ead8e4892c88c31b6594ae94a2bbb209e16e1fac456c1a3a624e" + }, + "ghcr.io/devcontainers/features/github-cli:1": { + "version": "1.1.1", + "resolved": "ghcr.io/devcontainers/features/github-cli@sha256:94879eebb6a0e4e2f197de9f12db7427cb4a25b82d93c55239ce8c8fc394a1b4", + "integrity": "sha256:94879eebb6a0e4e2f197de9f12db7427cb4a25b82d93c55239ce8c8fc394a1b4" + }, + "ghcr.io/rails/devcontainer/features/activestorage": { + "version": "1.1.1", + "resolved": "ghcr.io/rails/devcontainer/features/activestorage@sha256:7fa8fff898ac33076ebf65631d3c6c902dc9bad87de3e5dfa645f3e2d7a35c07", + "integrity": "sha256:7fa8fff898ac33076ebf65631d3c6c902dc9bad87de3e5dfa645f3e2d7a35c07" + }, + "ghcr.io/rails/devcontainer/features/sqlite3": { + "version": "1.0.0", + "resolved": "ghcr.io/rails/devcontainer/features/sqlite3@sha256:fa4a12e87152158ed9b67acb819ad2e1bd78c7e3808ff08e786a76a677af2c58", + "integrity": "sha256:fa4a12e87152158ed9b67acb819ad2e1bd78c7e3808ff08e786a76a677af2c58" + } + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..e19c9fd --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,35 @@ +// For format details, see https://containers.dev/implementors/json_reference/. +// For config options, see the README at: https://github.com/devcontainers/templates/tree/main/src/ruby +{ + "name": "endsideout", + "dockerComposeFile": "compose.yaml", + "service": "rails-app", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/rails/devcontainer/features/activestorage": {}, + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {"moby":false}, + "ghcr.io/rails/devcontainer/features/sqlite3": {} + }, + + "containerEnv": { + "CAPYBARA_SERVER_PORT": "45678", + "SELENIUM_HOST": "selenium", + "KAMAL_REGISTRY_PASSWORD": "$KAMAL_REGISTRY_PASSWORD" + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [3000], + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://containers.dev/implementors/json_reference/#remoteUser. + // "remoteUser": "root", + + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "bin/setup --skip-server" +} diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb index 9585bbd..d3fe8fb 100644 --- a/test/application_system_test_case.rb +++ b/test/application_system_test_case.rb @@ -3,7 +3,16 @@ require "axe/matchers/be_axe_clean" class ApplicationSystemTestCase < ActionDispatch::SystemTestCase - driven_by :selenium, using: :headless_firefox, screen_size: [ 1400, 1400 ] + if ENV["CAPYBARA_SERVER_PORT"] + served_by host: "rails-app", port: ENV["CAPYBARA_SERVER_PORT"] + + driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ], options: { + browser: :remote, + url: "http://#{ENV["SELENIUM_HOST"]}:4444" + } + else + driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ] + end def assert_accessible matcher = Axe::Matchers::BeAxeClean.new