Cucumber-js: ๊ธฐ๋Šฅ ์š”์ฒญ: `this` ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” UI

์— ๋งŒ๋“  2017๋…„ 01์›” 31์ผ  ยท  16์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: cucumber/cucumber-js

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ธ๊ณ„๊ฐ€ ์ฃผ์–ด์ง‘๋‹ˆ๋‹ค.

require('cucumber').defineSupportCode( ({setWorldConstructor:world}) => {
    world(class { 
      constructor(p) { ... }
      foo(bar) { return new Promise(.... ) }
    })
})

๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ•œ๋‹ค.

  When(/^I do the foo with (.*)$/i, (ctx, bar) => ctx.foo(bar) );

๋Œ€์‹ ์—

  When(/^I do the foo with (.*)$/i, function(bar) {
      return this.foo(bar)
  });

์ด๊ฒƒ์€ ๋˜ํ•œ ๋ชจ๋“  ๋น„๋™๊ธฐ ์ž‘์—…์—์„œ .bind(this) ์„ ๋ฉํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์„ ์—†์• ๊ฑฐ๋‚˜ ์›ํ•˜๋Š” ๊ฒฝ์šฐ var that = this ๋กœ ๋ฉํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

๋˜ ํ•˜๋‚˜์˜ ์ด์ (IMHO) - ์‚ฌ๋žŒ๋“ค์ด ์„ธ๊ณ„์— ๋Œ€ํ•œ ์ƒ์† ํŠธ๋ฆฌ์—์„œ ๋ฒ—์–ด๋‚˜ JS์˜ ๋” ๋‚˜์€ ๊ธฐ๋Šฅ์„ ๋” ์ž˜ ์ง€ํ–ฅํ•˜๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

accepted enhancement

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๊ดœ์ฐฎ์•„. ๋ชจ๋“  ์‚ฌ๋žŒ์ด ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” ์•„๋‹ˆ์ง€๋งŒ ๋ธŒ๋ ˆ์ดํ‚น ์ฒด์ธ์ง€ ๋„์ž…์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์„ธ๊ณ„๋ฅผ ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋Š” ์˜ต์…˜์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”?

defineSupportCode(({setWorldInjectionStrategy}) => {
  setWorldInjectionStrategy('this') // default
  setWorldInjectionStrategy('argument') // makes world be the first argument to steps and hooks 
})

๋ชจ๋“  16 ๋Œ“๊ธ€

๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋‹น์‹ ์ด ํ•ญ์ƒ world ๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„๋“ค์ธ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ ๊ทธ๊ฒƒ์ด API ๋ณ€๊ฒฝ์ด๋ผ๋Š” ๊ฒƒ์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.
--ui exports ๋ฐ --ui tdd ๋ฐ --ui bdd ๊ฐ€ ์žˆ๋Š” ๋ชจ์นด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํํ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹จ๊ณ„๊ฐ€ ์„ธ๊ณ„์—์„œ ํ˜ธ์ถœ/์ ์šฉ๋˜๋Š”์ง€ ๋˜๋Š” ์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ˆ˜๋ฝํ•˜๋Š”์ง€ ๊ฒฐ์ •ํ•˜๋Š” ํ”„๋กœ์ ํŠธ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ์žฅ๊ธฐ์ ์œผ๋กœ ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ, => ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” 1์ค„ ๋‹จ๊ณ„์— ์ข‹์Šต๋‹ˆ๋‹ค. ์ œ ๊ฒฝํ—˜์ƒ ์ด๋Ÿฐ ๋‹จ๊ณ„๋Š” ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ES6์— ์ปจํ…์ŠคํŠธ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š” ํ™”์‚ดํ‘œ ๊ธฐ๋Šฅ์ด ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋Š” ์‚ฌ์‹ค์— ๋†€๋ž์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋˜ํ•œ ๋ชจ๋“  ๋น„๋™๊ธฐ ์ž‘์—…์—์„œ .bind(this) ์„ ๋ฉ ๋•Œ๋ฆฌ๋Š” ๊ฒƒ์„ ์—†์• ๊ฑฐ๋‚˜ ์›ํ•˜๋Š” ๊ฒฝ์šฐ var that = this ๋กœ ๋ฉํ‚ค๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋‹จ๊ณ„ ์ •์˜ ์•ˆ์— ๊ตต์€ ํ™”์‚ดํ‘œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๊นŒ?

