Compare commits
4 Commits
2.0.1
...
5deb38ebb7
| Author | SHA1 | Date | |
|---|---|---|---|
| 5deb38ebb7 | |||
| 586e5f26bd | |||
| 9bf4c20f11 | |||
| f8d895ab21 |
+20
@@ -0,0 +1,20 @@
|
|||||||
|
services:
|
||||||
|
|
||||||
|
scorebscgpde:
|
||||||
|
image: nginx
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./dist:/usr/share/nginx/html:ro
|
||||||
|
container_name: scorebscgpde
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.scorebscgpde.rule=Host(`score.bsc-gp.de`)"
|
||||||
|
- "traefik.http.routers.scorebscgpde.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.scorebscgpde.tls.certresolver=myresolver"
|
||||||
|
networks:
|
||||||
|
- traefik
|
||||||
|
|
||||||
|
# Externes Traefik-Netzwerk für Reverse Proxy
|
||||||
|
networks:
|
||||||
|
traefik:
|
||||||
|
external: true
|
||||||
@@ -33,6 +33,35 @@ export default function App() {
|
|||||||
const validationModal = useValidationModal();
|
const validationModal = useValidationModal();
|
||||||
const completionModal = useCompletionModal();
|
const completionModal = useCompletionModal();
|
||||||
|
|
||||||
|
// Keep viewport height stable on Android tablets when virtual keyboard opens.
|
||||||
|
useEffect(() => {
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
const updateViewportVars = () => {
|
||||||
|
const viewport = window.visualViewport;
|
||||||
|
const appHeight = viewport ? viewport.height : window.innerHeight;
|
||||||
|
const keyboardOffset = viewport
|
||||||
|
? Math.max(0, window.innerHeight - viewport.height - viewport.offsetTop)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
root.style.setProperty('--app-height', `${Math.round(appHeight)}px`);
|
||||||
|
root.style.setProperty('--keyboard-offset', `${Math.round(keyboardOffset)}px`);
|
||||||
|
};
|
||||||
|
|
||||||
|
updateViewportVars();
|
||||||
|
window.addEventListener('resize', updateViewportVars);
|
||||||
|
window.addEventListener('orientationchange', updateViewportVars);
|
||||||
|
window.visualViewport?.addEventListener('resize', updateViewportVars);
|
||||||
|
window.visualViewport?.addEventListener('scroll', updateViewportVars);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', updateViewportVars);
|
||||||
|
window.removeEventListener('orientationchange', updateViewportVars);
|
||||||
|
window.visualViewport?.removeEventListener('resize', updateViewportVars);
|
||||||
|
window.visualViewport?.removeEventListener('scroll', updateViewportVars);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Game lifecycle handlers
|
// Game lifecycle handlers
|
||||||
const handleCreateGame = useCallback(async (gameData: any) => {
|
const handleCreateGame = useCallback(async (gameData: any) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100vh;
|
min-height: var(--app-height);
|
||||||
display: none;
|
display: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
.screen-content {
|
.screen-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100vh;
|
min-height: var(--app-height);
|
||||||
padding: var(--space-lg);
|
padding: var(--space-lg);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100vh;
|
min-height: var(--app-height);
|
||||||
display: none;
|
display: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
@@ -145,8 +145,10 @@
|
|||||||
|
|
||||||
.form-content {
|
.form-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow-y: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
padding: 0 var(--space-lg);
|
padding: 0 var(--space-lg);
|
||||||
|
padding-bottom: var(--space-md);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -154,7 +156,12 @@
|
|||||||
|
|
||||||
.form-footer {
|
.form-footer {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: var(--space-lg);
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 2;
|
||||||
|
background: var(--color-surface);
|
||||||
|
padding: var(--space-md) var(--space-lg) calc(var(--space-lg) + var(--keyboard-offset)) var(--space-lg);
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
}
|
}
|
||||||
.progress-indicator {
|
.progress-indicator {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -210,7 +217,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: var(--space-xxl);
|
margin-top: var(--space-lg);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
gap: var(--space-lg);
|
gap: var(--space-lg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,18 +26,29 @@ export const BreakOrderStep = ({ players, rule, onNext, onCancel, initialFirst =
|
|||||||
|
|
||||||
const handleFirst = (idx: number) => {
|
const handleFirst = (idx: number) => {
|
||||||
setFirst(idx);
|
setFirst(idx);
|
||||||
if (rule === 'winnerbreak' || (rule === 'wechselbreak' && playerCount === 2)) {
|
|
||||||
onNext(idx);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSecond = (idx: number) => {
|
const handleSecond = (idx: number) => {
|
||||||
setSecond(idx);
|
setSecond(idx);
|
||||||
onNext(first, idx);
|
};
|
||||||
|
|
||||||
|
const handleSubmit = (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (rule === 'wechselbreak' && playerCount === 3) {
|
||||||
|
if (first > 0 && (second ?? 0) > 0) {
|
||||||
|
onNext(first, second);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first > 0) {
|
||||||
|
onNext(first);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={styles['new-game-form']} aria-label="Break-Reihenfolge wählen">
|
<form className={styles['new-game-form']} aria-label="Break-Reihenfolge wählen" onSubmit={handleSubmit}>
|
||||||
<div className={styles['form-header']}>
|
<div className={styles['form-header']}>
|
||||||
<div className={styles['screen-title']}>Wer hat den ersten Anstoss?</div>
|
<div className={styles['screen-title']}>Wer hat den ersten Anstoss?</div>
|
||||||
<ProgressIndicator currentStep={7} style={{ marginBottom: 24 }} />
|
<ProgressIndicator currentStep={7} style={{ marginBottom: 24 }} />
|
||||||
@@ -87,18 +98,9 @@ export const BreakOrderStep = ({ players, rule, onNext, onCancel, initialFirst =
|
|||||||
←
|
←
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="submit"
|
||||||
className={styles['arrow-btn']}
|
className={styles['arrow-btn']}
|
||||||
aria-label="Weiter"
|
aria-label="Weiter"
|
||||||
onClick={() => {
|
|
||||||
if (rule === 'wechselbreak' && playerCount === 3) {
|
|
||||||
if (first > 0 && (second ?? 0) > 0) {
|
|
||||||
handleSecond(second as number);
|
|
||||||
}
|
|
||||||
} else if (first > 0) {
|
|
||||||
onNext(first);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
disabled={
|
disabled={
|
||||||
(rule === 'wechselbreak' && playerCount === 3) ? !(first > 0 && (second ?? 0) > 0) : !(first > 0)
|
(rule === 'wechselbreak' && playerCount === 3) ? !(first > 0 && (second ?? 0) > 0) : !(first > 0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,17 @@ interface BreakRuleStepProps {
|
|||||||
export const BreakRuleStep = ({ onNext, onCancel, initialValue = 'winnerbreak' }: BreakRuleStepProps) => {
|
export const BreakRuleStep = ({ onNext, onCancel, initialValue = 'winnerbreak' }: BreakRuleStepProps) => {
|
||||||
const [rule, setRule] = useState<BreakRule>(initialValue ?? 'winnerbreak');
|
const [rule, setRule] = useState<BreakRule>(initialValue ?? 'winnerbreak');
|
||||||
|
|
||||||
|
const handleSelect = (nextRule: BreakRule) => {
|
||||||
|
setRule(nextRule);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
onNext(rule);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={styles['new-game-form']} aria-label="Break-Regel wählen">
|
<form className={styles['new-game-form']} aria-label="Break-Regel wählen" onSubmit={handleSubmit}>
|
||||||
<div className={styles['form-header']}>
|
<div className={styles['form-header']}>
|
||||||
<div className={styles['screen-title']}>Break-Regel wählen</div>
|
<div className={styles['screen-title']}>Break-Regel wählen</div>
|
||||||
<ProgressIndicator currentStep={6} style={{ marginBottom: 24 }} />
|
<ProgressIndicator currentStep={6} style={{ marginBottom: 24 }} />
|
||||||
@@ -30,10 +39,7 @@ export const BreakRuleStep = ({ onNext, onCancel, initialValue = 'winnerbreak' }
|
|||||||
key={opt.key}
|
key={opt.key}
|
||||||
type="button"
|
type="button"
|
||||||
className={`${styles['quick-pick-btn']} ${rule === (opt.key as BreakRule) ? styles['selected'] : ''}`}
|
className={`${styles['quick-pick-btn']} ${rule === (opt.key as BreakRule) ? styles['selected'] : ''}`}
|
||||||
onClick={() => {
|
onClick={() => handleSelect(opt.key as BreakRule)}
|
||||||
setRule(opt.key as BreakRule);
|
|
||||||
onNext(opt.key as BreakRule);
|
|
||||||
}}
|
|
||||||
aria-label={`Break-Regel wählen: ${opt.label}`}
|
aria-label={`Break-Regel wählen: ${opt.label}`}
|
||||||
style={{ minWidth: 160, minHeight: 64, fontSize: '1.2rem', padding: '16px 32px' }}
|
style={{ minWidth: 160, minHeight: 64, fontSize: '1.2rem', padding: '16px 32px' }}
|
||||||
>
|
>
|
||||||
@@ -48,7 +54,7 @@ export const BreakRuleStep = ({ onNext, onCancel, initialValue = 'winnerbreak' }
|
|||||||
<button type="button" className={styles['arrow-btn']} aria-label="Zurück" onClick={onCancel} style={{ fontSize: 48, width: 80, height: 80, borderRadius: '50%', background: '#222', color: '#fff', border: 'none', boxShadow: '0 2px 8px rgba(0,0,0,0.15)', cursor: 'pointer' }}>
|
<button type="button" className={styles['arrow-btn']} aria-label="Zurück" onClick={onCancel} style={{ fontSize: 48, width: 80, height: 80, borderRadius: '50%', background: '#222', color: '#fff', border: 'none', boxShadow: '0 2px 8px rgba(0,0,0,0.15)', cursor: 'pointer' }}>
|
||||||
←
|
←
|
||||||
</button>
|
</button>
|
||||||
<button type="button" className={styles['arrow-btn']} aria-label="Weiter" onClick={() => onNext(rule)} style={{ fontSize: 48, width: 80, height: 80, borderRadius: '50%', background: '#222', color: '#fff', border: 'none', boxShadow: '0 2px 8px rgba(0,0,0,0.15)', cursor: 'pointer' }}>
|
<button type="submit" className={styles['arrow-btn']} aria-label="Weiter" style={{ fontSize: 48, width: 80, height: 80, borderRadius: '50%', background: '#222', color: '#fff', border: 'none', boxShadow: '0 2px 8px rgba(0,0,0,0.15)', cursor: 'pointer' }}>
|
||||||
→
|
→
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export const GameTypeStep = ({ onNext, onCancel, initialValue = '' }: GameTypeSt
|
|||||||
|
|
||||||
const handleSelect = (selectedType: string) => {
|
const handleSelect = (selectedType: string) => {
|
||||||
setGameType(selectedType);
|
setGameType(selectedType);
|
||||||
onNext(selectedType);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (e: Event) => {
|
const handleSubmit = (e: Event) => {
|
||||||
|
|||||||
@@ -111,8 +111,15 @@ export const Player1Step = ({ playerNameHistory, onNext, onCancel, initialValue
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
|
autoCapitalize="words"
|
||||||
|
spellCheck={false}
|
||||||
|
enterKeyHint="next"
|
||||||
aria-label="Name Spieler 1"
|
aria-label="Name Spieler 1"
|
||||||
aria-describedby="player1-help"
|
aria-describedby="player1-help"
|
||||||
|
onFocus={(e) => {
|
||||||
|
const target = e.currentTarget as HTMLInputElement;
|
||||||
|
target.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
||||||
|
}}
|
||||||
style={{
|
style={{
|
||||||
fontSize: UI_CONSTANTS.INPUT_FONT_SIZE,
|
fontSize: UI_CONSTANTS.INPUT_FONT_SIZE,
|
||||||
minHeight: UI_CONSTANTS.INPUT_MIN_HEIGHT,
|
minHeight: UI_CONSTANTS.INPUT_MIN_HEIGHT,
|
||||||
|
|||||||
@@ -70,7 +70,14 @@ export const Player2Step = ({ playerNameHistory, onNext, onCancel, initialValue
|
|||||||
setPlayer2(target.value);
|
setPlayer2(target.value);
|
||||||
}}
|
}}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
|
autoCapitalize="words"
|
||||||
|
spellCheck={false}
|
||||||
|
enterKeyHint="next"
|
||||||
aria-label="Name Spieler 2"
|
aria-label="Name Spieler 2"
|
||||||
|
onFocus={(e) => {
|
||||||
|
const target = e.currentTarget as HTMLInputElement;
|
||||||
|
target.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
||||||
|
}}
|
||||||
style={{ fontSize: '1.2rem', minHeight: 48, marginTop: 12, marginBottom: 12, width: '100%', paddingRight: 44 }}
|
style={{ fontSize: '1.2rem', minHeight: 48, marginTop: 12, marginBottom: 12, width: '100%', paddingRight: 44 }}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -67,7 +67,14 @@ export const Player3Step = ({ playerNameHistory, onNext, onCancel, initialValue
|
|||||||
setPlayer3(target.value);
|
setPlayer3(target.value);
|
||||||
}}
|
}}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
|
autoCapitalize="words"
|
||||||
|
spellCheck={false}
|
||||||
|
enterKeyHint="done"
|
||||||
aria-label="Name Spieler 3"
|
aria-label="Name Spieler 3"
|
||||||
|
onFocus={(e) => {
|
||||||
|
const target = e.currentTarget as HTMLInputElement;
|
||||||
|
target.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
||||||
|
}}
|
||||||
style={{ fontSize: '1.2rem', minHeight: 48, marginTop: 12, marginBottom: 12, width: '100%', paddingRight: 44 }}
|
style={{ fontSize: '1.2rem', minHeight: 48, marginTop: 12, marginBottom: 12, width: '100%', paddingRight: 44 }}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ export const RaceToStep = ({ onNext, onCancel, initialValue = '', gameType }: Ra
|
|||||||
const handleQuickPick = (value: number | typeof RACE_TO_INFINITY) => {
|
const handleQuickPick = (value: number | typeof RACE_TO_INFINITY) => {
|
||||||
const selected = value === RACE_TO_INFINITY ? RACE_TO_INFINITY : value;
|
const selected = value === RACE_TO_INFINITY ? RACE_TO_INFINITY : value;
|
||||||
setRaceTo(selected);
|
setRaceTo(selected);
|
||||||
const raceToValue =
|
|
||||||
selected === RACE_TO_INFINITY ? Infinity : parseInt(String(selected), 10) || 0;
|
|
||||||
onNext(raceToValue);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleInputChange = (e: Event) => {
|
const handleInputChange = (e: Event) => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.layout {
|
.layout {
|
||||||
height: 100vh;
|
height: var(--app-height);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import App from "../components/App";
|
|||||||
<html lang="de">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">
|
||||||
<title>BSC Score - Pool Scoring App</title>
|
<title>BSC Score - Pool Scoring App</title>
|
||||||
<meta name="description" content="Professional pool/billiards scoring application for tournaments and casual games">
|
<meta name="description" content="Professional pool/billiards scoring application for tournaments and casual games">
|
||||||
|
|
||||||
|
|||||||
+10
-7
@@ -3,17 +3,13 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
-webkit-touch-callout: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-khtml-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Design system tokens */
|
/* Design system tokens */
|
||||||
:root {
|
:root {
|
||||||
|
--app-height: 100dvh;
|
||||||
|
--keyboard-offset: 0px;
|
||||||
/* Colors */
|
/* Colors */
|
||||||
--color-primary: #ff9800;
|
--color-primary: #ff9800;
|
||||||
--color-primary-hover: #ffa726;
|
--color-primary-hover: #ffa726;
|
||||||
@@ -87,7 +83,7 @@
|
|||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -98,6 +94,13 @@ body {
|
|||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
min-height: var(--app-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
button, .btn, .button {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Improved input styling for better tablet experience */
|
/* Improved input styling for better tablet experience */
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
const LANDSCAPE_VIEWPORTS = [
|
||||||
|
{ name: 'small-landscape', width: 1024, height: 600 },
|
||||||
|
{ name: 'tablet-landscape', width: 1280, height: 800 },
|
||||||
|
{ name: 'large-landscape', width: 1366, height: 768 },
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const viewport of LANDSCAPE_VIEWPORTS) {
|
||||||
|
test(`viewport matrix: ${viewport.name}`, async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
||||||
|
await page.goto('http://localhost:3000/');
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Neues Spiel starten' }).click();
|
||||||
|
|
||||||
|
// Step 1: ensure keyboard-sized viewport still keeps controls usable.
|
||||||
|
await page.getByLabel('Name Spieler 1').fill('Alpha');
|
||||||
|
await page.setViewportSize({
|
||||||
|
width: viewport.width,
|
||||||
|
height: Math.max(360, viewport.height - Math.floor(viewport.height * 0.35)),
|
||||||
|
});
|
||||||
|
const nextButton = page.getByRole('button', { name: 'Weiter' });
|
||||||
|
await nextButton.scrollIntoViewIfNeeded();
|
||||||
|
await expect(nextButton).toBeVisible();
|
||||||
|
await nextButton.click();
|
||||||
|
|
||||||
|
// Step 2: keep reduced height and verify progression still works.
|
||||||
|
await page.getByLabel('Name Spieler 2').fill('Beta');
|
||||||
|
await page.getByRole('button', { name: 'Weiter' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Überspringen' }).click();
|
||||||
|
|
||||||
|
// Restore full landscape viewport for remaining wizard steps.
|
||||||
|
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: '8-Ball' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Weiter' }).click();
|
||||||
|
await page.getByRole('button', { name: '5' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Weiter' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Break-Regel wählen: Winnerbreak' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Weiter' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Zuerst: Alpha' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Weiter' }).click();
|
||||||
|
|
||||||
|
await expect(page.getByRole('button', { name: /Aktueller Punktestand für Alpha/i })).toBeVisible();
|
||||||
|
await expect(page.getByRole('button', { name: /Aktueller Punktestand für Beta/i })).toBeVisible();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user