ๅ˜ไฝ“ใƒ†ใ‚นใƒˆใฎไฝœๆˆๆ™‚ใฎไธๅฟซใชใ‚จใƒฉใƒผ

ๅ…ˆๆ—ฅใ€็งใฏๅ†…้ƒจใƒฌใƒใƒผใƒˆใ‚’ไฝœๆˆใ—ใพใ™ใ€‚ใ“ใฎใƒฌใƒใƒผใƒˆใงใฏใ€ๅ˜ไฝ“ใƒ†ใ‚นใƒˆใฎไฝœๆˆๆ™‚ใซ็™บ็”Ÿใ™ใ‚‹ๅฏ่ƒฝๆ€งใŒใ‚ใ‚‹ไธๅฟซใชใƒŸใ‚นใซใคใ„ใฆ้–‹็™บ่€…ใซๅ ฑๅ‘Šใ—ใพใ™ใ€‚ ็งใฎ่ฆณ็‚นใ‹ใ‚‰ๆœ€ใ‚‚ไธๆ„‰ๅฟซใชใ‚จใƒฉใƒผใฏใ€ใƒ†ใ‚นใƒˆใซๅˆๆ ผใ—ใŸใจใใงใ™ใŒใ€ๅŒๆ™‚ใซไธๅˆๆ ผใชใฎใงใ€ๅˆๆ ผใ—ใชใ„ใปใ†ใŒ่‰ฏใ„ใงใ—ใ‚‡ใ†ใ€‚ ใใ—ใฆใ€ใใฎใ‚ˆใ†ใชใ‚จใƒฉใƒผใฎไพ‹ใ‚’ๅ…จๅ“กใจๅ…ฑๆœ‰ใ™ใ‚‹ใ“ใจใซใ—ใพใ—ใŸใ€‚ ็ขบใ‹ใซใ“ใฎ้ ˜ๅŸŸใ‹ใ‚‰ไผใˆใ‚‹ในใไฝ•ใ‹ไป–ใฎใ‚‚ใฎใ€‚ Node.JSใจMochaใฎไพ‹ใฏๆ›ธใ‹ใ‚Œใฆใ„ใพใ™ใŒใ€ไธ€่ˆฌ็š„ใซใ€ใ“ใ‚Œใ‚‰ใฎใ‚จใƒฉใƒผใฏไป–ใฎใ‚จใ‚ณใ‚ทใ‚นใƒ†ใƒ ใซใ‚‚ๅฝ“ใฆใฏใพใ‚Šใพใ™ใ€‚



ใ‚‚ใฃใจ้ข็™ฝใใ™ใ‚‹ใŸใ‚ใซใ€ใใ‚Œใ‚‰ใฎใ„ใใคใ‹ใฏๅ•้กŒใ‚ณใƒผใƒ‰ใจใ‚นใƒใ‚คใƒฉใƒผใฎๅฝขใงใƒ•ใƒฌใƒผใƒ ๅŒ–ใ•ใ‚ŒใฆใŠใ‚Šใ€ใใ‚Œใ‚’้–‹ใใจใ€ๅ•้กŒใŒไฝ•ใงใ‚ใฃใŸใ‹ใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚ ใใฎใŸใ‚ใ€ใพใšใ‚ณใƒผใƒ‰ใ‚’่ฆ‹ใฆใ€ใ‚จใƒฉใƒผใ‚’่ฆ‹ใคใ‘ใฆใ‹ใ‚‰ใ€ใ‚นใƒใ‚คใƒฉใƒผใ‚’้–‹ใใ“ใจใ‚’ใŠๅ‹งใ‚ใ—ใพใ™ใ€‚ ๅ•้กŒใฎ่งฃๆฑบ็ญ–ใฏ็คบใ•ใ‚Œใพใ›ใ‚“ใ€‚่‡ชๅˆ†ใง่€ƒใˆใ‚‹ใ“ใจใ‚’ๆๆกˆใ—ใพใ™ใ€‚ ๆ€ ใ‘่€…ใ ใ‹ใ‚‰ใ€‚ ใƒชใ‚นใƒˆใฎ้ †ๅบใซใฏๆทฑใ„ๆ„ๅ‘ณใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ใใ‚Œใฏใ€่ก€ใพใฟใ‚Œใฎๆถ™ใซใชใฃใŸใ‚ใ‚‰ใ‚†ใ‚‹็จฎ้กžใฎๅฎŸ้š›ใฎๅ•้กŒใ‚’ๆ€ใ„ๅ‡บใ—ใŸใ‚ทใƒผใ‚ฑใƒณใ‚นใซใ™ใŽใพใ›ใ‚“ใ€‚ ็ขบใ‹ใซๅคšใใฎใ“ใจใฏใ‚ใชใŸใซใฏๆ˜Žใ‚‰ใ‹ใชใ‚ˆใ†ใซๆ€ใˆใพใ™ใŒใ€็ตŒ้จ“่ฑŠๅฏŒใช้–‹็™บ่€…ใงใ•ใˆ่ชคใฃใฆใใฎใ‚ˆใ†ใชใ‚ณใƒผใƒ‰ใ‚’ๆ›ธใใ“ใจใŒใงใใพใ™ใ€‚





่กŒใใพใ—ใ‚‡ใ†ใ€‚



0.ใƒ†ใ‚นใƒˆใฎๆฌ ๅฆ‚



ๅฅ‡ๅฆ™ใชใ“ใจใซใ€ใƒ†ใ‚นใƒˆใ‚’ๆ›ธใใจ้–‹็™บ้€ŸๅบฆใŒไฝŽไธ‹ใ™ใ‚‹ใจๅคšใใฎไบบใŒใ„ใพใ ใซไฟกใ˜ใฆใ„ใพใ™ใ€‚ ใ‚‚ใกใ‚ใ‚“ใ€ใƒ†ใ‚นใƒˆใฎไฝœๆˆใจใƒ†ใ‚นใƒˆๅฏ่ƒฝใชใ‚ณใƒผใƒ‰ใฎไฝœๆˆใซใ‚ˆใ‚Šๅคšใใฎๆ™‚้–“ใ‚’่ฒปใ‚„ใ™ๅฟ…่ฆใŒใ‚ใ‚‹ใ“ใจใฏๆ˜Žใ‚‰ใ‹ใงใ™ใ€‚ ใ—ใ‹ใ—ใ€ใใฎๅพŒใƒ‡ใƒใƒƒใ‚ฐใ—ใฆ้€€่กŒใ—ใŸๅพŒใฏใ€ใ•ใ‚‰ใซๅคšใใฎๆ™‚้–“ใ‚’่ฒปใ‚„ใ™ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™...



