@strivacity/sdk-angular 4.0.0-beta.0 → 4.0.0-beta.2

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.
@@ -108,7 +108,7 @@ describe('StrivacityNativeLoginService', () => {
108
108
  });
109
109
 
110
110
  test('calls onLogin and leaves the tracked state untouched when the sdk already has a session', async () => {
111
- const session = { access_token: 'access-token' } as unknown as SessionData;
111
+ const session = { access_token: 'access-token', expires_at: Math.floor(Date.now() / 1000) + 3600 } as unknown as SessionData;
112
112
  const flow = createMockFlow<NativeFlow>({ session });
113
113
  vi.mocked(flow.startSession).mockResolvedValue({ screen: 'identifier' });
114
114
  const onLogin = vi.fn();
@@ -149,19 +149,17 @@ describe('StrivacityNativeLoginService', () => {
149
149
  expect(login.loading()).toBe(true);
150
150
  });
151
151
 
152
- test('propagates a rejection from sdk.init() as-is, since only the startSession() call is guarded by the try/catch', async () => {
153
- // the AbortError short-circuit in start()'s own catch guards `this.startSession(...)`, not `await this.sdk.init()`
154
- // above it - startSession() also swallows every error itself (including AbortError) and reports it through onError,
155
- // so that branch is unreachable via a mocked flow; a rejecting init() is the one thing genuinely uncaught here.
152
+ test('reports a rejection from sdk.init() to onError and stops loading, without starting a session', async () => {
156
153
  const flow = createMockFlow<NativeFlow>();
157
- const abortError = new DOMException('The operation was aborted', 'AbortError');
158
- vi.mocked(flow.init).mockRejectedValue(abortError);
154
+ const error = new Error('init failed');
155
+ vi.mocked(flow.init).mockRejectedValue(error);
159
156
  const onError = vi.fn();
160
157
  const login = configure(flow);
161
158
 
162
- await expect(login.start({ onError })).rejects.toBe(abortError);
159
+ await login.start({ onError });
163
160
 
164
- expect(onError).not.toHaveBeenCalled();
161
+ expect(onError).toHaveBeenCalledWith(error);
162
+ expect(login.loading()).toBe(false);
165
163
  expect(flow.startSession).not.toHaveBeenCalled();
166
164
  });
167
165
  });
@@ -293,19 +291,17 @@ describe('StrivacityNativeLoginService', () => {
293
291
  expect(flow.logging!.debug).toHaveBeenCalledWith('Triggering close');
294
292
  });
295
293
 
296
- test('aborts the in-flight abort controller when the owning injector is destroyed', () => {
294
+ test('stops tracking the flow state when the owning injector is destroyed', () => {
297
295
  const flow = createMockFlow<NativeFlow>();
298
296
  vi.mocked(initFlow).mockReturnValue(flow);
299
297
  TestBed.configureTestingModule({ providers: [{ provide: STRIVACITY_SDK, useValue: createOptions({ mode: 'native' }) }, StrivacityAuthService] });
300
298
 
301
- const abortSpy = vi.spyOn(AbortController.prototype, 'abort');
302
-
303
299
  // both services must live on the component's own injector for fixture.destroy() to fire their DestroyRef callbacks
304
- const { destroy } = mountWithProviders([StrivacityAuthService, StrivacityNativeLoginService], () => inject(StrivacityNativeLoginService));
300
+ const { value: login, destroy } = mountWithProviders([StrivacityAuthService, StrivacityNativeLoginService], () => inject(StrivacityNativeLoginService));
305
301
 
306
302
  destroy();
303
+ login.setFormValue('form1', 'email', 'a@b.c');
307
304
 
308
- expect(abortSpy).toHaveBeenCalledTimes(1);
309
- abortSpy.mockRestore();
305
+ expect(login.forms()).toEqual({});
310
306
  });
311
307
  });
@@ -101,7 +101,7 @@ describe('createServerSDK', () => {
101
101
  });
102
102
 
103
103
  test.each([
104
- ['getSession', [{} as never], null],
104
+ ['getSession', [{} as never, { autoRefresh: false }], null],
105
105
  ['updateSession', [{ access_token: 'a' } as never, {} as never], undefined],
106
106
  ['refreshSession', [{} as never], { access_token: 'refreshed' }],
107
107
  ['revokeSession', [{} as never], undefined],
@@ -1,12 +1,13 @@
1
1
  import type { AngularServerSDK } from '../../../src/server/types';
2
- import { ApplicationInitStatus, REQUEST, TransferState } from '@angular/core';
2
+ import { ApplicationInitStatus, REQUEST, RESPONSE_INIT, TransferState } from '@angular/core';
3
3
  import { TestBed } from '@angular/core/testing';
4
4
  import { describe, test, expect, vi } from 'vitest';
5
+ import { pushSetCookie } from '@strivacity/sdk-core/utils';
5
6
  import { SESSION_TRANSFER_KEY, provideStrivacityServerSession } from '../../../src/server/session';
6
7
 
7
- function configure(request: Request | undefined, serverSdk: AngularServerSDK | undefined) {
8
+ function configure(request: Request | undefined, serverSdk: AngularServerSDK | undefined, responseInit?: ResponseInit) {
8
9
  TestBed.configureTestingModule({
9
- providers: [{ provide: REQUEST, useValue: request }, provideStrivacityServerSession(serverSdk)],
10
+ providers: [{ provide: REQUEST, useValue: request }, { provide: RESPONSE_INIT, useValue: responseInit ?? null }, provideStrivacityServerSession(serverSdk)],
10
11
  });
11
12
 
12
13
  return TestBed.inject(ApplicationInitStatus).donePromise;
@@ -18,17 +19,61 @@ describe('provideStrivacityServerSession', () => {
18
19
  const session = { access_token: 'access-token' };
19
20
  const getSession = vi.fn().mockResolvedValue(session);
20
21
 
21
- await configure(request, { getSession } as unknown as AngularServerSDK);
22
+ await configure(request, { getSession: getSession } as unknown as AngularServerSDK);
22
23
 
23
24
  expect(getSession).toHaveBeenCalledWith(request);
24
25
  expect(TestBed.inject(TransferState).get(SESSION_TRANSFER_KEY, undefined)).toEqual(session);
25
26
  });
26
27
 
28
+ test('never transfers the refresh token or the ID token to the client', async () => {
29
+ const request = new Request('https://brandtegrity.io');
30
+ const session = { access_token: 'access-token', refresh_token: 'refresh-token', id_token: 'id-token', expires_at: 9999999999, claims: { sub: 'user' } };
31
+ const getSession = vi.fn().mockResolvedValue(session);
32
+
33
+ await configure(request, { getSession: getSession } as unknown as AngularServerSDK);
34
+
35
+ expect(TestBed.inject(TransferState).get(SESSION_TRANSFER_KEY, undefined)).toEqual({
36
+ access_token: 'access-token',
37
+ expires_at: 9999999999,
38
+ claims: { sub: 'user' },
39
+ });
40
+ });
41
+
42
+ test('refreshes a near-expiry session on the server and writes the rotated cookie to the rendered response', async () => {
43
+ const request = new Request('https://brandtegrity.io/profile');
44
+ const rotated = { access_token: 'new', refresh_token: 'refresh-2', id_token: 'id-2', expires_at: 9999999999, claims: { sub: 'user' } };
45
+ const getSession = vi.fn().mockImplementation((req: Request) => {
46
+ pushSetCookie(req, 'sty.session=rotated; Path=/');
47
+ return Promise.resolve(rotated);
48
+ });
49
+ const responseInit: ResponseInit = { headers: { 'x-existing': '1' } };
50
+
51
+ await configure(request, { getSession } as unknown as AngularServerSDK, responseInit);
52
+
53
+ expect(getSession).toHaveBeenCalledWith(request);
54
+ expect(TestBed.inject(TransferState).get(SESSION_TRANSFER_KEY, undefined)).toEqual({
55
+ access_token: 'new',
56
+ expires_at: 9999999999,
57
+ claims: { sub: 'user' },
58
+ });
59
+ const headers = responseInit.headers as Headers;
60
+ expect(headers.getSetCookie()).toEqual(['sty.session=rotated; Path=/']);
61
+ expect(headers.get('x-existing')).toBe('1');
62
+ });
63
+
64
+ test('transfers null when the server-side refresh fails', async () => {
65
+ const request = new Request('https://brandtegrity.io/profile');
66
+
67
+ await configure(request, { getSession: vi.fn().mockResolvedValue(null) } as unknown as AngularServerSDK, {});
68
+
69
+ expect(TestBed.inject(TransferState).get(SESSION_TRANSFER_KEY, undefined)).toBeNull();
70
+ });
71
+
27
72
  test('transfers null when the server sdk finds no session for the request', async () => {
28
73
  const request = new Request('https://brandtegrity.io');
29
74
  const getSession = vi.fn().mockResolvedValue(null);
30
75
 
31
- await configure(request, { getSession } as unknown as AngularServerSDK);
76
+ await configure(request, { getSession: getSession } as unknown as AngularServerSDK);
32
77
 
33
78
  expect(TestBed.inject(TransferState).get(SESSION_TRANSFER_KEY, undefined)).toBeNull();
34
79
  });
@@ -36,7 +81,7 @@ describe('provideStrivacityServerSession', () => {
36
81
  test('is a no-op when there is no incoming request (e.g. not running under SSR)', async () => {
37
82
  const getSession = vi.fn().mockResolvedValue({ access_token: 'access-token' });
38
83
 
39
- await configure(undefined, { getSession } as unknown as AngularServerSDK);
84
+ await configure(undefined, { getSession: getSession } as unknown as AngularServerSDK);
40
85
 
41
86
  expect(getSession).not.toHaveBeenCalled();
42
87
  expect(TestBed.inject(TransferState).hasKey(SESSION_TRANSFER_KEY)).toBe(false);