Skip to content

Commit

Permalink
[wallet/desktop] fix: cosign form is not presented for multisig tx is…
Browse files Browse the repository at this point in the history
…s#1863 (#1881)

* [wallet/desktop] fix: cosign form is not presented for multisig tx

fix multisig graph action

* [wallet/desktop] task: update AccountMultisigGraph test

* [wallet/desktop] task: use root and current multisig graph to check if tx needs cosignature

* [wallet/desktop] feat: add new multisig graph presentation, fix graph construction

* [wallet/desktop] task: update and add tests for AccountMultisigGraph component

* [wallet/desktop] task: show multisig graph for cosigners

* [wallet/desktop] task: sort multisig graph by address, remove old tree

* [wallet/desktop] task: add test for AccountDetailsPage

* [wallet/desktop] fix: AccountDetailsPage test

* [wallet/desktop] task: add test for Account store module

* [wallet/desktop] fix: typo

* [wallet/desktop] task: update test for AccountMultisigGraph component
  • Loading branch information
OlegMakarenko committed Aug 3, 2022
1 parent b8f0995 commit a1e6bac
Show file tree
Hide file tree
Showing 10 changed files with 1,393 additions and 172 deletions.
229 changes: 130 additions & 99 deletions __tests__/components/AccountMultisigGraph.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { AccountMultisigGraphTs } from '@/components/AccountMultisigGraph/Accoun
import { AccountModel } from '@/core/database/entities/AccountModel';
import { AccountState } from '@/store/Account';
import { getComponent } from '@MOCKS/Components';
import { MultisigAccountInfoDTO } from 'symbol-openapi-typescript-fetch-client';
import { AddressBook } from 'symbol-address-book';
import { Address, MultisigAccountInfo } from 'symbol-sdk';

