Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Run Code Analysis
run: bundle exec rails code:analysis
- name: Check for duplicated code
run: npx --yes jscpd@5.4.1 .
- name: Run linter on production Dockerfile
uses: hadolint/hadolint-action@v3.3.0
with:
Expand Down
10 changes: 10 additions & 0 deletions .jscpd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"threshold": 1,
"reporters": ["console"],
"gitignore": true,
"ignore": [
"doc/openapi.yaml",
"public/*.html",
"knapsack_rspec_report.json"
]
}
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The `bin/*` wrappers transparently dispatch to Docker (`docker compose`) when `D
- `bin/bundle …` — bundler commands.
- `bin/web <cmd>` — arbitrary shell command inside the app container/environment.
- `bundle exec rails code:analysis` — runs the full lint suite: Brakeman, RuboCop, Reek, rails_best_practices, i18n-tasks (see `lib/tasks/code_analysis.rake`). Use this before opening a PR.
- `npx jscpd .` — copy/paste detection (config in `.jscpd.json`). Runs in CI and fails above 1% duplicated lines; generated files (`doc/openapi.yaml`) and Rails' static error pages are ignored.
- `bundle exec annotaterb models` — refresh schema annotations on models (config in `.annotaterb.yml`).
- `yarn build:js --watch` / `yarn build:css --watch` — JS/CSS bundling for ActiveAdmin assets (already wired into `bin/dev`).

Expand Down
2 changes: 1 addition & 1 deletion knapsack_rspec_report.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"spec/policies/admin_user_policy_spec.rb": 0.0266718809999702,
"spec/requests/api/v1/users/show_spec.rb": 0.8680702419999875,
"spec/policies/admin/user_policy_spec.rb": 0.017141818000027342,
"spec/requests/api/v1/users/create_spec.rb": 0.6782069589999651,
"spec/requests/api/v1/registrations/create_spec.rb": 0.6782069589999651,
"spec/acceptance/settings_spec.rb": 0.2261287540000012,
"spec/requests/api/v1/status_spec.rb": 0.01959373400001141,
"spec/policies/admin/page_policy_spec.rb": 0.021792449999963992,
Expand Down
112 changes: 73 additions & 39 deletions spec/requests/api/v1/registrations/create_spec.rb
Original file line number Diff line number Diff line change
@@ -1,69 +1,103 @@
# frozen_string_literal: true

describe 'POST api/v1/users/sign_up' do
describe 'POST api/v1/users' do
subject { post user_registration_path, params:, as: :json }

let(:user) { User.last }
let(:email) { 'test@example.com' }

let(:params) do
{
user: {
email: 'email@example.com',
password: 'password',
password_confirmation: 'password',
username: 'username',
first_name: 'first name',
last_name: 'last name'
username: 'test',
email:,
password: '12345678',
password_confirmation: '12345678',
first_name: 'Johnny',
last_name: 'Perez'
}
}
end

context 'with correct params' do
before do
it_behaves_like 'does not check authenticity token'
it_behaves_like 'there must not be a Set-Cookie in Header'

it 'returns a successful response' do
subject
expect(response).to have_http_status(:success)
end

it 'creates the user' do
expect { subject }.to change(User, :count).by(1)
end

it 'returns the user data', :aggregate_failures do
subject
expect(json[:user][:id]).to eq(user.id)
expect(json[:user][:email]).to eq(user.email)
expect(json[:user][:username]).to eq(user.username)
expect(json[:user][:uid]).to eq(user.uid)
expect(json[:user][:provider]).to eq('email')
expect(json[:user][:first_name]).to eq(user.first_name)
expect(json[:user][:last_name]).to eq(user.last_name)
end

it 'returns a valid client and access token' do
subject
token = response.header['access-token']
client = response.header['client']
expect(user.reload).to be_valid_token(token, client)
end

context 'when the email is not correct' do
let(:email) { 'invalid_email' }

it 'does not create a user' do
expect { subject }.not_to change(User, :count)
end

it 'does not return a successful response' do
subject
expect(response).to have_http_status(:unprocessable_content)
end
end

it_behaves_like 'there must not be a Set-Cookie in Header'
it_behaves_like 'does not check authenticity token'
context 'when the password is incorrect' do
let(:new_user) { User.find_by(email:) }

it 'returns success' do
expect(response).to be_successful
before do
params[:user].merge!({ password: 'short', password_confirmation: 'short' })
end

it 'returns the user' do
user = User.last
expect(json[:user][:id]).to eq(user.id)
expect(json[:user][:email]).to eq(params.dig(:user, :email))
expect(json[:user][:username]).to eq(params.dig(:user, :username))
expect(json[:user][:uid]).to eq(user.uid)
expect(json[:user][:provider]).to eq('email')
expect(json[:user][:first_name]).to eq(params.dig(:user, :first_name))
expect(json[:user][:last_name]).to eq(params.dig(:user, :last_name))
it 'does not create a user' do
subject
expect(new_user).to be_nil
end

it 'returns a valid client and access token' do
user = User.last
token = response.header['access-token']
client = response.header['client']
expect(user.reload).to be_valid_token(token, client)
it 'does not return a successful response' do
subject
expect(response).to have_http_status(:unprocessable_content)
end
end

context 'with incorrect params' do
let(:params) do
{
user: {
email: 'email@example.com',
password: 'password',
password_confirmation: 'wrong_password!'
}
}
context 'when passwords don\'t match' do
let(:new_user) { User.find_by(email:) }

before do
params[:user].merge!({ password: 'shouldmatch', password_confirmation: 'dontmatch' })
end

it 'does not create a user' do
subject
expect(new_user).to be_nil
end

it 'returns to be a client error' do
it 'does not return a successful response' do
subject
expect(response).to be_client_error
expect(response).to have_http_status(:unprocessable_content)
end

it 'return errors upon failure' do
it 'returns the error message' do
subject
expect(json.to_s).to match("Password confirmation doesn't match Password")
end
Expand Down
93 changes: 0 additions & 93 deletions spec/requests/api/v1/users/create_spec.rb

This file was deleted.

Loading