diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml
index 9d592deb7..20a6bc0ab 100644
--- a/.github/workflows/e2e-test.yml
+++ b/.github/workflows/e2e-test.yml
@@ -1,4 +1,4 @@
-name: E2E Cypress tests
+name: E2E Playwright tests
env:
LABEL_RUNNING: e2e-running
LABEL_SUCCESS: e2e-passed
@@ -29,11 +29,11 @@ jobs:
uses: actions/cache@v2
id: step-cache-node-modules
env:
- cache-name: cache-cypress-node-modules-test
+ cache-name: cache-node-modules-test
with:
path: |
node_modules
- /home/runner/.cache/Cypress
+ packages/*/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('yarn.lock') }}
- name: Install dependencies
if: steps.step-cache-node-modules.outputs.cache-hit != 'true'
@@ -41,7 +41,7 @@ jobs:
yarn --frozen-lockfile
test:
- name: Cypress tests
+ name: Playwright tests
needs: init
if: github.event.label.name == 'e2e-running' || github.event_name == 'push'
runs-on: ubuntu-latest
@@ -68,12 +68,13 @@ jobs:
type: remove
- name: Cache node_modules
uses: actions/cache@v2
+ id: step-cache-node-modules
env:
- cache-name: cache-cypress-node-modules-test
+ cache-name: cache-node-modules-test
with:
path: |
node_modules
- /home/runner/.cache/Cypress
+ packages/*/node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('yarn.lock') }}
- name: get preview url
id: get-preview-url
@@ -81,11 +82,16 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
platform: StorefrontCloud
- - name: yarn test e2e
+ - name: Set the env value
+ id: set-env-value
+ run: |
+ echo "BASE_URL=${{ github.event.inputs.page_url || steps.get-preview-url.outputs.comment_url }}" >> $GITHUB_ENV
+ - name: yarn test theme e2e
run: |
- yarn cypress run --config baseUrl=${{ github.event.inputs.page_url || steps.get-preview-url.outputs.comment_url }}
+ npx playwright install
+ yarn test:theme
env:
- CI: true
+ BASE_URL: ${{ github.event.inputs.page_url || steps.get-preview-url.outputs.comment_url }}
# Take care of labels
- name: remove running label
if: failure() || success()
diff --git a/package.json b/package.json
index a21b05abf..175e3d662 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
"lint": "prettier --write --parser typescript \"packages/**/*.ts\"",
"test": "NODE_OPTIONS=--unhandled-rejections=warn jest --runInBand",
"test:e2e": "jest --e2e=true --runInBand",
- "test:cypress": "cypress run",
+ "test:theme": "cd ./packages/default-theme && yarn test:e2e",
"test:coverage": "yarn test --coverage",
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs",
diff --git a/packages/default-theme/__e2e__/fixtures/example.json b/packages/default-theme/__e2e__/fixtures/example.json
deleted file mode 100644
index da18d9352..000000000
--- a/packages/default-theme/__e2e__/fixtures/example.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "name": "Using fixtures to represent data",
- "email": "hello@cypress.io",
- "body": "Fixtures are a great way to mock data for responses to routes"
-}
\ No newline at end of file
diff --git a/packages/default-theme/__e2e__/helpers/testHelpers.ts b/packages/default-theme/__e2e__/helpers/testHelpers.ts
new file mode 100644
index 000000000..6ee1f50f6
--- /dev/null
+++ b/packages/default-theme/__e2e__/helpers/testHelpers.ts
@@ -0,0 +1,48 @@
+import faker from "faker";
+import { Page, expect } from "@playwright/test";
+
+export async function fillRegistrationForm({ page }: { page: Page }) {
+ await expect(page.locator("#Salutation")).toContainText("Not specified");
+
+ // Fill [data-testid="registration-first-name-input"] [data-testid="registration-first-name-input"]
+ await page.fill(
+ '[data-testid="registration-first-name-input"] [data-testid="registration-first-name-input"]',
+ faker.name.firstName()
+ );
+
+ // Fill [data-testid="registration-last-name-input"] [data-testid="registration-last-name-input"]
+ await page.fill(
+ '[data-testid="registration-last-name-input"] [data-testid="registration-last-name-input"]',
+ faker.name.lastName()
+ );
+
+ // Click [data-testid="guest-registration-checkbox"] div
+ await page.click('[data-testid="guest-registration-checkbox"] div');
+
+ // Fill [data-testid="registration-email-input"] [data-testid="registration-email-input"]
+ await page.fill(
+ '[data-testid="registration-email-input"] [data-testid="registration-email-input"]',
+ faker.internet.email()
+ );
+
+ // Fill [data-testid="registration-street-input"] [data-testid="registration-street-input"]
+ await page.fill(
+ '[data-testid="registration-street-input"] [data-testid="registration-street-input"]',
+ faker.address.streetName()
+ );
+
+ // Fill [data-testid="registration-zipcode-input"] [data-testid="registration-zipcode-input"]
+ await page.fill(
+ '[data-testid="registration-zipcode-input"] [data-testid="registration-zipcode-input"]',
+ faker.address.zipCode()
+ );
+
+ // Fill [data-testid="registration-city-input"] [data-testid="registration-city-input"]
+ await page.fill(
+ '[data-testid="registration-city-input"] [data-testid="registration-city-input"]',
+ faker.address.cityName()
+ );
+
+ // Click [data-testid="register-button"]
+ await page.click('[data-testid="register-button"]');
+}
diff --git a/packages/default-theme/__e2e__/playwright.config.ts b/packages/default-theme/__e2e__/playwright.config.ts
new file mode 100644
index 000000000..2bf27b8a3
--- /dev/null
+++ b/packages/default-theme/__e2e__/playwright.config.ts
@@ -0,0 +1,12 @@
+import { PlaywrightTestConfig } from "@playwright/test";
+
+const baseURL = process.env.BASE_URL || "http://localhost:3000";
+console.error("Test for base url: ", baseURL);
+const config: PlaywrightTestConfig = {
+ use: {
+ baseURL,
+ },
+ timeout: 120000,
+ retries: 2,
+};
+export default config;
diff --git a/packages/default-theme/__e2e__/plugins/index.js b/packages/default-theme/__e2e__/plugins/index.js
deleted file mode 100644
index 8dd144a6c..000000000
--- a/packages/default-theme/__e2e__/plugins/index.js
+++ /dev/null
@@ -1,21 +0,0 @@
-///
-// ***********************************************************
-// This example plugins/index.js can be used to load plugins
-//
-// You can change the location of this file or turn off loading
-// the plugins file with the 'pluginsFile' configuration option.
-//
-// You can read more here:
-// https://on.cypress.io/plugins-guide
-// ***********************************************************
-
-// This function is called when a project is opened or re-opened (e.g. due to
-// the project's config changing)
-
-/**
- * @type {Cypress.PluginConfig}
- */
-module.exports = (on, config) => {
- // `on` is used to hook into various events Cypress emits
- // `config` is the resolved Cypress config
-};
diff --git a/packages/default-theme/__e2e__/specs/desktopHappyPathExistingUser.spec.ts b/packages/default-theme/__e2e__/specs/desktopHappyPathExistingUser.spec.ts
new file mode 100644
index 000000000..1ac11102c
--- /dev/null
+++ b/packages/default-theme/__e2e__/specs/desktopHappyPathExistingUser.spec.ts
@@ -0,0 +1,60 @@
+import { test } from "@playwright/test";
+
+test.use({
+ viewport: {
+ width: 1920,
+ height: 1080,
+ },
+});
+
+test("[DESKTOP] Happy path logged in user", async ({ page, baseURL }) => {
+ await page.goto('/');
+
+ await page.click('[data-testid="login-icon"]');
+ // Fill [data-testid="email-input"] [data-testid="email-input"]
+ await page.fill(
+ '[data-testid="email-input"] [data-testid="email-input"]',
+ "1d7b9fef36a34367ad02993594db3fc9rlegros@example.com"
+ );
+ // Fill [data-testid="password-input"] [data-testid="password-input"]
+ await page.fill(
+ '[data-testid="password-input"] [data-testid="password-input"]',
+ "shopware"
+ );
+ // Click [data-testid="submit-login-button"]
+ await page.click('[data-testid="submit-login-button"]');
+
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="top-navigation"] a'),
+ ]);
+
+ await Promise.all([
+ page.hover('[data-testid="product-card"]'),
+ page.click('[data-testid="product-card"] .sf-product-card__add-button'),
+ ]);
+
+ await page.click('[data-testid="cart-icon"]');
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="goToCheckout-button"]'),
+ ]);
+
+ await page.click(
+ '[data-testid="checkout-payment-method-Cash-on-delivery"] div'
+ );
+ await page.click(
+ '[data-testid="checkout-payment-method-Cash-on-delivery"] .is-active'
+ );
+
+ // Click [data-testid="termsAgreementCheckbox"] div
+ await page.click('[data-testid="termsAgreementCheckbox"] div');
+
+ // Click [data-testid="place-my-order"]
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="place-my-order"]'),
+ ]);
+
+ await page.click('h2:has-text("Thank you")');
+});
diff --git a/packages/default-theme/__e2e__/specs/desktopHappyPathGuestUser.spec.ts b/packages/default-theme/__e2e__/specs/desktopHappyPathGuestUser.spec.ts
new file mode 100644
index 000000000..607dde085
--- /dev/null
+++ b/packages/default-theme/__e2e__/specs/desktopHappyPathGuestUser.spec.ts
@@ -0,0 +1,76 @@
+import { test } from "@playwright/test";
+import { fillRegistrationForm } from "../helpers/testHelpers";
+
+test.use({
+ viewport: {
+ width: 1920,
+ height: 1080,
+ },
+});
+
+test("[DESKTOP] Happy path guest user", async ({ page }) => {
+ // Go to /
+ await page.goto("/");
+
+ // Click [data-testid="search-bar"]
+ await page.click('[data-testid="search-bar"]');
+
+ // Fill [data-testid="search-bar"]
+ await page.fill('[data-testid="search-bar"]', "aaa");
+
+ // Click [data-testid="quicksearch-result"]
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="quicksearch-result"]'),
+ ]);
+
+ // Click [data-testid="button-addToCart"]
+ await page.click('[data-testid="button-addToCart"]');
+
+ // Click [data-testid="cart-icon"]
+ await page.click('[data-testid="cart-icon"]');
+
+ // Click text=Total items 1
+ await page.click("text=Total items 1");
+
+ // Click [data-testid="goToCheckout-button"]
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="goToCheckout-button"]'),
+ ]);
+
+ await fillRegistrationForm({ page });
+
+ // Click text=Shipping methods
+ await page.click("text=Shipping methods");
+
+ await page.click(
+ '[data-testid="checkout-payment-method-Cash-on-delivery"] div'
+ );
+ await page.click(
+ '[data-testid="checkout-payment-method-Cash-on-delivery"] .is-active'
+ );
+
+ // Check if we can submit order without agreeing to Terms
+ // Click [data-testid="place-my-order"]
+ await page.click('[data-testid="place-my-order"]');
+ // Click text=This field is required
+ await page.click("text=This field is required");
+ // Click [data-testid="termsAgreementCheckbox"] div
+ await page.click('[data-testid="termsAgreementCheckbox"] div');
+
+ // Click [data-testid="place-my-order"]
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="place-my-order"]'),
+ ]);
+
+ // Click h2:has-text("Thank you")
+ await page.click('h2:has-text("Thank you")');
+
+ // Click text=Payment method Cash on delivery
+ await page.click("text=Payment method Cash on delivery");
+
+ // Close page
+ await page.close();
+});
diff --git a/packages/default-theme/__e2e__/specs/languageSwitcher.spec.js b/packages/default-theme/__e2e__/specs/languageSwitcher.todo.js
similarity index 100%
rename from packages/default-theme/__e2e__/specs/languageSwitcher.spec.js
rename to packages/default-theme/__e2e__/specs/languageSwitcher.todo.js
diff --git a/packages/default-theme/__e2e__/specs/mobileHappyPathGuestUser.spec.ts b/packages/default-theme/__e2e__/specs/mobileHappyPathGuestUser.spec.ts
new file mode 100644
index 000000000..78616bf8c
--- /dev/null
+++ b/packages/default-theme/__e2e__/specs/mobileHappyPathGuestUser.spec.ts
@@ -0,0 +1,74 @@
+import { test } from "@playwright/test";
+import { fillRegistrationForm } from "../helpers/testHelpers";
+
+test.use({
+ viewport: {
+ width: 320,
+ height: 480,
+ },
+});
+
+test("[MOBILE] Happy path guest user", async ({ page }) => {
+ // Go to /
+ await page.goto("/");
+
+ // Click [data-testid="search-bar"]
+ await page.click('[data-testid="search-bar"]');
+
+ // Fill [data-testid="search-bar"]
+ await page.fill('[data-testid="search-bar"]', "aaa");
+
+ // Press Enter
+ await Promise.all([
+ page.waitForNavigation(),
+ page.press('[data-testid="search-bar"]', "Enter"),
+ ]);
+
+ // Click img[alt="Levis X-star Wars Galaxy Far Away Pullover Hoodie Junior"]
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="product-card"] img'),
+ ]);
+
+ // Click [data-testid="button-addToCart"]
+ await page.click('[data-testid="button-addToCart"]');
+
+ // Click [aria-label="Go to Cart"]
+ await page.click('[aria-label="Go to Cart"]');
+
+ // Click [data-testid="goToCheckout-button"]
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="goToCheckout-button"]'),
+ ]);
+
+ await fillRegistrationForm({ page });
+
+ // Click text=Shipping methods
+ await page.click("text=Shipping methods");
+
+ await page.click(
+ '[data-testid="checkout-payment-method-Cash-on-delivery"] div'
+ );
+ await page.click(
+ '[data-testid="checkout-payment-method-Cash-on-delivery"] .is-active'
+ );
+
+ // Click [data-testid="termsAgreementCheckbox"] div
+ await page.click('[data-testid="termsAgreementCheckbox"] div');
+
+ // Click [data-testid="place-my-order"]
+ await Promise.all([
+ page.waitForNavigation(),
+ page.click('[data-testid="place-my-order"]'),
+ ]);
+
+ // Click h2:has-text("Thank you")
+ await page.click('h2:has-text("Thank you")');
+
+ // Click text=Payment method Cash on delivery
+ await page.click("text=Payment method Cash on delivery");
+
+ // Close page
+ await page.close();
+});
diff --git a/packages/default-theme/__e2e__/specs/passwordReset.spec.js b/packages/default-theme/__e2e__/specs/passwordReset.todo.js
similarity index 100%
rename from packages/default-theme/__e2e__/specs/passwordReset.spec.js
rename to packages/default-theme/__e2e__/specs/passwordReset.todo.js
diff --git a/packages/default-theme/__e2e__/specs/shoppingHappyPath.spec.js b/packages/default-theme/__e2e__/specs/shoppingHappyPath.spec.js
deleted file mode 100644
index 5f09ce2b7..000000000
--- a/packages/default-theme/__e2e__/specs/shoppingHappyPath.spec.js
+++ /dev/null
@@ -1,81 +0,0 @@
-describe("Shopping happy path", () => {
- beforeEach(() => {
- cy.intercept("GET", "**/store-api/currency").as("getCurrencies");
- cy.visit("/");
- cy.wait("@getCurrencies");
- });
-
- it("[DESKTOP]: checkout as guest user", () => {
- cy.get("[data-cy=search-bar]").click();
- cy.get("[data-cy=search-bar]").type("aaa");
- cy.get(".search-suggestions__product:nth-child(1)").click();
-
- cy.get("[data-cy=button-addToCart]").click();
-
- cy.get('[data-cy="cart-icon"] > .sf-badge').click();
- cy.get("[data-cy=goToCheckout-button]").click();
-
- cy.fillAndExecuteRegistrationForm();
-
- cy.get("[data-cy=checkout-payment-method-Cash-on-delivery] input").click();
-
- cy.get("[data-cy=place-my-order]").click();
-
- cy.contains("Thank you");
- });
-
- it("[DESKTOP]: checkout path as logged in user", () => {
- cy.login();
-
- cy.get("[data-cy=search-bar]").click();
- cy.get("[data-cy=search-bar]").type("aaa");
- cy.get(".search-suggestions__product:nth-child(1)").click();
- cy.get("[data-cy=button-addToCart]").click();
-
- cy.get('[data-cy="cart-icon"] > .sf-badge').click();
- cy.get("[data-cy=goToCheckout-button]").click();
-
- cy.get("[data-cy=checkout-payment-method-Cash-on-delivery] input").click();
-
- cy.get("[data-cy=place-my-order]").click();
-
- cy.contains("Thank you");
- });
-
- it("[MOBILE]: checkout as guest user", () => {
- cy.viewport("iphone-5");
- cy.get("[data-cy=search-bar]").click();
- cy.get("[data-cy=search-bar]").type("aaa{enter}");
- cy.get(".sf-product-card:nth-child(1) img").click();
- cy.get("[data-cy=button-addToCart]").click();
-
- cy.get('[data-cy="bottom-navigation-cart"]').click();
- cy.get("[data-cy=goToCheckout-button]").click();
-
- cy.fillAndExecuteRegistrationForm();
-
- cy.get("[data-cy=checkout-payment-method-Cash-on-delivery] input").click();
-
- cy.get("[data-cy=place-my-order]").click();
- cy.contains("Thank you");
- });
-
- it("[MOBILE]: checkout as logged in user", () => {
- cy.viewport("iphone-5");
- cy.login();
-
- cy.get("[data-cy=search-bar]").click();
- cy.get("[data-cy=search-bar]").type("aaa{enter}");
- cy.get(".sf-product-card:nth-child(1) img").click();
- cy.get("[data-cy=button-addToCart]").click();
-
- cy.get('[data-cy="bottom-navigation-cart"]').click();
- cy.get("[data-cy=goToCheckout-button]").click();
-
- cy.get("[data-cy=checkout-payment-method-Cash-on-delivery] input").click();
-
- cy.get("[data-cy=place-my-order]").click();
-
- cy.contains("Thank you");
- });
-});
diff --git a/packages/default-theme/__e2e__/support/commands.js b/packages/default-theme/__e2e__/support/commands.js
deleted file mode 100644
index 69b5bc6e5..000000000
--- a/packages/default-theme/__e2e__/support/commands.js
+++ /dev/null
@@ -1,97 +0,0 @@
-// ***********************************************
-// This example commands.js shows you how to
-// create various custom commands and overwrite
-// existing commands.
-//
-// For more comprehensive examples of custom
-// commands please read more here:
-// https://on.cypress.io/custom-commands
-// ***********************************************
-//
-//
-// -- This is a parent command --
-// Cypress.Commands.add("login", (email, password) => { ... })
-//
-//
-// -- This is a child command --
-// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
-//
-//
-// -- This is a dual command --
-// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
-//
-//
-// -- This will overwrite an existing command --
-
-// const { createPartiallyEmittedExpression } = require("typescript")
-import faker from "faker";
-
-// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
-
-Cypress.Commands.overwrite("click", (originalFunction, subject, options) => {
- // we're invoking click with force by default to avoid scrolling problems
- return originalFunction(subject, {
- ...options,
- force: true,
- });
-});
-
-Cypress.Commands.overwrite(
- "type",
- (originalFunction, subject, string, options) => {
- // we're invoking type with force by default to avoid scrolling problems
- return originalFunction(subject, string, {
- ...options,
- force: true,
- });
- }
-);
-
-Cypress.Commands.add(
- "login",
- ({
- username = "1d7b9fef36a34367ad02993594db3fc9rlegros@example.com",
- password = "shopware",
- } = {}) => {
- cy.intercept({
- method: "POST",
- url: "**/store-api/account/customer*",
- }).as("invokeLogin");
-
- cy.get('[data-cy="login-icon"]').click();
- cy.get("input[data-cy=email-input]").type(username);
- cy.get("input[data-cy=password-input]").type(password);
- cy.get("[data-cy=submit-login-button]").click();
-
- cy.wait("@invokeLogin").its("response.statusCode").should("eq", 200);
- }
-);
-
-Cypress.Commands.add("fillAndExecuteRegistrationForm", ({ email } = {}) => {
- cy.intercept({
- url: "**/store-api/account/register",
- }).as("invokeRegistration");
-
- cy.get("input[data-cy=registration-first-name-input]").type(
- faker.name.firstName()
- );
- cy.get("input[data-cy=registration-last-name-input]").type(
- faker.name.lastName()
- );
- cy.get("input[data-cy=registration-email-input]").type(
- email || faker.internet.email()
- );
- cy.get("[data-cy=guest-registration-checkbox] input").check();
- cy.get("input[data-cy=registration-street-input]").type(
- faker.address.streetName()
- );
- cy.get("input[data-cy=registration-zipcode-input]").type(
- faker.address.zipCode()
- );
- cy.get("input[data-cy=registration-city-input]").type(
- faker.address.cityName()
- );
- cy.get("[data-cy=register-button]").click();
-
- cy.wait("@invokeRegistration").its("response.statusCode").should("eq", 200);
-});
diff --git a/packages/default-theme/__e2e__/support/index.js b/packages/default-theme/__e2e__/support/index.js
deleted file mode 100644
index 413b0ecfa..000000000
--- a/packages/default-theme/__e2e__/support/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// ***********************************************************
-// This example support/index.js is processed and
-// loaded automatically before your test files.
-//
-// This is a great place to put global configuration and
-// behavior that modifies Cypress.
-//
-// You can change the location of this file or turn off
-// automatically serving support files with the
-// 'supportFile' configuration option.
-//
-// You can read more here:
-// https://on.cypress.io/configuration
-// ***********************************************************
-
-// Import commands.js using ES2015 syntax:
-import "./commands";
diff --git a/packages/default-theme/package.json b/packages/default-theme/package.json
index 95e258c9b..e7fc1359a 100644
--- a/packages/default-theme/package.json
+++ b/packages/default-theme/package.json
@@ -12,7 +12,8 @@
"build": "shopware-pwa build-theme",
"dev": "shopware-pwa dev-theme",
"lint": "prettier --write './**/*.{js,vue}'",
- "test": "jest"
+ "test": "jest",
+ "test:e2e": "playwright test --config=__e2e__/playwright.config.ts"
},
"husky": {
"hooks": {
@@ -35,9 +36,9 @@
},
"peerDependencies": {
"@vue/composition-api": "^1.3.1",
- "vue": "^2.0.0 || >=3.0.0-rc.0",
+ "core-js": "^3.19.0",
"nuxt": "^2.15.8",
- "core-js": "^3.19.0"
+ "vue": "^2.0.0 || >=3.0.0-rc.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
@@ -48,6 +49,7 @@
"@babel/runtime-corejs3": "^7.16.0",
"@nuxtjs/eslint-config": "^6.0.1",
"@nuxtjs/eslint-module": "^3.0.2",
+ "@playwright/test": "^1.17.1",
"@shopware-pwa/cli": "1.2.0",
"@vue/composition-api": "^1.3.1",
"@vue/test-utils": "^1.2.2",
@@ -61,6 +63,7 @@
"jest": "^27.3.1",
"lint-staged": "^11.2.6",
"lodash": "^4.17.21",
+ "playwright": "^1.17.1",
"prettier": "^2.4.1",
"vue-jest": "^4.0.0-0"
}
diff --git a/packages/default-theme/src/cms/elements/CmsElementContactForm.vue b/packages/default-theme/src/cms/elements/CmsElementContactForm.vue
index 167a001ee..a6d5d9d3a 100644
--- a/packages/default-theme/src/cms/elements/CmsElementContactForm.vue
+++ b/packages/default-theme/src/cms/elements/CmsElementContactForm.vue
@@ -13,13 +13,13 @@
:label="$t('Salutation')"
:valid="!$v.salutationId.$error"
:error-message="$t('Salutation must be selected')"
- data-cy="salutation-select"
+ data-testid="salutation-select"
>
{{ salutationOption.name }}
diff --git a/packages/default-theme/src/components/SwBottomMoreActions.vue b/packages/default-theme/src/components/SwBottomMoreActions.vue
index 1a4a90581..b1e5628f6 100644
--- a/packages/default-theme/src/components/SwBottomMoreActions.vue
+++ b/packages/default-theme/src/components/SwBottomMoreActions.vue
@@ -16,7 +16,7 @@
@@ -26,14 +26,14 @@
@@ -46,7 +46,7 @@