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
3 changes: 2 additions & 1 deletion apps/smart-forms-app/public/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"formsServerUrl": "https://smartforms.csiro.au/api/fhir",
"defaultClientId": "a57d90e3-5f69-4b92-aa2e-2992180863c1",
"launchScopes": "launch openid fhirUser online_access patient/AllergyIntolerance.cs patient/Condition.cs patient/Encounter.r patient/Immunization.cs patient/Medication.r patient/MedicationStatement.cs patient/Observation.cs patient/Patient.r patient/QuestionnaireResponse.crus user/Practitioner.r launch/questionnaire?role=http://ns.electronichealth.net.au/smart/role/new",
"registeredClientIdsUrl": "https://smartforms.csiro.au/smart-config/config.json"
"registeredClientIdsUrl": "https://smartforms.csiro.au/smart-config/config.json",
"showDeveloperMessages": true
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ export interface ConfigFile {
// "https://example.com/fhir": "6cc9bccb-3ae2-40d7-9660-22c99534520b"
// }
registeredClientIdsUrl: string | null;

// Controls whether developer-focused messages are shown.
// Set to false for clinical/production deployments to hide technical messages.
// Defaults to true if not specified (shows messages for backward compatibility).
showDeveloperMessages?: boolean;
}

export interface AppConfig extends ConfigFile {
Expand All @@ -53,6 +58,7 @@ export const FALLBACK_CONFIG: AppConfig = {
launchScopes:
'launch openid fhirUser online_access patient/AllergyIntolerance.cs patient/Condition.cs patient/Encounter.r patient/Immunization.cs patient/Medication.r patient/MedicationStatement.cs patient/Observation.cs patient/Patient.r patient/QuestionnaireResponse.crus user/Practitioner.r launch/questionnaire?role=http://ns.electronichealth.net.au/smart/role/new',
registeredClientIdsUrl: null,
showDeveloperMessages: true,
registeredClientIds: null
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
* limitations under the License.
*/

import { useState } from 'react';
import { useState, useContext } from 'react';
import CloseSnackbar from '../../../components/Snackbar/CloseSnackbar.tsx';
import { useSnackbar } from 'notistack';
import { ConfigContext } from '../../configChecker/contexts/ConfigContext.tsx';
import {
buildForm,
useQuestionnaireResponseStore,
Expand All @@ -44,6 +45,7 @@ function usePopulate(spinner: RendererSpinner, onStopSpinner: () => void): void
const [isPopulated, setIsPopulated] = useState(false);

const { enqueueSnackbar } = useSnackbar();
const { config } = useContext(ConfigContext);

// Do not run population if spinner purpose is "repopulate"
if (status !== 'prepopulate') {
Expand Down Expand Up @@ -127,10 +129,14 @@ function usePopulate(spinner: RendererSpinner, onStopSpinner: () => void): void

onStopSpinner();
if (issues) {
enqueueSnackbar(
'Form partially populated, there might be pre-population issues. View console for details.',
{ action: <CloseSnackbar /> }
);
// Only show the snackbar message if developer messages are enabled
if (config.showDeveloperMessages ?? true) {
enqueueSnackbar(
'Form partially populated, there might be pre-population issues. View console for details.',
{ action: <CloseSnackbar /> }
);
}
// Always log to console - clinicians won't see this, but developers need it
console.warn(issues);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ jest.mock('../../../components/Snackbar/CloseSnackbar', () => {
};
});

// Mock ConfigContext
const mockConfigContext = {
config: {
showDeveloperMessages: true
},
configLoading: false,
configValid: true,
configError: null,
configErrorType: null,
currentClientId: 'test-client-id',
onSetCurrentClientId: jest.fn()
};

jest.mock('react', () => ({
...jest.requireActual('react'),
useContext: jest.fn(() => mockConfigContext)
}));

// Create mock store functions that will be used in the module mock
const mockSourceQuestionnaire = jest.fn();
const mockSourceResponse = jest.fn();
Expand Down Expand Up @@ -373,7 +391,7 @@ describe('usePopulate', () => {
});
});

it('should handle successful population with issues', async () => {
it('should handle successful population with issues (developer messages enabled)', async () => {
const issues = {
resourceType: 'OperationOutcome' as const,
issue: [
Expand Down Expand Up @@ -408,13 +426,67 @@ describe('usePopulate', () => {
additionalContext: undefined
});
expect(mockOnStopSpinner).toHaveBeenCalled();
// Snackbar should be shown when developer messages are enabled
expect(mockEnqueueSnackbar).toHaveBeenCalledWith(
'Form partially populated, there might be pre-population issues. View console for details.',
{ action: expect.anything() }
);
// Console warning should always be shown
expect(consoleSpy).toHaveBeenCalledWith(issues);

consoleSpy.mockRestore();
});

it('should handle successful population with issues (developer messages disabled)', async () => {
// Temporarily set showDeveloperMessages to false
const originalShowDeveloperMessages = mockConfigContext.config.showDeveloperMessages;
mockConfigContext.config.showDeveloperMessages = false;

const issues = {
resourceType: 'OperationOutcome' as const,
issue: [
{
severity: 'warning' as const,
code: 'incomplete' as const,
diagnostics: 'Some fields could not be populated'
}
]
};
const spinner = createSpinner(true, 'prepopulate');

mockPopulateQuestionnaire.mockResolvedValue({
populateSuccess: true,
populateResult: {
populatedResponse: mockResponse,
issues
}
});

const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();

renderHook(() => usePopulate(spinner, mockOnStopSpinner));

// Wait for async operations
await new Promise((resolve) => setTimeout(resolve, 10));

expect(mockBuildForm).toHaveBeenCalledWith({
questionnaire: mockQuestionnaire,
questionnaireResponse: mockResponse,
terminologyServerUrl: 'https://test-terminology-server.com',
additionalContext: undefined
});
expect(mockOnStopSpinner).toHaveBeenCalled();
// Snackbar should NOT be shown when developer messages are disabled
expect(mockEnqueueSnackbar).not.toHaveBeenCalledWith(
'Form partially populated, there might be pre-population issues. View console for details.',
{ action: expect.anything() }
);
// Console warning should still be shown (developers can still see it)
expect(consoleSpy).toHaveBeenCalledWith(issues);

consoleSpy.mockRestore();
// Restore original value
mockConfigContext.config.showDeveloperMessages = originalShowDeveloperMessages;
});
});

Expand Down
Loading