๋˜ ํ•˜๋‚˜์˜ ์ด์ (IMHO) - ์‚ฌ๋žŒ๋“ค์ด ์„ธ๊ณ„์— ๋Œ€ํ•œ ์ƒ์† ํŠธ๋ฆฌ์—์„œ ๋ฒ—์–ด๋‚˜ JS์˜ ๋” ๋‚˜์€ ๊ธฐ๋Šฅ์„ ๋” ์ž˜ ์ง€ํ–ฅํ•˜๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ์ข€ ๋” ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? / ์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ, ์ €๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ํด๋ž˜์Šค๋กœ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ์‹์„ ๊ธฐํ”ผํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ ํ•™๊ต์— ์†ํ•ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด OOP์˜ ์–ด๋‘์šด ๋ฉด์— ๋…ธ์ถœ๋ ์ˆ˜๋ก ์ด ํ•™๊ต๋Š” ๋” ์ปค์ง‘๋‹ˆ๋‹ค. ํ™”์‚ดํ‘œ ๊ธฐ๋Šฅ์ด ์ปจํ…์ŠคํŠธ๋ฅผ ์œ ์ง€ ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰๋Š” JS ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ์›€์ง์ž„์€ ์ด ์›€์ง์ž„์˜ ๊ฐ•์ ์„ ๋ณด์—ฌ์ฃผ๋Š” ํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

์ข…๊ต์ ์ธ ๋…ผ์Ÿ์— ๋ผ์–ด๋“ค์ง€ ์•Š๊ณ  - ๋‚œ ๊ทธ๋ƒฅ ๋ผ์ด๋ธŒ๋ฅผ ๋ฏฟ๊ณ  ๋ผ์ด๋ธŒํ•˜์ž, ๋‹น์‹ ์€ ์ˆ˜์—…์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์–ด? ์—„์ฒญ๋‚œ. ์ €๋ฅผ ๊ฐ•์ œํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค :-)

์ œ ์ผ๋ฐ˜์ ์ธ ๋Š๋‚Œ์€ ์ž‘์€ ๋ณ€ํ™”๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ž˜ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฐฉํ–ฅ์„ ์•Œ๋ ค์ฃผ์‹œ๋ฉด ๊ธฐ๊บผ์ด ํ• ๊ฒŒ์š” ;-)

๋‹จ๊ณ„๋ฅผ ์ •์˜ํ•  ๋•Œ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๋ผ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋ฏ€๋กœ ๋…ผ๋ฆฌ์ ์œผ๋กœ this ๋Š” ๊ทธ ์ž๋ฆฌ์— ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด OOP ํŒจ๋Ÿฌ๋‹ค์ž„์ด ์•„๋‹Œ FP ํŒจ๋Ÿฌ๋‹ค์ž„์˜ ์ƒํ™ฉ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@osher ๋‚˜๋Š” @charlierudolph ๊ฐ€ ๋‹น์‹ ์—๊ฒŒ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฐ•์š”ํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋Š” ์˜์‹ฌ์˜ ์ด์ ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์‹ค์งˆ์ ์ธ ์ด์ ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ํ•œ ์ด ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ๊ณณ์—์„œ API ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฐ•์ œ๋กœ ํ†ตํ•ฉ(์ค‘๋‹จ)ํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

@charlierudolph ๋‚ด ์ƒ๊ฐ์— "JS์˜ ๋” ๋‚˜์€ ๋Šฅ๋ ฅ" @osher ๋Š” FP, Functional Programming์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

IMHO ์ด ๋ณ€๊ฒฝ์€ ๋‹จ๊ณ„ ์ •์˜๋ฅผ ์กฐ๊ธˆ ๋” ๊ฐ„๋‹จํ•˜๊ณ  ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹ค์Œ ์ค„์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. const thisWorldNotThisStep = this

๋ชจ๋“  ๋น„๋™๊ธฐ ํ•จ์ˆ˜์— ๋Œ€ํ•ด .bind(this) ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ๋‹จ๊ณ„ ์ •์˜ ๋‚ด์—์„œ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•œ const self = this ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ(ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹˜)๋Š” ๋‹จ๊ณ„ ์ •์˜ ๋‚ด์—์„œ this ๊ฐ€ ๋‹จ๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ ์„ธ๊ณ„๋ฅผ ์ฐธ์กฐํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์ง๊ด€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ดœ์ฐฎ์•„. ๋ชจ๋“  ์‚ฌ๋žŒ์ด ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” ์•„๋‹ˆ์ง€๋งŒ ๋ธŒ๋ ˆ์ดํ‚น ์ฒด์ธ์ง€ ๋„์ž…์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์„ธ๊ณ„๋ฅผ ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋Š” ์˜ต์…˜์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”?

