Cucumber-js: ์ œ์•ˆ: ์˜ค์ด-js ์‹คํ–‰์„ ์œ„ํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ API

์— ๋งŒ๋“  2021๋…„ 06์›” 28์ผ  ยท  29์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: cucumber/cucumber-js

๋ฌธ์ œ

ํ˜„์žฌ ์šฐ๋ฆฌ๋Š” ์˜ค์ด-js๋ฅผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์‹คํ–‰ํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€ ๊ฐ๋„์—์„œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • ์˜ค์ด-js ํ…Œ์ŠคํŠธ - ํ”„๋กœ์ ํŠธ์˜ CCK ๋ฐ ์Šน์ธ ํ…Œ์ŠคํŠธ์šฉ
  • ์‚ฌ์šฉ์ž ์ •์˜ ํฌ๋งทํ„ฐ ๋ฐ ์Šค๋‹ˆํŽซ ํ…Œ์ŠคํŠธ
  • ์˜ค์ด-js๋ฅผ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ(์˜ˆ: Serenity, Stryker)

๊ทธ๋Œ€๋กœ

ํ˜„์žฌ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝํ–ฅ์€ Cli ์˜ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ strung-together argv ์ž…๋ ฅ์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ๋งค์šฐ ์–ด์ƒ‰ํ•˜๊ณ  ๊ณต๊ฐœ API ์—๋„

๋•Œ๋•Œ๋กœ (์œ„์˜ ์ธ์‹๋œ ์ทจ์•ฝ์„ฑ ๋•Œ๋ฌธ์—) ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์˜ค์ด-js CLI์—๋งŒ ์˜์กดํ•˜์ง€๋งŒ ํ†ตํ•ฉ ๋ฐฉ๋ฒ•์„ ์ฐพ๊ณ  ๊ณ ์œ ํ•œ ์˜ต์…˜์„ ๊ฐ–๋Š” ๋ฐ ์–ด๋ ค์›€์„ ๊ฒช์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Runtime ํด๋ž˜์Šค ๋Š” ํ˜„์žฌ ๊ณต๊ฐœ API์˜ ์ผ๋ถ€์ด์ง€๋งŒ ํ˜ธ์ถœ์ž๊ฐ€ ์ œ๊ณตํ•  ํ”ผํด ๋ฐ ์ง€์› ์ฝ”๋“œ์— ๋”ฐ๋ผ ์ด๋Ÿฌํ•œ ์ปจํ…์ŠคํŠธ์—์„œ๋Š” ์œ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ œ์•ˆ

ํ”„๋กœ์ ํŠธ์˜ ๋‘ ๊ฐ€์ง€ ๊ตฌ์„ฑ ์š”์†Œ:

runCucumber

ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ ํ…Œ์ŠคํŠธ ์‹คํ–‰์„ ์‹คํ–‰ํ•˜๋Š” ์ƒˆ๋กœ์šด ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ฑ…์ž„:

  • ๋ฉ‹์ง„ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์˜ต์…˜ ๊ฐ์ฒด๋ฅผ ์ˆ˜๋ฝํ•˜์‹ญ์‹œ์˜ค.
  • ํ”ผํด์„ ํ•ด๊ฒฐํ•˜๊ณ , ์ง€์› ์ฝ”๋“œ๋ฅผ ๋กœ๋“œํ•˜๊ณ , ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ํฌ๋งทํ„ฐ๋ฅผ ์กฐ์ •ํ•˜๋Š” "์ž‘์—…"์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฒฐ๊ณผ๋กœ ํ•ด๊ฒฐ๋˜๋Š” ์•ฝ์†์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ณต๊ฐœ API์˜ ์ผ๋ถ€๊ฐ€ ๋  ๊ฒƒ์ด๋ฉฐ ์šฐ๋ฆฌ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ ์œ ์ง€ ๊ด€๋ฆฌ์ž๊ฐ€ ์˜ค์ด-js๋ฅผ "๋ž˜ํ•‘"ํ•  ๋•Œ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ์šฐ๋ฆฌ ์ž์‹ ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ€๋Šฅํ•œ ํ•œ process ์™€์˜ ์ง์ ‘์ ์ธ ์ƒํ˜ธ ์ž‘์šฉ์„ ํ”ผํ•˜๋Š” ๋Œ€์‹  ์ถœ๋ ฅ์„ ์œ„ํ•ด ์ •๊ทœํ™”๋œ ์˜ต์…˜๊ณผ ์ŠคํŠธ๋ฆผ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ˆ˜๋ฝํ•˜๊ณ  ๊ฒฐ๊ณผ ๋˜๋Š” ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์˜ค๋ฅ˜์— ๋”ฐ๋ผ ์ข…๋ฃŒ ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ํ˜ธ์ถœ์ž์—๊ฒŒ ๋งก๊น๋‹ˆ๋‹ค.

