When pre-conditions are required you should create these as part of the setup.
The best practice for sequential test cases is to avoid them and use a different setup approach instead.
For example, for "Given I am a logged in user visiting screen x" we may need to create a user, set the password, verify account, perform the login, navigate to the screen. All of that needs to be in the setup for the "Given".
As others have noted, it's best to make these various actions (e.g. 'login') reusable methods because desired states like "logged in" are likely to be shared amongst a great number of cases.
A very common approach used by many organizations is to take an existing user, use an existing account, use existing orders, etc. This is brittle. It works for a few days/weeks/months and then breaks because the account changes. or is locked out. Or the order is archived. Or paid off. etc. Basically what you encounter is that state changes. You need to control state to avoid this. In order to control state you need to create ALL the test data - users, accounts, orders, everything. This will also lead to some interesting decisions, e.g. "but surely we must have all 65000 us state codes in our database", with the answer "we don't distinuigh any business based on zip code so one valid 5 digit zip code is all we need (along perhaps with one invalid, shorter/longer, alpha digits etc for testing).
Companies with large databases and existing systems may consider this extreme and impractical. It is not easy but many other large (often newer) companies have figured out the importance and need to do this despite the initial challenges and hard work. Often, for large companies code to instantiate objects and set state already exists in the form of application APIs through SOAP, REST, etc. The challenge then is to leverage this existing application infrastructure for the purpose of testing and automation.