Comparing version 0.0.9 to 0.0.10
@@ -21,3 +21,3 @@ "use strict" | ||
const Actor = (perspective, abilities) => { | ||
const Actor = (abilities, perspective = Perspective()) => { | ||
const actor = { | ||
@@ -35,3 +35,3 @@ attemptsTo: async (...actions) => { | ||
}, | ||
through: newPerspective => Actor(newPerspective, abilities), | ||
through: newPerspective => Actor(abilities, newPerspective), | ||
gainsAbilities: extraAbilities => Object.assign(abilities, extraAbilities) | ||
@@ -38,0 +38,0 @@ } |
@@ -1,54 +0,61 @@ | ||
'use strict' | ||
"use strict" | ||
const assert = require('assert') | ||
const sinon = require('sinon') | ||
const { Perspective, Actor, Task, Memory, Remember, Recall } = require('./feynman') | ||
const assert = require("assert") | ||
const sinon = require("sinon") | ||
const { | ||
Perspective, | ||
Actor, | ||
Task, | ||
Memory, | ||
Remember, | ||
Recall | ||
} = require("./feynman") | ||
describe('feynman', () => { | ||
describe('task definitions', () => { | ||
it('defines a standalone task with some args', () => { | ||
describe("feynman", () => { | ||
describe("task definitions", () => { | ||
it("defines a standalone task with some args", () => { | ||
const StandaloneTask = Task( | ||
'StandaloneTask', | ||
'A task that stands alone', | ||
['arg'] | ||
"StandaloneTask", | ||
"A task that stands alone", | ||
["arg"] | ||
) | ||
assert(typeof StandaloneTask === 'function') | ||
assert.equal(StandaloneTask.id, 'StandaloneTask') | ||
assert.equal(StandaloneTask.description, 'A task that stands alone') | ||
const action = StandaloneTask('value') | ||
assert.equal(action.id, 'StandaloneTask') | ||
assert.deepEqual(action.params, { arg: 'value' }) | ||
assert(typeof StandaloneTask === "function") | ||
assert.equal(StandaloneTask.id, "StandaloneTask") | ||
assert.equal(StandaloneTask.description, "A task that stands alone") | ||
const action = StandaloneTask("value") | ||
assert.equal(action.id, "StandaloneTask") | ||
assert.deepEqual(action.params, { arg: "value" }) | ||
}) | ||
it('nests tasks', () => { | ||
const RootTask = Task('RootTask', 'The root task', ['rootArg'], Task => | ||
Task('NestedTask', 'with a nested task', ['nestedArg']) | ||
it("nests tasks", () => { | ||
const RootTask = Task("RootTask", "The root task", ["rootArg"], Task => | ||
Task("NestedTask", "with a nested task", ["nestedArg"]) | ||
) | ||
assert(typeof RootTask === 'function') | ||
assert.equal(RootTask.id, 'RootTask') | ||
assert.equal(RootTask.description, 'The root task') | ||
assert(typeof RootTask === "function") | ||
assert.equal(RootTask.id, "RootTask") | ||
assert.equal(RootTask.description, "The root task") | ||
const action = RootTask('root-value') | ||
assert.equal(action.id, 'RootTask') | ||
assert.deepEqual(action.params, { rootArg: 'root-value' }) | ||
assert(typeof RootTask.NestedTask === 'function') | ||
assert.equal(RootTask.NestedTask.id, 'RootTask.NestedTask') | ||
const action = RootTask("root-value") | ||
assert.equal(action.id, "RootTask") | ||
assert.deepEqual(action.params, { rootArg: "root-value" }) | ||
assert(typeof RootTask.NestedTask === "function") | ||
assert.equal(RootTask.NestedTask.id, "RootTask.NestedTask") | ||
assert.equal( | ||
RootTask.NestedTask.description, | ||
'The root task with a nested task' | ||
"The root task with a nested task" | ||
) | ||
const nestedAction = RootTask('root-value').NestedTask('nested-value') | ||
assert.equal(nestedAction.id, 'RootTask.NestedTask') | ||
const nestedAction = RootTask("root-value").NestedTask("nested-value") | ||
assert.equal(nestedAction.id, "RootTask.NestedTask") | ||
assert.deepEqual(nestedAction.params, { | ||
rootArg: 'root-value', | ||
nestedArg: 'nested-value', | ||
rootArg: "root-value", | ||
nestedArg: "nested-value" | ||
}) | ||
}) | ||
it('deeply nests tasks', () => { | ||
const RootTask = Task('RootTask', 'The root task', ['rootArg'], Task => | ||
Task('NestedTask', 'with a nested task', ['nestedArg'], Task => | ||
Task('DeeplyNestedTask', 'with a deeply nested task', [ | ||
'deeplyNestedArg', | ||
it("deeply nests tasks", () => { | ||
const RootTask = Task("RootTask", "The root task", ["rootArg"], Task => | ||
Task("NestedTask", "with a nested task", ["nestedArg"], Task => | ||
Task("DeeplyNestedTask", "with a deeply nested task", [ | ||
"deeplyNestedArg" | ||
]) | ||
@@ -58,21 +65,21 @@ ) | ||
const deeplyNestedAction = RootTask('root-value') | ||
.NestedTask('nested-value') | ||
.DeeplyNestedTask('deeply-nested-value') | ||
const deeplyNestedAction = RootTask("root-value") | ||
.NestedTask("nested-value") | ||
.DeeplyNestedTask("deeply-nested-value") | ||
assert.equal( | ||
deeplyNestedAction.id, | ||
'RootTask.NestedTask.DeeplyNestedTask' | ||
"RootTask.NestedTask.DeeplyNestedTask" | ||
) | ||
assert.deepEqual(deeplyNestedAction.params, { | ||
rootArg: 'root-value', | ||
nestedArg: 'nested-value', | ||
deeplyNestedArg: 'deeply-nested-value', | ||
rootArg: "root-value", | ||
nestedArg: "nested-value", | ||
deeplyNestedArg: "deeply-nested-value" | ||
}) | ||
}) | ||
it('deeply nests tasks without calling the root task', () => { | ||
const RootTask = Task('RootTask', 'The root task', [], Task => | ||
Task('NestedTask', 'with a nested task', ['nestedArg'], Task => | ||
Task('DeeplyNestedTask', 'with a deeply nested task', [ | ||
'deeplyNestedArg', | ||
it("deeply nests tasks without calling the root task", () => { | ||
const RootTask = Task("RootTask", "The root task", [], Task => | ||
Task("NestedTask", "with a nested task", ["nestedArg"], Task => | ||
Task("DeeplyNestedTask", "with a deeply nested task", [ | ||
"deeplyNestedArg" | ||
]) | ||
@@ -83,32 +90,32 @@ ) | ||
const deeplyNestedAction = RootTask.NestedTask( | ||
'nested-value' | ||
).DeeplyNestedTask('deeply-nested-value') | ||
"nested-value" | ||
).DeeplyNestedTask("deeply-nested-value") | ||
assert.equal( | ||
deeplyNestedAction.id, | ||
'RootTask.NestedTask.DeeplyNestedTask' | ||
"RootTask.NestedTask.DeeplyNestedTask" | ||
) | ||
assert.deepEqual(deeplyNestedAction.params, { | ||
nestedArg: 'nested-value', | ||
deeplyNestedArg: 'deeply-nested-value', | ||
nestedArg: "nested-value", | ||
deeplyNestedArg: "deeply-nested-value" | ||
}) | ||
}) | ||
it('allows for sibling nested tasks', () => { | ||
const RootTask = Task('RootTask', 'The root task', [], Task => { | ||
Task('NestedTask', 'with a nested task', ['nestedArg']) | ||
Task('SiblingNestedTask', 'with a sibling nested task', [ | ||
'siblingNestedArg', | ||
it("allows for sibling nested tasks", () => { | ||
const RootTask = Task("RootTask", "The root task", [], Task => { | ||
Task("NestedTask", "with a nested task", ["nestedArg"]) | ||
Task("SiblingNestedTask", "with a sibling nested task", [ | ||
"siblingNestedArg" | ||
]) | ||
}) | ||
const nestedAction = RootTask.NestedTask('nested-value') | ||
assert.equal(nestedAction.id, 'RootTask.NestedTask') | ||
assert.deepEqual(nestedAction.params, { nestedArg: 'nested-value' }) | ||
const nestedAction = RootTask.NestedTask("nested-value") | ||
assert.equal(nestedAction.id, "RootTask.NestedTask") | ||
assert.deepEqual(nestedAction.params, { nestedArg: "nested-value" }) | ||
const siblingNestedAction = RootTask.SiblingNestedTask( | ||
'sibling-nested-value' | ||
"sibling-nested-value" | ||
) | ||
assert.equal(siblingNestedAction.id, 'RootTask.SiblingNestedTask') | ||
assert.equal(siblingNestedAction.id, "RootTask.SiblingNestedTask") | ||
assert.deepEqual(siblingNestedAction.params, { | ||
siblingNestedArg: 'sibling-nested-value', | ||
siblingNestedArg: "sibling-nested-value" | ||
}) | ||
@@ -118,12 +125,12 @@ }) | ||
context('handling tasks through perspectives', () => { | ||
it('attempts a task with no parameters', async () => { | ||
context("handling tasks through perspectives", () => { | ||
it("attempts a task with no parameters", async () => { | ||
const browser = { | ||
refresh: sinon.spy(), | ||
refresh: sinon.spy() | ||
} | ||
const abilities = { browser } | ||
const Refresh = Task('Refresh', 'Refresh', [], Task => | ||
Task('browser', 'the browser', []) | ||
const Refresh = Task("Refresh", "Refresh", [], Task => | ||
Task("browser", "the browser", []) | ||
) | ||
const perspective = Perspective('web browser', handle => { | ||
const perspective = Perspective("web browser", handle => { | ||
handle(Refresh.browser, () => ({ browser }) => { | ||
@@ -133,3 +140,3 @@ browser.refresh() | ||
}) | ||
const joe = Actor(perspective, abilities) | ||
const joe = Actor(abilities, perspective) | ||
await joe.attemptsTo(Refresh.browser) | ||
@@ -139,12 +146,12 @@ sinon.assert.called(browser.refresh) | ||
it('attempts a task with a single parameter', async () => { | ||
it("attempts a task with a single parameter", async () => { | ||
const browser = { | ||
clickOn: sinon.spy(), | ||
clickOn: sinon.spy() | ||
} | ||
const abilities = { browser } | ||
const ClickOn = Task('ClickOn', 'Click on', [], Task => | ||
Task('button', 'button with $text', ['text']) | ||
const ClickOn = Task("ClickOn", "Click on", [], Task => | ||
Task("button", "button with $text", ["text"]) | ||
) | ||
const perspective = Perspective('web browser', handle => { | ||
const perspective = Perspective("web browser", handle => { | ||
handle(ClickOn.button, ({ text }) => ({ browser }) => | ||
@@ -154,18 +161,18 @@ browser.clickOn(text) | ||
}) | ||
const joe = Actor(perspective, abilities) | ||
await joe.attemptsTo(ClickOn.button('Book now')) | ||
sinon.assert.calledWith(browser.clickOn, 'Book now') | ||
const joe = Actor(abilities, perspective) | ||
await joe.attemptsTo(ClickOn.button("Book now")) | ||
sinon.assert.calledWith(browser.clickOn, "Book now") | ||
}) | ||
it('attempts a nested task', async () => { | ||
it("attempts a nested task", async () => { | ||
const browser = { | ||
fillIn: sinon.spy(), | ||
fillIn: sinon.spy() | ||
} | ||
const abilities = { browser } | ||
const FillIn = Task('FillIn', 'Fill in', [], Task => | ||
Task('label', 'label $name', ['name'], Task => | ||
Task('with', 'with $text', ['text']) | ||
const FillIn = Task("FillIn", "Fill in", [], Task => | ||
Task("label", "label $name", ["name"], Task => | ||
Task("with", "with $text", ["text"]) | ||
) | ||
) | ||
const perspective = Perspective('web browser', handle => { | ||
const perspective = Perspective("web browser", handle => { | ||
handle(FillIn.label.with, ({ name, text }) => ({ browser }) => | ||
@@ -175,22 +182,19 @@ browser.fillIn(name, text) | ||
}) | ||
const joe = Actor(perspective, abilities) | ||
await joe.attemptsTo(FillIn.label('email').with('joe@example.com')) | ||
sinon.assert.calledWith(browser.fillIn, 'email', 'joe@example.com') | ||
const joe = Actor(abilities, perspective) | ||
await joe.attemptsTo(FillIn.label("email").with("joe@example.com")) | ||
sinon.assert.calledWith(browser.fillIn, "email", "joe@example.com") | ||
}) | ||
}) | ||
context('with multiple perspectives', () => { | ||
const Book = Task('Book', 'Book', [], Task => { | ||
Task('aHoliday', 'a holiday to $destination', ['destination']) | ||
Task('aRoom', 'a room', []) | ||
Task('aFlight', 'a flight to $destination', ['destination']) | ||
}) | ||
context("with multiple perspectives", () => { | ||
const Book = { | ||
aHoliday: destination => ({ actor }) => | ||
actor.attemptsTo(Book.aRoom, Book.aFlight(destination)), | ||
aRoom: Task("aRoom", "a room", []), | ||
aFlight: Task("aFlight", "a flight to $destination", ["destination"]) | ||
} | ||
const handleBookAHoliday = ({ destination }) => ({ actor }) => | ||
actor.attemptsTo(Book.aRoom, Book.aFlight(destination)) | ||
const domainPerspective = Perspective('domain', handle => { | ||
handle(Book.aHoliday, handleBookAHoliday) | ||
const domainPerspective = Perspective("domain", handle => { | ||
handle(Book.aRoom, () => ({ state, domain }) => | ||
domain.bookRoom({ email: state.get('email') }) | ||
domain.bookRoom({ email: state.get("email") }) | ||
) | ||
@@ -202,17 +206,15 @@ handle(Book.aFlight, ({ destination }) => ({ domain }) => | ||
const webAppPerspective = Perspective('web browser', handle => { | ||
const webAppPerspective = Perspective("web browser", handle => { | ||
const FillIn = { | ||
field: ({ name }) => ({ | ||
with: text => ({ browser }) => browser.fillIn(name, text), | ||
}), | ||
with: text => ({ browser }) => browser.fillIn(name, text) | ||
}) | ||
} | ||
const Click = { | ||
on: text => ({ browser }) => browser.clickOn(text), | ||
on: text => ({ browser }) => browser.clickOn(text) | ||
} | ||
handle(Book.aHoliday, handleBookAHoliday) | ||
handle(Book.aRoom, () => ({ actor, state }) => | ||
actor.attemptsTo( | ||
FillIn.field({ name: 'Email' }).with(state.get('email')), | ||
Click.on('Book Room') | ||
FillIn.field({ name: "Email" }).with(state.get("email")), | ||
Click.on("Book Room") | ||
) | ||
@@ -222,39 +224,39 @@ ) | ||
it('allows actors to attempt the same task from different perspectives', async () => { | ||
it("allows actors to attempt the same task from different perspectives", async () => { | ||
const domain = { | ||
bookRoom: sinon.spy(), | ||
bookRoom: sinon.spy() | ||
} | ||
const browser = { | ||
clickOn: sinon.spy(), | ||
fillIn: sinon.spy(), | ||
fillIn: sinon.spy() | ||
} | ||
const state = new Map([['email', 'joe@example.com']]) | ||
const domainJoe = Actor(domainPerspective, { domain, browser, state }) | ||
const state = new Map([["email", "joe@example.com"]]) | ||
const domainJoe = Actor({ domain, browser, state }, domainPerspective) | ||
const webAppJoe = domainJoe.through(webAppPerspective) | ||
await domainJoe.attemptsTo(Book.aRoom) | ||
await webAppJoe.attemptsTo(Book.aRoom) | ||
sinon.assert.calledWith(domain.bookRoom, { email: 'joe@example.com' }) | ||
sinon.assert.calledWith(browser.fillIn, 'Email', 'joe@example.com') | ||
sinon.assert.calledWith(browser.clickOn, 'Book Room') | ||
sinon.assert.calledWith(domain.bookRoom, { email: "joe@example.com" }) | ||
sinon.assert.calledWith(browser.fillIn, "Email", "joe@example.com") | ||
sinon.assert.calledWith(browser.clickOn, "Book Room") | ||
}) | ||
it('runs higher order tasks', async () => { | ||
it("runs higher order tasks", async () => { | ||
const domain = { | ||
bookRoom: sinon.spy(), | ||
bookFlight: sinon.spy(), | ||
bookFlight: sinon.spy() | ||
} | ||
const state = new Map([['email', 'joe@example.com']]) | ||
const joe = Actor(domainPerspective, { domain, state }) | ||
await joe.attemptsTo(Book.aHoliday('Barbados')) | ||
sinon.assert.calledWith(domain.bookFlight, 'Barbados') | ||
sinon.assert.calledWith(domain.bookRoom, { email: 'joe@example.com' }) | ||
const state = new Map([["email", "joe@example.com"]]) | ||
const joe = Actor({ domain, state }, domainPerspective) | ||
await joe.attemptsTo(Book.aHoliday("Barbados")) | ||
sinon.assert.calledWith(domain.bookFlight, "Barbados") | ||
sinon.assert.calledWith(domain.bookRoom, { email: "joe@example.com" }) | ||
}) | ||
}) | ||
it('waits for async tasks to complete', async () => { | ||
it("waits for async tasks to complete", async () => { | ||
const saveSomething = Task() | ||
const db = { | ||
insert: sinon.spy(), | ||
insert: sinon.spy() | ||
} | ||
const perspective = Perspective('test', handle => { | ||
const perspective = Perspective("test", handle => { | ||
handle(saveSomething, () => ({ db }) => | ||
@@ -269,3 +271,3 @@ new Promise(resolve => | ||
}) | ||
const joe = Actor(perspective, { db }) | ||
const joe = Actor({ db }, perspective) | ||
await joe.attemptsTo(saveSomething) | ||
@@ -275,14 +277,16 @@ sinon.assert.called(db.insert) | ||
it('allows the actor to gain new abilities', async () => { | ||
it("allows the actor to gain new abilities", async () => { | ||
const db = { | ||
insert: sinon.spy(), | ||
insert: sinon.spy() | ||
} | ||
const joe = Actor(Perspective(), {}) | ||
const joe = Actor({}) | ||
joe.gainsAbilities({ db }) | ||
await joe.attemptsTo(({ db }) => { db.insert() }) | ||
await joe.attemptsTo(({ db }) => { | ||
db.insert() | ||
}) | ||
sinon.assert.called(db.insert) | ||
}) | ||
it('returns the actor when you attempt a task', async () => { | ||
const joe = Actor(Perspective(), {}) | ||
it("returns the actor when you attempt a task", async () => { | ||
const joe = Actor({}) | ||
const result = await joe.attemptsTo(() => {}) | ||
@@ -292,5 +296,5 @@ assert.equal(result, joe) | ||
it('waits for async interactions to complete', async () => { | ||
it("waits for async interactions to complete", async () => { | ||
const db = { | ||
insert: sinon.spy(), | ||
insert: sinon.spy() | ||
} | ||
@@ -304,3 +308,3 @@ const saveSomething = ({ db }) => | ||
) | ||
const joe = Actor(Perspective(), { db }) | ||
const joe = Actor({ db }) | ||
await joe.attemptsTo(saveSomething) | ||
@@ -311,5 +315,5 @@ sinon.assert.called(db.insert) | ||
it("gives a decent error when you attempt to do an action that doesn't have a corresponding handler", async () => { | ||
const doSomething = Task('DoSomething') | ||
const perspective = Perspective('Perspective') | ||
const joe = Actor(perspective, {}) | ||
const doSomething = Task("DoSomething") | ||
const perspective = Perspective("Perspective") | ||
const joe = Actor({}, perspective) | ||
let error | ||
@@ -327,18 +331,18 @@ try { | ||
describe('Memory', () => { | ||
it('allows an actor to remember state', async () => { | ||
const joe = Actor(Perspective(), { ...Memory() }) | ||
await joe.attemptsTo(Remember.that('thing').is('something')) | ||
assert.equal(await joe.asks(Recall.about('thing')), 'something') | ||
describe("Memory", () => { | ||
it("allows an actor to remember state", async () => { | ||
const joe = Actor({...Memory() }) | ||
await joe.attemptsTo(Remember.that("thing").is("something")) | ||
assert.equal(await joe.asks(Recall.about("thing")), "something") | ||
}) | ||
it("throws when asked for something it can't remember", async () => { | ||
const joe = Actor(Perspective(), { ...Memory() }) | ||
const joe = Actor({ ...Memory() }) | ||
let err | ||
try { | ||
await joe.asks(Recall.about('something unknown')) | ||
await joe.asks(Recall.about("something unknown")) | ||
} catch (e) { | ||
err = e | ||
} | ||
assert(err, 'Expected it to throw') | ||
assert(err, "Expected it to throw") | ||
assert( | ||
@@ -345,0 +349,0 @@ err.message.match(/something unknown/), |
{ | ||
"name": "feynman", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"description": "A screenplay pattern library for javascript", | ||
@@ -5,0 +5,0 @@ "main": "lib/feynman.js", |
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
32300130
441