defineSupportCode(({setWorldInjectionStrategy}) => {
  setWorldInjectionStrategy('this') // default
  setWorldInjectionStrategy('argument') // makes world be the first argument to steps and hooks 
})

๋‚˜๋Š” ์„ธ๊ณ„/์ปจํ…์ŠคํŠธ๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค๋Š” ์•„์ด๋””์–ด์— ์ „์ ์œผ๋กœ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ๊ณ„์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘์œผ๋กœ ๋ชจ๋“  JS ์ƒํƒœ๊ณ„๋Š” ES6์—์„œ ํ—ˆ์šฉํ•˜๋Š” ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์™„์ „ํžˆ ์ˆ˜์šฉํ•˜๋„๋ก ์›€์ง์ด๊ณ  ์žˆ์œผ๋ฉฐ ์ด๋Š” ์ข‹์€ ์ผ์ž…๋‹ˆ๋‹ค โค๏ธ

Express๋‚˜ Koa์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๋„๊ตฌ๋ฅผ ๋ณด๋ฉด ํ˜„์žฌ ์š”์ฒญ ์ปจํ…์ŠคํŠธ๋ฅผ this ๋กœ ์„ค์ •ํ•˜๊ณ  ๋ฏธ๋“ค์›จ์–ด์˜ ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค(์˜ค์ด ๋‹จ๊ณ„์™€ ๋™์ผ). ์ด ์†”๋ฃจ์…˜์€ ๊ธฐ๋Šฅ์˜ ์ „ํ†ต์ ์ธ ์‚ฌ์šฉ๊ณผ ES6 ํ™”์‚ดํ‘œ ๊ธฐ๋Šฅ์˜ ์‚ฌ์šฉ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.
์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ์„œ์˜ ์ปจํ…์ŠคํŠธ์˜ ๋˜ ๋‹ค๋ฅธ ์ด์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@charlierudolph๊ฐ€ ์ œ์•ˆํ•œ ์†”๋ฃจ์…˜์˜ ๊ฒฝ์šฐ ์ด๊ฒƒ์ด ์žฅ๊ธฐ์ ์œผ๋กœ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ๋‘˜๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์˜ค์ด ์˜ˆ์ œ๋Š” ๋ชจ๋“  ์„ค์น˜์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ฌธ์„œ๋Š” ๋‘ ๊ฐœ๋กœ ๋ณต์ œ๋ฉ๋‹ˆ๋‹ค. ๋ฉ‹์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ธŒ๋ ˆ์ดํ‚น ์ฒด์ธ์ง€ ๊ฑฑ์ •์€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ v2๋Š” ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ๋ณ€๊ฒฝ์„ ์†Œ๊ฐœํ•˜๊ธฐ์— ์™„๋ฒฝํ•œ ์‹œ๊ธฐ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋‹ค๋ฆผ์€ ๋‹ค๋ฅธ ์ „๊ณต์„ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Before ๋ฐ After ๋ฅผ world ์ฃผ์ž…ํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

defineSupportCode(function({After, Before, Given}) {
  let world;

  // Asynchronous Callback
  Before(function (w, scenarioResult, callback) {
    world = w;
    callback();
  });
  After(function (world, scenarioResult, callback) {
    callback();
  });

  Given('I access the world', () => {
    assert(world); // Yay!
  });
});

๊ทธ๋Ÿฐ ์‹์œผ๋กœ before ๋‹จ๊ณ„์—์„œ world ๋ณ€์ˆ˜๋ฅผ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ๋‹จ๊ณ„ ์ •์˜๋ฅผ ์—‰๋ง์œผ๋กœ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ ๊ธฐ์กด ์ž‘์—… ๋ฐฉ์‹์„ ์œ ์ง€ํ•˜๋ฉด์„œ deprecated ๋ฉ”์‹œ์ง€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š๋”๋ผ๋„ ํ•ด๋‹น ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์ž์‹ ์ด ๋ฌด์—‡์„ ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ์˜ต์…˜์„ ๋‚จ๊ฒจ๋‘์‹ญ์‹œ์˜ค.

์˜จ๋ผ์ธ์—์„œ ๋ฐœ๊ฒฌ๋œ ์Šค๋‹ˆํŽซ์˜ ํ˜ธํ™˜์„ฑ์— ๋Œ€ํ•œ ๋…ผ์Ÿ์ด ์„ค๋“๋ ฅ ์žˆ๋Š” ๋…ผ์Ÿ์ด ๋ ๊นŒ๋ด ๋‘๋ ต์Šต๋‹ˆ๋‹ค.

