Skip to content

Commit f28068f

Browse files
committed
Fix updating project feature spec
Previously this spec was not representative of how the API was being used in practice and it was only really working by accident. The PUT requests in the examples were using the `Project#id` rather than the `Project#identifier` as they should have been. The spec was working even though the `Api::ProjectsController#load_project` before action was *not* finding the project, because the `load_and_authorize_resource` before action was then finding the project using `Project.find(params[:id])` and setting the `@project` instance variable used by the rest of the logic in the controller. However, clients of editor-api like editor-standalone use the project identifier as the resource ID in the URL path [1], so this spec was completely unrepresentative of how the endpoint was really being used. In this commit I've changed the examples to use the `Project#identifier` as the resource ID in the PUT requests. This means that the `Api::ProjectsController#load_project` before action now finds the project by identifier and since it sets the `@project` instance variable the `load_and_authorize_resource` before action no longer attempts to load the resource, it just does the authorize step using the already loaded project. In order to make this work reliably, I had to explicitly set the `Project#locale` to one of the fallback locales in `ProjectLoader` [2], i.e. 'en' or `nil`. Otherwise, the random locale selected in the project factory [3] meant that sometimes the `load_project` before action (which uses the `ProjectLoader` did not find the project and the `load_and_authorize_resource` before action raised an `ActiveRecord::RecordNotFound` resulting in a 404 Not Found. Now the spec is no longer making use of the randome locale from the factory, I've taken the opportunity to add some new examples demonstrating the behaviour when the project has different locales. This effectively demonstrates that `load_project` is wired up to `ProjectLoader` correctly. As an aside, I'm not convinced that having the factory select a locale at random is a good idea. I found it very confusing when it led to undeterministic specs. However, I'll leave that for another time. [1]: https://github.com/RaspberryPiFoundation/editor-standalone/blob/1d4375635cb6890794732072d608dbd4b05b3bb0/src/utils/apiCallHandler/projects.js#L16 [2]: https://github.com/RaspberryPiFoundation/editor-api/blob/b4bd337d09a88b1f41ecdc13136f7d11da0dcf89/lib/project_loader.rb#L8 [3]: https://github.com/RaspberryPiFoundation/editor-api/blob/b4bd337d09a88b1f41ecdc13136f7d11da0dcf89/spec/factories/project.rb#L9
1 parent 300f736 commit f28068f

File tree

1 file changed

+30
-6
lines changed

1 file changed

+30
-6
lines changed

spec/features/project/updating_a_project_spec.rb

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
RSpec.describe 'Updating a project', type: :request do
66
let(:project_type) { Project::Types::PYTHON }
77
let(:user_id) { owner.id }
8-
let!(:project) { create(:project, name: 'Test Project', user_id:, locale: 'en', project_type:) }
8+
let(:locale) { 'en' }
9+
let!(:project) { create(:project, name: 'Test Project', user_id:, locale:, project_type:) }
910
let(:owner) { create(:owner, school:) }
1011
let(:school) { create(:school) }
1112

@@ -27,31 +28,31 @@
2728
end
2829

2930
it 'responds 200 OK' do
30-
put("/api/projects/#{project.id}", headers:, params:)
31+
put("/api/projects/#{project.identifier}", headers:, params:)
3132
expect(response).to have_http_status(:ok)
3233
end
3334

3435
it 'responds with the project JSON' do
35-
put("/api/projects/#{project.id}", headers:, params:)
36+
put("/api/projects/#{project.identifier}", headers:, params:)
3637
data = JSON.parse(response.body, symbolize_names: true)
3738

3839
expect(data[:name]).to eq('New Name')
3940
end
4041

4142
it 'responds with the components JSON' do
42-
put("/api/projects/#{project.id}", headers:, params:)
43+
put("/api/projects/#{project.identifier}", headers:, params:)
4344
data = JSON.parse(response.body, symbolize_names: true)
4445

4546
expect(data[:components].first[:content]).to eq('print("hello")')
4647
end
4748

4849
it 'responds 422 Unprocessable Entity when params are invalid' do
49-
put("/api/projects/#{project.id}", headers:, params: { project: { components: [{ name: ' ' }] } })
50+
put("/api/projects/#{project.identifier}", headers:, params: { project: { components: [{ name: ' ' }] } })
5051
expect(response).to have_http_status(:unprocessable_entity)
5152
end
5253

5354
it 'responds 401 Unauthorized when no token is given' do
54-
put("/api/projects/#{project.id}", params:)
55+
put("/api/projects/#{project.identifier}", params:)
5556
expect(response).to have_http_status(:unauthorized)
5657
end
5758

@@ -78,6 +79,29 @@
7879
end
7980
end
8081

82+
context 'when locale is nil, i.e. the other fallback locale in ProjectLoader' do
83+
let(:locale) { nil }
84+
85+
it 'responds 200 OK even though no locale is specified in query string' do
86+
put("/api/projects/#{project.identifier}", headers:, params:)
87+
expect(response).to have_http_status(:ok)
88+
end
89+
end
90+
91+
context "when locale is 'fr', i.e. not a fallback locale in ProjectLoader" do
92+
let(:locale) { 'fr' }
93+
94+
it 'responds 200 OK if locale is specified in query string' do
95+
put("/api/projects/#{project.identifier}?locale=fr", headers:, params:)
96+
expect(response).to have_http_status(:ok)
97+
end
98+
99+
it 'responds 404 Not Found if locale is not specified in query string' do
100+
put("/api/projects/#{project.identifier}", headers:, params:)
101+
expect(response).to have_http_status(:not_found)
102+
end
103+
end
104+
81105
private
82106

83107
def headers

0 commit comments

Comments
 (0)