Skip to content

Commit

Permalink
Merge branch component-tests of https://github.com/cassus/playwright-bdd
Browse files Browse the repository at this point in the history
 into cassus-component-tests
  • Loading branch information
vitalets committed Oct 26, 2023
2 parents bf53c82 + b05b733 commit 5f49d7b
Show file tree
Hide file tree
Showing 15 changed files with 2,353 additions and 134 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ npm-debug.log
# my
/dist
**/.features-gen/**/*.spec.js
**/.cache
test-results
playwright-report
/examples/playwright-bdd*.tgz
Expand Down
2,341 changes: 2,229 additions & 112 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@
"devDependencies": {
"@cucumber/cucumber": "^9.2.0",
"@eslint/js": "^8.51.0",
"@playwright/experimental-ct-react": "1.36",
"@playwright/test": "1.36",
"@types/node": "^18.15.0",
"@types/react": "^18.2.29",
"@types/react-dom": "^18.2.13",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"cross-env": "^7.0.3",
Expand All @@ -65,6 +68,8 @@
"npm-run-all": "^4.1.5",
"prettier": "^3.0.3",
"publint": "^0.2.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
},
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { defineBddConfig, BDDInputConfig } from './config';
export { createBdd } from './stepDefinitions/createBdd';
export { test } from './run/bddFixtures';
export { test, BddFixtures, bddFixtures } from './run/bddFixtures';
export { BddWorld, BddWorldOptions } from './run/bddWorld';
35 changes: 23 additions & 12 deletions src/playwright/testTypeImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { test, Fixtures } from '@playwright/test';
import { Location } from '@playwright/test/reporter';
import { getSymbolByName } from '../utils';
import { TestTypeCommon } from './types';
import { bddFixtures } from '../run/bddFixtures';
import { exit } from '../utils/exit';

