Skip to content

Commit b109b87

Browse files
committed
chore(journey-client): fixing import order
1 parent 927e317 commit b109b87

6 files changed

Lines changed: 179 additions & 85 deletions

File tree

e2e/journey-app/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import './style.css';
99
import { journey } from '@forgerock/journey-client';
1010
import { WebAuthn, WebAuthnStepType } from '@forgerock/journey-client/webauthn';
1111

12-
import type { JourneyClient, RequestMiddleware } from '@forgerock/journey-client/types';
13-
1412
import { renderCallbacks } from './callback-map.js';
1513
import { renderDeleteDevicesSection } from './components/delete-device.js';
1614
import { renderQRCodeStep } from './components/qr-code.js';
@@ -19,6 +17,8 @@ import { deleteWebAuthnDevice } from './services/delete-webauthn-device.js';
1917
import { webauthnComponent } from './components/webauthn-step.js';
2018
import { serverConfigs } from './server-configs.js';
2119

20+
import type { JourneyClient, RequestMiddleware } from '@forgerock/journey-client/types';
21+
2222
const qs = window.location.search;
2323
const searchParams = new URLSearchParams(qs);
2424

packages/journey-client/src/lib/client.store.test.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@
66
* of the MIT license. See the LICENSE file for details.
77
*/
88

9-
import { callbackType } from '@forgerock/sdk-types';
109
import { afterEach, describe, expect, test, vi } from 'vitest';
1110

12-
import type { GenericError, Step, WellknownResponse } from '@forgerock/sdk-types';
13-
1411
import { journey } from './client.store.js';
1512
import { createJourneyStep } from './step.utils.js';
13+
14+
import {
15+
callbackType,
16+
type GenericError,
17+
type Step,
18+
type WellknownResponse,
19+
} from '@forgerock/sdk-types';
20+
1621
import { JourneyClientConfig } from './config.types.js';
1722

1823
/**
@@ -158,7 +163,7 @@ describe('journey-client', () => {
158163
}
159164
});
160165

161-
test('start_401WithCodeInBody_ReturnsLoginFailure', async () => {
166+
test('start_401WithStepPayload_ReturnsLoginFailure', async () => {
162167
const failurePayload: Step = {
163168
code: 401,
164169
message: 'Access Denied',
@@ -222,7 +227,7 @@ describe('journey-client', () => {
222227
}
223228
});
224229

225-
test('next_401WithCodeInBody_ReturnsLoginFailure', async () => {
230+
test('next_401WithStepPayload_ReturnsLoginFailure', async () => {
226231
const initialStep = createJourneyStep({
227232
authId: 'test-auth-id',
228233
callbacks: [],
@@ -388,7 +393,7 @@ describe('journey-client', () => {
388393

389394
expect(isGenericError(result)).toBe(true);
390395
if (isGenericError(result)) {
391-
expect(result.error).toBe('no_response_data');
396+
expect(result.error).toBe('request_failed');
392397
expect(result.type).toBe('unknown_error');
393398
}
394399
});

packages/journey-client/src/lib/client.store.ts

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,22 @@
66
*/
77

88
import { logger as loggerFn, LogLevel, CustomLogger } from '@forgerock/sdk-logger';
9-
import { callbackType } from '@forgerock/sdk-types';
109
import {
1110
isGenericError,
1211
isValidWellknownUrl,
1312
createWellknownError,
1413
} from '@forgerock/sdk-utilities';
1514

16-
import type { GenericError } from '@forgerock/sdk-types';
17-
import type { ActionTypes, RequestMiddleware } from '@forgerock/sdk-request-middleware';
18-
import type { Step } from '@forgerock/sdk-types';
19-
2015
import { createJourneyStore } from './client.store.utils.js';
2116
import { configSlice } from './config.slice.js';
2217
import { journeyApi } from './journey.api.js';
2318
import { createStorage } from '@forgerock/storage';
2419
import { createJourneyObject } from './journey.utils.js';
2520
import { wellknownApi } from './wellknown.api.js';
2621

