-
-
Notifications
You must be signed in to change notification settings - Fork 0
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
New framework #7
Conversation
ChangeLogUseCaseInvoke pattern - context.execute(CompleteLoadingDocumentFactory.create(totalPageNumber));
+ context.useCase(CompleteLoadingDocumentFactory.create()).execute(totalPageNumber); |
UseCaseUseCase do following
A single file contain import documentRepository from "../infra/DocumentRepository";
import UseCase from "../framework/UseCase";
export class MarkClickedPageFactory {
static create() {
return new MarkClickedPageUseCase({
documentRepository
});
}
}
export class MarkClickedPageUseCase extends UseCase {
constructor({documentRepository}) {
super();
this.documentRepository = documentRepository;
}
execute(pageNumber) {
const document = this.documentRepository.lastUsed();
// mark page => (domain emit change)
document.markAtPage(pageNumber);
this.documentRepository.save(document);
}
} |
UseCase as TransactionUseCase invoke UseCase. import UseCase from "../framework/UseCase";
import TodoBackendServer from "../domain/TodoList/TodoBackendServer"
import todoListRepository, {TodoListRepository} from "../infra/TodoRepository"
import {AddTodoItemUseCase} from "./AddTodoItem";
import {UpdateTodoItemTitleUseCase} from "./UpdateTodoItemTitle";
import {RemoveTodoItemUseCase} from "./RemoveTodoItem";
export class TransactionTodoFactory {
static create() {
const todoBackendServer = new TodoBackendServer();
return new UpdateTodoItemTitleUseCase({
todoListRepository,
todoBackendServer
});
}
}
export class TransactionTodoUseCase extends UseCase {
/**
* @param {TodoListRepository} todoListRepository
* @param {TodoBackendServer} todoBackendServer
*/
constructor({todoListRepository, todoBackendServer}) {
super();
this.todoListRepository = todoListRepository;
this.todoBackendServer = todoBackendServer;
}
execute({title}) {
const options = {
todoListRepository: this.todoListRepository,
todoBackendServer: this.todoBackendServer
};
const addTodo = new AddTodoItemUseCase(options);
const updateTodoItem = new UpdateTodoItemTitleUseCase(options);
const removeTodoItem = new RemoveTodoItemUseCase(options);
const getLastItem = () => {
const todoList = this.todoListRepository.lastUsed();
return todoList.getAllTodoItems()[0];
};
// Add => Update => Remove
return Promise.resolve().then(() => {
return addTodo.execute({title});
}).then(() => {
const todoItem = getLastItem();
return updateTodoItem.execute({itemId: todoItem.id, title: "UPDATING TITLE"});
}).then(() => {
const todoItem = getLastItem();
return removeTodoItem.execute({itemId: todoItem.id});
});
}
} |
Repository
As a result, testing is simple. const assert = require("power-assert");
import {NewDocumentUseCase} from "../../src/js/UseCase/NewDocumentUseCase";
import Document from "../../src/js/domain/Document/Document";
import {DocumentRepository} from "../../src/js/infra/DocumentRepository";
describe("NewDocumentUseCase", function () {
context("when execute", function () {
it("should dispatch with document", function () {
const pdfURL = "test.pdf";
const documentRepository = new DocumentRepository();
documentRepository.onChange(() => {
const targetDocument = documentRepository.lastUsed();
assert(targetDocument instanceof Document);
});
const useCase = new NewDocumentUseCase({documentRepository});
return useCase.execute(pdfURL);
});
});
}); |
NewbieUseCase -> State testing
describe("ShowExportDialogUseCase", function () {
context("when execute", function () {
it("UseCase dispatch with output", function () {
// mock event emitter
const domainEventEmitter = new DomainEventEmitter();
DomainEventAggregator.setEventEmitterForTesting(domainEventEmitter);
const documentRepository = new DocumentRepository();
const document = new Document();
const expectedOutput = DocumentService.stringify(document);
documentRepository.save(document);
const useCase = new ShowExportDialogUseCase({documentRepository});
useCase.onDispatch((key, output) => {
assert(ShowExportDialogUseCase.name);
assert.equal(expectedOutput, output);
});
return useCase.execute();
});
it("State receive dispatched output", function (done) {
// Given
const domainEventEmitter = new DomainEventEmitter();
DomainEventAggregator.setEventEmitterForTesting(domainEventEmitter);
const documentRepository = new DocumentRepository();
const document = new Document();
const expectedOutput = DocumentService.stringify(document);
documentRepository.save(document);
// when
const store = new ExportStateStore({documentRepository});
const useCase = new ShowExportDialogUseCase({documentRepository});
eventDelegate(useCase, store);
store.onChange(() => {
const state = store.getState();
assert.strictEqual(state.exporting.output, expectedOutput);
done();
});
return useCase.execute();
});
});
}); |
UseCase
export default class ShowExportDialogUseCase extends UseCase{
constructor({documentRepository}) {
super();
/**
* @type {DocumentRepository}
*/
this.documentRepository = documentRepository;
}
execute() {
const document = this.documentRepository.lastUsed();
const output = DocumentService.stringify(document);
this.dispatch(ShowExportDialogUseCase.name, output);
}
} 💡 Can we receive |
Log Interfaceconst dispatcher = new Dispatcher();
// context connect dispatch with stores
const appContext = new AppContext({
dispatcher,
states: readAggregate.states
});
// LOG
const logMap = {};
dispatcher.onWillExecuteEachUseCase(useCase => {
const startTimeStamp = performance.now();
console.group(useCase.name, startTimeStamp);
logMap[useCase.name] = startTimeStamp;
});
dispatcher.onDispatch((key, ...args) => {
ContextLogger.logDispatch(key, ...args);
});
appContext.onChange(() => {
ContextLogger.logOnChange(appContext.states);
});
dispatcher.onDidExecuteEachUseCase(useCase => {
const startTimeStamp = logMap[useCase.name];
const takenTime = performance.now() - startTimeStamp;
console.info("Take time(ms): " + takenTime);
console.groupEnd(useCase.name);
}); |
StoreAdd |
StoreGroupIntroduce StoreGroup that collect store's changes. vs. |
} | ||
|
||
throwError(error) { | ||
this.dispatch(`${this.useCaseName}:error`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needed onThrowError
, but I think that listner should know from.
dispatcher has `dispatch(payload)` and `onDispatch(handler)`. These are used `payload` object that contain `type` value.
Dispatcherdispatcher has |
merged 🎉 |
新しいフレームワーク(1)
Presentation: http://azu.github.io/slide/2016/bikeshedjs/javascript-read-write-stack.html
Purpose
TODO