@shopbite-de/storefront 1.2.8 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +3 -1
- package/.github/workflows/build.yaml +30 -1
- package/.github/workflows/ci.yaml +37 -51
- package/app/components/Product/Card.vue +1 -0
- package/compose.yml +0 -3
- package/container +0 -0
- package/node.dockerfile +7 -2
- package/package.json +31 -23
- package/playwright.config.ts +77 -0
- package/test/e2e/simple-checkout-as-recurring-customer.test.ts +149 -0
- package/test/nuxt/useAddToCart.test.ts +162 -0
- package/test/nuxt/useDeliveryTime.test.ts +61 -0
- package/test/nuxt/useInterval.test.ts +59 -0
- package/test/nuxt/usePizzaToppings.test.ts +59 -0
- package/test/nuxt/useProductConfigurator.test.ts +87 -0
- package/{app/composables → test/nuxt}/useProductEvents.test.ts +1 -1
- package/test/nuxt/useProductVariants.test.ts +89 -0
- package/test/nuxt/useProductVariantsZwei.test.ts +48 -0
- package/test/nuxt/useScrollAnimation.test.ts +96 -0
- package/test/nuxt/useTopSellers.test.ts +50 -0
- package/test/nuxt/useWishlistActions.test.ts +124 -0
- package/vitest.config.ts +23 -0
package/.dockerignore
CHANGED
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
|
|
13
13
|
steps:
|
|
14
14
|
- name: Checkout repository
|
|
15
|
-
uses: actions/checkout@
|
|
15
|
+
uses: actions/checkout@v6
|
|
16
16
|
|
|
17
17
|
- name: Log in to the Container registry
|
|
18
18
|
uses: docker/login-action@v3
|
|
@@ -46,3 +46,32 @@ jobs:
|
|
|
46
46
|
push: true
|
|
47
47
|
tags: ${{ steps.meta-app.outputs.tags }}
|
|
48
48
|
labels: ${{ steps.meta-app.outputs.labels }}
|
|
49
|
+
|
|
50
|
+
release-npm:
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
needs: build-and-push
|
|
53
|
+
permissions:
|
|
54
|
+
contents: read
|
|
55
|
+
id-token: write
|
|
56
|
+
steps:
|
|
57
|
+
- name: Checkout repository
|
|
58
|
+
uses: actions/checkout@v6
|
|
59
|
+
|
|
60
|
+
- name: Install Node.js
|
|
61
|
+
uses: actions/setup-node@v6
|
|
62
|
+
with:
|
|
63
|
+
node-version: '24'
|
|
64
|
+
registry-url: 'https://registry.npmjs.org'
|
|
65
|
+
|
|
66
|
+
- name: Install pnpm
|
|
67
|
+
uses: pnpm/action-setup@v4
|
|
68
|
+
with:
|
|
69
|
+
version: 10.26.2
|
|
70
|
+
|
|
71
|
+
- name: Install dependencies
|
|
72
|
+
run: pnpm install --frozen-lockfile
|
|
73
|
+
|
|
74
|
+
- name: Publish to npm
|
|
75
|
+
run: pnpm publish --no-git-checks --access public
|
|
76
|
+
env:
|
|
77
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -5,55 +5,26 @@ on:
|
|
|
5
5
|
pull_request:
|
|
6
6
|
types: [opened, synchronize]
|
|
7
7
|
jobs:
|
|
8
|
-
|
|
9
|
-
name:
|
|
10
|
-
|
|
8
|
+
test:
|
|
9
|
+
name: Run unit and e2e tests
|
|
10
|
+
environment: test
|
|
11
11
|
env:
|
|
12
|
+
NUXT_PUBLIC_APP_ENV: 'test'
|
|
13
|
+
NUXT_PUBLIC_STORE_URL: 'http://localhost:3005'
|
|
14
|
+
NUXT_PUBLIC_SHOPWARE_DEV_STORE_FRONT_URL: 'http://localhost:3005'
|
|
15
|
+
PORT: '3005'
|
|
12
16
|
NUXT_PUBLIC_SHOPWARE_ENDPOINT: ${{ secrets.NUXT_PUBLIC_SHOPWARE_ENDPOINT }}
|
|
13
17
|
NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN: ${{ secrets.NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN }}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- name: Install Node.js
|
|
20
|
-
uses: actions/setup-node@v6
|
|
21
|
-
with:
|
|
22
|
-
node-version: '24'
|
|
23
|
-
|
|
24
|
-
- name: Install pnpm
|
|
25
|
-
uses: pnpm/action-setup@v4
|
|
26
|
-
|
|
27
|
-
- name: Get pnpm store directory
|
|
28
|
-
id: pnpm-cache
|
|
29
|
-
shell: bash
|
|
30
|
-
run: |
|
|
31
|
-
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
|
32
|
-
|
|
33
|
-
- name: Setup pnpm cache
|
|
34
|
-
uses: actions/cache@v4
|
|
35
|
-
with:
|
|
36
|
-
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
|
37
|
-
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
38
|
-
restore-keys: |
|
|
39
|
-
${{ runner.os }}-pnpm-store-
|
|
40
|
-
|
|
41
|
-
- name: Install dependencies
|
|
42
|
-
run: pnpm install --frozen-lockfile
|
|
43
|
-
|
|
44
|
-
- name: Build
|
|
45
|
-
env:
|
|
46
|
-
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
47
|
-
run: pnpm run build
|
|
48
|
-
test:
|
|
49
|
-
name: Run Unit tests
|
|
18
|
+
NUXT_PUBLIC_SITE_COUNTRY_ID: ${{ secrets.NUXT_PUBLIC_SITE_COUNTRY_ID }}
|
|
19
|
+
GEOPIFY: ${{ secrets.GEOPIFY }}
|
|
20
|
+
TEST_USER: ${{ secrets.TEST_USER }}
|
|
21
|
+
TEST_USER_PASS: ${{ secrets.TEST_USER_PASS }}
|
|
50
22
|
if: github.event.pull_request.draft == false
|
|
51
|
-
needs: init
|
|
52
23
|
timeout-minutes: 15
|
|
53
24
|
runs-on: ubuntu-latest
|
|
54
25
|
steps:
|
|
55
26
|
- name: Check out code
|
|
56
|
-
uses: actions/checkout@
|
|
27
|
+
uses: actions/checkout@v6
|
|
57
28
|
|
|
58
29
|
- name: Fetch main
|
|
59
30
|
run: git fetch origin main
|
|
@@ -66,7 +37,7 @@ jobs:
|
|
|
66
37
|
- name: Enable corepack and pnpm
|
|
67
38
|
run: |
|
|
68
39
|
corepack enable
|
|
69
|
-
corepack prepare pnpm@10.
|
|
40
|
+
corepack prepare pnpm@10.26.2 --activate
|
|
70
41
|
|
|
71
42
|
- name: Install build dependencies
|
|
72
43
|
run: |
|
|
@@ -74,7 +45,7 @@ jobs:
|
|
|
74
45
|
sudo apt-get install -y build-essential python3
|
|
75
46
|
|
|
76
47
|
- name: Cache pnpm dependencies
|
|
77
|
-
uses: actions/cache@
|
|
48
|
+
uses: actions/cache@v5
|
|
78
49
|
with:
|
|
79
50
|
path: |
|
|
80
51
|
/home/runner/.local/share/pnpm/store/v3
|
|
@@ -85,18 +56,33 @@ jobs:
|
|
|
85
56
|
|
|
86
57
|
- name: Install dependencies
|
|
87
58
|
run: pnpm install --frozen-lockfile --prefer-offline
|
|
88
|
-
working-directory: ${{ inputs.workdir }}
|
|
89
59
|
|
|
90
60
|
- name: Rebuild native modules
|
|
91
61
|
run: pnpm rebuild better-sqlite3
|
|
92
|
-
working-directory: ${{ inputs.workdir }}
|
|
93
62
|
|
|
94
|
-
- name:
|
|
63
|
+
- name: Build
|
|
95
64
|
env:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
65
|
+
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
66
|
+
run: pnpm run build
|
|
67
|
+
|
|
68
|
+
- name: Install Playwright Browsers
|
|
69
|
+
run: pnpm exec playwright install --with-deps chromium
|
|
70
|
+
|
|
71
|
+
- name: Unit tests
|
|
72
|
+
run: pnpm test:unit
|
|
73
|
+
|
|
74
|
+
- name: E2E tests
|
|
75
|
+
env:
|
|
76
|
+
TEST_USER: ${{ secrets.TEST_USER }}
|
|
77
|
+
TEST_USER_PASS: ${{ secrets.TEST_USER_PASS }}
|
|
78
|
+
|
|
79
|
+
run: pnpm test:e2e
|
|
80
|
+
|
|
81
|
+
- uses: actions/upload-artifact@v6
|
|
82
|
+
if: ${{ !cancelled() }}
|
|
83
|
+
with:
|
|
84
|
+
name: playwright-report
|
|
85
|
+
path: playwright-report/
|
|
86
|
+
retention-days: 30
|
|
99
87
|
|
|
100
|
-
run: pnpm test
|
|
101
|
-
working-directory: ${{ inputs.workdir }}
|
|
102
88
|
|
package/compose.yml
CHANGED
package/container
CHANGED
|
File without changes
|
package/node.dockerfile
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
|
|
1
2
|
FROM node:24-alpine AS build
|
|
2
3
|
|
|
3
|
-
ARG PNPM_VERSION=10.
|
|
4
|
+
ARG PNPM_VERSION=10.26.2
|
|
4
5
|
ARG NUXT_PUBLIC_SHOPWARE_ENDPOINT='https://my.shop/store-api'
|
|
5
6
|
ARG NUXT_PUBLIC_SHOPWARE_ACCESS_TOKEN='TOKEN'
|
|
6
7
|
|
|
@@ -26,7 +27,11 @@ WORKDIR /app
|
|
|
26
27
|
|
|
27
28
|
ENV NODE_ENV=production
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
RUN mkdir -p /app/.data && chown -R node:node /app
|
|
31
|
+
|
|
32
|
+
COPY --from=build --chown=node:node /app/.output /app/.output
|
|
33
|
+
|
|
34
|
+
USER node
|
|
30
35
|
|
|
31
36
|
EXPOSE 3000
|
|
32
37
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopbite-de/storefront",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"main": "nuxt.config.ts",
|
|
5
5
|
"description": "Shopware storefront for food delivery shops",
|
|
6
6
|
"keywords": [
|
|
@@ -13,29 +13,13 @@
|
|
|
13
13
|
"author": "@veliu",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"type": "module",
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "nuxt build",
|
|
18
|
-
"dev": "nuxt dev",
|
|
19
|
-
"generate": "nuxt generate",
|
|
20
|
-
"preview": "nuxt preview",
|
|
21
|
-
"postinstall": "nuxt prepare",
|
|
22
|
-
"test": "vitest run --coverage",
|
|
23
|
-
"test:ui": "vitest --ui",
|
|
24
|
-
"eslint": "eslint .",
|
|
25
|
-
"eslint:fix": "eslint --fix app/",
|
|
26
|
-
"prettier": "prettier --check \"**/*.{ts,tsx,md,vue}\"",
|
|
27
|
-
"prettier:fix": "prettier --check \"**/*.{ts,tsx,md,vue}\" --write",
|
|
28
|
-
"generate-types": "shopware-api-gen generate --apiType=store",
|
|
29
|
-
"load-schema": "bunx @shopware/api-gen loadSchema --apiType=store",
|
|
30
|
-
"lint:fix": "npm run prettier:fix && npm run eslint:fix"
|
|
31
|
-
},
|
|
32
16
|
"dependencies": {
|
|
33
17
|
"@headlessui/vue": "^1.7.23",
|
|
34
18
|
"@heroicons/vue": "^2.2.0",
|
|
35
19
|
"@iconify-json/lucide": "^1.2.73",
|
|
36
20
|
"@iconify-json/simple-icons": "^1.2.59",
|
|
37
21
|
"@nuxt/content": "^3.8.2",
|
|
38
|
-
"@nuxt/image": "^
|
|
22
|
+
"@nuxt/image": "^2.0.0",
|
|
39
23
|
"@nuxt/ui": "^4.1.0",
|
|
40
24
|
"@nuxtjs/plausible": "2.0.1",
|
|
41
25
|
"@nuxtjs/robots": "^5.5.6",
|
|
@@ -45,26 +29,50 @@
|
|
|
45
29
|
"@shopware/composables": "^1.9.1",
|
|
46
30
|
"@shopware/helpers": "^1.5.0",
|
|
47
31
|
"@shopware/nuxt-module": "^1.4.1",
|
|
48
|
-
"@tailwindcss/vite": "^4.1.17",
|
|
49
32
|
"@unhead/vue": "^2.0.19",
|
|
50
33
|
"@vite-pwa/nuxt": "^1.0.7",
|
|
51
|
-
"@vueuse/core": "^
|
|
34
|
+
"@vueuse/core": "^14.0.0",
|
|
35
|
+
"dotenv": "^17.2.3",
|
|
52
36
|
"nuxt": "^4.2.1",
|
|
53
37
|
"uuid": "^13.0.0"
|
|
54
38
|
},
|
|
55
39
|
"devDependencies": {
|
|
40
|
+
"@nuxt/devtools-kit": "^3.1.1",
|
|
56
41
|
"@nuxt/eslint": "^1.10.0",
|
|
57
42
|
"@nuxt/test-utils": "^3.20.1",
|
|
43
|
+
"@playwright/test": "^1.57.0",
|
|
44
|
+
"@types/node": "^25.0.3",
|
|
58
45
|
"@vitejs/plugin-vue": "^6.0.1",
|
|
59
|
-
"@vitest/coverage-v8": "4.0.
|
|
46
|
+
"@vitest/coverage-v8": "4.0.16",
|
|
47
|
+
"@vitest/ui": "4.0.16",
|
|
48
|
+
"@vue/compiler-dom": "^3.5.26",
|
|
49
|
+
"@vue/server-renderer": "^3.5.26",
|
|
60
50
|
"@vue/test-utils": "^2.4.6",
|
|
51
|
+
"dotenv-cli": "^11.0.0",
|
|
61
52
|
"eslint": "^9.39.1",
|
|
62
53
|
"happy-dom": "^20.0.10",
|
|
63
54
|
"jsdom": "^27.2.0",
|
|
64
55
|
"playwright-core": "^1.56.1",
|
|
65
56
|
"prettier": "^3.6.2",
|
|
57
|
+
"tailwindcss": "^4.1.18",
|
|
66
58
|
"typescript": "^5.9.3",
|
|
67
59
|
"vitest": "^4.0.10"
|
|
68
60
|
},
|
|
69
|
-
"
|
|
70
|
-
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "nuxt build",
|
|
63
|
+
"dev": "nuxt dev",
|
|
64
|
+
"generate": "nuxt generate",
|
|
65
|
+
"preview": "nuxt preview",
|
|
66
|
+
"postinstall": "nuxt prepare",
|
|
67
|
+
"test:unit": "vitest run --coverage",
|
|
68
|
+
"test:ui": "vitest --ui",
|
|
69
|
+
"test:e2e": "playwright test --project=chromium",
|
|
70
|
+
"eslint": "eslint .",
|
|
71
|
+
"eslint:fix": "eslint --fix app/",
|
|
72
|
+
"prettier": "prettier --check \"**/*.{ts,tsx,md,vue}\"",
|
|
73
|
+
"prettier:fix": "prettier --check \"**/*.{ts,tsx,md,vue}\" --write",
|
|
74
|
+
"generate-types": "shopware-api-gen generate --apiType=store",
|
|
75
|
+
"load-schema": "bunx @shopware/api-gen loadSchema --apiType=store",
|
|
76
|
+
"lint:fix": "npm run prettier:fix && npm run eslint:fix"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
import type { ConfigOptions } from "@nuxt/test-utils/playwright";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import dotenv from "dotenv";
|
|
5
|
+
import path from 'path';
|
|
6
|
+
|
|
7
|
+
dotenv.config({ path: path.resolve(".env.test") });
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* See https://playwright.dev/docs/test-configuration.
|
|
11
|
+
*/
|
|
12
|
+
export default defineConfig<ConfigOptions>({
|
|
13
|
+
use: {
|
|
14
|
+
baseURL: process.env.NUXT_PUBLIC_STORE_URL || "http://localhost:3000",
|
|
15
|
+
nuxt: {
|
|
16
|
+
rootDir: fileURLToPath(new URL(".", import.meta.url)),
|
|
17
|
+
},
|
|
18
|
+
trace: "on-first-retry",
|
|
19
|
+
},
|
|
20
|
+
testDir: "./test/e2e",
|
|
21
|
+
/* Run tests in files in parallel */
|
|
22
|
+
fullyParallel: true,
|
|
23
|
+
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
24
|
+
forbidOnly: !!process.env.CI,
|
|
25
|
+
/* Retry on CI only */
|
|
26
|
+
retries: process.env.CI ? 2 : 0,
|
|
27
|
+
/* Opt out of parallel tests on CI. */
|
|
28
|
+
workers: process.env.CI ? 1 : undefined,
|
|
29
|
+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
30
|
+
reporter: "html",
|
|
31
|
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
32
|
+
|
|
33
|
+
/* Configure projects for major browsers */
|
|
34
|
+
projects: [
|
|
35
|
+
{
|
|
36
|
+
name: "chromium",
|
|
37
|
+
use: { ...devices["Desktop Chrome"] },
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// {
|
|
41
|
+
// name: "firefox",
|
|
42
|
+
// use: { ...devices["Desktop Firefox"] },
|
|
43
|
+
// },
|
|
44
|
+
//
|
|
45
|
+
// {
|
|
46
|
+
// name: "webkit",
|
|
47
|
+
// use: { ...devices["Desktop Safari"] },
|
|
48
|
+
// },
|
|
49
|
+
|
|
50
|
+
/* Test against mobile viewports. */
|
|
51
|
+
// {
|
|
52
|
+
// name: 'Mobile Chrome',
|
|
53
|
+
// use: { ...devices['Pixel 5'] },
|
|
54
|
+
// },
|
|
55
|
+
// {
|
|
56
|
+
// name: 'Mobile Safari',
|
|
57
|
+
// use: { ...devices['iPhone 12'] },
|
|
58
|
+
// },
|
|
59
|
+
|
|
60
|
+
/* Test against branded browsers. */
|
|
61
|
+
// {
|
|
62
|
+
// name: 'Microsoft Edge',
|
|
63
|
+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
64
|
+
// },
|
|
65
|
+
// {
|
|
66
|
+
// name: 'Google Chrome',
|
|
67
|
+
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
68
|
+
// },
|
|
69
|
+
],
|
|
70
|
+
|
|
71
|
+
/* Run your local dev server before starting the tests */
|
|
72
|
+
webServer: {
|
|
73
|
+
command: "node .output/server/index.mjs",
|
|
74
|
+
url: process.env.NUXT_PUBLIC_STORE_URL || "http://localhost:3000",
|
|
75
|
+
reuseExistingServer: !process.env.CI,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { test, expect, type Page } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
test.beforeEach(async ({ page }) => {
|
|
4
|
+
await page.goto("/");
|
|
5
|
+
await page.evaluate(() => {
|
|
6
|
+
localStorage.clear();
|
|
7
|
+
sessionStorage.clear();
|
|
8
|
+
});
|
|
9
|
+
await page.context().clearCookies();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("Simple Checkout As Recurring Customer", async ({ page }) => {
|
|
13
|
+
const QUANTITY_TO_ADD = 4;
|
|
14
|
+
const PRODUCT_ID = "019a4baa4267700b911411eca842ee17";
|
|
15
|
+
|
|
16
|
+
await clearCart(page);
|
|
17
|
+
await navigateToCategoryAndVerifyProducts(page);
|
|
18
|
+
await selectProductAndAddToCart(page, PRODUCT_ID, QUANTITY_TO_ADD);
|
|
19
|
+
await proceedToCheckoutAndLogin(page);
|
|
20
|
+
await verifyCheckoutQuantity(page);
|
|
21
|
+
await selectPaymentAndShipping(page);
|
|
22
|
+
await proceedToOrderReview(page);
|
|
23
|
+
await page.goto("/");
|
|
24
|
+
await clearCart(page);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Helper Functions
|
|
28
|
+
|
|
29
|
+
async function clearCart(page: Page) {
|
|
30
|
+
const cartButton = page
|
|
31
|
+
.locator("button .i-lucide\\:shopping-cart")
|
|
32
|
+
.locator("..");
|
|
33
|
+
|
|
34
|
+
await expect(cartButton).toBeVisible({ timeout: 5000 });
|
|
35
|
+
await cartButton.click();
|
|
36
|
+
|
|
37
|
+
const cartDrawer = page.locator('[data-vaul-drawer][data-state="open"]');
|
|
38
|
+
await expect(cartDrawer).toBeVisible({ timeout: 5000 });
|
|
39
|
+
await expect(page.getByRole("heading", { name: /warenkorb/i })).toBeVisible();
|
|
40
|
+
|
|
41
|
+
const deleteButtons = page.getByRole("button", {
|
|
42
|
+
name: "Remove item from cart",
|
|
43
|
+
});
|
|
44
|
+
const itemCount = await deleteButtons.count();
|
|
45
|
+
|
|
46
|
+
for (let i = itemCount - 1; i >= 0; i--) {
|
|
47
|
+
await deleteButtons.nth(i).click();
|
|
48
|
+
await page.waitForTimeout(500);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function navigateToCategoryAndVerifyProducts(page: Page) {
|
|
53
|
+
await page.goto("/c/Pizza", { waitUntil: "load" });
|
|
54
|
+
await expect(page.locator("h1")).toHaveText("Pizza");
|
|
55
|
+
|
|
56
|
+
const productCards = page.locator('[id^="product-card-"]');
|
|
57
|
+
await expect(productCards).toHaveCount(5, { timeout: 10000 });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function selectProductAndAddToCart(
|
|
61
|
+
page: Page,
|
|
62
|
+
productId: string,
|
|
63
|
+
quantity: number,
|
|
64
|
+
) {
|
|
65
|
+
const productCard = page.locator(`#product-card-${productId}`);
|
|
66
|
+
await expect(productCard).toBeVisible();
|
|
67
|
+
|
|
68
|
+
// Verify product card structure
|
|
69
|
+
const buttons = productCard.locator("button");
|
|
70
|
+
await expect(buttons).toHaveCount(2);
|
|
71
|
+
await expect(productCard.locator("button .i-lucide\\:heart")).toBeVisible();
|
|
72
|
+
|
|
73
|
+
// Open product details
|
|
74
|
+
const showDetailsButton = productCard.locator(
|
|
75
|
+
"button .i-lucide\\:shopping-cart",
|
|
76
|
+
);
|
|
77
|
+
await expect(showDetailsButton).toBeVisible();
|
|
78
|
+
await showDetailsButton.click();
|
|
79
|
+
|
|
80
|
+
// Set quantity and add to cart
|
|
81
|
+
const quantityInput = page.getByRole("spinbutton", { name: /anzahl/i });
|
|
82
|
+
await expect(quantityInput).toBeVisible();
|
|
83
|
+
await quantityInput.fill(quantity.toString());
|
|
84
|
+
await expect(quantityInput).toHaveValue(quantity.toString());
|
|
85
|
+
|
|
86
|
+
const addToCartButton = page.getByRole("button", {
|
|
87
|
+
name: "In den Warenkorb",
|
|
88
|
+
});
|
|
89
|
+
await expect(addToCartButton).toBeVisible({ timeout: 10000 });
|
|
90
|
+
await addToCartButton.click();
|
|
91
|
+
await expect(addToCartButton).not.toBeVisible({ timeout: 5000 });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function proceedToCheckoutAndLogin(page: Page) {
|
|
95
|
+
await page.goto("/bestellung", { waitUntil: "load" });
|
|
96
|
+
|
|
97
|
+
const loginTab = page.getByRole("tab", { name: "Einloggen" });
|
|
98
|
+
await expect(loginTab).toBeVisible();
|
|
99
|
+
await loginTab.click();
|
|
100
|
+
|
|
101
|
+
// Fill login form
|
|
102
|
+
const loginEmailInput = page.getByPlaceholder("Email-Adresse eingeben");
|
|
103
|
+
const loginPasswordInput = page.getByPlaceholder("Passwort eingeben");
|
|
104
|
+
const loginButton = page.getByRole("button", { name: "Anmelden" });
|
|
105
|
+
|
|
106
|
+
await expect(loginEmailInput).toBeVisible();
|
|
107
|
+
await expect(loginPasswordInput).toBeVisible();
|
|
108
|
+
await expect(loginButton).toBeVisible();
|
|
109
|
+
|
|
110
|
+
await loginEmailInput.fill(process.env.TEST_USER!);
|
|
111
|
+
await loginPasswordInput.fill(process.env.TEST_USER_PASS!);
|
|
112
|
+
await loginButton.click();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function verifyCheckoutQuantity(page: Page) {
|
|
116
|
+
const checkoutQuantityInput = page.getByRole("spinbutton", {
|
|
117
|
+
name: /item quantity/i,
|
|
118
|
+
});
|
|
119
|
+
await expect(checkoutQuantityInput).toBeVisible();
|
|
120
|
+
// Quantity verification can be added here if needed
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function selectPaymentAndShipping(page: Page) {
|
|
124
|
+
const nextStepButton = page.getByRole("button", {
|
|
125
|
+
name: "Zahlungs- und Versandart auswählen",
|
|
126
|
+
});
|
|
127
|
+
await expect(nextStepButton).toBeVisible({ timeout: 10000 });
|
|
128
|
+
await expect(nextStepButton).toBeEnabled();
|
|
129
|
+
await nextStepButton.click();
|
|
130
|
+
|
|
131
|
+
// Verify payment method
|
|
132
|
+
const paymentRadio = page.getByRole("radio", { name: "Cash on delivery" });
|
|
133
|
+
await expect(paymentRadio).toBeVisible();
|
|
134
|
+
await expect(paymentRadio).toBeChecked();
|
|
135
|
+
|
|
136
|
+
// Verify delivery method
|
|
137
|
+
const deliveryRadio = page.getByRole("radio", { name: "Standard" });
|
|
138
|
+
await expect(deliveryRadio).toBeVisible();
|
|
139
|
+
await expect(deliveryRadio).toBeChecked();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function proceedToOrderReview(page: Page) {
|
|
143
|
+
const lastStepButton = page.getByRole("button", {
|
|
144
|
+
name: "Weiter zu Prüfen & Bestellen",
|
|
145
|
+
});
|
|
146
|
+
await expect(lastStepButton).toBeVisible({ timeout: 10000 });
|
|
147
|
+
await expect(lastStepButton).toBeEnabled();
|
|
148
|
+
await lastStepButton.click();
|
|
149
|
+
}
|