gemini-suggestions, tests-fail #1
8 changed files with 429 additions and 15 deletions
gemini-suggestions, tests-fail
commit
5f4b1f74e5
73
.rubocop.yml
Normal file
73
.rubocop.yml
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# .rubocop.yml
|
||||||
|
require:
|
||||||
|
- rubocop-performance # For performance-related cops
|
||||||
|
- rubocop-minitest
|
||||||
|
- rubocop-rspec
|
||||||
|
|
||||||
|
AllCops:
|
||||||
|
TargetRubyVersion: 3.4.4
|
||||||
|
Exclude:
|
||||||
|
- 'vendor/**/*'
|
||||||
|
- 'tmp/**/*'
|
||||||
|
- 'log/**/*'
|
||||||
|
- 'Gemfile.lock'
|
||||||
|
- 'Containerfile' # Not a Ruby file
|
||||||
|
- 'responses.yml' # Not a Ruby file
|
||||||
|
- 'README.md' # Not a Ruby file
|
||||||
|
|
||||||
|
# Style and Layout Cops
|
||||||
|
Layout/LineLength:
|
||||||
|
Max: 120 # A bit more lenient than default 80, but enforce a limit
|
||||||
|
Exclude:
|
||||||
|
- 'Rakefile' # Rake tasks can sometimes have long lines
|
||||||
|
|
||||||
|
Metrics/BlockLength:
|
||||||
|
# Allows longer blocks for RSpec and Minitest spec files
|
||||||
|
# Adjust as needed for your test framework
|
||||||
|
Exclude:
|
||||||
|
- '**/*_spec.rb'
|
||||||
|
- '**/*_test.rb'
|
||||||
|
# For non-test files, a reasonable limit
|
||||||
|
Max: 50
|
||||||
|
|
||||||
|
Metrics/AbcSize:
|
||||||
|
Max: 20 # Adjust if methods are consistently complex
|
||||||
|
|
||||||
|
Metrics/MethodLength:
|
||||||
|
Max: 15 # Keep methods concise
|
||||||
|
|
||||||
|
Style/Documentation:
|
||||||
|
Enabled: false # Disable documentation comments for simple apps
|
||||||
|
|
||||||
|
Style/FrozenStringLiteralComment:
|
||||||
|
Enabled: true # Good practice for Ruby 2.3+
|
||||||
|
|
||||||
|
Style/ClassAndModuleChildren:
|
||||||
|
Enabled: false # Allows MyApp::MyClass instead of MyApp::MyClass
|
||||||
|
|
||||||
|
Style/StringLiterals:
|
||||||
|
EnforcedStyle: single_quotes # Prefer single quotes unless interpolation is needed
|
||||||
|
|
||||||
|
Style/StringLiteralsInInterpolation:
|
||||||
|
EnforcedStyle: single_quotes # Prefer single quotes even within interpolation
|
||||||
|
|
||||||
|
Style/WordArray:
|
||||||
|
MinSize: 3 # Use %w[] for arrays of strings longer than this
|
||||||
|
|
||||||
|
Style/HashEachMethods:
|
||||||
|
Enabled: true # Prefer #each_key, #each_value, #each_pair over #each
|
||||||
|
|
||||||
|
Style/CaseEquality:
|
||||||
|
Enabled: false # Often used in Sinatra routes, e.g. when matched against paths
|
||||||
|
|
||||||
|
# Naming Cops
|
||||||
|
Naming/FileName:
|
||||||
|
Exclude:
|
||||||
|
- 'app.rb' # Allow for `app.rb` which is common for Sinatra entry points
|
||||||
|
|
||||||
|
# Performance Cops (from rubocop-performance)
|
||||||
|
Performance/CompareWithBlock:
|
||||||
|
Enabled: true
|
||||||
|
|
||||||
|
Performance/StringIdentifierArgument:
|
||||||
|
Enabled: true
|
||||||
18
Gemfile
18
Gemfile
|
|
@ -1,10 +1,24 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
gem 'sinatra', '~> 3.0'
|
|
||||||
gem 'puma', '~> 6.0'
|
|
||||||
gem 'json', '~> 2.6'
|
gem 'json', '~> 2.6'
|
||||||
|
gem 'puma', '~> 6.0'
|
||||||
|
gem 'sinatra', '~> 3.0'
|
||||||
gem 'yaml', '~> 0.2'
|
gem 'yaml', '~> 0.2'
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'rerun'
|
gem 'rerun'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
group :development, :test do
|
||||||
|
gem 'rack-test' # For HTTP integration tests
|
||||||
|
# Choose one testing framework:
|
||||||
|
gem 'minitest' # Uncomment this line if you prefer Minitest
|
||||||
|
gem 'rspec' # Uncomment this line if you prefer RSpec
|
||||||
|
|
||||||
|
gem 'rubocop'
|
||||||
|
gem 'rubocop-minitest'
|
||||||
|
gem 'rubocop-performance'
|
||||||
|
gem 'rubocop-rspec'
|
||||||
|
end
|
||||||
|
|
|
||||||
64
Gemfile.lock
64
Gemfile.lock
|
|
@ -1,7 +1,9 @@
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
|
ast (2.4.3)
|
||||||
base64 (0.3.0)
|
base64 (0.3.0)
|
||||||
|
diff-lcs (1.6.2)
|
||||||
ffi (1.17.2)
|
ffi (1.17.2)
|
||||||
ffi (1.17.2-aarch64-linux-gnu)
|
ffi (1.17.2-aarch64-linux-gnu)
|
||||||
ffi (1.17.2-aarch64-linux-musl)
|
ffi (1.17.2-aarch64-linux-musl)
|
||||||
|
|
@ -14,23 +16,75 @@ GEM
|
||||||
ffi (1.17.2-x86_64-linux-gnu)
|
ffi (1.17.2-x86_64-linux-gnu)
|
||||||
ffi (1.17.2-x86_64-linux-musl)
|
ffi (1.17.2-x86_64-linux-musl)
|
||||||
json (2.12.2)
|
json (2.12.2)
|
||||||
|
language_server-protocol (3.17.0.5)
|
||||||
|
lint_roller (1.1.0)
|
||||||
listen (3.9.0)
|
listen (3.9.0)
|
||||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||||
rb-inotify (~> 0.9, >= 0.9.10)
|
rb-inotify (~> 0.9, >= 0.9.10)
|
||||||
|
minitest (5.25.5)
|
||||||
mustermann (3.0.3)
|
mustermann (3.0.3)
|
||||||
ruby2_keywords (~> 0.0.1)
|
ruby2_keywords (~> 0.0.1)
|
||||||
nio4r (2.7.4)
|
nio4r (2.7.4)
|
||||||
|
parallel (1.27.0)
|
||||||
|
parser (3.3.8.0)
|
||||||
|
ast (~> 2.4.1)
|
||||||
|
racc
|
||||||
|
prism (1.4.0)
|
||||||
puma (6.6.0)
|
puma (6.6.0)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
|
racc (1.8.1)
|
||||||
rack (2.2.17)
|
rack (2.2.17)
|
||||||
rack-protection (3.2.0)
|
rack-protection (3.2.0)
|
||||||
base64 (>= 0.1.0)
|
base64 (>= 0.1.0)
|
||||||
rack (~> 2.2, >= 2.2.4)
|
rack (~> 2.2, >= 2.2.4)
|
||||||
|
rack-test (2.2.0)
|
||||||
|
rack (>= 1.3)
|
||||||
|
rainbow (3.1.1)
|
||||||
rb-fsevent (0.11.2)
|
rb-fsevent (0.11.2)
|
||||||
rb-inotify (0.11.1)
|
rb-inotify (0.11.1)
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
|
regexp_parser (2.10.0)
|
||||||
rerun (0.14.0)
|
rerun (0.14.0)
|
||||||
listen (~> 3.0)
|
listen (~> 3.0)
|
||||||
|
rspec (3.13.1)
|
||||||
|
rspec-core (~> 3.13.0)
|
||||||
|
rspec-expectations (~> 3.13.0)
|
||||||
|
rspec-mocks (~> 3.13.0)
|
||||||
|
rspec-core (3.13.4)
|
||||||
|
rspec-support (~> 3.13.0)
|
||||||
|
rspec-expectations (3.13.5)
|
||||||
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
|
rspec-support (~> 3.13.0)
|
||||||
|
rspec-mocks (3.13.5)
|
||||||
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
|
rspec-support (~> 3.13.0)
|
||||||
|
rspec-support (3.13.4)
|
||||||
|
rubocop (1.76.0)
|
||||||
|
json (~> 2.3)
|
||||||
|
language_server-protocol (~> 3.17.0.2)
|
||||||
|
lint_roller (~> 1.1.0)
|
||||||
|
parallel (~> 1.10)
|
||||||
|
parser (>= 3.3.0.2)
|
||||||
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
|
regexp_parser (>= 2.9.3, < 3.0)
|
||||||
|
rubocop-ast (>= 1.45.0, < 2.0)
|
||||||
|
ruby-progressbar (~> 1.7)
|
||||||
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
|
rubocop-ast (1.45.0)
|
||||||
|
parser (>= 3.3.7.2)
|
||||||
|
prism (~> 1.4)
|
||||||
|
rubocop-minitest (0.38.1)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (>= 1.75.0, < 2.0)
|
||||||
|
rubocop-ast (>= 1.38.0, < 2.0)
|
||||||
|
rubocop-performance (1.25.0)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (>= 1.75.0, < 2.0)
|
||||||
|
rubocop-ast (>= 1.38.0, < 2.0)
|
||||||
|
rubocop-rspec (3.6.0)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (~> 1.72, >= 1.72.1)
|
||||||
|
ruby-progressbar (1.13.0)
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
sinatra (3.2.0)
|
sinatra (3.2.0)
|
||||||
mustermann (~> 3.0)
|
mustermann (~> 3.0)
|
||||||
|
|
@ -38,6 +92,9 @@ GEM
|
||||||
rack-protection (= 3.2.0)
|
rack-protection (= 3.2.0)
|
||||||
tilt (~> 2.0)
|
tilt (~> 2.0)
|
||||||
tilt (2.6.0)
|
tilt (2.6.0)
|
||||||
|
unicode-display_width (3.1.4)
|
||||||
|
unicode-emoji (~> 4.0, >= 4.0.4)
|
||||||
|
unicode-emoji (4.0.4)
|
||||||
yaml (0.4.0)
|
yaml (0.4.0)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
|
|
@ -55,8 +112,15 @@ PLATFORMS
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
json (~> 2.6)
|
json (~> 2.6)
|
||||||
|
minitest
|
||||||
puma (~> 6.0)
|
puma (~> 6.0)
|
||||||
|
rack-test
|
||||||
rerun
|
rerun
|
||||||
|
rspec
|
||||||
|
rubocop
|
||||||
|
rubocop-minitest
|
||||||
|
rubocop-performance
|
||||||
|
rubocop-rspec
|
||||||
sinatra (~> 3.0)
|
sinatra (~> 3.0)
|
||||||
yaml (~> 0.2)
|
yaml (~> 0.2)
|
||||||
|
|
||||||
|
|
|
||||||
20
app.rb
20
app.rb
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'sinatra'
|
require 'sinatra'
|
||||||
require 'json'
|
require 'json'
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
|
|
@ -41,10 +43,8 @@ def determine_language(params, headers)
|
||||||
# Check for exact matches first
|
# Check for exact matches first
|
||||||
accepted_langs.each do |lang|
|
accepted_langs.each do |lang|
|
||||||
return lang if RESPONSES[lang]
|
return lang if RESPONSES[lang]
|
||||||
end
|
|
||||||
|
|
||||||
# Check for language family matches (e.g., 'nb' or 'nn' -> 'no')
|
# Check for language family matches (e.g., 'nb' or 'nn' -> 'no')
|
||||||
accepted_langs.each do |lang|
|
|
||||||
case lang
|
case lang
|
||||||
when /^zh/ # Chinese variants
|
when /^zh/ # Chinese variants
|
||||||
return 'zh'
|
return 'zh'
|
||||||
|
|
@ -111,7 +111,7 @@ get '/' do
|
||||||
no_response = get_no_response(lang)
|
no_response = get_no_response(lang)
|
||||||
|
|
||||||
case request.accept.first&.to_s
|
case request.accept.first&.to_s
|
||||||
when /application\/json/
|
when %r{application/json}
|
||||||
content_type :json
|
content_type :json
|
||||||
{
|
{
|
||||||
answer: no_response,
|
answer: no_response,
|
||||||
|
|
@ -150,8 +150,8 @@ get '/api/no' do
|
||||||
language: lang,
|
language: lang,
|
||||||
language_name: get_language_name(lang),
|
language_name: get_language_name(lang),
|
||||||
timestamp: Time.now.iso8601,
|
timestamp: Time.now.iso8601,
|
||||||
service: "No as a Service",
|
service: 'No as a Service',
|
||||||
version: "2.0.0"
|
version: '2.0.0'
|
||||||
}.to_json
|
}.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ get '/api/no/:lang' do
|
||||||
content_type :json
|
content_type :json
|
||||||
status 404
|
status 404
|
||||||
return {
|
return {
|
||||||
error: "Language not supported",
|
error: 'Language not supported',
|
||||||
requested: lang,
|
requested: lang,
|
||||||
available: get_available_languages.map { |l| l[:code] },
|
available: get_available_languages.map { |l| l[:code] },
|
||||||
timestamp: Time.now.iso8601
|
timestamp: Time.now.iso8601
|
||||||
|
|
@ -176,8 +176,8 @@ get '/api/no/:lang' do
|
||||||
language: lang,
|
language: lang,
|
||||||
language_name: get_language_name(lang),
|
language_name: get_language_name(lang),
|
||||||
timestamp: Time.now.iso8601,
|
timestamp: Time.now.iso8601,
|
||||||
service: "No as a Service",
|
service: 'No as a Service',
|
||||||
version: "2.0.0"
|
version: '2.0.0'
|
||||||
}.to_json
|
}.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ end
|
||||||
get '/health' do
|
get '/health' do
|
||||||
content_type :json
|
content_type :json
|
||||||
{
|
{
|
||||||
status: "healthy",
|
status: 'healthy',
|
||||||
languages_loaded: RESPONSES.keys.size,
|
languages_loaded: RESPONSES.keys.size,
|
||||||
timestamp: Time.now.iso8601
|
timestamp: Time.now.iso8601
|
||||||
}.to_json
|
}.to_json
|
||||||
|
|
@ -197,7 +197,7 @@ get '/*' do
|
||||||
no_response = get_no_response(lang)
|
no_response = get_no_response(lang)
|
||||||
|
|
||||||
case request.accept.first&.to_s
|
case request.accept.first&.to_s
|
||||||
when /application\/json/
|
when %r{application/json}
|
||||||
content_type :json
|
content_type :json
|
||||||
{
|
{
|
||||||
answer: no_response,
|
answer: no_response,
|
||||||
|
|
|
||||||
106
spec/app_spec.rb
Normal file
106
spec/app_spec.rb
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# spec/app_spec.rb
|
||||||
|
require_relative 'spec_helper' # Load common setup
|
||||||
|
|
||||||
|
RSpec.describe 'No as a Service' do
|
||||||
|
include Rack::Test::Methods # Rack::Test methods included via spec_helper.rb
|
||||||
|
|
||||||
|
# The `app` method is defined in spec_helper.rb, required by Rack::Test
|
||||||
|
|
||||||
|
context 'GET /' do
|
||||||
|
it 'returns a default English "no" in HTML' do
|
||||||
|
get '/'
|
||||||
|
# Debugging: puts last_response.status, last_response.body
|
||||||
|
expect(last_response.status).to eq(200), "Expected status 200, got #{last_response.status}"
|
||||||
|
expect(last_response.body).to include('No'), "Expected body to include 'No', got:\n#{last_response.body}"
|
||||||
|
expect(last_response.content_type).to include('text/html'),
|
||||||
|
"Expected HTML content type, got #{last_response.content_type}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns JSON when Accept header is application/json' do
|
||||||
|
header 'Accept', 'application/json'
|
||||||
|
get '/'
|
||||||
|
expect(last_response.status).to eq(200), "Expected status 200 with Accept: JSON, got #{last_response.status}"
|
||||||
|
expect(last_response.content_type).to include('application/json'),
|
||||||
|
"Expected JSON content type with Accept: JSON, got #{last_response.content_type}"
|
||||||
|
|
||||||
|
json_response = JSON.parse(last_response.body)
|
||||||
|
expect(json_response).to be_a(Hash), "Expected JSON response to be a Hash, got #{json_response.class}"
|
||||||
|
expect(json_response['response']).to be_a(String),
|
||||||
|
"Expected 'response' key with string value, got #{json_response['response'].class}"
|
||||||
|
expect(json_response['response']).not_to be_empty, "Expected 'response' value to be non-empty"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns JSON when format parameter is json' do
|
||||||
|
get '/?format=json'
|
||||||
|
expect(last_response.status).to eq(200), "Expected status 200 with ?format=json, got #{last_response.status}"
|
||||||
|
expect(last_response.content_type).to include('application/json'),
|
||||||
|
"Expected JSON content type with ?format=json, got #{last_response.content_type}"
|
||||||
|
|
||||||
|
json_response = JSON.parse(last_response.body)
|
||||||
|
expect(json_response).to be_a(Hash), "Expected JSON response to be a Hash, got #{json_response.class}"
|
||||||
|
expect(json_response['response']).to be_a(String),
|
||||||
|
"Expected 'response' key with string value, got #{json_response['response'].class}"
|
||||||
|
expect(json_response['response']).not_to be_empty, "Expected 'response' value to be non-empty"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'GET /:lang_code' do
|
||||||
|
it 'returns "no" in Norwegian (no)' do
|
||||||
|
get '/no'
|
||||||
|
expect(last_response.status).to eq(200), "Expected status 200 for /no, got #{last_response.status}"
|
||||||
|
expect(last_response.body).to include('Nei'),
|
||||||
|
"Expected body to include 'Nei' for /no, got:\n#{last_response.body}"
|
||||||
|
expect(last_response.content_type).to include('text/html'),
|
||||||
|
"Expected HTML content type for /no, got #{last_response.content_type}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns "no" in Swedish (sv)' do
|
||||||
|
get '/sv'
|
||||||
|
expect(last_response.status).to eq(200), "Expected status 200 for /sv, got #{last_response.status}"
|
||||||
|
expect(last_response.body).to include('Nej'),
|
||||||
|
"Expected body to include 'Nej' for /sv, got:\n#{last_response.body}"
|
||||||
|
expect(last_response.content_type).to include('text/html'),
|
||||||
|
"Expected HTML content type for /sv, got #{last_response.content_type}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 for an unsupported language code' do
|
||||||
|
get '/xyz'
|
||||||
|
expect(last_response.status).to eq(404),
|
||||||
|
"Expected status 404 for unsupported language, got #{last_response.status}"
|
||||||
|
expect(last_response.body).to include('Not Found'),
|
||||||
|
"Expected body to include 'Not Found', got:\n#{last_response.body}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'GET /languages' do
|
||||||
|
it 'lists all supported languages in JSON' do
|
||||||
|
get '/languages'
|
||||||
|
expect(last_response.status).to eq(200), "Expected status 200 for /languages, got #{last_response.status}"
|
||||||
|
expect(last_response.content_type).to include('application/json'),
|
||||||
|
"Expected JSON content type for /languages, got #{last_response.content_type}"
|
||||||
|
|
||||||
|
json_response = JSON.parse(last_response.body)
|
||||||
|
expect(json_response).to be_an(Array), "Expected JSON response to be an Array, got #{json_response.class}"
|
||||||
|
|
||||||
|
# Check for a subset of expected languages. Add all languages from your responses.yml.
|
||||||
|
expected_languages = %w[en no sv fi is da fo].sort
|
||||||
|
actual_languages = json_response.sort
|
||||||
|
|
||||||
|
expect(actual_languages.size).to eq(expected_languages.size),
|
||||||
|
"Expected #{expected_languages.size} languages, got #{actual_languages.size}"
|
||||||
|
expect(actual_languages).to eq(expected_languages), 'Language list mismatch.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'GET /health' do
|
||||||
|
it 'returns OK' do
|
||||||
|
get '/health'
|
||||||
|
expect(last_response.status).to eq(200), "Expected status 200 for /health, got #{last_response.status}"
|
||||||
|
expect(last_response.body).to eq('OK'), "Expected body 'OK' for /health, got '#{last_response.body}'"
|
||||||
|
expect(last_response.content_type).to include('text/plain'),
|
||||||
|
"Expected text/plain content type for /health, got #{last_response.content_type}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
31
spec/spec_helper.rb
Normal file
31
spec/spec_helper.rb
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# spec/spec_helper.rb
|
||||||
|
ENV['RACK_ENV'] = 'test' # Set environment to test, important for Sinatra config
|
||||||
|
|
||||||
|
require 'rack/test'
|
||||||
|
require 'rspec' # For RSpec
|
||||||
|
require 'json' # Required if you're testing JSON responses
|
||||||
|
|
||||||
|
# --- CRITICAL APP LOADING ---
|
||||||
|
# Adjust this path if your app.rb is NOT directly in the parent directory of 'spec/'
|
||||||
|
# Example: If app.rb is in `src/app.rb`, use `require_relative '../src/app.rb'`
|
||||||
|
require_relative '../app'
|
||||||
|
|
||||||
|
# Configure Rack::Test
|
||||||
|
RSpec.configure do |config|
|
||||||
|
config.include Rack::Test::Methods # Include Rack::Test methods
|
||||||
|
|
||||||
|
# This is *THE* most critical part for Sinatra tests.
|
||||||
|
# It must return the instance of your Sinatra application.
|
||||||
|
def app
|
||||||
|
# Option 1: For classic style Sinatra apps (most common for small apps)
|
||||||
|
# where you just have `get '/' do ... end` directly in app.rb
|
||||||
|
Sinatra::Application
|
||||||
|
|
||||||
|
# Option 2: For modular Sinatra apps (if your app.rb defines a class)
|
||||||
|
# class MyApp < Sinatra::Base; ... end
|
||||||
|
# If this is your case, uncomment the line below and replace 'MyApp'
|
||||||
|
# MyApp.new
|
||||||
|
end
|
||||||
|
end
|
||||||
96
test/app_test.rb
Normal file
96
test/app_test.rb
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# test/app_test.rb
|
||||||
|
require_relative 'test_helper' # Load common setup
|
||||||
|
|
||||||
|
class AppTest < Minitest::Test
|
||||||
|
include Rack::Test::Methods # Include Rack::Test methods
|
||||||
|
|
||||||
|
# The `app` method is defined in test_helper.rb, required by Rack::Test
|
||||||
|
|
||||||
|
def test_root_path_returns_default_english_no
|
||||||
|
get '/'
|
||||||
|
# Debugging: puts last_response.status, last_response.body
|
||||||
|
assert last_response.ok?, "Expected status 200, got #{last_response.status}"
|
||||||
|
assert_includes last_response.body, 'No', "Expected body to include 'No', got:\n#{last_response.body}"
|
||||||
|
assert_includes last_response.content_type, 'text/html',
|
||||||
|
"Expected HTML content type, got #{last_response.content_type}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_language_path_returns_specific_language_no
|
||||||
|
# Test Norwegian
|
||||||
|
get '/no'
|
||||||
|
assert last_response.ok?, "Expected status 200 for /no, got #{last_response.status}"
|
||||||
|
assert_includes last_response.body, 'Nei', "Expected body to include 'Nei' for /no, got:\n#{last_response.body}"
|
||||||
|
assert_includes last_response.content_type, 'text/html',
|
||||||
|
"Expected HTML content type for /no, got #{last_response.content_type}"
|
||||||
|
|
||||||
|
# Test Swedish
|
||||||
|
get '/sv'
|
||||||
|
assert last_response.ok?, "Expected status 200 for /sv, got #{last_response.status}"
|
||||||
|
assert_includes last_response.body, 'Nej', "Expected body to include 'Nej' for /sv, got:\n#{last_response.body}"
|
||||||
|
assert_includes last_response.content_type, 'text/html',
|
||||||
|
"Expected HTML content type for /sv, got #{last_response.content_type}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_unsupported_language_returns_not_found
|
||||||
|
get '/xyz' # Non-existent language
|
||||||
|
assert_equal 404, last_response.status, "Expected status 404 for unsupported language, got #{last_response.status}"
|
||||||
|
# Asserting a general 'Not Found' message. Adjust if your 404 page has a specific string.
|
||||||
|
assert_includes last_response.body, 'Not Found', "Expected body to include 'Not Found', got:\n#{last_response.body}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_lists_all_supported_languages_in_json
|
||||||
|
get '/languages'
|
||||||
|
assert last_response.ok?, "Expected status 200 for /languages, got #{last_response.status}"
|
||||||
|
assert_includes last_response.content_type, 'application/json',
|
||||||
|
"Expected JSON content type for /languages, got #{last_response.content_type}"
|
||||||
|
|
||||||
|
# Ensure JSON parsing is successful
|
||||||
|
json_response = JSON.parse(last_response.body)
|
||||||
|
assert_kind_of Array, json_response, "Expected JSON response to be an Array, got #{json_response.class}"
|
||||||
|
|
||||||
|
# Check for a subset of expected languages. Add all languages from your responses.yml.
|
||||||
|
expected_languages = %w[en no sv fi is da fo].sort # Sort for consistent comparison if order isn't guaranteed
|
||||||
|
actual_languages = json_response.sort
|
||||||
|
|
||||||
|
assert_equal expected_languages.size, actual_languages.size,
|
||||||
|
"Expected #{expected_languages.size} languages, got #{actual_languages.size}"
|
||||||
|
assert_equal expected_languages, actual_languages, 'Language list mismatch.'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_returns_json_when_accept_header_is_json
|
||||||
|
header 'Accept', 'application/json' # Set the Accept header
|
||||||
|
get '/'
|
||||||
|
assert last_response.ok?, "Expected status 200 with Accept: JSON, got #{last_response.status}"
|
||||||
|
assert_includes last_response.content_type, 'application/json',
|
||||||
|
"Expected JSON content type with Accept: JSON, got #{last_response.content_type}"
|
||||||
|
|
||||||
|
json_response = JSON.parse(last_response.body)
|
||||||
|
assert_kind_of Hash, json_response, "Expected JSON response to be a Hash, got #{json_response.class}"
|
||||||
|
assert json_response['response'].is_a?(String),
|
||||||
|
"Expected 'response' key with string value, got #{json_response['response'].class}"
|
||||||
|
assert json_response['response'].length.positive?, "Expected 'response' value to be non-empty"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_returns_json_when_format_param_is_json
|
||||||
|
get '/?format=json' # Use the format parameter
|
||||||
|
assert last_response.ok?, "Expected status 200 with ?format=json, got #{last_response.status}"
|
||||||
|
assert_includes last_response.content_type, 'application/json',
|
||||||
|
"Expected JSON content type with ?format=json, got #{last_response.content_type}"
|
||||||
|
|
||||||
|
json_response = JSON.parse(last_response.body)
|
||||||
|
assert_kind_of Hash, json_response, "Expected JSON response to be a Hash, got #{json_response.class}"
|
||||||
|
assert json_response['response'].is_a?(String),
|
||||||
|
"Expected 'response' key with string value, got #{json_response['response'].class}"
|
||||||
|
assert json_response['response'].length.positive?, "Expected 'response' value to be non-empty"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_health_check_returns_ok
|
||||||
|
get '/health'
|
||||||
|
assert last_response.ok?, "Expected status 200 for /health, got #{last_response.status}"
|
||||||
|
assert_equal 'OK', last_response.body, "Expected body 'OK' for /health, got '#{last_response.body}'"
|
||||||
|
assert_includes last_response.content_type, 'text/plain',
|
||||||
|
"Expected text/plain content type for /health, got #{last_response.content_type}"
|
||||||
|
end
|
||||||
|
end
|
||||||
30
test/test_helper.rb
Normal file
30
test/test_helper.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# test/test_helper.rb
|
||||||
|
ENV['RACK_ENV'] = 'test' # Set environment to test, important for Sinatra config
|
||||||
|
|
||||||
|
require 'rack/test'
|
||||||
|
require 'minitest/autorun' # For Minitest
|
||||||
|
require 'json' # Required if you're testing JSON responses
|
||||||
|
|
||||||
|
# --- CRITICAL APP LOADING ---
|
||||||
|
# Adjust this path if your app.rb is NOT directly in the parent directory of 'test/'
|
||||||
|
# Example: If app.rb is in `src/app.rb`, use `require_relative '../src/app.rb'`
|
||||||
|
require_relative '../app'
|
||||||
|
|
||||||
|
# Configure Rack::Test
|
||||||
|
module Rack::Test::Methods
|
||||||
|
def app
|
||||||
|
# This is *THE* most critical part for Sinatra tests.
|
||||||
|
# It must return the instance of your Sinatra application.
|
||||||
|
|
||||||
|
# Option 1: For classic style Sinatra apps (most common for small apps)
|
||||||
|
# where you just have `get '/' do ... end` directly in app.rb
|
||||||
|
Sinatra::Application
|
||||||
|
|
||||||
|
# Option 2: For modular Sinatra apps (if your app.rb defines a class)
|
||||||
|
# class MyApp < Sinatra::Base; ... end
|
||||||
|
# If this is your case, uncomment the line below and replace 'MyApp'
|
||||||
|
# MyApp.new
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue