1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Refactor to using injectable for dependency injection

Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
Iku-turso 2023-03-14 15:00:04 +02:00
parent 257d8a15cb
commit 62cd2957cc
10 changed files with 167 additions and 111 deletions

View File

@ -0,0 +1,9 @@
import { getInjectable } from "@ogre-tools/injectable";
const castDieInjectable = getInjectable({
id: "cast-die",
instantiate: () => () => Promise.resolve(0),
causesSideEffects: true,
});
export default castDieInjectable;

View File

@ -1,19 +1,19 @@
import type { Monster } from "./handle-landed-hit-on-monster-for"; import { getInjectable } from "@ogre-tools/injectable";
import type { Dependencies } from "./monster-beatdown"; import messageToPlayerInjectable from "./message-to-player";
import castDieInjectable from "./cast-die";
import monsterInjectable from "./monster";
import handleLandedHitOnMonsterInjectable from "./handle-landed-hit-on-monster-for";
export const handleAttackOnMonsterFor = const handleAttackOnMonsterInjectable = getInjectable({
({ id: "handle-attack-on-monster",
monster,
messageToPlayer, instantiate: (di) => {
handleLandedHitOnMonster, const messageToPlayer = di.inject(messageToPlayerInjectable);
castDie, const castDie = di.inject(castDieInjectable);
}: { const handleLandedHitOnMonster = di.inject(handleLandedHitOnMonsterInjectable);
monster: Monster; const monster = di.inject(monsterInjectable);
messageToPlayer: Dependencies["messageToPlayer"];
handleLandedHitOnMonster: () => { monsterIsDead: boolean }; return async () => {
castDie: () => Promise<number>;
}) =>
async () => {
messageToPlayer("You attack the monster."); messageToPlayer("You attack the monster.");
const dieResult = await castDie(); const dieResult = await castDie();
@ -32,3 +32,7 @@ export const handleAttackOnMonsterFor =
return { gameIsOver: false }; return { gameIsOver: false };
}; };
},
});
export default handleAttackOnMonsterInjectable;

View File

@ -1,25 +1,30 @@
import type { Dependencies } from "./monster-beatdown"; import { getInjectable } from "@ogre-tools/injectable";
import questionToPlayerInjectable from "./question-to-player";
import messageToPlayerInjectable from "./message-to-player";
export const handleAttackingTheMonsterAgainFor = const handleAttackingTheMonsterAgainInjectable = getInjectable({
({ id: "handle-attacking-the-monster-again",
messageToPlayer,
questionToPlayer,
}: {
messageToPlayer: Dependencies["messageToPlayer"];
questionToPlayer: Dependencies["questionToPlayer"];
}) =>
async () => {
const playerWantsToAttackAgain = await questionToPlayer("Do you want to attack again?");
if (playerWantsToAttackAgain) { instantiate: (di) => {
return { gameIsOver: false }; const questionToPlayer = di.inject(questionToPlayerInjectable);
} const messageToPlayer = di.inject(messageToPlayerInjectable);
messageToPlayer( return async () => {
"You lose your nerve mid-beat-down, and try to run away. You get eaten by a sad, disappointed monster.", const playerWantsToAttackAgain = await questionToPlayer("Do you want to attack again?");
);
messageToPlayer("You lose. Game over!"); if (playerWantsToAttackAgain) {
return { gameIsOver: false };
}
return { gameIsOver: true }; messageToPlayer(
}; "You lose your nerve mid-beat-down, and try to run away. You get eaten by a sad, disappointed monster.",
);
messageToPlayer("You lose. Game over!");
return { gameIsOver: true };
};
},
});
export default handleAttackingTheMonsterAgainInjectable;

View File

@ -1,17 +1,17 @@
import type { Monster } from "./handle-landed-hit-on-monster-for"; import { getInjectable } from "@ogre-tools/injectable";
import type { Dependencies } from "./monster-beatdown"; import messageToPlayerInjectable from "./message-to-player";
import questionToPlayerInjectable from "./question-to-player";
import monsterInjectable from "./monster";
export const handleInitialMonsterEncounterFor = const handleInitialMonsterEncounterInjectable = getInjectable({
({ id: "handle-initial-monster-encounter",
monster,
messageToPlayer, instantiate: (di) => {
questionToPlayer, const messageToPlayer = di.inject(messageToPlayerInjectable);
}: { const questionToPlayer = di.inject(questionToPlayerInjectable);
monster: Monster; const monster = di.inject(monsterInjectable);
messageToPlayer: Dependencies["messageToPlayer"];
questionToPlayer: Dependencies["questionToPlayer"]; return async () => {
}) =>
async () => {
messageToPlayer(`You encounter a monster with ${monster.hitPoints} hit-points`); messageToPlayer(`You encounter a monster with ${monster.hitPoints} hit-points`);
const playerWantsToAttack = await questionToPlayer("Attack the monster?"); const playerWantsToAttack = await questionToPlayer("Attack the monster?");
@ -27,3 +27,7 @@ export const handleInitialMonsterEncounterFor =
return { gameIsOver: true }; return { gameIsOver: true };
}; };
},
});
export default handleInitialMonsterEncounterInjectable;

View File

@ -1,18 +1,15 @@
import type { Dependencies } from "./monster-beatdown"; import { getInjectable } from "@ogre-tools/injectable";
import monsterInjectable from "./monster";
import messageToPlayerInjectable from "./message-to-player";
export type Monster = { const handleLandedHitOnMonsterInjectable = getInjectable({
hitPoints: number; id: "handle-landed-hit-on-monster",
};
export const handleLandedHitOnMonsterFor = instantiate: (di) => {
({ const monster = di.inject(monsterInjectable);
monster, const messageToPlayer = di.inject(messageToPlayerInjectable);
messageToPlayer,
}: { return () => {
monster: Monster;
messageToPlayer: Dependencies["messageToPlayer"];
}) =>
() => {
monster.hitPoints--; monster.hitPoints--;
if (monster.hitPoints) { if (monster.hitPoints) {
@ -31,3 +28,7 @@ export const handleLandedHitOnMonsterFor =
return { monsterIsDead: true }; return { monsterIsDead: true };
}; };
},
});
export default handleLandedHitOnMonsterInjectable;

View File

@ -0,0 +1,9 @@
import { getInjectable } from "@ogre-tools/injectable";
const messageToPlayerInjectable = getInjectable({
id: "message-to-player",
instantiate: () => (message: string) => {},
causesSideEffects: true,
});
export default messageToPlayerInjectable;

View File

@ -1,6 +1,15 @@
import { createGame, Dependencies } from "./monster-beatdown"; import { Dependencies, gameInjectable } from "./monster-beatdown";
import asyncFn, { AsyncFnMock } from "@async-fn/jest"; import asyncFn, { AsyncFnMock } from "@async-fn/jest";
import { getPromiseStatus } from "@k8slens/test-utils"; import { getPromiseStatus } from "@k8slens/test-utils";
import { createContainer } from "@ogre-tools/injectable";
import messageToPlayerInjectable from "./message-to-player";
import castDieInjectable from "./cast-die";
import questionToPlayerInjectable from "./question-to-player";
import handleInitialMonsterEncounterInjectable from "./handle-initial-monster-encounter-for";
import monsterInjectable from "./monster";
import handleAttackOnMonsterInjectable from "./handle-attack-on-monster-for";
import handleLandedHitOnMonsterInjectable from "./handle-landed-hit-on-monster-for";
import handleAttackingTheMonsterAgainInjectable from "./handle-attacking-the-monster-again-for";
describe("monster-beatdown", () => { describe("monster-beatdown", () => {
let game: { start: () => Promise<void> }; let game: { start: () => Promise<void> };
@ -10,15 +19,29 @@ describe("monster-beatdown", () => {
let gamePromise: Promise<void>; let gamePromise: Promise<void>;
beforeEach(() => { beforeEach(() => {
const di = createContainer("monster-beatdown");
di.register(
castDieInjectable,
gameInjectable,
handleAttackOnMonsterInjectable,
handleAttackingTheMonsterAgainInjectable,
handleInitialMonsterEncounterInjectable,
handleLandedHitOnMonsterInjectable,
messageToPlayerInjectable,
monsterInjectable,
questionToPlayerInjectable,
);
messageToPlayerMock = jest.fn(); messageToPlayerMock = jest.fn();
di.override(messageToPlayerInjectable, () => messageToPlayerMock);
di.override(questionToPlayerInjectable, () => questionToPlayerMock);
di.override(castDieInjectable, () => castDieMock);
questionToPlayerMock = asyncFn(); questionToPlayerMock = asyncFn();
castDieMock = asyncFn(); castDieMock = asyncFn();
game = createGame({ game = di.inject(gameInjectable);
messageToPlayer: messageToPlayerMock,
questionToPlayer: questionToPlayerMock,
castDie: castDieMock,
});
}); });
describe("when game is not started", () => { describe("when game is not started", () => {

View File

@ -1,7 +1,7 @@
import { handleLandedHitOnMonsterFor, Monster } from "./handle-landed-hit-on-monster-for"; import { getInjectable } from "@ogre-tools/injectable";
import { handleInitialMonsterEncounterFor } from "./handle-initial-monster-encounter-for"; import handleInitialMonsterEncounterInjectable from "./handle-initial-monster-encounter-for";
import { handleAttackOnMonsterFor } from "./handle-attack-on-monster-for"; import handleAttackOnMonsterInjectable from "./handle-attack-on-monster-for";
import { handleAttackingTheMonsterAgainFor } from "./handle-attacking-the-monster-again-for"; import handleAttackingTheMonsterAgainInjectable from "./handle-attacking-the-monster-again-for";
export type Dependencies = { export type Dependencies = {
messageToPlayer: (message: string) => void; messageToPlayer: (message: string) => void;
@ -9,49 +9,33 @@ export type Dependencies = {
castDie: () => Promise<number>; castDie: () => Promise<number>;
}; };
const createGame = ({ messageToPlayer, questionToPlayer, castDie }: Dependencies) => { export const gameInjectable = getInjectable({
const monster: Monster = { hitPoints: 3 }; id: "game",
const handleLandedHitOnMonster = handleLandedHitOnMonsterFor({ messageToPlayer, monster }); instantiate: (di) => {
const handleInitialMonsterEncounter = di.inject(handleInitialMonsterEncounterInjectable);
const handleAttackOnMonster = di.inject(handleAttackOnMonsterInjectable);
const handleAttackingTheMonsterAgain = di.inject(handleAttackingTheMonsterAgainInjectable);
const handleAttackOnMonster = handleAttackOnMonsterFor({ return {
monster, start: async () => {
messageToPlayer, const initialEncounterResult = await handleInitialMonsterEncounter();
handleLandedHitOnMonster, if (initialEncounterResult.gameIsOver) {
castDie,
});
const handleAttackingTheMonsterAgain = handleAttackingTheMonsterAgainFor({
messageToPlayer,
questionToPlayer,
});
const handleInitialMonsterEncounter = handleInitialMonsterEncounterFor({
messageToPlayer,
questionToPlayer,
monster,
});
return {
start: async () => {
const initialEncounterResult = await handleInitialMonsterEncounter();
if (initialEncounterResult.gameIsOver) {
return;
}
while (true) {
const attackResult = await handleAttackOnMonster();
if (attackResult.gameIsOver) {
return; return;
} }
const attackAgainResult = await handleAttackingTheMonsterAgain(); while (true) {
if (attackAgainResult.gameIsOver) { const attackResult = await handleAttackOnMonster();
return; if (attackResult.gameIsOver) {
} return;
} }
},
};
};
export { createGame }; const attackAgainResult = await handleAttackingTheMonsterAgain();
if (attackAgainResult.gameIsOver) {
return;
}
}
},
};
},
});

View File

@ -0,0 +1,8 @@
import { getInjectable } from "@ogre-tools/injectable";
const monsterInjectable = getInjectable({
id: "monster",
instantiate: () => ({ hitPoints: 3 }),
});
export default monsterInjectable;

View File

@ -0,0 +1,9 @@
import { getInjectable } from "@ogre-tools/injectable";
const questionToPlayerInjectable = getInjectable({
id: "question-to-player",
instantiate: () => (question: string) => Promise.resolve(true),
causesSideEffects: true,
});
export default questionToPlayerInjectable;