--ui ํ”Œ๋ž˜๊ทธ ๋˜๋Š” setWorldInjectionStrategy('argument') ๊ฐ€ ์žˆ๋”๋ผ๋„ ๋ชจ๋“  ์˜จ๋ผ์ธ ํ† ๋ก ๊ณผ ๊ทธ๋Ÿฌํ•œ ๋ณ€๊ฒฝ์— ์ ํ•ฉํ•œ ์†Œ๋ž€์„ ์ œ๊ณตํ•˜๋Š” ์ฃผ์š” ๋ฒ„์ „์˜ ๋ธŒ๋ ˆ์ดํ‚น ์ฒด์ธ์ง€๋กœ ๋” ์ž˜ ์ „๋‹ฌ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ํ˜ผ๋ž€์„ ์—†์• ๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋‚˜๋Š” cuke์˜ ๋‹ค์Œ ๋ฒ„์ „์—์„œ ๊ทธ๊ฒƒ์„ ํ•˜๋Š” ๊ฒƒ์— ํˆฌํ‘œํ•˜๊ณ , ๊ทธ๊ฒƒ์ด ๋ฆด๋ฆฌ์Šค๋  ๋•Œ๊นŒ์ง€ ...makedoingํ•ฉ๋‹ˆ๋‹ค.

์นด๋‚˜๋ฆฌ์•„ ๋ฒ„์ „ ๋˜๋Š” ์ˆจ๊ฒจ์ง„ ํ”Œ๋ž˜๊ทธ๋Š” ์ดˆ๊ธฐ์— ์‚ฌ์šฉํ•˜๊ณ  ํ”ผ๋“œ๋ฐฑํ•  ๋ฉ‹์ง„ ํ”„๋กœ๋ชจ์…˜์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋Œ€์ฒด FP ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ณต๊ฐœํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? (์•ฝ์† ์นœํ™”์ ์ž„์„ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด async/await ์‚ฌ์šฉ)

import {initialize, Given, Before} from 'cucumber/fn'

// specify a function that returns the initial context:
initialize(async () => ({ a: 42 }))

Before({ timeout: 10 }, async (ctx) => {
  await doStuff(ctx.a)
})

Given(/^a step passes with {number}$/, async (ctx, number) => {
  const newA = await computeStuff(ctx.a, number)
  // tell cucumber about the new context:
  return Object.assign({}, ctx, { a: newA })
})

๊ธฐ๋Šฅ์  ๋‹จ๊ณ„ ์ •์˜๋ฅผ ์ œ๊ณตํ•˜๋Š” ์˜ค์ด -fp๋ฅผ ํ•จ๊ป˜ ํ•ดํ‚นํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ๋ช‡ ๊ฐ€์ง€ ๊ฐœ์„  ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”ผ๋“œ๋ฐฑ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!

๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ด ๋ฌธ์ œ๋ฅผ ๋‹ซ๊ณ  ์‚ฌ๋žŒ๋“ค์ด ๊ทธ ์ž‘์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‹คํ—˜ํ•˜๋„๋ก ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ์–ธ์  ๊ฐ€ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ Cucumber.js๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@jbpros ํ…Œ์ŠคํŠธ์—์„œ ํ™”์‚ดํ‘œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋˜ ๋‹ค๋ฅธ ์ข…์†์„ฑ์„ ์„ค์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ๋ชจ๋“  ์‚ฌ๋žŒ์ด ์Šค์Šค๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ๊ฐ„๋‹จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“œ๋Š” ํฐ ๊ฒฝ๊ณ ์™€ ํ•จ๊ป˜ (๊ธฐ๋Šฅ์ ์œผ๋กœ) ๋งค์šฐ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

// Don't rely on `this` in step definitions. It's 2021 for crying out loud.
const definitionFunctionWrapper = (fn) =>
    function(...args) {
        return fn(...args.slice(0, -1), this);
    }

๋ชจ๋“  ๋‹จ์ผ ๋‹จ๊ณ„ ์ •์˜๋ผ๋Š” ๊ฒฝ๊ณ ๋Š” ์ด์ œ ์ถ”๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ธํ•ด ๋‹ค์Œ ์˜ค๋ฅ˜๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

    Error: function uses multiple asynchronous interfaces: callback and promise
       to use the callback interface: do not return a promise
       to use the promise interface: remove the last argument to the function

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ•˜๋ฉด

function has 3 arguments, should have 1 (if synchronous or returning a promise) or 2 (if accepting a callback)

