diff --git a/eslint.config.mjs b/eslint.config.mjs index 026694e0..c260397a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -62,7 +62,7 @@ export default [ }, }, { - files: ['test/**/only-skip-fixme.feature.spec.js', 'test/**/minimal.feature.spec.js'], + files: ['test/special-tag-only/**'], plugins: { playwright, }, diff --git a/scripts/no-only-in-features.mjs b/scripts/no-only-in-features.mjs index 87b0928f..e3abebf0 100644 --- a/scripts/no-only-in-features.mjs +++ b/scripts/no-only-in-features.mjs @@ -4,7 +4,7 @@ import fs from 'node:fs'; const files = process.argv.slice(2); -const skipFiles = ['only-skip-fixme.feature', 'minimal.feature']; +const skipFiles = ['only-feature.feature', 'only-scenario.feature']; files.forEach((filePath) => { if (skipFiles.some((skipFile) => filePath.endsWith(skipFile))) return; diff --git a/test/reporter-cucumber-msg/features/minimal/expected-reports/json-report.json b/test/reporter-cucumber-msg/features/minimal/expected-reports/json-report.json index 0f9ae3ee..46a39e1a 100644 --- a/test/reporter-cucumber-msg/features/minimal/expected-reports/json-report.json +++ b/test/reporter-cucumber-msg/features/minimal/expected-reports/json-report.json @@ -1,25 +1,25 @@ [ { - "description": " Cucumber doesn't execute this markdown, but @cucumber/react renders it\n \n * This is\n * a bullet\n * list", + "description": " Cucumber doesn't execute this markdown, but @cucumber/react renders it\n\n * This is\n * a bullet\n * list", "elements": [ { "description": "", "id": "minimal;cukes", "keyword": "Scenario", - "line": 11, + "line": 10, "name": "cukes", "steps": [ { "arguments": [], "keyword": "Given ", - "line": 12, + "line": 11, "name": "I have 42 cukes in my belly", "match": { "location": "features/minimal/common.steps.ts:3" }, "result": { "status": "passed", - "duration": 174540 + "duration": 238958 } } ], @@ -28,13 +28,9 @@ "name": "@foo", "line": 1 }, - { - "name": "@only", - "line": 10 - }, { "name": "@bar", - "line": 10 + "line": 9 } ], "type": "scenario" diff --git a/test/reporter-cucumber-msg/features/minimal/expected-reports/messages.ndjson b/test/reporter-cucumber-msg/features/minimal/expected-reports/messages.ndjson index cfafb7f6..62bb3025 100644 --- a/test/reporter-cucumber-msg/features/minimal/expected-reports/messages.ndjson +++ b/test/reporter-cucumber-msg/features/minimal/expected-reports/messages.ndjson @@ -1,12 +1,12 @@ {"meta":{"protocolVersion":"24.0.1","implementation":{"version":"10.3.1","name":"cucumber-js"},"cpu":{"name":"arm64"},"os":{"name":"darwin","version":"22.5.0"},"runtime":{"name":"node.js","version":"20.3.1"}}} -{"source":{"data":"@foo\nFeature: minimal\n \n Cucumber doesn't execute this markdown, but @cucumber/react renders it\n \n * This is\n * a bullet\n * list\n \n @only @bar\n Scenario: cukes\n Given I have 42 cukes in my belly\n","uri":"features/minimal/minimal.feature","mediaType":"text/x.cucumber.gherkin+plain"}} -{"gherkinDocument":{"feature":{"tags":[{"location":{"line":1,"column":1},"name":"@foo","id":"7d81343c-55bf-4abd-ae4b-027ded4face2"}],"location":{"line":2,"column":1},"language":"en","keyword":"Feature","name":"minimal","description":" Cucumber doesn't execute this markdown, but @cucumber/react renders it\n \n * This is\n * a bullet\n * list","children":[{"scenario":{"id":"5d83261a-c1a3-4093-afbd-593fb34d040e","tags":[{"location":{"line":10,"column":3},"name":"@only","id":"b4bb3fb7-50c3-4db7-840e-6079bb1effb9"},{"location":{"line":10,"column":9},"name":"@bar","id":"0e9ab335-3eba-4c65-93a5-4086cf50bf71"}],"location":{"line":11,"column":3},"keyword":"Scenario","name":"cukes","description":"","steps":[{"id":"bdf94b83-6330-4f97-994d-64831fc02e82","location":{"line":12,"column":5},"keyword":"Given ","keywordType":"Context","text":"I have 42 cukes in my belly"}],"examples":[]}}]},"comments":[],"uri":"features/minimal/minimal.feature"}} -{"pickle":{"id":"a7c52bfe-9011-4571-a82a-c567375ebe13","uri":"features/minimal/minimal.feature","astNodeIds":["5d83261a-c1a3-4093-afbd-593fb34d040e"],"tags":[{"name":"@foo","astNodeId":"7d81343c-55bf-4abd-ae4b-027ded4face2"},{"name":"@only","astNodeId":"b4bb3fb7-50c3-4db7-840e-6079bb1effb9"},{"name":"@bar","astNodeId":"0e9ab335-3eba-4c65-93a5-4086cf50bf71"}],"name":"cukes","language":"en","steps":[{"id":"c8f4467e-2d9d-4935-b7e4-c6d78adb7da9","text":"I have 42 cukes in my belly","type":"Context","astNodeIds":["bdf94b83-6330-4f97-994d-64831fc02e82"]}]}} -{"stepDefinition":{"id":"0b086661-bdc3-4d8a-93de-639be735d7b6","pattern":{"source":"I have {int} cukes in my belly","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"uri":"features/minimal/common.steps.ts","location":{"line":3}}}} -{"testRunStarted":{"timestamp":{"seconds":1707838108,"nanos":627000000}}} -{"testCase":{"pickleId":"a7c52bfe-9011-4571-a82a-c567375ebe13","id":"6469fa38-5ed5-43a0-8ee1-bd9e55d28529","testSteps":[{"id":"fe7a3192-3b5c-454d-9b76-4a101f0be584","pickleStepId":"c8f4467e-2d9d-4935-b7e4-c6d78adb7da9","stepDefinitionIds":["0b086661-bdc3-4d8a-93de-639be735d7b6"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":7,"value":"42","children":[]},"parameterTypeName":"int"}]}]}]}} -{"testCaseStarted":{"attempt":0,"testCaseId":"6469fa38-5ed5-43a0-8ee1-bd9e55d28529","id":"361745ea-72d0-4a68-8bcf-15c75bcb68e3","timestamp":{"seconds":1707838108,"nanos":631000000}}} -{"testStepStarted":{"testCaseStartedId":"361745ea-72d0-4a68-8bcf-15c75bcb68e3","testStepId":"fe7a3192-3b5c-454d-9b76-4a101f0be584","timestamp":{"seconds":1707838108,"nanos":631000000}}} -{"testStepFinished":{"testCaseStartedId":"361745ea-72d0-4a68-8bcf-15c75bcb68e3","testStepId":"fe7a3192-3b5c-454d-9b76-4a101f0be584","testStepResult":{"duration":{"seconds":0,"nanos":174540},"status":"PASSED"},"timestamp":{"seconds":1707838108,"nanos":631000000}}} -{"testCaseFinished":{"testCaseStartedId":"361745ea-72d0-4a68-8bcf-15c75bcb68e3","timestamp":{"seconds":1707838108,"nanos":631000000},"willBeRetried":false}} -{"testRunFinished":{"timestamp":{"seconds":1707838108,"nanos":631000000},"success":true}} +{"source":{"data":"@foo\nFeature: minimal\n Cucumber doesn't execute this markdown, but @cucumber/react renders it\n\n * This is\n * a bullet\n * list\n\n @bar\n Scenario: cukes\n Given I have 42 cukes in my belly\n","uri":"features/minimal/minimal.feature","mediaType":"text/x.cucumber.gherkin+plain"}} +{"gherkinDocument":{"feature":{"tags":[{"location":{"line":1,"column":1},"name":"@foo","id":"1f7f03ac-bcf7-4531-9d0a-eae5a90fcc29"}],"location":{"line":2,"column":1},"language":"en","keyword":"Feature","name":"minimal","description":" Cucumber doesn't execute this markdown, but @cucumber/react renders it\n\n * This is\n * a bullet\n * list","children":[{"scenario":{"id":"4f3d57eb-f678-4190-acf1-739cb68f8bbf","tags":[{"location":{"line":9,"column":3},"name":"@bar","id":"82ecfd0c-775e-457f-8748-64c6843bb4bf"}],"location":{"line":10,"column":3},"keyword":"Scenario","name":"cukes","description":"","steps":[{"id":"677e1be8-aad8-47d6-b800-eaa5e8468c66","location":{"line":11,"column":5},"keyword":"Given ","keywordType":"Context","text":"I have 42 cukes in my belly"}],"examples":[]}}]},"comments":[],"uri":"features/minimal/minimal.feature"}} +{"pickle":{"id":"024c5af0-2f06-4843-a403-718bc43a3eac","uri":"features/minimal/minimal.feature","astNodeIds":["4f3d57eb-f678-4190-acf1-739cb68f8bbf"],"tags":[{"name":"@foo","astNodeId":"1f7f03ac-bcf7-4531-9d0a-eae5a90fcc29"},{"name":"@bar","astNodeId":"82ecfd0c-775e-457f-8748-64c6843bb4bf"}],"name":"cukes","language":"en","steps":[{"id":"ea1ec2f8-71c2-450a-beb0-2cd0e88df0c8","text":"I have 42 cukes in my belly","type":"Context","astNodeIds":["677e1be8-aad8-47d6-b800-eaa5e8468c66"]}]}} +{"stepDefinition":{"id":"5a5145d5-9142-4a3f-a89d-3ebb198cdfe5","pattern":{"source":"I have {int} cukes in my belly","type":"CUCUMBER_EXPRESSION"},"sourceReference":{"uri":"features/minimal/common.steps.ts","location":{"line":3}}}} +{"testRunStarted":{"timestamp":{"seconds":1713538432,"nanos":565000000}}} +{"testCase":{"pickleId":"024c5af0-2f06-4843-a403-718bc43a3eac","id":"92ead51e-e1f9-4e69-9e78-10f446071387","testSteps":[{"id":"f412b821-2f74-4a61-893f-400d4e569865","pickleStepId":"ea1ec2f8-71c2-450a-beb0-2cd0e88df0c8","stepDefinitionIds":["5a5145d5-9142-4a3f-a89d-3ebb198cdfe5"],"stepMatchArgumentsLists":[{"stepMatchArguments":[{"group":{"start":7,"value":"42","children":[]},"parameterTypeName":"int"}]}]}]}} +{"testCaseStarted":{"attempt":0,"testCaseId":"92ead51e-e1f9-4e69-9e78-10f446071387","id":"76e03fd9-2351-4bcf-a4cc-6af78db1fdac","timestamp":{"seconds":1713538432,"nanos":569000000}}} +{"testStepStarted":{"testCaseStartedId":"76e03fd9-2351-4bcf-a4cc-6af78db1fdac","testStepId":"f412b821-2f74-4a61-893f-400d4e569865","timestamp":{"seconds":1713538432,"nanos":569000000}}} +{"testStepFinished":{"testCaseStartedId":"76e03fd9-2351-4bcf-a4cc-6af78db1fdac","testStepId":"f412b821-2f74-4a61-893f-400d4e569865","testStepResult":{"duration":{"seconds":0,"nanos":238958},"status":"PASSED"},"timestamp":{"seconds":1713538432,"nanos":569000000}}} +{"testCaseFinished":{"testCaseStartedId":"76e03fd9-2351-4bcf-a4cc-6af78db1fdac","timestamp":{"seconds":1713538432,"nanos":570000000},"willBeRetried":false}} +{"testRunFinished":{"timestamp":{"seconds":1713538432,"nanos":570000000},"success":true}} diff --git a/test/reporter-cucumber-msg/features/minimal/minimal.feature b/test/reporter-cucumber-msg/features/minimal/minimal.feature index 2149409d..2ddbe7e9 100644 --- a/test/reporter-cucumber-msg/features/minimal/minimal.feature +++ b/test/reporter-cucumber-msg/features/minimal/minimal.feature @@ -6,7 +6,6 @@ Feature: minimal * a bullet * list - @only @bar Scenario: cukes Given I have 42 cukes in my belly diff --git a/test/special-tag-only/features/only-feature.feature b/test/special-tag-only/features/only-feature.feature new file mode 100644 index 00000000..1abac8f8 --- /dev/null +++ b/test/special-tag-only/features/only-feature.feature @@ -0,0 +1,10 @@ +@only +Feature: only feature + + Scenario: scenario 1 + Given "passing" step + + # @skip has precendence over feature level @only + @skip + Scenario: skipped scenario + Given "failing" step diff --git a/test/special-tag-only/features/only-scenario.feature b/test/special-tag-only/features/only-scenario.feature new file mode 100644 index 00000000..b2c61940 --- /dev/null +++ b/test/special-tag-only/features/only-scenario.feature @@ -0,0 +1,39 @@ +Feature: only scenario + + @only + Scenario: scenario with only + Given "passing" step + + Scenario: scenario without only + Given "failing" step + + @foo + @only + Scenario: scenario with only and other tags + Given "passing" step + + # @only takes precendence over @skip + @only + @skip + Scenario: scenario with only and skip + Given "passing" step + + @only + Scenario Outline: scenario outline with only + Given "" step + + Examples: + | type | + | passing | + + Scenario Outline: scenario outline with only example + Given "" step + + Examples: + | type | + | failing | + + @only + Examples: + | type | + | passing | diff --git a/test/special-tag-only/package.json b/test/special-tag-only/package.json new file mode 100644 index 00000000..85168234 --- /dev/null +++ b/test/special-tag-only/package.json @@ -0,0 +1,4 @@ +{ + "description": "This file is required for Playwright to consider this dir as a . It ensures to load 'playwright-bdd' from './test/node_modules/playwright-bdd' and output './test-results' here to avoid conficts.", + "smoke": true +} diff --git a/test/special-tag-only/playwright.config.ts b/test/special-tag-only/playwright.config.ts new file mode 100644 index 00000000..c0b5e7db --- /dev/null +++ b/test/special-tag-only/playwright.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from '@playwright/test'; +import { defineBddConfig } from 'playwright-bdd'; + +const testDir = defineBddConfig({ + paths: ['features'], + require: ['steps/*.ts'], + featuresRoot: 'features', +}); + +export default defineConfig({ + testDir, +}); diff --git a/test/special-tag-only/steps/steps.ts b/test/special-tag-only/steps/steps.ts new file mode 100644 index 00000000..4e844f8f --- /dev/null +++ b/test/special-tag-only/steps/steps.ts @@ -0,0 +1,8 @@ +import { expect } from '@playwright/test'; +import { createBdd } from 'playwright-bdd'; + +const { Given } = createBdd(); + +Given('{string} step', ({}, type: 'failing' | 'passing') => { + if (type === 'failing') expect(1).toEqual(2); +}); diff --git a/test/special-tag-only/test.mjs b/test/special-tag-only/test.mjs new file mode 100644 index 00000000..a783a73a --- /dev/null +++ b/test/special-tag-only/test.mjs @@ -0,0 +1,28 @@ +import { test, TestDir, execPlaywrightTest } from '../_helpers/index.mjs'; + +const testDir = new TestDir(import.meta); + +test(testDir.name, () => { + execPlaywrightTest(testDir.name); + + checkOnlyFeature(); + checkOnlyScenario(); +}); + +function checkOnlyFeature() { + testDir.expectFileContains('.features-gen/only-feature.feature.spec.js', [ + 'test.describe.only("only feature", () => {', + 'test.skip("skipped scenario", async ({ }) => {});', + ]); +} + +function checkOnlyScenario() { + testDir.expectFileContains('.features-gen/only-scenario.feature.spec.js', [ + 'test.only("scenario with only"', + 'test("scenario without only"', + 'test.only("scenario with only and other tags"', + 'test.only("scenario with only and skip"', + 'test.describe.only("scenario outline with only"', + 'test.only("Example #2"', + ]); +} diff --git a/test/special-tags/features/only-skip-fixme.feature b/test/special-tags/features/only-skip-fixme.feature deleted file mode 100644 index b9bdb615..00000000 --- a/test/special-tags/features/only-skip-fixme.feature +++ /dev/null @@ -1,50 +0,0 @@ -@only -Feature: only-skip-fixme - - @only - Scenario: Only - Given success step 1 - - @foo - @only - Scenario: Only several tags - Given success step 1 - - # @skip has precendence over feature level @only - @skip - Scenario: Skip - Given skipped step - - # in case of several system tags, @only takes precendence - @only - @skip - Scenario: Skip with only - Given success step 2 - - @fixme - Scenario: Fixme - Given skipped step - - @only - Scenario Outline: Check doubled - Then success step - - @only - Examples: - | value | - | 2 | - | 3 | - - @skip - Examples: - | value | - | 4 | - - @skip - Scenario Outline: Skipped scenario outline - Given skipped step - Given success step - - Examples: - | value | - | 1 | diff --git a/test/special-tags/features/skip-scenario.feature b/test/special-tags/features/skip-scenario.feature new file mode 100644 index 00000000..484a82fb --- /dev/null +++ b/test/special-tags/features/skip-scenario.feature @@ -0,0 +1,30 @@ +Feature: skip scenario + + @skip + Scenario: skipped scenario + Given skipped step + + @fixme + Scenario: fixme scenario + Given skipped step + + @skip + Scenario Outline: skipped scenario outline + Given skipped step + Given success step + + Examples: + | value | + | 1 | + + Scenario Outline: scenario outline with skipped example + Given success step + + Examples: + | value | + | 1 | + + @skip + Examples: + | value | + | 2 | diff --git a/test/special-tags/playwright.config.ts b/test/special-tags/playwright.config.ts index e83afe47..c0b5e7db 100644 --- a/test/special-tags/playwright.config.ts +++ b/test/special-tags/playwright.config.ts @@ -9,6 +9,4 @@ const testDir = defineBddConfig({ export default defineConfig({ testDir, - // ignore b/c it contains test.only - testIgnore: 'only-skip-fixme.feature.spec.js', }); diff --git a/test/special-tags/test.mjs b/test/special-tags/test.mjs index a87f244a..b3085681 100644 --- a/test/special-tags/test.mjs +++ b/test/special-tags/test.mjs @@ -5,35 +5,26 @@ const testDir = new TestDir(import.meta); test(testDir.name, () => { execPlaywrightTest(testDir.name); - checkOnlySkip(); + checkSkipScenario(); + checkSkipFeature(); checkFailTag(); checkTimeoutTag(); checkSlowTag(); checkRetriesTag(); checkModeTag(); - checkSkippedFeature(); }); -function checkOnlySkip() { - const generatedFile = `.features-gen/only-skip-fixme.feature.spec.js`; - testDir.expectFileContains(generatedFile, [ - 'test.describe.only("only-skip-fixme"', - 'test.only("Only"', - 'test.only("Only several tags"', - 'test.only("Skip with only"', - 'test.describe.only("Check doubled"', - 'test.only("Example #1"', - 'test.only("Example #2"', - // skipped - 'test.skip("Skip"', - 'test.fixme("Fixme"', - 'test.skip("Example #3"', - 'test.describe.skip("Skipped scenario outline"', +function checkSkipScenario() { + testDir.expectFileContains(`.features-gen/skip-scenario.feature.spec.js`, [ + 'test.skip("skipped scenario", async ({ }) => {});', + 'test.fixme("fixme scenario", async ({ }) => {});', + 'test.describe.skip("skipped scenario outline", () => {});', + 'test("Example #1", async ({ Given }) => {', + 'test.skip("Example #2", async ({ }) => {});', ]); - testDir.expectFileNotContain(generatedFile, ['Skipped step']); } -function checkSkippedFeature() { +function checkSkipFeature() { testDir.expectFileNotExist(`.features-gen/skip-feature.feature.spec.js`); }