@inrupt/solid-client-authn-browser 1.13.4 → 1.15.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.
Files changed (38) hide show
  1. package/dist/ClientAuthentication.d.ts +1 -1
  2. package/dist/ClientAuthentication.js +2 -1
  3. package/dist/ClientAuthentication.js.map +1 -1
  4. package/dist/Session.d.ts +5 -3
  5. package/dist/Session.js +21 -17
  6. package/dist/Session.js.map +1 -1
  7. package/dist/defaultSession.d.ts +1 -0
  8. package/dist/defaultSession.js +5 -1
  9. package/dist/defaultSession.js.map +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +2 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/login/oidc/IssuerConfigFetcher.js +2 -1
  14. package/dist/login/oidc/IssuerConfigFetcher.js.map +1 -1
  15. package/dist/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.d.ts +1 -0
  16. package/dist/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.js +2 -1
  17. package/dist/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.js.map +1 -1
  18. package/dist/sessionInfo/SessionInfoManager.d.ts +1 -0
  19. package/dist/sessionInfo/SessionInfoManager.js +2 -1
  20. package/dist/sessionInfo/SessionInfoManager.js.map +1 -1
  21. package/dist/solid-client-authn.bundle.js +1 -1
  22. package/package.json +5 -7
  23. package/src/ClientAuthentication.spec.ts +15 -8
  24. package/src/ClientAuthentication.ts +2 -2
  25. package/src/Session.spec.ts +255 -119
  26. package/src/Session.ts +44 -18
  27. package/src/defaultSession.spec.ts +28 -19
  28. package/src/defaultSession.ts +15 -1
  29. package/src/index.ts +1 -0
  30. package/src/login/oidc/ClientRegistrar.spec.ts +1 -1
  31. package/src/login/oidc/IssuerConfigFetcher.spec.ts +60 -40
  32. package/src/login/oidc/IssuerConfigFetcher.ts +2 -1
  33. package/src/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.spec.ts +27 -22
  34. package/src/login/oidc/incomingRedirectHandler/AuthCodeRedirectHandler.ts +2 -0
  35. package/src/login/oidc/incomingRedirectHandler/ErrorOidcHandler.spec.ts +12 -3
  36. package/src/login/oidc/incomingRedirectHandler/FallbackRedirectHandler.spec.ts +12 -1
  37. package/src/sessionInfo/SessionInfoManager.ts +1 -0
  38. package/tsconfig.json +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inrupt/solid-client-authn-browser",
3
- "version": "1.13.4",
3
+ "version": "1.15.0",
4
4
  "license": "MIT",
5
5
  "types": "dist/index",
6
6
  "browser": "dist/index.js",
@@ -25,8 +25,9 @@
25
25
  "cross-fetch": "^3.1.5"
26
26
  },
27
27
  "dependencies": {
28
- "@inrupt/oidc-client-ext": "^1.13.4",
29
- "@inrupt/solid-client-authn-core": "^1.13.4",
28
+ "@inrupt/oidc-client-ext": "^1.15.0",
29
+ "@inrupt/solid-client-authn-core": "^1.15.0",
30
+ "@inrupt/universal-fetch": "^1.0.1",
30
31
  "@types/lodash.clonedeep": "^4.5.6",
31
32
  "@types/node": "^18.0.3",
32
33
  "@types/uuid": "^9.0.1",
@@ -38,8 +39,5 @@
38
39
  "publishConfig": {
39
40
  "access": "public"
40
41
  },
41
- "engines": {
42
- "node": "^14.0.0 || ^16.0.0"
43
- },
44
- "gitHead": "ab437bbfb613f4f64b82b17e3a38177998a1762a"
42
+ "gitHead": "e8f87a62bf739970d3fb5bc3fb48e587871f3719"
45
43
  }
@@ -36,6 +36,9 @@ import {
36
36
  mockHandleIncomingRedirect,
37
37
  } from "@inrupt/solid-client-authn-core/mocks";
