@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
400 lines (355 loc) • 13.7 kB
text/typescript
import { DeviceModelId } from "@ledgerhq/types-devices";
import { PostOnboardingActionId, PostOnboardingState } from "@ledgerhq/types-live";
import reducer, {
hubStateSelector,
initialState,
postOnboardingDeviceModelIdSelector,
postOnboardingSelector,
walletEntryPointEligibleForPortfolioSelector,
} from "./reducer";
import {
importPostOnboardingState,
initPostOnboarding,
setPostOnboardingActionCompleted,
clearPostOnboardingLastActionCompleted,
hidePostOnboardingWalletEntryPoint,
setPostOnboardingWalletEntryPointEligibility,
} from "./actions";
const initializationParamsA: Parameters<typeof initPostOnboarding> = [
{
deviceModelId: DeviceModelId.nanoX,
actionsIds: [
PostOnboardingActionId.claimMock,
PostOnboardingActionId.migrateAssetsMock,
PostOnboardingActionId.personalizeMock,
],
},
];
// initialState -> importPostOnboardingState(...initializationParamsA)
const stateA0: PostOnboardingState = {
deviceModelId: DeviceModelId.nanoX,
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
walletEntryPointEligibleForPortfolio: null,
actionsToComplete: [
PostOnboardingActionId.claimMock,
PostOnboardingActionId.migrateAssetsMock,
PostOnboardingActionId.personalizeMock,
],
actionsCompleted: {
[PostOnboardingActionId.claimMock]: false,
[PostOnboardingActionId.migrateAssetsMock]: false,
[PostOnboardingActionId.personalizeMock]: false,
},
lastActionCompleted: null,
postOnboardingInProgress: true,
};
// stateA0 -> setPostOnboardingActionCompleted(claimMock)
const stateA1: PostOnboardingState = {
deviceModelId: DeviceModelId.nanoX,
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
walletEntryPointEligibleForPortfolio: null,
actionsToComplete: [
PostOnboardingActionId.claimMock,
PostOnboardingActionId.migrateAssetsMock,
PostOnboardingActionId.personalizeMock,
],
actionsCompleted: {
[PostOnboardingActionId.claimMock]: true, // stateA0 -> setPostOnboardingActionCompleted(claimMock)
[PostOnboardingActionId.migrateAssetsMock]: false,
[PostOnboardingActionId.personalizeMock]: false,
},
lastActionCompleted: PostOnboardingActionId.claimMock, // stateA0 -> setPostOnboardingActionCompleted(claimMock)
postOnboardingInProgress: true,
};
// stateA1 -> clearPostOnboardingLastActionCompleted()
const stateA2: PostOnboardingState = {
deviceModelId: DeviceModelId.nanoX,
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
walletEntryPointEligibleForPortfolio: null,
actionsToComplete: [
PostOnboardingActionId.claimMock,
PostOnboardingActionId.migrateAssetsMock,
PostOnboardingActionId.personalizeMock,
],
actionsCompleted: {
[PostOnboardingActionId.claimMock]: true,
[PostOnboardingActionId.migrateAssetsMock]: false,
[PostOnboardingActionId.personalizeMock]: false,
},
lastActionCompleted: null, // stateA1 -> clearPostOnboardingLastActionCompleted()
postOnboardingInProgress: true,
};
// stateA2 -> setPostOnboardingActionCompleted(personalizeMock)
const stateA3: PostOnboardingState = {
deviceModelId: DeviceModelId.nanoX,
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
walletEntryPointEligibleForPortfolio: null,
actionsToComplete: [
PostOnboardingActionId.claimMock,
PostOnboardingActionId.migrateAssetsMock,
PostOnboardingActionId.personalizeMock,
],
actionsCompleted: {
[PostOnboardingActionId.claimMock]: true,
[PostOnboardingActionId.migrateAssetsMock]: false,
[PostOnboardingActionId.personalizeMock]: true, // stateA2 -> setPostOnboardingActionCompleted(personalizeMock)
},
lastActionCompleted: PostOnboardingActionId.personalizeMock, // stateA2 -> setPostOnboardingActionCompleted(personalizeMock)
postOnboardingInProgress: true,
};
// stateA3 -> hidePostOnboardingWalletEntryPoint()
const stateA4: PostOnboardingState = {
deviceModelId: DeviceModelId.nanoX,
walletEntryPointDismissed: true, // stateA3 -> hidePostOnboardingWalletEntryPoint()
entryPointFirstDisplayedDate: null,
walletEntryPointEligibleForPortfolio: null,
actionsToComplete: [
PostOnboardingActionId.claimMock,
PostOnboardingActionId.migrateAssetsMock,
PostOnboardingActionId.personalizeMock,
],
actionsCompleted: {
[PostOnboardingActionId.claimMock]: true,
[PostOnboardingActionId.migrateAssetsMock]: false,
[PostOnboardingActionId.personalizeMock]: true,
},
lastActionCompleted: PostOnboardingActionId.personalizeMock,
postOnboardingInProgress: true,
};
const initializationParamsB: Parameters<typeof initPostOnboarding> = [
{
deviceModelId: DeviceModelId.nanoS,
actionsIds: [PostOnboardingActionId.claimMock],
},
];
// initialState -> importPostOnboardingState(...initializationParamsB)
const stateB0 = {
deviceModelId: DeviceModelId.nanoS,
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
walletEntryPointEligibleForPortfolio: null,
actionsToComplete: [PostOnboardingActionId.claimMock],
actionsCompleted: { [PostOnboardingActionId.claimMock]: false },
lastActionCompleted: null,
postOnboardingInProgress: true,
};
// stateB0 -> setPostOnboardingActionCompleted(claimMock)
const stateB1 = {
deviceModelId: DeviceModelId.nanoS,
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
walletEntryPointEligibleForPortfolio: null,
actionsToComplete: [PostOnboardingActionId.claimMock],
actionsCompleted: { [PostOnboardingActionId.claimMock]: true },
lastActionCompleted: PostOnboardingActionId.claimMock,
postOnboardingInProgress: true,
};
const initializationParamsC: Parameters<typeof initPostOnboarding> = [
{
deviceModelId: DeviceModelId.nanoSP,
actionsIds: [],
},
];
// initialState -> importPostOnboardingState(...initializationParamsC)
const stateC0 = {
deviceModelId: DeviceModelId.nanoSP,
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
walletEntryPointEligibleForPortfolio: null,
actionsToComplete: [],
actionsCompleted: {},
lastActionCompleted: null,
postOnboardingInProgress: true,
};
describe("postOnboarding reducer (& action creators)", () => {
beforeAll(() => {
jest.useFakeTimers().setSystemTime(new Date("2020-01-20"));
});
afterAll(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
});
let state;
beforeEach(() => {
// reset state to initial state;
state = reducer(undefined, {} as any);
});
it("should initialize the state properly", () => {
expect(state).toEqual(initialState);
});
it("should handle importPostOnboardingState", () => {
state = reducer(state, importPostOnboardingState({ newState: stateA0 }));
expect(state).toEqual(stateA0);
state = reducer(state, importPostOnboardingState({ newState: stateA1 }));
expect(state).toEqual(stateA1);
});
it("should handle initPostOnboarding", () => {
state = reducer(state, initPostOnboarding(...initializationParamsA));
expect(state).toEqual(stateA0);
});
it("should handle setPostOnboardingActionCompleted", () => {
state = stateA0;
state = reducer(
state,
setPostOnboardingActionCompleted({
actionId: PostOnboardingActionId.claimMock,
}),
);
expect(state).toEqual(stateA1);
});
it("should handle clearPostOnboardingLastActionCompleted", () => {
state = stateA1;
state = reducer(state, clearPostOnboardingLastActionCompleted());
expect(state).toEqual({ ...stateA2 });
});
it("should handle hidePostOnboardingWalletEntryPoint", () => {
state = stateA3;
state = reducer(state, hidePostOnboardingWalletEntryPoint());
expect(state).toEqual(stateA4);
});
it("should handle setPostOnboardingWalletEntryPointEligibility", () => {
state = stateA0;
state = reducer(state, setPostOnboardingWalletEntryPointEligibility(true));
expect(state.walletEntryPointEligibleForPortfolio).toBe(true);
state = reducer(state, setPostOnboardingWalletEntryPointEligibility(false));
expect(state.walletEntryPointEligibleForPortfolio).toBe(false);
const stateBefore = state;
state = reducer(state, {
type: "POST_ONBOARDING_SET_WALLET_ENTRY_POINT_ELIGIBILITY",
// @ts-expect-error - testing with null payload
payload: null,
});
expect(state).toBe(stateBefore);
expect(state.walletEntryPointEligibleForPortfolio).toBe(false);
state = reducer(state, {
type: "POST_ONBOARDING_SET_WALLET_ENTRY_POINT_ELIGIBILITY",
payload: undefined,
});
expect(state).toBe(stateBefore);
state = reducer(state, {
type: "POST_ONBOARDING_SET_WALLET_ENTRY_POINT_ELIGIBILITY",
// @ts-expect-error - testing with string payload
payload: "true",
});
expect(state).toBe(stateBefore);
});
it("should handle successive actions properly", () => {
// initializing state with new device & set of actions
state = reducer(state, initPostOnboarding(...initializationParamsA));
expect(state).toEqual(stateA0);
// setting completed for claimMock
state = reducer(
state,
setPostOnboardingActionCompleted({
actionId: PostOnboardingActionId.claimMock,
}),
);
expect(state).toEqual(stateA1);
// clearing last completed action
state = reducer(state, clearPostOnboardingLastActionCompleted());
expect(state).toEqual(stateA2);
// setting completed for personalizeMock
state = reducer(
state,
setPostOnboardingActionCompleted({
actionId: PostOnboardingActionId.personalizeMock,
}),
);
expect(state).toEqual(stateA3);
// hiding wallet entrypoint
state = reducer(state, hidePostOnboardingWalletEntryPoint());
expect(state).toEqual(stateA4);
// initializing state with new device & set of actions
state = reducer(state, initPostOnboarding(...initializationParamsB));
expect(state).toEqual(stateB0);
// setting completed for claimMock
state = reducer(
state,
setPostOnboardingActionCompleted({
actionId: PostOnboardingActionId.claimMock,
}),
);
expect(state).toEqual(stateB1);
// initializing state with new device & set of actions
state = reducer(state, initPostOnboarding(...initializationParamsC));
expect(state).toEqual(stateC0);
});
});
describe("postOnboarding selectors", () => {
it("should keep valid device ids", () => {
const stateValidDeviceId: PostOnboardingState = {
deviceModelId: DeviceModelId.nanoX,
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
actionsToComplete: [],
actionsCompleted: {},
lastActionCompleted: null,
postOnboardingInProgress: false,
walletEntryPointEligibleForPortfolio: null,
};
const storeState = { postOnboarding: stateValidDeviceId };
const postOnboarding = postOnboardingSelector(storeState);
expect(postOnboarding).toEqual(stateValidDeviceId);
const hubState = hubStateSelector(storeState);
expect(hubState).toEqual({
deviceModelId: stateValidDeviceId.deviceModelId,
actionsToComplete: stateValidDeviceId.actionsToComplete,
actionsCompleted: stateValidDeviceId.actionsCompleted,
lastActionCompleted: stateValidDeviceId.lastActionCompleted,
postOnboardingInProgress: false,
});
const deviceModelId = postOnboardingDeviceModelIdSelector(storeState);
expect(deviceModelId).toEqual(stateValidDeviceId.deviceModelId);
});
it('should sanitize "nanoFTS" device ids to "stax"', () => {
const stateValidDeviceId: PostOnboardingState = {
// @ts-expect-error - testing with "nanoFTS" device id
deviceModelId: "nanoFTS",
walletEntryPointDismissed: false,
entryPointFirstDisplayedDate: new Date("2020-01-20"),
actionsToComplete: [],
actionsCompleted: {},
lastActionCompleted: null,
postOnboardingInProgress: false,
walletEntryPointEligibleForPortfolio: null,
};
const storeState = { postOnboarding: stateValidDeviceId };
const postOnboarding = postOnboardingSelector(storeState);
expect(postOnboarding).toEqual({
...stateValidDeviceId,
deviceModelId: DeviceModelId.stax,
});
const hubState = hubStateSelector(storeState);
expect(hubState).toEqual({
deviceModelId: DeviceModelId.stax,
actionsToComplete: stateValidDeviceId.actionsToComplete,
actionsCompleted: stateValidDeviceId.actionsCompleted,
lastActionCompleted: stateValidDeviceId.lastActionCompleted,
postOnboardingInProgress: false,
});
const deviceModelId = postOnboardingDeviceModelIdSelector(storeState);
expect(deviceModelId).toEqual(DeviceModelId.stax);
});
it("should return walletEntryPointEligibleForPortfolio from state", () => {
const storeStateTrue = {
postOnboarding: {
...initialState,
walletEntryPointEligibleForPortfolio: true,
},
};
expect(walletEntryPointEligibleForPortfolioSelector(storeStateTrue)).toBe(true);
const storeStateFalse = {
postOnboarding: {
...initialState,
walletEntryPointEligibleForPortfolio: false,
},
};
expect(walletEntryPointEligibleForPortfolioSelector(storeStateFalse)).toBe(false);
const storeStateNull = { postOnboarding: initialState };
expect(walletEntryPointEligibleForPortfolioSelector(storeStateNull)).toBe(null);
});
});