Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hip-lands-call.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@forgerock/journey-client': patch
---

Removed duplicate middleware config and added support for typed middleware
6 changes: 5 additions & 1 deletion e2e/journey-app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ const searchParams = new URLSearchParams(qs);
const config = serverConfigs[searchParams.get('clientId') || 'basic'];

const journeyName = searchParams.get('journey') ?? 'UsernamePassword';
let requestMiddleware: RequestMiddleware[] = [];
let requestMiddleware: RequestMiddleware<'JOURNEY_START' | 'JOURNEY_NEXT' | 'JOURNEY_TERMINATE'>[] =
[];

if (searchParams.get('middleware') === 'true') {
requestMiddleware = [
Expand All @@ -30,10 +31,12 @@ if (searchParams.get('middleware') === 'true') {
case 'JOURNEY_START':
req.url.searchParams.set('start-authenticate-middleware', 'start-authentication');
req.headers.append('x-start-authenticate-middleware', 'start-authentication');
req.headers?.set('Accept-Language', 'xx-XX');
break;
case 'JOURNEY_NEXT':
req.url.searchParams.set('authenticate-middleware', 'authentication');
req.headers.append('x-authenticate-middleware', 'authentication');
req.headers?.set('Accept-Language', 'yy-YY');
break;
}
next();
Expand All @@ -43,6 +46,7 @@ if (searchParams.get('middleware') === 'true') {
case 'JOURNEY_TERMINATE':
req.url.searchParams.set('end-session-middleware', 'end-session');
req.headers.append('x-end-session-middleware', 'end-session');
req.headers?.set('Accept-Language', 'zz-ZZ');
break;
}
next();
Expand Down
38 changes: 27 additions & 11 deletions e2e/journey-suites/src/request-middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { expect, test } from '@playwright/test';
import { asyncEvents } from './utils/async-events.js';
import { username, password } from './utils/demo-user.js';

test.skip('Test happy paths on test page', async ({ page }) => {
test('Test middleware on test page', async ({ page }) => {
const { clickButton, navigate } = asyncEvents(page);
await navigate('/?middleware=true&journey=Login');

Expand All @@ -24,7 +24,7 @@ test.skip('Test happy paths on test page', async ({ page }) => {
});

page.on('request', async (req) => {
networkArray.push(`${new URL(req.url()).pathname}, ${req.resourceType()}`);
networkArray.push(req.url().toString());
});

page.on('request', async (req) => {
Expand All @@ -46,17 +46,33 @@ test.skip('Test happy paths on test page', async ({ page }) => {
await clickButton('Logout', '/authenticate');

// Test assertions
// test URL query parameters added to URL on networkArray

expect(networkArray).toContain('start-authenticate-middleware, fetch');
expect(networkArray).toContain('authenticate-middleware, fetch');
expect(networkArray).toContain('end-session-middleware, fetch');
// Test URL query parameters added to URL on networkArray
const startRequest = networkArray.find((url) => url.includes('start-authenticate-middleware'));
const nextRequest = networkArray.find((url) => url.includes('authenticate-middleware'));
const endRequest = networkArray.find((url) => url.includes('end-session-middleware'));

expect(
headerArray.find((headers) => headers.get('x-start-authenticate-middleware')),
).toBeTruthy();
expect(headerArray.find((headers) => headers.get('x-authenticate-middleware'))).toBeTruthy();
expect(headerArray.find((headers) => headers.get('x-end-session-middleware'))).toBeTruthy();
expect(startRequest?.includes('start-authenticate-middleware=start-authentication')).toBeTruthy();
expect(nextRequest?.includes('authenticate-middleware=authentication')).toBeTruthy();
expect(endRequest?.includes('end-session-middleware=end-session')).toBeTruthy();

// Check for addition of custom headers
const startHeader = headerArray.find((headers) => headers.get('x-start-authenticate-middleware'));
const nextHeader = headerArray.find((headers) => headers.get('x-authenticate-middleware'));
const endHeader = headerArray.find((headers) => headers.get('x-end-session-middleware'));

expect(startHeader?.get('x-start-authenticate-middleware')).toBe('start-authentication');
expect(nextHeader?.get('x-authenticate-middleware')).toBe('authentication');
expect(endHeader?.get('x-end-session-middleware')).toBe('end-session');

// Check that Accept-Language header was modified from default en-US locale and set to correct value in each middleware
expect(startHeader?.get('Accept-Language')).not.toContain('en-US');
expect(nextHeader?.get('Accept-Language')).not.toContain('en-US');
expect(endHeader?.get('Accept-Language')).not.toContain('en-US');

expect(startHeader?.get('Accept-Language')).toBe('xx-XX');
expect(nextHeader?.get('Accept-Language')).toBe('yy-YY');
expect(endHeader?.get('Accept-Language')).toBe('zz-ZZ');

expect(messageArray.includes('Journey completed successfully')).toBe(true);
expect(messageArray.includes('Logout successful')).toBe(true);
Expand Down
10 changes: 4 additions & 6 deletions packages/journey-client/src/lib/client.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import {
} from '@forgerock/sdk-utilities';

import type { GenericError } from '@forgerock/sdk-types';

import type { RequestMiddleware } from '@forgerock/sdk-request-middleware';
import type { ActionTypes, RequestMiddleware } from '@forgerock/sdk-request-middleware';
import type { Step } from '@forgerock/sdk-types';

import { createJourneyStore } from './client.store.utils.js';
Expand All @@ -28,7 +27,7 @@ import { wellknownApi } from './wellknown.api.js';
import type { JourneyStep } from './step.utils.js';
import type { JourneyClientConfig } from './config.types.js';
import type { RedirectCallback } from './callbacks/redirect-callback.js';
import { NextOptions, StartParam, ResumeOptions } from './interfaces.js';
import type { NextOptions, StartParam, ResumeOptions } from './interfaces.js';
import type { JourneyLoginFailure } from './login-failure.utils.js';
import type { JourneyLoginSuccess } from './login-success.utils.js';

Expand Down Expand Up @@ -78,13 +77,13 @@ export interface JourneyClient {
* }
* ```
*/
export async function journey({
export async function journey<ActionType extends ActionTypes = ActionTypes>({
config,
requestMiddleware,
logger,
}: {
config: JourneyClientConfig;
requestMiddleware?: RequestMiddleware[];
requestMiddleware?: RequestMiddleware<ActionType>[];
logger?: {
level: LogLevel;
custom?: CustomLogger;
Expand Down Expand Up @@ -116,7 +115,6 @@ export async function journey({
store.dispatch(
configSlice.actions.set({
wellknownResponse: wellknownResponse,
middleware: config.middleware ?? requestMiddleware,
}),
);

Expand Down
6 changes: 3 additions & 3 deletions packages/journey-client/src/lib/client.store.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { logger as loggerFn } from '@forgerock/sdk-logger';
import { RequestMiddleware } from '@forgerock/sdk-request-middleware';
import { ActionTypes, RequestMiddleware } from '@forgerock/sdk-request-middleware';
import { combineReducers, configureStore } from '@reduxjs/toolkit';

import { configSlice } from './config.slice.js';
Expand All @@ -19,11 +19,11 @@ const rootReducer = combineReducers({
[wellknownApi.reducerPath]: wellknownApi.reducer,
});

export const createJourneyStore = ({
export const createJourneyStore = <ActionType extends ActionTypes>({
requestMiddleware,
logger,
}: {
requestMiddleware?: RequestMiddleware[];
requestMiddleware?: RequestMiddleware<ActionType, unknown>[];
logger?: ReturnType<typeof loggerFn>;
}) => {
return configureStore({
Expand Down
18 changes: 0 additions & 18 deletions packages/journey-client/src/lib/config.slice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { describe, it, expect } from 'vitest';
import { configSlice } from './config.slice.js';

import type { WellknownResponse } from '@forgerock/sdk-types';
import type { RequestMiddleware } from '@forgerock/sdk-request-middleware';
import type { ResolvedConfig } from './config.slice.js';

function createMockWellknown(overrides: Partial<WellknownResponse> = {}): WellknownResponse {
Expand Down Expand Up @@ -86,21 +85,4 @@ describe('journey-client config.slice', () => {
expect(state.error?.message).toContain('authorization_endpoint');
});
});

describe('configSlice_Middleware_StoresMiddleware', () => {
it('should store the provided middleware array', () => {
// Arrange
const mockMiddleware: RequestMiddleware[] = [(_req, _action, next) => next()];
const payload: ResolvedConfig = {
wellknownResponse: createMockWellknown(),
middleware: mockMiddleware,
};

// Act
const state = configSlice.reducer(undefined, configSlice.actions.set(payload));

// Assert
expect(state.middleware).toEqual(mockMiddleware);
});
});
});
6 changes: 0 additions & 6 deletions packages/journey-client/src/lib/config.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
*/

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

import type { WellknownResponse } from '@forgerock/sdk-types';
import type { RequestMiddleware } from '@forgerock/sdk-request-middleware';

import type { InternalJourneyClientConfig } from './config.types.js';
import { convertWellknown } from './wellknown.utils.js';

Expand All @@ -20,12 +17,10 @@ import { convertWellknown } from './wellknown.utils.js';
*/
export interface ResolvedConfig {
wellknownResponse: WellknownResponse;
middleware?: Array<RequestMiddleware>;
}

const initialState: InternalJourneyClientConfig = {
serverConfig: { baseUrl: '', paths: { authenticate: '', sessions: '' } },
middleware: [],
};

/**
Expand All @@ -48,7 +43,6 @@ export const configSlice = createSlice({
state.serverConfig = wellknown;
state.error = undefined;
}
state.middleware = action.payload.middleware;
},
},
});
7 changes: 0 additions & 7 deletions packages/journey-client/src/lib/config.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import type { GenericError } from '@forgerock/sdk-types';
import type { RequestMiddleware } from '@forgerock/sdk-request-middleware';
import type { ResolvedServerConfig } from './wellknown.utils.js';

/**
Expand Down Expand Up @@ -34,8 +33,6 @@ export interface JourneyServerConfig {
*/
export interface JourneyClientConfig {
serverConfig: JourneyServerConfig;
/** Optional middleware for request customization */
middleware?: Array<RequestMiddleware>;
}

/**
Expand All @@ -46,9 +43,5 @@ export interface JourneyClientConfig {
*/
export interface InternalJourneyClientConfig {
serverConfig: ResolvedServerConfig;
/** Optional middleware for request customization */
middleware?: Array<RequestMiddleware>;
error?: GenericError;
}

export type { RequestMiddleware };
2 changes: 1 addition & 1 deletion packages/journey-client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

// Re-export types from internal packages that consumers need
export type { LogLevel, CustomLogger } from '@forgerock/sdk-logger';
export type { RequestMiddleware } from '@forgerock/sdk-request-middleware';
export type { RequestMiddleware, ActionTypes } from '@forgerock/sdk-request-middleware';
export type {
Step,
Callback,
Expand Down
Loading