38
38
 
39
+ import { fetch } from "@inrupt/universal-fetch";
40
+ import * as UniversalFetch from "@inrupt/universal-fetch";
41
+
39
42
  import { mockLoginHandler } from "./login/__mocks__/LoginHandler";
40
43
  import { mockLogoutHandler } from "./logout/__mocks__/LogoutHandler";
41
44
  import {
@@ -45,6 +48,16 @@ import {
45
48
  import ClientAuthentication from "./ClientAuthentication";
46
49
  import { mockDefaultIssuerConfigFetcher } from "./login/oidc/__mocks__/IssuerConfigFetcher";
47
50
 
51
+ jest.mock("@inrupt/universal-fetch", () => {
52
+ const fetchModule = jest.requireActual(
53
+ "@inrupt/universal-fetch"
54
+ ) as typeof UniversalFetch;
55
+ return {
56
+ ...fetchModule,
57
+ fetch: jest.fn<typeof fetch>(),
58
+ };
59
+ });
60
+
48
61
  jest.mock("@inrupt/solid-client-authn-core", () => {
49
62
  const actualCoreModule = jest.requireActual(
50
63
  "@inrupt/solid-client-authn-core"
@@ -284,13 +297,9 @@ describe("ClientAuthentication", () => {
284
297
 
285
298
  describe("fetch", () => {
286
299
  it("calls fetch", async () => {
287
- window.fetch = jest.fn<typeof fetch>();
288
300
  const clientAuthn = getClientAuthentication();
289
301
  await clientAuthn.fetch("https://html5zombo.com");
290
- expect(window.fetch).toHaveBeenCalledWith(
291
- "https://html5zombo.com",
292
- undefined
293
- );
302
+ expect(fetch).toHaveBeenCalledWith("https://html5zombo.com", undefined);
294
303
  });
295
304
  });
296
305
 
@@ -299,7 +308,6 @@ describe("ClientAuthentication", () => {
299
308
  // TODO: add tests for events & errors
300
309
 
301
310
  it("reverts back to un-authenticated fetch on logout", async () => {
302
- window.fetch = jest.fn<typeof fetch>();
303
311
  // eslint-disable-next-line no-restricted-globals
304
312
  history.replaceState = jest.fn();
305
313
  const clientAuthn = getClientAuthentication();
@@ -314,13 +322,12 @@ describe("ClientAuthentication", () => {
314
322
  expect(clientAuthn.fetch).not.toBe(unauthFetch);
315
323
 
316
324
  await clientAuthn.logout("mySession");
317
- const spyFetch = jest.spyOn(window, "fetch");
318
325
  await clientAuthn.fetch("https://example.com", {
319
326
  credentials: "omit",
320
327
  });
321
328
  // Calling logout should revert back to our un-authenticated fetch.
322
329
  expect(clientAuthn.fetch).toBe(unauthFetch);
323
- expect(spyFetch).toHaveBeenCalledWith("https://example.com", {
330
+ expect(fetch).toHaveBeenCalledWith("https://example.com", {
324
331
  credentials: "omit",
325
332
  });
326
333
  });
@@ -36,14 +36,14 @@ import {
36
36
  EVENTS,
37
37
  isValidRedirectUrl,
38
38
  } from "@inrupt/solid-client-authn-core";
39
+ import { fetch } from "@inrupt/universal-fetch";
39
40
  import { removeOidcQueryParam } from "@inrupt/oidc-client-ext";
40
41
  import { EventEmitter } from "events";
41
42
 
42
43
  // By only referring to `window` at runtime, apps that do server-side rendering
43
44
  // won't run into errors when rendering code that instantiates a
44
45
  // ClientAuthentication:
45
- const globalFetch: typeof window.fetch = (request, init) =>
46
- window.fetch(request, init);
46
+ const globalFetch: typeof fetch = (request, init) => fetch(request, init);
47
47
 
48
48
  /**
49
49
  * @hidden
@@ -27,15 +27,27 @@ import {
27
27
  USER_SESSION_PREFIX,
28
28
  } from "@inrupt/solid-client-authn-core";
29
29
  import { mockStorage } from "@inrupt/solid-client-authn-core/mocks";
30
+ import { fetch } from "@inrupt/universal-fetch";
31
+ import * as UniversalFetch from "@inrupt/universal-fetch";
30
32
  import { mockClientAuthentication } from "./__mocks__/ClientAuthentication";
31
33
  import { Session } from "./Session";
32
34
  import { LocalStorageMock } from "./storage/__mocks__/LocalStorage";
33
35
  import { mockSessionInfoManager } from "./sessionInfo/__mocks__/SessionInfoManager";
34
36
  import { KEY_CURRENT_SESSION, KEY_CURRENT_URL } from "./constant";
35
- import type ClientAuthentication from "./ClientAuthentication";
37
+ import ClientAuthentication from "./ClientAuthentication";
36
38
 
37
39
  /* eslint-disable @typescript-eslint/ban-ts-comment */
38
40
 
41
+ jest.mock("@inrupt/universal-fetch", () => {
42
+ const fetchModule = jest.requireActual(
43
+ "@inrupt/universal-fetch"
44
+ ) as typeof UniversalFetch;
45
+ return {
46
+ ...fetchModule,
47
+ fetch: jest.fn<typeof fetch>(),
48
+ };
49
+ });
50
+
39
51
  const mockLocalStorage = (stored: Record<string, string>) => {
40
52
  Object.defineProperty(window, "localStorage", {
41
53
  value: new LocalStorageMock(stored),
@@ -202,7 +214,6 @@ describe("Session", () => {
202
214
 
203
215
  describe("fetch", () => {
204
216
  it("wraps up ClientAuthentication fetch if logged in", async () => {
205
- window.fetch = jest.fn<typeof fetch>();
206
217
  const clientAuthentication = mockClientAuthentication();
207
218
  const clientAuthnFetch = jest.spyOn(clientAuthentication, "fetch");
208
219
  const mySession = new Session({ clientAuthentication });
@@ -212,7 +223,6 @@ describe("Session", () => {
212
223
  });
213
224
 
214
225
  it("preserves a binding to its Session instance", async () => {
215
- window.fetch = jest.fn<typeof fetch>();
216
226
  const clientAuthentication = mockClientAuthentication();
217
227
  const clientAuthnFetch = jest.spyOn(clientAuthentication, "fetch");
218
228
  const mySession = new Session({ clientAuthentication });
@@ -225,12 +235,10 @@ describe("Session", () => {
225
235
  });
226
236
 
227
237
  it("does not rebind window.fetch if logged out", async () => {
228
- window.fetch = jest.fn<typeof fetch>();
229
238
  const clientAuthentication = mockClientAuthentication();
230
239
  const mySession = new Session({ clientAuthentication });
231
240
  await mySession.fetch("https://some.url/");
232
- expect(window.fetch).toHaveBeenCalled();
233
- expect((window.fetch as jest.Mock).mock.instances).toEqual([window]);
241
+ expect(fetch).toHaveBeenCalled();
234
242
  });
235
243
  });
236
244
 
@@ -408,19 +416,6 @@ describe("Session", () => {
408
416
  });
409
417
  });
410
418
 
411
- describe("onError", () => {
412
- it("calls the registered callback on error", async () => {
413
- const onErrorCallback = jest.fn();
414
- const mySession = new Session();
415
- mySession.onError(onErrorCallback);
416
- mySession.emit(EVENTS.ERROR, "error", "error_description");
417
- expect(onErrorCallback).toHaveBeenCalledWith(
418
- "error",
419
- "error_description"
420
- );
421
- });
422
- });
423
-
424
419
  describe("silent authentication", () => {
425
420
  it("does nothing if no previous session is available", async () => {
426
421
  mockLocalStorage({});
@@ -777,130 +772,271 @@ describe("Session", () => {
777
772
  });
778
773
  });
779
774
 
780
- describe("onLogin", () => {
781
- it("calls the registered callback on login", async () => {
782
- const myCallback = jest.fn();
783
- const clientAuthentication = mockClientAuthentication();
784
- clientAuthentication.handleIncomingRedirect = (
785
- jest.fn() as any
786
- ).mockResolvedValue({
787
- isLoggedIn: true,
788
- sessionId: "a session ID",
789
- webId: "https://some.webid#them",
775
+ describe("legacy events handlers", () => {
776
+ describe("onError", () => {
777
+ it("calls the registered callback on error", async () => {
778
+ const onErrorCallback = jest.fn();
779
+ const mySession = new Session();
780
+ mySession.onError(onErrorCallback);
781
+ mySession.emit(EVENTS.ERROR, "error", "error_description");
782
+ expect(onErrorCallback).toHaveBeenCalledWith(
783
+ "error",
784
+ "error_description"
785
+ );
790
786
  });
791
- mockLocalStorage({});
792
- const mySession = new Session({ clientAuthentication });
793
- mySession.onLogin(myCallback);
794
- await mySession.handleIncomingRedirect("https://some.url");
795
- expect(myCallback).toHaveBeenCalled();
796
787
  });
797
788
 
798
- it("does not call the registered callback if login isn't successful", async () => {
799
- const failCallback = (): void => {
800
- throw new Error(
801
- "Should *NOT* call callback - this means test has failed!"
789
+ describe("onLogin", () => {
790
+ it("calls the registered callback on login", async () => {
791
+ const myCallback = jest.fn();
792
+ const clientAuthentication = mockClientAuthentication();
793
+ clientAuthentication.handleIncomingRedirect = (
794
+ jest.fn() as any
795
+ ).mockResolvedValue({
796
+ isLoggedIn: true,
797
+ sessionId: "a session ID",
798
+ webId: "https://some.webid#them",
799
+ });
800
+ mockLocalStorage({});
801
+ const mySession = new Session({ clientAuthentication });
802
+ mySession.onLogin(myCallback);
803
+ await mySession.handleIncomingRedirect("https://some.url");
804
+ expect(myCallback).toHaveBeenCalled();
805
+ });
806
+
807
+ it("does not call the registered callback if login isn't successful", async () => {
808
+ const failCallback = (): void => {
809
+ throw new Error(
810
+ "Should *NOT* call callback - this means test has failed!"
811
+ );
812
+ };
813
+ const clientAuthentication = mockClientAuthentication();
814
+ clientAuthentication.handleIncomingRedirect = jest.fn(
815
+ async (_url: string) => {
816
+ return {
817
+ isLoggedIn: false,
818
+ sessionId: "a session ID",
819
+ webId: "https://some.webid#them",
820
+ };
821
+ }
802
822
  );
803
- };
804
- const clientAuthentication = mockClientAuthentication();
805
- clientAuthentication.handleIncomingRedirect = jest.fn(
806
- async (_url: string) => {
807
- return {
808
- isLoggedIn: false,
809
- sessionId: "a session ID",
810
- webId: "https://some.webid#them",
811
- };
812
- }
813
- );
814
- const mySession = new Session({ clientAuthentication });
815
- mySession.onLogin(failCallback);
816
- await expect(
817
- mySession.handleIncomingRedirect("https://some.url")
818
- ).resolves.not.toThrow();
823
+ const mySession = new Session({ clientAuthentication });
824
+ mySession.onLogin(failCallback);
825
+ await expect(
826
+ mySession.handleIncomingRedirect("https://some.url")
827
+ ).resolves.not.toThrow();
828
+ });
829
+
830
+ it("sets the appropriate information before calling the callback", async () => {
831
+ const clientAuthentication = mockClientAuthentication();
832
+ clientAuthentication.handleIncomingRedirect = jest.fn(
833
+ async (_url: string) => {
834
+ return {
835
+ isLoggedIn: true,
836
+ sessionId: "a session ID",
837
+ webId: "https://some.webid#them",
838
+ };
839
+ }
840
+ );
841
+ const mySession = new Session({ clientAuthentication });
842
+ const myCallback = jest.fn((): void => {
843
+ expect(mySession.info.webId).toBe("https://some.webid#them");
844
+ });
845
+ mySession.onLogin(myCallback);
846
+ await mySession.handleIncomingRedirect("https://some.url");
847
+ expect(myCallback).toHaveBeenCalled();
848
+ // Verify that the conditional assertion has been called
849
+ expect.assertions(2);
850
+ });
819
851
  });
820
852
 
821
- it("sets the appropriate information before calling the callback", async () => {
822
- const clientAuthentication = mockClientAuthentication();
823
- clientAuthentication.handleIncomingRedirect = jest.fn(
824
- async (_url: string) => {
825
- return {
826
- isLoggedIn: true,
827
- sessionId: "a session ID",
828
- webId: "https://some.webid#them",
829
- };
830
- }
831
- );
832
- const mySession = new Session({ clientAuthentication });
833
- const myCallback = jest.fn((): void => {
834
- expect(mySession.info.webId).toBe("https://some.webid#them");
853
+ describe("onLogout", () => {
854
+ it("calls the registered callback on logout", async () => {
855
+ const myCallback = jest.fn();
856
+ const mySession = new Session({
857
+ clientAuthentication: mockClientAuthentication(),
858
+ });
859
+
860
+ mySession.onLogout(myCallback);
861
+ await mySession.logout();
862
+ expect(myCallback).toHaveBeenCalled();
835
863
  });
836
- mySession.onLogin(myCallback);
837
- await mySession.handleIncomingRedirect("https://some.url");
838
- expect(myCallback).toHaveBeenCalled();
839
- // Verify that the conditional assertion has been called
840
- expect.assertions(2);
841
864
  });
842
- });
843
865
 
844
- describe("onLogout", () => {
845
- it("calls the registered callback on logout", async () => {
846
- const myCallback = jest.fn();
847
- const mySession = new Session({
848
- clientAuthentication: mockClientAuthentication(),
866
+ describe("onSessionRestore", () => {
867
+ it("calls the registered callback on session restore", async () => {
868
+ // Set our window's location to our test value.
869
+ const defaultLocation = "https://coolSite.com/resource";
870
+ const currentLocation = "https://coolSite.com/redirect";
871
+
872
+ // This pretends we have previously triggered silent authentication and stored
873
+ // the location.
874
+ mockLocalStorage({
875
+ [KEY_CURRENT_URL]: defaultLocation,
876
+ });
877
+ // This acts as the URL the user has been redirected to.
878
+ mockLocation(currentLocation);
879
+ // This pretends the login is successful.
880
+ const clientAuthentication = mockClientAuthentication();
881
+ clientAuthentication.handleIncomingRedirect = (
882
+ jest.fn() as any
883
+ ).mockResolvedValue({
884
+ isLoggedIn: true,
885
+ sessionId: "a session ID",
886
+ webId: "https://some.webid#them",
887
+ });
888
+
889
+ const mySession = new Session({
890
+ clientAuthentication,
891
+ });
892
+ const myCallback = (urlBeforeRestore: string): void => {
893
+ expect(urlBeforeRestore).toEqual(defaultLocation);
894
+ };
895
+
896
+ mySession.onSessionRestore(myCallback);
897
+ await mySession.handleIncomingRedirect(currentLocation);
898
+
899
+ // This verifies that the callback has been called
900
+ expect.assertions(1);
849
901
  });
902
+ });
850
903
 
851
- mySession.onLogout(myCallback);
852
- await mySession.logout();
853
- expect(myCallback).toHaveBeenCalled();
904
+ describe("onSessionExpiration", () => {
905
+ it("calls the provided callback when receiving the appropriate event", async () => {
906
+ const myCallback = jest.fn();
907
+ const mySession = new Session({
908
+ clientAuthentication: mockClientAuthentication(),
909
+ });
910
+ mySession.onSessionExpiration(myCallback);
911
+ mySession.emit(EVENTS.SESSION_EXPIRED);
912
+ expect(myCallback).toHaveBeenCalled();
913
+ });
854
914
  });
855
915
  });
856
916
 
857
- describe("onSessionRestore", () => {
858
- it("calls the registered callback on session restore", async () => {
859
- // Set our window's location to our test value.
860
- const defaultLocation = "https://coolSite.com/resource";
861
- const currentLocation = "https://coolSite.com/redirect";
917
+ describe("events.on", () => {
918
+ describe("login", () => {
919
+ it("calls the registered callback on login", async () => {
920
+ const myCallback = jest.fn();
921
+ const clientAuthentication = mockClientAuthentication();
922
+ clientAuthentication.handleIncomingRedirect = jest
923
+ .fn<ClientAuthentication["handleIncomingRedirect"]>()
924
+ .mockResolvedValue({
925
+ isLoggedIn: true,
926
+ sessionId: "a session ID",
927
+ webId: "https://some.webid#them",
928
+ });
929
+ mockLocalStorage({});
930
+ const mySession = new Session({ clientAuthentication });
931
+ mySession.events.on(EVENTS.LOGIN, myCallback);
932
+ await mySession.handleIncomingRedirect("https://some.url");
933
+ expect(myCallback).toHaveBeenCalled();
934
+ });
862
935
 
863
- // This pretends we have previously triggered silent authentication and stored
864
- // the location.
865
- mockLocalStorage({
866
- [KEY_CURRENT_URL]: defaultLocation,
936
+ it("does not call the registered callback if login isn't successful", async () => {
937
+ const myCallback = jest.fn();
938
+ const clientAuthentication = mockClientAuthentication();
939
+ clientAuthentication.handleIncomingRedirect = jest
940
+ .fn<ClientAuthentication["handleIncomingRedirect"]>()
941
+ .mockResolvedValue({
942
+ isLoggedIn: true,
943
+ sessionId: "a session ID",
944
+ webId: "https://some.webid#them",
945
+ });
946
+ const mySession = new Session({ clientAuthentication });
947
+ mySession.events.on(EVENTS.LOGIN, myCallback);
948
+ expect(myCallback).not.toHaveBeenCalled();
867
949
  });
868
- // This acts as the URL the user has been redirected to.
869
- mockLocation(currentLocation);
870
- // This pretends the login is successful.
871
- const clientAuthentication = mockClientAuthentication();
872
- clientAuthentication.handleIncomingRedirect = (
873
- jest.fn() as any
874
- ).mockResolvedValue({
875
- isLoggedIn: true,
876
- sessionId: "a session ID",
877
- webId: "https://some.webid#them",
950
+
951
+ it("sets the appropriate information before calling the callback", async () => {
952
+ const clientAuthentication = mockClientAuthentication();
953
+ clientAuthentication.handleIncomingRedirect = jest
954
+ .fn<ClientAuthentication["handleIncomingRedirect"]>()
955
+ .mockResolvedValue({
956
+ isLoggedIn: true,
957
+ sessionId: "a session ID",
958
+ webId: "https://some.webid#them",
959
+ });
960
+ const mySession = new Session({ clientAuthentication });
961
+ const myCallback = jest.fn((): void => {
962
+ expect(mySession.info.webId).toBe("https://some.webid#them");
963
+ });
964
+ mySession.events.on(EVENTS.LOGIN, myCallback);
965
+ await mySession.handleIncomingRedirect("https://some.url");
966
+ expect(myCallback).toHaveBeenCalled();
967
+ // Verify that the conditional assertion has been called
968
+ expect.assertions(2);
878
969
  });
970
+ });
879
971
 
880
- const mySession = new Session({
881
- clientAuthentication,
972
+ describe("logout", () => {
973
+ it("calls the registered callback on logout", async () => {
974
+ const myCallback = jest.fn();
975
+ const mySession = new Session({
976
+ clientAuthentication: mockClientAuthentication(),
977
+ });
978
+
979
+ mySession.events.on(EVENTS.LOGOUT, myCallback);
980
+ await mySession.logout();
981
+ expect(myCallback).toHaveBeenCalled();
882
982
  });
883
- const myCallback = (urlBeforeRestore: string): void => {
884
- expect(urlBeforeRestore).toEqual(defaultLocation);
885
- };
983
+ });
886
984
 
887
- mySession.onSessionRestore(myCallback);
888
- await mySession.handleIncomingRedirect(currentLocation);
985
+ describe("sessionRestore", () => {
986
+ it("calls the registered callback on session restore", async () => {
987
+ // Set our window's location to our test value.
988
+ const defaultLocation = "https://coolSite.com/resource";
989
+ const currentLocation = "https://coolSite.com/redirect";
889
990
 
890
- // This verifies that the callback has been called
891
- expect.assertions(1);
991
+ // This pretends we have previously triggered silent authentication and stored
992
+ // the location.
993
+ mockLocalStorage({
994
+ [KEY_CURRENT_URL]: defaultLocation,
995
+ });
996
+ // This acts as the URL the user has been redirected to.
997
+ mockLocation(currentLocation);
998
+ // This pretends the login is successful.
999
+ const clientAuthentication = mockClientAuthentication();
1000
+ clientAuthentication.handleIncomingRedirect = jest
1001
+ .fn<ClientAuthentication["handleIncomingRedirect"]>()
1002
+ .mockResolvedValue({
1003
+ isLoggedIn: true,
1004
+ sessionId: "a session ID",
1005
+ webId: "https://some.webid#them",
1006
+ });
1007
+
1008
+ const mySession = new Session({
1009
+ clientAuthentication,
1010
+ });
1011
+ const myCallback = (urlBeforeRestore: string): void => {
1012
+ expect(urlBeforeRestore).toEqual(defaultLocation);
1013
+ };
1014
+
1015
+ mySession.events.on(EVENTS.SESSION_RESTORED, myCallback);
1016
+ await mySession.handleIncomingRedirect(currentLocation);
1017
+
1018
+ // This verifies that the callback has been called
1019
+ expect.assertions(1);
1020
+ });
892
1021
  });
893
1022
  });
894
1023
 
895
- describe("onSessionExpiration", () => {
896
- it("calls the provided callback when receiving the appropriate event", async () => {
897
- const myCallback = jest.fn();
898
- const mySession = new Session({
899
- clientAuthentication: mockClientAuthentication(),
900
- });
901
- mySession.onSessionExpiration(myCallback);
902
- mySession.emit(EVENTS.SESSION_EXPIRED);
903
- expect(myCallback).toHaveBeenCalled();
1024
+ describe("proxies events to the session", () => {
1025
+ // This describe block is only required as long as Session extends the EventEmitter
1026
+ // class.
1027
+ it("proxies the EventEmitter calls from events to the session object", () => {
1028
+ const mySession = new Session();
1029
+ const spiedOn = jest.spyOn(mySession, "on");
1030
+ mySession.events.on("login", jest.fn());
1031
+ expect(spiedOn).toHaveBeenCalled();
1032
+ });
1033
+
1034
+ it("throws on calls from events which aren't part of the EventEmitter interface", () => {
1035
+ const mySession = new Session();
1036
+ // @ts-expect-error onLogin is a function on Session, and not SessionEventEmitter
1037
+ expect(() => mySession.events.onLogin(jest.fn())).toThrow(
1038
+ "[onLogin] is not supported"
1039
+ );
904
1040
  });
905
1041
  });
906
1042
  });