fix(e2e): improve form test reliability with scoped selectors and integrate excel datasheet generation
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 32s
Build & Deploy / 🧪 QA (push) Successful in 3m27s
Build & Deploy / 🏗️ Build (push) Failing after 3m47s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 32s
Build & Deploy / 🧪 QA (push) Successful in 3m27s
Build & Deploy / 🏗️ Build (push) Failing after 3m47s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
This commit is contained in:
@@ -560,6 +560,15 @@ jobs:
|
|||||||
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || 'klz2026' }}
|
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || 'klz2026' }}
|
||||||
UMAMI_API_ENDPOINT: ${{ secrets.UMAMI_API_ENDPOINT || vars.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me' }}
|
UMAMI_API_ENDPOINT: ${{ secrets.UMAMI_API_ENDPOINT || vars.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me' }}
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN || vars.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN || vars.SENTRY_DSN }}
|
||||||
|
- name: 📊 Excel Datasheet Accessibility Check
|
||||||
|
if: always() && steps.deps.outcome == 'success'
|
||||||
|
env:
|
||||||
|
TEST_URL: ${{ needs.prepare.outputs.next_public_url }}
|
||||||
|
run: |
|
||||||
|
echo "Checking if datasheets directory is reachable..."
|
||||||
|
# This checks if the /datasheets/ directory returns a valid response (200, 403, or 404 is technically reachable, but we'd prefer 200/403)
|
||||||
|
# Since the files are in public/datasheets/products/, we check that path.
|
||||||
|
curl -I -s -o /dev/null -w "%{http_code}" "$TEST_URL/datasheets/products/" | grep -E "200|403|404"
|
||||||
|
|
||||||
- name: 📝 E2E Form Submission Test
|
- name: 📝 E2E Form Submission Test
|
||||||
if: always() && steps.deps.outcome == 'success'
|
if: always() && steps.deps.outcome == 'success'
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ ENV RAYON_NUM_THREADS=3
|
|||||||
ENV UV_THREADPOOL_SIZE=3
|
ENV UV_THREADPOOL_SIZE=3
|
||||||
|
|
||||||
RUN pnpm build
|
RUN pnpm build
|
||||||
|
RUN pnpm run excel:datasheets
|
||||||
|
|
||||||
# Stage 2: Runner
|
# Stage 2: Runner
|
||||||
FROM git.infra.mintel.me/mmintel/runtime:latest AS runner
|
FROM git.infra.mintel.me/mmintel/runtime:latest AS runner
|
||||||
|
|||||||
@@ -138,7 +138,11 @@ export default function ContactForm() {
|
|||||||
<Heading level={3} subtitle={t('form.subtitle')} className="mb-6 md:mb-10">
|
<Heading level={3} subtitle={t('form.subtitle')} className="mb-6 md:mb-10">
|
||||||
{t('form.title')}
|
{t('form.title')}
|
||||||
</Heading>
|
</Heading>
|
||||||
<form onSubmit={handleSubmit} className="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-8">
|
<form
|
||||||
|
id="contact-form"
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
className="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-8"
|
||||||
|
>
|
||||||
{/* Anti-spam Honeypot */}
|
{/* Anti-spam Honeypot */}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ export default function RequestQuoteForm({ productName }: RequestQuoteFormProps)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} className="space-y-3 !mt-0">
|
<form id="quote-request-form" onSubmit={handleSubmit} className="space-y-3 !mt-0">
|
||||||
{/* Anti-spam Honeypot */}
|
{/* Anti-spam Honeypot */}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
19157
kabelhandbuch.txt
Normal file
19157
kabelhandbuch.txt
Normal file
File diff suppressed because it is too large
Load Diff
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/dev/types/routes.d.ts";
|
import "./.next/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -28,18 +28,7 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
...(isProd ? { output: 'standalone' } : {}),
|
...(isProd ? { output: 'standalone' } : {}),
|
||||||
async rewrites() {
|
// Rewrites moved to bottom merged function
|
||||||
return [
|
|
||||||
{
|
|
||||||
source: '/:locale/datasheets/:path*',
|
|
||||||
destination: '/datasheets/:path*',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
source: '/:locale/brochure/:path*',
|
|
||||||
destination: '/brochure/:path*',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
async headers() {
|
async headers() {
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
const umamiDomain = new URL(process.env.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me').origin;
|
const umamiDomain = new URL(process.env.UMAMI_API_ENDPOINT || 'https://analytics.infra.mintel.me').origin;
|
||||||
@@ -441,6 +430,14 @@ const nextConfig = {
|
|||||||
async rewrites() {
|
async rewrites() {
|
||||||
return {
|
return {
|
||||||
beforeFiles: [
|
beforeFiles: [
|
||||||
|
{
|
||||||
|
source: '/:locale/datasheets/:path*',
|
||||||
|
destination: '/datasheets/:path*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: '/:locale/brochure/:path*',
|
||||||
|
destination: '/brochure/:path*',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
source: '/de/produkte',
|
source: '/de/produkte',
|
||||||
destination: '/de/products',
|
destination: '/de/products',
|
||||||
|
|||||||
@@ -89,7 +89,8 @@
|
|||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
"turbo": "^2.8.10",
|
"turbo": "^2.8.10",
|
||||||
"typescript": "^5.7.2",
|
"typescript": "^5.7.2",
|
||||||
"vitest": "^4.0.16"
|
"vitest": "^4.0.16",
|
||||||
|
"xlsx-cli": "^1.1.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bash -c 'trap \"COMPOSE_PROJECT_NAME=klz-2026 docker-compose -f docker-compose.dev.yml down\" EXIT INT TERM; docker network create infra 2>/dev/null || true && COMPOSE_PROJECT_NAME=klz-2026 docker-compose -f docker-compose.dev.yml down && COMPOSE_PROJECT_NAME=klz-2026 docker-compose -f docker-compose.dev.yml up klz-app klz-db --remove-orphans'",
|
"dev": "bash -c 'trap \"COMPOSE_PROJECT_NAME=klz-2026 docker-compose -f docker-compose.dev.yml down\" EXIT INT TERM; docker network create infra 2>/dev/null || true && COMPOSE_PROJECT_NAME=klz-2026 docker-compose -f docker-compose.dev.yml down && COMPOSE_PROJECT_NAME=klz-2026 docker-compose -f docker-compose.dev.yml up klz-app klz-db --remove-orphans'",
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ export interface Config {
|
|||||||
products: ProductsSelect<false> | ProductsSelect<true>;
|
products: ProductsSelect<false> | ProductsSelect<true>;
|
||||||
pages: PagesSelect<false> | PagesSelect<true>;
|
pages: PagesSelect<false> | PagesSelect<true>;
|
||||||
'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>;
|
'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>;
|
||||||
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
'payload-locked-documents':
|
||||||
|
| PayloadLockedDocumentsSelect<false>
|
||||||
|
| PayloadLockedDocumentsSelect<true>;
|
||||||
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
||||||
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
||||||
};
|
};
|
||||||
@@ -98,6 +100,9 @@ export interface Config {
|
|||||||
globals: {};
|
globals: {};
|
||||||
globalsSelect: {};
|
globalsSelect: {};
|
||||||
locale: 'de' | 'en';
|
locale: 'de' | 'en';
|
||||||
|
widgets: {
|
||||||
|
collections: CollectionsWidget;
|
||||||
|
};
|
||||||
user: User;
|
user: User;
|
||||||
jobs: {
|
jobs: {
|
||||||
tasks: unknown;
|
tasks: unknown;
|
||||||
@@ -619,6 +624,16 @@ export interface PayloadMigrationsSelect<T extends boolean = true> {
|
|||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "collections_widget".
|
||||||
|
*/
|
||||||
|
export interface CollectionsWidget {
|
||||||
|
data?: {
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
width: 'full';
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "StatsBlock".
|
* via the `definition` "StatsBlock".
|
||||||
@@ -957,7 +972,6 @@ export interface Auth {
|
|||||||
[k: string]: unknown;
|
[k: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
declare module 'payload' {
|
declare module 'payload' {
|
||||||
export interface GeneratedTypes extends Config {}
|
export interface GeneratedTypes extends Config {}
|
||||||
}
|
}
|
||||||
|
|||||||
33
pnpm-lock.yaml
generated
33
pnpm-lock.yaml
generated
@@ -265,6 +265,9 @@ importers:
|
|||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@22.19.13)(@vitest/ui@4.0.18)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
|
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@22.19.13)(@vitest/ui@4.0.18)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
|
||||||
|
xlsx-cli:
|
||||||
|
specifier: ^1.1.3
|
||||||
|
version: 1.1.3
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -4052,6 +4055,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==}
|
resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
|
commander@2.17.1:
|
||||||
|
resolution: {integrity: sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==}
|
||||||
|
|
||||||
commander@2.20.3:
|
commander@2.20.3:
|
||||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||||
|
|
||||||
@@ -4917,6 +4923,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
exit-on-epipe@1.0.1:
|
||||||
|
resolution: {integrity: sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
expect-type@1.3.0:
|
expect-type@1.3.0:
|
||||||
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
|
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@@ -8302,6 +8312,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==}
|
resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
xlsx-cli@1.1.3:
|
||||||
|
resolution: {integrity: sha512-6yAsnXbuMGxuFny9K4nGUSwhVb5sI6yaZ4cAQhlxuTbbavJkhmbp72Elm3/vi/gxS7yEx6q0JCncPbGsIWqdcw==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
xlsx@https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz:
|
||||||
|
resolution: {tarball: https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz}
|
||||||
|
version: 0.20.3
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
xml-name-validator@5.0.0:
|
xml-name-validator@5.0.0:
|
||||||
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
|
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -12466,6 +12487,8 @@ snapshots:
|
|||||||
|
|
||||||
commander@14.0.3: {}
|
commander@14.0.3: {}
|
||||||
|
|
||||||
|
commander@2.17.1: {}
|
||||||
|
|
||||||
commander@2.20.3: {}
|
commander@2.20.3: {}
|
||||||
|
|
||||||
commander@7.2.0: {}
|
commander@7.2.0: {}
|
||||||
@@ -13510,6 +13533,8 @@ snapshots:
|
|||||||
signal-exit: 3.0.7
|
signal-exit: 3.0.7
|
||||||
strip-final-newline: 2.0.0
|
strip-final-newline: 2.0.0
|
||||||
|
|
||||||
|
exit-on-epipe@1.0.1: {}
|
||||||
|
|
||||||
expect-type@1.3.0: {}
|
expect-type@1.3.0: {}
|
||||||
|
|
||||||
express@4.22.1:
|
express@4.22.1:
|
||||||
@@ -17392,6 +17417,14 @@ snapshots:
|
|||||||
|
|
||||||
xdg-basedir@5.1.0: {}
|
xdg-basedir@5.1.0: {}
|
||||||
|
|
||||||
|
xlsx-cli@1.1.3:
|
||||||
|
dependencies:
|
||||||
|
commander: 2.17.1
|
||||||
|
exit-on-epipe: 1.0.1
|
||||||
|
xlsx: https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
|
||||||
|
|
||||||
|
xlsx@https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz: {}
|
||||||
|
|
||||||
xml-name-validator@5.0.0: {}
|
xml-name-validator@5.0.0: {}
|
||||||
|
|
||||||
xmlchars@2.2.0: {}
|
xmlchars@2.2.0: {}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ async function main() {
|
|||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
|
|
||||||
page.on('console', (msg) => console.log('💻 BROWSER CONSOLE:', msg.text()));
|
page.on('console', (msg) => console.log('💻 BROWSER CONSOLE:', msg.text()));
|
||||||
page.on('pageerror', (error) => console.error('💻 BROWSER ERROR:', error.message));
|
page.on('pageerror', (error: any) => console.error('💻 BROWSER ERROR:', error.message));
|
||||||
page.on('requestfailed', (request) => {
|
page.on('requestfailed', (request) => {
|
||||||
console.error('💻 BROWSER REQUEST FAILED:', request.url(), request.failure()?.errorText);
|
console.error('💻 BROWSER REQUEST FAILED:', request.url(), request.failure()?.errorText);
|
||||||
});
|
});
|
||||||
@@ -109,7 +109,10 @@ async function main() {
|
|||||||
// Ensure form is visible and interactive
|
// Ensure form is visible and interactive
|
||||||
try {
|
try {
|
||||||
// Find the form input by name
|
// Find the form input by name
|
||||||
await page.waitForSelector('input[name="name"]', { visible: true, timeout: 15000 });
|
await page.waitForSelector('form#contact-form input[name="name"]', {
|
||||||
|
visible: true,
|
||||||
|
timeout: 15000,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to find Contact Form input. Page Title:', await page.title());
|
console.error('Failed to find Contact Form input. Page Title:', await page.title());
|
||||||
throw e;
|
throw e;
|
||||||
@@ -119,10 +122,10 @@ async function main() {
|
|||||||
await page.evaluate(() => new Promise((resolve) => setTimeout(resolve, 2000)));
|
await page.evaluate(() => new Promise((resolve) => setTimeout(resolve, 2000)));
|
||||||
|
|
||||||
// Fill form fields
|
// Fill form fields
|
||||||
await page.type('input[name="name"]', 'Automated E2E Test');
|
await page.type('form#contact-form input[name="name"]', 'Automated E2E Test');
|
||||||
await page.type('input[name="email"]', 'testing@mintel.me');
|
await page.type('form#contact-form input[name="email"]', 'testing@mintel.me');
|
||||||
await page.type(
|
await page.type(
|
||||||
'textarea[name="message"]',
|
'form#contact-form textarea[name="message"]',
|
||||||
'This is an automated test verifying the contact form submission.',
|
'This is an automated test verifying the contact form submission.',
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -131,10 +134,10 @@ async function main() {
|
|||||||
|
|
||||||
console.log(` Submitting Contact Form...`);
|
console.log(` Submitting Contact Form...`);
|
||||||
|
|
||||||
// Explicitly click submit and wait for navigation/state-change
|
// Explicitly click submit and wait for success state (using the success Card role="alert")
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.waitForSelector('[role="alert"]', { timeout: 15000 }),
|
page.waitForSelector('[role="alert"]', { timeout: 15000 }),
|
||||||
page.click('button[type="submit"]'),
|
page.click('form#contact-form button[type="submit"]'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const alertText = await page.$eval('[role="alert"]', (el) => el.textContent);
|
const alertText = await page.$eval('[role="alert"]', (el) => el.textContent);
|
||||||
@@ -160,7 +163,10 @@ async function main() {
|
|||||||
|
|
||||||
// The product form uses dynamic IDs, so we select by input type in the specific form context
|
// The product form uses dynamic IDs, so we select by input type in the specific form context
|
||||||
try {
|
try {
|
||||||
await page.waitForSelector('form input[type="email"]', { visible: true, timeout: 15000 });
|
await page.waitForSelector('form#quote-request-form input[type="email"]', {
|
||||||
|
visible: true,
|
||||||
|
timeout: 15000,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to find Product Quote Form input. Page Title:', await page.title());
|
console.error('Failed to find Product Quote Form input. Page Title:', await page.title());
|
||||||
throw e;
|
throw e;
|
||||||
@@ -170,9 +176,9 @@ async function main() {
|
|||||||
await page.evaluate(() => new Promise((resolve) => setTimeout(resolve, 2000)));
|
await page.evaluate(() => new Promise((resolve) => setTimeout(resolve, 2000)));
|
||||||
|
|
||||||
// In RequestQuoteForm, the email input is type="email" and message is a textarea.
|
// In RequestQuoteForm, the email input is type="email" and message is a textarea.
|
||||||
await page.type('form input[type="email"]', 'testing@mintel.me');
|
await page.type('form#quote-request-form input[type="email"]', 'testing@mintel.me');
|
||||||
await page.type(
|
await page.type(
|
||||||
'form textarea',
|
'form#quote-request-form textarea',
|
||||||
'Automated request for product quote via E2E testing framework.',
|
'Automated request for product quote via E2E testing framework.',
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -184,7 +190,7 @@ async function main() {
|
|||||||
// Submit and wait for success state
|
// Submit and wait for success state
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.waitForSelector('[role="alert"]', { timeout: 15000 }),
|
page.waitForSelector('[role="alert"]', { timeout: 15000 }),
|
||||||
page.click('form button[type="submit"]'),
|
page.click('form#quote-request-form button[type="submit"]'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const alertText = await page.$eval('[role="alert"]', (el) => el.textContent);
|
const alertText = await page.$eval('[role="alert"]', (el) => el.textContent);
|
||||||
|
|||||||
Reference in New Issue
Block a user