Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yii::$app null when called inside haveFriend does #114

Open
smichae opened this issue Dec 30, 2024 · 15 comments
Open

Yii::$app null when called inside haveFriend does #114

smichae opened this issue Dec 30, 2024 · 15 comments

Comments

@smichae
Copy link
Contributor

smichae commented Dec 30, 2024

v1.1.11 introduced new behavior where Yii::$app is null inside a "does" function call by a "friend". I'm not sure if this is intended behavior, but when the a friend's 'does' function is called, it calls Codeception\Module\Yii2 _initializeSession. Up until v1.1.10, this called the client->removeContext, but now it calls client->restart. Restart sets Yii2::$app to null, and in the "does" friend flow, startApp() is not called. This doesn't seem to be intended behavior since tests are encouraged to use Yii2::$app directly.

@SamMousa
Copy link
Collaborator

This is definitely a bug.

@SamMousa
Copy link
Collaborator

Can you link the commit that breaks it? I can't find the relevant change in .11...

@smichae
Copy link
Contributor Author

smichae commented Dec 30, 2024

I believe it was this one that also deleted the removeContext method. 219fbd9

@SamMousa
Copy link
Collaborator

SamMousa commented Jan 6, 2025

Hmm, looking into how to fix this.

Code sample:

$I->amOnPage('/messages');
$nick = $I->haveFriend('nick');
$nick->does(function(AcceptanceTester $I) {
    $I->amOnPage('/messages/new');
    $I->fillField('body', 'Hello all!');
    $I->click('Send');
    $I->see('Hello all!', '.message');
});
$I->wait(3);
$I->see('Hello all!', '.message');

The idea of interacting with \Yii::$app is that you can configure or assert the application state during requests.

In the old situation there was already strange stuff going on; inside the closure there's a new \Yii::$app that's not the same as the "old" one.

While the change was definitely unintended, I'm not sure if the old behavior is better than the new one.

Could you show us some sample test code?

@michaelarnauts
Copy link
Contributor

I've also hit this bug and can confirm above. We have a test suite that is doing authentication checks on our application. One test uses a $I->haveFriend() to switch to another user and during their login, a random session id is generated by calling $uuid = \Yii::$app->security->generateRandomString(32);. This doesn't work anymore since \Yii:$app is null now.

@SamMousa
Copy link
Collaborator

SamMousa commented Jan 6, 2025

Yeah the bug is confirmed, now the question is how to solve it properly. Since the previous behavior was already doing some weird stuff with application state.

Do you have some example test code that you could share publicly @michaelarnauts ?

@michaelarnauts
Copy link
Contributor

It's not easy to use my existing tests, but something like this fails now.

    public function runSomeTests(\FunctionalTester $I)
    {
        // works
        $uuid = \Yii::$app->security->generateRandomString(32);

        $friend = $I->haveFriend('friend');
        $friend->does(function (FunctionalTester $I) {
            // doesn't work
            $uuid = \Yii::$app->security->generateRandomString(32);
        });
    }

This will trigger a [Warning] Attempt to read property "security" on null.

@SamMousa
Copy link
Collaborator

SamMousa commented Jan 6, 2025

I'm failing to properly explain what I want..
I know how to reproduce the bug, but the old behaviour was also not usable in a lot of cases.

So I'm asking for real life examples of how you use this functionality in your tests, this might inspire me to both solve the bug AND make the behaviour internally consistent.

Some questions I have in my head:

  • what happens to application state changes before the closure?
  • what happens to application state changes after the closure?

@michaelarnauts
Copy link
Contributor

I would expect the \Yii:$app to be a different instance for the friend as for the initial FunctionalTester, but I do expect it to be initialized ofcourse, as is done with the initial function call. I would also expect that the full state of \Yii::$app was backed up before the closure and fully restored after the closure.

I guess it would make sense if the friend adds some HTTP headers, that those changes would be reverted.

I'm not using sessions or cookies in my application, but I do use $I->amBearerAuthenticated() to test some REST API's, and I sometimes want to use a second user in a haveFriend closure to do some other stuff, and go back to the initial user afterwards.

Note that I've had a related merge request a while ago: #91, you also had questions about haveFriend there.

@SamMousa
Copy link
Collaborator

SamMousa commented Jan 6, 2025

I would also expect that the full state of \Yii::$app was backed up before the closure and fully restored after the closure.

This was not true, and is probably not realistic for the Yii2 framework. Having multiple instances in series is already making us jump through hoops. Making them exist at the same time would make it less reliable.
I agree with the expectation btw, that is how it should work.

I guess it would make sense if the friend adds some HTTP headers, that those changes would be reverted.

This happens at the codeception level, so that's not our problem, but I know cookies are restored, not sure about headers.

you also had questions about haveFriend there.

Yeah because I'm not sure the whole MultiSession thing is worth it.

est some REST API's, and I sometimes want to use a second user in a haveFriend closure to do some other stuff, and go back to the initial user afterwards.

I have this too, but I choose to deliberately just set the header and work in series instead of inside a haveFriend closure (also I did not know about it until probably #91).

What would you think about:

  1. Restoring this bug to old behavior in bugfix release
  2. Removing multisession in a major release.

We cannot make reasonable expectations come true and therefore I believe we can do better without this feature.

@michaelarnauts
Copy link
Contributor

I think the behaviour should indeed be restored in a bugfix release. Especially since it's hidden behind a "fix typing" merge request.

As for removing the feature, that would be a pity, since there can still be a use case. I don't mind that the app state is the same for a friend. If this behaviour is documented, I think the feature can stay, but that decision is all up to you of course.

@SamMousa
Copy link
Collaborator

SamMousa commented Jan 6, 2025

You up for making a PR? If not i will tomorrow.

@samdark your opinion on removing multi session in a major release?

@SamMousa
Copy link
Collaborator

SamMousa commented Jan 6, 2025

I don't mind that the app state is the same for a friend.

Actually app state is blank inside the friend and not restored after the friend...
So changes before the friend get lost and not restored after the friend.

@michaelarnauts
Copy link
Contributor

You up for making a PR? If not i will tomorrow.

@samdark your opinion on removing multi session in a major release?

Hey @SamMousa . Do you have any update on this?

@SamMousa
Copy link
Collaborator

I forgot about it to be honest. Are you up for making a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants