Comparing version 0.0.10 to 0.0.13
@@ -21,3 +21,3 @@ "use strict" | ||
const Actor = (abilities, perspective = Perspective()) => { | ||
const Actor = (abilities = {}, perspective = Perspective("unknown")) => { | ||
const actor = { | ||
@@ -36,3 +36,7 @@ attemptsTo: async (...actions) => { | ||
through: newPerspective => Actor(abilities, newPerspective), | ||
gainsAbilities: extraAbilities => Object.assign(abilities, extraAbilities) | ||
gainsAbilities: extraAbilities => { | ||
Object.assign(abilities, extraAbilities) | ||
return actor | ||
}, | ||
perspective | ||
} | ||
@@ -83,3 +87,4 @@ return actor | ||
const Perspective = (perspectiveName, definition) => { | ||
const Perspective = (name, definition) => { | ||
const handlers = {} | ||
const perspective = { | ||
@@ -89,15 +94,16 @@ handlerFor: action => { | ||
const { id, params = {} } = action | ||
if (!(id in perspective)) | ||
if (!(handlers.hasOwnProperty(id))) | ||
throw new Error( | ||
`No handler found for task "${action.id}" in "${ | ||
perspectiveName | ||
}" perspective` | ||
name | ||
}" perspective.\n\nAlternatives:\n${Object.keys(handlers).join("\n")}` | ||
) | ||
return perspective[id](params) | ||
} | ||
return handlers[id](params) | ||
}, | ||
name: name | ||
} | ||
const handle = (action, fn) => { | ||
perspective[action.id] = fn | ||
const registerHandler = (action, fn) => { | ||
handlers[action.id] = fn | ||
} | ||
if (definition) definition(handle) | ||
if (definition) definition(registerHandler) | ||
return perspective | ||
@@ -104,0 +110,0 @@ } |
@@ -271,4 +271,3 @@ "use strict" | ||
} | ||
const joe = Actor({}) | ||
joe.gainsAbilities({ db }) | ||
const joe = Actor({}).gainsAbilities({ db }) | ||
await joe.attemptsTo(({ db }) => { | ||
@@ -312,5 +311,6 @@ db.insert() | ||
} | ||
assert.equal( | ||
error.message, | ||
'No handler found for task "DoSomething" in "Perspective" perspective' | ||
assert( | ||
error.message.match( | ||
/No handler found for task "DoSomething" in "Perspective" perspective/ | ||
) | ||
) | ||
@@ -321,3 +321,3 @@ }) | ||
it("allows an actor to remember state", async () => { | ||
const joe = Actor({...Memory() }) | ||
const joe = Actor({ ...Memory() }) | ||
await joe.attemptsTo(Remember.that("thing").is("something")) | ||
@@ -324,0 +324,0 @@ assert.equal(await joe.asks(Recall.about("thing")), "something") |
{ | ||
"name": "feynman", | ||
"version": "0.0.10", | ||
"version": "0.0.13", | ||
"description": "A screenplay pattern library for javascript", | ||
@@ -5,0 +5,0 @@ "main": "lib/feynman.js", |
@@ -5,8 +5,68 @@ # Feynman | ||
Feynman is designed to make it simple to run the same tasks at different levels of your stack. | ||
What's unique about feynman is that you can define multiple *perspectives* that allow you to run the same tasks against your | ||
application in different ways. More on that later. | ||
Here's an example: | ||
It starts with the `Actor` | ||
## Actors perform actions using their abilities | ||
At its most basic, you give an `Actor` some `Abilities` and then tell them to perform some `Actions`: | ||
```javascript | ||
const { Book, CancelRoom, CurrentBookings } = require('TODO') | ||
const { Actor } = require('feynman') | ||
const abilities = { console } | ||
const Write = { | ||
message: text => ({ console }) => console.log(text), | ||
error: text => ({ console }) => console.error(text) | ||
} | ||
const actor = Actor(abilities) | ||
actor.attemptsTo( | ||
Write.message("Hello world"), | ||
Write.error("eek!") | ||
) | ||
``` | ||
The whole set of abilities (in this case, just the `console`) is passed to each action handler function when it's attempted. The action | ||
handler can just pick out the abilities it needs to do its work. | ||
So what's the point? Well, by definining your test automation code as these little actions, you can compose them together into | ||
higher-level abstractions. | ||
## Actions are composable | ||
Actions are *composable* because they're also passed the actor, so you can tell them to perform more actions: | ||
```javascript | ||
const { Actor } = require('feynman') | ||
const abilities = { console } | ||
const Write = { | ||
message: text => ({ console }) => console.log(text) | ||
} | ||
const Sing { | ||
song: ({ actor }) => | ||
actor.attemptsTo( | ||
Write.message("Three blind mice") | ||
Write.message("See how they run") | ||
) | ||
} | ||
} | ||
const actor = Actor(abilities) | ||
actor.attemptsTo(Sing.song()) | ||
``` | ||
This allows you to build up higher-level behaviours out of granular actions. | ||
## Actors can take different perspectives | ||
If you want your [acceptance tests to run fast](https://www.youtube.com/watch?v=Fk4rCn4YLLU), you often want to be able to exercise the same behaviour through different levels in your stack. | ||
.... TODO | ||
```javascript | ||
const { Book, CancelRoom, CurrentBookings } = require('./tasks') | ||
const throughTheDomain = new DomainPerspective() | ||
@@ -13,0 +73,0 @@ const throughTheWebApp = new WebAppPerspective() |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
32307451
2
16
526
178