diff --git a/.changeset/cute-snails-burn.md b/.changeset/cute-snails-burn.md new file mode 100644 index 0000000000..6490b4f9f2 --- /dev/null +++ b/.changeset/cute-snails-burn.md @@ -0,0 +1,5 @@ +--- +'@forgerock/davinci-client': patch +--- + +error states should be cleared from state when a successful next or success node was processed diff --git a/.github/instructions/nx.instructions.md b/.github/instructions/nx.instructions.md deleted file mode 100644 index 31c03569c9..0000000000 --- a/.github/instructions/nx.instructions.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -applyTo: '**' ---- - -// This file is automatically generated by Nx Console - -You are in an nx workspace using Nx 21.0.3 and pnpm as the package manager. - -You have access to the Nx MCP server and the tools it provides. Use them. Follow these guidelines in order to best help the user: - -# General Guidelines -- When answering questions, use the nx_workspace tool first to gain an understanding of the workspace architecture -- For questions around nx configuration, best practices or if you're unsure, use the nx_docs tool to get relevant, up-to-date docs!! Always use this instead of assuming things about nx configuration -- If the user needs help with an Nx configuration or project graph error, use the 'nx_workspace' tool to get any errors -- To help answer questions about the workspace structure or simply help with demonstrating how tasks depend on each other, use the 'nx_visualize_graph' tool - -# Generation Guidelines -If the user wants to generate something, use the following flow: - -- learn about the nx workspace and any specifics the user needs by using the 'nx_workspace' tool and the 'nx_project_details' tool if applicable -- get the available generators using the 'nx_generators' tool -- decide which generator to use. If no generators seem relevant, check the 'nx_available_plugins' tool to see if the user could install a plugin to help them -- get generator details using the 'nx_generator_schema' tool -- you may use the 'nx_docs' tool to learn more about a specific generator or technology if you're unsure -- decide which options to provide in order to best complete the user's request. Don't make any assumptions and keep the options minimalistic -- open the generator UI using the 'nx_open_generate_ui' tool -- wait for the user to finish the generator -- read the generator log file using the 'nx_read_generator_log' tool -- use the information provided in the log file to answer the user's question or continue with what they were doing -undefined - -# CI Error Guidelines -If the user wants help with fixing an error in their CI pipeline, use the following flow: -- Retrieve the list of current CI Pipeline Executions (CIPEs) using the 'nx_cloud_cipe_details' tool -- If there are any errors, use the 'nx_cloud_fix_cipe_failure' tool to retrieve the logs for a specific task -- Use the task logs to see what's wrong and help the user fix their problem. Use the appropriate tools if necessary -- Make sure that the problem is fixed by running the task that you passed into the 'nx_cloud_fix_cipe_failure' tool - - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1635f2f0f0..78298fd39f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ concurrency: jobs: pr: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 permissions: pull-requests: write contents: write diff --git a/packages/davinci-client/src/lib/collector.utils.test.ts b/packages/davinci-client/src/lib/collector.utils.test.ts index 575ecb1d56..49dbabd5c4 100644 --- a/packages/davinci-client/src/lib/collector.utils.test.ts +++ b/packages/davinci-client/src/lib/collector.utils.test.ts @@ -427,7 +427,7 @@ describe('Object value collectors', () => { title: 'Device 1', id: '123123', default: true, - value: 'device1-value', + description: 'device1-value', }, { type: 'device2', @@ -435,7 +435,7 @@ describe('Object value collectors', () => { title: 'Device 2', id: '345345', default: false, - value: 'device2-value', + description: 'device2-value', }, ], required: true, @@ -444,7 +444,7 @@ describe('Object value collectors', () => { const transformedDevices = mockField.options.map((device) => ({ label: device.title, value: device.id, - content: device.value, + content: device.description, type: device.type, key: device.id, default: device.default, diff --git a/packages/davinci-client/src/lib/collector.utils.ts b/packages/davinci-client/src/lib/collector.utils.ts index c662b644dc..145a48c6d7 100644 --- a/packages/davinci-client/src/lib/collector.utils.ts +++ b/packages/davinci-client/src/lib/collector.utils.ts @@ -374,7 +374,7 @@ export function returnObjectCollector< const unmappedDefault = field.options.find((device) => device.default); defaultValue = { type: unmappedDefault ? unmappedDefault.type : '', - value: unmappedDefault ? unmappedDefault.value : '', + value: unmappedDefault ? unmappedDefault.description : '', id: unmappedDefault ? unmappedDefault.id : '', }; @@ -382,7 +382,7 @@ export function returnObjectCollector< options = field.options.map((device) => ({ type: device.type, label: device.title, - content: device.value, + content: device.description, value: device.id, key: device.id, default: device.default, diff --git a/packages/davinci-client/src/lib/davinci.types.ts b/packages/davinci-client/src/lib/davinci.types.ts index ba77f9bca8..18d0208c16 100644 --- a/packages/davinci-client/src/lib/davinci.types.ts +++ b/packages/davinci-client/src/lib/davinci.types.ts @@ -126,7 +126,7 @@ export type DeviceAuthenticationField = { title: string; id: string; default: boolean; - value: string; + description: string; }[]; required: boolean; }; diff --git a/packages/davinci-client/src/lib/node.slice.test.ts b/packages/davinci-client/src/lib/node.slice.test.ts index fa3be4c128..77eb21349a 100644 --- a/packages/davinci-client/src/lib/node.slice.test.ts +++ b/packages/davinci-client/src/lib/node.slice.test.ts @@ -41,6 +41,49 @@ describe('The node slice reducers', () => { expect(nodeSlice.reducer(undefined, action)).toEqual(nodeNext0); }); + it('should clear error when we successfully process a node with a next', () => { + const actionError = { + type: 'node/error', + payload: { + data: error0a, + requestId: '1234', + httpStatus: 400, + }, + }; + const errorState = { + cache: { + key: '1234', + }, + client: { + status: 'error' as const, + }, + error: { + code: ' Invalid username and/or password', + collectors: [], + message: ' Invalid username and/or password', + internalHttpStatus: 400, + status: 'error', + type: 'davinci_error', + }, + httpStatus: 400, + server: { + status: 'error', + }, + status: 'error', + }; + const errorStateReducer = nodeSlice.reducer(undefined, actionError); + expect(errorStateReducer).toEqual(errorState); + + const action = { + type: 'node/next', + payload: { + data: next0, + requestId: '1234', + httpStatus: 200, + }, + }; + expect(nodeSlice.reducer(errorStateReducer, action)).toEqual(nodeNext0); + }); it('should handle success node after DaVinci flow', () => { const action = { type: 'node/success', @@ -67,6 +110,50 @@ describe('The node slice reducers', () => { expect(nodeSlice.reducer(undefined, action)).toEqual(nodeSuccess1); }); + it('should clear error when we successfully process a node', () => { + const action = { + type: 'node/error', + payload: { + data: error0a, + requestId: '1234', + httpStatus: 400, + }, + }; + const errorState = { + cache: { + key: '1234', + }, + client: { + status: 'error' as const, + }, + error: { + code: ' Invalid username and/or password', + collectors: [], + message: ' Invalid username and/or password', + internalHttpStatus: 400, + status: 'error', + type: 'davinci_error', + }, + httpStatus: 400, + server: { + status: 'error', + }, + status: 'error', + }; + const errorStateReducer = nodeSlice.reducer(undefined, action); + expect(errorStateReducer).toEqual(errorState); + + const actionSuccess = { + type: 'node/success', + payload: { + data: success1, + requestId: '1234', + httpStatus: 200, + }, + }; + expect(nodeSlice.reducer(errorStateReducer, actionSuccess)).toEqual(nodeSuccess1); + }); + it('should handle error node', () => { const action = { type: 'node/error', diff --git a/packages/davinci-client/src/lib/node.slice.ts b/packages/davinci-client/src/lib/node.slice.ts index 2fff26ad7b..d6afb5c8fc 100644 --- a/packages/davinci-client/src/lib/node.slice.ts +++ b/packages/davinci-client/src/lib/node.slice.ts @@ -51,7 +51,7 @@ export const initialNodeState = { status: START_STATUS, }, status: START_STATUS, -}; +} satisfies StartNode; type NodeStates = ErrorNode | FailureNode | ContinueNode | SuccessNode | StartNode; @@ -204,6 +204,8 @@ export const nodeSlice = createSlice({ status: CONTINUE_STATUS, }; + newState.error = null; + newState.httpStatus = action.payload.httpStatus; newState.server = { @@ -257,6 +259,7 @@ export const nodeSlice = createSlice({ status: SUCCESS_STATUS, }; + newState.error = null; newState.status = SUCCESS_STATUS; return newState; diff --git a/packages/protect/src/lib/protect.test.ts b/packages/protect/src/lib/protect.test.ts index 6ddb49e4d3..66d7820a87 100644 --- a/packages/protect/src/lib/protect.test.ts +++ b/packages/protect/src/lib/protect.test.ts @@ -171,6 +171,14 @@ describe('protect (success tests)', () => { }); describe('protect (error tests)', () => { + beforeAll(() => { + vi.doMock('./signals-sdk.js', () => { + throw new Error('Failed to load PingOne Signals SDK'); + }); + }); + afterAll(() => { + vi.doUnmock('./signals-sdk.js'); + }); it('should error on failed signals sdk load', async () => { await expect(protect(config)).rejects.toThrowError('Failed to load PingOne Signals SDK'); });