๋˜ํ•œ Runtime ๋Š” ์‹ค์ œ๋กœ ๋‚ด๋ถ€์ ์ธ ๊ฒƒ์ด๋ฏ€๋กœ ๊ณต๊ฐœ API์—์„œ ๋‚˜์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

CLI

์‚ฌ์‹ค์ƒ runCucumber ์˜ "ํด๋ผ์ด์–ธํŠธ"์ž…๋‹ˆ๋‹ค. ์ฑ…์ž„:

  • ๋‹ค์–‘ํ•œ ์†Œ์Šค(argv, env vars, config ํŒŒ์ผ)์˜ ์˜ต์…˜ ์ง‘๊ณ„( ์ฃผ์„ ์ฐธ์กฐ)
  • ํ•ด๊ฒฐ๋œ ์˜ต์…˜์œผ๋กœ runCucumber ์ „ํ™”
  • ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ์ ์ ˆํ•˜๊ฒŒ ์ข…๋ฃŒ

์ด๊ฒƒ์€ ๊ณ„์†ํ•ด์„œ ๊ณต๊ฐœ API์— ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ๊ธฐ๋Šฅ ๊ณต๊ฐœ API์—์žˆ๋Š” / ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ด ๊ฐ™์€ ํ”„๋กœ์ ํŠธ์— ์ง€๊ธˆ์ฒ˜๋Ÿผ ์šฐ๋ฆฌ๊ฐ€ ์‰ฝ๊ฒŒ, ์–ด๋–ค ์ ์—์„œ ์ž์‹ ์˜ ํŒจํ‚ค์ง€๋กœ ๊ทธ๊ฒƒ์„ ๊นฐ ์ˆ˜ ์žˆ๋„๋ก ๋†๋‹ด .

์ด ๋ถ„๋ฆฌ๋Š” ๋˜ํ•œ ๋‚ด๋ถ€๋กœ ํ˜๋Ÿฌ ๋“ค์–ด๊ฐ€์ง€ ์•Š๊ณ  ๋ช‡ ๊ฐ€์ง€ ํฅ๋ฏธ๋กœ์šด ์ƒˆ๋กœ์šด CLI ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ๊ธธ์„ ์—ด์–ด์ค๋‹ˆ๋‹ค. ์˜ˆ:

  • --gui ์˜ค์ด-์ „์ž ์žฌ๋ฃŒ
  • --interactive TDD ์‹œ ๋น ๋ฅธ ๋Œ€์ƒ ์žฌ์‹คํ–‰

๋“ฑ

