Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/locales/en/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@
"bottomdescription": "If you’re ready and understand, please click the “Proceed to scan” button. This will open a scanner where you scan the QR code or manually enter the URL.",
"buttons": {
"connected": "Get connected",
"onboardingdocumentation": "Visit our website",
"onboardingdocumentation": "Visit our documentation",
"recoverydocumentation": "Recovery documentation"
}
},
Expand All @@ -426,7 +426,10 @@
},
"advancedsetup": {
"title": "Advanced setup",
"description": "To connect, please enter the SSI agent boot and connect URLs (in your email or from your command line).",
"description": {
"connectboot": "To connect, please enter the SSI agent boot and connect URLs (in your email or from your command line).",
"connect": "To connect, please enter the SSI agent connect URL (in your email or from your command line)."
},
"buttons": {
"connect": "Connect",
"cancel": "Cancel"
Expand Down
6 changes: 4 additions & 2 deletions src/ui/globals/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ const DOUBLE_TAP_DELAY = 300;
const SUPPORT_EMAIL = "mailto:[email protected]";
const WEBSITE_LINK = "https://www.veridian.id";
const DOCUMENTATION_LINK = "https://docs.veridian.id/";
const ONBOARDING_DOCUMENTATION_LINK = "https://docs.veridian.id/onboarding";
const RECOVERY_DOCUMENTATION_LINK = "https://docs.veridian.id/recovery";
const ONBOARDING_DOCUMENTATION_LINK =
"https://docs.veridian.id/onboarding#ssi-agent-details";
const RECOVERY_DOCUMENTATION_LINK =
"https://docs.veridian.id/recovery#ssi-agent-details";
const FEDERAL_DATA_PROTECTION_LINK = "https://www.edoeb.admin.ch/de";
const DATA_PROTECTION_AUTHORITIES_LINK =
"https://ec.europa.eu/justice/article-29/structure/data-protection-authorities/index_en.htm";
Expand Down
6 changes: 2 additions & 4 deletions src/ui/pages/CreateSSIAgent/CreateSSIAgent.scss
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,6 @@
}

.ssi-agent-scan-input-modal.responsive-modal {
&.loading {
z-index: -1 !important;
}

.buttons-last-slot {
min-width: auto !important;

Expand All @@ -91,6 +87,8 @@
}

& .responsive-modal-content {
padding-bottom: var(--ion-safe-area-bottom);

& > * {
margin-bottom: 0;
}
Expand Down
264 changes: 262 additions & 2 deletions src/ui/pages/CreateSSIAgent/CreateSSIAgent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const checkPermisson = jest.fn(() =>
const requestPermission = jest.fn();
const startScan = jest.fn();
const stopScan = jest.fn();
const getPlatformMock = jest.fn(() => ["mobile"]);
const discoverConnectUrlMock = jest.fn();

const customiseMockValue: {
identifiers: { creation: { individualOnly: string } };
Expand Down Expand Up @@ -133,6 +133,7 @@ jest.mock("../../../core/agent/agent", () => ({
agent: {
bootAndConnect: bootAndConnectMock,
recoverKeriaAgent: recoverKeriaAgentMock,
discoverConnectUrl: discoverConnectUrlMock,
basicStorage: {
deleteById: basicStorageDeleteMock,
createOrUpdateBasicRecord: createOrUpdateBasicRecordMock,
Expand Down Expand Up @@ -220,6 +221,12 @@ describe("SSI agent page", () => {
dispatch: dispatchMock,
};

beforeEach(() => {
discoverConnectUrlMock.mockImplementation(() =>
Promise.resolve(connectUrl)
);
});

describe("SSI connect summary", () => {
test("Render", async () => {
const { getByText } = render(
Expand Down Expand Up @@ -687,6 +694,255 @@ describe("SSI agent page", () => {
});
});

describe("Scan: recovery", () => {
const dispatchMock = jest.fn();
const initialState = {
stateCache: {
routes: [],
authentication: {
loggedIn: true,
time: Date.now(),
passcodeIsSet: true,
recoveryWalletProgress: true,
},
},
seedPhraseCache: {
seedPhrase: "seedphrase seedphrase",
},
};

const storeMocked = {
...makeTestStore(initialState),
dispatch: dispatchMock,
};

test("SSI boot url with scanner", async () => {
const barcodes = [
{
displayValue: bootUrl,
format: BarcodeFormat.QrCode,
rawValue: bootUrl,
valueType: BarcodeValueType.Url,
},
];

addListener.mockImplementation(
(
eventName: string,
listenerFunc: (result: BarcodesScannedEvent) => void
) => {
setTimeout(() => {
listenerFunc({
barcodes,
});
}, 100);

return {
remove: jest.fn(),
};
}
);

discoverConnectUrlMock.mockImplementation(() =>
Promise.resolve(connectUrl)
);

const history = createMemoryHistory();
const { getByText, queryByText } = render(
<IonReactMemoryRouter history={history}>
<Provider store={storeMocked}>
<CreateSSIAgent />
</Provider>
</IonReactMemoryRouter>
);

fireEvent.click(
getByText(EN_TRANSLATIONS.ssiagent.connect.buttons.connected)
);

await waitFor(() => {
expect(
queryByText(
EN_TRANSLATIONS.ssiagent.scanssi.scan.button.advancedsetup
)
).toBe(null);
expect(
getByText(EN_TRANSLATIONS.ssiagent.scanssi.scan.button.entermanual)
).toBeVisible;
});

await waitFor(() => {
expect(recoverKeriaAgentMock).toBeCalledWith(
initialState.seedPhraseCache.seedPhrase.split(" "),
connectUrl
);
});
});

test("SSI boot url with manual modal", async () => {
addListener.mockImplementation(
(
eventName: string,
listenerFunc: (result: BarcodesScannedEvent) => void
) => {
return {
remove: jest.fn(),
};
}
);

discoverConnectUrlMock.mockImplementation(() =>
Promise.resolve(connectUrl)
);

const history = createMemoryHistory();
const { getByText, getByTestId } = render(
<IonReactMemoryRouter history={history}>
<Provider store={storeMocked}>
<CreateSSIAgent />
</Provider>
</IonReactMemoryRouter>
);

fireEvent.click(
getByText(EN_TRANSLATIONS.ssiagent.connect.buttons.connected)
);

await waitFor(() => {
expect(
getByText(EN_TRANSLATIONS.ssiagent.scanssi.scan.button.entermanual)
).toBeVisible();
});

fireEvent.click(
getByText(EN_TRANSLATIONS.ssiagent.scanssi.scan.button.entermanual)
);

await waitFor(() => {
expect(getByTestId("ssi-agent-scan-input-modal")).toBeVisible();
});

fireEvent(
getByTestId("ssi-agent-scan-input"),
new CustomEvent("ionInput", {
detail: {
value: bootUrl,
},
})
);

fireEvent.click(
getByText(EN_TRANSLATIONS.ssiagent.scanssi.scan.modal.confirm)
);

await waitFor(() => {
expect(recoverKeriaAgentMock).toBeCalledWith(
initialState.seedPhraseCache.seedPhrase.split(" "),
connectUrl
);
});
});

test("recovery with input url when failed to search connect url", async () => {
addListener.mockImplementation(
(
eventName: string,
listenerFunc: (result: BarcodesScannedEvent) => void
) => {
setTimeout(() => {
listenerFunc({
barcodes,
});
}, 100);

return {
remove: jest.fn(),
};
}
);

discoverConnectUrlMock.mockImplementation(() => {
return Promise.reject(new Error(Agent.CONNECT_URL_DISCOVERY_FAILED));
});

const history = createMemoryHistory();

const { getByText } = render(
<IonReactMemoryRouter history={history}>
<Provider store={storeMocked}>
<CreateSSIAgent />
</Provider>
</IonReactMemoryRouter>
);

fireEvent.click(
getByText(EN_TRANSLATIONS.ssiagent.connect.buttons.connected)
);

await waitFor(() => {
expect(
getByText(EN_TRANSLATIONS.ssiagent.scanssi.scan.button.entermanual)
).toBeVisible();
});

await waitFor(() => {
expect(recoverKeriaAgentMock).toBeCalledWith(
initialState.seedPhraseCache.seedPhrase.split(" "),
bootUrl
);
});
});

test("Show a toast error when the input url isn't boot and connect url", async () => {
addListener.mockImplementation(
(
eventName: string,
listenerFunc: (result: BarcodesScannedEvent) => void
) => {
setTimeout(() => {
listenerFunc({
barcodes,
});
}, 100);

return {
remove: jest.fn(),
};
}
);

discoverConnectUrlMock.mockImplementation(() => {
return Promise.reject(new Error("error"));
});

const history = createMemoryHistory();

const { getByText } = render(
<IonReactMemoryRouter history={history}>
<Provider store={storeMocked}>
<CreateSSIAgent />
</Provider>
</IonReactMemoryRouter>
);

fireEvent.click(
getByText(EN_TRANSLATIONS.ssiagent.connect.buttons.connected)
);

await waitFor(() => {
expect(
getByText(EN_TRANSLATIONS.ssiagent.scanssi.scan.button.entermanual)
).toBeVisible();
});

await waitFor(() => {
expect(dispatchMock).toBeCalledWith(
setToastMsg(ToastMsgType.INVALID_CONNECT_URL)
);
});
});
});

describe("Advanced settings", () => {
async function inputValue(
getByTestId: RenderResult["getByTestId"],
Expand Down Expand Up @@ -778,7 +1034,9 @@ describe("SSI agent page", () => {
});

expect(
getByText(EN_TRANSLATIONS.ssiagent.advancedsetup.description)
getByText(
EN_TRANSLATIONS.ssiagent.advancedsetup.description.connectboot
)
).toBeVisible();

expect(
Expand Down Expand Up @@ -1188,6 +1446,8 @@ describe("SSI agent page", () => {
Promise.reject(new Error(Agent.KERIA_BOOT_FAILED_BAD_NETWORK))
);

discoverConnectUrlMock.mockClear();

const history = createMemoryHistory();

const { getByText, getByTestId } = render(
Expand Down
Loading