type FixturesWithLocation = {
fixtures: Fixtures;
Expand Down Expand Up @@ -46,18 +48,27 @@ export async function runStepWithCustomLocation(
}

/**
* Returns true if all fixtures of parent test found in child test.
* Returns true if this `test` function has all the fixtures we need
*/
export function isParentChildTest(parent: TestTypeCommon, child: TestTypeCommon) {
if (parent === child) return false;
const childLocationsSet = new Set(
getTestFixtures(child).map((f) => locationToString(f.location)),
);
return getTestFixtures(parent).every((f) => {
return childLocationsSet.has(locationToString(f.location));
});
}
export function assertHasBddFixtures(test: TestTypeCommon) {
const allDefinedFixtures = Object.assign(
{},
...getTestFixtures(test).map((fixtureSet) => fixtureSet.fixtures),
) as Fixtures<
Record<string, unknown>,
Record<string, unknown>,
Record<string, unknown>,
Record<string, unknown>
>;

function locationToString({ file, line, column }: Location) {
return `${file}:${line}:${column}`;
const missingFixtures = Object.keys(bddFixtures).filter(
(name) => allDefinedFixtures[name] === undefined,
);
if (missingFixtures.length > 0) {
exit(
`createBdd() should use test extended from "playwright-bdd" Missing fixtures: ${missingFixtures.join(
', ',
)}`,
);
}
}
7 changes: 4 additions & 3 deletions src/run/bddFixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type BddFixtures = {
$test: TestTypeCommon;
};

export const test = base.extend<BddFixtures>({
export const bddFixtures: Parameters<typeof base.extend<BddFixtures>>[0] = {
$bddWorldBase: async ({ $tags, $test }, use, testInfo) => {
const config = getConfigFromEnv(testInfo.project.testDir);
const environment = { cwd: getPlaywrightConfigDir() };
Expand All @@ -48,7 +48,7 @@ export const test = base.extend<BddFixtures>({
$tags,
$test,
parameters: runConfiguration.runtime.worldParameters || {},
log: () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
log: () => {},
attach: async () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
});
await world.init();
Expand Down Expand Up @@ -86,7 +86,8 @@ export const test = base.extend<BddFixtures>({
$tags: ({}, use) => use([]),
// Init $test fixture with base test, but it will be always overwritten in test file
$test: ({}, use) => use(base),
});
};
export const test = base.extend<BddFixtures>(bddFixtures);

/** these fixtures automatically injected into every step call */
export type BddAutoInjectFixtures = Pick<BddFixtures, '$test' | '$tags'> & {
Expand Down
7 changes: 3 additions & 4 deletions src/stepDefinitions/createBdd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import { GherkinStepKeyword } from '@cucumber/cucumber/lib/models/gherkin_step_k
import { FixturesArg, KeyValue, TestTypeCommon } from '../playwright/types';
import { TestType } from '@playwright/test';
import { BddAutoInjectFixtures, test as baseTest } from '../run/bddFixtures';
import { isParentChildTest } from '../playwright/testTypeImpl';
import { assertHasBddFixtures } from '../playwright/testTypeImpl';
import { defineStep } from './defineStep';
import { exit } from '../utils/exit';

/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types */

Expand Down Expand Up @@ -49,8 +48,8 @@ function isCustomTest<T extends KeyValue = {}, W extends KeyValue = {}>(
customTest?: TestType<T, W>,
) {
const isCustomTest = Boolean(customTest && customTest !== (baseTest as TestTypeCommon));
if (isCustomTest && customTest && !isParentChildTest(baseTest, customTest)) {
exit(`createBdd() should use test extended from "playwright-bdd"`);
if (customTest && isCustomTest) {
assertHasBddFixtures(customTest);
}
return isCustomTest;
}
13 changes: 13 additions & 0 deletions test/component-tests/features/scenario-simple.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Feature: component-tests

Scenario: Mount component and interact with it
Given Mounted input component
When I type "ABC"
Then input field has "ABC"

Scenario: Using event handler in a component
Given Mounted button with an event handler that record how many times it was pressed
When I press the button
Then the recorded number of times the button was pressed is 1
When I press the button
Then the recorded number of times the button was pressed is 2
13 changes: 13 additions & 0 deletions test/component-tests/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineConfig } from '@playwright/experimental-ct-react';
import { defineBddConfig } from '../../dist';

const testDir = defineBddConfig({
importTestFrom: 'steps/fixtures.ts',
paths: ['features'],
require: ['steps/steps.tsx'],
});

export default defineConfig({
testDir,
forbidOnly: Boolean(process.env.FORBID_ONLY),
});
6 changes: 6 additions & 0 deletions test/component-tests/playwright/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<html lang="en">
<body>
<div id="root"></div>
<script type="module" src="./index.ts"></script>
</body>
</html>
1 change: 1 addition & 0 deletions test/component-tests/playwright/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Apply theme here, add anything your component needs at runtime here.
13 changes: 13 additions & 0 deletions test/component-tests/steps/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { test as ctBase } from '@playwright/experimental-ct-react';
import { BddFixtures, bddFixtures } from '../../../dist';

type Fixtures = {
world: {
clickedTimes: number;
};
};

const bddCtBase = ctBase.extend<BddFixtures>(bddFixtures);
export const test = bddCtBase.extend<Fixtures>({
world: ({}, use) => use({ clickedTimes: 0 }),
});
35 changes: 35 additions & 0 deletions test/component-tests/steps/steps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react-dom';
import { expect } from '@playwright/test';
import { createBdd } from '../../../dist';
import { test } from './fixtures';

const { Given, When, Then } = createBdd(test);

Given('Mounted input component', async ({ mount }) => {
await mount(<input type="text" data-testid="textField" />);
});

When('I type {string}', async ({ page }, arg: string) => {
await page.getByTestId('textField').fill(arg);
});

Then('input field has {string}', async ({ page }, arg: string) => {
await expect(page.getByTestId('textField')).toHaveValue(arg);
});

Given(
'Mounted button with an event handler that record how many times it was pressed',
async ({ mount, world }) => {
await mount(
<button type="button" data-testid="button" onClick={() => (world.clickedTimes += 1)} />,
);
},
);

When('I press the button', async ({ page }) => {
await page.getByTestId('button').click();
});

Then('the recorded number of times the button was pressed is {int}', async ({ world }, arg) => {
expect(world.clickedTimes).toBe(arg);
});
3 changes: 3 additions & 0 deletions test/component-tests/test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { test, getTestName, execPlaywrightTest } from '../helpers.mjs';

test(getTestName(import.meta), (t) => execPlaywrightTest(t.name));
5 changes: 3 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"skipLibCheck": true,
"noEmit": true,
"resolveJsonModule": true,
"esModuleInterop": true
"esModuleInterop": true,
"jsx": "react"
},
"include": ["**/*.ts"]
"include": ["**/*.ts", "**/*.tsx"]
}

0 comments on commit 5f49d7b

Please sign in to comment.