I can use the PlayWright experimental component testing to test my HelloWorld.vue component. This works:
import { test, expect } from '@playwright/experimental-ct-vue';
import HelloWorld from './HelloWorld.vue';
test.use({ viewport: { width: 500, height: 500 } });
test('should work', async ({ mount }) => {
const component = await mount(HelloWorld, {
props: {
msg: 'You did it!'
}
});
await expect(component).toContainText('Vite + Vue');
});
But now I want to add CucumberJS into the stack. Since the Vue app uses ESM modules my step definition file is an mjs
file so I can use "import" rather than "require".
The issue is I get the TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".vue"
where I am importing the component.
cmp-helloworld.mjs:
import { Given, When, Then } from '@cucumber/cucumber';
import { test, expect } from '@playwright/experimental-ct-vue';
import HelloWorld from '../../components/HelloWorld.vue'; // <== Throws the error
let component;
When('I mount the component with the message {string}', async function (message) {
component = await mount(HelloWorld, {
props: {
msg: message
}
});
});
// Then ...
Any ideas about how can I do this, please? It will be a bummer if I can't use BDD with PlayWright component tests.
And... if I solve the import issue, yes I will need to get the mount
function from somewhere. But that is the next hurdle. Has anyone achieved this combination?
Edit: sharing package.json
{
"name": "myappct",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test:unit": "vitest",
"test:e2e": "playwright test -c playwright-e2e.conf.js",
"test-ct": "playwright test -c playwright-ct.config.js",
"pretest": "node ./src/test/helpers/init.mjs",
"test": "cross-env TEST_PROFILE=test cucumber-js --config src/test/config/cucumber.mjs || true",
"posttest": "node cucumber-html-report.js",
"test:failed": "cucumber-js -p rerun @rerun.txt"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.5.0",
"vue": "^3.4.29"
},
"devDependencies": {
"@cucumber/cucumber": "^10.8.0",
"@playwright/experimental-ct-vue": "^1.45.1",
"@playwright/test": "^1.45.1",
"@types/node": "^20.14.10",
"@vitejs/plugin-vue": "^5.0.5",
"@vue/test-utils": "^2.4.6",
"cross-env": "^7.0.3",
"fs-extra": "^11.2.0",
"jsdom": "^24.1.0",
"multiple-cucumber-html-reporter": "^3.6.2",
"vite": "^5.3.1",
"vite-plugin-vue-devtools": "^7.3.1",
"vitest": "^1.6.0"
}
}
And just for completeness, here is a working example of a PlayWright + Cucumber (JS) e2e test. I was hoping to be able to achieve something similar with component testing.
import { Given, When, Then, setDefaultTimeout } from '@cucumber/cucumber';
import { test, expect, chromium } from '@playwright/test';
// Global browser and page state for scenarios
let browser;
let page;
Given('I am on the Playwright website', async function () {
browser = await chromium.launch({ headless: true });
page = await browser.newPage();
await page.goto('https://playwright.dev/');
});
Then('the page title should be {string}', async function (title) {
// Turn the string into a regular expression
const re = new RegExp(title);
await expect(page).toHaveTitle(re);
await browser.close();
});
When('I click on the {string} link', async function (linkText) {
// Click the get started link.
await page.getByRole('link', { name: linkText }).click();
});
Then('I should be redirected to the {string} page', async function (pageName) {
// Expects page to have a heading with the name of Installation.
await expect(page.getByRole('heading', { name: pageName })).toBeVisible();
await browser.close();
});
After much testing and hair-pulling I find that for now it is not possible to use CucumberJS to test Vue components. PlayWright + CucumberJS is fine for Vue e2e tests but not for component testing.
One reason is a fundamental conflict in the module systems. While CucumberJS now does support ES modules, Vue is using Vite to transpile (whether you use CommonJS or add "type":"module" to package.json to get ESM). So, when the Cucumber step file encounters an import like:
import HelloWorld from '../../components/HelloWorld.vue';
it expects an ESM import but it is not such a thing. Vue can handle this "importing" via Vite, but Cucumber cannot so it wont know what to do with the file even if it did manage to import it.
I am using Vitest and Vitest-cucumber for Vue / Quasar component testing and that works well enough. Vitest-cucumber is not a CucumberJS implementation - it is a partial implementation of Gherkin with wrapper functions around "describe / it" via Given, When, Then functions etc. But at least I can write Gherkin feature files for better documentation than just the unit tests.
If you want to use that for Quasar, see also: here
:-)