์˜ค์ด-js๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์€ ํ•จ์ˆ˜ ์ธ์ˆ˜ ๊ฒ€์‚ฌ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ์˜ต์…˜์ด๋ฉฐ ์ด ๋ฌธ์ œ๋Š” ์‚ฌ๋ผ์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋‘ ๋ฒˆ์งธ ์ƒ๊ฐ์— ์˜ค์ด๋Š” ๋‹จ๊ณ„ ์ •์˜ ํ•จ์ˆ˜์˜ ์ธ์ˆ˜ ์ˆ˜์— ๋”ฐ๋ผ ์ฝœ๋ฐฑ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฐ˜ํ™˜๋œ ์•ฝ์†์— ์šฐ์„  ์ˆœ์œ„๋ฅผ ๋ถ€์—ฌํ•˜๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@andyearnshaw ๊ท€ํ•˜์˜ ์˜๊ฒฌ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. "stepdef์˜ ํ™”์‚ดํ‘œ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ" ์ข…์†์„ฑ์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์šฐ๋ ค๋ฅผ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒํƒœ ๋น„์ €์žฅ ๋‹จ๊ณ„ ์ •์˜๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๊ฐœ์ธ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. ๊ด€์‹ฌ ์žˆ๋Š” ์‚ฌ๋žŒ์„ ์œ„ํ•ด ํŒจํ‚ค์ง€๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์ฝ”์–ด์—์„œ ์ด๋Ÿฌํ•œ ์ˆœ์ˆ˜ํ•œ stepdef API์— ๋Œ€ํ•œ ์ง€์†์ ์ธ ๋…ผ์Ÿ์— ๋Œ€ํ•œ ์ž„์‹œ ์†”๋ฃจ์…˜์œผ๋กœ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค(๋ฏฟ๊ฑฐ๋‚˜ ๋ง๊ฑฐ๋‚˜). ๋‚ด๊ฐ€ ๋งํ–ˆ๋“ฏ์ด ์ด๊ฒƒ์€ ์–ด๋Š ์‹œ์ ์—์„œ ํ•ต์‹ฌ์— ์ฐฉ๋ฅ™ํ•  ์ˆ˜ ์žˆ๋Š” ์‹คํ—˜์ด๋ฉฐ ์‹ค์ œ๋กœ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ํ”ผ๋“œ๋ฐฑ์„ ์ •๋ง ๊ฐ์‚ฌํ•˜๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ฒฌ์ธ๋ ฅ์ด ์ถฉ๋ถ„ํ•˜๋‹ค๋ฉด ์˜ค์ด์— ํ†ตํ•ฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ๋…ผ๊ฑฐ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ tap() ๋ฐ ๊ฐ•์ œ ์ฝ๊ธฐ ์ „์šฉ ์ปจํ…์ŠคํŠธ์™€ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ (์ž‘์€) ์œ ์šฉํ•œ ๊ธฐ๋Šฅ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

stepdef ํ•จ์ˆ˜์— ๋Œ€ํ•œ arity ๊ฒ€์‚ฌ๋Š” ํ™•์‹คํžˆ ์ด lib์—์„œ (๋งค์šฐ ์ถ”์•…ํ•œ ๋ฐฉ์‹์œผ๋กœ) ์šฐํšŒํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. CLI์™€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹ ๋ชจ๋‘์—์„œ ์ด ๊ธฐ๋Šฅ์„ ๋„๋Š” ์˜ต์…˜์€ ์ด ์ž‘์—…(๋ฐ ์ž ์žฌ์ ์œผ๋กœ ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‚ฌ๋ก€)์— ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ์‹ถ์ง€๋งŒ ํ˜„์žฌ๋กœ์„œ๋Š” ์‹œ๊ฐ„์ด ๋ถ€์กฑํ•œ ์ž์›์ž…๋‹ˆ๋‹ค.

๊ทธ ๋™์•ˆ arity ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ์˜ค์ด-fp์—์„œ ์ž์œ ๋กญ๊ฒŒ ์˜๊ฐ์„ ์–ป์œผ์‹ญ์‹œ์˜ค.

@jbpros ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹น์‹ ์ด ๊ฑฐ๊ธฐ์—

@andyearnshaw ํ•˜ ๋งž์Šต๋‹ˆ๋‹ค. ์„ค๋ช… ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ด ์•„์ด๋””์–ด๋ฅผ ๋ฒ„๋ ค์„œ๋Š” ์•ˆ ๋˜๋ฉฐ ์ด ๋ฌธ์ œ๋ฅผ ๊ณต๊ฐœ์ ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์•„๋งˆ๋„ ์ผ์„ ํˆฌ๋ช…ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ผ ๊ฒƒ์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