diff --git a/public/stage1/tests.js b/public/stage1/tests.js index 46f1ed45..9b2e2451 100644 --- a/public/stage1/tests.js +++ b/public/stage1/tests.js @@ -12,7 +12,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を document.getElementById(elementId) に // 書き換え、ブラウザをリロードしてみてください。 var elementId = 'firebrick'; - var element = 'change me!'; + var element = document.getElementById(elementId); expect(element).to.be.instanceof(HTMLElement); expect(element).to.have.property('id', elementId); @@ -27,7 +27,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementId = 'chocolate'; - var element = 'change me!'; + var element = document.getElementById(elementId); expect(element).to.be.instanceof(HTMLElement); expect(element).to.have.property('id', elementId); @@ -41,7 +41,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementClassName = 'mediumseagreen'; - var elements = 'change me!'; + var elements = document.getElementsByClassName(elementClassName); expect(elements).to.have.length(1); expect(elements[0]).to.have.property('className', elementClassName); @@ -55,7 +55,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementClassName = 'turquoise'; - var elements = 'change me!'; + var elements = document.getElementsByClassName(elementClassName); expect(elements).to.have.length(2); expect(elements[0]).to.have.property('className', elementClassName); @@ -70,7 +70,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementTagName = 'blockquote'; - var elements = 'change me!'; + var elements = document.getElementsByTagName(elementTagName); expect(elements).to.have.length(1); expect(elements[0]).to.have.property('tagName', elementTagName.toUpperCase()); @@ -93,7 +93,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // すると、開発ツール上で
  • ... が選択されます。 // このことから、7 番の赤色の要素の ID は brown だということがわかります。 // では、'change me!' を document.getElementById('brown') に書き換えてみましょう。 - var element = 'change me!'; + var element = document.getElementById('brown'); expect(element).to.have.property(secret('vq'), secret('oebja')); }); @@ -102,7 +102,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素が1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.getElementById('darkorange'); expect(element).to.have.property(secret('vq'), secret('qnexbenatr')); }); @@ -111,7 +111,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('9 番の緑色の要素が1つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.getElementsByClassName('limegreen'); expect(elements).to.have.length(1); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('yvzrterra')); @@ -121,7 +121,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('10 番の水色の要素が2つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.getElementsByClassName('mediumturquoise'); expect(elements).to.have.length(2); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('zrqvhzghedhbvfr')); @@ -135,7 +135,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // なお、11 番の青色の要素は li 要素ではありません! // よくみると、色がついているのはさらに内側の要素のようです。 - var elements = 'change me!'; + var elements = document.getElementsByTagName('p'); expect(elements).to.have.length(1); expect(elements[0]).to.have.property(secret('gntAnzr'), secret('C')); @@ -152,7 +152,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // 'change me!' を document.querySelector('#firebrick') に // 書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('#firebrick'); expect(element).to.have.property(secret('vq'), secret('sveroevpx')); @@ -164,7 +164,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('2 番の橙色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('#chocolate'); expect(element).to.have.property(secret('vq'), secret('pubpbyngr')); @@ -176,7 +176,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('3 番の緑色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('.mediumseagreen'); expect(element).to.have.property(secret('pynffAnzr'), secret('zrqvhzfrnterra')); }); @@ -185,7 +185,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('4 番の水色の要素を querySelectorAll を使って2つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.querySelectorAll('.turquoise'); expect(elements).to.have.length(2); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('ghedhbvfr')); @@ -196,7 +196,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('5 番の青色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('[title=steelblue]'); expect(element).to.have.property(secret('gntAnzr'), secret('OYBPXDHBGR')); }); @@ -205,7 +205,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('6 番の紫色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('[data-js-training=blueviolet]'); expect(element).to.have.deep.property(secret('qngnfrg.wfGenvavat'), secret('oyhrivbyrg')); @@ -220,8 +220,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // 'change me!' を '.js-training:nth-child(2) li' // に書き換えてください。 - var selector = 'change me!'; - + var selector = 'ul + ul > li:first-child'; var element = document.querySelector(selector); expect(selector).to.not.have.string('#'); expect(element).to.have.property(secret('vq'), secret('oebja')); @@ -231,7 +230,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素を ID セレクタを使わずに1つ取得できる', function() { // 'change me!' を書き換えてください。 - var selector = 'change me!'; + var selector = 'ul + ul > li:nth-child(2)'; var element = document.querySelector(selector); expect(selector).to.not.have.string('#'); @@ -245,7 +244,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('12 番の紫色の要素を、属性セレクタと :nth-child(N) セレクタを使わずに1つ取得できる', function() { // 'change me!' を書き換えてください。 - var selector = 'change me!'; + var selector = 'ul + ul > li:last-child'; var element = document.querySelector(selector); expect(selector).to.not.match(/\[\s*name\s*[~\|\^\$\*]?=/); @@ -265,7 +264,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 基本的な使い方は document.querySelectorAll と同じです。 // // 'change me!' を $('#brown') に書き換えてください。 - var $element = 'change me!'; + var $element = $('#brown'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('oebja')); @@ -275,7 +274,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('#darkorange'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('qnexbenatr')); @@ -288,7 +287,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('9 番の緑色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('.limegreen'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.class(secret('yvzrterra')); @@ -298,7 +297,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('10 番の水色の要素を jQuery を使って2つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('.mediumturquoise'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(2); @@ -309,7 +308,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('11 番の青色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('p'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(1); @@ -320,7 +319,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('12 番の紫色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('[data-js-training="darkorchid"]'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(1); @@ -334,7 +333,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('動いている寿司要素を取得する', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.getElementsByTagName('x-flying-sushi-monster')[0]; expect(element).to.have.deep.property( secret('grkgPbagrag'), '\uD83C\uDF63'); diff --git a/public/stage2/tests.js b/public/stage2/tests.js index b430dfdc..9f370ad3 100644 --- a/public/stage2/tests.js +++ b/public/stage2/tests.js @@ -11,8 +11,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // var element = document.getElementById('firebrick'); // element.textContent = element.textContent + element.textContent; - var element = 'change me!'; - + var element = document.getElementById('firebrick'); + element.textContent = element.textContent + element.textContent; expect(element).to.have.property(secret('vq'), secret('sveroevpx')); expect(element).to.have.deep.property( @@ -24,7 +24,9 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; + var element = document.getElementById('chocolate'); + element.textContent = element.textContent + element.textContent; + expect(element).to.have.property(secret('vq'), secret('pubpbyngr')); @@ -40,8 +42,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; - + var element = document.getElementsByClassName('mediumseagreen')[0]; + element.style.backgroundColor = 'limegreen'; expect(element).to.have.property( secret('pynffAnzr'), secret('zrqvhzfrnterra')); @@ -58,8 +60,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; - + var element = document.getElementsByClassName('turquoise')[0]; + element.style.opacity = '0.5'; expect(element).to.have.property( secret('pynffAnzr'), secret('ghedhbvfr')); @@ -76,8 +78,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; - + var element = document.getElementsByTagName('blockquote')[0]; + element.style.transform = 'rotate(10deg)'; expect(element).to.have.property( secret('gntAnzr'), secret('OYBPXDHBGR')); @@ -97,7 +99,9 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // なお、上に 20px 移動させる方法は複数ありますが、今回は top 属性を // 使う方法を使ってください。 - var element = 'change me!'; + var element = document.querySelector('[data-js-training="blueviolet"]'); + element.style.position = 'relative'; + element.style.top = '-20px'; expect(element).to.have.deep.property( @@ -127,8 +131,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // var $element = $('#brown'); // $element.text($element.text() + $element.text()); - var $element = 'change me!'; - + var $element = $('#brown'); + $element.text($element.text() + $element.text()); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('oebja')); @@ -140,8 +144,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; - + var $element = $('#darkorange'); + $element.text($element.text() + $element.text()); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('qnexbenatr')); @@ -156,7 +160,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('.limegreen'); + $element.css({'background-color': 'mediumseagreen'}); expect($element).to.be.instanceof(jQuery); @@ -173,7 +178,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('.mediumturquoise'); + $element.css({'opacity': '0.5'}); expect($element).to.be.instanceof(jQuery); @@ -186,7 +192,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('p'); + $element.css({'transform': 'rotate(10deg)'}); expect($element).to.be.instanceof(jQuery); @@ -205,7 +212,9 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // なお、上に 20px 移動させる方法は複数ありますが、今回は top 属性を // 使う方法を使ってください。 - var $element = 'change me!'; + var $element = $('[data-js-training="darkorchid"]'); + $element.css({'position': 'relative', + 'top': '-20px'}); expect($element).to.be.instanceof(jQuery); diff --git a/public/stage3/tests.js b/public/stage3/tests.js index fa3cb6f2..0c6ff7ef 100644 --- a/public/stage3/tests.js +++ b/public/stage3/tests.js @@ -11,7 +11,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // var element = document.querySelector('#firebrick'); // var ghost = document.querySelector('.firebrick-ghost'); // element.removeChild(ghost); - + var element = document.querySelector('#firebrick'); + var ghost = document.querySelector('.firebrick-ghost'); + element.removeChild(ghost); var firebrick = document.getElementById('firebrick'); expect(firebrick.childNodes.length).to.equal(1); @@ -22,6 +24,10 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('2 番の要素からインベーダー要素を除去する', function() { // ここにコードを記述してください。 + var element = document.querySelector('#chocolate'); + var ghost = document.querySelector('.chocolate-space-invader'); + element.removeChild(ghost); + var darkorange = document.getElementById('chocolate'); @@ -33,7 +39,13 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('3 番の要素の左右の幽霊要素をすべて除去する', function() { // ここにコードを記述してください。 - + var element = document.querySelector('.mediumseagreen'); + var ghosts = document.querySelectorAll('.mediumseagreen-ghosts'); + var length = ghosts.length; + var i; + for (i = 0; i < length; i += 1) { + element.removeChild(ghosts[i]); + } var darkorange = document.querySelector('.mediumseagreen'); expect(darkorange).to.have.property('textContent', '3\uD83C\uDF3F'); @@ -45,7 +57,8 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で elementToAdd.textContent = '\uD83D\uDC2C'; // 上の elementToAdd を追加するコードをここに記述してください。 - + var target = document.querySelector('.turquoise'); + target.appendChild(elementToAdd); var turquoise = document.querySelector('.turquoise'); expect(turquoise.childNodes.length).to.equal(2); @@ -60,7 +73,8 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // 上の elementToAdd を、5 番の青色の要素の最初に追加するコードを // ここに記述してください。 - + var target = document.getElementsByTagName('blockquote')[0]; + target.insertBefore(elementToAdd, target.firstChild); var blockquote = document.querySelector('blockquote'); expect(blockquote.childNodes.length).to.equal(2); @@ -79,7 +93,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // ここに以下のコードを記述してください。 // // $('.brown-ghost').remove(); - + $('.brown-ghost').remove(); var $brown = $('#brown'); expect($brown.children()).to.have.length(0); @@ -90,7 +104,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('7 番の要素からインベーダー要素を除去する', function() { // ここにコードを記述してください。 - + $('.darkorange-space-invader').remove(); var $darkorange = $('#darkorange'); expect($darkorange.children()).to.have.length(0); @@ -104,7 +118,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('8 番の要素の左右の幽霊要素をすべて除去する', function() { // ここにコードを記述してください。 - + $('.limegreen-ghosts').remove(); var $limegreen = $('.limegreen'); expect($limegreen).to.have.text('8\uD83C\uDF3F'); @@ -115,7 +129,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で var $elementToAdd = $('\uD83D\uDC2C'); // 上の $elementToAdd を追加するコードをここに記述してください。 - + $('.mediumturquoise').append($elementToAdd); var $mediumturquoise = $('.mediumturquoise'); expect($mediumturquoise.children()).to.have.length(1); @@ -127,7 +141,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で var $elementToAdd = $('\uD83D\uDC1F'); // 上の $elementToAdd を追加するコードをここに記述してください。 - + $('p').prepend($elementToAdd); var $p = $('p'); expect($p.children()).to.have.length(1); diff --git a/public/stage4/tests.js b/public/stage4/tests.js index 599536b6..d202e0d6 100644 --- a/public/stage4/tests.js +++ b/public/stage4/tests.js @@ -23,6 +23,10 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun // }); // // ここに上記のどちらかのコードを記述してください。 + $('#firebrick').on('click', function(event) { + var $target = $(event.target); + $target.text(Number($target.text()) + 1); + }); var firebrick = document.getElementById('firebrick'); @@ -37,6 +41,10 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun it('2 番の要素の click イベントで要素内の数字を 1 ずつ小さくできる', function() { // ここにコードを記述してください。 + $('#chocolate').on('click', function(event) { + var $target = $(event.target); + $target.text(Number($target.text()) - 1); + }); var chocolate = document.getElementById('chocolate'); @@ -51,7 +59,14 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun it('3 番の要素の click イベントで要素を 10 度ずつ回転できる', function() { // ここにコードを記述してください。 + var $target = $('.mediumseagreen'); + $target.on('click', (function(){ + var angleDeg = 0; + return function(){ + $target.css({'transform': 'rotate(' + (angleDeg += 10) + 'deg)'}); + }; + })()); var mediumseagreen = document.querySelector('.mediumseagreen'); mediumseagreen.dispatchEvent(createClickEvent()); @@ -67,7 +82,11 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun it('4 番の要素を入力された角度に回転できる', function() { // ここにコードを記述してください。 - + var $target = $('.turquoise'); + var $input = $target.find('input'); + $input.on('change', function(){ + $target.css({'transform': 'rotate(' + this.value + 'deg)'}); + }); var turquoise = document.querySelector('.turquoise'); var turquoiseInput = turquoise.querySelector('input'); @@ -93,9 +112,16 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun // なお、expect(steelblue).to.be.null は上記のテストの要件を満たして // いないので、正解ではありません。 - var steelblue = document.querySelector('.steelblue'); - expect(steelblue).to.have.property('textContent', '5 \uD83D\uDC33'); - done(); + document.addEventListener('DOMContentLoaded', (function(){ + var steelblue = document.querySelector('.steelblue'); + expect(steelblue).to.have.property('textContent', '5 \uD83D\uDC33'); + done(); + })); + // window.addEventListener('load', (function(){ + // var steelblue = document.querySelector('.steelblue'); + // expect(steelblue).to.have.property('textContent', '5 \uD83D\uDC33'); + // done(); + // })); }); }); }); diff --git a/public/stage5/tests.js b/public/stage5/tests.js index 568548d3..759ac9b4 100644 --- a/public/stage5/tests.js +++ b/public/stage5/tests.js @@ -9,10 +9,10 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', // // ここに下記のコードを記述してください。 // - // promise.then(function(msg) { - // expect(msg).to.equal('resolved!'); - // testDone(); - // }); + promise.then(function(msg) { + expect(msg).to.equal('resolved!'); + testDone(); + }); }); @@ -27,6 +27,10 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', // ここにコードを記述してください。 + promise.catch(function(msg) { + expect(msg).to.equal('rejected!'); + testDone(); + }); }); @@ -38,8 +42,7 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var promise3 = createWaitPromise(messageFragments[2], 30); // 作成した promise を promise 変数に代入してください。 - var promise = 'change me!'; - + var promise = Promise.all([promise1, promise2, promise3]); return expect(promise).to.eventually.deep.equal(messageFragments); }); @@ -52,7 +55,7 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var promise3 = createWaitPromise(messageFragments[2], 30); // 作成した promise を promise 変数に代入してください。 - var promise = 'change me!'; + var promise = Promise.race([promise1, promise2, promise3]); return expect(promise).to.eventually.equal(messageFragments[1]); @@ -69,9 +72,9 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', // // ここに下記のコードを記述してください。 // - // var promisedFriends = fetch(api + username).then(function(res) { - // return res.json(); - // }); + var promisedFriends = fetch(api + username).then(function(res) { + return res.json(); + }); return expect(promisedFriends).to.eventually.have.length(1) @@ -84,7 +87,9 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var username = 'Shen'; // 作成した promise を promisedFriends 変数に代入してください。 - var promisedFriends = 'change me!'; + var promisedFriends = fetch(api + username).then(function(res) { + return res.json(); + }); return expect(promisedFriends).to.eventually.have.length(2) @@ -97,21 +102,134 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var username = 'Shen'; // 作成した promise を promisedFriends 変数に代入してください。 - var promisedFriends = 'change me!'; + var fetchFriends = function(friends){ + return Promise.all(friends.map(function(friend){return fetchFriend(friend);})); + }; + var fetchFriend = function(friend){ + return fetch(api + friend).then(function(res) { + return res.json(); + }); + }; + var promisedFriends = fetchFriends(["jisp", "TeJaS"]) + .then(function(res){return Array.prototype.concat.apply([], res);}); return expect(promisedFriends).to.eventually.have.length(1) .and.have.members(['TypeScript']); }); - it.skip('/api/friends API を使って CoffeeScript の友人を再帰的に取得できる', function() { + it('/api/friends API を使って CoffeeScript の友人を再帰的に取得できる', function() { // 難易度高いので、自信のある人だけ挑戦してください。 // it.skip の .skip を消せば、テストが走るようになります。 // 作成した promise を promisedFriends 変数に代入してください。 - var promisedFriends = 'change me!'; + var api = '/api/friends/'; + var promisedFriends = []; + var fetchFriendsRecursive = function(targets, list){ + list = list || []; + return fetchFriends(targets).then(function(friends){ + if (friends.length == 0) { + return list; + } + list = list.concat(friends); + return fetchFriendsRecursive(friends, list); + }); + }; + + var fetchFriends = function(targets){ + return Promise.all(targets.map(fetchFriend)) + .then(flatMap); + }; + var fetchFriend = function(target){ + return fetch(api + target).then(function(res) { + return res.json(); + }); + }; + + var flatMap = function(list){ + return Array.prototype.concat.apply([], list); + }; + // 作成した promise を promisedFriends 変数に代入してください。 + promisedFriends = fetchFriendsRecursive(['CoffeeScript']); + + // /** + // * 友人を取得する。 + // * @param {string} usernameToFetch 友人の取得対象のユーザー名。 + // * @return {Thenable>} 友人の配列。 + // */ + // function getFriends(usernameToFetch) { + // return fetch(api + usernameToFetch) + // .then(function(response) { + // return response.json(); + // }); + // } + + // /** + // * 配列または配列をもつ promise を展開し、平たい配列をもつ promise を + // * 返す。 + // * @param {Array|T>} arrayOfPromisedArray promise または、 + // * オブジェクトの配列。 + // * @return {Thenable>} 平たい配列をもつ promise。 + // * @template T + // */ + // function flatMap(arrayOfPromisedArray) { + // return Promise.all(arrayOfPromisedArray) + // .then(function(arrayOfArray) { + // return arrayOfArray.reduce(function(flatArray, array) { + // // JavaScript には破壊的な配列結合がないので、 + // // Array#push を悪用することが多いです。 + // Array.prototype.push.apply(flatArray, array); + // return flatArray; + // }, []); + // }); + // } + + // /** + // * 配列を結合する関数を返す。この関数の実行前に、結合する配列の片方を + // * 指定する必要がある。 + // * @param {Array} arrayA 関数の実行前に指定する、結合したい配列。 + // * @return {function(Array): Array} arrayA と arrayB を結合する関数。 + // * @template T + // */ + // function concat(arrayA) { + // return function(arrayB) { + // return arrayA.concat(arrayB); + // }; + // } + + // /** + // * 友人を再帰的に取得する。 + // * @param {string} usernameToFetch 友人の取得対象の名前。 + // * @return {Thenable>} 友人名の配列をもつ promise。 + // */ + // function getFriendsRecursively(usernameToFetch) { + // return getFriends(usernameToFetch) + // .then(function(friends) { + // if (friends.length === 0) return friends; + + // var promisedFriendsOfFriends = Promise.all( + // friends.map(getFriendsRecursively)); + + // return promisedFriendsOfFriends + // .then(flatMap) + // .then(concat(friends)); + // }); + // } + + // /** + // * いい感じにメソッドチェーンの途中で値を出力する + // * @param なんか + // * @return なんか + // */ + // function tap(object){ + // console.log(object); + // return object; + // } + + // 作成した promise を promisedFriends 変数に代入してください。 + // promisedFriends = getFriendsRecursively('CoffeeScript'); return expect(promisedFriends).to.eventually.have.length(5) .and.have.members([ @@ -127,7 +245,10 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', it('Github の mixi-inc の organization の情報を取得できる', function() { // 作成した promise を mixiOrg 変数に代入してください。 - var mixiOrg = 'change me!'; + var endpoint = 'http://api.github.com/'; + var api = 'orgs/'; + var name = 'mixi-inc'; + var mixiOrg = fetch(endpoint + api + name).then(function(res){return res.json();}); return expect(mixiOrg).to.eventually.have.property('id', 1089312); @@ -138,10 +259,13 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', it('Github API を使って、mixi-inc/JavaScriptTraining の情報を取得できる', function() { var repository = 'mixi-inc/JavaScriptTraining'; + var endpoint = 'http://api.github.com/'; + var api = 'repos/'; + var name = 'mixi-inc/'; + var repos = 'JavaScriptTraining'; // 作成した promise を mixiRepo 変数に代入してください。 - var mixiRepo = 'change me!'; - + var mixiRepo = fetch(endpoint + api + name + repos).then(function(res){return res.json();}); return expect(mixiRepo).to.eventually.have.property('full_name', repository); @@ -156,7 +280,37 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var mostPopularRepos = 'change me!'; // 作成した promise を mostPopularRepos 変数に代入してください。 + var queryString = function(params){ + var str = []; + for(var p in params) + if (params.hasOwnProperty(p)) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(params[p])); + } + return str.join("&"); + }; + + var fetchMostPopularRepo = function(keyword){ + var endpoint = 'http://api.github.com/'; + var api = 'search/repositories?'; + var params = { + q: keyword, + sort: 'star' + }; + return fetch(endpoint + api + queryString(params)).then(function(res) { + return res.json(); + }); + }; + + var fetchMostPopularRepos = function(keywords){ + return Promise.all(keywords.map(function(keyword){return fetchMostPopularRepo(keyword);})); + }; + mostPopularRepos = fetchMostPopularRepos(languages).then(function(res){ + var ret = res.map(function(repos){ + return repos.items[0].name; + }); + return ret; + }); return expect(mostPopularRepos).to.eventually.have.length(2) .and.satisfy(function(names) {