1

Where am I going wrong?

 describe '#update' do
    let(:new_name) { Faker::Lorem.word }
    let(:request) { patch :update, id: parent_folder.id, folder: { name: new_name, parent_id: nil, user_id: user.id } }

    it 'should change the name' do
      expect{ request }.to change(parent_folder.reload,:name).from(parent_folder.name).to(new_name)
    end

    it 'does work gadnammit' do
      ap parent_folder.reload.name #=> e.g. aqua
      request
      ap parent_folder.reload.name #=> e.g. hortis
    end
  end

The result of 'should change the name' is

Failure/Error: expect{ request }.to change(parent_folder.reload,:name).from(parent_folder.name).to(new_name)# @new_name
expected #name to have changed from "maxime" to "jimmies", but did not change

And yet 'does work gadnammit' logs two different names:

All examples were filtered out; ignoring {:focus=>true}
F."omnis"
"jimmies"

Failures:

1) FoldersController#update should change the name
     Failure/Error: expect{ request }.to change(parent_folder.reload,:name).from(parent_folder.name).to(new_name)# @new_name
       expected #name to have changed from "maxime" to "jimmies", but did not change
     # ./spec/controllers/folders_controller_spec.rb:62:in `block (3 levels) in <top (required)>'

Also, when you're using the let helper with Faker, I am aware you get a new result each time the variable it creates is called, which could be giving the illusion the name is changing in the 'does work gadnammit' spec. However, changing it to a hardcoded string yields no difference:

let(:new_name) { "stagnant" }

Also, this spec:

it 'should make database queries' do
  expect{ request }.to make_database_queries 
end

passes so I really think it is working...

SELECT  "users".* FROM "users"  WHERE "users"."id" = 1  ORDER BY "users"."id" ASC LIMIT 1
SELECT  "folders".* FROM "folders"  WHERE "folders"."user_id" = ? AND "folders"."id" = ? LIMIT 1
SAVEPOINT active_record_1
UPDATE "folders" SET "name" = ?, "updated_at" = ? WHERE "folders"."id" = 1
RELEASE SAVEPOINT active_record_1

(make_database_queries matcher courtesy of db-query-matchers gem)

TL;DR Why isn't

expect{ request }.to change(parent_folder.reload,:name).from(parent_folder.name).to(new_name)

working?

1 Answer 1

2

The parameter parent.folder.rename is evaluated at the time change is called. It doesn't (and can't) get re-evaluated after the block-under-test is executed. This most likely explains why name called on the resulting object does not change.

If you want an expression to be re-evaluated before and after the execution of the block under test, you need to pass change a block as in:

change { parent.folder.reload }.from(...).to(...)

The "parameter" version of change works when the first parameter remains unchanged (e.g. a constant) and the value returned by the method associated with the second parameter changes.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks peter! Shame it doesn't read nearly as well as expect{ request }.to change... Why is it that expect{ delete :destroy, id: child_folder.id }.to change(Folder, :count).by(-1) works? Surely that must evaluate Folder.count before and after the request is executed, so why doesn't it work when querying an actual record?
Right, I'm going to be honest I'm a bit confused. expect { employee.develop_great_new_social_networking_app }.to change(employee, :title).from("Mail Clerk").to("CEO") from rubydoc.info/github/rspec/rspec-expectations/RSpec/… very closely matchers what I want to and yet this doesn't work? Example please :)
I had to ask this question a second time. Didn't notice the curly braces, ignore me :P

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.