From 5ddaeb453652be034558bb99fedfbe9a779dc56a Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Fri, 23 Sep 2022 16:57:34 +0100 Subject: [PATCH 01/25] feat: added configuration options to K-menu --- client/src/utils/KBar.tsx | 114 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index 2617d402..9278df84 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -63,6 +63,120 @@ export const KBar: React.FunctionComponent = ({ children }) = dispatch(fetchAllCharacters()) }, }, + { + id: 'configuration', + name: 'Choose your configuration options...', + keywords: 'interface color dark light', + section: 'Configuration', + }, + { + id: 'ledger', + name: 'Select your preferred ledger', + keywords: 'ledger', + section: '', + parent: 'configuration', + }, + { + id: 'BCovrin', + name: 'BCovrin', + keywords: 'BCovrin', + section: '', + perform: () => { + alert('BCovrin selected!') + }, + parent: 'ledger', + }, + { + id: 'issue-credential-protocol-version', + name: 'Select your preferred credential protocol version', + keywords: 'issue-credential-protocol-version', + section: '', + parent: 'configuration', + }, + { + id: 'issue-credential-protocol-version-1', + name: 'v1', + keywords: 'issue-credential-protocol-version-1', + section: '', + perform: () => { + alert('Credential Protocol Version 1 selected') + }, + parent: 'issue-credential-protocol-version', + }, + { + id: 'issue-credential-protocol-version-2', + name: 'v2', + keywords: 'issue-credential-protocol-version-2', + section: '', + perform: () => { + alert('Credential Protocol Version 2 selected') + }, + parent: 'issue-credential-protocol-version', + }, + { + id: 'present-proof-protocol-version', + name: 'Select your preferred proof protocol version', + keywords: 'present-proof-protocol-version', + section: '', + parent: 'configuration', + }, + { + id: 'present-proof-protocol-version-1', + name: 'v1', + keywords: 'present-proof-protocol-version-1', + section: '', + perform: () => { + alert('Proof Protocol Version 1 selected') + }, + parent: 'present-proof-protocol-version', + }, + { + id: 'present-proof-protocol-version-2', + name: 'v2', + keywords: 'present-proof-protocol-version-2', + section: '', + perform: () => { + alert('Proof Protocol Version 2 selected') + }, + parent: 'present-proof-protocol-version', + }, + { + id: 'invitation-method', + name: 'Select your preferred invitation method', + keywords: 'invitation-method', + section: '', + parent: 'configuration', + }, + { + id: 'invitation-method-oob', + name: 'Out-of-band invitation', + keywords: 'invitation-method-oob', + section: '', + perform: () => { + alert('Out-of-band invitation method selected') + }, + parent: 'invitation-method', + }, + { + id: 'invitation-method-legacy', + name: 'Out-of-band legacy invitation', + keywords: 'invitation-method-legacy', + section: '', + perform: () => { + alert('Out-of-band legacy invitation method selected') + }, + parent: 'invitation-method', + }, + { + id: 'invitation-method-legacy-connectionless', + name: 'Out-of-band legacy connectionless invitation', + keywords: 'invitation-method-legacy-connectionless', + section: '', + perform: () => { + alert('Out-of-band legacy connectionless invitation method selected') + }, + parent: 'invitation-method', + }, { id: 'theme', name: 'Change theme…', From 225a6218fd64961a4d1fd83b8963a25b4c37638a Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Mon, 26 Sep 2022 12:47:33 +0100 Subject: [PATCH 02/25] feat: added logic for invitation method switch from K-menu Signed-off-by: Jim Ezesinachi --- client/src/api/ConnectionApi.ts | 10 +++++- .../configuration/configurationSelectors.ts | 5 +++ .../configuration/configurationSlice.ts | 28 ++++++++++++++++ .../src/slices/connection/connectionThunks.ts | 7 +++- client/src/slices/index.ts | 2 ++ client/src/store/configureStore.tsx | 2 +- client/src/utils/KBar.tsx | 33 ++++++++----------- 7 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 client/src/slices/configuration/configurationSelectors.ts create mode 100644 client/src/slices/configuration/configurationSlice.ts diff --git a/client/src/api/ConnectionApi.ts b/client/src/api/ConnectionApi.ts index 7cadc87e..35623a77 100644 --- a/client/src/api/ConnectionApi.ts +++ b/client/src/api/ConnectionApi.ts @@ -2,7 +2,15 @@ import type { AxiosResponse } from 'axios' import { apiCall } from './BaseUrl' -export const createInvitation = (agentName?: string, agentImageUrl?: string): Promise => { +export const createOobInvitation = (agentName?: string, agentImageUrl?: string): Promise => { + return apiCall.post('/oob/create-invitation', { + autoAcceptConnection: true, + label: agentName, + imageUrl: agentImageUrl, + }) +} + +export const createLegacyInvitation = (agentName?: string, agentImageUrl?: string): Promise => { return apiCall.post('/oob/create-legacy-invitation', { autoAcceptConnection: true, label: agentName, diff --git a/client/src/slices/configuration/configurationSelectors.ts b/client/src/slices/configuration/configurationSelectors.ts new file mode 100644 index 00000000..6bf01be4 --- /dev/null +++ b/client/src/slices/configuration/configurationSelectors.ts @@ -0,0 +1,5 @@ +import type { RootState } from '../../store/configureStore' + +import { useSelector } from 'react-redux' + +export const useConfiguration = () => useSelector((state: RootState) => state.configuration) diff --git a/client/src/slices/configuration/configurationSlice.ts b/client/src/slices/configuration/configurationSlice.ts new file mode 100644 index 00000000..d10881d6 --- /dev/null +++ b/client/src/slices/configuration/configurationSlice.ts @@ -0,0 +1,28 @@ +import { createSlice } from '@reduxjs/toolkit' + +interface ConfigurationState { + invitationMethod: string +} + +const initialState: ConfigurationState = { + invitationMethod: 'legacy', +} + +const configurationSlice = createSlice({ + name: 'configuration', + initialState, + reducers: { + setinvitationMethod: (state, action) => { + state.invitationMethod = action.payload === 'oob' ? 'oob' : 'legacy' + if (action.payload) { + document.documentElement.classList.add('dark') + } else { + document.documentElement.classList.remove('dark') + } + }, + }, +}) + +export const { setinvitationMethod } = configurationSlice.actions + +export default configurationSlice.reducer diff --git a/client/src/slices/connection/connectionThunks.ts b/client/src/slices/connection/connectionThunks.ts index 7e23fe77..31c601e3 100644 --- a/client/src/slices/connection/connectionThunks.ts +++ b/client/src/slices/connection/connectionThunks.ts @@ -3,6 +3,7 @@ import type { Entity } from '../../slices/types' import { createAsyncThunk } from '@reduxjs/toolkit' import * as Api from '../../api/ConnectionApi' +import { useConfiguration } from '../configuration/configurationSelectors' export const fetchConnectionById = createAsyncThunk('connection/fetchById', async (id: string) => { const response = await Api.getConnectionById(id) @@ -15,6 +16,10 @@ export const fetchConnectionByOutOfBandId = createAsyncThunk('connection/fetchBy }) export const createInvitation = createAsyncThunk('connection/createInvitation', async (entity?: Entity) => { - const response = await Api.createInvitation(entity?.name, entity?.imageUrl) + const { invitationMethod } = useConfiguration() + const response = + invitationMethod === 'oob' + ? await Api.createOobInvitation(entity?.name, entity?.imageUrl) + : await Api.createLegacyInvitation(entity?.name, entity?.imageUrl) return response.data }) diff --git a/client/src/slices/index.ts b/client/src/slices/index.ts index fd93cf28..d9f0c047 100644 --- a/client/src/slices/index.ts +++ b/client/src/slices/index.ts @@ -1,6 +1,7 @@ import { combineReducers } from 'redux' import charactersSlice from './characters/charactersSlice' +import configurationSlice from './configuration/configurationSlice' import connectionSlice from './connection/connectionSlice' import credentialsSlice from './credentials/credentialsSlice' import onboardingSlice from './onboarding/onboardingSlice' @@ -19,6 +20,7 @@ const rootReducer = combineReducers({ credentials: credentialsSlice, onboarding: onboardingSlice, preferences: preferencesSlice, + configuration: configurationSlice, proof: proofSlice, section: sectionSlice, useCases: useCaseSlice, diff --git a/client/src/store/configureStore.tsx b/client/src/store/configureStore.tsx index 81e4e707..f8718c49 100644 --- a/client/src/store/configureStore.tsx +++ b/client/src/store/configureStore.tsx @@ -8,7 +8,7 @@ import rootReducer from '../slices/index' export const persistConfig = { key: 'redux-store-root', storage, - whitelist: ['preferences', 'characters', 'onboarding', 'credentials', 'connection'], + whitelist: ['preferences', 'configuration', 'characters', 'onboarding', 'credentials', 'connection'], version: 4, } diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index 9278df84..41997059 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -6,6 +6,7 @@ import Confetti from 'react-confetti' import { confettiFade } from '../FramerAnimations' import { useAppDispatch } from '../hooks/hooks' import { fetchAllCharacters } from '../slices/characters/charactersThunks' +import { setinvitationMethod } from '../slices/configuration/configurationSlice' import { usePreferences } from '../slices/preferences/preferencesSelectors' import { resetDashboard, setDarkMode } from '../slices/preferences/preferencesSlice' import { fetchWallets } from '../slices/wallets/walletsThunks' @@ -65,13 +66,14 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'configuration', - name: 'Choose your configuration options...', - keywords: 'interface color dark light', + name: 'Choose demo configuration options...', + shortcut: ['o'], + keywords: 'configuration', section: 'Configuration', }, { id: 'ledger', - name: 'Select your preferred ledger', + name: 'Select ledger', keywords: 'ledger', section: '', parent: 'configuration', @@ -82,13 +84,13 @@ export const KBar: React.FunctionComponent = ({ children }) = keywords: 'BCovrin', section: '', perform: () => { - alert('BCovrin selected!') + alert('BCovrin ledger selected!') }, parent: 'ledger', }, { id: 'issue-credential-protocol-version', - name: 'Select your preferred credential protocol version', + name: 'Select credential protocol version', keywords: 'issue-credential-protocol-version', section: '', parent: 'configuration', @@ -115,7 +117,7 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'present-proof-protocol-version', - name: 'Select your preferred proof protocol version', + name: 'Select proof protocol version', keywords: 'present-proof-protocol-version', section: '', parent: 'configuration', @@ -142,7 +144,7 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'invitation-method', - name: 'Select your preferred invitation method', + name: 'Select invitation method', keywords: 'invitation-method', section: '', parent: 'configuration', @@ -153,33 +155,24 @@ export const KBar: React.FunctionComponent = ({ children }) = keywords: 'invitation-method-oob', section: '', perform: () => { - alert('Out-of-band invitation method selected') + dispatch(setinvitationMethod('oob')) }, parent: 'invitation-method', }, { id: 'invitation-method-legacy', - name: 'Out-of-band legacy invitation', + name: 'Legacy invitation', keywords: 'invitation-method-legacy', section: '', perform: () => { - alert('Out-of-band legacy invitation method selected') - }, - parent: 'invitation-method', - }, - { - id: 'invitation-method-legacy-connectionless', - name: 'Out-of-band legacy connectionless invitation', - keywords: 'invitation-method-legacy-connectionless', - section: '', - perform: () => { - alert('Out-of-band legacy connectionless invitation method selected') + dispatch(setinvitationMethod('legacy')) }, parent: 'invitation-method', }, { id: 'theme', name: 'Change theme…', + shortcut: ['t'], keywords: 'interface color dark light', section: 'Preferences', }, From 967a190dd1c208db9c135e293bbe3681586461e4 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Mon, 26 Sep 2022 13:27:19 +0100 Subject: [PATCH 03/25] test: updated tests Signed-off-by: Jim Ezesinachi --- cypress/e2e/usecase_page.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/usecase_page.cy.ts b/cypress/e2e/usecase_page.cy.ts index b9082595..35417a6b 100644 --- a/cypress/e2e/usecase_page.cy.ts +++ b/cypress/e2e/usecase_page.cy.ts @@ -58,7 +58,7 @@ describe('UseCase Page', () => { cy.get('[data-cy=select-use-case]').first().click() - cy.intercept('POST', `${API_URL}/connections/create-invitation`).as('createInvitation') + cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') cy.get('[data-cy=start-container]') cy.get('[data-cy=small-button]').click() From 9ac5fba79500cfebca98dd650b9a8ec981dffe39 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Mon, 26 Sep 2022 18:36:58 +0100 Subject: [PATCH 04/25] test: removed theme logic from setInvitationMethod Signed-off-by: Jim Ezesinachi --- client/src/slices/configuration/configurationSlice.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/client/src/slices/configuration/configurationSlice.ts b/client/src/slices/configuration/configurationSlice.ts index d10881d6..290527c8 100644 --- a/client/src/slices/configuration/configurationSlice.ts +++ b/client/src/slices/configuration/configurationSlice.ts @@ -14,11 +14,6 @@ const configurationSlice = createSlice({ reducers: { setinvitationMethod: (state, action) => { state.invitationMethod = action.payload === 'oob' ? 'oob' : 'legacy' - if (action.payload) { - document.documentElement.classList.add('dark') - } else { - document.documentElement.classList.remove('dark') - } }, }, }) From 7fcf676546c7aeb5e02e21c7a871df2dd4f55aef Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Tue, 27 Sep 2022 10:41:34 +0100 Subject: [PATCH 05/25] fix: fixed use of React hooks incorectly Signed-off-by: Jim Ezesinachi --- .../src/pages/onboarding/steps/SetupConnection.tsx | 12 +++++++++++- client/src/pages/useCase/steps/StepConnection.tsx | 8 +++++++- .../src/slices/configuration/configurationSlice.ts | 6 +++--- client/src/slices/connection/connectionThunks.ts | 9 +++------ client/src/slices/types.ts | 1 + 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/client/src/pages/onboarding/steps/SetupConnection.tsx b/client/src/pages/onboarding/steps/SetupConnection.tsx index 902df430..b1b624c5 100644 --- a/client/src/pages/onboarding/steps/SetupConnection.tsx +++ b/client/src/pages/onboarding/steps/SetupConnection.tsx @@ -1,3 +1,4 @@ +import type { Entity } from '../../../slices/types' import type { Content } from '../../../utils/OnboardingUtils' import { motion } from 'framer-motion' @@ -10,6 +11,7 @@ import { Loader } from '../../../components/Loader' import { QRCode } from '../../../components/QRCode' import { useAppDispatch } from '../../../hooks/hooks' import { useInterval } from '../../../hooks/useInterval' +import { useConfiguration } from '../../../slices/configuration/configurationSelectors' import { createInvitation, fetchConnectionById, @@ -36,9 +38,17 @@ export const SetupConnection: React.FC = ({ }) => { const dispatch = useAppDispatch() const isCompleted = connectionState === 'response-sent' || connectionState === 'completed' + const { invitationMethod } = useConfiguration() useEffect(() => { - if (!isCompleted) dispatch(createInvitation()) + const entity: Entity = { + name: '', + icon: '', + invitationMethod: false, + } + + entity.invitationMethod = invitationMethod ? true : false + if (!isCompleted) dispatch(createInvitation(entity)) }, []) useEffect(() => { diff --git a/client/src/pages/useCase/steps/StepConnection.tsx b/client/src/pages/useCase/steps/StepConnection.tsx index 8e32dc63..b6bf4e55 100644 --- a/client/src/pages/useCase/steps/StepConnection.tsx +++ b/client/src/pages/useCase/steps/StepConnection.tsx @@ -10,6 +10,7 @@ import { fade, fadeX } from '../../../FramerAnimations' import { QRCode } from '../../../components/QRCode' import { useAppDispatch } from '../../../hooks/hooks' import { useInterval } from '../../../hooks/useInterval' +import { useConfiguration } from '../../../slices/configuration/configurationSelectors' import { createInvitation, fetchConnectionById, @@ -27,9 +28,14 @@ export const StepConnection: React.FC = ({ step, connection, entity }) => const dispatch = useAppDispatch() const { id, state, invitationUrl, outOfBandId } = connection const isCompleted = state === 'response-sent' || state === 'completed' + const { invitationMethod } = useConfiguration() useEffect(() => { - if (!isCompleted) dispatch(createInvitation(entity)) + entity.invitationMethod = invitationMethod ? true : false + + if (!isCompleted) { + dispatch(createInvitation(entity)) + } }, []) useInterval( diff --git a/client/src/slices/configuration/configurationSlice.ts b/client/src/slices/configuration/configurationSlice.ts index 290527c8..7fb0807b 100644 --- a/client/src/slices/configuration/configurationSlice.ts +++ b/client/src/slices/configuration/configurationSlice.ts @@ -1,11 +1,11 @@ import { createSlice } from '@reduxjs/toolkit' interface ConfigurationState { - invitationMethod: string + invitationMethod: boolean } const initialState: ConfigurationState = { - invitationMethod: 'legacy', + invitationMethod: false, } const configurationSlice = createSlice({ @@ -13,7 +13,7 @@ const configurationSlice = createSlice({ initialState, reducers: { setinvitationMethod: (state, action) => { - state.invitationMethod = action.payload === 'oob' ? 'oob' : 'legacy' + state.invitationMethod = action.payload === 'oob' ? true : false }, }, }) diff --git a/client/src/slices/connection/connectionThunks.ts b/client/src/slices/connection/connectionThunks.ts index 31c601e3..dc89ddf3 100644 --- a/client/src/slices/connection/connectionThunks.ts +++ b/client/src/slices/connection/connectionThunks.ts @@ -3,7 +3,6 @@ import type { Entity } from '../../slices/types' import { createAsyncThunk } from '@reduxjs/toolkit' import * as Api from '../../api/ConnectionApi' -import { useConfiguration } from '../configuration/configurationSelectors' export const fetchConnectionById = createAsyncThunk('connection/fetchById', async (id: string) => { const response = await Api.getConnectionById(id) @@ -16,10 +15,8 @@ export const fetchConnectionByOutOfBandId = createAsyncThunk('connection/fetchBy }) export const createInvitation = createAsyncThunk('connection/createInvitation', async (entity?: Entity) => { - const { invitationMethod } = useConfiguration() - const response = - invitationMethod === 'oob' - ? await Api.createOobInvitation(entity?.name, entity?.imageUrl) - : await Api.createLegacyInvitation(entity?.name, entity?.imageUrl) + const response = entity?.invitationMethod + ? await Api.createOobInvitation(entity?.name, entity?.imageUrl) + : await Api.createLegacyInvitation(entity?.name, entity?.imageUrl) return response.data }) diff --git a/client/src/slices/types.ts b/client/src/slices/types.ts index 52b37a4b..9c49ccf2 100644 --- a/client/src/slices/types.ts +++ b/client/src/slices/types.ts @@ -98,6 +98,7 @@ export interface Entity { name: string icon: string imageUrl?: string + invitationMethod?: boolean } export interface Colors { From c701866e81a7848e665fd3f90acc42af8483bcab Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Tue, 27 Sep 2022 21:06:16 +0100 Subject: [PATCH 06/25] fix: fixed issue with ConfigurationState use Signed-off-by: Jim Ezesinachi --- .../onboarding/steps/SetupConnection.tsx | 12 ++--------- .../pages/useCase/steps/StepConnection.tsx | 6 ++---- .../configuration/configurationSlice.ts | 10 +++++----- .../src/slices/connection/connectionThunks.ts | 20 ++++++++++++------- client/src/slices/types.ts | 6 +++++- client/src/utils/KBar.tsx | 6 +++--- cypress/e2e/usecase_page.cy.ts | 2 +- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/client/src/pages/onboarding/steps/SetupConnection.tsx b/client/src/pages/onboarding/steps/SetupConnection.tsx index b1b624c5..7bf0d639 100644 --- a/client/src/pages/onboarding/steps/SetupConnection.tsx +++ b/client/src/pages/onboarding/steps/SetupConnection.tsx @@ -1,4 +1,3 @@ -import type { Entity } from '../../../slices/types' import type { Content } from '../../../utils/OnboardingUtils' import { motion } from 'framer-motion' @@ -38,17 +37,10 @@ export const SetupConnection: React.FC = ({ }) => { const dispatch = useAppDispatch() const isCompleted = connectionState === 'response-sent' || connectionState === 'completed' - const { invitationMethod } = useConfiguration() + const { useLegacyInvitation } = useConfiguration() useEffect(() => { - const entity: Entity = { - name: '', - icon: '', - invitationMethod: false, - } - - entity.invitationMethod = invitationMethod ? true : false - if (!isCompleted) dispatch(createInvitation(entity)) + if (!isCompleted) dispatch(createInvitation({ useLegacyInvitation })) }, []) useEffect(() => { diff --git a/client/src/pages/useCase/steps/StepConnection.tsx b/client/src/pages/useCase/steps/StepConnection.tsx index b6bf4e55..e3996bd1 100644 --- a/client/src/pages/useCase/steps/StepConnection.tsx +++ b/client/src/pages/useCase/steps/StepConnection.tsx @@ -28,13 +28,11 @@ export const StepConnection: React.FC = ({ step, connection, entity }) => const dispatch = useAppDispatch() const { id, state, invitationUrl, outOfBandId } = connection const isCompleted = state === 'response-sent' || state === 'completed' - const { invitationMethod } = useConfiguration() + const { useLegacyInvitation } = useConfiguration() useEffect(() => { - entity.invitationMethod = invitationMethod ? true : false - if (!isCompleted) { - dispatch(createInvitation(entity)) + dispatch(createInvitation({ entity, useLegacyInvitation })) } }, []) diff --git a/client/src/slices/configuration/configurationSlice.ts b/client/src/slices/configuration/configurationSlice.ts index 7fb0807b..c8c114bf 100644 --- a/client/src/slices/configuration/configurationSlice.ts +++ b/client/src/slices/configuration/configurationSlice.ts @@ -1,23 +1,23 @@ import { createSlice } from '@reduxjs/toolkit' interface ConfigurationState { - invitationMethod: boolean + useLegacyInvitation: boolean } const initialState: ConfigurationState = { - invitationMethod: false, + useLegacyInvitation: true, } const configurationSlice = createSlice({ name: 'configuration', initialState, reducers: { - setinvitationMethod: (state, action) => { - state.invitationMethod = action.payload === 'oob' ? true : false + setLegacyInvitation: (state, action) => { + state.useLegacyInvitation = action.payload }, }, }) -export const { setinvitationMethod } = configurationSlice.actions +export const { setLegacyInvitation } = configurationSlice.actions export default configurationSlice.reducer diff --git a/client/src/slices/connection/connectionThunks.ts b/client/src/slices/connection/connectionThunks.ts index dc89ddf3..0c11b02d 100644 --- a/client/src/slices/connection/connectionThunks.ts +++ b/client/src/slices/connection/connectionThunks.ts @@ -1,4 +1,4 @@ -import type { Entity } from '../../slices/types' +import type { CreateInvitationProps } from '../../slices/types' import { createAsyncThunk } from '@reduxjs/toolkit' @@ -14,9 +14,15 @@ export const fetchConnectionByOutOfBandId = createAsyncThunk('connection/fetchBy return response.data }) -export const createInvitation = createAsyncThunk('connection/createInvitation', async (entity?: Entity) => { - const response = entity?.invitationMethod - ? await Api.createOobInvitation(entity?.name, entity?.imageUrl) - : await Api.createLegacyInvitation(entity?.name, entity?.imageUrl) - return response.data -}) +export const createInvitation = createAsyncThunk( + 'connection/createInvitation', + async (createInvitationOptions?: CreateInvitationProps) => { + const entity = createInvitationOptions?.entity + + const response = createInvitationOptions?.useLegacyInvitation + ? await Api.createLegacyInvitation(entity?.name, entity?.imageUrl) + : await Api.createOobInvitation(entity?.name, entity?.imageUrl) + + return response.data + } +) diff --git a/client/src/slices/types.ts b/client/src/slices/types.ts index 9c49ccf2..82c48a62 100644 --- a/client/src/slices/types.ts +++ b/client/src/slices/types.ts @@ -98,7 +98,11 @@ export interface Entity { name: string icon: string imageUrl?: string - invitationMethod?: boolean +} + +export interface CreateInvitationProps { + entity?: Entity + useLegacyInvitation?: boolean } export interface Colors { diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index 41997059..79bff1bb 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -6,7 +6,7 @@ import Confetti from 'react-confetti' import { confettiFade } from '../FramerAnimations' import { useAppDispatch } from '../hooks/hooks' import { fetchAllCharacters } from '../slices/characters/charactersThunks' -import { setinvitationMethod } from '../slices/configuration/configurationSlice' +import { setLegacyInvitation } from '../slices/configuration/configurationSlice' import { usePreferences } from '../slices/preferences/preferencesSelectors' import { resetDashboard, setDarkMode } from '../slices/preferences/preferencesSlice' import { fetchWallets } from '../slices/wallets/walletsThunks' @@ -155,7 +155,7 @@ export const KBar: React.FunctionComponent = ({ children }) = keywords: 'invitation-method-oob', section: '', perform: () => { - dispatch(setinvitationMethod('oob')) + dispatch(setLegacyInvitation(false)) }, parent: 'invitation-method', }, @@ -165,7 +165,7 @@ export const KBar: React.FunctionComponent = ({ children }) = keywords: 'invitation-method-legacy', section: '', perform: () => { - dispatch(setinvitationMethod('legacy')) + dispatch(setLegacyInvitation(true)) }, parent: 'invitation-method', }, diff --git a/cypress/e2e/usecase_page.cy.ts b/cypress/e2e/usecase_page.cy.ts index 35417a6b..55824bc6 100644 --- a/cypress/e2e/usecase_page.cy.ts +++ b/cypress/e2e/usecase_page.cy.ts @@ -58,7 +58,7 @@ describe('UseCase Page', () => { cy.get('[data-cy=select-use-case]').first().click() - cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') + // cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') cy.get('[data-cy=start-container]') cy.get('[data-cy=small-button]').click() From 8417fc940069dd82fd5fc3cc6f332b266507dd55 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Wed, 28 Sep 2022 08:06:58 +0100 Subject: [PATCH 07/25] Update client/src/utils/KBar.tsx Co-authored-by: Jan --- client/src/utils/KBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index 79bff1bb..531942a1 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -79,7 +79,7 @@ export const KBar: React.FunctionComponent = ({ children }) = parent: 'configuration', }, { - id: 'BCovrin', + id: 'bcovrin', name: 'BCovrin', keywords: 'BCovrin', section: '', From 14cc3046feaed1eb0da778f6eb9aabb540b9a9a4 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Wed, 28 Sep 2022 08:07:22 +0100 Subject: [PATCH 08/25] Update client/src/slices/configuration/configurationSlice.ts Co-authored-by: Jan --- client/src/slices/configuration/configurationSlice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/slices/configuration/configurationSlice.ts b/client/src/slices/configuration/configurationSlice.ts index c8c114bf..6b1420dc 100644 --- a/client/src/slices/configuration/configurationSlice.ts +++ b/client/src/slices/configuration/configurationSlice.ts @@ -12,7 +12,7 @@ const configurationSlice = createSlice({ name: 'configuration', initialState, reducers: { - setLegacyInvitation: (state, action) => { + setUseLegacyInvitation: (state, action) => { state.useLegacyInvitation = action.payload }, }, From 1840c079cde442b8ace1b29dd32dad0107db7071 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Wed, 28 Sep 2022 08:12:41 +0100 Subject: [PATCH 09/25] fix: renamed Bcovrin menu object and setLegacyInvitation method Signed-off-by: Jim Ezesinachi --- .../src/slices/configuration/configurationSlice.ts | 2 +- client/src/utils/KBar.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/src/slices/configuration/configurationSlice.ts b/client/src/slices/configuration/configurationSlice.ts index 6b1420dc..36d39d87 100644 --- a/client/src/slices/configuration/configurationSlice.ts +++ b/client/src/slices/configuration/configurationSlice.ts @@ -18,6 +18,6 @@ const configurationSlice = createSlice({ }, }) -export const { setLegacyInvitation } = configurationSlice.actions +export const { setUseLegacyInvitation } = configurationSlice.actions export default configurationSlice.reducer diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index 531942a1..6301db9e 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -6,7 +6,7 @@ import Confetti from 'react-confetti' import { confettiFade } from '../FramerAnimations' import { useAppDispatch } from '../hooks/hooks' import { fetchAllCharacters } from '../slices/characters/charactersThunks' -import { setLegacyInvitation } from '../slices/configuration/configurationSlice' +import { setUseLegacyInvitation } from '../slices/configuration/configurationSlice' import { usePreferences } from '../slices/preferences/preferencesSelectors' import { resetDashboard, setDarkMode } from '../slices/preferences/preferencesSlice' import { fetchWallets } from '../slices/wallets/walletsThunks' @@ -80,11 +80,11 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'bcovrin', - name: 'BCovrin', - keywords: 'BCovrin', + name: 'BCovrin Test', + keywords: 'bcovrin', section: '', perform: () => { - alert('BCovrin ledger selected!') + alert('BCovrin Test ledger selected!') }, parent: 'ledger', }, @@ -155,7 +155,7 @@ export const KBar: React.FunctionComponent = ({ children }) = keywords: 'invitation-method-oob', section: '', perform: () => { - dispatch(setLegacyInvitation(false)) + dispatch(setUseLegacyInvitation(false)) }, parent: 'invitation-method', }, @@ -165,7 +165,7 @@ export const KBar: React.FunctionComponent = ({ children }) = keywords: 'invitation-method-legacy', section: '', perform: () => { - dispatch(setLegacyInvitation(true)) + dispatch(setUseLegacyInvitation(true)) }, parent: 'invitation-method', }, From 29b4a9193640d22e5f44e4fae8e8af0ae600acd8 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Wed, 28 Sep 2022 09:13:15 +0100 Subject: [PATCH 10/25] fix: actions menu and ConfigurationSlice Signed-off-by: Jim Ezesinachi --- .../onboarding/steps/SetupConnection.tsx | 4 +- .../pages/useCase/steps/StepConnection.tsx | 4 +- .../configuration/configurationSlice.ts | 10 ++--- .../src/slices/connection/connectionThunks.ts | 2 +- client/src/slices/types.ts | 2 +- client/src/utils/KBar.tsx | 40 +++++++++---------- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/client/src/pages/onboarding/steps/SetupConnection.tsx b/client/src/pages/onboarding/steps/SetupConnection.tsx index 7bf0d639..fedc9cc6 100644 --- a/client/src/pages/onboarding/steps/SetupConnection.tsx +++ b/client/src/pages/onboarding/steps/SetupConnection.tsx @@ -37,10 +37,10 @@ export const SetupConnection: React.FC = ({ }) => { const dispatch = useAppDispatch() const isCompleted = connectionState === 'response-sent' || connectionState === 'completed' - const { useLegacyInvitation } = useConfiguration() + const { useLegacyInvitations } = useConfiguration() useEffect(() => { - if (!isCompleted) dispatch(createInvitation({ useLegacyInvitation })) + if (!isCompleted) dispatch(createInvitation({ useLegacyInvitations })) }, []) useEffect(() => { diff --git a/client/src/pages/useCase/steps/StepConnection.tsx b/client/src/pages/useCase/steps/StepConnection.tsx index e3996bd1..35c356d8 100644 --- a/client/src/pages/useCase/steps/StepConnection.tsx +++ b/client/src/pages/useCase/steps/StepConnection.tsx @@ -28,11 +28,11 @@ export const StepConnection: React.FC = ({ step, connection, entity }) => const dispatch = useAppDispatch() const { id, state, invitationUrl, outOfBandId } = connection const isCompleted = state === 'response-sent' || state === 'completed' - const { useLegacyInvitation } = useConfiguration() + const { useLegacyInvitations } = useConfiguration() useEffect(() => { if (!isCompleted) { - dispatch(createInvitation({ entity, useLegacyInvitation })) + dispatch(createInvitation({ entity, useLegacyInvitations })) } }, []) diff --git a/client/src/slices/configuration/configurationSlice.ts b/client/src/slices/configuration/configurationSlice.ts index 36d39d87..ade33c95 100644 --- a/client/src/slices/configuration/configurationSlice.ts +++ b/client/src/slices/configuration/configurationSlice.ts @@ -1,23 +1,23 @@ import { createSlice } from '@reduxjs/toolkit' interface ConfigurationState { - useLegacyInvitation: boolean + useLegacyInvitations: boolean } const initialState: ConfigurationState = { - useLegacyInvitation: true, + useLegacyInvitations: true, } const configurationSlice = createSlice({ name: 'configuration', initialState, reducers: { - setUseLegacyInvitation: (state, action) => { - state.useLegacyInvitation = action.payload + setUseLegacyInvitations: (state, action) => { + state.useLegacyInvitations = action.payload }, }, }) -export const { setUseLegacyInvitation } = configurationSlice.actions +export const { setUseLegacyInvitations } = configurationSlice.actions export default configurationSlice.reducer diff --git a/client/src/slices/connection/connectionThunks.ts b/client/src/slices/connection/connectionThunks.ts index 0c11b02d..24e52361 100644 --- a/client/src/slices/connection/connectionThunks.ts +++ b/client/src/slices/connection/connectionThunks.ts @@ -19,7 +19,7 @@ export const createInvitation = createAsyncThunk( async (createInvitationOptions?: CreateInvitationProps) => { const entity = createInvitationOptions?.entity - const response = createInvitationOptions?.useLegacyInvitation + const response = createInvitationOptions?.useLegacyInvitations ? await Api.createLegacyInvitation(entity?.name, entity?.imageUrl) : await Api.createOobInvitation(entity?.name, entity?.imageUrl) diff --git a/client/src/slices/types.ts b/client/src/slices/types.ts index 82c48a62..eb216566 100644 --- a/client/src/slices/types.ts +++ b/client/src/slices/types.ts @@ -102,7 +102,7 @@ export interface Entity { export interface CreateInvitationProps { entity?: Entity - useLegacyInvitation?: boolean + useLegacyInvitations?: boolean } export interface Colors { diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index 6301db9e..e3643e32 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -6,7 +6,7 @@ import Confetti from 'react-confetti' import { confettiFade } from '../FramerAnimations' import { useAppDispatch } from '../hooks/hooks' import { fetchAllCharacters } from '../slices/characters/charactersThunks' -import { setUseLegacyInvitation } from '../slices/configuration/configurationSlice' +import { setUseLegacyInvitations } from '../slices/configuration/configurationSlice' import { usePreferences } from '../slices/preferences/preferencesSelectors' import { resetDashboard, setDarkMode } from '../slices/preferences/preferencesSlice' import { fetchWallets } from '../slices/wallets/walletsThunks' @@ -91,14 +91,14 @@ export const KBar: React.FunctionComponent = ({ children }) = { id: 'issue-credential-protocol-version', name: 'Select credential protocol version', - keywords: 'issue-credential-protocol-version', + keywords: 'issue credential protocol version', section: '', parent: 'configuration', }, { id: 'issue-credential-protocol-version-1', name: 'v1', - keywords: 'issue-credential-protocol-version-1', + keywords: 'issue credential protocol version 1', section: '', perform: () => { alert('Credential Protocol Version 1 selected') @@ -108,7 +108,7 @@ export const KBar: React.FunctionComponent = ({ children }) = { id: 'issue-credential-protocol-version-2', name: 'v2', - keywords: 'issue-credential-protocol-version-2', + keywords: 'issue credential protocol version 2', section: '', perform: () => { alert('Credential Protocol Version 2 selected') @@ -118,14 +118,14 @@ export const KBar: React.FunctionComponent = ({ children }) = { id: 'present-proof-protocol-version', name: 'Select proof protocol version', - keywords: 'present-proof-protocol-version', + keywords: 'present proof protocol version', section: '', parent: 'configuration', }, { id: 'present-proof-protocol-version-1', name: 'v1', - keywords: 'present-proof-protocol-version-1', + keywords: 'present proof protocol version 1', section: '', perform: () => { alert('Proof Protocol Version 1 selected') @@ -135,7 +135,7 @@ export const KBar: React.FunctionComponent = ({ children }) = { id: 'present-proof-protocol-version-2', name: 'v2', - keywords: 'present-proof-protocol-version-2', + keywords: 'present proof protocol version 2', section: '', perform: () => { alert('Proof Protocol Version 2 selected') @@ -143,31 +143,31 @@ export const KBar: React.FunctionComponent = ({ children }) = parent: 'present-proof-protocol-version', }, { - id: 'invitation-method', - name: 'Select invitation method', - keywords: 'invitation-method', + id: 'invitation-type', + name: 'Change connection invitation type', + keywords: 'invitation type', section: '', parent: 'configuration', }, { - id: 'invitation-method-oob', - name: 'Out-of-band invitation', - keywords: 'invitation-method-oob', + id: 'invitation-type-oob', + name: 'Out Of Band', + keywords: 'invitation type oob', section: '', perform: () => { - dispatch(setUseLegacyInvitation(false)) + dispatch(setUseLegacyInvitations(false)) }, - parent: 'invitation-method', + parent: 'invitation-type', }, { - id: 'invitation-method-legacy', - name: 'Legacy invitation', - keywords: 'invitation-method-legacy', + id: 'invitation-type-legacy', + name: 'Legacy (RFC 0160)', + keywords: 'invitation type legacy', section: '', perform: () => { - dispatch(setUseLegacyInvitation(true)) + dispatch(setUseLegacyInvitations(true)) }, - parent: 'invitation-method', + parent: 'invitation-type', }, { id: 'theme', From d3c5d3eb15fcd6fb1ad7a7537c9d4c5597c6a5e1 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Wed, 28 Sep 2022 13:54:20 +0100 Subject: [PATCH 11/25] fix: added state logic for credential protocol version switch Signed-off-by: Jim Ezesinachi --- client/src/api/CredentialApi.ts | 8 ++++++-- .../pages/onboarding/steps/AcceptCredential.tsx | 8 ++++++-- client/src/pages/useCase/steps/StepCredential.tsx | 10 ++++++++-- client/src/slices/credentials/credentialsSlice.ts | 7 ++++++- client/src/slices/credentials/credentialsThunks.ts | 4 ++-- client/src/utils/KBar.tsx | 14 +++++++++----- 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/client/src/api/CredentialApi.ts b/client/src/api/CredentialApi.ts index 77051c69..b1e41c70 100644 --- a/client/src/api/CredentialApi.ts +++ b/client/src/api/CredentialApi.ts @@ -3,9 +3,13 @@ import type { AxiosResponse } from 'axios' import { apiCall } from './BaseUrl' -export const issueCredential = async (connectionId: string, data: CredentialData): Promise => { +export const issueCredential = async ( + connectionId: string, + data: CredentialData, + protocolVersion: 'v1' | 'v2' +): Promise => { return apiCall.post(`/credentials/offer-credential`, { - protocolVersion: 'v1', + protocolVersion: protocolVersion, connectionId: connectionId, credentialFormats: { indy: { diff --git a/client/src/pages/onboarding/steps/AcceptCredential.tsx b/client/src/pages/onboarding/steps/AcceptCredential.tsx index 563c4d21..8f9c6271 100644 --- a/client/src/pages/onboarding/steps/AcceptCredential.tsx +++ b/client/src/pages/onboarding/steps/AcceptCredential.tsx @@ -49,10 +49,11 @@ export const AcceptCredential: React.FC = ({ content, connectionId, crede (x) => x.state === 'credential-issued' || x.state === 'done' ) + let { protocolVersion } = useCredentials() useEffect(() => { if (credentials.length === 0) { currentCharacter.starterCredentials.forEach((item) => { - dispatch(issueCredential({ connectionId: connectionId, cred: item })) + dispatch(issueCredential({ connectionId: connectionId, cred: item, protocolVersion })) trackEvent('credential-issued') }) setCredentialsIssued(true) @@ -97,6 +98,8 @@ export const AcceptCredential: React.FC = ({ content, connectionId, crede dispatch({ type: 'demo/RESET' }) } + protocolVersion = useCredentials().protocolVersion + const sendNewCredentials = () => { credentials.forEach((cred) => { if (cred.state !== 'credential-issued' && cred.state !== 'done') { @@ -110,7 +113,8 @@ export const AcceptCredential: React.FC = ({ content, connectionId, crede ) }) - if (newCredential) dispatch(issueCredential({ connectionId: connectionId, cred: newCredential })) + if (newCredential) + dispatch(issueCredential({ connectionId: connectionId, cred: newCredential, protocolVersion })) } }) closeFailedRequestModal() diff --git a/client/src/pages/useCase/steps/StepCredential.tsx b/client/src/pages/useCase/steps/StepCredential.tsx index c282ca33..4e86320b 100644 --- a/client/src/pages/useCase/steps/StepCredential.tsx +++ b/client/src/pages/useCase/steps/StepCredential.tsx @@ -11,6 +11,7 @@ import { ActionCTA } from '../../../components/ActionCTA' import { Loader } from '../../../components/Loader' import { useAppDispatch } from '../../../hooks/hooks' import { useInterval } from '../../../hooks/useInterval' +import { useCredentials } from '../../../slices/credentials/credentialsSelectors' import { deleteCredentialById, fetchCredentialsByConId, @@ -42,6 +43,8 @@ export const StepCredential: React.FC = ({ step, connectionId, issueCrede ) const [issuedCredData, setIssuedCredData] = useState([]) + let { protocolVersion } = useCredentials() + const issueCreds = () => { // get attributes from proof let attributes: Attribute[] = [] @@ -60,7 +63,7 @@ export const StepCredential: React.FC = ({ step, connectionId, issueCrede // issue credentials credentialData.forEach((item) => { - dispatch(issueCredential({ connectionId: connectionId, cred: item })) + dispatch(issueCredential({ connectionId: connectionId, cred: item, protocolVersion })) trackEvent('credential-issued') }) } @@ -76,6 +79,8 @@ export const StepCredential: React.FC = ({ step, connectionId, issueCrede !credentialsAccepted ? 1000 : null ) + protocolVersion = useCredentials().protocolVersion + const sendNewCredentials = () => { credentials.forEach((cred) => { if (cred.state !== 'credential-issued' && cred.state !== 'done') { @@ -88,7 +93,8 @@ export const StepCredential: React.FC = ({ step, connectionId, issueCrede credClass.metadata.get('_internal/indyCredential')?.credentialDefinitionId ) }) - if (newCredential) dispatch(issueCredential({ connectionId: connectionId, cred: newCredential })) + if (newCredential) + dispatch(issueCredential({ connectionId: connectionId, cred: newCredential, protocolVersion })) } }) closeFailedRequestModal() diff --git a/client/src/slices/credentials/credentialsSlice.ts b/client/src/slices/credentials/credentialsSlice.ts index 62234e36..510cb5b2 100644 --- a/client/src/slices/credentials/credentialsSlice.ts +++ b/client/src/slices/credentials/credentialsSlice.ts @@ -15,6 +15,7 @@ interface CredentialState { issuedCredentials: CredentialExchangeRecord[] isLoading: boolean isIssueCredentialLoading: boolean + protocolVersion: 'v1' | 'v2' error: SerializedError | undefined } @@ -23,6 +24,7 @@ const initialState: CredentialState = { issuedCredentials: [], isLoading: true, isIssueCredentialLoading: true, + protocolVersion: 'v1', error: undefined, } @@ -36,6 +38,9 @@ const credentialSlice = createSlice({ ) state.credentials = [] }, + setProtocolVersion: (state, action) => { + state.protocolVersion = action.payload + }, }, extraReducers: (builder) => { builder @@ -90,6 +95,6 @@ const credentialSlice = createSlice({ }, }) -export const { clearCredentials } = credentialSlice.actions +export const { clearCredentials, setProtocolVersion } = credentialSlice.actions export default credentialSlice.reducer diff --git a/client/src/slices/credentials/credentialsThunks.ts b/client/src/slices/credentials/credentialsThunks.ts index 7035b06b..70c0ff07 100644 --- a/client/src/slices/credentials/credentialsThunks.ts +++ b/client/src/slices/credentials/credentialsThunks.ts @@ -11,8 +11,8 @@ export const fetchCredentialsByConId = createAsyncThunk('credentials/fetchAllByC export const issueCredential = createAsyncThunk( 'credentials/issueCredential', - async (data: { connectionId: string; cred: CredentialData }) => { - const response = await Api.issueCredential(data.connectionId, data.cred) + async (data: { connectionId: string; cred: CredentialData; protocolVersion: 'v1' | 'v2' }) => { + const response = await Api.issueCredential(data.connectionId, data.cred, data.protocolVersion) return response.data } ) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index e3643e32..b3f1f000 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -1,3 +1,5 @@ +import type { ActionImpl } from 'kbar' + import { AnimatePresence, motion } from 'framer-motion' import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch } from 'kbar' import { useEffect, useState } from 'react' @@ -7,6 +9,7 @@ import { confettiFade } from '../FramerAnimations' import { useAppDispatch } from '../hooks/hooks' import { fetchAllCharacters } from '../slices/characters/charactersThunks' import { setUseLegacyInvitations } from '../slices/configuration/configurationSlice' +import { setProtocolVersion } from '../slices/credentials/credentialsSlice' import { usePreferences } from '../slices/preferences/preferencesSelectors' import { resetDashboard, setDarkMode } from '../slices/preferences/preferencesSlice' import { fetchWallets } from '../slices/wallets/walletsThunks' @@ -97,21 +100,21 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'issue-credential-protocol-version-1', - name: 'v1', + name: 'V1', keywords: 'issue credential protocol version 1', section: '', perform: () => { - alert('Credential Protocol Version 1 selected') + dispatch(setProtocolVersion('v1')) }, parent: 'issue-credential-protocol-version', }, { id: 'issue-credential-protocol-version-2', - name: 'v2', + name: 'V2', keywords: 'issue credential protocol version 2', section: '', perform: () => { - alert('Credential Protocol Version 2 selected') + dispatch(setProtocolVersion('v2')) }, parent: 'issue-credential-protocol-version', }, @@ -164,9 +167,10 @@ export const KBar: React.FunctionComponent = ({ children }) = name: 'Legacy (RFC 0160)', keywords: 'invitation type legacy', section: '', - perform: () => { + perform: (action: ActionImpl) => { dispatch(setUseLegacyInvitations(true)) }, + isActive: true, parent: 'invitation-type', }, { From 18234fc35407cfad7eef92e374e845571cfdc937 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Thu, 29 Sep 2022 09:57:10 +0100 Subject: [PATCH 12/25] feat: moved ConfigurationSlice logic into ConnectionSlice and added reset logic to config menu options Signed-off-by: Jim Ezesinachi --- .../onboarding/steps/SetupConnection.tsx | 4 ++-- .../pages/useCase/steps/StepConnection.tsx | 4 ++-- .../configuration/configurationSelectors.ts | 5 ---- .../configuration/configurationSlice.ts | 23 ------------------- .../src/slices/connection/connectionSlice.ts | 7 +++++- client/src/slices/index.ts | 2 -- client/src/utils/KBar.tsx | 13 +++++++---- 7 files changed, 19 insertions(+), 39 deletions(-) delete mode 100644 client/src/slices/configuration/configurationSelectors.ts delete mode 100644 client/src/slices/configuration/configurationSlice.ts diff --git a/client/src/pages/onboarding/steps/SetupConnection.tsx b/client/src/pages/onboarding/steps/SetupConnection.tsx index fedc9cc6..ce02193e 100644 --- a/client/src/pages/onboarding/steps/SetupConnection.tsx +++ b/client/src/pages/onboarding/steps/SetupConnection.tsx @@ -10,7 +10,7 @@ import { Loader } from '../../../components/Loader' import { QRCode } from '../../../components/QRCode' import { useAppDispatch } from '../../../hooks/hooks' import { useInterval } from '../../../hooks/useInterval' -import { useConfiguration } from '../../../slices/configuration/configurationSelectors' +import { useConnection } from '../../../slices/connection/connectionSelectors' import { createInvitation, fetchConnectionById, @@ -37,7 +37,7 @@ export const SetupConnection: React.FC = ({ }) => { const dispatch = useAppDispatch() const isCompleted = connectionState === 'response-sent' || connectionState === 'completed' - const { useLegacyInvitations } = useConfiguration() + const { useLegacyInvitations } = useConnection() useEffect(() => { if (!isCompleted) dispatch(createInvitation({ useLegacyInvitations })) diff --git a/client/src/pages/useCase/steps/StepConnection.tsx b/client/src/pages/useCase/steps/StepConnection.tsx index 35c356d8..c930d982 100644 --- a/client/src/pages/useCase/steps/StepConnection.tsx +++ b/client/src/pages/useCase/steps/StepConnection.tsx @@ -10,7 +10,7 @@ import { fade, fadeX } from '../../../FramerAnimations' import { QRCode } from '../../../components/QRCode' import { useAppDispatch } from '../../../hooks/hooks' import { useInterval } from '../../../hooks/useInterval' -import { useConfiguration } from '../../../slices/configuration/configurationSelectors' +import { useConnection } from '../../../slices/connection/connectionSelectors' import { createInvitation, fetchConnectionById, @@ -28,7 +28,7 @@ export const StepConnection: React.FC = ({ step, connection, entity }) => const dispatch = useAppDispatch() const { id, state, invitationUrl, outOfBandId } = connection const isCompleted = state === 'response-sent' || state === 'completed' - const { useLegacyInvitations } = useConfiguration() + const { useLegacyInvitations } = useConnection() useEffect(() => { if (!isCompleted) { diff --git a/client/src/slices/configuration/configurationSelectors.ts b/client/src/slices/configuration/configurationSelectors.ts deleted file mode 100644 index 6bf01be4..00000000 --- a/client/src/slices/configuration/configurationSelectors.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { RootState } from '../../store/configureStore' - -import { useSelector } from 'react-redux' - -export const useConfiguration = () => useSelector((state: RootState) => state.configuration) diff --git a/client/src/slices/configuration/configurationSlice.ts b/client/src/slices/configuration/configurationSlice.ts deleted file mode 100644 index ade33c95..00000000 --- a/client/src/slices/configuration/configurationSlice.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit' - -interface ConfigurationState { - useLegacyInvitations: boolean -} - -const initialState: ConfigurationState = { - useLegacyInvitations: true, -} - -const configurationSlice = createSlice({ - name: 'configuration', - initialState, - reducers: { - setUseLegacyInvitations: (state, action) => { - state.useLegacyInvitations = action.payload - }, - }, -}) - -export const { setUseLegacyInvitations } = configurationSlice.actions - -export default configurationSlice.reducer diff --git a/client/src/slices/connection/connectionSlice.ts b/client/src/slices/connection/connectionSlice.ts index ad2a9749..caa1eee6 100644 --- a/client/src/slices/connection/connectionSlice.ts +++ b/client/src/slices/connection/connectionSlice.ts @@ -8,6 +8,7 @@ export interface ConnectionState { invitationUrl?: string outOfBandId?: string isLoading: boolean + useLegacyInvitations: boolean } const initialState: ConnectionState = { @@ -16,6 +17,7 @@ const initialState: ConnectionState = { invitationUrl: undefined, outOfBandId: undefined, isLoading: false, + useLegacyInvitations: true, } const connectionSlice = createSlice({ @@ -28,6 +30,9 @@ const connectionSlice = createSlice({ state.invitationUrl = undefined state.isLoading = false }, + setUseLegacyInvitations: (state, action) => { + state.useLegacyInvitations = action.payload + }, }, extraReducers: (builder) => { builder @@ -65,6 +70,6 @@ const connectionSlice = createSlice({ }, }) -export const { clearConnection } = connectionSlice.actions +export const { clearConnection, setUseLegacyInvitations } = connectionSlice.actions export default connectionSlice.reducer diff --git a/client/src/slices/index.ts b/client/src/slices/index.ts index d9f0c047..fd93cf28 100644 --- a/client/src/slices/index.ts +++ b/client/src/slices/index.ts @@ -1,7 +1,6 @@ import { combineReducers } from 'redux' import charactersSlice from './characters/charactersSlice' -import configurationSlice from './configuration/configurationSlice' import connectionSlice from './connection/connectionSlice' import credentialsSlice from './credentials/credentialsSlice' import onboardingSlice from './onboarding/onboardingSlice' @@ -20,7 +19,6 @@ const rootReducer = combineReducers({ credentials: credentialsSlice, onboarding: onboardingSlice, preferences: preferencesSlice, - configuration: configurationSlice, proof: proofSlice, section: sectionSlice, useCases: useCaseSlice, diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index b3f1f000..dda9d9b2 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -1,5 +1,3 @@ -import type { ActionImpl } from 'kbar' - import { AnimatePresence, motion } from 'framer-motion' import { KBarProvider, KBarPortal, KBarPositioner, KBarAnimator, KBarSearch } from 'kbar' import { useEffect, useState } from 'react' @@ -8,7 +6,7 @@ import Confetti from 'react-confetti' import { confettiFade } from '../FramerAnimations' import { useAppDispatch } from '../hooks/hooks' import { fetchAllCharacters } from '../slices/characters/charactersThunks' -import { setUseLegacyInvitations } from '../slices/configuration/configurationSlice' +import { setUseLegacyInvitations } from '../slices/connection/connectionSlice' import { setProtocolVersion } from '../slices/credentials/credentialsSlice' import { usePreferences } from '../slices/preferences/preferencesSelectors' import { resetDashboard, setDarkMode } from '../slices/preferences/preferencesSlice' @@ -88,6 +86,7 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { alert('BCovrin Test ledger selected!') + dispatch({ type: 'demo/RESET' }) }, parent: 'ledger', }, @@ -105,6 +104,7 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { dispatch(setProtocolVersion('v1')) + dispatch({ type: 'demo/RESET' }) }, parent: 'issue-credential-protocol-version', }, @@ -115,6 +115,7 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { dispatch(setProtocolVersion('v2')) + dispatch({ type: 'demo/RESET' }) }, parent: 'issue-credential-protocol-version', }, @@ -132,6 +133,7 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { alert('Proof Protocol Version 1 selected') + dispatch({ type: 'demo/RESET' }) }, parent: 'present-proof-protocol-version', }, @@ -142,6 +144,7 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { alert('Proof Protocol Version 2 selected') + dispatch({ type: 'demo/RESET' }) }, parent: 'present-proof-protocol-version', }, @@ -159,6 +162,7 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { dispatch(setUseLegacyInvitations(false)) + dispatch({ type: 'demo/RESET' }) }, parent: 'invitation-type', }, @@ -167,8 +171,9 @@ export const KBar: React.FunctionComponent = ({ children }) = name: 'Legacy (RFC 0160)', keywords: 'invitation type legacy', section: '', - perform: (action: ActionImpl) => { + perform: () => { dispatch(setUseLegacyInvitations(true)) + dispatch({ type: 'demo/RESET' }) }, isActive: true, parent: 'invitation-type', From cc61008b3a7ce2bea32f2bfc89372a424dbd20c1 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Mon, 3 Oct 2022 13:11:39 +0100 Subject: [PATCH 13/25] test: added oob invitation test and removed demo reset call in onboarding page Signed-off-by: Jim Ezesinachi --- .../pages/landing/components/MainSection.tsx | 1 + .../src/pages/onboarding/OnboardingPage.tsx | 1 - client/src/utils/KBar.tsx | 9 -- client/src/utils/RenderResults.tsx | 1 + ...s => legacy_invitation_usecase_page.cy.ts} | 4 +- cypress/e2e/oob_invitation_usecase.cy.ts | 142 ++++++++++++++++++ 6 files changed, 146 insertions(+), 12 deletions(-) rename cypress/e2e/{usecase_page.cy.ts => legacy_invitation_usecase_page.cy.ts} (97%) create mode 100644 cypress/e2e/oob_invitation_usecase.cy.ts diff --git a/client/src/pages/landing/components/MainSection.tsx b/client/src/pages/landing/components/MainSection.tsx index 4bb9a8cb..27b5ba75 100644 --- a/client/src/pages/landing/components/MainSection.tsx +++ b/client/src/pages/landing/components/MainSection.tsx @@ -83,6 +83,7 @@ export const MainSection: React.FC = () => {
{ dispatch(fetchAllUseCasesByCharId(currentCharacter.id)) navigate('/dashboard') } else { - dispatch({ type: 'demo/RESET' }) dispatch(fetchWallets()) dispatch(fetchAllCharacters()) setMounted(true) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index dda9d9b2..8b940d34 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -68,7 +68,6 @@ export const KBar: React.FunctionComponent = ({ children }) = { id: 'configuration', name: 'Choose demo configuration options...', - shortcut: ['o'], keywords: 'configuration', section: 'Configuration', }, @@ -86,7 +85,6 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { alert('BCovrin Test ledger selected!') - dispatch({ type: 'demo/RESET' }) }, parent: 'ledger', }, @@ -104,7 +102,6 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { dispatch(setProtocolVersion('v1')) - dispatch({ type: 'demo/RESET' }) }, parent: 'issue-credential-protocol-version', }, @@ -115,7 +112,6 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { dispatch(setProtocolVersion('v2')) - dispatch({ type: 'demo/RESET' }) }, parent: 'issue-credential-protocol-version', }, @@ -133,7 +129,6 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { alert('Proof Protocol Version 1 selected') - dispatch({ type: 'demo/RESET' }) }, parent: 'present-proof-protocol-version', }, @@ -144,7 +139,6 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { alert('Proof Protocol Version 2 selected') - dispatch({ type: 'demo/RESET' }) }, parent: 'present-proof-protocol-version', }, @@ -162,7 +156,6 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { dispatch(setUseLegacyInvitations(false)) - dispatch({ type: 'demo/RESET' }) }, parent: 'invitation-type', }, @@ -173,9 +166,7 @@ export const KBar: React.FunctionComponent = ({ children }) = section: '', perform: () => { dispatch(setUseLegacyInvitations(true)) - dispatch({ type: 'demo/RESET' }) }, - isActive: true, parent: 'invitation-type', }, { diff --git a/client/src/utils/RenderResults.tsx b/client/src/utils/RenderResults.tsx index 37d865c3..53d58415 100644 --- a/client/src/utils/RenderResults.tsx +++ b/client/src/utils/RenderResults.tsx @@ -28,6 +28,7 @@ const ResultItem = forwardRef( return (
{ const record = response.body.find((x) => x.threadId === threadId && x.state === 'request-received') cy.request('POST', `${TEST_AGENT_URL}/proofs/${record.id}/accept-request`).then(() => { // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(3000) // wait for the test agent request to be processed + cy.wait(10000) // wait for the test agent request to be processed cy.get('[data-cy=section') cy.get('[data-cy="small-button"]').click() }) @@ -113,7 +113,7 @@ describe('UseCase Page', () => { cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(3000) // wait for the test agent request to be processed + cy.wait(10000) // wait for the test agent request to be processed cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { const cred = resp.body.find((x) => x.threadId === threadId) cy.wrap(cred).its('state').should('equal', 'done') diff --git a/cypress/e2e/oob_invitation_usecase.cy.ts b/cypress/e2e/oob_invitation_usecase.cy.ts new file mode 100644 index 00000000..564f22b0 --- /dev/null +++ b/cypress/e2e/oob_invitation_usecase.cy.ts @@ -0,0 +1,142 @@ +const API_URL = Cypress.env('apiUrl') +const TEST_AGENT_URL = 'http://localhost:9000' + +describe('UseCase Page', () => { + it('successfully completes school use case', () => { + cy.visit('/') + cy.get('[data-cy=try-demo-button]').click() + + const shortcut = Cypress.platform === 'darwin' ? 'command+k' : 'ctrl+k' + cy.get('body').type(`{${shortcut}}`) + cy.get('[data-cy=configuration]') + .click() + .get('[data-cy=invitation-type]') + .click() + .get('[data-cy=invitation-type-oob]') + .click() + + cy.get('[data-cy=next-onboarding-step]').click() + cy.get('[data-cy=use-wallet]').first().click() + cy.get('[data-cy=small-button]').click() + + cy.get('[data-cy=select-char]').first().click() + cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') + cy.get('[data-cy=next-onboarding-step]').click() + + cy.wait('@createInvitation').then((interception) => { + const body = { invitationUrl: interception.response?.body.invitationUrl, autoAcceptConnection: true } + + const oobId = interception.response?.body.outOfBandRecord.id + + cy.intercept('GET', `${API_URL}/connections?outOfBandId=${oobId}`).as('getConnectionRecord') + + cy.request('POST', `${TEST_AGENT_URL}/oob/receive-invitation-url`, body) + + cy.wait(['@getConnectionRecord']).then((inter) => { + const record = inter.response?.body[0] + cy.wrap(record).its('state').should('not.equal', 'invited') + }) + }) + + cy.intercept('POST', '/credentials/offer-credential').as('offerCredential') + + cy.get('[data-cy=next-onboarding-step]').click() + + cy.wait('@offerCredential').then((interception) => { + const connectionId = interception.response?.body.connectionId + const threadId = interception.response?.body.threadId + + cy.request('GET', `${TEST_AGENT_URL}/credentials/`).should((response) => { + const testAgentRecord = response.body.find( + (credentialRecord) => credentialRecord.threadId === threadId && credentialRecord.state === 'offer-received' + ) + + cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) + + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(3000) // wait for the test agent request to be processed + cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { + const cred = resp.body.find((credentialRecord) => credentialRecord.threadId === threadId) + cy.wrap(cred).its('state').should('equal', 'done') + }) + + cy.get('[data-cy="next-onboarding-step"]').click() + }) + }) + + cy.get('[data-cy=next-onboarding-step]').click() + cy.url().should('be.equal', `${Cypress.config('baseUrl')}/dashboard`) + + cy.get('[data-cy=select-use-case]').first().click() + + // cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') + cy.get('[data-cy=start-container]') + cy.get('[data-cy=small-button]').click() + + cy.wait('@createInvitation').then((interception) => { + const body = { invitationUrl: interception.response?.body.invitationUrl, autoAcceptConnection: true } + + const oobId = interception.response?.body.outOfBandRecord.id + + cy.intercept('GET', `${API_URL}/connections?outOfBandId=${oobId}`).as('getConnectionRecord') + + cy.request('POST', `${TEST_AGENT_URL}/oob/receive-invitation-url`, body) + + cy.wait(['@getConnectionRecord']).then((inter) => { + const record = inter.response?.body[0] + cy.wrap(record).its('state').should('not.equal', 'invited') + }) + }) + + cy.intercept('POST', `${API_URL}/proofs/request-proof`).as('createProof') + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.wait('@createProof').then((interception) => { + const threadId = interception.response?.body.threadId + cy.request('GET', `${TEST_AGENT_URL}/proofs/`).should((response) => { + const record = response.body.find((x) => x.threadId === threadId && x.state === 'request-received') + cy.request('POST', `${TEST_AGENT_URL}/proofs/${record.id}/accept-request`).then(() => { + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(5000) // wait for the test agent request to be processed + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + }) + }) + }) + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.intercept('POST', '/credentials/offer-credential').as('offerCredential') + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.wait('@offerCredential').then((interception) => { + const connectionId = interception.response?.body.connectionId + const threadId = interception.response?.body.threadId + + cy.request('GET', `${TEST_AGENT_URL}/credentials/`).should((response) => { + const testAgentRecord = response.body.find((x) => x.threadId === threadId && x.state === 'offer-received') + + cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) + + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(5000) // wait for the test agent request to be processed + cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { + const cred = resp.body.find((x) => x.threadId === threadId) + cy.wrap(cred).its('state').should('equal', 'done') + }) + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + }) + }) + + cy.get('[data-cy=end-container]') + cy.get('[data-cy=standard-button]').click() + cy.url().should('be.equal', `${Cypress.config('baseUrl')}/dashboard`) + }) +}) From 14dc22cb90ad713422e2028513979b51b007c58a Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Tue, 4 Oct 2022 09:12:06 +0100 Subject: [PATCH 14/25] Update cypress/e2e/legacy_invitation_usecase_page.cy.ts Co-authored-by: Jan --- cypress/e2e/legacy_invitation_usecase_page.cy.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/cypress/e2e/legacy_invitation_usecase_page.cy.ts b/cypress/e2e/legacy_invitation_usecase_page.cy.ts index 8691f5fc..a1c8028b 100644 --- a/cypress/e2e/legacy_invitation_usecase_page.cy.ts +++ b/cypress/e2e/legacy_invitation_usecase_page.cy.ts @@ -58,7 +58,6 @@ describe('UseCase Page', () => { cy.get('[data-cy=select-use-case]').first().click() - // cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') cy.get('[data-cy=start-container]') cy.get('[data-cy=small-button]').click() From 61dd6a35ba479af30e921b36374d88b289c87d53 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Tue, 4 Oct 2022 10:07:51 +0100 Subject: [PATCH 15/25] separated stage logic into demo/RESET and demo/resetState and removed unused items from K-menu Signed-off-by: Jim Ezesinachi --- client/src/App.tsx | 2 +- client/src/pages/dashboard/DashboardPage.tsx | 4 +- .../dashboard/components/ProfileCard.tsx | 2 +- .../pages/onboarding/OnboardingContainer.tsx | 4 +- .../onboarding/steps/AcceptCredential.tsx | 2 +- .../src/slices/characters/charactersSlice.ts | 4 + .../src/slices/connection/connectionSlice.ts | 6 ++ .../slices/credentials/credentialsSlice.ts | 6 ++ .../src/slices/onboarding/onboardingSlice.ts | 6 ++ .../slices/preferences/preferencesSlice.ts | 2 +- client/src/slices/proof/proofSlice.ts | 4 + client/src/slices/section/sectionSlice.ts | 11 ++- client/src/slices/useCases/useCasesSlice.ts | 4 + client/src/slices/wallets/walletsSlice.ts | 4 + client/src/utils/KBar.tsx | 88 +++++++++---------- .../e2e/legacy_invitation_usecase_page.cy.ts | 6 +- cypress/e2e/oob_invitation_usecase.cy.ts | 3 +- 17 files changed, 98 insertions(+), 60 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index fa51591a..2e0ecf6b 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -42,7 +42,7 @@ function App() { if (connectionDate && lastServerReset) { if (connectionDate < lastServerReset) { navigate('/') - dispatch({ type: 'demo/RESET' }) + dispatch({ type: 'demo/resetState' }) } } }, [connectionDate, lastServerReset]) diff --git a/client/src/pages/dashboard/DashboardPage.tsx b/client/src/pages/dashboard/DashboardPage.tsx index 7b1a2913..ead677fb 100644 --- a/client/src/pages/dashboard/DashboardPage.tsx +++ b/client/src/pages/dashboard/DashboardPage.tsx @@ -62,12 +62,12 @@ export const DashboardPage: React.FC = () => { const ERROR_DESCRIPTION = `That's not gone well. Please restart the demo.` const routeError = () => { navigate('/demo') - dispatch({ type: 'demo/RESET' }) + dispatch({ type: 'demo/resetState' }) } const completeDemo = () => { navigate('/') - dispatch({ type: 'demo/RESET' }) + dispatch({ type: 'demo/resetState' }) if (currentCharacter) trackEvent('demo-character-completed', { diff --git a/client/src/pages/dashboard/components/ProfileCard.tsx b/client/src/pages/dashboard/components/ProfileCard.tsx index b065f529..34a83367 100644 --- a/client/src/pages/dashboard/components/ProfileCard.tsx +++ b/client/src/pages/dashboard/components/ProfileCard.tsx @@ -22,7 +22,7 @@ export const ProfileCard: React.FC = ({ currentCharacter }) => { before you switch to another character.` const reset = () => { - dispatch({ type: 'demo/RESET' }) + dispatch({ type: 'demo/resetState' }) } const cancel = () => { diff --git a/client/src/pages/onboarding/OnboardingContainer.tsx b/client/src/pages/onboarding/OnboardingContainer.tsx index 0bf3098b..f1f74b51 100644 --- a/client/src/pages/onboarding/OnboardingContainer.tsx +++ b/client/src/pages/onboarding/OnboardingContainer.tsx @@ -219,7 +219,7 @@ export const OnboardingContainer: React.FC = ({ dispatch(fetchAllUseCasesByCharId(currentCharacter.id)) } else { // something went wrong so reset - dispatch({ type: 'demo/RESET' }) + dispatch({ type: 'demo/resetState' }) } } @@ -235,7 +235,7 @@ export const OnboardingContainer: React.FC = ({ const leave = () => { navigate('/') - dispatch({ type: 'demo/RESET' }) + dispatch({ type: 'demo/resetState' }) } return ( diff --git a/client/src/pages/onboarding/steps/AcceptCredential.tsx b/client/src/pages/onboarding/steps/AcceptCredential.tsx index 8f9c6271..19a03096 100644 --- a/client/src/pages/onboarding/steps/AcceptCredential.tsx +++ b/client/src/pages/onboarding/steps/AcceptCredential.tsx @@ -95,7 +95,7 @@ export const AcceptCredential: React.FC = ({ content, connectionId, crede const routeError = () => { navigate('/demo') - dispatch({ type: 'demo/RESET' }) + dispatch({ type: 'demo/resetState' }) } protocolVersion = useCredentials().protocolVersion diff --git a/client/src/slices/characters/charactersSlice.ts b/client/src/slices/characters/charactersSlice.ts index 37b71ae7..cea1d144 100644 --- a/client/src/slices/characters/charactersSlice.ts +++ b/client/src/slices/characters/charactersSlice.ts @@ -44,6 +44,10 @@ const characterSlice = createSlice({ state.isLoading = false state.currentCharacter = action.payload }) + .addCase('demo/resetState', (state) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + state = initialState + }) }, }) diff --git a/client/src/slices/connection/connectionSlice.ts b/client/src/slices/connection/connectionSlice.ts index caa1eee6..9a0f7a85 100644 --- a/client/src/slices/connection/connectionSlice.ts +++ b/client/src/slices/connection/connectionSlice.ts @@ -67,6 +67,12 @@ const connectionSlice = createSlice({ state.invitationUrl = undefined state.isLoading = false }) + .addCase('demo/resetState', (state) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const useLegacyInvitations = state.useLegacyInvitations + state = initialState + state.useLegacyInvitations = useLegacyInvitations + }) }, }) diff --git a/client/src/slices/credentials/credentialsSlice.ts b/client/src/slices/credentials/credentialsSlice.ts index 510cb5b2..6de880c0 100644 --- a/client/src/slices/credentials/credentialsSlice.ts +++ b/client/src/slices/credentials/credentialsSlice.ts @@ -92,6 +92,12 @@ const credentialSlice = createSlice({ state.credentials = [] state.isLoading = false }) + .addCase('demo/resetState', (state) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const protocolVersion = state.protocolVersion + state = initialState + state.protocolVersion = protocolVersion + }) }, }) diff --git a/client/src/slices/onboarding/onboardingSlice.ts b/client/src/slices/onboarding/onboardingSlice.ts index 80cdcd3c..cb44a343 100644 --- a/client/src/slices/onboarding/onboardingSlice.ts +++ b/client/src/slices/onboarding/onboardingSlice.ts @@ -34,6 +34,12 @@ const onboardingSlice = createSlice({ state.isCompleted = false }, }, + extraReducers: (builder) => { + builder.addCase('demo/resetState', (state) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + state = initialState + }) + }, }) export const { diff --git a/client/src/slices/preferences/preferencesSlice.ts b/client/src/slices/preferences/preferencesSlice.ts index db0995a5..d300d629 100644 --- a/client/src/slices/preferences/preferencesSlice.ts +++ b/client/src/slices/preferences/preferencesSlice.ts @@ -50,7 +50,7 @@ const preferencesSlice = createSlice({ }, extraReducers: (builder) => { builder - .addCase('demo/RESET', (state) => { + .addCase('demo/resetState', (state) => { state.darkMode = localStorage.getItem('theme') === 'dark' state.connectionDate = undefined }) diff --git a/client/src/slices/proof/proofSlice.ts b/client/src/slices/proof/proofSlice.ts index b30af9ae..98f9ec42 100644 --- a/client/src/slices/proof/proofSlice.ts +++ b/client/src/slices/proof/proofSlice.ts @@ -54,6 +54,10 @@ const proofSlice = createSlice({ state.proof = undefined state.isLoading = false }) + .addCase('demo/resetState', (state) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + state = initialState + }) }, }) diff --git a/client/src/slices/section/sectionSlice.ts b/client/src/slices/section/sectionSlice.ts index c6b1c13f..612075e1 100644 --- a/client/src/slices/section/sectionSlice.ts +++ b/client/src/slices/section/sectionSlice.ts @@ -23,9 +23,14 @@ const sectionSlice = createSlice({ }, }, extraReducers: (builder) => { - builder.addCase('clearUseCase', (state) => { - state.section = undefined - }) + builder + .addCase('clearUseCase', (state) => { + state.section = undefined + }) + .addCase('demo/resetState', (state) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + state = initialState + }) }, }) diff --git a/client/src/slices/useCases/useCasesSlice.ts b/client/src/slices/useCases/useCasesSlice.ts index 4ae4be1a..c8d2ee95 100644 --- a/client/src/slices/useCases/useCasesSlice.ts +++ b/client/src/slices/useCases/useCasesSlice.ts @@ -62,6 +62,10 @@ const useCaseSlice = createSlice({ state.sectionCount = 0 state.stepCount = 0 }) + .addCase('demo/resetState', (state) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + state = initialState + }) }, }) diff --git a/client/src/slices/wallets/walletsSlice.ts b/client/src/slices/wallets/walletsSlice.ts index 8501fbcd..93174464 100644 --- a/client/src/slices/wallets/walletsSlice.ts +++ b/client/src/slices/wallets/walletsSlice.ts @@ -27,6 +27,10 @@ const characterSlice = createSlice({ state.isLoading = false state.wallets = action.payload }) + .addCase('demo/resetState', (state) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + state = initialState + }) }, }) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index 8b940d34..bfc80884 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -71,23 +71,23 @@ export const KBar: React.FunctionComponent = ({ children }) = keywords: 'configuration', section: 'Configuration', }, - { - id: 'ledger', - name: 'Select ledger', - keywords: 'ledger', - section: '', - parent: 'configuration', - }, - { - id: 'bcovrin', - name: 'BCovrin Test', - keywords: 'bcovrin', - section: '', - perform: () => { - alert('BCovrin Test ledger selected!') - }, - parent: 'ledger', - }, + // { + // id: 'ledger', + // name: 'Select ledger', + // keywords: 'ledger', + // section: '', + // parent: 'configuration', + // }, + // { + // id: 'bcovrin', + // name: 'BCovrin Test', + // keywords: 'bcovrin', + // section: '', + // perform: () => { + // alert('BCovrin Test ledger selected!') + // }, + // parent: 'ledger', + // }, { id: 'issue-credential-protocol-version', name: 'Select credential protocol version', @@ -115,33 +115,33 @@ export const KBar: React.FunctionComponent = ({ children }) = }, parent: 'issue-credential-protocol-version', }, - { - id: 'present-proof-protocol-version', - name: 'Select proof protocol version', - keywords: 'present proof protocol version', - section: '', - parent: 'configuration', - }, - { - id: 'present-proof-protocol-version-1', - name: 'v1', - keywords: 'present proof protocol version 1', - section: '', - perform: () => { - alert('Proof Protocol Version 1 selected') - }, - parent: 'present-proof-protocol-version', - }, - { - id: 'present-proof-protocol-version-2', - name: 'v2', - keywords: 'present proof protocol version 2', - section: '', - perform: () => { - alert('Proof Protocol Version 2 selected') - }, - parent: 'present-proof-protocol-version', - }, + // { + // id: 'present-proof-protocol-version', + // name: 'Select proof protocol version', + // keywords: 'present proof protocol version', + // section: '', + // parent: 'configuration', + // }, + // { + // id: 'present-proof-protocol-version-1', + // name: 'v1', + // keywords: 'present proof protocol version 1', + // section: '', + // perform: () => { + // alert('Proof Protocol Version 1 selected') + // }, + // parent: 'present-proof-protocol-version', + // }, + // { + // id: 'present-proof-protocol-version-2', + // name: 'v2', + // keywords: 'present proof protocol version 2', + // section: '', + // perform: () => { + // alert('Proof Protocol Version 2 selected') + // }, + // parent: 'present-proof-protocol-version', + // }, { id: 'invitation-type', name: 'Change connection invitation type', diff --git a/cypress/e2e/legacy_invitation_usecase_page.cy.ts b/cypress/e2e/legacy_invitation_usecase_page.cy.ts index 8691f5fc..f68da7a3 100644 --- a/cypress/e2e/legacy_invitation_usecase_page.cy.ts +++ b/cypress/e2e/legacy_invitation_usecase_page.cy.ts @@ -1,7 +1,7 @@ const API_URL = Cypress.env('apiUrl') const TEST_AGENT_URL = 'http://localhost:9000' -describe('UseCase Page', () => { +describe('Onboarding demo test using legacy invitation', () => { it('successfully completes school use case', () => { cy.visit('/demo') cy.get('[data-cy=next-onboarding-step]').click() @@ -88,7 +88,7 @@ describe('UseCase Page', () => { const record = response.body.find((x) => x.threadId === threadId && x.state === 'request-received') cy.request('POST', `${TEST_AGENT_URL}/proofs/${record.id}/accept-request`).then(() => { // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(10000) // wait for the test agent request to be processed + cy.wait(5000) // wait for the test agent request to be processed cy.get('[data-cy=section') cy.get('[data-cy="small-button"]').click() }) @@ -113,7 +113,7 @@ describe('UseCase Page', () => { cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(10000) // wait for the test agent request to be processed + cy.wait(5000) // wait for the test agent request to be processed cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { const cred = resp.body.find((x) => x.threadId === threadId) cy.wrap(cred).its('state').should('equal', 'done') diff --git a/cypress/e2e/oob_invitation_usecase.cy.ts b/cypress/e2e/oob_invitation_usecase.cy.ts index 564f22b0..930db0f5 100644 --- a/cypress/e2e/oob_invitation_usecase.cy.ts +++ b/cypress/e2e/oob_invitation_usecase.cy.ts @@ -1,7 +1,7 @@ const API_URL = Cypress.env('apiUrl') const TEST_AGENT_URL = 'http://localhost:9000' -describe('UseCase Page', () => { +describe('Onboarding demo test using out of band invitation', () => { it('successfully completes school use case', () => { cy.visit('/') cy.get('[data-cy=try-demo-button]').click() @@ -69,7 +69,6 @@ describe('UseCase Page', () => { cy.get('[data-cy=select-use-case]').first().click() - // cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') cy.get('[data-cy=start-container]') cy.get('[data-cy=small-button]').click() From cd92196286fbc05cdb2100ddc211e1aca31842a5 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Tue, 4 Oct 2022 20:14:10 +0100 Subject: [PATCH 16/25] Update client/src/slices/credentials/credentialsSlice.ts Co-authored-by: Timo Glastra --- client/src/slices/credentials/credentialsSlice.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/slices/credentials/credentialsSlice.ts b/client/src/slices/credentials/credentialsSlice.ts index 6de880c0..d2863e30 100644 --- a/client/src/slices/credentials/credentialsSlice.ts +++ b/client/src/slices/credentials/credentialsSlice.ts @@ -93,10 +93,10 @@ const credentialSlice = createSlice({ state.isLoading = false }) .addCase('demo/resetState', (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const protocolVersion = state.protocolVersion - state = initialState - state.protocolVersion = protocolVersion + return { + ...initialState, + protocolVersion: state.protocolVersion + } }) }, }) From b095c64fd2690ae0c8a5d9c9c6fc28b1be03bbfb Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Tue, 4 Oct 2022 20:15:04 +0100 Subject: [PATCH 17/25] Update client/src/slices/onboarding/onboardingSlice.ts Co-authored-by: Timo Glastra --- client/src/slices/onboarding/onboardingSlice.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/slices/onboarding/onboardingSlice.ts b/client/src/slices/onboarding/onboardingSlice.ts index cb44a343..cc0c3303 100644 --- a/client/src/slices/onboarding/onboardingSlice.ts +++ b/client/src/slices/onboarding/onboardingSlice.ts @@ -36,8 +36,7 @@ const onboardingSlice = createSlice({ }, extraReducers: (builder) => { builder.addCase('demo/resetState', (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - state = initialState + return initialState }) }, }) From af7cd9b120943e09a27229a6d837ff34b1c3f5b0 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Tue, 4 Oct 2022 20:15:25 +0100 Subject: [PATCH 18/25] Update client/src/store/configureStore.tsx Co-authored-by: Timo Glastra --- client/src/store/configureStore.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/store/configureStore.tsx b/client/src/store/configureStore.tsx index f8718c49..81e4e707 100644 --- a/client/src/store/configureStore.tsx +++ b/client/src/store/configureStore.tsx @@ -8,7 +8,7 @@ import rootReducer from '../slices/index' export const persistConfig = { key: 'redux-store-root', storage, - whitelist: ['preferences', 'configuration', 'characters', 'onboarding', 'credentials', 'connection'], + whitelist: ['preferences', 'characters', 'onboarding', 'credentials', 'connection'], version: 4, } From 5b685ef524d712a4797709515ce6276d3f1c08e0 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Tue, 4 Oct 2022 20:30:16 +0100 Subject: [PATCH 19/25] fixed slice reducer logic for demo/resetState and removed commented items from K-menu Signed-off-by: Jim Ezesinachi --- .../src/slices/characters/charactersSlice.ts | 5 +-- .../src/slices/connection/connectionSlice.ts | 8 ++-- .../slices/credentials/credentialsSlice.ts | 6 +-- .../src/slices/onboarding/onboardingSlice.ts | 2 +- client/src/slices/proof/proofSlice.ts | 5 +-- client/src/slices/section/sectionSlice.ts | 5 +-- client/src/slices/useCases/useCasesSlice.ts | 5 +-- client/src/slices/wallets/walletsSlice.ts | 5 +-- client/src/utils/KBar.tsx | 44 ------------------- 9 files changed, 18 insertions(+), 67 deletions(-) diff --git a/client/src/slices/characters/charactersSlice.ts b/client/src/slices/characters/charactersSlice.ts index cea1d144..79fbf23b 100644 --- a/client/src/slices/characters/charactersSlice.ts +++ b/client/src/slices/characters/charactersSlice.ts @@ -44,9 +44,8 @@ const characterSlice = createSlice({ state.isLoading = false state.currentCharacter = action.payload }) - .addCase('demo/resetState', (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - state = initialState + .addCase('demo/resetState', () => { + return initialState }) }, }) diff --git a/client/src/slices/connection/connectionSlice.ts b/client/src/slices/connection/connectionSlice.ts index 9a0f7a85..77bdb493 100644 --- a/client/src/slices/connection/connectionSlice.ts +++ b/client/src/slices/connection/connectionSlice.ts @@ -68,10 +68,10 @@ const connectionSlice = createSlice({ state.isLoading = false }) .addCase('demo/resetState', (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const useLegacyInvitations = state.useLegacyInvitations - state = initialState - state.useLegacyInvitations = useLegacyInvitations + return { + ...initialState, + useLegacyInvitations: state.useLegacyInvitations, + } }) }, }) diff --git a/client/src/slices/credentials/credentialsSlice.ts b/client/src/slices/credentials/credentialsSlice.ts index d2863e30..c852e03e 100644 --- a/client/src/slices/credentials/credentialsSlice.ts +++ b/client/src/slices/credentials/credentialsSlice.ts @@ -94,9 +94,9 @@ const credentialSlice = createSlice({ }) .addCase('demo/resetState', (state) => { return { - ...initialState, - protocolVersion: state.protocolVersion - } + ...initialState, + protocolVersion: state.protocolVersion, + } }) }, }) diff --git a/client/src/slices/onboarding/onboardingSlice.ts b/client/src/slices/onboarding/onboardingSlice.ts index cc0c3303..89c23bf6 100644 --- a/client/src/slices/onboarding/onboardingSlice.ts +++ b/client/src/slices/onboarding/onboardingSlice.ts @@ -35,7 +35,7 @@ const onboardingSlice = createSlice({ }, }, extraReducers: (builder) => { - builder.addCase('demo/resetState', (state) => { + builder.addCase('demo/resetState', () => { return initialState }) }, diff --git a/client/src/slices/proof/proofSlice.ts b/client/src/slices/proof/proofSlice.ts index 98f9ec42..8f5f863b 100644 --- a/client/src/slices/proof/proofSlice.ts +++ b/client/src/slices/proof/proofSlice.ts @@ -54,9 +54,8 @@ const proofSlice = createSlice({ state.proof = undefined state.isLoading = false }) - .addCase('demo/resetState', (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - state = initialState + .addCase('demo/resetState', () => { + return initialState }) }, }) diff --git a/client/src/slices/section/sectionSlice.ts b/client/src/slices/section/sectionSlice.ts index 612075e1..0e99073f 100644 --- a/client/src/slices/section/sectionSlice.ts +++ b/client/src/slices/section/sectionSlice.ts @@ -27,9 +27,8 @@ const sectionSlice = createSlice({ .addCase('clearUseCase', (state) => { state.section = undefined }) - .addCase('demo/resetState', (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - state = initialState + .addCase('demo/resetState', () => { + return initialState }) }, }) diff --git a/client/src/slices/useCases/useCasesSlice.ts b/client/src/slices/useCases/useCasesSlice.ts index c8d2ee95..c55dbca9 100644 --- a/client/src/slices/useCases/useCasesSlice.ts +++ b/client/src/slices/useCases/useCasesSlice.ts @@ -62,9 +62,8 @@ const useCaseSlice = createSlice({ state.sectionCount = 0 state.stepCount = 0 }) - .addCase('demo/resetState', (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - state = initialState + .addCase('demo/resetState', () => { + return initialState }) }, }) diff --git a/client/src/slices/wallets/walletsSlice.ts b/client/src/slices/wallets/walletsSlice.ts index 93174464..815488d9 100644 --- a/client/src/slices/wallets/walletsSlice.ts +++ b/client/src/slices/wallets/walletsSlice.ts @@ -27,9 +27,8 @@ const characterSlice = createSlice({ state.isLoading = false state.wallets = action.payload }) - .addCase('demo/resetState', (state) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - state = initialState + .addCase('demo/resetState', () => { + return initialState }) }, }) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index bfc80884..af8f8815 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -71,23 +71,6 @@ export const KBar: React.FunctionComponent = ({ children }) = keywords: 'configuration', section: 'Configuration', }, - // { - // id: 'ledger', - // name: 'Select ledger', - // keywords: 'ledger', - // section: '', - // parent: 'configuration', - // }, - // { - // id: 'bcovrin', - // name: 'BCovrin Test', - // keywords: 'bcovrin', - // section: '', - // perform: () => { - // alert('BCovrin Test ledger selected!') - // }, - // parent: 'ledger', - // }, { id: 'issue-credential-protocol-version', name: 'Select credential protocol version', @@ -115,33 +98,6 @@ export const KBar: React.FunctionComponent = ({ children }) = }, parent: 'issue-credential-protocol-version', }, - // { - // id: 'present-proof-protocol-version', - // name: 'Select proof protocol version', - // keywords: 'present proof protocol version', - // section: '', - // parent: 'configuration', - // }, - // { - // id: 'present-proof-protocol-version-1', - // name: 'v1', - // keywords: 'present proof protocol version 1', - // section: '', - // perform: () => { - // alert('Proof Protocol Version 1 selected') - // }, - // parent: 'present-proof-protocol-version', - // }, - // { - // id: 'present-proof-protocol-version-2', - // name: 'v2', - // keywords: 'present proof protocol version 2', - // section: '', - // perform: () => { - // alert('Proof Protocol Version 2 selected') - // }, - // parent: 'present-proof-protocol-version', - // }, { id: 'invitation-type', name: 'Change connection invitation type', From 3ecda9b98af3f0330c071386416455dd52025040 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Wed, 5 Oct 2022 09:22:53 +0100 Subject: [PATCH 20/25] test: added issue credential protocol version tests Signed-off-by: Jim Ezesinachi --- .../issue_credential_version_1_use_case.cy.ts | 141 ++++++++++++++++++ .../issue_credential_version_2_use_case.cy.ts | 141 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 cypress/e2e/issue_credential_version_1_use_case.cy.ts create mode 100644 cypress/e2e/issue_credential_version_2_use_case.cy.ts diff --git a/cypress/e2e/issue_credential_version_1_use_case.cy.ts b/cypress/e2e/issue_credential_version_1_use_case.cy.ts new file mode 100644 index 00000000..9ad14e39 --- /dev/null +++ b/cypress/e2e/issue_credential_version_1_use_case.cy.ts @@ -0,0 +1,141 @@ +const API_URL = Cypress.env('apiUrl') +const TEST_AGENT_URL = 'http://localhost:9000' + +describe('Onboarding demo test using out of band invitation', () => { + it('successfully completes school use case', () => { + cy.visit('/') + cy.get('[data-cy=try-demo-button]').click() + + const shortcut = Cypress.platform === 'darwin' ? 'command+k' : 'ctrl+k' + cy.get('body').type(`{${shortcut}}`) + cy.get('[data-cy=configuration]') + .click() + .get('[data-cy=issue-credential-protocol-version]') + .click() + .get('[data-cy=issue-credential-protocol-version-1]') + .click() + + cy.get('[data-cy=next-onboarding-step]').click() + cy.get('[data-cy=use-wallet]').first().click() + cy.get('[data-cy=small-button]').click() + + cy.get('[data-cy=select-char]').first().click() + cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') + cy.get('[data-cy=next-onboarding-step]').click() + + cy.wait('@createInvitation').then((interception) => { + const body = { invitationUrl: interception.response?.body.invitationUrl, autoAcceptConnection: true } + + const oobId = interception.response?.body.outOfBandRecord.id + + cy.intercept('GET', `${API_URL}/connections?outOfBandId=${oobId}`).as('getConnectionRecord') + + cy.request('POST', `${TEST_AGENT_URL}/oob/receive-invitation-url`, body) + + cy.wait(['@getConnectionRecord']).then((inter) => { + const record = inter.response?.body[0] + cy.wrap(record).its('state').should('not.equal', 'invited') + }) + }) + + cy.intercept('POST', '/credentials/offer-credential').as('offerCredential') + + cy.get('[data-cy=next-onboarding-step]').click() + + cy.wait('@offerCredential').then((interception) => { + const connectionId = interception.response?.body.connectionId + const threadId = interception.response?.body.threadId + + cy.request('GET', `${TEST_AGENT_URL}/credentials/`).should((response) => { + const testAgentRecord = response.body.find( + (credentialRecord) => credentialRecord.threadId === threadId && credentialRecord.state === 'offer-received' + ) + + cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) + + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(3000) // wait for the test agent request to be processed + cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { + const cred = resp.body.find((credentialRecord) => credentialRecord.threadId === threadId) + cy.wrap(cred).its('state').should('equal', 'done') + }) + + cy.get('[data-cy="next-onboarding-step"]').click() + }) + }) + + cy.get('[data-cy=next-onboarding-step]').click() + cy.url().should('be.equal', `${Cypress.config('baseUrl')}/dashboard`) + + cy.get('[data-cy=select-use-case]').first().click() + + cy.get('[data-cy=start-container]') + cy.get('[data-cy=small-button]').click() + + cy.wait('@createInvitation').then((interception) => { + const body = { invitationUrl: interception.response?.body.invitationUrl, autoAcceptConnection: true } + + const oobId = interception.response?.body.outOfBandRecord.id + + cy.intercept('GET', `${API_URL}/connections?outOfBandId=${oobId}`).as('getConnectionRecord') + + cy.request('POST', `${TEST_AGENT_URL}/oob/receive-invitation-url`, body) + + cy.wait(['@getConnectionRecord']).then((inter) => { + const record = inter.response?.body[0] + cy.wrap(record).its('state').should('not.equal', 'invited') + }) + }) + + cy.intercept('POST', `${API_URL}/proofs/request-proof`).as('createProof') + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.wait('@createProof').then((interception) => { + const threadId = interception.response?.body.threadId + cy.request('GET', `${TEST_AGENT_URL}/proofs/`).should((response) => { + const record = response.body.find((x) => x.threadId === threadId && x.state === 'request-received') + cy.request('POST', `${TEST_AGENT_URL}/proofs/${record.id}/accept-request`).then(() => { + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(5000) // wait for the test agent request to be processed + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + }) + }) + }) + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.intercept('POST', '/credentials/offer-credential').as('offerCredential') + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.wait('@offerCredential').then((interception) => { + const connectionId = interception.response?.body.connectionId + const threadId = interception.response?.body.threadId + + cy.request('GET', `${TEST_AGENT_URL}/credentials/`).should((response) => { + const testAgentRecord = response.body.find((x) => x.threadId === threadId && x.state === 'offer-received') + + cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) + + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(5000) // wait for the test agent request to be processed + cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { + const cred = resp.body.find((x) => x.threadId === threadId) + cy.wrap(cred).its('state').should('equal', 'done') + }) + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + }) + }) + + cy.get('[data-cy=end-container]') + cy.get('[data-cy=standard-button]').click() + cy.url().should('be.equal', `${Cypress.config('baseUrl')}/dashboard`) + }) +}) diff --git a/cypress/e2e/issue_credential_version_2_use_case.cy.ts b/cypress/e2e/issue_credential_version_2_use_case.cy.ts new file mode 100644 index 00000000..86d16ed6 --- /dev/null +++ b/cypress/e2e/issue_credential_version_2_use_case.cy.ts @@ -0,0 +1,141 @@ +const API_URL = Cypress.env('apiUrl') +const TEST_AGENT_URL = 'http://localhost:9000' + +describe('Onboarding demo test using out of band invitation', () => { + it('successfully completes school use case', () => { + cy.visit('/') + cy.get('[data-cy=try-demo-button]').click() + + const shortcut = Cypress.platform === 'darwin' ? 'command+k' : 'ctrl+k' + cy.get('body').type(`{${shortcut}}`) + cy.get('[data-cy=configuration]') + .click() + .get('[data-cy=issue-credential-protocol-version]') + .click() + .get('[data-cy=issue-credential-protocol-version-2]') + .click() + + cy.get('[data-cy=next-onboarding-step]').click() + cy.get('[data-cy=use-wallet]').first().click() + cy.get('[data-cy=small-button]').click() + + cy.get('[data-cy=select-char]').first().click() + cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') + cy.get('[data-cy=next-onboarding-step]').click() + + cy.wait('@createInvitation').then((interception) => { + const body = { invitationUrl: interception.response?.body.invitationUrl, autoAcceptConnection: true } + + const oobId = interception.response?.body.outOfBandRecord.id + + cy.intercept('GET', `${API_URL}/connections?outOfBandId=${oobId}`).as('getConnectionRecord') + + cy.request('POST', `${TEST_AGENT_URL}/oob/receive-invitation-url`, body) + + cy.wait(['@getConnectionRecord']).then((inter) => { + const record = inter.response?.body[0] + cy.wrap(record).its('state').should('not.equal', 'invited') + }) + }) + + cy.intercept('POST', '/credentials/offer-credential').as('offerCredential') + + cy.get('[data-cy=next-onboarding-step]').click() + + cy.wait('@offerCredential').then((interception) => { + const connectionId = interception.response?.body.connectionId + const threadId = interception.response?.body.threadId + + cy.request('GET', `${TEST_AGENT_URL}/credentials/`).should((response) => { + const testAgentRecord = response.body.find( + (credentialRecord) => credentialRecord.threadId === threadId && credentialRecord.state === 'offer-received' + ) + + cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) + + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(3000) // wait for the test agent request to be processed + cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { + const cred = resp.body.find((credentialRecord) => credentialRecord.threadId === threadId) + cy.wrap(cred).its('state').should('equal', 'done') + }) + + cy.get('[data-cy="next-onboarding-step"]').click() + }) + }) + + cy.get('[data-cy=next-onboarding-step]').click() + cy.url().should('be.equal', `${Cypress.config('baseUrl')}/dashboard`) + + cy.get('[data-cy=select-use-case]').first().click() + + cy.get('[data-cy=start-container]') + cy.get('[data-cy=small-button]').click() + + cy.wait('@createInvitation').then((interception) => { + const body = { invitationUrl: interception.response?.body.invitationUrl, autoAcceptConnection: true } + + const oobId = interception.response?.body.outOfBandRecord.id + + cy.intercept('GET', `${API_URL}/connections?outOfBandId=${oobId}`).as('getConnectionRecord') + + cy.request('POST', `${TEST_AGENT_URL}/oob/receive-invitation-url`, body) + + cy.wait(['@getConnectionRecord']).then((inter) => { + const record = inter.response?.body[0] + cy.wrap(record).its('state').should('not.equal', 'invited') + }) + }) + + cy.intercept('POST', `${API_URL}/proofs/request-proof`).as('createProof') + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.wait('@createProof').then((interception) => { + const threadId = interception.response?.body.threadId + cy.request('GET', `${TEST_AGENT_URL}/proofs/`).should((response) => { + const record = response.body.find((x) => x.threadId === threadId && x.state === 'request-received') + cy.request('POST', `${TEST_AGENT_URL}/proofs/${record.id}/accept-request`).then(() => { + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(5000) // wait for the test agent request to be processed + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + }) + }) + }) + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.intercept('POST', '/credentials/offer-credential').as('offerCredential') + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + + cy.wait('@offerCredential').then((interception) => { + const connectionId = interception.response?.body.connectionId + const threadId = interception.response?.body.threadId + + cy.request('GET', `${TEST_AGENT_URL}/credentials/`).should((response) => { + const testAgentRecord = response.body.find((x) => x.threadId === threadId && x.state === 'offer-received') + + cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) + + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(5000) // wait for the test agent request to be processed + cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { + const cred = resp.body.find((x) => x.threadId === threadId) + cy.wrap(cred).its('state').should('equal', 'done') + }) + + cy.get('[data-cy=section') + cy.get('[data-cy="small-button"]').click() + }) + }) + + cy.get('[data-cy=end-container]') + cy.get('[data-cy=standard-button]').click() + cy.url().should('be.equal', `${Cypress.config('baseUrl')}/dashboard`) + }) +}) From 4fc5c9a6c0f316c2c9427395ef2ad4819cd7eac0 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Wed, 5 Oct 2022 09:24:32 +0100 Subject: [PATCH 21/25] test: switched issue credential protocol version tests from oob to legacy Signed-off-by: Jim Ezesinachi --- cypress/e2e/issue_credential_version_1_use_case.cy.ts | 2 +- cypress/e2e/issue_credential_version_2_use_case.cy.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/issue_credential_version_1_use_case.cy.ts b/cypress/e2e/issue_credential_version_1_use_case.cy.ts index 9ad14e39..88108cde 100644 --- a/cypress/e2e/issue_credential_version_1_use_case.cy.ts +++ b/cypress/e2e/issue_credential_version_1_use_case.cy.ts @@ -20,7 +20,7 @@ describe('Onboarding demo test using out of band invitation', () => { cy.get('[data-cy=small-button]').click() cy.get('[data-cy=select-char]').first().click() - cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') + cy.intercept('POST', `${API_URL}/oob/create-legacy-invitation`).as('createInvitation') cy.get('[data-cy=next-onboarding-step]').click() cy.wait('@createInvitation').then((interception) => { diff --git a/cypress/e2e/issue_credential_version_2_use_case.cy.ts b/cypress/e2e/issue_credential_version_2_use_case.cy.ts index 86d16ed6..ff9d7e7f 100644 --- a/cypress/e2e/issue_credential_version_2_use_case.cy.ts +++ b/cypress/e2e/issue_credential_version_2_use_case.cy.ts @@ -20,7 +20,7 @@ describe('Onboarding demo test using out of band invitation', () => { cy.get('[data-cy=small-button]').click() cy.get('[data-cy=select-char]').first().click() - cy.intercept('POST', `${API_URL}/oob/create-invitation`).as('createInvitation') + cy.intercept('POST', `${API_URL}/oob/create-legacy-invitation`).as('createInvitation') cy.get('[data-cy=next-onboarding-step]').click() cy.wait('@createInvitation').then((interception) => { From 3b5fa9140692c5e33d877a5a974ad384a5759e98 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Thu, 6 Oct 2022 10:29:41 +0100 Subject: [PATCH 22/25] test: renamed issue credential test assertions and set wait times to 5000ms & feat: added resetState to K-menu and Onboarding page Signed-off-by: Jim Ezesinachi --- client/src/pages/onboarding/OnboardingPage.tsx | 1 + client/src/utils/KBar.tsx | 13 ++++++++++++- .../e2e/issue_credential_version_1_use_case.cy.ts | 13 ++----------- .../e2e/issue_credential_version_2_use_case.cy.ts | 4 ++-- cypress/e2e/legacy_invitation_usecase_page.cy.ts | 2 +- cypress/e2e/oob_invitation_usecase.cy.ts | 2 +- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/client/src/pages/onboarding/OnboardingPage.tsx b/client/src/pages/onboarding/OnboardingPage.tsx index 45bd9346..96816d00 100644 --- a/client/src/pages/onboarding/OnboardingPage.tsx +++ b/client/src/pages/onboarding/OnboardingPage.tsx @@ -41,6 +41,7 @@ export const OnboardingPage: React.FC = () => { dispatch(fetchAllUseCasesByCharId(currentCharacter.id)) navigate('/dashboard') } else { + dispatch({ type: 'demo/resetState' }) dispatch(fetchWallets()) dispatch(fetchAllCharacters()) setMounted(true) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index af8f8815..e1136fdb 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -56,7 +56,7 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'resetDemo', - name: 'Reset demo', + name: 'Reset demo (including configuration options chosen from this menu)', shortcut: ['r'], keywords: 'Reset demo', perform: () => { @@ -65,6 +65,17 @@ export const KBar: React.FunctionComponent = ({ children }) = dispatch(fetchAllCharacters()) }, }, + { + id: 'resetState', + name: 'Reset state (not including configuration options chosen from this menu', + shortcut: ['s'], + keywords: 'Reset state', + perform: () => { + dispatch({ type: 'demo/resetState' }) + dispatch(fetchWallets()) + dispatch(fetchAllCharacters()) + }, + }, { id: 'configuration', name: 'Choose demo configuration options...', diff --git a/cypress/e2e/issue_credential_version_1_use_case.cy.ts b/cypress/e2e/issue_credential_version_1_use_case.cy.ts index 88108cde..ab497b96 100644 --- a/cypress/e2e/issue_credential_version_1_use_case.cy.ts +++ b/cypress/e2e/issue_credential_version_1_use_case.cy.ts @@ -1,20 +1,11 @@ const API_URL = Cypress.env('apiUrl') const TEST_AGENT_URL = 'http://localhost:9000' -describe('Onboarding demo test using out of band invitation', () => { +describe('Onboarding demo test using issue credential protocol version 1', () => { it('successfully completes school use case', () => { cy.visit('/') cy.get('[data-cy=try-demo-button]').click() - const shortcut = Cypress.platform === 'darwin' ? 'command+k' : 'ctrl+k' - cy.get('body').type(`{${shortcut}}`) - cy.get('[data-cy=configuration]') - .click() - .get('[data-cy=issue-credential-protocol-version]') - .click() - .get('[data-cy=issue-credential-protocol-version-1]') - .click() - cy.get('[data-cy=next-onboarding-step]').click() cy.get('[data-cy=use-wallet]').first().click() cy.get('[data-cy=small-button]').click() @@ -54,7 +45,7 @@ describe('Onboarding demo test using out of band invitation', () => { cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(3000) // wait for the test agent request to be processed + cy.wait(5000) // wait for the test agent request to be processed cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { const cred = resp.body.find((credentialRecord) => credentialRecord.threadId === threadId) cy.wrap(cred).its('state').should('equal', 'done') diff --git a/cypress/e2e/issue_credential_version_2_use_case.cy.ts b/cypress/e2e/issue_credential_version_2_use_case.cy.ts index ff9d7e7f..e9547c38 100644 --- a/cypress/e2e/issue_credential_version_2_use_case.cy.ts +++ b/cypress/e2e/issue_credential_version_2_use_case.cy.ts @@ -1,7 +1,7 @@ const API_URL = Cypress.env('apiUrl') const TEST_AGENT_URL = 'http://localhost:9000' -describe('Onboarding demo test using out of band invitation', () => { +describe('Onboarding demo test using issue credential protocol version 2', () => { it('successfully completes school use case', () => { cy.visit('/') cy.get('[data-cy=try-demo-button]').click() @@ -54,7 +54,7 @@ describe('Onboarding demo test using out of band invitation', () => { cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(3000) // wait for the test agent request to be processed + cy.wait(5000) // wait for the test agent request to be processed cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { const cred = resp.body.find((credentialRecord) => credentialRecord.threadId === threadId) cy.wrap(cred).its('state').should('equal', 'done') diff --git a/cypress/e2e/legacy_invitation_usecase_page.cy.ts b/cypress/e2e/legacy_invitation_usecase_page.cy.ts index a67151a6..8d057270 100644 --- a/cypress/e2e/legacy_invitation_usecase_page.cy.ts +++ b/cypress/e2e/legacy_invitation_usecase_page.cy.ts @@ -43,7 +43,7 @@ describe('Onboarding demo test using legacy invitation', () => { cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(3000) // wait for the test agent request to be processed + cy.wait(5000) // wait for the test agent request to be processed cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { const cred = resp.body.find((credentialRecord) => credentialRecord.threadId === threadId) cy.wrap(cred).its('state').should('equal', 'done') diff --git a/cypress/e2e/oob_invitation_usecase.cy.ts b/cypress/e2e/oob_invitation_usecase.cy.ts index 930db0f5..db973be8 100644 --- a/cypress/e2e/oob_invitation_usecase.cy.ts +++ b/cypress/e2e/oob_invitation_usecase.cy.ts @@ -54,7 +54,7 @@ describe('Onboarding demo test using out of band invitation', () => { cy.request('POST', `${TEST_AGENT_URL}/credentials/${testAgentRecord.id}/accept-offer`) // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(3000) // wait for the test agent request to be processed + cy.wait(5000) // wait for the test agent request to be processed cy.request('GET', `${API_URL}/demo/credentials/${connectionId}`).should((resp) => { const cred = resp.body.find((credentialRecord) => credentialRecord.threadId === threadId) cy.wrap(cred).its('state').should('equal', 'done') From ae67c8a3fb9d15327fb6bc109e51b75e1ac3d844 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Thu, 6 Oct 2022 12:31:59 +0100 Subject: [PATCH 23/25] Update client/src/utils/KBar.tsx Co-authored-by: Jan --- client/src/utils/KBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index e1136fdb..acba16eb 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -67,7 +67,7 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'resetState', - name: 'Reset state (not including configuration options chosen from this menu', + name: 'Reset demo', shortcut: ['s'], keywords: 'Reset state', perform: () => { From f4e3b3b35ac18da34b21b562c9abcdc3b76bdbdb Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Thu, 6 Oct 2022 12:32:19 +0100 Subject: [PATCH 24/25] Update client/src/utils/KBar.tsx Co-authored-by: Jan --- client/src/utils/KBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index acba16eb..675b34b8 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -56,7 +56,7 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'resetDemo', - name: 'Reset demo (including configuration options chosen from this menu)', + name: 'Reset demo (including configuration options)', shortcut: ['r'], keywords: 'Reset demo', perform: () => { From 41a34c4ab5ad0a5a2ead2cc326d5a86307115644 Mon Sep 17 00:00:00 2001 From: Jim Ezesinachi Date: Thu, 6 Oct 2022 12:32:31 +0100 Subject: [PATCH 25/25] Update client/src/utils/KBar.tsx Co-authored-by: Jan --- client/src/utils/KBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/utils/KBar.tsx b/client/src/utils/KBar.tsx index 675b34b8..137a992c 100644 --- a/client/src/utils/KBar.tsx +++ b/client/src/utils/KBar.tsx @@ -78,7 +78,7 @@ export const KBar: React.FunctionComponent = ({ children }) = }, { id: 'configuration', - name: 'Choose demo configuration options...', + name: 'Change demo configuration...', keywords: 'configuration', section: 'Configuration', },