@@ -12,6 +12,8 @@ describe('ImpersonationAdminToolbarComponent', () => {
1212 } ;
1313
1414 beforeEach ( async ( ) => {
15+ impersonation . requestAdminAction . calls . reset ( ) ;
16+ impersonation . requestAdminAction . and . resolveTo ( { account : { cards : [ ] } } ) ;
1517 await TestBed . configureTestingModule ( {
1618 declarations : [ ImpersonationAdminToolbarComponent ] ,
1719 imports : [ FormsModule ] ,
@@ -44,4 +46,90 @@ describe('ImpersonationAdminToolbarComponent', () => {
4446 expect ( styles . borderBottomColor ) . toBe ( 'rgb(70, 80, 90)' ) ;
4547 expect ( styles . borderBottomWidth ) . toBe ( '2px' ) ;
4648 } ) ;
49+
50+ it ( 'aligns its content with the modal header using Bootstrap spacing' , ( ) => {
51+ const toolbar = fixture . nativeElement . querySelector ( '.admin-toolbar' ) as HTMLElement ;
52+
53+ expect ( toolbar . classList ) . toContain ( 'px-3' ) ;
54+ expect ( toolbar . classList ) . toContain ( 'py-2' ) ;
55+ expect ( toolbar . classList ) . not . toContain ( 'p-2' ) ;
56+ expect ( getComputedStyle ( toolbar ) . paddingLeft ) . toBe ( '16px' ) ;
57+ } ) ;
58+
59+ it ( 'loads and manually refreshes the admin context without a success message' , async ( ) => {
60+ await fixture . whenStable ( ) ;
61+ expect ( fixture . componentInstance . message ) . toBe ( '' ) ;
62+
63+ fixture . componentInstance . message = '卡片 123 已绑定' ;
64+ await fixture . componentInstance . refresh ( ) ;
65+
66+ expect ( fixture . componentInstance . message ) . toBe ( '' ) ;
67+ expect ( impersonation . requestAdminAction ) . toHaveBeenCalledWith ( 'refresh-admin-context' , { } ) ;
68+ } ) ;
69+
70+ it ( 'shows specific feedback after a write operation succeeds' , async ( ) => {
71+ await fixture . componentInstance . run ( 'bind-card-by-ext-id' , { extId : 12345678 } ) ;
72+ fixture . detectChanges ( ) ;
73+
74+ expect ( fixture . componentInstance . message ) . toBe ( '卡片 12345678 已绑定' ) ;
75+ expect ( fixture . nativeElement . querySelector ( '[role="status"].text-success' ) . textContent )
76+ . toContain ( '卡片 12345678 已绑定' ) ;
77+ } ) ;
78+
79+ it ( 'keeps refresh errors visible' , async ( ) => {
80+ impersonation . requestAdminAction . and . rejectWith ( new Error ( '刷新失败' ) ) ;
81+
82+ await fixture . componentInstance . refresh ( ) ;
83+ fixture . detectChanges ( ) ;
84+
85+ expect ( fixture . componentInstance . message ) . toBe ( '刷新失败' ) ;
86+ expect ( fixture . nativeElement . querySelector ( '[role="alert"].text-danger' ) . textContent )
87+ . toContain ( '刷新失败' ) ;
88+ } ) ;
89+
90+ it ( 'disables write actions until their required inputs are valid' , async ( ) => {
91+ await fixture . whenStable ( ) ;
92+ fixture . detectChanges ( ) ;
93+ const buttons = Array . from ( fixture . nativeElement . querySelectorAll ( 'button' ) ) as HTMLButtonElement [ ] ;
94+
95+ expect ( buttons . filter ( button => button . textContent ?. trim ( ) !== '刷新' ) . every ( button => button . disabled ) ) . toBeTrue ( ) ;
96+
97+ const extIdInput = fixture . nativeElement . querySelector ( 'input[placeholder="ExtId"]' ) as HTMLInputElement ;
98+ extIdInput . value = '12345678' ;
99+ extIdInput . dispatchEvent ( new Event ( 'input' ) ) ;
100+ fixture . detectChanges ( ) ;
101+ const updatedButtons = Array . from ( fixture . nativeElement . querySelectorAll ( 'button' ) ) as HTMLButtonElement [ ] ;
102+
103+ expect ( fixture . componentInstance . extIdValue ) . toBe ( 12345678 ) ;
104+ expect ( fixture . componentInstance . pending ) . toBeFalse ( ) ;
105+ expect ( updatedButtons . find ( button => button . textContent ?. trim ( ) === '绑定' ) ?. disabled ) . toBeFalse ( ) ;
106+ expect ( updatedButtons . find ( button => button . textContent ?. trim ( ) === '删除外部码' ) ?. disabled ) . toBeTrue ( ) ;
107+ } ) ;
108+
109+ it ( 'does not let an older refresh overwrite a newer write result' , async ( ) => {
110+ await fixture . whenStable ( ) ;
111+ let resolveRefresh ! : ( value : any ) => void ;
112+ let resolveWrite ! : ( value : any ) => void ;
113+ const refreshResult = new Promise ( resolve => resolveRefresh = resolve ) ;
114+ const writeResult = new Promise ( resolve => resolveWrite = resolve ) ;
115+ impersonation . requestAdminAction . and . returnValues ( refreshResult , writeResult ) ;
116+
117+ const refresh = fixture . componentInstance . refresh ( ) ;
118+ const write = fixture . componentInstance . run ( 'bind-card-by-ext-id' , { extId : 12345678 } ) ;
119+ resolveWrite ( { account : { cards : [ { extId : 12345678 } ] } } ) ;
120+ await write ;
121+ resolveRefresh ( { account : { cards : [ ] } } ) ;
122+ await refresh ;
123+
124+ expect ( fixture . componentInstance . data . account . cards ) . toEqual ( [ { extId : 12345678 } ] ) ;
125+ expect ( fixture . componentInstance . message ) . toBe ( '卡片 12345678 已绑定' ) ;
126+ } ) ;
127+
128+ it ( 'allows fields to shrink before the toolbar wraps on narrow viewports' , ( ) => {
129+ const field = fixture . nativeElement . querySelector ( '.field' ) as HTMLElement ;
130+ const styles = getComputedStyle ( field ) ;
131+
132+ expect ( styles . flexShrink ) . toBe ( '1' ) ;
133+ expect ( styles . minWidth ) . toBe ( '0px' ) ;
134+ } ) ;
47135} ) ;
0 commit comments