Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solutions for Sherlock tutorial #56

Draft
wants to merge 1 commit into
base: tutorial-base
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions tutorial/1 - intro.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('intro', () => {
* This can also be indicated with the `__YOUR_TURN__` variable.
*
* It should be clear what to do here... */
bool = __YOUR_TURN__;
bool = true;
expect(bool).toBeTrue();
// We use expectations like this to verify the result.
});
Expand All @@ -55,7 +55,7 @@ describe('intro', () => {
* ** Your Turn **
* Remove the `.skip` so this part of the tutorial will run.
*/
describe.skip('the basics', () => {
describe('the basics', () => {
/**
* The `Atom` is the basic building block of `@skunkteam/sherlock`.
* It holds a value which you can `get()` and `set()`.
Expand All @@ -73,6 +73,7 @@ describe.skip('the basics', () => {

// ** Your Turn **
// Use the `.set(<newValue>)` method to change the value of the `Atom`.
myValue$.set(2);
expect(myValue$.get()).toEqual(2);
});

Expand All @@ -97,7 +98,7 @@ describe.skip('the basics', () => {
* negative to a positive number and vice versa) of the original `Atom`.
*/
// Use `myValue$.derive(val => ...)` to implement `myInverse$`.
const myInverse$ = myValue$.derive(__YOUR_TURN__ => __YOUR_TURN__);
const myInverse$ = myValue$.derive(val => -val);
expect(myInverse$.get()).toEqual(-1);
// So if we set `myValue$` to -2:
myValue$.set(-2);
Expand All @@ -122,7 +123,7 @@ describe.skip('the basics', () => {
*
* Now react to `myCounter$`. In every `react()`.
* Increase the `reacted` variable by one. */
myCounter$.react(() => __YOUR_TURN__);
myCounter$.react(() => reacted++);
expect(reacted).toEqual(1);
// `react()` will react immediately, more on that later.

Expand Down
34 changes: 20 additions & 14 deletions tutorial/2 - deriving.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe.skip('deriving', () => {
*/

// We can combine txt with `repeat$.get()` here.
const lyric$ = text$.derive(txt => txt /* __YOUR_TURN__ */);
const lyric$ = text$.derive(txt => txt.repeat(repeat$.get()));

expect(lyric$.get()).toEqual(`It won't be long`);

Expand Down Expand Up @@ -74,12 +74,18 @@ describe.skip('deriving', () => {
*/

// Should return 'Fizz' when `myCounter$` is a multiple of 3 and '' otherwise.
const fizz$: Derivable<string> = myCounter$.derive(__YOUR_TURN__);
const fizz$: Derivable<string> = myCounter$.derive(value => {
return value % 3 ? '' : 'Fizz';
});

// Should return 'Buzz' when `myCounter$` is a multiple of 5 and '' otherwise.
const buzz$: Derivable<string> = myCounter$.derive(__YOUR_TURN__);
const buzz$: Derivable<string> = myCounter$.derive(value => {
return value % 5 ? '' : 'Buzz';
});

const fizzBuzz$: Derivable<string | number> = derive(__YOUR_TURN__);
const fizzBuzz$: Derivable<string | number> = derive(() => {
return fizz$.get() + buzz$.get() || myCounter$.get();
});

expect(fizz$.get()).toEqual('');
expect(buzz$.get()).toEqual('');
Expand Down Expand Up @@ -153,9 +159,9 @@ describe.skip('deriving', () => {
const tweetCount = pastTweets.length;
const lastTweet = pastTweets[tweetCount - 1];

expect(tweetCount).toEqual(__YOUR_TURN__); // Is there a new tweet?
expect(lastTweet).toContain(__YOUR_TURN__); // Who sent it? Donald? Or Barack?
expect(lastTweet).toContain(__YOUR_TURN__); // What did he tweet?
expect(tweetCount).toEqual(3); // Is there a new tweet?
expect(lastTweet).toContain('Donald'); // Who sent it? Donald? Or Barack?
expect(lastTweet).toContain('politics'); // What did he tweet?

/**
* As you can see, this is something to look out for.
Expand Down Expand Up @@ -200,17 +206,17 @@ describe.skip('deriving', () => {
*/
const fizz$ = myCounter$
.derive(count => count % 3)
.is(__YOUR_TURN__)
.and(__YOUR_TURN__)
.or(__YOUR_TURN__) as Derivable<string>;
.is(0)
.and('Fizz')
.or('') as Derivable<string>;

const buzz$ = myCounter$
.derive(count => count % 5)
.is(__YOUR_TURN__)
.and(__YOUR_TURN__)
.or(__YOUR_TURN__) as Derivable<string>;
.is(0)
.and('Buzz')
.or('') as Derivable<string>;

const fizzBuzz$ = derive(() => fizz$.get() + buzz$.get()).or(__YOUR_TURN__);
const fizzBuzz$ = derive(() => fizz$.get() + buzz$.get()).or(myCounter$);

for (let count = 1; count <= 100; count++) {
// Set the value of the `Atom`,
Expand Down
41 changes: 27 additions & 14 deletions tutorial/3 - reacting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ describe.skip('reacting', () => {
* Time to react to `myAtom$` with the `reactor()` function defined
* above.
*/

myAtom$.react(reactor);
expectReact(1, 'initial value');

// Now set a 'new value' to `myAtom$`.

myAtom$.set('new value');
expectReact(2, 'new value');
});

Expand All @@ -99,7 +99,7 @@ describe.skip('reacting', () => {
*
* catch the returned `stopper` in a variable
*/
myAtom$.react(reactor);
let stopper = myAtom$.react(reactor);

expectReact(1, 'initial value');

Expand All @@ -108,7 +108,7 @@ describe.skip('reacting', () => {
*
* Call the `stopper`.
*/

stopper();
myAtom$.set('new value');

// And the reaction stopped.
Expand All @@ -130,9 +130,9 @@ describe.skip('reacting', () => {
* In the reaction below, use the stopper callback to stop the
* reaction
*/
myAtom$.react((val, __YOUR_TURN___) => {
myAtom$.react((val, stop) => {
reactor(val);
__YOUR_TURN___;
stop();
});

expectReact(1, 'initial value');
Expand Down Expand Up @@ -185,7 +185,7 @@ describe.skip('reacting', () => {
*
* Try giving `boolean$` as `until` option.
*/
string$.react(reactor, __YOUR_TURN__);
string$.react(reactor, { until: boolean$ });

// It should react directly as usual.
expectReact(1, 'Value');
Expand Down Expand Up @@ -233,7 +233,13 @@ describe.skip('reacting', () => {
* Use `!string$.get()` to return `true` when the `string` is
* empty.
*/
string$.react(reactor, __YOUR_TURN__);
let stringEmpty = function () {
return !string$.get();
};

string$.react(reactor, {
until: stringEmpty,
});

// It should react as usual:
string$.set('New value');
Expand Down Expand Up @@ -261,7 +267,7 @@ describe.skip('reacting', () => {
* Try using the first parameter of the `until` function to do
* the same as above.
*/
string$.react(reactor, __YOUR_TURN__);
string$.react(reactor, { until: parent$ => !parent$.get() });

// It should react as usual.
string$.set('New value');
Expand Down Expand Up @@ -305,7 +311,7 @@ describe.skip('reacting', () => {
*
* *Hint: remember the `.is()` method from tutorial 2?*
*/
sherlock$.react(reactor, __YOUR_TURN__);
sherlock$.react(reactor, { from: parent$ => parent$.is('dear') });

expectReact(0);
['Elementary,', 'my', 'dear', 'Watson'].forEach(txt => sherlock$.set(txt));
Expand Down Expand Up @@ -334,7 +340,7 @@ describe.skip('reacting', () => {
* Now, let's react to all even numbers.
* Except 4, we don't want to make it too easy now.
*/
count$.react(reactor, __YOUR_TURN__);
count$.react(reactor, { when: parent$ => parent$.derive(value => value % 2 == 0 && value != 4) });

expectReact(1, 0);

Expand All @@ -361,7 +367,7 @@ describe.skip('reacting', () => {
*
* Say you want to react when `done$` is true. But not right away..
*/
done$.react(reactor, __YOUR_TURN__);
done$.react(reactor, { skipFirst: true });
expectReact(0);

done$.set(true);
Expand All @@ -387,7 +393,10 @@ describe.skip('reacting', () => {
*
* *Hint: you will need to combine `once` with another option*
*/
finished$.react(reactor, __YOUR_TURN__);
finished$.react(reactor, {
once: true,
skipFirst: true,
});
expectReact(0);

// When finished it should react once.
Expand All @@ -414,7 +423,11 @@ describe.skip('reacting', () => {
* `connected$` indicates the current connection status.
* This should be possible with three simple ReactorOptions
*/
connected$.react(reactor, __YOUR_TURN__);
connected$.react(reactor, {
skipFirst: true,
once: true,
from: parent$ => parent$,
});

// It starts as 'not connected'
expectReact(0);
Expand Down
50 changes: 25 additions & 25 deletions tutorial/4 - inner workings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const __YOUR_TURN__ = {} as any;
/**
* Time to dive a bit deeper into the inner workings of `@skunkteam/sherlock`.
*/
describe.skip('inner workings', () => {
describe('inner workings', () => {
/**
* What if there is a derivation that reads from one of two `Derivable`s
* dynamically? Will both of those `Derivable`s be tracked for changes?
Expand Down Expand Up @@ -43,8 +43,8 @@ describe.skip('inner workings', () => {
*
* What do you expect?
*/
expect(reacted).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(reacted).toHaveBeenLastCalledWith(__YOUR_TURN__, expect.toBeFunction());
expect(reacted).toHaveBeenCalledTimes(1);
expect(reacted).toHaveBeenLastCalledWith(1, expect.toBeFunction());

// `switch$` is still set to true (number)
number$.set(2);
Expand All @@ -54,8 +54,8 @@ describe.skip('inner workings', () => {
*
* What do you expect?
*/
expect(reacted).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(reacted).toHaveBeenLastCalledWith(__YOUR_TURN__, expect.toBeFunction());
expect(reacted).toHaveBeenCalledTimes(2);
expect(reacted).toHaveBeenLastCalledWith(2, expect.toBeFunction());

// Now let's reset the mock function, so the call count should
// be 0 again.
Expand All @@ -71,8 +71,8 @@ describe.skip('inner workings', () => {
*
* What do you expect now?
*/
expect(reacted).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(reacted).toHaveBeenLastCalledWith(__YOUR_TURN__, expect.toBeFunction());
expect(reacted).toHaveBeenCalledTimes(1);
expect(reacted).toHaveBeenLastCalledWith('two', expect.toBeFunction());
});

/**
Expand All @@ -98,17 +98,17 @@ describe.skip('inner workings', () => {
*/

// Well, what do you expect?
expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(0);

myDerivation$.get();

// And after a `.get()`?
expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(1);

myDerivation$.get();

// And after the second `.get()`? Is there an extra call?
expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(2);

/**
* The state of any `Derivable` can change at any moment.
Expand Down Expand Up @@ -147,27 +147,27 @@ describe.skip('inner workings', () => {
*
* Ok, it's your turn to complete the expectations.
*/
expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(1);

myDerivation$.get();

expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(1);

myAtom$.set(false);

expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(2);

myDerivation$.get();

expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(2);

stopper();

expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(2);

myDerivation$.get();

expect(hasDerived).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasDerived).toHaveBeenCalledTimes(3);

/**
* Since the `.react()` already listens to the value(changes) there is
Expand Down Expand Up @@ -212,23 +212,23 @@ describe.skip('inner workings', () => {
// Note that this is the same value as it was initialized with
myAtom$.set(1);

expect(first).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(second).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(first).toHaveBeenCalledTimes(1);
expect(second).toHaveBeenCalledTimes(1);

myAtom$.set(2);

expect(first).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(second).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(first).toHaveBeenCalledTimes(2);
expect(second).toHaveBeenCalledTimes(1);

myAtom$.set(3);

expect(first).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(second).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(first).toHaveBeenCalledTimes(3);
expect(second).toHaveBeenCalledTimes(2);

myAtom$.set(4);

expect(first).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(second).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(first).toHaveBeenCalledTimes(4);
expect(second).toHaveBeenCalledTimes(2);

/**
* Can you explain the behavior above?
Expand Down Expand Up @@ -265,7 +265,7 @@ describe.skip('inner workings', () => {
* The `Atom` is set with exactly the same object as before. Will the
* `.react()` fire?
*/
expect(hasReacted).toHaveBeenCalledTimes(__YOUR_TURN__);
expect(hasReacted).toHaveBeenCalledTimes(1);

/**
* But what if you use an object, that can be easily compared through a
Expand Down
Loading