Expose story context to the success result of the story run method.
See original GitHub issueStories can be used both as stand-alone objects or substories of other stories.
If we want to return a value from such a story when we run it as a stand-alone object, we have a problem.
We can’t use the Result
class in the story since it’ll stop the execution of the parent story when we inject the story.
For example, we have a story like this:
class TokenUseCase:
@story
@arguments('user')
def obtain_token(I):
I.require_user_active
I.create_token
I.return_token
def require_user_active(self, ctx):
if ctx.user.is_active:
return Success()
return Failure()
def create_token(self, ctx):
ctx.token = self.create_user_token(ctx.user)
return Success()
def return_token(self, ctx):
return Result({'token': ctx.token})
In this case, we have two options:
- Split this story into two parts. One will be used as a substory. The other one is the stand-alone wrapper from two steps. One for the story, one for the return statement.
- Pass a boolean somehow (IoC for example) to the last step to decide what kind of objects we need to return.
Both variants do not bring me joy.
To be clear, in most cases Result won’t be a problem If we describe the actual process from the business domain, and this process supposed to give us a result, this will be a valid behavior on any level of nesting.
The problem appears only for relatively low-level stuff like tokens. We can’t make any business decision at this level of logic, so Result is not suited there by design.
Even it’s a relatively rare problem from a business logic perspective, I don’t want to force users to write wrappers and pass boolean.
return_token
should not even exist in this case.
I propose to make available ctx
object on the successful result of the run method.
This way we’ll be able to access the token
variable when we want to use it as a stand-alone story.
class TokenUseCase:
@story
@arguments('user')
def obtain_token(I):
I.require_user_active
I.create_token
def require_user_active(self, ctx):
if ctx.user.is_active:
return Success()
return Failure()
def create_token(self, ctx):
ctx.token = self.create_user_token(ctx.user)
return Success()
result = TokenUseCase().obtain_token.run(User())
assert result.is_success
assert result.ctx.token == 'abc'
I would like to invite @ditansu and @ramidk to discuss this proposal.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:2
- Comments:9 (6 by maintainers)
Top GitHub Comments
@ditansu From what I understand, you’ll be happy with the origin proposal from this issue.
Superseded by #627