ํ์ฌ ์ฐ๋ฆฌ๋ ์ค์ด-js๋ฅผ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก ์คํํ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๋ ๊ฐ์ง ๊ฐ๋์์ ํ์ํฉ๋๋ค.
ํ์ฌ ๋ฐ์ํ๋ ๊ฒฝํฅ์ Cli
์ ์๋ก์ด ์ธ์คํด์ค๊ฐ strung-together argv ์
๋ ฅ์ผ๋ก ์์ฑ๋๋ค๋ ๊ฒ์
๋๋ค. ๋ถ๋ช
ํ ๋งค์ฐ ์ด์ํ๊ณ ๊ณต๊ฐ API ์๋
๋๋๋ก (์์ ์ธ์๋ ์ทจ์ฝ์ฑ ๋๋ฌธ์) ํ๋ ์์ํฌ๋ ์ค์ด-js CLI์๋ง ์์กดํ์ง๋ง ํตํฉ ๋ฐฉ๋ฒ์ ์ฐพ๊ณ ๊ณ ์ ํ ์ต์ ์ ๊ฐ๋ ๋ฐ ์ด๋ ค์์ ๊ฒช์ ๊ฒ์ ๋๋ค.
Runtime
ํด๋์ค ๋ ํ์ฌ ๊ณต๊ฐ API์ ์ผ๋ถ์ด์ง๋ง ํธ์ถ์๊ฐ ์ ๊ณตํ ํผํด ๋ฐ ์ง์ ์ฝ๋์ ๋ฐ๋ผ ์ด๋ฌํ ์ปจํ
์คํธ์์๋ ์ ์ฉํ์ง ์์ต๋๋ค.
ํ๋ก์ ํธ์ ๋ ๊ฐ์ง ๊ตฌ์ฑ ์์:
runCucumber
ํ๋ก์ธ์ค ๋ด์์ ํ ์คํธ ์คํ์ ์คํํ๋ ์๋ก์ด ๋น๋๊ธฐ ํจ์์ ๋๋ค. ์ฑ ์:
์ด๊ฒ์ ๊ณต๊ฐ API์ ์ผ๋ถ๊ฐ ๋ ๊ฒ์ด๋ฉฐ ์ฐ๋ฆฌ๋ ํ๋ ์์ํฌ ์ ์ง ๊ด๋ฆฌ์๊ฐ ์ค์ด-js๋ฅผ "๋ํ"ํ ๋ ์ด๋ฅผ ์ฌ์ฉํ๋๋ก ๊ถ์ฅํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๋ํ ์ฐ๋ฆฌ ์์ ์ ํ ์คํธ๋ฅผ ์ํด ๊ทธ๊ฒ์ ์ฌ์ฉํ ๊ฒ์ ๋๋ค.
๊ฐ๋ฅํ ํ process
์์ ์ง์ ์ ์ธ ์ํธ ์์ฉ์ ํผํ๋ ๋์ ์ถ๋ ฅ์ ์ํด ์ ๊ทํ๋ ์ต์
๊ณผ ์คํธ๋ฆผ ์ธํฐํ์ด์ค๋ฅผ ์๋ฝํ๊ณ ๊ฒฐ๊ณผ ๋๋ ์ฒ๋ฆฌ๋์ง ์์ ์ค๋ฅ์ ๋ฐ๋ผ ์ข
๋ฃ ๋ฐฉ๋ฒ์ ๊ฒฐ์ ํ๋ ๊ฒ์ ํธ์ถ์์๊ฒ ๋งก๊น๋๋ค.
๋ํ Runtime
๋ ์ค์ ๋ก ๋ด๋ถ์ ์ธ ๊ฒ์ด๋ฏ๋ก ๊ณต๊ฐ API์์ ๋์์ผ ํฉ๋๋ค.
์ฌ์ค์ runCucumber
์ "ํด๋ผ์ด์ธํธ"์
๋๋ค. ์ฑ
์:
runCucumber
์ ํ์ด๊ฒ์ ๊ณ์ํด์ ๊ณต๊ฐ API์ ์์ ๊ฒ์ ๋๋ค. ๋ํ ๊ทธ๊ฒ์ ๋จ์ง ๊ธฐ๋ฅ ๊ณต๊ฐ API์์๋ / ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ธ ํจํด์ด ๊ฐ์ ํ๋ก์ ํธ์ ์ง๊ธ์ฒ๋ผ ์ฐ๋ฆฌ๊ฐ ์ฝ๊ฒ, ์ด๋ค ์ ์์ ์์ ์ ํจํค์ง๋ก ๊ทธ๊ฒ์ ๊นฐ ์ ์๋๋ก ๋๋ด .
์ด ๋ถ๋ฆฌ๋ ๋ํ ๋ด๋ถ๋ก ํ๋ฌ ๋ค์ด๊ฐ์ง ์๊ณ ๋ช ๊ฐ์ง ํฅ๋ฏธ๋ก์ด ์๋ก์ด CLI ๊ธฐ๋ฅ์ ์ํ ๊ธธ์ ์ด์ด์ค๋๋ค. ์:
--gui
์ค์ด-์ ์ ์ฌ๋ฃ--interactive
TDD ์ ๋น ๋ฅธ ๋์ ์ฌ์คํ๋ํ ๋ค์์ ์ํ ๊ธฐ๋ฅ(CLI ๋ฐ ๊ธฐํ ์ฌ์ฉ ๊ฐ๋ฅ)์ ๋ ธ์ถํฉ๋๋ค.
i18nKeywords
๋ฐ i18nLanguages
๋ค๊ฐ์ค๋ 8.0.0 ๋ฆด๋ฆฌ์ค์์ ์ด๋ฅผ ๋ชฉํ๋ก ์ผ์ ๊ฒ์ ๋๋ค. ์ค๋ ์์ํ ์ค๋น๊ฐ ๋์์ต๋๋ค.
์ด๊ธฐ ํผ๋๋ฐฑ์ ์ํ ํ์ด์ง: @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
...์ฐจ๋ผ๋ฆฌ 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 ์คํธ๋ฆผ์ ์ฌ์ฉํ ์ ์์)
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
(ํ๋์ ํฌ๋งทํฐ๋ง stdout ์คํธ๋ฆผ์ ์ฌ์ฉํ ์ ์์)