@oxy.so/core 1.12.1 → 1.16.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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/crypto/webIdentityCarrier.js +1 -1
- package/dist/cjs/i18n/locales/ar-SA.json +33 -88
- package/dist/cjs/i18n/locales/ca-ES.json +35 -90
- package/dist/cjs/i18n/locales/de-DE.json +33 -88
- package/dist/cjs/i18n/locales/en-US.json +45 -141
- package/dist/cjs/i18n/locales/es-ES.json +44 -140
- package/dist/cjs/i18n/locales/fr-FR.json +33 -88
- package/dist/cjs/i18n/locales/it-IT.json +33 -88
- package/dist/cjs/i18n/locales/ja-JP.json +33 -88
- package/dist/cjs/i18n/locales/ko-KR.json +33 -88
- package/dist/cjs/i18n/locales/locales/ar-SA.json +33 -88
- package/dist/cjs/i18n/locales/locales/ca-ES.json +35 -90
- package/dist/cjs/i18n/locales/locales/de-DE.json +33 -88
- package/dist/cjs/i18n/locales/locales/en-US.json +45 -141
- package/dist/cjs/i18n/locales/locales/es-ES.json +44 -140
- package/dist/cjs/i18n/locales/locales/fr-FR.json +33 -88
- package/dist/cjs/i18n/locales/locales/it-IT.json +33 -88
- package/dist/cjs/i18n/locales/locales/ja-JP.json +33 -88
- package/dist/cjs/i18n/locales/locales/ko-KR.json +33 -88
- package/dist/cjs/i18n/locales/locales/pt-PT.json +33 -88
- package/dist/cjs/i18n/locales/locales/zh-CN.json +34 -89
- package/dist/cjs/i18n/locales/pt-PT.json +33 -88
- package/dist/cjs/i18n/locales/zh-CN.json +34 -89
- package/dist/cjs/index.js +10 -7
- package/dist/cjs/mixins/OxyServices.utility.js +140 -0
- package/dist/cjs/server/securityHeaders.js +19 -1
- package/dist/cjs/session/accountDialogController.js +37 -142
- package/dist/cjs/utils/authWebUrl.js +7 -6
- package/dist/cjs/utils/oauthPkce.js +5 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/crypto/webIdentityCarrier.js +1 -1
- package/dist/esm/i18n/locales/ar-SA.json +33 -88
- package/dist/esm/i18n/locales/ca-ES.json +35 -90
- package/dist/esm/i18n/locales/de-DE.json +33 -88
- package/dist/esm/i18n/locales/en-US.json +45 -141
- package/dist/esm/i18n/locales/es-ES.json +44 -140
- package/dist/esm/i18n/locales/fr-FR.json +33 -88
- package/dist/esm/i18n/locales/it-IT.json +33 -88
- package/dist/esm/i18n/locales/ja-JP.json +33 -88
- package/dist/esm/i18n/locales/ko-KR.json +33 -88
- package/dist/esm/i18n/locales/locales/ar-SA.json +33 -88
- package/dist/esm/i18n/locales/locales/ca-ES.json +35 -90
- package/dist/esm/i18n/locales/locales/de-DE.json +33 -88
- package/dist/esm/i18n/locales/locales/en-US.json +45 -141
- package/dist/esm/i18n/locales/locales/es-ES.json +44 -140
- package/dist/esm/i18n/locales/locales/fr-FR.json +33 -88
- package/dist/esm/i18n/locales/locales/it-IT.json +33 -88
- package/dist/esm/i18n/locales/locales/ja-JP.json +33 -88
- package/dist/esm/i18n/locales/locales/ko-KR.json +33 -88
- package/dist/esm/i18n/locales/locales/pt-PT.json +33 -88
- package/dist/esm/i18n/locales/locales/zh-CN.json +34 -89
- package/dist/esm/i18n/locales/pt-PT.json +33 -88
- package/dist/esm/i18n/locales/zh-CN.json +34 -89
- package/dist/esm/index.js +2 -1
- package/dist/esm/mixins/OxyServices.utility.js +138 -0
- package/dist/esm/server/securityHeaders.js +19 -1
- package/dist/esm/session/accountDialogController.js +37 -142
- package/dist/esm/utils/authWebUrl.js +6 -5
- package/dist/esm/utils/oauthPkce.js +5 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/crypto/webIdentityCarrier.d.ts +1 -1
- package/dist/types/index.d.ts +5 -3
- package/dist/types/mixins/OxyServices.utility.d.ts +84 -1
- package/dist/types/server/requesterAssertion.d.ts +2 -2
- package/dist/types/server/securityHeaders.d.ts +9 -12
- package/dist/types/session/accountDialogController.d.ts +29 -98
- package/dist/types/utils/authWebUrl.d.ts +6 -5
- package/dist/types/utils/oauthPkce.d.ts +10 -0
- package/package.json +2 -2
- package/src/crypto/webIdentityCarrier.ts +1 -1
- package/src/i18n/locales/ar-SA.json +33 -88
- package/src/i18n/locales/ca-ES.json +35 -90
- package/src/i18n/locales/de-DE.json +33 -88
- package/src/i18n/locales/en-US.json +45 -141
- package/src/i18n/locales/es-ES.json +44 -140
- package/src/i18n/locales/fr-FR.json +33 -88
- package/src/i18n/locales/it-IT.json +33 -88
- package/src/i18n/locales/ja-JP.json +33 -88
- package/src/i18n/locales/ko-KR.json +33 -88
- package/src/i18n/locales/pt-PT.json +33 -88
- package/src/i18n/locales/zh-CN.json +34 -89
- package/src/index.ts +9 -3
- package/src/mixins/OxyServices.utility.ts +208 -0
- package/src/mixins/__tests__/accountEvents.test.ts +158 -0
- package/src/server/__tests__/securityHeaders.test.ts +17 -0
- package/src/server/securityHeaders.ts +29 -1
- package/src/session/__tests__/accountDialogController.test.ts +42 -184
- package/src/session/accountDialogController.ts +50 -185
- package/src/utils/__tests__/oauthPkce.test.ts +7 -0
- package/src/utils/authWebUrl.ts +6 -5
- package/src/utils/oauthPkce.ts +16 -1
|
@@ -201,8 +201,6 @@ interface Harness {
|
|
|
201
201
|
function makeHarness(
|
|
202
202
|
over: Partial<{
|
|
203
203
|
clientId: string | null;
|
|
204
|
-
openPopup: () => import('../accountDialogController').PopupWindowHandle | null;
|
|
205
|
-
hubBaseUrl: string;
|
|
206
204
|
platform: import('../../utils/commonsDelivery').CommonsDeliveryPlatform;
|
|
207
205
|
openUrl: (url: string) => void;
|
|
208
206
|
canOpenApp: (url: string) => Promise<boolean>;
|
|
@@ -220,8 +218,6 @@ function makeHarness(
|
|
|
220
218
|
commitSession,
|
|
221
219
|
onSignedIn,
|
|
222
220
|
pollIntervalMs: 1000,
|
|
223
|
-
openPopup: over.openPopup,
|
|
224
|
-
hubBaseUrl: over.hubBaseUrl,
|
|
225
221
|
platform: over.platform,
|
|
226
222
|
openUrl: over.openUrl,
|
|
227
223
|
canOpenApp: over.canOpenApp,
|
|
@@ -710,129 +706,57 @@ describe('AccountDialogController — sign in with Oxy', () => {
|
|
|
710
706
|
});
|
|
711
707
|
});
|
|
712
708
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
close: jest.fn(() => {
|
|
721
|
-
closed = true;
|
|
722
|
-
}),
|
|
723
|
-
location: { href: '' },
|
|
724
|
-
setClosed: () => {
|
|
725
|
-
closed = true;
|
|
726
|
-
},
|
|
727
|
-
};
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
describe('AccountDialogController — startPasskeyHubSignIn (b2 passkey hub popup)', () => {
|
|
731
|
-
it('opens the popup synchronously, then navigates it to the hub URL with the authorizeCode once the session exists', async () => {
|
|
732
|
-
const popup = fakePopup();
|
|
733
|
-
const openPopup = jest.fn(() => popup);
|
|
734
|
-
const { controller, oxy } = makeHarness({ openPopup, hubBaseUrl: 'https://id.oxy.so' });
|
|
735
|
-
oxy.startCommonsSignIn.mockResolvedValue({
|
|
736
|
-
sessionToken: 'secret-tok',
|
|
737
|
-
authorizeCode: 'AUTH-CODE',
|
|
738
|
-
qrPayload: 'oxycommons://approve?v=1&code=AUTH-CODE',
|
|
739
|
-
expiresAt: Date.now() + 300_000,
|
|
740
|
-
status: 'pending',
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
await controller.startPasskeyHubSignIn();
|
|
744
|
-
|
|
745
|
-
expect(openPopup).toHaveBeenCalledTimes(1);
|
|
746
|
-
expect(popup.location.href).toBe('https://id.oxy.so/continue?code=AUTH-CODE');
|
|
747
|
-
// Same underlying device-flow session showQr would create — the QR view
|
|
748
|
-
// still renders as a fallback/alternative alongside the popup.
|
|
749
|
-
const snap = controller.getSnapshot();
|
|
750
|
-
expect(snap.view).toBe('qr');
|
|
751
|
-
expect(snap.signIn.phase).toBe('waiting');
|
|
752
|
-
expect(snap.signIn.authorizeCode).toBe('AUTH-CODE');
|
|
753
|
-
controller.cancelSignIn();
|
|
709
|
+
describe('AccountDialogController — startInlineQr (the sign-in entry\'s embedded QR)', () => {
|
|
710
|
+
const pending = (code: string) => ({
|
|
711
|
+
sessionToken: `secret-${code}`,
|
|
712
|
+
authorizeCode: code,
|
|
713
|
+
qrPayload: `oxycommons://approve?v=1&code=${code}`,
|
|
714
|
+
expiresAt: Date.now() + 300_000,
|
|
715
|
+
status: 'pending',
|
|
754
716
|
});
|
|
755
717
|
|
|
756
|
-
it('
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
sessionToken: 'secret-tok',
|
|
761
|
-
authorizeCode: 'AUTH-CODE',
|
|
762
|
-
qrPayload: 'oxycommons://approve?v=1&code=AUTH-CODE',
|
|
763
|
-
expiresAt: Date.now() + 300_000,
|
|
764
|
-
status: 'pending',
|
|
765
|
-
});
|
|
718
|
+
it('starts a QR-only request without leaving the entry — no push, no Commons, no view change', async () => {
|
|
719
|
+
const { controller, oxy } = makeHarness();
|
|
720
|
+
oxy.startCommonsSignIn.mockResolvedValue(pending('AUTH-CODE'));
|
|
721
|
+
controller.setView('signin');
|
|
766
722
|
|
|
767
|
-
await controller.
|
|
723
|
+
await controller.startInlineQr();
|
|
768
724
|
|
|
769
|
-
expect(oxy.startCommonsSignIn).toHaveBeenCalledWith({ clientId: 'oxy_dk_test' });
|
|
770
725
|
const snap = controller.getSnapshot();
|
|
771
|
-
expect(snap.view).toBe('
|
|
726
|
+
expect(snap.view).toBe('signin');
|
|
727
|
+
expect(snap.signIn.inline).toBe(true);
|
|
772
728
|
expect(snap.signIn.phase).toBe('waiting');
|
|
729
|
+
expect(snap.signIn.route).toBe('qr');
|
|
773
730
|
expect(snap.signIn.qrPayload).toBe('oxycommons://approve?v=1&code=AUTH-CODE');
|
|
731
|
+
// A bearer is planted in this harness, so an asked-for request WOULD push.
|
|
732
|
+
expect(oxy.deliverCommonsSignIn).not.toHaveBeenCalled();
|
|
774
733
|
controller.cancelSignIn();
|
|
775
734
|
});
|
|
776
735
|
|
|
777
|
-
it('
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
oxy.startCommonsSignIn.mockRejectedValue(new Error('network down'));
|
|
782
|
-
|
|
783
|
-
await controller.startPasskeyHubSignIn();
|
|
784
|
-
|
|
785
|
-
expect(popup.close).toHaveBeenCalledTimes(1);
|
|
786
|
-
expect(popup.location.href).toBe('');
|
|
787
|
-
expect(controller.getSnapshot().signIn.phase).toBe('error');
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
it('surfaces "cancelled" and closes the popup watcher when the user closes the popup before authorizing', async () => {
|
|
791
|
-
jest.useFakeTimers();
|
|
792
|
-
try {
|
|
793
|
-
const popup = fakePopup();
|
|
794
|
-
const openPopup = jest.fn(() => popup);
|
|
795
|
-
const { controller, oxy } = makeHarness({ openPopup });
|
|
796
|
-
oxy.startCommonsSignIn.mockResolvedValue({
|
|
797
|
-
sessionToken: 'secret-tok',
|
|
798
|
-
authorizeCode: 'AUTH-CODE',
|
|
799
|
-
qrPayload: 'oxycommons://approve?v=1&code=AUTH-CODE',
|
|
800
|
-
expiresAt: Date.now() + 300_000,
|
|
801
|
-
status: 'pending',
|
|
802
|
-
});
|
|
803
|
-
oxy.pollCommonsSignIn.mockResolvedValue({ authorized: false, status: 'pending' });
|
|
804
|
-
|
|
805
|
-
await controller.startPasskeyHubSignIn();
|
|
806
|
-
expect(controller.getSnapshot().signIn.phase).toBe('waiting');
|
|
736
|
+
it('"Try again" repeats the embedded QR', async () => {
|
|
737
|
+
const { controller, oxy } = makeHarness();
|
|
738
|
+
oxy.startCommonsSignIn.mockResolvedValue(pending('AUTH-CODE'));
|
|
739
|
+
await controller.startInlineQr();
|
|
807
740
|
|
|
808
|
-
|
|
809
|
-
await jest.advanceTimersByTimeAsync(1000); // the 1s popup-close watchdog tick
|
|
741
|
+
await controller.retrySignIn();
|
|
810
742
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
// A VOLUNTARY exit — the surface must be able to tell it from a failure.
|
|
815
|
-
expect(snap.signIn.failure).toBe('cancelled');
|
|
816
|
-
} finally {
|
|
817
|
-
jest.useRealTimers();
|
|
818
|
-
}
|
|
743
|
+
expect(oxy.startCommonsSignIn).toHaveBeenCalledTimes(2);
|
|
744
|
+
expect(controller.getSnapshot().signIn.inline).toBe(true);
|
|
745
|
+
controller.cancelSignIn();
|
|
819
746
|
});
|
|
820
747
|
|
|
821
|
-
it('
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
|
|
748
|
+
it('gives way to a sign-in the person chooses, withdrawing its own request', async () => {
|
|
749
|
+
const { controller, oxy } = makeHarness();
|
|
750
|
+
oxy.startCommonsSignIn.mockResolvedValueOnce(pending('INLINE')).mockResolvedValueOnce(pending('ASKED'));
|
|
751
|
+
await controller.startInlineQr();
|
|
825
752
|
|
|
826
|
-
await controller.
|
|
753
|
+
await controller.showQr();
|
|
827
754
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
expect(
|
|
832
|
-
|
|
833
|
-
expect(popup.location.href).toBe('');
|
|
834
|
-
expect(controller.getSnapshot().signIn.phase).toBe('error');
|
|
835
|
-
expect(controller.getSnapshot().signIn.error).toMatch(/clientId/);
|
|
755
|
+
expect(oxy.denyCommonsSignIn).toHaveBeenCalledWith('INLINE');
|
|
756
|
+
const snap = controller.getSnapshot();
|
|
757
|
+
expect(snap.signIn.inline).toBe(false);
|
|
758
|
+
expect(snap.signIn.authorizeCode).toBe('ASKED');
|
|
759
|
+
controller.cancelSignIn();
|
|
836
760
|
});
|
|
837
761
|
});
|
|
838
762
|
|
|
@@ -1384,30 +1308,6 @@ describe('AccountDialogController — automatic delivery selection (#691 phase 5
|
|
|
1384
1308
|
}
|
|
1385
1309
|
});
|
|
1386
1310
|
|
|
1387
|
-
it('does not run automatic delivery for the passkey hub flow (the popup is the primary surface)', async () => {
|
|
1388
|
-
const popup = fakePopup();
|
|
1389
|
-
const oxy = makeOxy();
|
|
1390
|
-
oxy.startCommonsSignIn.mockResolvedValue({ ...DELIVERY_HANDLE, expiresAt: Date.now() + 600_000 });
|
|
1391
|
-
oxy.pollCommonsSignIn.mockResolvedValue({ authorized: false, status: 'pending' });
|
|
1392
|
-
oxy.deliverCommonsSignIn.mockResolvedValue({ delivered: true, targets: 1 });
|
|
1393
|
-
const controller = new AccountDialogController({
|
|
1394
|
-
oxyServices: oxy as unknown as OxyServices,
|
|
1395
|
-
sessionClient: new TestSessionClient(host().host),
|
|
1396
|
-
clientId: 'oxy_dk_test',
|
|
1397
|
-
pollIntervalMs: 1000,
|
|
1398
|
-
platform: 'desktop',
|
|
1399
|
-
openPopup: () => popup,
|
|
1400
|
-
hubBaseUrl: 'https://auth.oxy.so',
|
|
1401
|
-
});
|
|
1402
|
-
|
|
1403
|
-
await controller.startPasskeyHubSignIn();
|
|
1404
|
-
await flush();
|
|
1405
|
-
|
|
1406
|
-
expect(oxy.deliverCommonsSignIn).not.toHaveBeenCalled();
|
|
1407
|
-
expect(controller.getSnapshot().signIn.route).toBe('qr');
|
|
1408
|
-
controller.cancelSignIn();
|
|
1409
|
-
});
|
|
1410
|
-
|
|
1411
1311
|
it('never leaks the secret device-flow token into the snapshot', async () => {
|
|
1412
1312
|
const { controller } = makeDeliveryHarness({ platform: 'desktop' });
|
|
1413
1313
|
|
|
@@ -1429,6 +1329,7 @@ describe('AccountDialogController — automatic delivery selection (#691 phase 5
|
|
|
1429
1329
|
'openedAt',
|
|
1430
1330
|
'progress',
|
|
1431
1331
|
'attempt',
|
|
1332
|
+
'inline',
|
|
1432
1333
|
]);
|
|
1433
1334
|
// Only the PUBLIC handles are exposed.
|
|
1434
1335
|
expect(snap.signIn.authorizeCode).toBe('AUTH-CODE');
|
|
@@ -1684,6 +1585,7 @@ describe('AccountDialogController — cancellation converges (#691 phase 5)', ()
|
|
|
1684
1585
|
openedAt: null,
|
|
1685
1586
|
progress: 'idle',
|
|
1686
1587
|
attempt: expect.any(Number),
|
|
1588
|
+
inline: false,
|
|
1687
1589
|
});
|
|
1688
1590
|
await jest.advanceTimersByTimeAsync(10_000);
|
|
1689
1591
|
expect(oxy.pollCommonsSignIn).not.toHaveBeenCalled();
|
|
@@ -1735,10 +1637,9 @@ describe('AccountDialogController — cancellation converges (#691 phase 5)', ()
|
|
|
1735
1637
|
}
|
|
1736
1638
|
});
|
|
1737
1639
|
|
|
1738
|
-
it('destroy tears down the poll timer
|
|
1640
|
+
it('destroy tears down the poll timer and the auth-session socket', async () => {
|
|
1739
1641
|
jest.useFakeTimers();
|
|
1740
1642
|
try {
|
|
1741
|
-
const popup = fakePopup();
|
|
1742
1643
|
const oxy = makeOxy();
|
|
1743
1644
|
oxy.startCommonsSignIn.mockResolvedValue({ ...DELIVERY_HANDLE, expiresAt: Date.now() + 600_000 });
|
|
1744
1645
|
oxy.pollCommonsSignIn.mockResolvedValue({ authorized: false, status: 'pending' });
|
|
@@ -1764,11 +1665,10 @@ describe('AccountDialogController — cancellation converges (#691 phase 5)', ()
|
|
|
1764
1665
|
clientId: 'oxy_dk_test',
|
|
1765
1666
|
pollIntervalMs: 1000,
|
|
1766
1667
|
platform: 'desktop',
|
|
1767
|
-
openPopup: () => popup,
|
|
1768
1668
|
socketFactory: factory as unknown as SocketIOFactory,
|
|
1769
1669
|
});
|
|
1770
1670
|
|
|
1771
|
-
await controller.
|
|
1671
|
+
await controller.showQr();
|
|
1772
1672
|
await jest.advanceTimersByTimeAsync(0);
|
|
1773
1673
|
expect(controller.getSnapshot().signIn.phase).toBe('waiting');
|
|
1774
1674
|
|
|
@@ -1776,8 +1676,7 @@ describe('AccountDialogController — cancellation converges (#691 phase 5)', ()
|
|
|
1776
1676
|
|
|
1777
1677
|
expect(socket).not.toBeNull();
|
|
1778
1678
|
expect(socket?.disconnected).toBe(true);
|
|
1779
|
-
|
|
1780
|
-
// No poll timer and no popup watchdog survive the teardown.
|
|
1679
|
+
// No poll timer survives the teardown.
|
|
1781
1680
|
await jest.advanceTimersByTimeAsync(30_000);
|
|
1782
1681
|
expect(oxy.pollCommonsSignIn).not.toHaveBeenCalled();
|
|
1783
1682
|
} finally {
|
|
@@ -2305,33 +2204,8 @@ describe('AccountDialogController — an abandoned attempt stays abandoned', ()
|
|
|
2305
2204
|
});
|
|
2306
2205
|
|
|
2307
2206
|
describe('AccountDialogController — "Try again" repeats the user\'s choice', () => {
|
|
2308
|
-
it('
|
|
2309
|
-
|
|
2310
|
-
let popup = fakePopup();
|
|
2311
|
-
const openPopup = jest.fn(() => {
|
|
2312
|
-
popup = fakePopup();
|
|
2313
|
-
return popup;
|
|
2314
|
-
});
|
|
2315
|
-
const { controller, oxy } = makeHarness({ openPopup });
|
|
2316
|
-
oxy.startCommonsSignIn.mockRejectedValue(new Error('boom'));
|
|
2317
|
-
|
|
2318
|
-
await controller.startPasskeyHubSignIn();
|
|
2319
|
-
expect(controller.getSnapshot().signIn.phase).toBe('error');
|
|
2320
|
-
|
|
2321
|
-
oxy.startCommonsSignIn.mockResolvedValue({ ...DELIVERY_HANDLE, expiresAt: Date.now() + 600_000 });
|
|
2322
|
-
const retry = controller.retrySignIn();
|
|
2323
|
-
// Opened synchronously, inside the press — before any await.
|
|
2324
|
-
expect(openPopup).toHaveBeenCalledTimes(2);
|
|
2325
|
-
await retry;
|
|
2326
|
-
|
|
2327
|
-
expect(oxy.deliverCommonsSignIn).not.toHaveBeenCalled();
|
|
2328
|
-
expect(popup.location.href).toContain('/continue?code=AUTH-CODE');
|
|
2329
|
-
controller.cancelSignIn();
|
|
2330
|
-
});
|
|
2331
|
-
|
|
2332
|
-
it('retries "Sign in with Oxy" (never the hub) after a failed Oxy attempt', async () => {
|
|
2333
|
-
const openPopup = jest.fn(() => fakePopup());
|
|
2334
|
-
const { controller, oxy } = makeHarness({ openPopup });
|
|
2207
|
+
it('retries "Sign in with Oxy" after a failed Oxy attempt', async () => {
|
|
2208
|
+
const { controller, oxy } = makeHarness();
|
|
2335
2209
|
oxy.startCommonsSignIn.mockRejectedValueOnce(new Error('boom'));
|
|
2336
2210
|
|
|
2337
2211
|
await controller.signInWithOxy();
|
|
@@ -2340,27 +2214,11 @@ describe('AccountDialogController — "Try again" repeats the user\'s choice', (
|
|
|
2340
2214
|
oxy.startCommonsSignIn.mockResolvedValue({ ...DELIVERY_HANDLE, expiresAt: Date.now() + 600_000 });
|
|
2341
2215
|
await controller.retrySignIn();
|
|
2342
2216
|
|
|
2343
|
-
expect(openPopup).not.toHaveBeenCalled();
|
|
2344
2217
|
expect(oxy.signInWithSharedIdentity).toHaveBeenCalledTimes(2);
|
|
2345
2218
|
expect(controller.getSnapshot().signIn.phase).toBe('waiting');
|
|
2346
2219
|
controller.cancelSignIn();
|
|
2347
2220
|
});
|
|
2348
2221
|
|
|
2349
|
-
it('closes a hub popup that was opened for an attempt the user cancelled while its request was created', async () => {
|
|
2350
|
-
const popup = fakePopup();
|
|
2351
|
-
const { controller, oxy } = makeHarness({ openPopup: () => popup });
|
|
2352
|
-
const created = deferred<unknown>();
|
|
2353
|
-
oxy.startCommonsSignIn.mockReturnValue(created.promise);
|
|
2354
|
-
|
|
2355
|
-
const running = controller.startPasskeyHubSignIn();
|
|
2356
|
-
controller.cancelSignIn();
|
|
2357
|
-
// Closed at once, not left blank until the slow request returns.
|
|
2358
|
-
expect(popup.close).toHaveBeenCalled();
|
|
2359
|
-
|
|
2360
|
-
created.resolve({ ...DELIVERY_HANDLE, expiresAt: Date.now() + 600_000 });
|
|
2361
|
-
await running;
|
|
2362
|
-
expect(popup.location.href).toBe('');
|
|
2363
|
-
});
|
|
2364
2222
|
});
|
|
2365
2223
|
|
|
2366
2224
|
describe('AccountDialogController — device mutations report their own outcome', () => {
|