@micha.bigler/ui-core-micha 3.14.4 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +7 -0
- package/dist/chat/kitSxRegistry.js +9 -0
- package/dist/components/charts/kitSxRegistry.js +6 -0
- package/dist/entries/charts.js +6 -0
- package/dist/entries/chat.js +8 -0
- package/dist/entries/markdown.js +1 -0
- package/dist/index.js +0 -14
- package/dist/pages/AccountPage.js +1 -2
- package/dist/pages/LoginPage.js +1 -2
- package/dist/pages/PasswordChangePage.js +1 -2
- package/dist/pages/PasswordInvitePage.js +1 -2
- package/dist/pages/PasswordResetRequestPage.js +1 -2
- package/dist/pages/SignUpPage.js +1 -2
- package/dist/pages/SignupConfirmPage.js +1 -2
- package/dist/theme/kitSxEntry.js +11 -0
- package/dist/theme/kitSxRegistry.js +2 -15
- package/package.json +32 -7
- package/.github/workflows/ci.yml +0 -35
- package/.github/workflows/publish.yml +0 -126
- package/DESIGN.md +0 -60
- package/WORK_ORDERS.md +0 -150
- package/dev/entries.jsx +0 -721
- package/dev/fixtures.js +0 -26
- package/dev/main.jsx +0 -75
- package/dev/mockTransport.jsx +0 -128
- package/docs/CHART-LAYOUT.md +0 -157
- package/docs/DARK-TOKENS.md +0 -140
- package/docs/TYPE-SCALE.md +0 -111
- package/docs/messaging-deviations.md +0 -118
- package/index.html +0 -12
- package/renovate.json +0 -10
- package/scripts/chart-api-census.mjs +0 -415
- package/src/auth/AuthContext.jsx +0 -158
- package/src/auth/ReauthModal.jsx +0 -82
- package/src/auth/UserMenu.jsx +0 -121
- package/src/auth/apiClient.jsx +0 -232
- package/src/auth/authApi.jsx +0 -539
- package/src/auth/authConfig.jsx +0 -34
- package/src/auth/reauth.js +0 -47
- package/src/chat/ChatComposer.jsx +0 -36
- package/src/chat/ChatList.jsx +0 -87
- package/src/chat/ChatThread.jsx +0 -128
- package/src/chat/ChatWorkspace.jsx +0 -244
- package/src/chat/MarkdownReply.jsx +0 -22
- package/src/chat/ModelPicker.jsx +0 -85
- package/src/chat/api.js +0 -18
- package/src/chat/useChatSocket.js +0 -32
- package/src/chat/wire.js +0 -7
- package/src/components/AccessCodeManager.jsx +0 -288
- package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
- package/src/components/AllowedEmailDomainsManager.jsx +0 -92
- package/src/components/AuthFactorRequirementCard.jsx +0 -95
- package/src/components/BulkInviteCsvTab.jsx +0 -198
- package/src/components/EmptyState.jsx +0 -38
- package/src/components/LoginForm.jsx +0 -159
- package/src/components/MFAComponent.jsx +0 -350
- package/src/components/MfaLoginComponent.jsx +0 -252
- package/src/components/MobileBottomNav.jsx +0 -82
- package/src/components/PasskeysComponent.jsx +0 -252
- package/src/components/PasswordChangeForm.jsx +0 -87
- package/src/components/PasswordResetRequestForm.jsx +0 -43
- package/src/components/PasswordSetForm.jsx +0 -97
- package/src/components/ProfileComponent.jsx +0 -348
- package/src/components/QrSignupManager.jsx +0 -404
- package/src/components/QrSignupValidityManager.jsx +0 -106
- package/src/components/RegistrationMethodsManager.jsx +0 -150
- package/src/components/SecurityComponent.jsx +0 -141
- package/src/components/SocialLoginButtons.jsx +0 -83
- package/src/components/SoftChip.jsx +0 -93
- package/src/components/StatTile.jsx +0 -39
- package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
- package/src/components/TurnstileWidget.jsx +0 -99
- package/src/components/UserInviteComponent.jsx +0 -76
- package/src/components/UserListComponent.jsx +0 -618
- package/src/components/charts/BarChart.jsx +0 -102
- package/src/components/charts/ChartFrame.jsx +0 -214
- package/src/components/charts/LineChart.jsx +0 -126
- package/src/components/charts/ScatterChart.jsx +0 -299
- package/src/components/charts/TimeSeriesChart.jsx +0 -300
- package/src/components/charts/chartDefaults.js +0 -644
- package/src/components/charts/chartLabels.js +0 -36
- package/src/components/charts/exportChart.js +0 -258
- package/src/components/charts/formatters.js +0 -39
- package/src/components/charts/palette.js +0 -33
- package/src/components/charts/yearTickInterval.js +0 -7
- package/src/i18n/authTranslations.ts +0 -2651
- package/src/i18n/chartsTranslations.ts +0 -91
- package/src/i18n/chatTranslations.ts +0 -55
- package/src/i18n/messagingTranslations.ts +0 -120
- package/src/i18n/notificationsTranslations.ts +0 -32
- package/src/i18n/onboardingTranslations.ts +0 -29
- package/src/i18n/sectionNavTranslations.ts +0 -20
- package/src/i18n/uiCoreTranslations.js +0 -29
- package/src/i18n/userMenuTranslations.ts +0 -5
- package/src/index.js +0 -158
- package/src/layout/PageLayout.jsx +0 -36
- package/src/layout/SectionNav.jsx +0 -320
- package/src/messaging/AttachmentList.jsx +0 -145
- package/src/messaging/Composer.jsx +0 -197
- package/src/messaging/ConversationLaunchers.jsx +0 -51
- package/src/messaging/ConversationList.jsx +0 -109
- package/src/messaging/DirectMessageLauncher.jsx +0 -112
- package/src/messaging/MessageBubble.jsx +0 -183
- package/src/messaging/MessagingProvider.jsx +0 -0
- package/src/messaging/MessagingScopeConfig.jsx +0 -24
- package/src/messaging/PollCard.jsx +0 -163
- package/src/messaging/ReactionBar.jsx +0 -43
- package/src/messaging/ReadTicks.jsx +0 -82
- package/src/messaging/Thread.jsx +0 -195
- package/src/messaging/api.js +0 -48
- package/src/messaging/composerImageCompression.js +0 -35
- package/src/messaging/linkifyText.jsx +0 -37
- package/src/notifications/NotificationBell.jsx +0 -84
- package/src/notifications/NotificationSettings.jsx +0 -330
- package/src/notifications/NotificationsProvider.jsx +0 -224
- package/src/notifications/PopupSurface.jsx +0 -105
- package/src/notifications/api.js +0 -55
- package/src/notifications/feedApi.js +0 -18
- package/src/notifications/realtime.jsx +0 -138
- package/src/notifications/serviceWorker/sw.js +0 -50
- package/src/onboarding/OnboardingProvider.jsx +0 -326
- package/src/onboarding/OnboardingWizard.jsx +0 -61
- package/src/onboarding/WizardDialogShell.jsx +0 -51
- package/src/onboarding/api.js +0 -13
- package/src/onboarding/stepSelection.js +0 -16
- package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
- package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
- package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
- package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
- package/src/pages/AccountPage.jsx +0 -394
- package/src/pages/LoginPage.jsx +0 -343
- package/src/pages/PasswordChangePage.jsx +0 -62
- package/src/pages/PasswordInvitePage.jsx +0 -177
- package/src/pages/PasswordResetRequestPage.jsx +0 -68
- package/src/pages/SignUpPage.jsx +0 -268
- package/src/pages/SignupConfirmPage.jsx +0 -155
- package/src/testing/checkKitIntegration.js +0 -233
- package/src/theme/createAppTheme.js +0 -423
- package/src/theme/fonts.js +0 -3
- package/src/theme/index.js +0 -21
- package/src/theme/kitSxRegistry.js +0 -285
- package/src/theme/themeCompleteness.js +0 -1045
- package/src/theme/tokens.js +0 -478
- package/src/utils/auth-errors.js +0 -76
- package/src/utils/authService.js +0 -223
- package/src/utils/resolveErrorText.js +0 -28
- package/src/utils/webauthn.js +0 -51
- package/tests/AccountPage.profileStatements.test.jsx +0 -162
- package/tests/AccountPage.test.jsx +0 -200
- package/tests/AuthContext.test.jsx +0 -129
- package/tests/BarChart.test.jsx +0 -112
- package/tests/BrowserPushStep.test.jsx +0 -110
- package/tests/ChartFrame.test.jsx +0 -336
- package/tests/ConversationList.test.jsx +0 -144
- package/tests/CookieConsentStep.test.jsx +0 -69
- package/tests/EmptyState.test.jsx +0 -62
- package/tests/LineChart.test.jsx +0 -80
- package/tests/MessagingProvider.test.jsx +0 -50
- package/tests/MobileBottomNav.test.jsx +0 -319
- package/tests/NotificationBell.test.jsx +0 -60
- package/tests/NotificationSettings.test.jsx +0 -276
- package/tests/NotificationsProvider.test.jsx +0 -240
- package/tests/OnboardingProvider.test.jsx +0 -294
- package/tests/OnboardingWizard.test.jsx +0 -143
- package/tests/PasswordChangeForm.test.jsx +0 -70
- package/tests/PasswordInvitePage.test.jsx +0 -142
- package/tests/PasswordSetForm.test.jsx +0 -70
- package/tests/PopupSurface.test.jsx +0 -142
- package/tests/ProfileComponent.refresh.test.jsx +0 -194
- package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
- package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
- package/tests/ScatterChart.test.jsx +0 -270
- package/tests/SectionNav.test.jsx +0 -363
- package/tests/SignUpPage.test.jsx +0 -208
- package/tests/SoftChip.test.jsx +0 -105
- package/tests/StatTile.test.jsx +0 -57
- package/tests/Thread.test.jsx +0 -151
- package/tests/TimeSeriesChart.test.jsx +0 -367
- package/tests/UserListComponent.test.jsx +0 -192
- package/tests/UserMenu.test.jsx +0 -171
- package/tests/apiClientLanguage.test.js +0 -33
- package/tests/apiClientPublicPaths.test.js +0 -178
- package/tests/authApiLogin.test.js +0 -42
- package/tests/authApiRegistration.test.js +0 -31
- package/tests/authErrorCodeRendering.test.jsx +0 -77
- package/tests/authErrors.test.js +0 -74
- package/tests/authTranslations.test.js +0 -74
- package/tests/chart-api-census.test.js +0 -366
- package/tests/chartAxisTickBand.test.jsx +0 -95
- package/tests/chartDefaults.test.js +0 -902
- package/tests/chartLabels.test.js +0 -50
- package/tests/chartsPalette.test.js +0 -99
- package/tests/chatApi.test.js +0 -48
- package/tests/chatDriverNames.test.jsx +0 -71
- package/tests/chatExports.test.js +0 -3
- package/tests/chatList.test.jsx +0 -84
- package/tests/chatPicker.test.jsx +0 -82
- package/tests/chatSocket.test.jsx +0 -26
- package/tests/chatThread.test.jsx +0 -116
- package/tests/chatTranslations.test.js +0 -47
- package/tests/chatWorkspace.test.jsx +0 -234
- package/tests/checkKitIntegration.test.jsx +0 -219
- package/tests/createAppTheme.test.js +0 -132
- package/tests/createAppThemeDark.test.js +0 -127
- package/tests/createAppThemeLightGuard.test.js +0 -40
- package/tests/createAppThemePageContrast.test.js +0 -108
- package/tests/createAppThemeTypography.test.js +0 -53
- package/tests/errorCallSiteGuard.test.js +0 -32
- package/tests/exportChart.test.js +0 -313
- package/tests/feedApi.test.js +0 -46
- package/tests/fixtures/light-theme-baseline.json +0 -2234
- package/tests/i18nAggregate.test.js +0 -120
- package/tests/i18nGermanVariant.test.js +0 -65
- package/tests/loginPageErrorResolution.test.jsx +0 -102
- package/tests/messagingApi.test.js +0 -32
- package/tests/messagingChunk6.test.jsx +0 -116
- package/tests/messagingCompactBubble.test.jsx +0 -64
- package/tests/messagingComposer.test.jsx +0 -136
- package/tests/messagingComposerChunk5.test.jsx +0 -113
- package/tests/messagingContractConformance.test.js +0 -69
- package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
- package/tests/messagingExports.test.js +0 -21
- package/tests/messagingInteractions.test.jsx +0 -136
- package/tests/messagingLastMessagePreview.test.jsx +0 -93
- package/tests/messagingLinkify.test.jsx +0 -51
- package/tests/messagingMessageActions.test.jsx +0 -163
- package/tests/messagingMsg6.test.jsx +0 -105
- package/tests/messagingMsg6f.test.jsx +0 -155
- package/tests/messagingMsg6g.test.jsx +0 -166
- package/tests/messagingMsg6h.test.jsx +0 -136
- package/tests/messagingMsg6i.test.jsx +0 -129
- package/tests/messagingPollRendering.test.jsx +0 -142
- package/tests/messagingReactionMerge.test.jsx +0 -77
- package/tests/messagingReadTicksTooltip.test.jsx +0 -36
- package/tests/messagingThreadReceipts.test.jsx +0 -178
- package/tests/messagingThreadingQuoting.test.jsx +0 -87
- package/tests/messagingUnreadLifecycle.test.jsx +0 -78
- package/tests/notificationsApi.test.js +0 -41
- package/tests/notificationsExports.test.js +0 -34
- package/tests/onboardingDescriptors.test.js +0 -132
- package/tests/packageTreeShaking.test.js +0 -126
- package/tests/realtime.test.jsx +0 -219
- package/tests/resolveErrorText.test.js +0 -72
- package/tests/stepSelection.test.js +0 -53
- package/tests/themeCompleteness.test.js +0 -626
- package/tests/timeSeriesLegend.test.js +0 -99
- package/tests/userScreenTranslations.test.jsx +0 -218
- package/tsconfig.build.json +0 -18
- package/vite.config.mjs +0 -6
- package/work-orders/AUTH-1.md +0 -74
- package/work-orders/AUTH-2.md +0 -74
- package/work-orders/AUTH-4.md +0 -183
- package/work-orders/AUTH-5.md +0 -154
- package/work-orders/AUTH-7.md +0 -181
- package/work-orders/AUTH-8.md +0 -184
- package/work-orders/CHART-1.md +0 -285
- package/work-orders/CHART-2.md +0 -222
- package/work-orders/CHART-3.md +0 -163
- package/work-orders/CHART-4.md +0 -203
- package/work-orders/CHART-5.md +0 -226
- package/work-orders/CHART-6.md +0 -428
- package/work-orders/CHART-7.md +0 -175
- package/work-orders/DX-1.md +0 -169
- package/work-orders/DX-2.md +0 -188
- package/work-orders/DX-3.md +0 -195
- package/work-orders/I18N-1.md +0 -254
- package/work-orders/I18N-3.md +0 -207
- package/work-orders/MSG-3.md +0 -375
- package/work-orders/MSG-3b.md +0 -1002
- package/work-orders/MSG-3c.md +0 -378
- package/work-orders/MSG-3d.md +0 -268
- package/work-orders/MSG-3e.md +0 -164
- package/work-orders/MSG-3f.md +0 -391
- package/work-orders/MSG-6e.md +0 -308
- package/work-orders/MSG-6f.md +0 -214
- package/work-orders/MSG-6g.md +0 -244
- package/work-orders/MSG-6h.md +0 -238
- package/work-orders/MSG-6i.md +0 -271
- package/work-orders/MSG-6j.md +0 -117
- package/work-orders/NOTIF-12.md +0 -214
- package/work-orders/NOTIF-13.md +0 -142
- package/work-orders/NOTIF-14.md +0 -151
- package/work-orders/PRIM-1.md +0 -177
- package/work-orders/SHELL-1.md +0 -255
- package/work-orders/SHELL-2.md +0 -197
- package/work-orders/SHELL-3.md +0 -359
- package/work-orders/SHELL-4.md +0 -351
- package/work-orders/SHELL-5.md +0 -345
- package/work-orders/SHELL-6.md +0 -210
- package/work-orders/THEME-1.md +0 -587
- package/work-orders/THEME-10.md +0 -303
- package/work-orders/THEME-11.md +0 -208
- package/work-orders/THEME-2.md +0 -339
- package/work-orders/THEME-3.md +0 -210
- package/work-orders/THEME-4.md +0 -271
- package/work-orders/THEME-5.md +0 -341
- package/work-orders/THEME-6.md +0 -247
- package/work-orders/THEME-7.md +0 -82
- package/work-orders/THEME-8.md +0 -211
- package/work-orders/THEME-9.md +0 -194
- package/work-orders/UCM-AUTH-10.md +0 -490
- package/work-orders/UCM-AUTH-11.md +0 -185
- package/work-orders/UCM-AUTH-12.md +0 -98
- package/work-orders/UCM-AUTH-13.md +0 -47
- package/work-orders/UCM-AUTH-9.md +0 -207
- package/work-orders/UCM-CHART-10.md +0 -150
- package/work-orders/UCM-CHART-11.md +0 -132
- package/work-orders/UCM-CHART-12.md +0 -348
- package/work-orders/UCM-CHART-13.md +0 -122
- package/work-orders/UCM-CHART-14.md +0 -198
- package/work-orders/UCM-CHART-15.md +0 -187
- package/work-orders/UCM-CHART-16.md +0 -169
- package/work-orders/UCM-CHART-17.md +0 -195
- package/work-orders/UCM-CHART-18.md +0 -200
- package/work-orders/UCM-CHART-8.md +0 -147
- package/work-orders/UCM-CHART-9.md +0 -265
- package/work-orders/UCM-CHAT-1.md +0 -190
- package/work-orders/UCM-CHAT-2.md +0 -75
- package/work-orders/UCM-CI-1.md +0 -65
- package/work-orders/UCM-DEP-1.md +0 -63
- package/work-orders/UCM-I18N-4.md +0 -226
- package/work-orders/UCM-I18N-5.md +0 -211
- package/work-orders/UCM-MSG-20.md +0 -192
- package/work-orders/UCM-PRIM-2.md +0 -114
- package/work-orders/UCM-SHELL-7.md +0 -134
- package/work-orders/UCM-SHELL-8.md +0 -125
- package/work-orders/UCM-TEST-1.md +0 -304
- package/work-orders/UCM-THEME-13.md +0 -69
- package/work-orders/UCM-THEME-14.md +0 -312
- package/work-orders/UCM-THEME-15.md +0 -356
- package/work-orders/UCM-THEME-16.md +0 -80
- package/work-orders/UCM-THEME-17.md +0 -111
- package/work-orders/UCM-THEME-18.md +0 -184
- package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
- package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
- package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
- package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
- package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
- package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
- package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
|
@@ -1,626 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
import { createTheme } from '@mui/material/styles';
|
|
5
|
-
import { describe, expect, it } from 'vitest';
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
assertThemeComplete,
|
|
9
|
-
assertKitSxDisjoint,
|
|
10
|
-
calculateContrastRatio,
|
|
11
|
-
createAppTheme,
|
|
12
|
-
KIT_COMPONENT_SX_REGISTRY,
|
|
13
|
-
reportOffPaletteColours,
|
|
14
|
-
reportKitSxBypasses,
|
|
15
|
-
reportRedundantThemeValues,
|
|
16
|
-
THEME_COMPLETENESS_SURFACES,
|
|
17
|
-
} from '../src/theme';
|
|
18
|
-
import { BASELINE_PALETTE } from '../src/theme/tokens';
|
|
19
|
-
|
|
20
|
-
function sourceFiles(directory) {
|
|
21
|
-
return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
22
|
-
const entryPath = path.join(directory, entry.name);
|
|
23
|
-
if (entry.isDirectory()) return sourceFiles(entryPath);
|
|
24
|
-
if (!/\.jsx?$/.test(entry.name)) return [];
|
|
25
|
-
return [{ path: path.relative(process.cwd(), entryPath), source: fs.readFileSync(entryPath, 'utf8') }];
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
describe('theme completeness', () => {
|
|
30
|
-
it('finds untouched MUI surfaces and accepts createAppTheme', () => {
|
|
31
|
-
const bare = assertThemeComplete(createTheme());
|
|
32
|
-
const baseline = assertThemeComplete(
|
|
33
|
-
createAppTheme({ palette: { primary: { main: '#0F62FE' } } }),
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
expect(bare.findings.length).toBeGreaterThan(0);
|
|
37
|
-
expect(bare.findings.map(({ surface }) => surface)).toContain('shape.borderRadius');
|
|
38
|
-
expect(assertThemeComplete(createTheme({ components: { MuiButton: {} } })).findings
|
|
39
|
-
.map(({ surface }) => surface))
|
|
40
|
-
.toContain('components.MuiButton.styleOverrides.root.minHeight');
|
|
41
|
-
expect(bare.findings.map(({ surface }) => surface)).toEqual(expect.arrayContaining([
|
|
42
|
-
'components.MuiBottomNavigation.styleOverrides.root.boxShadow',
|
|
43
|
-
'components.MuiBottomNavigation.styleOverrides.root.backgroundColor',
|
|
44
|
-
'components.MuiBottomNavigationAction.styleOverrides.root.padding',
|
|
45
|
-
'components.MuiBottomNavigationAction.styleOverrides.root.gap',
|
|
46
|
-
'components.MuiBottomNavigationAction.styleOverrides.root.& .MuiSvgIcon-root.width',
|
|
47
|
-
'components.MuiBottomNavigationAction.styleOverrides.root.& .MuiSvgIcon-root.height',
|
|
48
|
-
'components.MuiBottomNavigationAction.styleOverrides.root.color',
|
|
49
|
-
'components.MuiBottomNavigationAction.styleOverrides.label.fontSize',
|
|
50
|
-
'components.MuiBottomNavigationAction.styleOverrides.label.fontWeight',
|
|
51
|
-
'components.MuiBottomNavigationAction.styleOverrides.label.lineHeight',
|
|
52
|
-
'components.MuiBottomNavigationAction.styleOverrides.label.maxWidth',
|
|
53
|
-
'components.MuiBottomNavigationAction.styleOverrides.label.whiteSpace',
|
|
54
|
-
'components.MuiBottomNavigationAction.styleOverrides.label.overflow',
|
|
55
|
-
'components.MuiBottomNavigationAction.styleOverrides.label.textOverflow',
|
|
56
|
-
'components.MuiBottomNavigationAction.styleOverrides.label.&.Mui-selected.fontSize',
|
|
57
|
-
'components.MuiBottomNavigationAction.styleOverrides.root.&.Mui-selected.color',
|
|
58
|
-
]));
|
|
59
|
-
expect(baseline.findings).toEqual([]);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('requires and automatically resolves the subtle background for a minimal adopter', () => {
|
|
63
|
-
const muiDefault = createTheme();
|
|
64
|
-
const theme = createAppTheme({ palette: { primary: { main: '#0F62FE' } } });
|
|
65
|
-
|
|
66
|
-
expect(muiDefault.palette.background.subtle).toBeUndefined();
|
|
67
|
-
expect(THEME_COMPLETENESS_SURFACES.map(({ surface }) => surface))
|
|
68
|
-
.toContain('palette.background.subtle');
|
|
69
|
-
expect(assertThemeComplete(theme).findings).toEqual([]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('keeps the narrowed bottom-navigation inventory complete', () => {
|
|
73
|
-
const bottomNavigationSurfaces = THEME_COMPLETENESS_SURFACES
|
|
74
|
-
.map(({ surface }) => surface)
|
|
75
|
-
.filter((surface) => surface.startsWith('components.MuiBottomNavigation'));
|
|
76
|
-
|
|
77
|
-
expect(bottomNavigationSurfaces).toHaveLength(16);
|
|
78
|
-
[
|
|
79
|
-
'components.MuiBottomNavigation.styleOverrides.root.borderTop',
|
|
80
|
-
'components.MuiBottomNavigation.styleOverrides.root.borderColor',
|
|
81
|
-
'components.MuiBottomNavigationAction.styleOverrides.root.minWidth',
|
|
82
|
-
'components.MuiBottomNavigationAction.styleOverrides.root.maxWidth',
|
|
83
|
-
].forEach((surface) => expect(bottomNavigationSurfaces).not.toContain(surface));
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('ignores a valid exemption for a deregistered surface', () => {
|
|
87
|
-
const result = assertThemeComplete(
|
|
88
|
-
createAppTheme({ palette: { primary: { main: '#0F62FE' } } }),
|
|
89
|
-
{
|
|
90
|
-
exemptions: [{
|
|
91
|
-
surface: 'components.MuiBottomNavigation.styleOverrides.root.borderTop',
|
|
92
|
-
reason: 'Legacy exemption retained while the application upgrades.',
|
|
93
|
-
}],
|
|
94
|
-
},
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
expect(result.findings).toEqual([]);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('suppresses exactly one surface when an exemption includes a reason', () => {
|
|
101
|
-
const theme = createTheme();
|
|
102
|
-
const before = assertThemeComplete(theme).findings;
|
|
103
|
-
const after = assertThemeComplete(theme, {
|
|
104
|
-
exemptions: [{
|
|
105
|
-
surface: 'palette.background.paper',
|
|
106
|
-
reason: 'This application deliberately uses white as its surface.',
|
|
107
|
-
}],
|
|
108
|
-
}).findings;
|
|
109
|
-
|
|
110
|
-
expect(after).toHaveLength(before.length - 1);
|
|
111
|
-
expect(after.map(({ surface }) => surface)).not.toContain('palette.background.paper');
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('reports an exemption without a reason as its own finding', () => {
|
|
115
|
-
const result = assertThemeComplete(createTheme(), {
|
|
116
|
-
exemptions: [{ surface: 'shape.borderRadius' }],
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
expect(result.findings.map(({ surface }) => surface)).toContain('exemption.shape.borderRadius');
|
|
120
|
-
expect(result.findings.map(({ surface }) => surface)).toContain('shape.borderRadius');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('meets status-on-tint and control-boundary contrast thresholds', () => {
|
|
124
|
-
const theme = createAppTheme({ palette: { primary: { main: '#8AB4F8' } } });
|
|
125
|
-
|
|
126
|
-
for (const status of ['success', 'warning', 'error', 'info', 'stale']) {
|
|
127
|
-
expect(calculateContrastRatio(theme.palette[status].text, theme.palette[status].bg)).toBeGreaterThanOrEqual(4.5);
|
|
128
|
-
}
|
|
129
|
-
for (const state of ['main', 'hover', 'focus', 'error']) {
|
|
130
|
-
expect(calculateContrastRatio(theme.palette.controlBorder[state], '#FFFFFF')).toBeGreaterThanOrEqual(3);
|
|
131
|
-
expect(calculateContrastRatio(theme.palette.controlBorder[state], theme.palette.background.default)).toBeGreaterThanOrEqual(3);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
theme.palette.success.text = 'not-a-colour';
|
|
135
|
-
expect(assertThemeComplete(theme).findings.map(({ surface }) => surface))
|
|
136
|
-
.toContain('contrast.success.text-on-bg');
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('keeps secondary ink AA-legible on the subtle background', () => {
|
|
140
|
-
const ratio = calculateContrastRatio('#5B6670', '#F4F5F6');
|
|
141
|
-
expect(ratio).toBeGreaterThanOrEqual(4.5);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('requires every MUI status main to clear AA on white and the page background', () => {
|
|
145
|
-
const theme = createAppTheme({ palette: { primary: { main: '#8AB4F8' } } });
|
|
146
|
-
|
|
147
|
-
for (const status of ['success', 'warning', 'error', 'info']) {
|
|
148
|
-
expect(calculateContrastRatio(theme.palette[status].main, '#FFFFFF')).toBeGreaterThanOrEqual(4.5);
|
|
149
|
-
expect(calculateContrastRatio(
|
|
150
|
-
theme.palette[status].main,
|
|
151
|
-
theme.palette.background.default,
|
|
152
|
-
)).toBeGreaterThanOrEqual(4.5);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
theme.palette.warning.main = '#C08A2C';
|
|
156
|
-
expect(assertThemeComplete(theme).findings.map(({ surface }) => surface)).toEqual(
|
|
157
|
-
expect.arrayContaining([
|
|
158
|
-
'contrast.warning.main-on-white',
|
|
159
|
-
'contrast.warning.main-on-page',
|
|
160
|
-
]),
|
|
161
|
-
);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('reports main contrast findings without hard-failing for a non-adopting app theme', () => {
|
|
165
|
-
const result = assertThemeComplete(createTheme());
|
|
166
|
-
|
|
167
|
-
expect(result.findings.map(({ surface }) => surface)).toEqual(
|
|
168
|
-
expect.arrayContaining([
|
|
169
|
-
'contrast.warning.main-on-white',
|
|
170
|
-
'contrast.warning.main-on-page',
|
|
171
|
-
]),
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('anchors the select touch target on the input root, not the inner select slot', () => {
|
|
176
|
-
// THEME-8: a min-height on styleOverrides.select lands on a display:block
|
|
177
|
-
// element with variant-dependent, top-anchored padding -- the surplus
|
|
178
|
-
// height collects entirely below the text instead of centring it. The
|
|
179
|
-
// root is already flex/align-items:center, so anchoring there is what
|
|
180
|
-
// actually centres the text. A test only checking "44px somewhere" would
|
|
181
|
-
// pass on the broken version too.
|
|
182
|
-
const theme = createAppTheme({ palette: { primary: { main: '#0F62FE' } } });
|
|
183
|
-
const selectOverrides = theme.components.MuiSelect.styleOverrides;
|
|
184
|
-
|
|
185
|
-
expect(selectOverrides.select?.minHeight).toBeUndefined();
|
|
186
|
-
expect(selectOverrides.root.minHeight).toBe(40);
|
|
187
|
-
expect(selectOverrides.root['@media (any-pointer: coarse)'].minHeight).toBe(44);
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
describe('kit sx disjointness', () => {
|
|
192
|
-
const theme = createAppTheme({ palette: { primary: { main: '#0F62FE' } } });
|
|
193
|
-
|
|
194
|
-
it('finds the real shadowing incident shape and names every part', () => {
|
|
195
|
-
const result = assertKitSxDisjoint(theme, {
|
|
196
|
-
registry: [{
|
|
197
|
-
component: 'FixtureBottomNav',
|
|
198
|
-
muiComponent: 'MuiBottomNavigation',
|
|
199
|
-
sx: { boxShadow: 'none' },
|
|
200
|
-
}],
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
expect(result.findings).toEqual([{
|
|
204
|
-
surface: 'FixtureBottomNav.MuiBottomNavigation.boxShadow',
|
|
205
|
-
reason: expect.stringMatching(/FixtureBottomNav.*MuiBottomNavigation.*boxShadow/),
|
|
206
|
-
}]);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('checks same-root variant slots without conflating child slots', () => {
|
|
210
|
-
const chipResult = assertKitSxDisjoint(theme, {
|
|
211
|
-
registry: [{
|
|
212
|
-
component: 'FixtureChip',
|
|
213
|
-
muiComponent: 'MuiChip',
|
|
214
|
-
sx: { borderColor: 'red' },
|
|
215
|
-
}],
|
|
216
|
-
});
|
|
217
|
-
const bottomNavActionResult = assertKitSxDisjoint(theme, {
|
|
218
|
-
registry: [{
|
|
219
|
-
component: 'FixtureBottomNavAction',
|
|
220
|
-
muiComponent: 'MuiBottomNavigationAction',
|
|
221
|
-
sx: { maxWidth: 'none' },
|
|
222
|
-
}],
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
expect(chipResult.findings.map(({ surface }) => surface))
|
|
226
|
-
.toContain('FixtureChip.MuiChip.borderColor');
|
|
227
|
-
expect(bottomNavActionResult.findings).toEqual([]);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('normalises bgcolor against a backgroundColor baseline default', () => {
|
|
231
|
-
const result = assertKitSxDisjoint({
|
|
232
|
-
components: {
|
|
233
|
-
MuiPaper: {
|
|
234
|
-
styleOverrides: { root: { backgroundColor: '#FFFFFF' } },
|
|
235
|
-
},
|
|
236
|
-
},
|
|
237
|
-
}, {
|
|
238
|
-
registry: [{
|
|
239
|
-
component: 'FixturePaper',
|
|
240
|
-
muiComponent: 'MuiPaper',
|
|
241
|
-
sx: { bgcolor: '#FFFFFF' },
|
|
242
|
-
}],
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
expect(result.findings).toEqual([{
|
|
246
|
-
surface: 'FixturePaper.MuiPaper.bgcolor',
|
|
247
|
-
reason: expect.stringMatching(/FixturePaper.*MuiPaper.*bgcolor/),
|
|
248
|
-
}]);
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
it('keeps every registered kit sx object disjoint from the baseline', () => {
|
|
252
|
-
expect(KIT_COMPONENT_SX_REGISTRY.length).toBeGreaterThan(2);
|
|
253
|
-
expect(assertKitSxDisjoint(theme, {
|
|
254
|
-
exemptions: [
|
|
255
|
-
{
|
|
256
|
-
surface: 'UserListComponent.bodyCell.MuiTableCell.py',
|
|
257
|
-
reason: 'The user list intentionally uses a tighter row density than the baseline TableCell default.',
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
surface: 'UserListComponent.emptyCell.MuiTableCell.py',
|
|
261
|
-
reason: 'The empty-state message intentionally uses more vertical breathing room than the baseline TableCell default.',
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
surface: 'SoftChip.root.MuiChip.height',
|
|
265
|
-
reason: 'SoftChip is a small annotation chip, deliberately auto-height rather than the baseline interactive Chip\'s fixed 32px.',
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
surface: 'SoftChip.caveat.MuiChip.borderRadius',
|
|
269
|
-
reason: 'The caveat variant uses the shared square-ish radius token (shape.borderRadius), not the baseline Chip\'s pill radius.',
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
surface: 'SoftChip.caveat.MuiChip.fontSize',
|
|
273
|
-
reason: 'PRIM-1 token delta: caveat text is 12/500, one weight step above the nearest baseline variant (caption, 12/400). Adding a variant for this is an app-level baseline decision out of scope for this promotion; deliberately left unresolved.',
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
surface: 'SoftChip.status.MuiChip.borderRadius',
|
|
277
|
-
reason: 'The status variant is a pill, matching cockpit\'s existing lane-status pill shape, not the baseline Chip\'s default radius.',
|
|
278
|
-
},
|
|
279
|
-
],
|
|
280
|
-
}).findings).toEqual([]);
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
it('flags inline sx while accepting a top-level exported object', () => {
|
|
284
|
-
const result = reportKitSxBypasses([
|
|
285
|
-
{
|
|
286
|
-
path: 'InlineFixture.jsx',
|
|
287
|
-
source: 'export function Fixture() { return <Button sx={{ minHeight: 12 }} />; }',
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
path: 'ExportedFixture.jsx',
|
|
291
|
-
source: 'export const FIXTURE_SX = { minHeight: 12 }; export function Fixture() { return <Button sx={FIXTURE_SX} />; }',
|
|
292
|
-
},
|
|
293
|
-
]);
|
|
294
|
-
|
|
295
|
-
expect(result.findings).toHaveLength(1);
|
|
296
|
-
expect(result.findings[0]).toEqual({
|
|
297
|
-
surface: 'InlineFixture.jsx:1.MuiButton.sx',
|
|
298
|
-
reason: expect.stringMatching(/Button.*inline sx object.*exported object/i),
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
it('flags a local sx identifier and ignores nested JSX props', () => {
|
|
303
|
-
const result = reportKitSxBypasses([
|
|
304
|
-
{
|
|
305
|
-
path: 'LocalFixture.jsx',
|
|
306
|
-
source: 'const LOCAL_SX = { minHeight: 12 }; export function Fixture() { return <Button sx={LOCAL_SX} />; }',
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
path: 'NestedFixture.jsx',
|
|
310
|
-
source: 'export function Fixture() { return <Button startIcon={<Box sx={{ width: 12 }} />} />; }',
|
|
311
|
-
},
|
|
312
|
-
]);
|
|
313
|
-
|
|
314
|
-
expect(result.findings).toEqual([{
|
|
315
|
-
surface: 'LocalFixture.jsx:1.MuiButton.sx',
|
|
316
|
-
reason: expect.stringMatching(/Button.*non-exported sx object.*LOCAL_SX/i),
|
|
317
|
-
}]);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it('flags an exported sx object omitted from the registry', () => {
|
|
321
|
-
const result = reportKitSxBypasses([{
|
|
322
|
-
path: 'UnregisteredFixture.jsx',
|
|
323
|
-
source: 'export const UNREGISTERED_SX = { minHeight: 12 }; export function Fixture() { return <Button sx={UNREGISTERED_SX} />; }',
|
|
324
|
-
}], { registry: [] });
|
|
325
|
-
|
|
326
|
-
expect(result.findings).toEqual([{
|
|
327
|
-
surface: 'UnregisteredFixture.jsx:1.MuiButton.sx',
|
|
328
|
-
reason: expect.stringMatching(/Button.*exported sx object.*UNREGISTERED_SX.*MuiButton registry entry/i),
|
|
329
|
-
}]);
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
it('flags an sx object registered against the wrong MUI key', () => {
|
|
333
|
-
const result = reportKitSxBypasses([{
|
|
334
|
-
path: 'WrongTargetFixture.jsx',
|
|
335
|
-
source: 'export const WRONG_TARGET_SX = { minHeight: 12 }; export function Fixture() { return <Button sx={WRONG_TARGET_SX} />; }',
|
|
336
|
-
}], {
|
|
337
|
-
registry: [{ exportName: 'WRONG_TARGET_SX', muiComponent: 'MuiPaper' }],
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
expect(result.findings).toEqual([{
|
|
341
|
-
surface: 'WrongTargetFixture.jsx:1.MuiButton.sx',
|
|
342
|
-
reason: expect.stringMatching(/WRONG_TARGET_SX.*MuiButton registry entry/i),
|
|
343
|
-
}]);
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
it('does not let current kit source bypass the exported-object convention', () => {
|
|
347
|
-
expect(reportKitSxBypasses(
|
|
348
|
-
sourceFiles(path.resolve('src')),
|
|
349
|
-
{ registry: KIT_COMPONENT_SX_REGISTRY },
|
|
350
|
-
).findings).toEqual([]);
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
it('suppresses exactly one collision with a reason', () => {
|
|
354
|
-
const registry = [{
|
|
355
|
-
component: 'FixtureButton',
|
|
356
|
-
muiComponent: 'MuiButton',
|
|
357
|
-
sx: { minHeight: 12, textTransform: 'uppercase' },
|
|
358
|
-
}];
|
|
359
|
-
const before = assertKitSxDisjoint(theme, { registry }).findings;
|
|
360
|
-
const after = assertKitSxDisjoint(theme, {
|
|
361
|
-
registry,
|
|
362
|
-
exemptions: [{
|
|
363
|
-
surface: 'FixtureButton.MuiButton.minHeight',
|
|
364
|
-
reason: 'The fixture deliberately overrides one baseline property.',
|
|
365
|
-
}],
|
|
366
|
-
}).findings;
|
|
367
|
-
|
|
368
|
-
expect(before).toHaveLength(2);
|
|
369
|
-
expect(after).toHaveLength(1);
|
|
370
|
-
expect(after[0].surface).toBe('FixtureButton.MuiButton.textTransform');
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
it('honours a reasoned exemption declared on the theme', () => {
|
|
374
|
-
const exemptTheme = {
|
|
375
|
-
...theme,
|
|
376
|
-
themeCompleteness: {
|
|
377
|
-
...theme.themeCompleteness,
|
|
378
|
-
exemptions: [{
|
|
379
|
-
surface: 'FixtureButton.MuiButton.minHeight',
|
|
380
|
-
reason: 'The fixture deliberately owns its compact height.',
|
|
381
|
-
}],
|
|
382
|
-
},
|
|
383
|
-
};
|
|
384
|
-
const result = assertKitSxDisjoint(exemptTheme, {
|
|
385
|
-
registry: [{
|
|
386
|
-
component: 'FixtureButton',
|
|
387
|
-
muiComponent: 'MuiButton',
|
|
388
|
-
sx: { minHeight: 12 },
|
|
389
|
-
}],
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
expect(result.findings).toEqual([]);
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
it('reports an exemption without a reason as its own finding', () => {
|
|
396
|
-
const result = assertKitSxDisjoint(theme, {
|
|
397
|
-
registry: [{
|
|
398
|
-
component: 'FixtureButton',
|
|
399
|
-
muiComponent: 'MuiButton',
|
|
400
|
-
sx: { minHeight: 12 },
|
|
401
|
-
}],
|
|
402
|
-
exemptions: [{ surface: 'FixtureButton.MuiButton.minHeight' }],
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
expect(result.findings.map(({ surface }) => surface)).toEqual([
|
|
406
|
-
'exemption.FixtureButton.MuiButton.minHeight',
|
|
407
|
-
'FixtureButton.MuiButton.minHeight',
|
|
408
|
-
]);
|
|
409
|
-
});
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
describe('off-palette colour reporting', () => {
|
|
413
|
-
it('flags an unknown hex literal and accepts a baseline palette value', () => {
|
|
414
|
-
const result = reportOffPaletteColours([
|
|
415
|
-
{ path: 'Unknown.jsx', source: "const sx = { bgcolor: '#123456' };" },
|
|
416
|
-
{ path: 'Baseline.jsx', source: "const sx = { bgcolor: '#F4F5F6' };" },
|
|
417
|
-
{ path: 'Token.jsx', source: "const sx = { bgcolor: 'background.subtle' };" },
|
|
418
|
-
]);
|
|
419
|
-
|
|
420
|
-
expect(result.findings).toEqual([{
|
|
421
|
-
surface: 'Unknown.jsx:1.colour',
|
|
422
|
-
reason: expect.stringMatching(/#123456.*baseline palette/i),
|
|
423
|
-
}]);
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
it('flags a named CSS colour used by sx', () => {
|
|
427
|
-
const result = reportOffPaletteColours([{
|
|
428
|
-
path: 'Named.jsx',
|
|
429
|
-
source: "const sx = { bgcolor: 'white' };",
|
|
430
|
-
}]);
|
|
431
|
-
|
|
432
|
-
expect(result.findings).toEqual([{
|
|
433
|
-
surface: 'Named.jsx:1.colour',
|
|
434
|
-
reason: expect.stringMatching(/named CSS colour.*white.*baseline palette/i),
|
|
435
|
-
}]);
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it('flags rgba literals and named Canvas fill colours', () => {
|
|
439
|
-
const result = reportOffPaletteColours([
|
|
440
|
-
{
|
|
441
|
-
path: 'Border.jsx',
|
|
442
|
-
source: "const sx = { border: '1px solid rgba(0,0,0,0.2)' };",
|
|
443
|
-
},
|
|
444
|
-
{
|
|
445
|
-
path: 'exportChart.js',
|
|
446
|
-
source: "context.fillStyle = 'white';",
|
|
447
|
-
},
|
|
448
|
-
{
|
|
449
|
-
path: 'NamedBorder.jsx',
|
|
450
|
-
source: "const sx = { border: '1px solid white', boxShadow: '0 0 1px black' };",
|
|
451
|
-
},
|
|
452
|
-
]);
|
|
453
|
-
|
|
454
|
-
expect(result.findings).toEqual([
|
|
455
|
-
{
|
|
456
|
-
surface: 'Border.jsx:1.colour',
|
|
457
|
-
reason: expect.stringMatching(/rgba\(0,0,0,0\.2\).*baseline palette/i),
|
|
458
|
-
},
|
|
459
|
-
{
|
|
460
|
-
surface: 'exportChart.js:1.colour',
|
|
461
|
-
reason: expect.stringMatching(/named CSS colour.*white.*baseline palette/i),
|
|
462
|
-
},
|
|
463
|
-
{
|
|
464
|
-
surface: 'NamedBorder.jsx:1.colour',
|
|
465
|
-
reason: expect.stringMatching(/named CSS colour.*white.*baseline palette/i),
|
|
466
|
-
},
|
|
467
|
-
{
|
|
468
|
-
surface: 'NamedBorder.jsx:1.colour',
|
|
469
|
-
reason: expect.stringMatching(/named CSS colour.*black.*baseline palette/i),
|
|
470
|
-
},
|
|
471
|
-
]);
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
it('excludes only QrSignupManager print-document HTML', () => {
|
|
475
|
-
const result = reportOffPaletteColours([{
|
|
476
|
-
path: 'src/components/QrSignupManager.jsx',
|
|
477
|
-
source: [
|
|
478
|
-
"const panel = { bgcolor: '#123456' };",
|
|
479
|
-
'printWindow.document.write(`',
|
|
480
|
-
' <style>body { background: #654321; }</style>',
|
|
481
|
-
'`);',
|
|
482
|
-
].join('\n'),
|
|
483
|
-
}]);
|
|
484
|
-
|
|
485
|
-
expect(result.findings).toHaveLength(1);
|
|
486
|
-
expect(result.findings[0]).toEqual({
|
|
487
|
-
surface: 'src/components/QrSignupManager.jsx:1.colour',
|
|
488
|
-
reason: expect.stringMatching(/#123456/),
|
|
489
|
-
});
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
it('derives its allowlist from the supplied palette', () => {
|
|
493
|
-
const source = [{ path: 'NewToken.jsx', source: "const sx = { bgcolor: '#123456' };" }];
|
|
494
|
-
const extendedPalette = {
|
|
495
|
-
...BASELINE_PALETTE,
|
|
496
|
-
fixture: { main: '#123456' },
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
expect(reportOffPaletteColours(source).findings).toHaveLength(1);
|
|
500
|
-
expect(reportOffPaletteColours(source, { palette: extendedPalette }).findings).toEqual([]);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
it('reports MUI numeric ramps separately without treating token paths as literals', () => {
|
|
504
|
-
const result = reportOffPaletteColours([{
|
|
505
|
-
path: 'Ramp.jsx',
|
|
506
|
-
source: "const sx = { bgcolor: 'grey.50', borderColor: 'divider', color: 'success.bg', transition: 'release.50' };",
|
|
507
|
-
}]);
|
|
508
|
-
|
|
509
|
-
expect(result.findings).toEqual([{
|
|
510
|
-
surface: 'Ramp.jsx:1.colour',
|
|
511
|
-
reason: expect.stringMatching(/^Report only:.*grey\.50.*untouched numeric palette ramp/i),
|
|
512
|
-
}]);
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
it('ignores comment issue numbers and theme implementation sources', () => {
|
|
516
|
-
const result = reportOffPaletteColours([
|
|
517
|
-
{
|
|
518
|
-
path: 'src/components/charts/chartLabels.js',
|
|
519
|
-
source: '// MUI issues mui-x#18768 and #18399',
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
path: 'src/theme/createAppTheme.js',
|
|
523
|
-
source: "const contrastSurface = '#123456';",
|
|
524
|
-
},
|
|
525
|
-
]);
|
|
526
|
-
|
|
527
|
-
expect(result.findings).toEqual([]);
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
it('keeps current kit source free of hard off-palette findings', () => {
|
|
531
|
-
const result = reportOffPaletteColours(sourceFiles(path.resolve('src')));
|
|
532
|
-
const hardFindings = result.findings.filter(
|
|
533
|
-
({ reason }) => !reason.startsWith('Report only:'),
|
|
534
|
-
);
|
|
535
|
-
|
|
536
|
-
expect(hardFindings).toEqual([]);
|
|
537
|
-
expect(result.findings.some(({ reason }) => reason.includes('grey.50'))).toBe(true);
|
|
538
|
-
});
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
describe('redundant app-side theme values', () => {
|
|
542
|
-
const theme = createAppTheme({ palette: { primary: { main: '#0F62FE' } } });
|
|
543
|
-
|
|
544
|
-
it('flags an sx value that already equals the theme, naming the file, line, component and property', () => {
|
|
545
|
-
const result = reportRedundantThemeValues(
|
|
546
|
-
[{
|
|
547
|
-
path: 'src/components/Example.jsx',
|
|
548
|
-
source: "export function Example() {\n return <Paper sx={{ borderColor: 'divider' }} />;\n}",
|
|
549
|
-
}],
|
|
550
|
-
{ theme },
|
|
551
|
-
);
|
|
552
|
-
|
|
553
|
-
expect(result.findings).toEqual([{
|
|
554
|
-
surface: 'src/components/Example.jsx:2.MuiPaper.borderColor',
|
|
555
|
-
reason: expect.stringMatching(/MuiPaper.*borderColor.*theme already resolves/),
|
|
556
|
-
}]);
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
it('does not flag a genuinely different value', () => {
|
|
560
|
-
const result = reportRedundantThemeValues(
|
|
561
|
-
[{
|
|
562
|
-
path: 'src/components/Example.jsx',
|
|
563
|
-
source: "<Paper sx={{ borderColor: 'error.main' }} />",
|
|
564
|
-
}],
|
|
565
|
-
{ theme },
|
|
566
|
-
);
|
|
567
|
-
|
|
568
|
-
expect(result.findings).toEqual([]);
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
it('does not flag a component tag outside the attribution list at all', () => {
|
|
572
|
-
const result = reportRedundantThemeValues(
|
|
573
|
-
[{
|
|
574
|
-
path: 'src/components/Example.jsx',
|
|
575
|
-
source: "<Box sx={{ borderColor: 'divider' }} />",
|
|
576
|
-
}],
|
|
577
|
-
{ theme },
|
|
578
|
-
);
|
|
579
|
-
|
|
580
|
-
expect(result.findings).toEqual([]);
|
|
581
|
-
});
|
|
582
|
-
|
|
583
|
-
it('does not flag a property the theme does not style on an attributable component', () => {
|
|
584
|
-
// MuiTextField's baseline styleOverrides.root has no borderColor, so this
|
|
585
|
-
// must fall through the themeValue === undefined branch, not match.
|
|
586
|
-
const result = reportRedundantThemeValues(
|
|
587
|
-
[{
|
|
588
|
-
path: 'src/components/Example.jsx',
|
|
589
|
-
source: "<TextField sx={{ borderColor: 'divider' }} />",
|
|
590
|
-
}],
|
|
591
|
-
{ theme },
|
|
592
|
-
);
|
|
593
|
-
|
|
594
|
-
expect(result.findings).toEqual([]);
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
it('skips a numeric borderRadius rather than false-positive on MUI\'s theme-scale multiplier', () => {
|
|
598
|
-
// sx={{ borderRadius: 8 }} on a Card actually renders as
|
|
599
|
-
// theme.shape.borderRadius * 8, not the raw baseline styleOverride value
|
|
600
|
-
// -- comparing the two numbers directly would be a false positive.
|
|
601
|
-
const result = reportRedundantThemeValues(
|
|
602
|
-
[{
|
|
603
|
-
path: 'src/components/Example.jsx',
|
|
604
|
-
source: `<Card sx={{ borderRadius: ${theme.components.MuiCard.styleOverrides.root.borderRadius} }} />`,
|
|
605
|
-
}],
|
|
606
|
-
{ theme },
|
|
607
|
-
);
|
|
608
|
-
|
|
609
|
-
expect(result.findings).toEqual([]);
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
it('matches the finding shape of its sibling checks', () => {
|
|
613
|
-
const result = reportRedundantThemeValues(
|
|
614
|
-
[{ path: 'a.jsx', source: "<Paper sx={{ borderColor: 'divider' }} />" }],
|
|
615
|
-
{ theme },
|
|
616
|
-
);
|
|
617
|
-
|
|
618
|
-
expect(result).toEqual({ findings: expect.any(Array) });
|
|
619
|
-
expect(result.findings[0]).toEqual({ surface: expect.any(String), reason: expect.any(String) });
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
it('returns no findings and requires a theme', () => {
|
|
623
|
-
expect(reportRedundantThemeValues([{ path: 'a.jsx', source: "<Paper sx={{ borderColor: 'divider' }} />" }]))
|
|
624
|
-
.toEqual({ findings: [] });
|
|
625
|
-
});
|
|
626
|
-
});
|