diff --git a/CHANGELOG.md b/CHANGELOG.md index d446dfad..5708a99d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog ## dev -* i18n: Generate scenario outlines correctly [#60](https://github.com/vitalets/playwright-bdd/issues/60)). +* i18n: Generate scenario outlines correctly [#60](https://github.com/vitalets/playwright-bdd/issues/60). +* Check for duplicate fixture names [#52](https://github.com/vitalets/playwright-bdd/issues/52) ## 5.3.0 * Add support for Playwright `1.38`. diff --git a/src/stepDefinitions/decorators/poms.ts b/src/stepDefinitions/decorators/poms.ts index 3f1255e2..96f208c3 100644 --- a/src/stepDefinitions/decorators/poms.ts +++ b/src/stepDefinitions/decorators/poms.ts @@ -8,6 +8,7 @@ import { TestType } from '@playwright/test'; import { BuiltInFixtures } from '../../playwright/types'; import { BddFixtures } from '../../run/bddFixtures'; import { linkStepsWithPomNode } from './steps'; +import { exitWithMessage } from '../../utils'; type PomClass = Function; @@ -17,9 +18,10 @@ type PomClass = Function; */ const pomGraph = new Map(); -// Representation of POM class with inherited children classes. +// POM class with inherited children POMs: representation of classes inheritance. export type PomNode = { fixtureName: string; + className: string; children: Set; }; @@ -38,17 +40,32 @@ export function Fixture(fixtureName: CustomFixturesNames) { } function createPomNode(Ctor: PomClass, fixtureName: string) { - const pomNode: PomNode = { fixtureName, children: new Set() }; + const pomNode: PomNode = { + fixtureName, + className: Ctor.name, + children: new Set(), + }; + ensureUniqueFixtureName(pomNode); pomGraph.set(Ctor, pomNode); linkStepsWithPomNode(Ctor, pomNode); linkParentWithPomNode(Ctor, pomNode); return pomNode; } +function ensureUniqueFixtureName({ fixtureName, className }: PomNode) { + if (!fixtureName) return; + const existingPom = getPomNodeByFixtureName(fixtureName); + if (existingPom) + exitWithMessage( + `Duplicate fixture name "${fixtureName}"`, + `defined for classes: ${existingPom.className}, ${className}`, + ); +} + function linkParentWithPomNode(Ctor: PomClass, pomNode: PomNode) { const parentCtor = Object.getPrototypeOf(Ctor); if (!parentCtor) return; - // if parentCtor is not in pomGraph, add it as well + // if parentCtor is not in pomGraph, add it. // Case: parent class is not marked with @Fixture, but has decorator steps (base class) const parentPomNode = pomGraph.get(parentCtor) || createPomNode(parentCtor, ''); parentPomNode.children.add(pomNode); diff --git a/test/decorators-duplicate-fixture-name/fixtures.ts b/test/decorators-duplicate-fixture-name/fixtures.ts new file mode 100644 index 00000000..29f2db7a --- /dev/null +++ b/test/decorators-duplicate-fixture-name/fixtures.ts @@ -0,0 +1,25 @@ +import { test as base } from '../../dist'; +import { Fixture, Given } from '../../dist/decorators'; + +type Fixtures = { + todoPage: TodoPage; + todoPage2: TodoPage2; +}; + +export const test = base.extend({ + todoPage: ({}, use) => use(new TodoPage()), + todoPage2: ({}, use) => use(new TodoPage2()), +}); + +@Fixture('todoPage') +class TodoPage { + @Given('TodoPage: step') + async step() {} +} + +// notice the same fixture name +@Fixture('todoPage') +class TodoPage2 { + @Given('TodoPage2: step') + async step() {} +} diff --git a/test/decorators-duplicate-fixture-name/playwright.config.ts b/test/decorators-duplicate-fixture-name/playwright.config.ts new file mode 100644 index 00000000..b023f78e --- /dev/null +++ b/test/decorators-duplicate-fixture-name/playwright.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from '@playwright/test'; +import { defineBddConfig } from '../../dist'; + +const testDir = defineBddConfig({ + importTestFrom: 'fixtures.ts', + paths: [`sample.feature`], +}); + +export default defineConfig({ + testDir, + forbidOnly: Boolean(process.env.FORBID_ONLY), +}); diff --git a/test/decorators-duplicate-fixture-name/sample.feature b/test/decorators-duplicate-fixture-name/sample.feature new file mode 100644 index 00000000..83cb9fae --- /dev/null +++ b/test/decorators-duplicate-fixture-name/sample.feature @@ -0,0 +1,4 @@ +Feature: duplicate fixture name + + Scenario: sample scenario + Given TodoPage: step diff --git a/test/decorators-duplicate-fixture-name/test.mjs b/test/decorators-duplicate-fixture-name/test.mjs new file mode 100644 index 00000000..c2346c50 --- /dev/null +++ b/test/decorators-duplicate-fixture-name/test.mjs @@ -0,0 +1,9 @@ +import { test, TestDir, execPlaywrightTestWithError } from '../helpers.mjs'; + +const testDir = new TestDir(import.meta); + +test(testDir.name, () => + execPlaywrightTestWithError(testDir.name, [ + `Duplicate fixture name "todoPage" defined for classes: TodoPage, TodoPage2`, + ]), +);