Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions .github/workflows/playwright-demo-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: Playwright Demo Tests

on:
push:
branches:
- main
paths:
- '.github/workflows/playwright-demo-tests.yml'
- 'docs/demo-environment.md'
- 'docs/qa-guide.md'
- 'examples/storybook/**'
- 'packages/**'
- 'playwright.config.ts'
- 'tests/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
pull_request:
types: [opened, synchronize, edited, ready_for_review]
paths:
- '.github/workflows/playwright-demo-tests.yml'
- 'docs/demo-environment.md'
- 'docs/qa-guide.md'
- 'examples/storybook/**'
- 'packages/**'
- 'playwright.config.ts'
- 'tests/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
pull_request_target:
types: [opened, synchronize, edited, ready_for_review]
paths:
- '.github/workflows/playwright-demo-tests.yml'
- 'docs/demo-environment.md'
- 'docs/qa-guide.md'
- 'examples/storybook/**'
- 'packages/**'
- 'playwright.config.ts'
- 'tests/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'

permissions:
contents: read

jobs:
authorize-tests:
if: github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-latest
environment: external
steps:
- run: true

playwright-demo:
if: >-
${{
always() && (
github.event_name == 'push' ||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event_name == 'pull_request_target' &&
github.event.pull_request.head.repo.full_name != github.repository &&
needs.authorize-tests.result == 'success')
)
}}
needs: authorize-tests
runs-on: ubuntu-latest
steps:
- name: Checkout approved fork pull request head
if: github.event_name == 'pull_request_target'
uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }}
allow-unsafe-pr-checkout: true
persist-credentials: false

- name: Checkout pull request head
if: github.event_name == 'pull_request'
uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false

- name: Checkout
if: github.event_name == 'push'
uses: actions/checkout@v5
with:
persist-credentials: false

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.0

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build packages
run: pnpm run build

- name: Install Playwright browsers
run: pnpm exec playwright install chromium --with-deps

- name: Check Playwright demo configuration
env:
VITE_REOWN_PROJECT_ID: ${{ secrets.VITE_REOWN_PROJECT_ID }}
run: |
if [ -z "${VITE_REOWN_PROJECT_ID}" ]; then
echo "::error title=Missing VITE_REOWN_PROJECT_ID::Set the VITE_REOWN_PROJECT_ID repository secret so the AppKit-backed Playwright stories can run in CI."
exit 1
fi

- name: Run Playwright demo tests
env:
VITE_REOWN_PROJECT_ID: ${{ secrets.VITE_REOWN_PROJECT_ID }}
run: |
if [ -z "${VITE_REOWN_PROJECT_ID}" ]; then
echo "::error title=Missing VITE_REOWN_PROJECT_ID::Set the VITE_REOWN_PROJECT_ID repository secret so the AppKit-backed Playwright stories can run in CI."
exit 1
fi
pnpm test:demo

