cucumber-ltd / feynman Goto Github PK
View Code? Open in Web Editor NEWOrganise test automation code around behaviour
Organise test automation code around behaviour
This will avoid the noise when defining namespaces around tasks, like:
const CreateProject = Task('CreateProject', [], Task => Task('named', ['projectName']))
and instead you can just write
const CreateProject = Task('CreateProject', Task => Task('named', ['projectName']))
I know this is going to result in fiddly code that counts argument numbers but for readability of client code I think it's worth it.
We are currently using this in Cucumber Pro:
const tell = ({ listener, tellerItem, listenerItem }) => async ({
actor,
}) => {
listenerItem = listenerItem || tellerItem
const value = await actor.asks(Recall.about(tellerItem))
await listener.attemptsTo(Remember.that(listenerItem).is(value))
}
handle(Tell.about, tell)
handle(Tell.about.as, tell)
Consider the following:
interactions({
ProjectInfoAboutProject: { named: (projectName) => { /* handler stuff */ } }
})
Say we also want a sub-interaction like this:
ProjectInfoAboutProject.named(projectName).hasCollaboratorNamed('Joe')
Is not feasible at the moment. It'd be good to have a similar API to tasks:
interactions({
ProjectInfoAboutProject: {
named: interaction('projectName', ({ projectName }) => /* handler stuff */, {
hasCollaboratorNamed: interaction(
'collaboratorName',
({ projectName, collaboratorName }) => /* sub-handler */
)
})
}
})
It should be possible to pass a question to the Remember.that
action so as to avoid this sort of code:
Remember.that('my name').is(await actor.asks(WhatIsMyName))
and instead just be able to write:
Remember.that('my name').is(WhatIsMyName)
@jbpros I wanted to start a conversation about logging.
I've been thinking we could configure a logger like this:
const { configure } = require('feynman')
configure(config => config.logger = console)
Then we should be able to see task descriptions coming out:
Given a user named Dave with email '[email protected]'
Actor dave:
Create a user named 'dave' with email '[email protected]'
Now that leaves us with how to log the bare (inter)action functions.
If you imagine defining an action like SignUp
that then uses some browser interactions, it might look like this at the moment:
const SignUp = (
as: name => ({ actor }) =>
actor.attemptsTo(Follow.link("Sign up"), FillIn.fieldLabelled("Username").with(name))
}
We won't be able to log any of these, because (as far as I understand it) we can't ask the action function what the names of the wrapping functions / constants were that it was created by.
But we also want to keep the mechanism of defining these actions super lightweight, because the whole essence of this pattern, as I see it, is having lots and lots of these small compose-able actions, so we want to have minimal overhead on making new ones.
So could we make it possible to do this?
const { SignUp } = actions({ SignUp: ({
as: name => ({ actor }) =>
actor.attemptsTo(Follow.link("Sign up"), FillIn.fieldLabelled("Username").with(name))
})
})
The actions
method would return a proxy that decorated the action function with a description
built from the calls that had been made through the proxy to access the builder functions. That way we'd then be able to log it nicely, and we'd minimise the barrier to building new actions.
WDYT? Am I making sense?
Consider adding a cucumber-feynman package which does this automatically.
e.g. we have this code for our "web" perspective:
let pool, server
Before(async function() {
pool = new BrowserPool()
abilities({
createBrowser: pool.take.bind(pool),
})
server = abilities.server
await server.start(webappHttpPort())
})
After(() => pool.closeAllBrowsers())
After(() => server.stop())
What we want is to be able to wrap that in something that only runs it when the web
perspective is the default.
e.g.
perspective("web", { whenDefault: () => {
let pool, server
Before(async function() {
pool = new BrowserPool()
abilities({
createBrowser: pool.take.bind(pool),
})
server = abilities.server
await server.start(webappHttpPort())
})
After(() => pool.closeAllBrowsers())
After(() => server.stop())
}})
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.