私は cyclejs と rxjs を学んでおり、取り組んでいるコンポーネントの 1 つの単体テストを書くのに苦労しています。長い質問で申し訳ありません。私は質問を単純化しようとしましたが、これが私ができる最善のことです。
コンポーネントは次のことを行います:
1) ロードされると、リクエストをエンドポイントに送信して、ユーザーのタスクを取得します。これらのタスクから、現在作業中のタスク ユーザーを見つけ、ユーザーがタスクの完了ボタンをクリックしたときに呼び出されるエンドポイントを含む URL ストリームを作成します。
2) 新しい値がテスト ストリームに来ると、それまでに定義されたテストから新しいストリームを作成します。
3) ユーザーがタスクの完了をクリックすると、コンポーネントは最初にリクエストをエンドポイントに送信し、ユーザーが定義したテストをタスクに追加します。次に、呼び出しが成功した場合、コンポーネントは別の要求をエンドポイントに送信します。この要求はステップ 1 で取得され、タスクを完了します。
4) 完全なタスク要求が完了すると、コンポーネントはユーザーに通知を表示します。
コンポーネントは次のとおりです。
import Rx from 'rx';
import {Observable} from 'rx';
const Model = ({test$, completeTask$, sources}) => {
const processId = Number(sources.routeParams.processId);
const SET_TEST_RESULTS = `http://dummyhost/tosettests/${processId}`;
const GET_USER_TASKS = 'http://dummyhost/togetusertasks';
const taskRequest$ = Observable.just({
url: GET_USER_TASKS,
method: 'GET'
});
const url$ = sources.HTTP
.filter(response => response.request.url === GET_USER_TASKS)
.flatMap(response => response.body)
.filter(task => task.processId === processId)
.take(1)
.map(task=> {
const activitiId = task.processInstanceId;
return {
completeTask: `http://dummyhost/tocompletetask/${activitiId}`
};
});
const definedTest$ = test$
.scan((acc, curr) => {
acc.push(curr);
return acc;
}, [])
.startWith([])
.share();
const setTestResultsRequest$ = completeTask$
.withLatestFrom(definedTest$, (event, tests) => {
return {
url: SET_TEST_RESULTS,
method: 'POST',
send: {
tests
}
};
});
const setTestResultsResponse$ = sources.HTTP
.filter(response => response.request.url === SET_TEST_RESULTS);
const completeTaskRequest$ = setTestResultsResponse$
.withLatestFrom(url$, (response, url) => {
return {
url: url.completeTask,
method: 'POST'
};
});
const completeTaskResponse$ = sources.HTTP
.withLatestFrom(url$, (response, url) => {
return {
response,
url
};
})
.filter(data => data.response.request.url === data.url.completeTask)
.map((data)=> data.response);
const successNotification$ = completeTaskResponse$
.map(() => {
return {
action: 'success',
message: 'Tests have been defined!'
};
});
const request$ = Observable.merge(taskRequest$, setTestResultsRequest$, completeTaskRequest$);
return {
request$: request$,
notification$: successNotification$,
definedTest$: definedTest$
};
};
私が単体テストしようとしているのは次のとおりです
。1)コンポーネントはタスクにテストを定義するためのリクエストを送信する必要があります
2)コンポーネントはタスクを完了するためにリクエストを送信する必要があります
3)コンポーネントは通知を表示する必要があります
これまでに Mocha で書いた単体テストは次のとおりです。
describe('When complete task is clicked', ()=> {
const tests = [
{
name: 'test 1 name'
},
{
name: 'test 2 name'
},
{
name: 'test 3 name'
}
];
const test$ = Observable.fromArray(tests);
const completeTask$ = Observable.just({}).delay(300);
const processId = 3;
const activitiId = 3;
var actions;
before(done => {
const HTTPSource = new Rx.ReplaySubject();
const sources = {
DOM: mockDOMSource(),
routeParams: {processId},
HTTP: HTTPSource
};
actions = Model({test$, completeTask$, sources});
const request$ = actions.request$.share();
request$
.filter(request=> request.url === 'http://dummyhost/togetusertasks')
.subscribe((request) => {
const response = {
request,
body: [{
processId,
processInstanceId: activitiId
}]
};
HTTPSource.onNext(response);
});
request$
.filter(request=> request.url === `http://dummyhost/tosettests/${processId}`)
.subscribe((request) => {
const response = {
request
};
HTTPSource.onNext(response);
});
request$
.filter(request=> request.url === `http://dummyhost/tocompletetask/${activitiId}`)
.subscribe((request) => {
const response = {
request
};
HTTPSource.onNext(response);
done();
});
});
it('should send a request to add tests', (done)=> {
actions.request$
.filter(request=> request.url === `http://dummyhost/tosettests/${processId}`)
.subscribe(() => {
done();
});
});
it('should send a request to complete task', (done)=> {
actions.request$
.filter(request=> request.url === `http://dummyhost/tocompletetask/${activitiId}`)
.subscribe(() => {
done();
});
});
it('should show a notification to inform user that tests have been defined', (done) => {
actions.notification$.take(1)
.subscribe(notification => {
expect(notification.action).to.equal('success');
done();
});
});
});
テストでは、HTTP ソースをモックしようとしました。コンポーネントから返されるリクエスト ストリーム シンクをサブスクライブすることで、リクエストごとにモック レスポンスを作成できます。しかし、関数の前にモカを正常に実行するには、共有演算子を使用する必要があります。そうしないと、ユーザーのタスクを取得する最初のリクエストしかモックできません。だから、私の最初の質問は次のとおりです。
mocha の before 関数を正常に実行するために共有演算子を使用する必要があるのはなぜですか?
現在、完全なタスク リクエストが送信され、通知が表示されることを確認するテストは合格です。しかし、タスク要求への定義テストを検証するテストは失敗しています。完全なタスク要求が送信されたことを確認するために、コンポーネントは最初に定義テストをタスク要求に送信する必要があるため、これは奇妙です。コンポーネントのシンクから返されたリクエスト ストリームで何らかの理由で失われたタスク リクエストにテストを定義しているようです。2 番目の質問は、
なぜ 2 番目と 3 番目のテストは成功するのに、最初のテストが失敗するのかということです。
すべてのコードを 1 つのファイルにまとめた要点を以下に示します: 要旨リンク
前に言ったように、私は cyclejs と rxjs は初めてです。私がテストしているものを完全に理解していないと思います。したがって、cyclejs と rxjs に関するコメントや回答で、正しい道を教えてくれるものは大歓迎です。
質問が十分に明確ではないと思われる場合は、お知らせください。私は最善を尽くして質問を改善します。