1.ใƒ†ใ‚นใƒˆๅฎŸ่กŒใฎๆฌ ๅฆ‚



ๅฎŸ่กŒใ—ใชใ„ใƒ†ใ‚นใƒˆใ€ใพใŸใฏๆ™‚ใ€…ๅฎŸ่กŒใ™ใ‚‹ใƒ†ใ‚นใƒˆใŒใ‚ใ‚‹ๅ ดๅˆใ€ใ“ใ‚Œใฏใƒ†ใ‚นใƒˆใŒใชใ„ใ‚ˆใ†ใงใ™ใ€‚ ใ•ใ‚‰ใซๆ‚ชใ„ใ“ใจใซใ€ๅคใ„ใƒ†ใ‚นใƒˆใ‚ณใƒผใƒ‰ใจ่ชคใฃใŸใ‚ปใ‚ญใƒฅใƒชใƒ†ใ‚ฃๆ„่ญ˜ใŒใ‚ใ‚Šใพใ™ใ€‚ ใ‚ณใƒผใƒ‰ใ‚’ใƒ–ใƒฉใƒณใƒใซใƒ—ใƒƒใ‚ทใƒฅใ™ใ‚‹ใจใใฏใ€ๅฐ‘ใชใใจใ‚‚CIใƒ—ใƒญใ‚ปใ‚นใงใƒ†ใ‚นใƒˆใ‚’ๅฎŸ่กŒใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ ใ‚ˆใ‚Š่‰ฏใ„-ใƒ—ใƒƒใ‚ทใƒฅใฎๅ‰ใซใƒญใƒผใ‚ซใƒซใงใ€‚ ใใ†ใ™ใ‚Œใฐใ€้–‹็™บ่€…ใฏๆ•ฐๆ—ฅใงใƒ“ใƒซใƒ‰ใซๆˆปใ‚‹ๅฟ…่ฆใŒใชใใชใ‚Šใ€็ตๅฑ€ใฎใจใ“ใ‚ใ€ใƒ“ใƒซใƒ‰ใซๅˆๆ ผใ—ใพใ›ใ‚“ใงใ—ใŸใ€‚



2.ใ‚ซใƒใƒฌใƒƒใ‚ธใฎๆฌ ๅฆ‚



ใใ‚Œใงใ‚‚ใƒ†ใ‚นใƒˆใฎใ‚ซใƒใƒฌใƒƒใ‚ธใŒใ‚ใ‹ใ‚‰ใชใ„ๅ ดๅˆใฏใ€ไปŠใ™ใ่ชญใฟใซ่กŒใใพใ—ใ‚‡ใ†ใ€‚ ๅฐ‘ใชใใจใ‚‚ใ‚ฆใ‚ฃใ‚ญใƒšใƒ‡ใ‚ฃใ‚ข ใ€‚ ใใ‚Œไปฅๅค–ใฎๅ ดๅˆใ€ใƒ†ใ‚นใƒˆใงใฏใ€ใƒใ‚งใƒƒใ‚ฏใ™ใ‚‹ใ‚ณใƒผใƒ‰ใฎ10๏ผ…ใฎๅผทๅบฆใงใƒ†ใ‚นใƒˆใ™ใ‚‹ๅฏ่ƒฝๆ€งใŒ้ซ˜ใใชใ‚Šใพใ™ใ€‚ ้…ใ‹ใ‚Œๆ—ฉใ‹ใ‚Œใ€ใ‚ใชใŸใฏ้–“้•ใ„ใชใใใ‚Œใซ่ธใฟ่พผใ‚€ใงใ—ใ‚‡ใ†ใ€‚ ใ‚‚ใกใ‚ใ‚“ใ€ใ‚ณใƒผใƒ‰ใ‚’100๏ผ…็ถฒ็พ…ใ—ใฆใ‚‚ใ€ๅฎŒๅ…จใซๆญฃใ—ใ„ใ“ใจใ‚’ไฟ่จผใ™ใ‚‹ใ‚ใ‘ใงใฏใ‚ใ‚Šใพใ›ใ‚“ใŒใ€ๆฝœๅœจ็š„ใชใ‚จใƒฉใƒผใŒใฏใ‚‹ใ‹ใซๅคšใ่กจ็คบใ•ใ‚Œใ‚‹ใŸใ‚ใ€ใ‚ซใƒใƒฌใƒƒใ‚ธใŒใชใ„ใ‚ˆใ‚Šใ‚‚ใฏใ‚‹ใ‹ใซๅ„ชใ‚Œใฆใ„ใพใ™ใ€‚ Node.JSใฎๆœ€ๆ–ฐใƒใƒผใ‚ธใƒงใƒณใŒใใ‚Œใ‚’่ชญใ‚€ใŸใ‚ใฎ็ต„ใฟ่พผใฟใƒ„ใƒผใƒซใ‚’ๆŒใฃใฆใ„ใ‚‹ใฎใ‚‚ไธๆ€่ญฐใงใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ ไธ€่ˆฌ็š„ใซใ€ๅ ฑ้“ใฎใƒˆใƒ”ใƒƒใ‚ฏใฏๆทฑใใ€้žๅธธใซๅ…จไฝ“่ซ–็š„ใงใ™ใŒใ€็งใฏใใ‚Œใซใคใ„ใฆๆทฑใๅ…ฅใ‚Šใ™ใŽใพใ›ใ‚“-็งใฏๅคšใใซใคใ„ใฆๅฐ‘ใ—่จ€ใ„ใŸใ„ใงใ™ใ€‚