- name: Upload Playwright artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-demo-artifacts
path: |
playwright-report
test-results
Comment thread
Copilot marked this conversation as resolved.
tests/**/test-results
173 changes: 90 additions & 83 deletions packages/governance-widget/src/GovernanceWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -421,22 +421,32 @@ function MemberFooter({
data-testid="GovernanceWidget-member-footer"
position="fixed"
bottom={0}
width={bounds?.width ?? '100%'}
width={bounds ? undefined : '100%'}
maxWidth={bounds ? undefined : GOVERNANCE_WIDGET_MAX_WIDTH}
left={bounds?.left ?? '50%'}
left={bounds ? undefined : '50%'}
zIndex={10}
backgroundColor="$background"
borderTopWidth={1}
paddingHorizontal="$4"
padding={0}
// Keep the footer fixed for the widget's content width, rather than
// stretching it across the host page or Storybook viewport.
style={{
pointerEvents: 'none',
transform: bounds ? undefined : 'translateX(-50%)',
width: bounds ? `${bounds.width}px` : undefined,
maxWidth: bounds ? `${bounds.width}px` : undefined,
left: bounds ? `${bounds.left}px` : undefined,
transform: bounds ? 'none' : 'translateX(-50%)',
boxSizing: 'border-box',
} as any}
>
<XStack alignItems="center" justifyContent="space-between" gap="$3" flexWrap="wrap">
<XStack
alignItems="center"
justifyContent="space-between"
gap="$3"
flexWrap="wrap"
paddingHorizontal="$4"
paddingVertical="$4"
>
<Text variant="caption" tone="secondary">
House: {house}
</Text>
Expand Down Expand Up @@ -589,7 +599,8 @@ function GovernanceWidgetView({
testId?: string
}) {
const { state, actions } = adapter
const widgetRef = useRef<HTMLDivElement>(null)
const resolvedTestId = testId ?? 'GovernanceWidget'
const widgetRef = useRef<HTMLDivElement | null>(null)
const [widgetBounds, setWidgetBounds] = useState<WidgetBounds>()
useEffect(() => {
const element = widgetRef.current
Expand All @@ -604,7 +615,7 @@ function GovernanceWidgetView({
const observer = new ResizeObserver(updateBounds)
observer.observe(element)
return () => observer.disconnect()
}, [])
}, [resolvedTestId])

// Skip is a view-only choice, not membership state: it never touches the
// contract, so a reload or a wallet reconnect (address change) drops back
Expand All @@ -623,83 +634,79 @@ function GovernanceWidgetView({
(state.status === 'onboarding_required' && isOnboardingSkipped)

return (
<YStack
ref={widgetRef}
gap="$4"
width="100%"
paddingBottom="$16"
data-testid={testId ?? 'GovernanceWidget'}
>
<GovernanceHeader state={state} actions={actions} />
<RuntimeNotice state={state} actions={actions} />
{state.error && state.status !== 'friendly_error' && state.transaction.status === 'idle' ? (
<Card data-testid="GovernanceWidget-action-error">
<YStack gap="$2">
<Text color="$error" fontWeight="700">Governance action unavailable</Text>
<Text tone="secondary">{state.error}</Text>
<div ref={widgetRef} data-testid={resolvedTestId} style={{ width: '100%' }}>
<YStack gap="$4" width="100%" paddingBottom="$16">
<GovernanceHeader state={state} actions={actions} />
<RuntimeNotice state={state} actions={actions} />
{state.error && state.status !== 'friendly_error' && state.transaction.status === 'idle' ? (
<Card data-testid="GovernanceWidget-action-error">
<YStack gap="$2">
<Text color="$error" fontWeight="700">Governance action unavailable</Text>
<Text tone="secondary">{state.error}</Text>
</YStack>
</Card>
) : null}
{state.status === 'vote_detail' ? <GovernanceVoteDetail state={state} actions={actions} /> : null}
{state.status === 'onboarding_required' && isOnboardingSkipped ? (
<GovernanceSignupBanner onResume={() => setIsOnboardingSkipped(false)} />
) : null}
{state.status === 'onboarding_required' && !isOnboardingSkipped ? (
<YStack gap="$4">
{state.lifecycleNotice ? (
<Card data-testid="GovernanceWidget-lifecycle-notice">
<Text color="$success" fontWeight="700">{state.lifecycleNotice}</Text>
</Card>
) : null}
<GovernanceOnboardingWidget
currentStepId={state.onboardingStepId}
identityStatus={state.identityStatus}
walletAddress={state.address ?? undefined}
initialHouse={state.selectedHouse}
initialProfileDraft={state.profileDraft}
stakeAmountLabel={state.stakeAmountLabel}
stakeAmountLabels={{
citizenship: formatStakeAmount(state.minimumStakeAmounts.citizenship),
alignment: formatStakeAmount(state.minimumStakeAmounts.alignment),
}}
transactionSteps={state.transactionSteps}
dataTestId="GovernanceWidget-onboarding"
onHouseChange={actions.selectHouse}
onIdentityVerificationPress={() => {
void actions.startIdentityVerification()
}}
onProfileSubmit={(profileDraft) => {
void actions.register(profileDraft)
}}
/>
<Button
variant="secondary"
size="sm"
alignSelf="center"
height={32}
paddingHorizontal="$3"
borderWidth={1}
borderColor="$primary"
borderRadius="$2"
backgroundColor="$primary"
color="$white"
hoverStyle={{ backgroundColor: '$primaryDark', borderColor: '$primaryDark', color: '$white' }}
pressStyle={{ backgroundColor: '$primaryDark', borderColor: '$primaryDark', color: '$white' }}
focusStyle={{ backgroundColor: '$primaryDark', borderColor: '$primaryDark', color: '$white' }}
data-testid="GovernanceWidget-skip-onboarding"
style={{ scrollMarginBottom: 80 }}
onPress={() => setIsOnboardingSkipped(true)}
>
<ButtonText color="$white">Skip for now</ButtonText>
</Button>
</YStack>
</Card>
) : null}
{state.status === 'vote_detail' ? <GovernanceVoteDetail state={state} actions={actions} /> : null}
{state.status === 'onboarding_required' && isOnboardingSkipped ? (
<GovernanceSignupBanner onResume={() => setIsOnboardingSkipped(false)} />
) : null}
{state.status === 'onboarding_required' && !isOnboardingSkipped ? (
<YStack gap="$4">
{state.lifecycleNotice ? (
<Card data-testid="GovernanceWidget-lifecycle-notice">
<Text color="$success" fontWeight="700">{state.lifecycleNotice}</Text>
</Card>
) : null}
<GovernanceOnboardingWidget
currentStepId={state.onboardingStepId}
identityStatus={state.identityStatus}
walletAddress={state.address ?? undefined}
initialHouse={state.selectedHouse}
initialProfileDraft={state.profileDraft}
stakeAmountLabel={state.stakeAmountLabel}
stakeAmountLabels={{
citizenship: formatStakeAmount(state.minimumStakeAmounts.citizenship),
alignment: formatStakeAmount(state.minimumStakeAmounts.alignment),
}}
transactionSteps={state.transactionSteps}
dataTestId="GovernanceWidget-onboarding"
onHouseChange={actions.selectHouse}
onIdentityVerificationPress={() => {
void actions.startIdentityVerification()
}}
onProfileSubmit={(profileDraft) => {
void actions.register(profileDraft)
}}
/>
<Button
variant="secondary"
size="sm"
alignSelf="center"
height={32}
paddingHorizontal="$3"
borderWidth={1}
borderColor="$primary"
borderRadius="$2"
backgroundColor="$primary"
color="$white"
hoverStyle={{ backgroundColor: '$primaryDark', borderColor: '$primaryDark', color: '$white' }}
pressStyle={{ backgroundColor: '$primaryDark', borderColor: '$primaryDark', color: '$white' }}
focusStyle={{ backgroundColor: '$primaryDark', borderColor: '$primaryDark', color: '$white' }}
data-testid="GovernanceWidget-skip-onboarding"
style={{ scrollMarginBottom: 80 }}
onPress={() => setIsOnboardingSkipped(true)}
>
<ButtonText color="$white">Skip for now</ButtonText>
</Button>
</YStack>
) : null}
{state.status === 'pending_alignment' ? <PendingAlignmentState state={state} /> : null}
{state.status === 'revoked' ? <RevokedState state={state} /> : null}
{shouldShowDashboard ? <GovernanceDashboard state={state} actions={actions} /> : null}
{isActiveStatus(state.status) ? <MembershipExitState state={state} actions={actions} /> : null}
<MemberFooter state={state} />
</YStack>
) : null}
{state.status === 'pending_alignment' ? <PendingAlignmentState state={state} /> : null}
{state.status === 'revoked' ? <RevokedState state={state} /> : null}
{shouldShowDashboard ? <GovernanceDashboard state={state} actions={actions} /> : null}
{isActiveStatus(state.status) ? <MembershipExitState state={state} actions={actions} /> : null}
<MemberFooter state={state} bounds={widgetBounds} />
</YStack>
</div>
)
}

Expand Down
Binary file modified tests/design-system/test-results/claimwidget-dark-gwv2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/claimwidget-light-gooddapp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-barchart-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-barchart-empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-barchart-horizontal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-barchart-responsive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-barchart-stress-10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-barchart-stress-100.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-barchart-stress-1000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-barchart-stress.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-card-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-claimwidget-cobalt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-claimwidget-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-claimwidget-teal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-datatable-compact.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-datatable-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-datatable-empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-datatable-nulls.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-datatable-stress.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-drawer-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/design-system/test-results/story-glowcard-default.png
Binary file modified tests/design-system/test-results/story-lineareachart-default.png
Binary file modified tests/design-system/test-results/story-lineareachart-empty.png
Binary file modified tests/design-system/test-results/story-lineareachart-gap.png
Binary file modified tests/design-system/test-results/story-lineareachart-multiaxis.png
Binary file modified tests/design-system/test-results/story-lineareachart-responsive.png
Binary file modified tests/design-system/test-results/story-lineareachart-single.png
Binary file modified tests/design-system/test-results/story-lineareachart-step.png
Binary file modified tests/design-system/test-results/story-lineareachart-stress.png
Binary file modified tests/design-system/test-results/story-piedonutchart-default.png
Binary file modified tests/design-system/test-results/story-piedonutchart-empty.png
Binary file modified tests/design-system/test-results/story-piedonutchart-purepie.png
Binary file modified tests/design-system/test-results/story-piedonutchart-stress.png
Binary file modified tests/design-system/test-results/story-scorecard-default.png
Binary file modified tests/design-system/test-results/story-stepper-default.png
Binary file modified tests/design-system/test-results/story-theme-default.png
Binary file modified tests/design-system/test-results/story-tokenamount-default.png
Binary file modified tests/widgets/citizen-claim-widget/test-results/ccw-03-error.png
Binary file modified tests/widgets/gooddata-widget/test-results/gdw-02-live.png
Binary file modified tests/widgets/gooddata-widget/test-results/gdw-03-demo.png
Binary file modified tests/widgets/gooddata-widget/test-results/gdw-05-empty.png
Loading
Loading