Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: gherkin supports i18n #3934

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion lib/interfaces/gherkin.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ parser.stopAtFirstError = false;

module.exports = (text, file) => {
const ast = parser.parse(text);
let currentLanguage;

if (ast.feature) {
currentLanguage = getTranslation(ast.feature.language);
}

if (!ast.feature) {
throw new Error(`No 'Features' available in Gherkin '${file}' provided!`);
Expand Down Expand Up @@ -96,7 +101,7 @@ module.exports = (text, file) => {
suite.beforeEach('Before', scenario.injected(async () => runSteps(child.background.steps), suite, 'before'));
continue;
}
if (child.scenario && child.scenario.keyword === 'Scenario Outline') {
if (child.scenario && (currentLanguage ? child.scenario.keyword === currentLanguage.contexts.ScenarioOutline : child.scenario.keyword === 'Scenario Outline')) {
for (const examples of child.scenario.examples) {
const fields = examples.tableHeader.cells.map(c => c.value);
for (const example of examples.tableBody) {
Expand Down Expand Up @@ -162,3 +167,17 @@ function addExampleInTable(exampleSteps, placeholders) {
}
return steps;
}

function getTranslation(language) {
const translations = Object.keys(require('../../translations'));

for (const availableTranslation of translations) {
if (!language) {
break;
}

if (availableTranslation.includes(language)) {
return require('../../translations')[availableTranslation];
}
}
}
17 changes: 17 additions & 0 deletions test/data/sandbox/features/step_definitions/my_steps.de.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const I = actor();

Given('ich habe ein Produkt mit einem Preis von {int}$ in meinem Warenkorb', (price) => {
I.addItem(parseInt(price, 10));
});

Given('der Rabatt für Bestellungen über $\{int} beträgt {int} %', (maxPrice, discount) => { // eslint-disable-line
I.haveDiscountForPrice(maxPrice, discount);
});

When('ich zur Kasse gehe', () => {
I.checkout();
});

Then('sollte ich den Gesamtpreis von "{float}" $ sehen', (price) => {
I.seeSum(price);
});
21 changes: 21 additions & 0 deletions test/data/sandbox/i18n/codecept.bdd.de.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
exports.config = {
tests: './*_no_test.js',
timeout: 10000,
output: '../output',
helpers: {
BDD: {
require: '../support/bdd_helper.js',
},
},
gherkin: {
features: './features/examples.de.feature',
steps: [
'./features/step_definitions/my_steps.de.js',
],
},
include: {},
bootstrap: false,
mocha: {},
name: 'sandbox',
translation: 'de-DE',
};
16 changes: 16 additions & 0 deletions test/data/sandbox/i18n/features/examples.de.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#language: de
Funktionalität: Checkout-Prozess
Um Produkte zu kaufen
Als Kunde
Möchte ich in der Lage sein, mehrere Produkte zu kaufen

@i18n
Szenariogrundriss: Bestellrabatt
Angenommen ich habe ein Produkt mit einem Preis von <price>$ in meinem Warenkorb
Und der Rabatt für Bestellungen über $20 beträgt 10 %
Wenn ich zur Kasse gehe
Dann sollte ich den Gesamtpreis von "<total>" $ sehen

Beispiele:
| price | total |
| 10 | 10.0 |
17 changes: 17 additions & 0 deletions test/data/sandbox/i18n/features/step_definitions/my_steps.de.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const I = actor();

Given('ich habe ein Produkt mit einem Preis von {int}$ in meinem Warenkorb', (price) => {
I.addItem(parseInt(price, 10));
});

Given('der Rabatt für Bestellungen über $\{int} beträgt {int} %', (maxPrice, discount) => { // eslint-disable-line
I.haveDiscountForPrice(maxPrice, discount);
});

When('ich zur Kasse gehe', () => {
I.checkout();
});

Then('sollte ich den Gesamtpreis von "{float}" $ sehen', (price) => {
I.seeSum(price);
});
27 changes: 27 additions & 0 deletions test/runner/bdd_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,31 @@ When(/^I define a step with a \\( paren and a "(.*?)" string$/, () => {
done();
});
});

describe('i18n', () => {
const codecept_dir = path.join(__dirname, '/../data/sandbox/i18n');
const config_run_config = config => `${codecept_run} --config ${codecept_dir}/${config}`;

before(() => {
process.chdir(codecept_dir);
});
it('should run feature files in DE', (done) => {
exec(config_run_config('codecept.bdd.de.js') + ' --steps --grep "@i18n"', (err, stdout, stderr) => { //eslint-disable-line
stdout.should.include('On Angenommen: ich habe ein produkt mit einem preis von 10$ in meinem warenkorb');
stdout.should.include('On Und: der rabatt für bestellungen über $20 beträgt 10 %');
stdout.should.include('On Wenn: ich zur kasse gehe');
stdout.should.include('On Dann: sollte ich den gesamtpreis von "10.0" $ sehen');
stdout.should.include('On Angenommen: ich habe ein produkt mit einem preis von 10$ in meinem warenkorb');
stdout.should.include('Ich add item 10');
stdout.should.include('On Und: der rabatt für bestellungen über $20 beträgt 10 %');
stdout.should.include('Ich have discount for price 20, 10');
stdout.should.include('On Wenn: ich zur kasse gehe');
stdout.should.include('Ich checkout');
stdout.should.include('On Dann: sollte ich den gesamtpreis von "10.0" $ sehen');
stdout.should.include('Ich see sum 10');
assert(!err);
done();
});
});
});
});
5 changes: 5 additions & 0 deletions translations/de-DE.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module.exports = {
I: 'Ich',
contexts: {
Feature: 'Funktionalität',
Scenario: 'Szenario',
ScenarioOutline: 'Szenariogrundriss',
},
actions: {
amOutsideAngularApp: 'befinde_mich_außerhalb_der_angular_app',
amInsideAngularApp: 'bedinde_mich_innerhalb_der_angular_app',
Expand Down
1 change: 1 addition & 0 deletions translations/fr-FR.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = {
contexts: {
Feature: 'Fonctionnalité',
Scenario: 'Scénario',
ScenarioOutline: 'Plan du scénario',
Before: 'Avant',
After: 'Après',
BeforeSuite: 'AvantLaSuite',
Expand Down
1 change: 1 addition & 0 deletions translations/it-IT.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = {
contexts: {
Feature: 'Caratteristica',
Scenario: 'lo_scenario',
ScenarioOutline: 'Schema dello scenario',
Before: 'Prima',
After: 'Dopo',
BeforeSuite: 'Prima_della_suite',
Expand Down
5 changes: 5 additions & 0 deletions translations/ja-JP.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module.exports = {
I: '私は',
contexts: {
Feature: 'フィーチャ',
Scenario: 'シナリオ',
ScenarioOutline: 'シナリオアウトライン',
},
actions: {
amOutsideAngularApp: 'Angularの外に出る',
amInsideAngularApp: 'Angularの中に入る',
Expand Down
5 changes: 5 additions & 0 deletions translations/pl-PL.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module.exports = {
I: 'Ja',
contexts: {
Feature: 'Funkcja',
Scenario: 'Scenariusz',
ScenarioOutline: 'Szablon scenariusza',
},
actions: {
amOutsideAngularApp: 'jestem_poza_aplikacją_angular',
amInsideAngularApp: 'jestem_w_aplikacji_angular',
Expand Down
1 change: 1 addition & 0 deletions translations/pt-BR.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = {
contexts: {
Feature: 'Funcionalidade',
Scenario: 'Cenário',
ScenarioOutline: 'Esquema do Cenário',
Before: 'Antes',
After: 'Depois',
BeforeSuite: 'AntesDaSuite',
Expand Down
1 change: 1 addition & 0 deletions translations/ru-RU.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = {
contexts: {
Feature: 'Цель',
Scenario: 'Сценарий',
ScenarioOutline: 'Структура сценария',
Before: 'Начало',
After: 'Конец',
BeforeSuite: 'Перед_всем',
Expand Down
5 changes: 5 additions & 0 deletions translations/zh-CN.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module.exports = {
I: '我',
contexts: {
Feature: '功能',
Scenario: '场景',
ScenarioOutline: '场景大纲',
},
actions: {
amOutsideAngularApp: '在Angular应用外',
amInsideAngularApp: '在Angular应用内',
Expand Down
5 changes: 5 additions & 0 deletions translations/zh-TW.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module.exports = {
I: '我',
contexts: {
Feature: '功能',
Scenario: '場景',
ScenarioOutline: '場景大綱',
},
actions: {
amOutsideAngularApp: '在Angular應用外',
amInsideAngularApp: '在Angular應用內',
Expand Down