describe('components/AccountMultisigGraph', () => {
Expand All @@ -27,117 +27,94 @@ describe('components/AccountMultisigGraph', () => {
const cosig2Address = 'TD2KY5BKECF6YKSWSTGMUHFP66GG33S5MG6UOYQ';
const cosig11Address = 'TDYEWBAMEW27OODEODPQ4OKYFEU6N24NC4O7KZA';
const cosig21Address = 'TCZCGIGFXU5LW7BCUQCXVVYS6JJDHJWONYVVGXY';
const randomAddress = 'TCZ1234FXU5LW7BCUQCXVVYS6JJDHJWONYVVGXY';
const mockAddressBook = new AddressBook([
{
id: '0',
name: 'contact name',
address: cosig2Address,
},
]);

const multisigAccountGraphInfosDTO = [
const multisigAccounts = [
{
version: 1,
accountAddress: Address.createFromRawAddress(msigAddress),
minApproval: 2,
minRemoval: 1,
cosignatoryAddresses: [Address.createFromRawAddress(cosig1Address), Address.createFromRawAddress(cosig2Address)],
multisigAddresses: [],
},
{
version: 1,
accountAddress: Address.createFromRawAddress(cosig1Address),
minApproval: 1,
minRemoval: 1,
cosignatoryAddresses: [Address.createFromRawAddress(cosig11Address)],
multisigAddresses: [Address.createFromRawAddress(msigAddress)],
},
{
level: 0,
multisigEntries: [
{
multisig: {
version: 1,
accountAddress: msigAddress,
minApproval: 2,
minRemoval: 1,
cosignatoryAddresses: [cosig1Address, cosig2Address],
multisigAddresses: [],
},
},
],
version: 1,
accountAddress: Address.createFromRawAddress(cosig2Address),
minApproval: 1,
minRemoval: 1,
cosignatoryAddresses: [Address.createFromRawAddress(cosig21Address)],
multisigAddresses: [Address.createFromRawAddress(msigAddress)],
},
{
level: 1,
multisigEntries: [
{
multisig: {
version: 1,
accountAddress: cosig1Address,
minApproval: 1,
minRemoval: 1,
cosignatoryAddresses: [cosig11Address],
multisigAddresses: [msigAddress],
},
},
{
multisig: {
version: 1,
accountAddress: cosig2Address,
minApproval: 1,
minRemoval: 1,
cosignatoryAddresses: [cosig21Address],
multisigAddresses: [msigAddress],
},
},
],
version: 1,
accountAddress: Address.createFromRawAddress(cosig21Address),
minApproval: 0,
minRemoval: 0,
cosignatoryAddresses: [],
multisigAddresses: [Address.createFromRawAddress(cosig2Address)],
},
{
level: 2,
multisigEntries: [
{
multisig: {
version: 1,
accountAddress: cosig21Address,
minApproval: 0,
minRemoval: 0,
cosignatoryAddresses: [],
multisigAddresses: [cosig2Address],
},
},
{
multisig: {
version: 1,
accountAddress: cosig11Address,
minApproval: 0,
minRemoval: 0,
cosignatoryAddresses: [],
multisigAddresses: [cosig1Address],
},
},
],
version: 1,
accountAddress: Address.createFromRawAddress(cosig11Address),
minApproval: 0,
minRemoval: 0,
cosignatoryAddresses: [],
multisigAddresses: [Address.createFromRawAddress(cosig1Address), Address.createFromRawAddress(randomAddress)],
},
];

const toMultisigAccountInfo = (dto: MultisigAccountInfoDTO): MultisigAccountInfo => {
return new MultisigAccountInfo(
dto.multisig.version || 1,
Address.createFromRawAddress(dto.multisig.accountAddress),
dto.multisig.minApproval,
dto.multisig.minRemoval,
dto.multisig.cosignatoryAddresses.map((cosigner) => Address.createFromRawAddress(cosigner)),
dto.multisig.multisigAddresses.map((multisig) => Address.createFromRawAddress(multisig)),
);
};
const multisigAccounts = new Map<number, MultisigAccountInfo[]>();

multisigAccountGraphInfosDTO.map((multisigAccountGraphInfoDTO) => {
multisigAccounts.set(
multisigAccountGraphInfoDTO.level,
multisigAccountGraphInfoDTO.multisigEntries.map((multisigAccountInfoDTO) => {
return toMultisigAccountInfo(multisigAccountInfoDTO);
}),
);
});

const mockAccountStore = {
namespaced: true,
state: {
multisigAccountGraph: undefined,
multisigAccountGraphInfo: undefined,
knownAccounts: [],
},
getters: {
multisigAccountGraph: (state) => {
return state.multisigAccountGraph;
multisigAccountGraphInfo: (state) => {
return state.multisigAccountGraphInfo;
},
knownAccounts: (state) => {
return state.knownAccounts;
},
},
};

const getAccountMultisigGraphWrapper = (account: AccountModel, stateChanges?: AccountState) => {
const wrapper = getComponent(AccountMultisigGraph, { account: mockAccountStore }, stateChanges, {
const mockAddressBookStore = {
namespaced: true,
getters: {
getAddressBook: () => {
return mockAddressBook;
},
},
};

const mockStore = {
account: mockAccountStore,
addressBook: mockAddressBookStore,
};

const getAccountMultisigGraphWrapper = (account: AccountModel, stateChanges?: AccountState, stubs?: Record<string, any>) => {
const props = {
account,
});
return wrapper;
};

return getComponent(AccountMultisigGraph, mockStore, stateChanges, props, stubs);
};

test('renders account multisig graph component when multisig account graph is undefined', () => {
Expand Down Expand Up @@ -165,26 +142,80 @@ describe('components/AccountMultisigGraph', () => {
expect(wrapper.find('span.label').exists()).toBeTruthy();
});

test('current account is selected in multisig graph', () => {
test('current account is selected in multisig graph', async () => {
// Arrange:
const account = ({ address: cosig1Address } as unknown) as AccountModel;
const stateChanges = {
multisigAccountGraph: (multisigAccounts as unknown) as MultisigAccountInfo[][],
multisigAccountGraphInfo: (multisigAccounts as unknown) as MultisigAccountInfo[],
knownAccounts: [{ name: 'myAccount', address: cosig1Address }],
} as Partial<AccountState>;

// Act:
const wrapper = getAccountMultisigGraphWrapper(account, stateChanges as AccountState);
const component = wrapper.vm as AccountMultisigGraphTs;
await component.$nextTick();

// Assert:
expect(component.dataset[0].title).toContain(msigAddress);
expect(component.dataset[0].children[0].selected).toBe(true);
});

test('center graph view', () => {
// Arrange:
const account = ({ address: cosig1Address } as unknown) as AccountModel;
const stateChanges = {
multisigAccountGraph: [],
} as Partial<AccountState>;
const stubs = {
VueTree: {
template: '<div class="graph-view"><div/><svg/></div>',
},
};
const mockSetAttribute = jest.fn();
const mockRemToPixels = jest.fn().mockReturnValue(2);
const expectedStyles = `transform: scale(1) translate(2px, 0px); transform-origin: center center;`;

// Act:
const wrapper = getAccountMultisigGraphWrapper(account, stateChanges as AccountState, stubs);
const component = wrapper.vm as AccountMultisigGraphTs;
const vueTreeChildren = (component.$refs['VueTree'] as Vue).$el.children;
vueTreeChildren[0].setAttribute = mockSetAttribute;
vueTreeChildren[1].setAttribute = mockSetAttribute;
component['remToPixels'] = mockRemToPixels;
component['centerGraph']();

// Assert:
expect(mockSetAttribute).toBeCalledTimes(2);
expect(mockSetAttribute).nthCalledWith(1, 'style', expectedStyles);
expect(mockSetAttribute).nthCalledWith(2, 'style', expectedStyles);
});

test('show graph modal', () => {
// Arrange:
const account = ({ address: cosig1Address } as unknown) as AccountModel;
const stateChanges = {
multisigAccountGraph: [],
} as Partial<AccountState>;
const mockUpdateGraphConfig = jest.fn();
const mockCenterGraph = jest.fn();
const stubs = {
VueTree: {
template: '<div class="graph-view"><div/><svg/></div>',
},
};

// Act:
const wrapper = getAccountMultisigGraphWrapper(account, stateChanges as AccountState, stubs);
const graphViewElement = wrapper.find('.graph-view');
const component = wrapper.vm as AccountMultisigGraphTs;
component['updateGraphConfig'] = mockUpdateGraphConfig;
component['centerGraph'] = mockCenterGraph;
component['showGraphModal']();

// Assert:
expect(component.multisigGraphTree[0].info.accountAddress.address).toBe(msigAddress);
expect(component.multisigGraphTree[0].info.cosignatoryAddresses[0].address).toBe(cosig1Address);
expect(component.multisigGraphTree[0].info.cosignatoryAddresses[1].address).toBe(cosig2Address);
expect(component.multisigGraphTree[0].children[0].info.accountAddress.address).toBe(cosig1Address);
expect(component.multisigGraphTree[0].children[1].info.accountAddress.address).toBe(cosig2Address);
expect(component.multisigGraphTree[0].children[0].children[0].info.accountAddress.address).toBe(cosig11Address);
expect(component.multisigGraphTree[0].children[1].children[0].info.accountAddress.address).toBe(cosig21Address);
expect(component.multisigGraphTree[0].children[0].selected).toBe(true);
expect(mockUpdateGraphConfig).toBeCalledTimes(1);
expect(mockCenterGraph).toBeCalledTimes(1);
expect(component.isGraphModalShown).toBe(true);
expect(graphViewElement.exists()).toBe(true);
});
});
Loading

0 comments on commit a1e6bac

Please sign in to comment.