131 lines
5.2 KiB
PowerShell
131 lines
5.2 KiB
PowerShell
$ErrorActionPreference = 'Stop'
|
|
|
|
function ConvertFrom-Utf8Base64 {
|
|
param([string]$Value)
|
|
return [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($Value))
|
|
}
|
|
|
|
function Assert-Contains {
|
|
param(
|
|
[string]$Content,
|
|
[string]$Expected,
|
|
[string]$Message
|
|
)
|
|
|
|
if ($Content -notmatch [regex]::Escape($Expected)) {
|
|
throw $Message
|
|
}
|
|
}
|
|
|
|
function Assert-NotContains {
|
|
param(
|
|
[string]$Content,
|
|
[string]$Unexpected,
|
|
[string]$Message
|
|
)
|
|
|
|
if ($Content -match [regex]::Escape($Unexpected)) {
|
|
throw $Message
|
|
}
|
|
}
|
|
|
|
$root = Split-Path -Parent $PSScriptRoot
|
|
$entryPath = Join-Path $root 'pages/auth/a01-entry.vue'
|
|
$legacyLoginPath = Join-Path $root 'pages/auth/a02-login.vue'
|
|
$pagesPath = Join-Path $root 'pages.json'
|
|
|
|
if (-not (Test-Path -LiteralPath $entryPath)) {
|
|
throw 'Missing the single A01 login page.'
|
|
}
|
|
if (Test-Path -LiteralPath $legacyLoginPath) {
|
|
throw 'A02 was merged into A01, so the legacy page file must be removed.'
|
|
}
|
|
|
|
$pages = Get-Content -LiteralPath $pagesPath -Raw -Encoding utf8 | ConvertFrom-Json
|
|
if ($pages.pages[0].path -ne 'pages/auth/a01-entry') {
|
|
throw 'A01 must remain the first application route.'
|
|
}
|
|
if ($pages.pages.path -contains 'pages/auth/a02-login') {
|
|
throw 'pages.json must not retain the legacy A02 route.'
|
|
}
|
|
if ($pages.pages.Count -ne 53) {
|
|
throw "Expected 53 final routes after the A02 merge, found $($pages.pages.Count)."
|
|
}
|
|
|
|
$entry = Get-Content -LiteralPath $entryPath -Raw -Encoding utf8
|
|
|
|
# Final decorative surfaces must come from real bitmap assets.
|
|
foreach ($asset in @(
|
|
'a01-login-header-v1.png',
|
|
'a01-login-header-exact-v2.png',
|
|
'auth-ink-scenery.png',
|
|
'a01-login-scroll-frame-v1.png',
|
|
'a01-title-divider-v2.png',
|
|
'a01-primary-button.png',
|
|
'a01-secondary-button.png',
|
|
'auth-wechat.png',
|
|
'a01-icon-phone-v1.png',
|
|
'a01-icon-lock-v1.png',
|
|
'a01-icon-eye-open-v1.png',
|
|
'a01-icon-eye-closed-pupil-v2.png',
|
|
'a01-icon-sms-code-v2.png',
|
|
'a02-agreement-unchecked.png',
|
|
'a02-agreement-checked.png'
|
|
)) {
|
|
Assert-Contains -Content $entry -Expected $asset -Message "A01 is missing asset reference: $asset"
|
|
}
|
|
foreach ($obsoleteHeaderAsset in @('auth-header.png', 'brand-seal.png', 'a01-paper-transition-v1.png')) {
|
|
Assert-NotContains -Content $entry -Unexpected $obsoleteHeaderAsset -Message "A01 must use the selected design's single exact header bitmap instead of composing $obsoleteHeaderAsset."
|
|
}
|
|
|
|
$requiredCopy = @(
|
|
'55m75b2V5a626LCx',
|
|
'5a+G56CB55m75b2V',
|
|
'6aqM6K+B56CB55m75b2V',
|
|
'5omL5py65Y+3',
|
|
'5a+G56CB',
|
|
'6aqM6K+B56CB',
|
|
'5b+Y6K6w5a+G56CB',
|
|
'6I635Y+W6aqM6K+B56CB',
|
|
'5b6u5L+h55m75b2V',
|
|
'6L+Y5rKh5pyJ6LSm5Y+377yf',
|
|
'5rOo5YaM6LSm5Y+3',
|
|
'44CK55So5oi35Y2P6K6u44CL',
|
|
'44CK6ZqQ56eB5pS/562W44CL'
|
|
) | ForEach-Object { ConvertFrom-Utf8Base64 $_ }
|
|
foreach ($copy in $requiredCopy) {
|
|
Assert-Contains -Content $entry -Expected $copy -Message "A01 is missing required visible copy: $copy"
|
|
}
|
|
|
|
foreach ($contract in @(
|
|
"const activeLoginMethod = ref('password')",
|
|
'const passwordVisible = ref(false)',
|
|
"const LOGIN_METHOD_STORAGE_KEY = 'a01:last-login-method'",
|
|
'uni.getStorageSync(LOGIN_METHOD_STORAGE_KEY)',
|
|
'uni.setStorageSync(LOGIN_METHOD_STORAGE_KEY, method)',
|
|
'const switchLoginMethod = (method) =>',
|
|
'const togglePasswordVisibility = () =>',
|
|
"url: '/pages/auth/a04-register'",
|
|
"url: '/pages/auth/a05-reset-password'",
|
|
'class="feedback-toast"',
|
|
'class="verification-layer"',
|
|
'class="login-submit"'
|
|
)) {
|
|
Assert-Contains -Content $entry -Expected $contract -Message "A01 is missing state or interaction contract: $contract"
|
|
}
|
|
|
|
foreach ($nativeUi in @('uni.showToast', 'uni.showModal', 'uni.showLoading', 'uni.showActionSheet')) {
|
|
Assert-NotContains -Content $entry -Unexpected $nativeUi -Message "A01 must not use native UniApp feedback: $nativeUi"
|
|
}
|
|
Assert-NotContains -Content $entry -Unexpected "url: '/pages/auth/a02-login" -Message 'A01 must not navigate to A02.'
|
|
Assert-NotContains -Content $entry -Unexpected 'brand-intro' -Message 'A01 must remove the legacy oversized brand introduction.'
|
|
Assert-NotContains -Content $entry -Unexpected 'min-height: 100vh' -Message 'A01 must not depend on 100vh for its page shell.'
|
|
Assert-NotContains -Content $entry -Unexpected 'exact-chrome-overlay' -Message 'A01 must not stack a second full-screen scroll perimeter over the complete scroll frame.'
|
|
Assert-NotContains -Content $entry -Unexpected 'auth-design-scenery-v1.png' -Message 'A01 must not use the scenery bitmap that contains stray scroll handles.'
|
|
Assert-NotContains -Content $entry -Unexpected 'a01-icon-eye-closed-v1.png' -Message 'A01 hidden-password icon must retain the center pupil instead of using the hollow crossed eye.'
|
|
Assert-NotContains -Content $entry -Unexpected 'a01-icon-verification-v1.png' -Message 'A01 SMS field must use a message-code icon instead of a success-state checkmark.'
|
|
Assert-NotContains -Content $entry -Unexpected 'a01-icon-sms-code-v1.svg' -Message 'A01 SMS field must use the custom generated icon instead of the temporary third-party SVG.'
|
|
Assert-NotContains -Content $entry -Unexpected '@media (max-height:' -Message 'A01 must preserve the design ratio on short screens and scroll instead of compressing with pixel breakpoints.'
|
|
|
|
Write-Output 'A01-LOGIN-MERGE-CONTRACT PASS'
|