mirror of
https://gh-proxy.org/https://github.com/klinsmaya/workdsh.git
synced 2026-11-09 18:07:02 +08:00
test(desktop): define browser access and welcome flow
This commit is contained in:
@@ -60,6 +60,33 @@ describe('Desktop Setup Wizard copy and contract', () => {
|
||||
expect(english.skipDialogBody).toContain('Desktop settings')
|
||||
})
|
||||
|
||||
it('introduces first-time setup for the current Profile before showing settings', () => {
|
||||
const english = desktopSetupWizardCopy('en')
|
||||
const chinese = desktopSetupWizardCopy('zh')
|
||||
expect(chinese.welcomeTitle).toBeTruthy()
|
||||
expect(chinese.welcomeBody).toContain('Profile')
|
||||
expect(chinese.firstProfileSetup).toContain('第一次')
|
||||
expect(chinese.firstProfileSetup).toContain('桌面模式')
|
||||
expect(chinese.startSetup).toBe('开始设置')
|
||||
expect(english.welcomeTitle).toBeTruthy()
|
||||
expect(english.welcomeBody).toContain('Profile')
|
||||
expect(english.firstProfileSetup).toMatch(/first(?:-time| time)/iu)
|
||||
expect(english.firstProfileSetup).toMatch(/Desktop mode/iu)
|
||||
expect(english.startSetup).toBe('Start setup')
|
||||
})
|
||||
|
||||
it('treats browser opening as permission, not an automatic startup action', () => {
|
||||
const english = desktopSetupWizardCopy('en')
|
||||
const chinese = desktopSetupWizardCopy('zh')
|
||||
expect(chinese.openBrowser).toBe('允许在浏览器中打开')
|
||||
expect(chinese.openBrowser).not.toMatch(/启动后|自动/u)
|
||||
expect(chinese.browserCompatibilityNotice).toContain('兼容模式')
|
||||
expect(chinese.browserCompatibilityNotice).toMatch(/只(?:能|支持|可)/u)
|
||||
expect(english.openBrowser).toMatch(/allow.+(?:open|opening).+browser/iu)
|
||||
expect(english.openBrowser).not.toMatch(/after startup|automatically/iu)
|
||||
expect(english.browserCompatibilityNotice).toMatch(/only.+compatibility mode/iu)
|
||||
})
|
||||
|
||||
it('requires confirmation only when loopback access is changed to LAN', () => {
|
||||
expect(desktopSetupWizardRequiresLanConfirmation('loopback', 'lan')).toBe(true)
|
||||
expect(desktopSetupWizardRequiresLanConfirmation('lan', 'loopback')).toBe(false)
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
SetupWizardNavigation,
|
||||
SetupWizardStepPage,
|
||||
SetupWizardSuccess,
|
||||
SetupWizardWelcome,
|
||||
} from '../src/native-ui/setup-wizard/App.tsx'
|
||||
import { Button } from '../src/native-ui/components/ui/button.tsx'
|
||||
import { DialogClose } from '../src/native-ui/components/ui/dialog.tsx'
|
||||
@@ -51,7 +52,7 @@ const selection: DesktopSetupWizardSelection = {
|
||||
|
||||
const copy = desktopSetupWizardCopy('zh')
|
||||
|
||||
function renderStep(step: Exclude<(typeof DESKTOP_SETUP_WIZARD_STEPS)[number], 'success'>): string {
|
||||
function renderStep(step: Exclude<(typeof DESKTOP_SETUP_WIZARD_STEPS)[number], 'welcome' | 'success'>): string {
|
||||
return renderToStaticMarkup(createElement(SetupWizardStepPage, {
|
||||
copy,
|
||||
input,
|
||||
@@ -85,8 +86,9 @@ function elementTree(node: ReactNode): readonly ReactElement[] {
|
||||
afterEach(() => { vi.unstubAllGlobals() })
|
||||
|
||||
describe('Setup Wizard step flow', () => {
|
||||
it('keeps one setting per page and browser access as the final setting page', () => {
|
||||
it('starts with an introduction and keeps browser access as the final setting page', () => {
|
||||
expect(DESKTOP_SETUP_WIZARD_STEPS).toEqual([
|
||||
'welcome',
|
||||
'mode',
|
||||
'material',
|
||||
'market',
|
||||
@@ -99,6 +101,7 @@ describe('Setup Wizard step flow', () => {
|
||||
it('moves only between adjacent pages and stops at both boundaries', () => {
|
||||
expect(DESKTOP_SETUP_WIZARD_STEPS.map(step => previousDesktopSetupWizardStep(step))).toEqual([
|
||||
undefined,
|
||||
'welcome',
|
||||
'mode',
|
||||
'material',
|
||||
'market',
|
||||
@@ -106,6 +109,7 @@ describe('Setup Wizard step flow', () => {
|
||||
'browser',
|
||||
])
|
||||
expect(DESKTOP_SETUP_WIZARD_STEPS.map(step => nextDesktopSetupWizardStep(step))).toEqual([
|
||||
'mode',
|
||||
'material',
|
||||
'market',
|
||||
'notifications',
|
||||
@@ -116,6 +120,48 @@ describe('Setup Wizard step flow', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Setup Wizard welcome page', () => {
|
||||
it('identifies the Profile and explains why first-run Desktop setup is shown', () => {
|
||||
const markup = renderToStaticMarkup(createElement(SetupWizardWelcome, {
|
||||
copy,
|
||||
onSkip: () => {},
|
||||
onStart: () => {},
|
||||
profileName: input.profileName,
|
||||
}))
|
||||
expect(markup).toContain('data-setup-step="welcome"')
|
||||
expect(markup).toContain(copy.welcomeTitle)
|
||||
expect(markup).toContain(copy.welcomeBody)
|
||||
expect(markup).toContain(copy.firstProfileSetup)
|
||||
expect(markup).toContain(copy.profile)
|
||||
expect(markup).toContain(input.profileName)
|
||||
})
|
||||
|
||||
it('offers Start setup and confirmed Skip without ordinary arrow navigation', () => {
|
||||
const markup = renderToStaticMarkup(createElement(SetupWizardWelcome, {
|
||||
copy,
|
||||
onSkip: () => {},
|
||||
onStart: () => {},
|
||||
profileName: input.profileName,
|
||||
}))
|
||||
const navigation = renderToStaticMarkup(createElement(SetupWizardNavigation, {
|
||||
copy,
|
||||
onBack: () => {},
|
||||
onNext: () => {},
|
||||
onSkip: () => {},
|
||||
step: 'welcome',
|
||||
}))
|
||||
expect(markup).toContain(copy.startSetup)
|
||||
expect(markup).toContain(copy.skip)
|
||||
expect(markup).toContain('data-slot="dialog-trigger"')
|
||||
expect(markup).toContain('aria-haspopup="dialog"')
|
||||
expect(markup).not.toContain(`aria-label="${copy.back}"`)
|
||||
expect(markup).not.toContain(`aria-label="${copy.next}"`)
|
||||
expect(markup).not.toContain('lucide-arrow-left')
|
||||
expect(markup).not.toContain('lucide-arrow-right')
|
||||
expect(navigation).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Setup Wizard setting pages', () => {
|
||||
it.each([
|
||||
['mode', 'presentationTitle', 'presentationBody'],
|
||||
@@ -162,6 +208,17 @@ describe('Setup Wizard setting pages', () => {
|
||||
expect(browser).not.toContain(copy.dshMarket)
|
||||
})
|
||||
|
||||
it('describes browser access as an opt-in capability limited to compatibility mode', () => {
|
||||
const browser = renderStep('browser')
|
||||
expect(browser).toContain(copy.openBrowser)
|
||||
expect(browser).toContain(copy.browserCompatibilityNotice)
|
||||
expect(copy.openBrowser).toBe('允许在浏览器中打开')
|
||||
expect(copy.openBrowser).not.toContain('启动后')
|
||||
expect(copy.openBrowser).not.toContain('自动')
|
||||
expect(copy.browserCompatibilityNotice).toContain('兼容模式')
|
||||
expect(copy.browserCompatibilityNotice).toMatch(/只(?:能|支持|可)/u)
|
||||
})
|
||||
|
||||
it('uses the shadcn Switch component for every wizard toggle', () => {
|
||||
const notifications = renderStep('notifications')
|
||||
const browser = renderStep('browser')
|
||||
@@ -174,7 +231,7 @@ describe('Setup Wizard setting pages', () => {
|
||||
|
||||
describe('Setup Wizard navigation and completion', () => {
|
||||
it('shows Skip on the left and back/forward arrow buttons on every setting page', () => {
|
||||
for (const step of DESKTOP_SETUP_WIZARD_STEPS.slice(0, -1)) {
|
||||
for (const step of DESKTOP_SETUP_WIZARD_STEPS.slice(1, -1)) {
|
||||
const markup = renderToStaticMarkup(createElement(SetupWizardNavigation, {
|
||||
copy,
|
||||
onBack: () => {},
|
||||
@@ -191,7 +248,7 @@ describe('Setup Wizard navigation and completion', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps the first-page back button visible but disabled', () => {
|
||||
it('lets the first setting page return to the welcome page', () => {
|
||||
const markup = renderToStaticMarkup(createElement(SetupWizardNavigation, {
|
||||
copy,
|
||||
onBack: () => {},
|
||||
@@ -199,7 +256,8 @@ describe('Setup Wizard navigation and completion', () => {
|
||||
onSkip: () => {},
|
||||
step: 'mode',
|
||||
}))
|
||||
expect(markup).toMatch(new RegExp(`<button[^>]+aria-label="${copy.back}"[^>]+disabled`, 'u'))
|
||||
expect(markup).toContain(`aria-label="${copy.back}"`)
|
||||
expect(markup).not.toMatch(new RegExp(`<button[^>]+aria-label="${copy.back}"[^>]+disabled`, 'u'))
|
||||
})
|
||||
|
||||
it('uses a dialog trigger for Skip and explains where setup remains available', () => {
|
||||
|
||||
Reference in New Issue
Block a user