Skip to content

Commit f200156

Browse files
committed
chore: setup-tests-normalize-config
1 parent 5cbafa7 commit f200156

File tree

9 files changed

+116
-15
lines changed

9 files changed

+116
-15
lines changed

.claude/settings.local.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"mcp__serena__search_for_pattern",
5+
"mcp__serena__list_dir",
6+
"mcp__serena__find_file",
7+
"mcp__serena__read_file",
8+
"WebSearch",
9+
"WebFetch(domain:github.com)",
10+
"WebFetch(domain:raw.githubusercontent.com)"
11+
],
12+
"deny": [],
13+
"ask": []
14+
}
15+
}

e2e/am-mock-api/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
"keywords": [],
77
"license": "ISC",
88
"author": "",
9-
"type": "module",
109
"main": "./index.js",
1110
"dependencies": {
1211
"@types/express": "^4.17.17",

e2e/journey-app/main.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ const searchParams = new URLSearchParams(qs);
2323

2424
const config = serverConfigs[searchParams.get('clientId') || 'basic'];
2525

26+
const tree = searchParams.get('tree') ?? 'UsernamePassword';
27+
2628
const requestMiddleware: RequestMiddleware[] = [
2729
(req, action, next) => {
2830
switch (action.type) {
@@ -42,13 +44,13 @@ const requestMiddleware: RequestMiddleware[] = [
4244
];
4345

4446
(async () => {
45-
const journeyClient = await journey({ config, requestMiddleware });
47+
const journeyClient = await journey({ config: config, requestMiddleware });
4648

4749
const errorEl = document.getElementById('error') as HTMLDivElement;
4850
const formEl = document.getElementById('form') as HTMLFormElement;
4951
const journeyEl = document.getElementById('journey') as HTMLDivElement;
5052

51-
let step = await journeyClient.start();
53+
let step = await journeyClient.start({ journey: tree });
5254

5355
function renderComplete() {
5456
if (step?.type !== 'LoginSuccess') {
@@ -70,7 +72,7 @@ const requestMiddleware: RequestMiddleware[] = [
7072

7173
console.log('Logout successful');
7274

73-
step = await journeyClient.start();
75+
step = await journeyClient.start({ journey: tree });
7476

7577
renderForm();
7678
});

e2e/journey-app/server-configs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import type { JourneyClientConfig } from '@forgerock/journey-client/types';
99
export const serverConfigs: Record<string, JourneyClientConfig> = {
1010
basic: {
1111
serverConfig: {
12-
baseUrl: 'https://openam-sdks.forgeblocks.com/am/',
12+
baseUrl: 'http://localhost:9443/am',
1313
},
14-
realmPath: '/alpha',
14+
realmPath: 'root',
1515
},
1616
};

e2e/journey-suites/playwright.config.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ const config: PlaywrightTestConfig = {
2727
process.env.CI == 'false'
2828
? {
2929
command: 'pnpm watch @forgerock/journey-app',
30-
port: 5829,
31-
ignoreHTTPSErrors: true,
32-
reuseExistingServer: !process.env.CI,
3330
cwd: workspaceRoot,
3431
}
3532
: undefined,
@@ -40,6 +37,13 @@ const config: PlaywrightTestConfig = {
4037
reuseExistingServer: !process.env.CI,
4138
cwd: workspaceRoot,
4239
},
40+
{
41+
command: 'pnpm nx serve am-mock-api',
42+
port: 5829,
43+
ignoreHTTPSErrors: true,
44+
reuseExistingServer: !process.env.CI,
45+
cwd: workspaceRoot,
46+
},
4347
].filter(Boolean),
4448
};
4549

e2e/journey-suites/src/basic.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import { expect, test } from '@playwright/test';
99
import { asyncEvents } from './utils/async-events.js';
10-
import { username, password } from './utils/demo-user.js';
1110

1211
test('Test happy paths on test page', async ({ page }) => {
1312
const { navigate } = asyncEvents(page);
@@ -24,8 +23,8 @@ test('Test happy paths on test page', async ({ page }) => {
2423
expect(page.url()).toBe('http://localhost:5829/');
2524

2625
// Perform basic login
27-
await page.getByLabel('User Name').fill(username);
28-
await page.getByLabel('Password').fill(password);
26+
await page.getByLabel('User Name').fill('sdkuser');
27+
await page.getByLabel('Password').fill('password');
2928
await page.getByRole('button', { name: 'Submit' }).click();
3029
await expect(page.getByText('Complete')).toBeVisible();
3130

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"test": "CI=true nx affected:test",
3535
"test:e2e": "CI=true nx affected:e2e",
3636
"verdaccio": "nx local-registry",
37-
"watch": "nx watch-deps"
37+
"watch": "nx vite:watch-deps"
3838
},
3939
"lint-staged": {
4040
"*": [

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

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,65 @@ describe('journey-client', () => {
238238
});
239239
});
240240

241+
describe('baseUrl normalization', () => {
242+
test('should add trailing slash to baseUrl without one', async () => {
243+
const configWithoutSlash: JourneyClientConfig = {
244+
serverConfig: {
245+
baseUrl: 'http://localhost:9443/am',
246+
},
247+
realmPath: 'root',
248+
};
249+
250+
const mockStepResponse: Step = { authId: 'test-auth-id', callbacks: [] };
251+
mockFetch.mockResolvedValue(new Response(JSON.stringify(mockStepResponse)));
252+
253+
const client = await journey({ config: configWithoutSlash });
254+
await client.start();
255+
256+
expect(mockFetch).toHaveBeenCalledTimes(1);
257+
const request = mockFetch.mock.calls[0][0] as Request;
258+
expect(request.url).toBe('http://localhost:9443/am/json/realms/root/authenticate');
259+
});
260+
261+
test('should preserve trailing slash if already present', async () => {
262+
const configWithSlash: JourneyClientConfig = {
263+
serverConfig: {
264+
baseUrl: 'http://localhost:9443/am/',
265+
},
266+
realmPath: 'root',
267+
};
268+
269+
const mockStepResponse: Step = { authId: 'test-auth-id', callbacks: [] };
270+
mockFetch.mockResolvedValue(new Response(JSON.stringify(mockStepResponse)));
271+
272+
const client = await journey({ config: configWithSlash });
273+
await client.start();
274+
275+
expect(mockFetch).toHaveBeenCalledTimes(1);
276+
const request = mockFetch.mock.calls[0][0] as Request;
277+
expect(request.url).toBe('http://localhost:9443/am/json/realms/root/authenticate');
278+
});
279+
280+
test('should work with baseUrl without context path', async () => {
281+
const configNoContext: JourneyClientConfig = {
282+
serverConfig: {
283+
baseUrl: 'http://localhost:9443',
284+
},
285+
realmPath: 'root',
286+
};
287+
288+
const mockStepResponse: Step = { authId: 'test-auth-id', callbacks: [] };
289+
mockFetch.mockResolvedValue(new Response(JSON.stringify(mockStepResponse)));
290+
291+
const client = await journey({ config: configNoContext });
292+
await client.start();
293+
294+
expect(mockFetch).toHaveBeenCalledTimes(1);
295+
const request = mockFetch.mock.calls[0][0] as Request;
296+
expect(request.url).toBe('http://localhost:9443/json/realms/root/authenticate');
297+
});
298+
});
299+
241300
// TODO: Add tests for endSession when the test environment AbortSignal issue is resolved
242301
// test('endSession() should call the sessions endpoint with DELETE method', async () => {
243302
// mockFetch.mockResolvedValue(new Response('', { status: 200 }));

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@ import type { JourneyClientConfig } from './config.types.js';
2222
import type { RedirectCallback } from './callbacks/redirect-callback.js';
2323
import { NextOptions, StartParam, ResumeOptions } from './interfaces.js';
2424

25+
/**
26+
* Normalizes the serverConfig to ensure baseUrl has a trailing slash.
27+
* This is required for the resolve() function to work correctly with context paths like /am.
28+
*/
29+
function normalizeConfig(config: JourneyClientConfig): JourneyClientConfig {
30+
if (config.serverConfig?.baseUrl) {
31+
const url = config.serverConfig.baseUrl;
32+
if (url.charAt(url.length - 1) !== '/') {
33+
return {
34+
...config,
35+
serverConfig: {
36+
...config.serverConfig,
37+
baseUrl: url + '/',
38+
},
39+
};
40+
}
41+
}
42+
return config;
43+
}
44+
2545
export async function journey({
2646
config,
2747
requestMiddleware,
@@ -36,8 +56,11 @@ export async function journey({
3656
}) {
3757
const log = loggerFn({ level: logger?.level || 'error', custom: logger?.custom });
3858

39-
const store = createJourneyStore({ requestMiddleware, logger: log, config });
40-
store.dispatch(setConfig(config));
59+
// Normalize config to ensure baseUrl has trailing slash
60+
const normalizedConfig = normalizeConfig(config);
61+
62+
const store = createJourneyStore({ requestMiddleware, logger: log, config: normalizedConfig });
63+
store.dispatch(setConfig(normalizedConfig));
4164

4265
const stepStorage = createStorage<{ step: Step }>({
4366
type: 'sessionStorage',

0 commit comments

Comments
 (0)