Skip to content

Commit b6d3630

Browse files
authored
Merge pull request #500 from ForgeRock/SDKS-4284-fix-kba
fix(journey-client): add support for KBA allowUserDefinedQuestions flag
2 parents 6358d9a + e99b374 commit b6d3630

File tree

6 files changed

+66
-6
lines changed

6 files changed

+66
-6
lines changed

.changeset/config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
"@forgerock/oidc-suites",
2525
"@forgerock/local-release-tool",
2626
"@forgerock/protect-app",
27-
"@forgerock/protect-suites"
27+
"@forgerock/protect-suites",
28+
"@forgerock/journey-app",
29+
"@forgerock/journey-suites"
2830
]
2931
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@forgerock/journey-client': patch
3+
---
4+
5+
Add support for KBA `allowUserDefinedQuestions` flag

e2e/journey-app/components/kba-create.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ export default function kbaCreateComponent(
3434
questionInput.appendChild(option);
3535
});
3636

37+
// Add option to create a question if allowed
38+
if (callback.isAllowedUserDefinedQuestions()) {
39+
const userDefinedOption = document.createElement('option');
40+
userDefinedOption.value = 'user-defined';
41+
userDefinedOption.text = 'Enter your own question';
42+
questionInput.appendChild(userDefinedOption);
43+
}
44+
3745
// Answer field
3846
const answerLabel = document.createElement('label');
3947
answerLabel.htmlFor = `${collectorKey}-answer`;
@@ -53,10 +61,32 @@ export default function kbaCreateComponent(
5361

5462
// Event listeners
5563
questionInput.addEventListener('input', (event) => {
56-
callback.setQuestion((event.target as HTMLInputElement).value);
64+
const selectedQuestion = (event.target as HTMLInputElement).value;
65+
if (selectedQuestion === 'user-defined') {
66+
// If user-defined option is selected, prompt for custom question
67+
const customQuestionLabel = document.createElement('label');
68+
customQuestionLabel.htmlFor = `${collectorKey}-question-user-defined`;
69+
customQuestionLabel.innerText = 'Type your question ' + idx + ':';
70+
71+
const customQuestionInput = document.createElement('input');
72+
customQuestionInput.type = 'text';
73+
customQuestionInput.id = `${collectorKey}-question-user-defined`;
74+
customQuestionInput.placeholder = 'Type your question';
75+
76+
container.lastElementChild?.before(customQuestionLabel);
77+
container.lastElementChild?.before(customQuestionInput);
78+
customQuestionInput.addEventListener('input', (e) => {
79+
callback.setQuestion((e.target as HTMLInputElement).value);
80+
console.log('Custom question ' + idx + ':', callback.getInputValue(0));
81+
});
82+
} else {
83+
callback.setQuestion((event.target as HTMLInputElement).value);
84+
console.log('Selected question ' + idx + ':', callback.getInputValue(0));
85+
}
5786
});
5887

5988
answerInput.addEventListener('input', (event) => {
6089
callback.setAnswer((event.target as HTMLInputElement).value);
90+
console.log('Answer ' + idx + ':', callback.getInputValue(1));
6191
});
6292
}

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@ test('Test happy paths on test page', async ({ page }) => {
4040
await page.getByLabel('Send me news and updates').check();
4141
// Fill password
4242
await page.getByLabel('Password').fill(password);
43-
// Select "Select a security question 7" dropdown and choose "What's your favorite color?"
44-
await page.getByLabel('Select a security question 7').selectOption("What's your favorite color?");
45-
// Fill answer with "Red"
46-
await page.getByLabel('Answer 7').fill('Red');
43+
44+
// Select "Select a security question 7" dropdown and choose custom question
45+
await page.getByLabel('Select a security question 7').selectOption('user-defined');
46+
await page.getByLabel('Type your question 7:').fill(`What is your pet's name?`);
47+
// Fill answer with "Rover"
48+
await page.getByLabel('Answer 7').fill('Rover');
49+
4750
// Select "Select a security question 8" dropdown and choose "Who was your first employer?"
4851
await page
4952
.getByLabel('Select a security question 8')
@@ -61,6 +64,10 @@ test('Test happy paths on test page', async ({ page }) => {
6164
await clickButton('Logout', '/authenticate');
6265

6366
// Test assertions
67+
expect(messageArray.includes(`Custom question 7: What is your pet's name?`)).toBe(true);
68+
expect(messageArray.includes('Answer 7: Rover')).toBe(true);
69+
expect(messageArray.includes(`Selected question 8: Who was your first employer?`)).toBe(true);
70+
expect(messageArray.includes('Answer 8: AAA Engineering')).toBe(true);
6471
expect(messageArray.includes('Journey completed successfully')).toBe(true);
6572
expect(messageArray.includes('Logout successful')).toBe(true);
6673
});

packages/journey-client/src/lib/callbacks/kba-create-callback.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ describe('KbaCreateCallback', () => {
2424
name: 'predefinedQuestions',
2525
value: ['Question 1', 'Question 2'],
2626
},
27+
{
28+
name: 'allowUserDefinedQuestions',
29+
value: true,
30+
},
2731
],
2832
input: [
2933
{
@@ -50,4 +54,9 @@ describe('KbaCreateCallback', () => {
5054
expect(cb.getInputValue('IDToken1question')).toBe('My custom question');
5155
expect(cb.getInputValue('IDToken1answer')).toBe('Blue');
5256
});
57+
58+
it('should indicate if user-defined questions are allowed', () => {
59+
const cb = new KbaCreateCallback(payload);
60+
expect(cb.isAllowedUserDefinedQuestions()).toBe(true);
61+
});
5362
});

packages/journey-client/src/lib/callbacks/kba-create-callback.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ export class KbaCreateCallback extends BaseCallback {
3333
return this.getOutputByName<string[]>('predefinedQuestions', []);
3434
}
3535

36+
/**
37+
* Gets whether the user can define questions.
38+
*/
39+
public isAllowedUserDefinedQuestions(): boolean {
40+
return this.getOutputByName<boolean>('allowUserDefinedQuestions', false);
41+
}
42+
3643
/**
3744
* Sets the callback's security question.
3845
*/

0 commit comments

Comments
 (0)