3ใ€‚





const {assert} = require('chai'); const Promise = require('bluebird'); const sinon = require('sinon'); class MightyLibrary { static someLongFunction() { return Promise.resolve(1); // just imagine a really complex and long function here } } async function doItQuickOrFail() { let res; try { res = await MightyLibrary.someLongFunction().timeout(1000); } catch (err) { if (err instanceof Promise.TimeoutError) { return false; } throw err; } return res; } describe('using Timeouts', ()=>{ it('should return false if waited too much', async ()=>{ // stub function to emulate looong work sinon.stub(MightyLibrary, 'someLongFunction').callsFake(()=>Promise.delay(10000).then(()=>true)); const res = await doItQuickOrFail(); assert.equal(res, false); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
ๅ˜ไฝ“ใƒ†ใ‚นใƒˆใฎใ‚ฟใ‚คใƒ ใ‚ขใ‚ฆใƒˆใ€‚



ใ“ใ“ใงใฏใ€้•ทใ„ๆ“ไฝœใฎใ‚ฟใ‚คใƒ ใ‚ขใ‚ฆใƒˆ่จญๅฎšใŒๅฎŸ้š›ใซๆฉŸ่ƒฝใ™ใ‚‹ใ“ใจใ‚’็ขบ่ชใ—ใŸใ‹ใฃใŸใฎใงใ™ใ€‚ ไธ€่ˆฌใซใ€ใ“ใ‚Œใฏใจใซใ‹ใใปใจใ‚“ใฉๆ„ๅ‘ณใŒใ‚ใ‚Šใพใ›ใ‚“-ๆจ™ๆบ–ใƒฉใ‚คใƒ–ใƒฉใƒชใ‚’ใƒใ‚งใƒƒใ‚ฏใ™ใ‚‹ในใใงใฏใ‚ใ‚Šใพใ›ใ‚“-ใ—ใ‹ใ—ใ€ใ“ใฎใ‚ณใƒผใƒ‰ใฏๅˆฅใฎๅ•้กŒใซใคใชใŒใ‚Šใพใ™-ใƒ†ใ‚นใƒˆใฎๅฎŸ่กŒๆ™‚้–“ใ‚’1็ง’้–“ๅข—ๅŠ ใ•ใ›ใพใ™ใ€‚ ใ“ใ‚Œใฏใใ‚Œใปใฉๅคšใใฏใชใ„ใ‚ˆใ†ใซๆ€ใ‚ใ‚Œใพใ™...ใ—ใ‹ใ—ใ€ใ“ใฎ็ง’ๆ•ฐใซใ€ๅŒๆง˜ใฎใƒ†ใ‚นใƒˆใฎๆ•ฐใ€้–‹็™บ่€…ใฎๆ•ฐใ€1ๆ—ฅใ‚ใŸใ‚Šใฎ่ตทๅ‹•ๆ•ฐใ‚’ๆŽ›ใ‘ใฆใใ ใ•ใ„...ใใ—ใฆใ€ใใฎใ‚ˆใ†ใชใ‚ฟใ‚คใƒ ใ‚ขใ‚ฆใƒˆใฎใŸใ‚ใซใ€ๆฏŽๆ—ฅใงใฏใชใใจใ‚‚ๆฏŽ้€ฑไฝ•ๆ™‚้–“ใ‚‚ใฎไป•ไบ‹ใ‚’ๅคฑใ†ๅฏ่ƒฝๆ€งใŒใ‚ใ‚‹ใ“ใจใ‚’็†่งฃใงใใพใ™ใ€‚






4ใ€‚





 const fs = require('fs'); const testData = JSON.parse(fs.readFileSync('./testData.json', 'utf8')); describe('some block', ()=>{ it('should do something', ()=>{ someTest(testData); }) })
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
ใƒ†ใ‚นใƒˆใƒ–ใƒญใƒƒใ‚ฏๅค–ใฎใƒ†ใ‚นใƒˆใƒ‡ใƒผใ‚ฟใฎ่ชญใฟ่พผใฟใ€‚



ไธ€่ฆ‹ใ€ใƒ†ใ‚นใƒˆใƒ‡ใƒผใ‚ฟใ‚’ใฉใ“ใง่ชญใ‚€ใ‹ใฏๅ•้กŒใงใฏใชใ„ใจๆ€ใ‚ใ‚Œใพใ™-่ชฌๆ˜Žใ€ใƒ–ใƒญใƒƒใ‚ฏใ€ใพใŸใฏใƒขใ‚ธใƒฅใƒผใƒซ่‡ชไฝ“ใ€‚ 2็•ช็›ฎใซใ‚‚ใ€‚ ใ—ใ‹ใ—ใ€ไฝ•็™พใ‚‚ใฎใƒ†ใ‚นใƒˆใŒใ‚ใ‚Šใ€ใใฎๅคšใใŒๅคง้‡ใฎใƒ‡ใƒผใ‚ฟใ‚’ไฝฟ็”จใ—ใฆใ„ใ‚‹ใจๆƒณๅƒใ—ใฆใใ ใ•ใ„ใ€‚ ใใ‚Œใ‚‰ใ‚’ใƒ†ใ‚นใƒˆๅค–ใงใƒญใƒผใƒ‰ใ™ใ‚‹ใจใ€ใƒ†ใ‚นใƒˆใฎ็ต‚ไบ†ใพใงใ™ในใฆใฎใƒ†ใ‚นใƒˆใƒ‡ใƒผใ‚ฟใŒใƒกใƒขใƒชใซๆฎ‹ใ‚Šใ€ๆ™‚้–“ใŒ็ตŒใคใซใคใ‚Œใฆใ€่ตทๅ‹•ใซใ‚ˆใ‚ŠๅคšใใฎRAMใŒๆถˆ่ฒปใ•ใ‚Œใ€ใƒ†ใ‚นใƒˆใŒๅฎŸ่กŒใ•ใ‚Œใชใใชใ‚‹ใ“ใจใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚ๆจ™ๆบ–ไฝœๆฅญๆฉŸๆขฐใ€‚






5ใ€‚





 const {assert} = require('chai'); const sinon = require('sinon'); class Dog { // eslint-disable-next-line class-methods-use-this say() { return 'Wow'; } } describe('stubsEverywhere', ()=>{ before(()=>{ sinon.stub(Dog.prototype, 'say').callsFake(()=>{ return 'meow'; }); }); it('should say meow', ()=>{ const dog = new Dog(); assert.equal(dog.say(), 'meow', 'dog should say "meow!"'); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
ใ‚ณใƒผใƒ‰ใฏๅฎŸ้š›ใซใฏใ‚นใ‚ฟใƒ–ใซ็ฝฎใๆ›ใˆใ‚‰ใ‚Œใพใ™ใ€‚



ใใฃใจใ‚ใชใŸใฏใ™ใใซใ“ใฎใฐใ‹ใ’ใŸ้–“้•ใ„ใ‚’่ฆ‹ใพใ—ใŸใ€‚ ใ‚‚ใกใ‚ใ‚“ใ€ๅฎŸ้š›ใฎใ‚ณใƒผใƒ‰ใงใฏใ€ใ“ใ‚Œใฏใใ‚Œใปใฉๆ˜Ž็™ฝใงใฏใ‚ใ‚Šใพใ›ใ‚“ใŒใ€ใ‚นใ‚ฟใƒ–ใงใƒใƒณใ‚ฐใ—ใฆใ„ใ‚‹ใ‚ณใƒผใƒ‰ใ‚’่ฆ‹ใŸใฎใงใ€ไฝ•ใ‚‚ใƒ†ใ‚นใƒˆใ—ใพใ›ใ‚“ใงใ—ใŸใ€‚






6ใ€‚





 const sinon = require('sinon'); const {assert} = require('chai'); class Widget { fetch() {} loadData() { this.fetch(); } } if (!sinon.sandbox || !sinon.sandbox.stub) { sinon.sandbox = sinon.createSandbox(); } describe('My widget', () => { it('is awesome', () => { const widget = new Widget(); widget.fetch = sinon.sandbox.stub().returns({ one: 1, two: 2 }); widget.loadData(); assert.isTrue(widget.fetch.called); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
ใƒ†ใ‚นใƒˆ้–“ใฎไพๅญ˜้–ขไฟ‚ใ€‚



ไธ€่ฆ‹ใ™ใ‚‹ใจใ€ๅฝผใ‚‰ใŒใ“ใ“ใซๆ›ธใใฎใ‚’ๅฟ˜ใ‚ŒใŸใ“ใจใฏๆ˜Žใ‚‰ใ‹ใงใ™



  afterEach(() => { sinon.sandbox.restore(); });
      
      







ใ—ใ‹ใ—ใ€ๅ•้กŒใฏใ“ใ‚Œใ ใ‘ใงใฏใชใใ€ใ™ในใฆใฎใƒ†ใ‚นใƒˆใงๅŒใ˜ใ‚ตใƒณใƒ‰ใƒœใƒƒใ‚ฏใ‚นใŒไฝฟ็”จใ•ใ‚Œใ‚‹ใ“ใจใงใ™ใ€‚ ใพใŸใ€ใƒ†ใ‚นใƒˆๅฎŸ่กŒ็’ฐๅขƒใ‚’ๆททๅŒใ™ใ‚‹ใ“ใจใฏ้žๅธธใซ็ฐกๅ˜ใงใ‚ใ‚‹ใŸใ‚ใ€็›ธไบ’ใซไพๅญ˜ใ—ๅง‹ใ‚ใพใ™ใ€‚ ใใฎๅพŒใ€ใƒ†ใ‚นใƒˆใฏ็‰นๅฎšใฎ้ †ๅบใงใฎใฟๅฎŸ่กŒใ•ใ‚Œใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ™ใŒใ€ไธ€่ˆฌ็š„ใซใƒ†ใ‚นใƒˆใ™ใ‚‹ๅฏพ่ฑกใฏๆ˜Ž็ขบใงใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚



ๅนธใ„ใชใ“ใจใซใ€sinon.sandboxใฏใ‚ใ‚‹ๆ™‚็‚นใงๅปƒๆญขใ•ใ‚Œใฆ้ฃฒใพใ‚ŒใŸใŸใ‚ใ€ใใฎใ‚ˆใ†ใชๅ•้กŒใฏใƒฌใ‚ฌใ‚ทใƒผใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆใงใ—ใ‹็™บ็”Ÿใ—ใพใ›ใ‚“ใŒใ€ใƒ†ใ‚นใƒˆๅฎŸ่กŒ็’ฐๅขƒใ‚’ๆททไนฑใ•ใ›ใ‚‹ๆ–นๆณ•ใฏไป–ใซใ‚‚ใŸใใ•ใ‚“ใ‚ใ‚Šใ€ๅพŒใง่ชฟๆŸปใ™ใ‚‹ใฎใฏ่‹ฆ็—›ใงใ™ใ€‚ใฉใฎใ‚ณใƒผใƒ‰ใŒไธๆญฃใชๅ‹•ไฝœใฎ็ฝชใ‚’็Šฏใ—ใฆใ„ใพใ™ใ€‚ ใจใ“ใ‚ใงใ€ๆœ€่ฟ‘ใ€ใƒใƒ–ใซใ€Œใ‚ขใ‚คใ‚นใƒ•ใ‚กใ‚ฏใƒˆใƒชใƒผใ€ใฎใ‚ˆใ†ใชใƒ†ใƒณใƒ—ใƒฌใƒผใƒˆใซ้–ขใ™ใ‚‹ๆŠ•็จฟใŒใ‚ใ‚Šใพใ—ใŸใ€‚ใ“ใ‚Œใฏไธ‡่ƒฝ่–ฌใงใฏใ‚ใ‚Šใพใ›ใ‚“ใŒใ€ใใฎใ‚ˆใ†ใชๅ ดๅˆใซๅฝน็ซ‹ใคใ“ใจใŒใ‚ใ‚Šใพใ™ใ€‚








7.ใƒ†ใ‚นใƒˆใƒ•ใ‚กใ‚คใƒซใฎ่†จๅคงใชใƒ†ใ‚นใƒˆใƒ‡ใƒผใ‚ฟ





้žๅธธใซ้ ป็นใซใ€JSONใƒ•ใ‚กใ‚คใƒซใ€ใ•ใ‚‰ใซใฏXMLใŒใฉใ‚Œใปใฉๅทจๅคงใงใ‚ใ‚‹ใ‹ใ‚’ใƒ†ใ‚นใƒˆใซ็›ดๆŽฅ่ฆ‹ใพใ—ใŸใ€‚ ใชใœใ“ใ‚Œใ‚’่กŒใ†ไพกๅ€คใŒใชใ„ใฎใ‹ใฏๆ˜Žใ‚‰ใ‹ใ ใจๆ€ใ„ใพใ™ใ€‚่ฆ‹ใŸใ‚Š็ทจ้›†ใ—ใŸใ‚Šใ™ใ‚‹ใฎใฏ่‹ฆ็—›ใซใชใ‚Šใพใ™ใŒใ€ใฉใฎIDEใงใ‚‚ๆ„Ÿ่ฌใ™ใ‚‹ใ“ใจใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ ๅคงใใชใƒ†ใ‚นใƒˆใƒ‡ใƒผใ‚ฟใŒใ‚ใ‚‹ๅ ดๅˆใฏใ€ใƒ†ใ‚นใƒˆใƒ•ใ‚กใ‚คใƒซใ‹ใ‚‰ๅ–ใ‚Šๅ‡บใ—ใพใ™ใ€‚



8ใ€‚



 const {assert} = require('chai'); const crypto = require('crypto'); describe('extraTests', ()=>{ it('should generate unique bytes', ()=>{ const arr = []; for (let i = 0; i < 1000; i++) { const value = crypto.randomBytes(256); arr.push(value); } const unique = arr.filter((el, index)=>arr.indexOf(el) === index); assert.equal(arr.length, unique.length, 'Data is not random enough!'); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
่ฟฝๅŠ ใƒ†ใ‚นใƒˆใ€‚



ใ“ใฎๅ ดๅˆใ€้–‹็™บ่€…ใฏ่‡ชๅˆ†ใฎไธ€ๆ„ใฎ่ญ˜ๅˆฅๅญใŒไธ€ๆ„ใซใชใ‚‹ใ“ใจใ‚’้žๅธธใซๅฟƒ้…ใ—ใฆใ„ใŸใŸใ‚ใ€ใ“ใฎใƒใ‚งใƒƒใ‚ฏใ‚’ไฝœๆˆใ—ใพใ—ใŸใ€‚ ไธ€่ˆฌใซใ€็†่งฃใงใใ‚‹้ก˜ๆœ›-ใ—ใ‹ใ—ใ€ใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚’่ชญใ‚€ใ‹ใ€ใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆใซ่ฟฝๅŠ ใ›ใšใซใใฎใ‚ˆใ†ใชใƒ†ใ‚นใƒˆใ‚’ๆ•ฐๅ›žๅฎŸ่กŒใ™ใ‚‹ใ“ใจใ‚’ใŠๅ‹งใ‚ใ—ใพใ™ใ€‚ ใ™ในใฆใฎใƒ“ใƒซใƒ‰ใงๅฎŸ่กŒใ—ใฆใ‚‚ๆ„ๅ‘ณใŒใ‚ใ‚Šใพใ›ใ‚“ใ€‚



ใ•ใฆใ€ใƒ†ใ‚นใƒˆใงใฎใƒฉใƒณใƒ€ใƒ ใชๅ€คใฎใƒใ‚ฏใ‚ฟใ‚คใฏใ€ใใ‚Œ่‡ชไฝ“ใ€ไธๅฎ‰ๅฎšใชใƒ†ใ‚นใƒˆใ‚’ใ‚ผใƒญใ‹ใ‚‰ไฝœๆˆใ™ใ‚‹ใ“ใจใซใ‚ˆใ‚Šใ€่‡ชๅˆ†่‡ช่บซใ‚’่ถณใงๆ’ƒใค็ด ๆ™ดใ‚‰ใ—ใ„ๆ–นๆณ•ใงใ™ใ€‚






9.ใƒขใƒƒใ‚ฏใฎๆฌ ๅฆ‚



ใƒฉใ‚คใƒ–ใƒ‡ใƒผใ‚ฟใƒ™ใƒผใ‚นใจ100ใฎใ‚ตใƒผใƒ“ใ‚นใงใƒ†ใ‚นใƒˆใ‚’ๅฎŸ่กŒใ—ใ€ใใ‚Œใ‚‰ใซๅฏพใ—ใฆใƒ†ใ‚นใƒˆใ‚’ๅฎŸ่กŒใ™ใ‚‹ๆ–นใŒใฏใ‚‹ใ‹ใซ็ฐกๅ˜ใงใ™ใ€‚

ใ—ใ‹ใ—ใ€้…ใ‹ใ‚Œๆ—ฉใ‹ใ‚ŒๅฎŸใ‚’็ตใณใพใ™-ใƒ‡ใƒผใ‚ฟๅ‰Š้™คใƒ†ใ‚นใƒˆใฏ่ฃฝๅ“ใƒ™ใƒผใ‚นใงๅฎŸ่กŒใ•ใ‚Œใ€ใƒ‘ใƒผใƒˆใƒŠใƒผใ‚ตใƒผใƒ“ใ‚นใฎ็ ดๆใซใ‚ˆใ‚ŠไฝŽไธ‹ใ—ๅง‹ใ‚ใพใ™ใ€‚ใพใŸใฏใ€CIใซใฏๅฎŸ่กŒใ™ใ‚‹ใŸใ‚ใฎใƒ™ใƒผใ‚นใŒใ‚ใ‚Šใพใ›ใ‚“ใ€‚ ไธ€่ˆฌ็š„ใซใ€ใ‚ขใ‚คใƒ†ใƒ ใฏ้žๅธธใซๅ…จไฝ“็š„ใงใ™ใŒใ€ๅŽŸๅ‰‡ใจใ—ใฆ-ๅค–้ƒจใ‚ตใƒผใƒ“ใ‚นใ‚’ใ‚จใƒŸใƒฅใƒฌใƒผใƒˆใงใใ‚‹ๅ ดๅˆใฏใ€ใใ‚Œใ‚’่กŒใ†ใ“ใจใ‚’ใŠๅ‹งใ‚ใ—ใพใ™ใ€‚



11ใ€‚



 const {assert} = require('chai'); class CustomError extends Error { } function mytestFunction() { throw new CustomError('important message'); } describe('badCompare', ()=>{ it('should throw only my custom errors', ()=>{ let errorHappened = false; try { mytestFunction(); } catch (err) { errorHappened = true; assert.isTrue(err instanceof CustomError); } assert.isTrue(errorHappened); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
่ค‡้›‘ใชใ‚จใƒฉใƒผใƒ‡ใƒใƒƒใ‚ฐใ€‚



ใ™ในใฆใŒๆ‚ชใ„ใ‚ใ‘ใงใฏใ‚ใ‚Šใพใ›ใ‚“ใŒใ€1ใคใฎๅ•้กŒใŒใ‚ใ‚Šใพใ™ใ€‚ใƒ†ใ‚นใƒˆใŒ็ช็„ถใ‚ฏใƒฉใƒƒใ‚ทใƒฅใ—ใŸๅ ดๅˆใ€ๆฌกใฎๅฝขๅผใฎใ‚จใƒฉใƒผใŒ่กจ็คบใ•ใ‚Œใพใ™ใ€‚



1) badCompare

should throw only my custom errors:



AssertionError: expected false to be true

+ expected - actual



-false

+true



at Context.it (test/011_badCompare/test.js:23:14)








ใ•ใ‚‰ใซใ€ๅฎŸ้š›ใซใฉใฎใ‚ˆใ†ใชใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใŸใ‹ใ‚’็†่งฃใ™ใ‚‹ใซใฏใ€ใƒ†ใ‚นใƒˆใ‚’ๆ›ธใ็›ดใ™ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ ใใฎใŸใ‚ใ€ไบˆๆœŸใ—ใชใ„ใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใŸๅ ดๅˆใฏใ€ใใ‚ŒใŒ็™บ็”Ÿใ—ใŸใจใ„ใ†ไบ‹ๅฎŸใ ใ‘ใงใชใใ€ใƒ†ใ‚นใƒˆใซใคใ„ใฆ่ฉฑใ—ใฆใ‚‚ใ‚‰ใ†ใ‚ˆใ†ใซใ—ใฆใใ ใ•ใ„ใ€‚






12ใ€‚



 const {assert} = require('chai'); function someVeryBigFunc1() { return 1; // imagine a tonn of code here } function someVeryBigFunc2() { return 2; // imagine a tonn of code here } describe('all Before Tests', ()=>{ let res1; let res2; before(async ()=>{ res1 = await someVeryBigFunc1(); res2 = await someVeryBigFunc2(); }); it('should return 1', ()=>{ assert.equal(res1, 1); }); it('should return 2', ()=>{ assert.equal(res2, 2); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
beforeใƒ–ใƒญใƒƒใ‚ฏใฎใ™ในใฆใ€‚



ใ€Œbeforeใ€ใƒ–ใƒญใƒƒใ‚ฏๅ†…ใฎใ™ในใฆใฎๆ“ไฝœใ‚’ๅฎŸ่กŒใ—ใ€ใ€Œitใ€ๅ†…ใซใƒใ‚งใƒƒใ‚ฏใฎใฟใ‚’ๆฎ‹ใ™ใฎใฏใ‚ฏใƒผใƒซใชใ‚ขใƒ—ใƒญใƒผใƒใฎใ‚ˆใ†ใงใ™ใ€‚

ใใ†ใงใ‚‚ใชใ„ใ€‚

ใ“ใฎๅ ดๅˆใ€ใƒ†ใ‚นใƒˆใฎๅฎŸ้š›ใฎๅฎŸ่กŒๆ™‚้–“ใ€่ฝไธ‹ใฎ็†็”ฑใ€ใ‚ใ‚‹ใƒ†ใ‚นใƒˆใซ้–ขไฟ‚ใ™ใ‚‹ใ‚‚ใฎใ€ๅˆฅใฎใƒ†ใ‚นใƒˆใซ้–ขไฟ‚ใ™ใ‚‹ใ‚‚ใฎใ‚’็†่งฃใงใใชใ„ๆททไนฑใŒใ‚ใ‚‹ใŸใ‚ใงใ™ใ€‚

ใ—ใŸใŒใฃใฆใ€ใ™ในใฆใฎใƒ†ใ‚นใƒˆไฝœๆฅญ๏ผˆๆจ™ๆบ–ใฎๅˆๆœŸๅŒ–ใ‚’้™คใ๏ผ‰ใฏใ€ใƒ†ใ‚นใƒˆ่‡ชไฝ“ใฎๅ†…้ƒจใงๅฎŸ่กŒใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚






13ใ€‚



 const {assert} = require('chai'); const moment = require('moment'); function someDateBasedFunction(date) { if (moment().isAfter(date)) { return 0; } return 1; } describe('useFutureDate', ()=>{ it('should return 0 for passed date', ()=>{ const pastDate = moment('2010-01-01'); assert.equal(someDateBasedFunction(pastDate), 0); }); it('should return 1 for future date', ()=>{ const itWillAlwaysBeInFuture = moment('2030-01-01'); assert.equal(someDateBasedFunction(itWillAlwaysBeInFuture), 1); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
ๆ—ฅไป˜ใง็ตใถใ€‚



ใใ‚Œใฏๆ˜Žใ‚‰ใ‹ใช้–“้•ใ„ใฎใ‚ˆใ†ใซใ‚‚ๆ€ใˆใพใ™ใŒใ€ๆ˜Žๆ—ฅใฏๆฑบใ—ใฆๆฅใชใ„ใจไฟกใ˜ใฆใ„ใ‚‹็–ฒใ‚ŒใŸ้–‹็™บ่€…ใฎ้–“ใงใ‚‚ๅฎšๆœŸ็š„ใซ็™บ็”Ÿใ—ใพใ™ใ€‚ ๆ˜จๆ—ฅใฏ้ †่ชฟใ ใฃใŸใƒ“ใƒซใƒ‰ใŒใ€ไปŠๆ—ฅใฏ็ช็„ถไฝŽไธ‹ใ—ใพใ™ใ€‚



ใ„ใšใ‚Œใ‹ใฎๆ—ฅไป˜ใŒ้…ใ‹ใ‚Œๆ—ฉใ‹ใ‚Œๆฅใ‚‹ใ“ใจใ‚’ๅฟ˜ใ‚Œใชใ„ใงใใ ใ•ใ„-ใ—ใŸใŒใฃใฆใ€ `sinon.fakeTimers`ใฎใ‚ˆใ†ใชใ‚‚ใฎใงๆ™‚้–“ใ‚จใƒŸใƒฅใƒฌใƒผใ‚ทใƒงใƒณใ‚’ไฝฟ็”จใ™ใ‚‹ใ‹ใ€ๅฐ‘ใชใใจใ‚‚2050ๅนดใฎใ‚ˆใ†ใชใƒชใƒขใƒผใƒˆๆ—ฅไป˜ใ‚’่จญๅฎšใ—ใฆใใ ใ•ใ„-ใ‚ใชใŸใฎๅญๅญซใ‚’ๅ‚ทใคใ‘ใฆใใ ใ•ใ„...






14ใ€‚





 describe('dynamicRequires', ()=>{ it('should return english locale', ()=>{ // HACK : // Some people mutate locale in tests to chinese so I will require moment here // eslint-disable-next-line global-require const moment = require('moment'); const someDate = moment('2010-01-01').format('MMMM'); assert.equal(someDate, 'January'); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
ใƒขใ‚ธใƒฅใƒผใƒซใฎๅ‹•็š„ใƒญใƒผใƒ‰ใ€‚



Eslintใ‚’ใŠๆŒใกใฎๅ ดๅˆใฏใ€ใŠใใ‚‰ใๆ—ขใซๅ‹•็š„ไพๅญ˜้–ขไฟ‚ใ‚’็ฆๆญขใ—ใฆใ„ใ‚‹ใงใ—ใ‚‡ใ†ใ€‚ ใ‹ใฉใ†ใ‹ใ€‚

ๅคšใใฎๅ ดๅˆใ€้–‹็™บ่€…ใฏใƒ†ใ‚นใƒˆๅ†…ใงใƒฉใ‚คใƒ–ใƒฉใƒชใพใŸใฏใ•ใพใ–ใพใชใƒขใ‚ธใƒฅใƒผใƒซใ‚’็›ดๆŽฅใƒญใƒผใƒ‰ใ—ใ‚ˆใ†ใจใ—ใฆใ„ใ‚‹ใ“ใจใŒใ‚ใ‹ใ‚Šใพใ™ใ€‚ ใ—ใ‹ใ—ใ€ๅฝผใ‚‰ใฏไธ€่ˆฌใซใ€Œrequireใ€ใŒใฉใฎใ‚ˆใ†ใซๆฉŸ่ƒฝใ™ใ‚‹ใ‹ใ‚’็Ÿฅใฃใฆใ„ใพใ™-ใ—ใ‹ใ—ใ€ๅฝผใ‚‰ใฏใ“ใ‚Œใพใง่ชฐใ‚‚ๆททไนฑใ—ใฆใ„ใชใ„ใ‚ฏใƒชใƒผใƒณใชใƒขใ‚ธใƒฅใƒผใƒซใ‚’ไธŽใˆใ‚‰ใ‚Œใ‚‹ใ“ใจใซใชใฃใฆใ„ใ‚‹ใจใ„ใ†ๅนปๆƒณใ‚’ๅฅฝใฟใพใ™ใ€‚

ใ“ใฎไปฎๅฎšใฏใ€ใƒ†ใ‚นใƒˆไธญใฎ่ฟฝๅŠ ใƒขใ‚ธใƒฅใƒผใƒซใฎใƒญใƒผใƒ‰ใŒ้…ใใ€ใ•ใ‚‰ใซๆœชๅฎš็พฉใฎๅ‹•ไฝœใ‚’ๅผ•ใ่ตทใ“ใ™ใจใ„ใ†็‚นใงๅฑ้™บใงใ™ใ€‚






15ใ€‚



 function someComplexFunc() { // Imagine a piece of really strange code here return 1; } describe('cryptic', ()=>{ it('success', ()=>{ const result = someComplexFunc(); assert.equal(result, 1); }); it('should not fail', ()=>{ const result = someComplexFunc(); assert.equal(result, 1); }); it('is right', ()=>{ const result = someComplexFunc(); assert.equal(result, 1); }); it('makes no difference for solar system', ()=>{ const result = someComplexFunc(); assert.equal(result, 1); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
็†่งฃใงใใชใ„ใƒ†ใ‚นใƒˆๅใ€‚



ๆ˜Žใ‚‰ใ‹ใชใ“ใจใซใ†ใ‚“ใ–ใ‚Šใ—ใฆใ„ใ‚‹ใฏใšใงใ™ใ‚ˆใญ๏ผŸ ใ—ใ‹ใ—ใ€ๅคšใใฎไบบใฏใƒ†ใ‚นใƒˆใฎใŸใ‚ใซใ‚ใ‹ใ‚Šใ‚„ใ™ใ„ๅๅ‰ใ‚’ๆ›ธใใ“ใจใ‚’ๆฐ—ใซใ—ใชใ„ใฎใงใ€ใใ‚Œใซใคใ„ใฆ่จ€ใ‚ใชใ‘ใ‚Œใฐใชใ‚Šใพใ›ใ‚“-็ตๆžœใจใ—ใฆใ€็‰นๅฎšใฎใƒ†ใ‚นใƒˆใŒๅคšใใฎ็ ”็ฉถใฎๅพŒใซใฎใฟ็†่งฃใ™ใ‚‹ใ“ใจใŒๅฏ่ƒฝใงใ™ใ€‚






16ใ€‚



 const {assert} = require('chai'); const Promise = require('bluebird'); function someTomeoutingFunction() { throw new Promise.TimeoutError(); } describe('no Error check', ()=>{ it('should throw error', async ()=>{ let timedOut = false; try { await someTomeoutingFunction(); } catch (err) { timedOut = true; } assert.equal(timedOut, true); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
ใ‚นใƒญใƒผใ•ใ‚ŒใŸใ‚จใƒฉใƒผใฎๆคœ่จผใฎๆฌ ๅฆ‚ใ€‚



ๅคšใใฎๅ ดๅˆใ€้–ขๆ•ฐใŒใ‚จใƒฉใƒผใ‚’ใ‚นใƒญใƒผใ™ใ‚‹ใ“ใจใ‚’็ขบ่ชใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ ใ—ใ‹ใ—ใ€ใ“ใ‚Œใ‚‰ใŒ็งใŸใกใŒๆŽขใ—ใฆใ„ใ‚‹ใƒ‰ใƒญใ‚คใƒ‰ใงใ‚ใ‚‹ใ‹ใฉใ†ใ‹ใ‚’ๅธธใซ็ขบ่ชใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™-ๅˆฅใฎๅ ดๆ‰€ใงใ€ไป–ใฎ็†็”ฑใงๅˆฅใฎใ‚จใƒฉใƒผใŒใ‚นใƒญใƒผใ•ใ‚ŒใŸใ“ใจใŒ็ช็„ถๅˆคๆ˜Žใ™ใ‚‹ๅฏ่ƒฝๆ€งใŒใ‚ใ‚‹ใŸใ‚...






17ใ€‚





 function someBadFunc() { throw new Error('I am just wrong!'); } describe.skip('skipped test', ()=>{ it('should be fine', ()=>{ someBadFunc(); }); });
      
      







ใ“ใ“ใงไฝ•ใŒๆ‚ชใ„ใฎ
็„กๅŠนใชใƒ†ใ‚นใƒˆใ€‚



ใ‚‚ใกใ‚ใ‚“ใ€ใ‚ณใƒผใƒ‰ใŒใ™ใงใซไฝ•ๅบฆใ‚‚ๆ‰‹ใงใƒ†ใ‚นใƒˆใ•ใ‚ŒใฆใŠใ‚Šใ€็ทŠๆ€ฅใซใƒญใƒผใƒซใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใ€ไฝ•ใ‚‰ใ‹ใฎ็†็”ฑใงใƒ†ใ‚นใƒˆใŒๆฉŸ่ƒฝใ—ใชใ„ๅ ดๅˆใ€็ŠถๆณใŒๅธธใซ็™บ็”Ÿใ™ใ‚‹ๅฏ่ƒฝๆ€งใŒใ‚ใ‚Šใพใ™ใ€‚ ใŸใจใˆใฐใ€ไปฅๅ‰ใซๆ›ธใ„ใŸๅˆฅใฎใƒ†ใ‚นใƒˆใฎๆ˜Žใ‚‰ใ‹ใช่ค‡้›‘ใ•ใฎใŸใ‚ใงใ™ใ€‚ ใใ—ใฆใ€ใƒ†ใ‚นใƒˆใฏใ‚ชใƒ•ใซใชใ‚Šใพใ™ใ€‚ ใ“ใ‚Œใฏๆญฃๅธธใงใ™ใ€‚ ๆญฃๅธธใงใฏใ‚ใ‚Šใพใ›ใ‚“-ใƒ†ใ‚นใƒˆใ‚’ใ‚ชใƒณใซๆˆปใ™ใ‚ฟใ‚นใ‚ฏใ‚’ใ™ใใซ่จญๅฎšใ—ใชใ„ใงใใ ใ•ใ„ใ€‚ ใ“ใ‚Œใ‚’่กŒใ‚ใชใ„ใจใ€็„กๅŠนๅŒ–ใ•ใ‚ŒใŸใƒ†ใ‚นใƒˆใฎๆ•ฐใŒๅข—ใˆใ€ใใ‚Œใ‚‰ใฎใ‚ณใƒผใƒ‰ใฏๅธธใซๆ™‚ไปฃ้…ใ‚Œใซใชใ‚Šใพใ™ใ€‚ ๅ”ฏไธ€ใฎ้ธๆŠž่‚ขใŒๆฎ‹ใ‚‹ใพใง-ๆ…ˆๆ‚ฒใ‚’็คบใ—ใ€ใ“ใ‚Œใ‚‰ใ™ในใฆใฎใƒ†ใ‚นใƒˆใ‚’ๆŠ•ใ’ใพใ™ใ€‚ใชใœใชใ‚‰ใ€้–“้•ใ„ใ‚’็†่งฃใ™ใ‚‹ใ‚ˆใ‚Šใ‚‚ใ‚‚ใ†ไธ€ๅบฆๆ›ธใๆ–นใŒ้€Ÿใ„ใ‹ใ‚‰ใงใ™ใ€‚






ใ“ใ“ใซใใฎใ‚ˆใ†ใช้ธๆŠžใŒๅ‡บใฆใใพใ—ใŸใ€‚ ใ“ใ‚Œใ‚‰ใฎใƒ†ใ‚นใƒˆใฏใ™ในใฆใƒ†ใ‚นใƒˆใซๅˆๆ ผใ—ใพใ™ใŒใ€่จญ่จˆไธŠ็ ดๆใ—ใฆใ„ใพใ™ใ€‚ ใ‚ณใƒกใƒณใƒˆใ€ใพใŸใฏใใฎใ‚ˆใ†ใช้–“้•ใ„ใ‚’ๅŽ้›†ใ™ใ‚‹ใŸใ‚ใซไฝœๆˆใ—ใŸใƒชใƒใ‚ธใƒˆใƒชใซใ‚ชใƒ—ใ‚ทใƒงใƒณใ‚’่ฟฝๅŠ ใ—ใพใ™ใ€‚



All Articles