22+
import { callbackType, type GenericError, type Step } from '@forgerock/sdk-types';
23+
import type { ActionTypes, RequestMiddleware } from '@forgerock/sdk-request-middleware';
24+
2725
import type { JourneyStep } from './step.utils.js';
2826
import type { JourneyClientConfig } from './config.types.js';
2927
import type { RedirectCallback } from './callbacks/redirect-callback.js';
@@ -155,34 +153,18 @@ export async function journey<ActionType extends ActionTypes = ActionTypes>({
155153

156154
const self: JourneyClient = {
157155
start: async (options?: StartParam) => {
158-
const { data } = await store.dispatch(journeyApi.endpoints.start.initiate(options));
159-
if (data) {
160-
return createJourneyObject(data);
161-
}
162-
163-
const genericError: GenericError = {
164-
error: 'no_response_data',
165-
message: 'No data received from server when starting journey',
166-
type: 'unknown_error',
167-
};
168-
return genericError;
156+
const { data, error } = await store.dispatch(journeyApi.endpoints.start.initiate(options));
157+
return createJourneyObject(data, error);
169158
},
170159

171160
/**
172161
* Submits the current Step payload to the authentication API and retrieves the next JourneyStep in the journey.
173162
*/
174163
next: async (step: JourneyStep, options?: NextOptions) => {
175-
const { data } = await store.dispatch(journeyApi.endpoints.next.initiate({ step, options }));
176-
if (data) {
177-
return createJourneyObject(data);
178-
}
179-
180-
const genericError: GenericError = {
181-
error: 'no_response_data',
182-
message: 'No data received from server when submitting step',
183-
type: 'unknown_error',
184-
};
185-
return genericError;
164+
const { data, error } = await store.dispatch(
165+
journeyApi.endpoints.next.initiate({ step, options }),
166+
);
167+
return createJourneyObject(data, error);
186168
},
187169

188170
// TODO: Remove the actual redirect from this method and just return the URL to the caller

packages/journey-client/src/lib/journey.api.ts

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2020 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -9,6 +9,8 @@ import { initQuery, RequestMiddleware } from '@forgerock/sdk-request-middleware'
99
import { REQUESTED_WITH, getEndpointPath, stringify, resolve } from '@forgerock/sdk-utilities';
1010
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query';
1111

12+
import { NextOptions, StartParam } from './interfaces.js';
13+
1214
import type { Step } from '@forgerock/sdk-types';
1315
import type { logger as loggerFn } from '@forgerock/sdk-logger';
1416
import type {
@@ -21,9 +23,7 @@ import type {
2123
} from '@reduxjs/toolkit/query';
2224

2325
import { JourneyStep } from './step.types.js';
24-
2526
import type { InternalJourneyClientConfig } from './config.types.js';
26-
import { NextOptions, StartParam } from './interfaces.js';
2727

2828
/**
2929
* Minimal state type for accessing journey config from RTK Query endpoints.
@@ -89,9 +89,6 @@ interface Extras {
8989
logger: ReturnType<typeof loggerFn>;
9090
}
9191

92-
// Only treat these numeric codes as login failures coming back in the Step payload.
93-
const LOGIN_FAILURE_CODES = [400, 401, 403, 412, 423, 429];
94-
9592
export const journeyApi = createApi({
9693
reducerPath: 'journeyReducer',
9794
baseQuery: fetchBaseQuery({
@@ -136,24 +133,6 @@ export const journeyApi = createApi({
136133
return result as QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>;
137134
});
138135

139-
/**
140-
* If the endpoint returned an HTTP error whose body is an AM Step with a
141-
* login-failure code, treat it as successful data so callers receive the
142-
* Step via the `data` path (keeps downstream logic simpler).
143-
*/
144-
if ('error' in response) {
145-
const errorData = (response.error as FetchBaseQueryError | undefined)?.data as
146-
| Step
147-
| undefined;
148-
if (errorData && errorData.code && LOGIN_FAILURE_CODES.includes(errorData.code)) {
149-
return { data: errorData } as QueryReturnValue<
150-
Step,
151-
FetchBaseQueryError,
152-
FetchBaseQueryMeta
153-
>;
154-
}
155-
}
156-
157136
return response as QueryReturnValue<Step, FetchBaseQueryError, FetchBaseQueryMeta>;
158137
},
159138
}),
@@ -183,24 +162,6 @@ export const journeyApi = createApi({
183162
return result as QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>;
184163
});
185164

186-
/**
187-
* If the endpoint returned an HTTP error whose body is an AM Step with a
188-
* login-failure code, treat it as successful data so callers receive the
189-
* Step via the `data` path (keeps downstream logic simpler).
190-
*/
191-
if ('error' in response) {
192-
const errorData = (response.error as FetchBaseQueryError | undefined)?.data as
193-
| Step
194-
| undefined;
195-
if (errorData && errorData.code && LOGIN_FAILURE_CODES.includes(errorData.code)) {
196-
return { data: errorData } as QueryReturnValue<
197-
Step,
198-
FetchBaseQueryError,
199-
FetchBaseQueryMeta
200-
>;
201-
}
202-
}
203-
204165
return response as QueryReturnValue<Step, FetchBaseQueryError, FetchBaseQueryMeta>;
205166
},
206167
}),
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright (c) 2026 Ping Identity Corporation. All rights reserved.
3+
*
4+
* This software may be modified and distributed under the terms
5+
* of the MIT license. See the LICENSE file for details.
6+
*/
7+
8+
import { describe, expect, it } from 'vitest';
9+
10+
import { StepType, type Step } from '@forgerock/sdk-types';
11+
12+
import { createJourneyObject } from './journey.utils.js';
13+
import type { JourneyLoginFailure } from './login-failure.utils.js';
14+
15+
describe('createJourneyObject', () => {
16+
it('returns Step when provided a step with authId', () => {
17+
const stepPayload: Step = {
18+
authId: 'test-auth-id',
19+
callbacks: [],
20+
};
21+
22+
const result = createJourneyObject(stepPayload, undefined);
23+
24+
expect(result).not.toHaveProperty('error');
25+
expect(result).toHaveProperty('type', StepType.Step);
26+
expect(result).toHaveProperty('payload');
27+
expect((result as { payload: Step }).payload).toEqual(stepPayload);
28+
});
29+
30+
it('returns LoginSuccess when provided a step with successUrl', () => {
31+
const successPayload: Step = {
32+
successUrl: 'https://example.com/success',
33+
realm: 'root',
34+
tokenId: 'token-123',
35+
};
36+
37+
const result = createJourneyObject(successPayload, undefined);
38+
39+
expect(result).not.toHaveProperty('error');
40+
expect(result).toHaveProperty('type', StepType.LoginSuccess);
41+
expect(result).toHaveProperty('payload', successPayload);
42+
});
43+
44+
it('returns no_response_data GenericError when no step and no error', () => {
45+
const result = createJourneyObject(undefined, undefined);
46+
47+
expect(result).toMatchObject({
48+
error: 'no_response_data',
49+
message: 'No data received from server',
50+
type: 'unknown_error',
51+
});
52+
});
53+
54+
it('returns request_failed GenericError when no step but error exists', () => {
55+
const result = createJourneyObject(undefined, { status: 500 });
56+
57+
expect(result).toMatchObject({
58+
error: 'request_failed',
59+
message: 'Request failed: 500',
60+
type: 'unknown_error',
61+
});
62+
});
63+
64+
it('returns request_failed when error.data is present but not Step-like', () => {
65+
const result = createJourneyObject(undefined, { status: 401, data: { foo: 'bar' } });
66+
67+
expect(result).toMatchObject({
68+
error: 'request_failed',
69+
message: 'Request failed: 401',
70+
type: 'unknown_error',
71+
});
72+
});
73+
74+
it('returns LoginFailure when error.data contains a failure Step payload', () => {
75+
const failurePayload: Step = {
76+
code: 401,
77+
message: 'Access Denied',
78+
reason: 'Unauthorized',
79+
detail: { failureUrl: 'https://example.com/failure' },
80+
};
81+
82+
const result = createJourneyObject(undefined, { status: 401, data: failurePayload });
83+
84+
expect(result).not.toHaveProperty('error');
85+
expect(result).toHaveProperty('type', StepType.LoginFailure);
86+
expect(result).toHaveProperty('payload', failurePayload);
87+
88+
const failure = result as JourneyLoginFailure;
89+
expect(failure.getCode()).toBe(401);
90+
expect(failure.getMessage()).toBe('Access Denied');
91+
expect(failure.getReason()).toBe('Unauthorized');
92+
});
93+
});

0 commit comments

Comments
 (0)