@@ -21,18 +21,10 @@ void main() {
2121 sessionInvalidator = _FakeTokenSessionInvalidator (tokenLocalDataSource);
2222
2323 adapter = _TokenRefreshAdapter ();
24- dio = Dio (
25- BaseOptions (
26- baseUrl: 'https://example.com' ,
27- receiveDataWhenStatusError: true ,
28- ),
29- )..httpClientAdapter = adapter;
30- dio.interceptors.add (
31- TokenInterceptor (
32- dio,
33- tokenLocalDataSource: tokenLocalDataSource,
34- sessionInvalidator: sessionInvalidator,
35- ),
24+ dio = _dioWithTokenInterceptor (
25+ adapter,
26+ tokenLocalDataSource: tokenLocalDataSource,
27+ sessionInvalidator: sessionInvalidator,
3628 );
3729 });
3830
@@ -122,6 +114,41 @@ void main() {
122114 );
123115 });
124116
117+ test ('shares refresh coordination across interceptor instances' , () async {
118+ final refreshCompleter = Completer <void >();
119+ adapter = _TokenRefreshAdapter (refreshCompleter: refreshCompleter);
120+ final firstDio = _dioWithTokenInterceptor (
121+ adapter,
122+ tokenLocalDataSource: tokenLocalDataSource,
123+ sessionInvalidator: sessionInvalidator,
124+ );
125+ final secondDio = _dioWithTokenInterceptor (
126+ adapter,
127+ tokenLocalDataSource: tokenLocalDataSource,
128+ sessionInvalidator: sessionInvalidator,
129+ );
130+
131+ final firstRequest = firstDio.get <String >('/protected/one' );
132+ await _flushMicrotasks ();
133+ final secondRequest = secondDio.get <String >('/protected/two' );
134+ await _flushMicrotasks ();
135+
136+ expect (adapter.refreshRequests, 1 );
137+ refreshCompleter.complete ();
138+
139+ final responses = await Future .wait ([firstRequest, secondRequest]);
140+
141+ expect (responses.map ((response) => response.statusCode), everyElement (200 ));
142+ expect (adapter.refreshRequests, 1 );
143+ expect (tokenLocalDataSource.storeTokensCallCount, 1 );
144+ expect (
145+ adapter.protectedAuthorizationHeaders.where (
146+ (header) => header == 'Bearer new-access-token' ,
147+ ),
148+ hasLength (2 ),
149+ );
150+ });
151+
125152 test ('rejects original request when retry after refresh fails' , () async {
126153 adapter = _TokenRefreshAdapter (retryStatusCode: 500 );
127154 dio.httpClientAdapter = adapter;
@@ -211,6 +238,27 @@ void main() {
211238 );
212239}
213240
241+ Dio _dioWithTokenInterceptor (
242+ HttpClientAdapter adapter, {
243+ required TokenLocalDataSource tokenLocalDataSource,
244+ required TokenSessionInvalidator sessionInvalidator,
245+ }) {
246+ final dio = Dio (
247+ BaseOptions (
248+ baseUrl: 'https://example.com' ,
249+ receiveDataWhenStatusError: true ,
250+ ),
251+ )..httpClientAdapter = adapter;
252+ dio.interceptors.add (
253+ TokenInterceptor (
254+ dio,
255+ tokenLocalDataSource: tokenLocalDataSource,
256+ sessionInvalidator: sessionInvalidator,
257+ ),
258+ );
259+ return dio;
260+ }
261+
214262Future <void > _flushMicrotasks () async {
215263 for (var i = 0 ; i < 5 ; i++ ) {
216264 await Future <void >.delayed (Duration .zero);
0 commit comments