๋˜ํ•œ ๋‹ค์Œ์„ ์œ„ํ•œ ๊ธฐ๋Šฅ(CLI ๋ฐ ๊ธฐํƒ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

  • ์˜ต์…˜ ๊ฐ€์ ธ์˜ค๊ธฐ
  • i18nKeywords ๋ฐ i18nLanguages

ํƒ€์ž„์Šค์ผ€์ผ

๋‹ค๊ฐ€์˜ค๋Š” 8.0.0 ๋ฆด๋ฆฌ์Šค์—์„œ ์ด๋ฅผ ๋ชฉํ‘œ๋กœ ์‚ผ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ค๋Š˜ ์‹œ์ž‘ํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

breaking change enhancement

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

์ถœ๋ ฅ ํŒŒ์ผ ์ด๋ฆ„์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ธฐ์ž์—๊ฒŒ ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ• ๊นŒ์š”?

formats: {
    stdout: './my-awesome-stryker-formatter',
    files: {
      'report.html': './my/fancy-reporter.js',
      'other-report.html': '@me/reporter-package',
    }
  },

(ํ•˜๋‚˜์˜ ํฌ๋งทํ„ฐ๋งŒ stdout ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ)

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

์ดˆ๊ธฐ ํ”ผ๋“œ๋ฐฑ์„ ์œ„ํ•œ ํŽ˜์ด์ง•: @aslakhellesoy @charlierudolph @aurelien- reeves @mattwynne @nicojs @jan-molak

๋‚˜๋Š” ์ด ์ œ์•ˆ์„ ์ข‹์•„ํ•œ๋‹ค! ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ fake-cucumber์˜ runCucumber ์—์„œ ์ด์™€ ๊ฐ™์€ API๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@davidjgoss - ์ž˜ ๋“ค๋ฆฝ๋‹ˆ๋‹ค!

์ฐธ๊ณ ๋กœ Serenity/JS๊ฐ€ ํ˜„์žฌ Cucumber๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. CucumberCLIAdapter
๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ์€ ๊ตฌ์„ฑ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ argv - CucumberOptions ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋…ผ๋ฆฌ์ž…๋‹ˆ๋‹ค.

argv ๋Œ€์‹  options ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ํ›จ์”ฌ ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค ๐Ÿ‘๐Ÿป

์‚ฌ๋ž‘ํ•ด!

์ƒˆ๋กœ์šด ๊ณต๊ฐœ API๋ฅผ ์ง€์ •ํ•˜๋Š” ๋™์•ˆ ๋ฌธ์ œ #1489์—์„œ ์ตœ๊ทผ์— ๋ฐœ์ƒํ•œ ์ผ์„ ๊ณ ๋ คํ•˜๊ณ  ํ…Œ์ŠคํŠธ ์ค‘์ธ ํ•„ํ„ฐ ๋ฐ ๊ฒฐ๊ณผ ๊ธฐ๋Šฅ๊ณผ ๋” ๋งŽ์€ ์ƒํ˜ธ ์ž‘์šฉ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๊ณต๊ฐœ API๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ๋ง๋ถ™์—ฌ์„œ Cucumber-Electron๋„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ณต๊ฐœ API๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ด ์—†๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚ซ์Šต๋‹ˆ๋‹ค. ๊ณ„์†ํ•˜์„ธ์š” ๐Ÿ‘!

๋ฐ”๋žŒ์งํ•˜๊ฒŒ๋Š” cucumber-js ์™€ ๋™์ผํ•œ ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœํ•„์„ ๋กœ๋“œํ•˜๋Š” API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ผ๋ฐ˜์ ์ธ cucumber-js ํ˜ธ์ถœ์˜ ์ •ํ™•ํ•œ ๋™์ž‘์„ ๋ชจ๋ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

loadProfiles(directory = process.cwd()): Record<string, Profile>

StrykerJS๋Š” ๋˜ํ•œ custom_formatters API์™€ eventBroadcaster ๊ฒŒ์‹œํ•œ ์ด๋ฒคํŠธ์— ํฌ๊ฒŒ ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ๊ณต๊ฐœ API์—๋„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ฐธ์กฐ: https://github.com/stryker-mutator/stryker-js/blob/03b1f20ed933d3a50b52022cfe363c606c2b16c5/packages/cucumber-runner/src/stryker-formatter.ts#L45 -L69

๊ฐ€๋Šฅํ•˜๋ฉด ๋‚˜๋Š” ์˜ค์ด-js์™€ ๋™์ผํ•œ ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœํ•„์„ ๋กœ๋“œํ•˜๋Š” API๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์ผ๋ฐ˜์ ์ธ ์˜ค์ด-js ํ˜ธ์ถœ์˜ ์ •ํ™•ํ•œ ๋™์ž‘์„ ๋ชจ๋ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ข‹์€ ์ ์ž…๋‹ˆ๋‹ค. ํ”„๋กœํ•„(์ตœ์†Œํ•œ ํ˜„์žฌ ํ˜•์‹)์€ ๊ธฐ๋ณธ์ ์œผ๋กœ CLI์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ๊ฒฝ๊ณ„์˜ ์ธก๋ฉด์— ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์˜ณ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ํ”„๋กœํ•„์„ ๋กœ๋“œํ•˜๊ณ  ๋ถ€๋ถ„ ์˜ต์…˜ ๊ฐœ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๊ณต๊ฐœ API๋ฅผ ์ง€์ •ํ•˜๋Š” ๋™์•ˆ ๋ฌธ์ œ #1489์—์„œ ์ตœ๊ทผ์— ๋ฐœ์ƒํ•œ ์ผ์„ ๊ณ ๋ คํ•˜๊ณ  ํ…Œ์ŠคํŠธ ์ค‘์ธ ํ•„ํ„ฐ ๋ฐ ๊ฒฐ๊ณผ ๊ธฐ๋Šฅ๊ณผ ๋” ๋งŽ์€ ์ƒํ˜ธ ์ž‘์šฉ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๊ณต๊ฐœ API๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

API๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์‚ฌ์šฉ์ž ์ง€์ • ํ”ผํด ํ•„ํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์˜ต์…˜์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค(๋‚ด์žฅ ํ•„ํ„ฐ๋ง์„ ๊ตฌ๋™ํ•˜๋Š” ์ด๋ฆ„, ํƒœ๊ทธ ๋“ฑ).

๋งค์šฐ command-line-y์ธ ๊ฒฝ์šฐ ํ”„๋กœํ•„์— ๋Œ€ํ•œ ํ˜„์žฌ ๊ตฌ๋ฌธ์ž…๋‹ˆ๋‹ค.

JSON, JavaScript, YAML ๋˜๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ ๊ฐ™์€ ๋ณด๋‹ค ์ผ๋ฐ˜์ ์ธ ํ˜•์‹์œผ๋กœ ํ”„๋กœํ•„์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด โค๏ธโค๏ธโค๏ธ. JSON์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.cucumber.json

{
  "default": {
    "requireModule": ["ts-node/register"],
    "require": ["support/**/*./ts"],
    "worldParameters": {
      "appUrl": "http://localhost:3000/",
    },
    "format": ["progress-bar", "html:./cucumber-report.html"]
  },
  "ci": {
    "requireModule": ["ts-node/register"],
    "require": ["support/**/*./ts"],
    "worldParameters": {
      "appUrl": "http://localhost:3000/",
    },
    "format": ["html:./cucumber-report.html"],
    "publish": true
  }
}

๋˜๋Š” JavaScript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ

.cucumber.js

const common = {
  "requireModule": ["ts-node/register"],
  "require": ["support/**/*./ts"],
  "worldParameters": {
    "appUrl": "http://localhost:3000/",
  }
}

module.exports = {
  default: {
    ...common,
    "format": ["progress-bar", "html:./cucumber-report.html"]
  },
  ci: {
    ...common,
    "format": ["html:./cucumber-report.html"],
    "publish": true
  }
}

๋˜๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ(์˜ˆ: dotenv์™€ ๊ฐ™์€ ๋„๊ตฌ๋กœ ๋กœ๋“œ๋จ):

.cucumber.env

CUCUMBER_PROFILE_DEFAULT_REQUIREMODULE=ts-node/register
CUCUMBER_PROFILE_DEFAULT_REQUIRE=ts-node/register
CUCUMBER_PROFILE_DEFAULT_WORLDPARAMETERS_APPURL=http://localhost:3000/
CUCUMBER_PROFILE_DEFAULT_FORMAT=progress-bar,html:./cucumber-report.html
CUCUMBER_PROFILE_CI_REQUIREMODULE=ts-node/register
CUCUMBER_PROFILE_CI_REQUIRE=ts-node/register
CUCUMBER_PROFILE_CI_WORLDPARAMETERS_APPURL=http://localhost:3000/
CUCUMBER_PROFILE_CI_FORMAT=progress-bar,html:./cucumber-report.html
CUCUMBER_PROFILE_CI_PUBLISH=true

์‚ฌ์‹ค, config ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ •ํ™•ํžˆ ์ด๊ฒƒ์„ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒƒ๋“ค์ด ๋ฐฉํ•ด๊ฐ€ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ Cucumber-JVM์— ํ†ตํ•ฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋๋‚ด์ง€ ๋ชปํ–ˆ์ง€๋งŒ JavaScript ๊ตฌํ˜„์œผ๋กœ ์‹œ๋„ํ•ด ๋ณผ ์ˆ˜๋Š” ์—†์„๊นŒ์š”?

@aslakhellesoy ๋Š” ๊ทธ๊ฒƒ์ด ๊ต‰์žฅํ•  ๊ฒƒ์ด๋ผ๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค! ์ด ์ œ์•ˆ์— ๋Œ€ํ•ด POC๋ฅผ ์ง„ํ–‰ํ•˜๋„๋ก ํ•˜์—ฌ ์ข€ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ์ด์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ด์šฉ์ด ์žˆ๊ณ  ๊ทธ ์ผ๋ถ€๋กœ ํ”„๋กœํ•„์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค(4.5๋…„, #751 ๐Ÿ˜„).

์ฐธ์กฐ #1004

์ด๊ฒƒ์€ ์ข‹์€ ์ ์ž…๋‹ˆ๋‹ค. ํ”„๋กœํ•„(์ตœ์†Œํ•œ ํ˜„์žฌ ํ˜•์‹)์€ ๊ธฐ๋ณธ์ ์œผ๋กœ CLI์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ๊ฒฝ๊ณ„์˜ ์ธก๋ฉด์— ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์˜ณ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ํ”„๋กœํ•„์„ ๋กœ๋“œํ•˜๊ณ  ๋ถ€๋ถ„ ์˜ต์…˜ ๊ฐœ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ, ํ”Œ๋Ÿฌ๊ทธ์ธ ์ œ์ž‘์ž์˜ ๊ด€์ ์—์„œ ๋ณด๋ฉด ๋Œ€๋‹จํ•˜๊ณ  ๊ฐ์‚ฌํ•  ์ผ์ž…๋‹ˆ๋‹ค.

JSON, JavaScript, YAML ๋˜๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜์™€ ๊ฐ™์€ ๋ณด๋‹ค ์ผ๋ฐ˜์ ์ธ ํ˜•์‹์œผ๋กœ ํ”„๋กœํ•„์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด โค๏ธโค๏ธโค๏ธ. JSON์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฑฐ ์ข‹์„ ๊ฑฐ ๊ฐ™์•„! ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์ด ๋ฐ”๋กœ ๋‚ด๊ฐ€ ์˜ค์ดJS์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ API๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” API๋ฅผ ๊ณ ๋ง™๊ฒŒ ์—ฌ๊ธฐ๋Š” ์ด์œ ์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ cucumber.js ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์šฐ์„  ์ˆœ์œ„, ํŒŒ์ผ ํ˜•์‹ ๋“ฑ์„ ํฌํ•จํ•˜์—ฌ ๊ตฌ์„ฑ ํŒŒ์ผ ๋กœ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ณต์ œํ•˜๊ณ  ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒƒ์ž…๋‹ˆ๋‹ค ๐Ÿ˜….

Q: ํ•„์š” ์บ์‹œ๋ฅผ ์ง€์šฐ์ง€ ์•Š๊ณ  _ runCucumber ๋ฅผ ์—ฐ์†์œผ๋กœ ๋‘ ๋ฒˆ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์€ ๋Œ์—ฐ๋ณ€์ด ํ…Œ์ŠคํŠธ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ํ™œ์„ฑ ๋Œ์—ฐ๋ณ€์ด๋ฅผ ์ „ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด์„œ ํ™˜๊ฒฝ์„ ๋กœ๋“œํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ๋น ๋ฅด๊ฒŒ ์—ฐ์†์ ์œผ๋กœ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ง€๊ธˆ ์šฐ๋ฆฌ๋Š” cli ๊ฐœ์ธ API๋ฅผ ์‚ฌ์šฉ ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๊ฐ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‚ฌ์ด์— require.cache ์—์„œ ๋‹จ๊ณ„ ์ •์˜ ํŒŒ์ผ์„ ์ง€์›Œ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ CommonJS์— ์ด์ƒ์ ์ด์ง€ ์•Š์œผ๋ฉฐ esm์—์„œ๋Š” ์ „ํ˜€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ์˜์‚ฌ ์ฝ”๋“œ:

const profiles = await loadProfiles();
const options = {
  ...profiles.default,
  formatter: require.resolve('./our-awesomely-crafted-formatter'),
  some: 'other options we want to override',
}
const cucumber = new Cucumber(options);

// Allow cucumber to load the step definitions once. 
// This is `async`, so support for esm can be added without a breaking change
await cucumber.initialize();

// Initial test run ("dry run"), without mutants active
await cucumber.run();

collectMutantCoveragePerTestFromFormatter();

// Start mutation testing:

global.activeMutant = 1;
await cucumber.run({ features: ['features/a.feature:24']);
collectResultsFromFormatterToDetermineKilledOrSurvivedMutant()

global.activeMutant = 2;
await cucumber.run({ features: ['features/b.feature:24:25:26', 'features/c.feature:12']);
collectResultsFromFormatterToDetermineKilledOrSurvivedMutant()

// etc

@nicojs ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ด๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋žŒ๋‹ค์—์„œ ์˜ค์ด๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋Š” ์‚ฌ๋žŒ๋“ค๊ณผ ํ•จ๊ป˜ ์ด์ „์— ๋ช‡ ๋ฒˆ

์ง€๊ธˆ๊นŒ์ง€ ์Šค์ผ€์น˜ํ•œ ๊ฒƒ์€ ๊ธฐ๋Šฅ์ ์ธ ์Šคํƒ€์ผ์— ๊ฐ€๊น์ง€๋งŒ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

const runnerOptions = {
    support: {
        require: ['features/support/**/*.js']
    }
}

// initial run returns support code library
const { support } = await runCucumber(runnerOptions)

// subsequent run reuses support code library
await runCucumber({
    ...runnerOptions,
    support
})

๊ทธ๊ฒƒ์€ ์šฐ๋ฆฌ์—๊ฒŒ ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ‘

์šฐ๋ฆฌ์—๊ฒŒ๋„ ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ‘๐Ÿป

๋‚˜๋Š” ์ด์™€ ๊ฐ™์€ ๊ฒƒ์ด ์˜ค๋Š˜๋‚  ์šฐ๋ฆฌ๊ฐ€ ํ…Œ์ŠคํŠธ ๋„๊ตฌ ํ†ตํ•ฉ(Jest, Cypress)์œผ๋กœ ์ธํ•ด ๊ฒช๊ณ  ์žˆ๋Š” ํฐ ํ˜ผ๋ž€์— ๋Œ€ํ•œ ๋Œ€์•ˆ์œผ๋กœ ๋งค์šฐ ์œ ์šฉํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค(์ค‘์š”ํ•œ ์ˆœ์„œ๋Œ€๋กœ).

  • cypress-cucumber-preprocessor ๋Š” ์˜ˆ์ œ์˜ ํƒœ๊ทธ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(https://github.com/TheBrainFamily/cypress-cucumber-preprocessor/issues/196).
  • jest-cucumber ๋Š” Cucumber JSON ๋ณด๊ณ ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(https://github.com/bencompton/jest-cucumber/issues/27).
  • cypress-cucumber-preprocessor ๋Š” ์ง‘๊ณ„์— ๋Œ€ํ•œ ๊ณต์‹ ์ง€์› ์—†์ด ์—ฌ๋Ÿฌ Cucumber JSON ๋ณด๊ณ ์„œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค(https://github.com/TheBrainFamily/cypress-cucumber-preprocessor/issues/423).
  • jest-cucumber ์€ jest-cucumber-fusion ๋งŒํผ ํŽธ๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • cucumber-jest ...
  • Karma์—๋Š” ๋” ์ด์ƒ ์ž‘๋™ํ•˜๋Š” ๊ตฌํ˜„์ด ์—†์Šต๋‹ˆ๋‹ค(https://github.com/cucumber/cucumber-js/issues/1095).

์ฐจ๋ผ๋ฆฌ Jest/Karma/Cypress/etc ์‚ฌ์ด์— ์ตœ์†Œํ•œ์˜ ๊ธ€๋ฃจ ์ฝ”๋“œ๋ฅผ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์˜ค์ด-js๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๋ˆ„๋ฝ๋œ ๊ธฐ๋Šฅ์œผ๋กœ ์ธํ•ด ๊ณ ํ†ต์„ ๊ฒช์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ข‹์€ ์ œ์•ˆ @davidjgoss ๐Ÿ‘

๋ช…๋ น์ค„ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์™€ ํ…Œ์ŠคํŠธ๋กœ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” "๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง" ์‚ฌ์ด์˜ ์ด๋Ÿฌํ•œ ๋ถ„๋ฆฌ๋Š” ์œก๊ฐํ˜• ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด์„ ์ƒ๊ฐ๋‚˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์˜ค์ด-๋ฃจ๋น„์—์„œ ์šฐ๋ฆฌ๋Š” "ํด๋ฆฐ ๋ฃธ"์—์„œ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋นŒ๋“œํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ํ•ต์‹ฌ ๋„๋ฉ”์ธ ๋กœ์ง(๋˜๋Š” "๋‚ด๋ถ€ ์œก๊ฐํ˜•")์„ ๋ณ„๋„์˜ gem ํŒจํ‚ค์ง€๋กœ ๋ถ„ํ• ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์—ฌ๊ธฐ์„œ ์ปจํ…์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์˜๊ฐ์„ ์–ป๊ฑฐ๋‚˜ ์ด ๋””์ž์ธ์˜ ํ˜์‹ ์„ Ruby API์— ํ”ผ๋“œ๋ฐฑํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์น˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์˜ค์ด-๋ฃจ๋น„-์ฝ”์–ด ๋ณด์„์˜ README์— ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž, ์—ฌ๊ธฐ "์‹คํ–‰" ๋น„ํŠธ์— ๋Œ€ํ•œ API ์„œ๋ช…์˜ ์ฒซ ๋ฒˆ์งธ ํŒจ์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” IConfiguration ๊ฐ์ฒด์— ํฌ๊ฒŒ ๊ธฐ๋ฐ˜์„ ๋‘๊ณ  ์žˆ์ง€๋งŒ(์•„๋ž˜๋กœ ๋„ˆ๋ฌด ๋งŽ์€ ๋ฆฌํŒฉํ† ๋ง์„ ์ผ์œผํ‚ค์ง€ ์•Š์•„์•ผ ํ•จ) "ํ‰ํ‰ํ•œ" ์ •๋„๋Š” ์กฐ๊ธˆ ๋œํ•ฉ๋‹ˆ๋‹ค.

export interface IRunCucumberOptions {
  cwd: string
  features: {
    defaultDialect?: string
    paths: string[]
  }
  filters: {
    name?: string[]
    tagExpression?: string
  }
  support:
    | {
        transpileWith?: string[]
        paths: string[]
      }
    | ISupportCodeLibrary
  runtime: {
    dryRun?: boolean
    failFast?: boolean
    filterStacktraces?: boolean
    parallel?: {
      count: number
    }
    retry?: {
      count: number
      tagExpression?: string
    }
    strict: boolean
    worldParameters?: any
  }
  formats: {
    stdout: string
    files: Record<string, string>
    options: IParsedArgvFormatOptions
  }
}

export interface IRunResult {
  success: boolean
  support: ISupportCodeLibrary
}

export async function runCucumber(
  options: IRunCucumberOptions
): Promise<IRunResult> {
  // do stuff
}

๊ทธ๋ฆฌ๊ณ  ๋งค์šฐ ์ธ์œ„์ ์ธ ์‚ฌ์šฉ ์˜ˆ:

const result = await runCucumber({
  cwd: process.cwd(),
  features: {
    paths: ['features/**/*.feature'],
  },
  filters: {
    name: ['Acme'],
    tagExpression: '<strong i="10">@interesting</strong>',
  },
  support: {
    transpileWith: ['ts-node'],
    paths: ['features/support/**/*.ts'],
  },
  runtime: {
    failFast: true,
    retry: {
      count: 1,
      tagExpression: '<strong i="11">@flaky</strong>',
    },
    strict: true,
    worldParameters: {
      foo: 'bar',
    },
  },
  formats: {
    stdout: '@cucumber/pretty-formatter',
    files: {
      'report.html': 'html',
      'TEST-cucumber.xml': 'junit',
    },
    options: {
      printAttachments: false,
    },
  },
})

ํ”ผ๋“œ๋ฐฑ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค! ์ด๊ฒƒ์€ ๋˜ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์ด ๋  ํ”„๋กœํ•„/๊ตฌ์„ฑ ๋กœ๋”ฉ์„ ๋‹ค๋ฃจ์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์‹ญ์‹œ์˜ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ์ข‹์•„ ๋ณด์ธ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์งˆ๋ฌธ: ์‚ฌ์šฉ์ž ์ง€์ • ํฌ๋งทํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๊นŒ?

@nicojs ๋Š” CLI์™€ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

formats: {
    files: {
      'report.html': './my/fancy-reporter.js',
      'other-report.html': '@me/reporter-package',
    }
  },

@davidjgoss์˜ ์ง„ํ–‰ ์ƒํ™ฉ์„ ๋ณด๋‹ˆ ๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค!

์ด ์ž‘์—…์˜ ์ง„ํ–‰ ์†๋„๋ฅผ ๋Šฆ์ถ”๊ณ  ์‹ถ์ง€๋Š” ์•Š์ง€๋งŒ ๋™์‹œ์— ๋‹ค๋ฅธ Cucumber ๊ตฌํ˜„์—์„œ๋„ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•์‹์„ ์ฑ„ํƒํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ JSON ์Šคํ‚ค๋งˆ์ด์ง€๋งŒ, ๋…ผ์˜ํ•˜๋Š” ๋™์•ˆ TypeScript ์œ ํ˜•์ด ์šฐ๋ฆฌ ์ธ๊ฐ„์ด ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ธฐ ๋” ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

cucumber/common ๋ชจ๋…ธ๋ ˆํฌ์—์„œ ์ œ์•ˆ๋œ ํ˜•์‹์— ๋Œ€ํ•œ ์ƒˆ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ต์‹ฌ ํŒ€์„ ์ดˆ๋Œ€ํ•˜์—ฌ ํ† ๋ก ํ•˜๋„๋ก ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.

@aslakhellesoy ๊ฐ€ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹ API๊ฐ€ ๊ณตํ†ต ์˜ต์…˜ ๊ตฌ์กฐ์— ์—ฐ๊ฒฐ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ? runCucumber ์˜ต์…˜์— ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์•ฝ๊ฐ„์˜ ๋ณต์žก์„ฑ์ด ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๋กœ๋“œํ•  ๋งค๊ฐœ๋ณ€์ˆ˜์ด๊ฑฐ๋‚˜ ์ด์ „์— ๋กœ๋“œ๋œ ์ง€์› ์ฝ”๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ support ๋ธ”๋ก์ด ์žˆ๋‹ค๋Š” ์ ์—์„œ ๋งค๋ ฅ์ ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ + ํ”ผํด์— ๋Œ€ํ•ด์„œ๋„ ์œ ์‚ฌํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹ API์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์€ ๋‹ค์–‘ํ•œ ์˜ต์…˜(์˜ˆ: --exit )์ด CLI์—์„œ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹ API๊ฐ€ ๊ณตํ†ต ์˜ต์…˜ ๊ตฌ์กฐ์— ์—ฐ๊ฒฐ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?

์˜ต์…˜ ํŒŒ์ผ ๋‚ด์šฉ์„ runCucumber ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๋Š” ํ•œ ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ JSON ์Šคํ‚ค๋งˆ์ด์ง€๋งŒ, ๋…ผ์˜ํ•˜๋Š” ๋™์•ˆ TypeScript ์œ ํ˜•์ด ์šฐ๋ฆฌ ์ธ๊ฐ„์ด ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ธฐ ๋” ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์™œ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? StrykerJS์—์„œ JSON ์Šคํ‚ค๋งˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ json-schema-to-typescript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ typescript๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. TS ์ถœ๋ ฅ ํŒŒ์ผ์„ ์†Œ์Šค ์ œ์–ด์— ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๊ณ  ๋Œ€์‹  prebuild ๋‹จ๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฆ‰์„์—์„œ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

JSON ์Šคํ‚ค๋งˆ๋Š” ์—ฌ์ „ํžˆ ์ธ๊ฐ„ IMO์—์„œ ์–ด๋Š ์ •๋„ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ Stryker ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ PR์„ ๋ฐ›์•˜๊ณ  ์‚ฌ๋žŒ๋“ค์€ ๋ฌด์—‡์„ ํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿคทโ€โ™€๏ธ

CLI์—์„œ์™€ ๊ฐ™์ด

formats: {
    files: {
      'report.html': './my/fancy-reporter.js',
      'other-report.html': '@me/reporter-package',
    }
  },

์ถœ๋ ฅ ํŒŒ์ผ ์ด๋ฆ„์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ธฐ์ž์—๊ฒŒ ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ• ๊นŒ์š”? ์ด๋ ‡๊ฒŒ:

formats: {
  files: {
    '': require.resolve('./my-awesome-stryker-formatter')
  }
}

์šฐ๋ฆฌ๋Š” ์™œ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

๊ตฌ์„ฑ ๊ตฌ์กฐ์— ๋Œ€ํ•œ ๋‹จ์ผ ์ •๋ณด ์†Œ์Šค๋กœ JSON ์Šคํ‚ค๋งˆ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. - ๊ทธ๋Ÿฐ ๋‹ค์Œ ํ•ด๋‹น ์Šคํ‚ค๋งˆ์—์„œ TypeScript/Java/Whatever ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ JSON ์Šคํ‚ค๋งˆ๋Š” ์‚ฌ๋žŒ์ด ์ฝ๊ธฐ์— ์•ฝ๊ฐ„ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ cucumber/common ์˜ GitHub ๋ฌธ์ œ์—์„œ ์Šคํ‚ค๋งˆ์— ๋Œ€ํ•ด ๋…ผ์˜ ํ•˜๋Š” ๋™์•ˆ

๋ฌด์Šจ ๋ง์ธ์ง€ ์•Œ๊ฒ ์–ด?

JSON ์Šคํ‚ค๋งˆ๋Š” ์—ฌ์ „ํžˆ ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. IMO

๋‚˜์—๊ฒŒ๋Š” ์•„๋‹™๋‹ˆ๋‹ค :-) ๋„ˆ๋ฌด ์žฅํ™ฉํ•ฉ๋‹ˆ๋‹ค.

์ถœ๋ ฅ ํŒŒ์ผ ์ด๋ฆ„์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ธฐ์ž์—๊ฒŒ ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ• ๊นŒ์š”?

formats: {
    stdout: './my-awesome-stryker-formatter',
    files: {
      'report.html': './my/fancy-reporter.js',
      'other-report.html': '@me/reporter-package',
    }
  },

(ํ•˜๋‚˜์˜ ํฌ๋งทํ„ฐ๋งŒ stdout ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ)

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