Skip to content

Commit

Permalink
Merge pull request #8147 from LedgerHQ/fix/LIVE-14524-llm
Browse files Browse the repository at this point in the history
[LIVE-14524] LLM - Improve QRCode flow for Ledger Sync tests
  • Loading branch information
KVNLS authored Oct 18, 2024
2 parents 5d7e67e + 0885c49 commit 6d1a0f4
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 42 deletions.
5 changes: 5 additions & 0 deletions .changeset/gold-bats-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"live-mobile": minor
---

Improve QRCode flow for Ledger Sync allowing use to automate tests
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ const StepFlow = ({
const { memberCredentials } = useInitMemberCredentials();
const trustchain = useSelector(trustchainSelector);

const { handleStart, handleSendDigits, inputCallback, nbDigits } = useSyncWithQrCode();
const { handleStart, handleSendDigits, nbDigits } = useSyncWithQrCode();

const handleQrCodeScanned = (data: string) => {
onQrCodeScanned();
if (memberCredentials) handleStart(data, memberCredentials);
};

const handlePinCodeSubmit = (input: string) => {
if (input && inputCallback && nbDigits === input.length) handleSendDigits(inputCallback, input);
if (input && nbDigits === input.length) handleSendDigits(input);
};

const getScene = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,52 @@
import React from "react";
import { render, screen } from "@tests/test-renderer";

import { render, screen, act } from "@tests/test-renderer";
import { INITIAL_TEST, WalletSyncSettingsNavigator } from "./shared";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";
import { createQRCodeCandidateInstance } from "@ledgerhq/ledger-key-ring-protocol/qrcode/index";
import { BarcodeScanningResult } from "expo-camera";

const MOCK_BARCODE: BarcodeScanningResult = {
cornerPoints: [],
bounds: {
origin: {
x: 0,
y: 0,
},
size: {
height: 0,
width: 0,
},
},
type: "",
data: "",
};

jest.mock("../hooks/useQRCodeHost", () => ({
useQRCodeHost: () => ({
currentOption: jest.fn(),
url: "ledger.com",
const mockSimulateBarcodeScanned = jest.fn();
jest.mock("expo-camera", () => ({
CameraView: jest.fn(({ onBarcodeScanned }) => {
mockSimulateBarcodeScanned.mockImplementation(onBarcodeScanned);
return null;
}),
}));

jest.mock("@ledgerhq/ledger-key-ring-protocol/qrcode/index", () => ({
createQRCodeHostInstance: () =>
Promise.resolve({
trustchainApiBaseUrl: getWalletSyncEnvironmentParams("STAGING").trustchainApiBaseUrl,
onDisplayQRCode: jest.fn().mockImplementation(url => url),
onDisplayDigits: jest.fn().mockImplementation(digits => digits),
addMember: jest.fn(),
}),
createQRCodeCandidateInstance: jest.fn(),
}));

jest.useFakeTimers();

describe("SynchronizeWithQrCode", () => {
it("Should display the QR code when 'show qr' toggle is pressed and add a new member through the flow", async () => {
let resolveQRCodeFlowPromise: unknown = null;
let requestQRCodeInput: unknown = null;
let pinCodeSet = false;
const mockPromiseQRCodeCandidate = new Promise(resolve => {
resolveQRCodeFlowPromise = resolve;
});
(createQRCodeCandidateInstance as jest.Mock).mockImplementation(({ onRequestQRCodeInput }) => {
requestQRCodeInput = onRequestQRCodeInput;
return mockPromiseQRCodeCandidate;
});

const { user } = render(<WalletSyncSettingsNavigator />, {
overrideInitialState: INITIAL_TEST,
});
Expand All @@ -34,16 +56,39 @@ describe("SynchronizeWithQrCode", () => {
await user.press(screen.queryAllByText(/show qr/i)[0]);
expect(screen.getByTestId("ws-qr-code-displayed")).toBeVisible();

// TODO: We need to simulate the QR code scanning process
// //PinCode Page after scanning QRCode
// // Need to wait 3 seconds to simulate the time taken to scan the QR code
// expect(await screen.findByText("Enter Ledger Sync code")).toBeDefined();

// //Succes Page after PinCode
// expect(
// await screen.findByText(
// "Changes in your accounts will now automatically appear across all apps and platforms.",
// ),
// ).toBeDefined();
await act(() => {
mockSimulateBarcodeScanned(MOCK_BARCODE);
});

// Call programmatically the requestQRCodeInput function to display the pin code input
await act(() => {
if (typeof requestQRCodeInput === "function") {
requestQRCodeInput({ digits: 3 }, (code: string) => {
if (code === "123") {
pinCodeSet = true;
}
});
}
});

expect(await screen.findByText("Enter Ledger Sync code")).toBeDefined();
const inputs = screen.getAllByDisplayValue("");
await user.type(inputs[0], "1");
await user.type(inputs[1], "2");
await user.type(inputs[2], "3");

// Resolve the QR code flow promise only if pin code is set
if (pinCodeSet) {
if (typeof resolveQRCodeFlowPromise === "function") {
resolveQRCodeFlowPromise({ member: { name: "test" } });
}
}

expect(await screen.findByText("We are updating the synched instances...")).toBeDefined();
//Simulate the sync process
await act(() => {
jest.advanceTimersByTime(3 * 1000);
});
expect(await screen.findByText("Sync successful")).toBeDefined();
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useNavigation } from "@react-navigation/native";
import React from "react";
import React, { useCallback } from "react";
import { useSelector } from "react-redux";
import Activation from ".";
import { TrackScreen } from "~/analytics";
Expand Down Expand Up @@ -52,16 +52,21 @@ const ActivationFlow = ({
const { currentStep, setCurrentStep } = useCurrentStep();
const { memberCredentials } = useInitMemberCredentials();

const { handleStart, handleSendDigits, inputCallback, nbDigits } = useSyncWithQrCode();
const { handleStart, handleSendDigits, nbDigits } = useSyncWithQrCode();

const handleQrCodeScanned = (data: string) => {
onQrCodeScanned();
if (memberCredentials) handleStart(data, memberCredentials);
};

const handlePinCodeSubmit = (input: string) => {
if (input && inputCallback && nbDigits === input.length) handleSendDigits(inputCallback, input);
};
const handlePinCodeSubmit = useCallback(
(input: string) => {
if (input && nbDigits === input.length) {
handleSendDigits(input);
}
},
[handleSendDigits, nbDigits],
);

const hasCompletedOnboarding = useSelector(hasCompletedOnboardingSelector);
const { navigate } =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useState } from "react";
import { useCallback, useState, useRef } from "react";
import { MemberCredentials, TrustchainMember } from "@ledgerhq/ledger-key-ring-protocol/types";
import { createQRCodeCandidateInstance } from "@ledgerhq/ledger-key-ring-protocol/qrcode/index";
import {
Expand Down Expand Up @@ -28,21 +28,21 @@ export const useSyncWithQrCode = () => {

const navigation = useNavigation();

const [inputCallback, setInputCallback] = useState<((input: string) => void) | null>(null);
const inputCallbackRef = useRef<((input: string) => void) | null>(null);
const dispatch = useDispatch();

const onRequestQRCodeInput = useCallback(
(config: { digits: number }, callback: (input: string) => void) => {
setDigits(config.digits);
setInputCallback(() => callback);
inputCallbackRef.current = callback;
},
[],
);

const onSyncFinished = useCallback(() => {
setDigits(null);
setInput(null);
setInputCallback(null);
inputCallbackRef.current = null;
navigation.navigate(NavigatorName.WalletSync, {
screen: ScreenName.WalletSyncLoading,
params: {
Expand Down Expand Up @@ -102,9 +102,9 @@ export const useSyncWithQrCode = () => {
);

const handleSendDigits = useCallback(
(inputCallback: (_: string) => void, input: string) => (inputCallback(input), true),
(input: string) => (inputCallbackRef.current?.(input), true),
[],
);

return { nbDigits, input, handleStart, handleSendDigits, setInput, inputCallback };
return { nbDigits, input, handleStart, handleSendDigits, setInput };
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect } from "react";
import { WalletSyncNavigatorStackParamList } from "~/components/RootNavigator/types/WalletSyncNavigator";
import { ScreenName } from "~/const";
import { BaseComposite, StackNavigatorProps } from "~/components/RootNavigator/types/helpers";
Expand Down Expand Up @@ -31,9 +31,11 @@ export function ActivationLoading({ route }: Props) {
useLoadingStep(created);
const hasCompletedOnboarding = useSelector(hasCompletedOnboardingSelector);

if (!hasCompletedOnboarding) {
dispatch(completeOnboarding());
}
useEffect(() => {
if (!hasCompletedOnboarding) {
dispatch(completeOnboarding());
}
}, [dispatch, hasCompletedOnboarding]);

return (
<>
Expand Down

0 comments on commit 6d1a0f4

Please sign in to comment.