Skip to content

Commit 339df22

Browse files
fix: prevent fetchUserContacts error when user has no contact (#219)
* fix: fix contact fetching error when user has no contacts * test: update and add tests
1 parent 7bdb940 commit 339df22

File tree

2 files changed

+179
-114
lines changed

2 files changed

+179
-114
lines changed

src/utils/subgraphQuery.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export const getValidContact = async (
2929
graphQLClient: GraphQLClient,
3030
contacts: Contact[]
3131
): Promise<Contact[]> => {
32+
if (contacts.length === 0) {
33+
return [];
34+
}
3235
try {
3336
// Contacts addresses
3437
const contactsAddresses = contacts.map((contact) => contact.address);

tests/e2e/fetchUserContacts.test.ts

Lines changed: 176 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -42,120 +42,182 @@ describe('web3mail.fetchMyContacts()', () => {
4242
await waitSubgraphIndexing();
4343
}, 4 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME);
4444

45-
it(
46-
'Tow different user should have different contacts',
47-
async () => {
48-
const user1 = Wallet.createRandom().address;
49-
const user2 = Wallet.createRandom().address;
50-
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
51-
expect(defaultConfig).not.toBeNull();
52-
const authorizedApp = defaultConfig!.dappAddress;
53-
54-
await dataProtector.grantAccess({
55-
authorizedApp: authorizedApp,
56-
protectedData: protectedData1.address,
57-
authorizedUser: user1,
58-
});
59-
60-
await dataProtector.grantAccess({
61-
authorizedApp: authorizedApp,
62-
protectedData: protectedData2.address,
63-
authorizedUser: user2,
64-
});
65-
66-
const contactUser1 = await web3mail.fetchUserContacts({
67-
userAddress: user1,
68-
});
69-
const contactUser2 = await web3mail.fetchUserContacts({
70-
userAddress: user2,
71-
});
72-
expect(contactUser1).not.toEqual(contactUser2);
73-
},
74-
MAX_EXPECTED_WEB2_SERVICES_TIME
75-
);
76-
77-
it(
78-
'Test that the protected data can be accessed by authorized user',
79-
async () => {
80-
const userWithAccess = Wallet.createRandom().address;
81-
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
82-
expect(defaultConfig).not.toBeNull();
83-
const authorizedApp = defaultConfig!.dappAddress;
84-
85-
await dataProtector.grantAccess({
86-
authorizedApp: authorizedApp,
87-
protectedData: protectedData1.address,
88-
authorizedUser: userWithAccess,
89-
});
90-
const contacts = await web3mail.fetchUserContacts({
91-
userAddress: userWithAccess,
92-
});
93-
expect(contacts.length).toBeGreaterThan(0);
94-
},
95-
MAX_EXPECTED_WEB2_SERVICES_TIME
96-
);
97-
98-
it(
99-
'should throw a protocol error',
100-
async () => {
101-
// Call getTestConfig to get the default configuration
102-
const [ethProvider, defaultOptions] = getTestConfig(wallet.privateKey);
103-
const user1 = Wallet.createRandom().address;
104-
105-
const options = {
106-
...defaultOptions,
107-
iexecOptions: {
108-
...defaultOptions.iexecOptions,
109-
iexecGatewayURL: 'https://test',
110-
},
111-
};
112-
113-
// Pass the modified options to IExecWeb3mail
114-
const invalidWeb3mail = new IExecWeb3mail(ethProvider, options);
115-
let error: WorkflowError | undefined;
116-
117-
try {
118-
await invalidWeb3mail.fetchUserContacts({
45+
describe('when no access is granted', () => {
46+
it(
47+
'should return an empty contact array',
48+
async () => {
49+
const userNoAccess = Wallet.createRandom().address;
50+
51+
const contacts = await web3mail.fetchUserContacts({
52+
userAddress: userNoAccess,
53+
isUserStrict: true,
54+
});
55+
expect(contacts.length).toBe(0);
56+
},
57+
2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME
58+
);
59+
});
60+
61+
describe('when access is granted', () => {
62+
it(
63+
'should return the user contacts for both app and whitelist',
64+
async () => {
65+
const userWithAccess = Wallet.createRandom().address;
66+
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
67+
expect(defaultConfig).not.toBeNull();
68+
const authorizedApp = defaultConfig!.dappAddress;
69+
const authorizedWhitelist = defaultConfig!.whitelistSmartContract;
70+
71+
await dataProtector.grantAccess({
72+
authorizedApp: authorizedApp,
73+
protectedData: protectedData1.address,
74+
authorizedUser: userWithAccess,
75+
});
76+
77+
await dataProtector.grantAccess({
78+
authorizedApp: authorizedWhitelist,
79+
protectedData: protectedData2.address,
80+
authorizedUser: userWithAccess,
81+
});
82+
83+
const contacts = await web3mail.fetchUserContacts({
84+
userAddress: userWithAccess,
85+
isUserStrict: true,
86+
});
87+
expect(contacts.length).toBe(2);
88+
},
89+
MAX_EXPECTED_WEB2_SERVICES_TIME
90+
);
91+
92+
it(
93+
'Two different user should have different contacts',
94+
async () => {
95+
const user1 = Wallet.createRandom().address;
96+
const user2 = Wallet.createRandom().address;
97+
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
98+
expect(defaultConfig).not.toBeNull();
99+
const authorizedApp = defaultConfig!.dappAddress;
100+
101+
await dataProtector.grantAccess({
102+
authorizedApp: authorizedApp,
103+
protectedData: protectedData1.address,
104+
authorizedUser: user1,
105+
});
106+
107+
await dataProtector.grantAccess({
108+
authorizedApp: authorizedApp,
109+
protectedData: protectedData2.address,
110+
authorizedUser: user2,
111+
});
112+
113+
const contactUser1 = await web3mail.fetchUserContacts({
119114
userAddress: user1,
120115
});
121-
} catch (err) {
122-
error = err as WorkflowError;
123-
}
124-
125-
expect(error).toBeInstanceOf(WorkflowError);
126-
expect(error?.message).toBe(
127-
"A service in the iExec protocol appears to be unavailable. You can retry later or contact iExec's technical support for help."
128-
);
129-
expect(error?.isProtocolError).toBe(true);
130-
},
131-
2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME
132-
);
133-
134-
it(
135-
'should throw a fetchUserContacts error',
136-
async () => {
137-
// Call getTestConfig to get the default configuration
138-
const [ethProvider, defaultOptions] = getTestConfig(wallet.privateKey);
139-
140-
const options = {
141-
...defaultOptions,
142-
dataProtectorSubgraph: 'https://test',
143-
};
144-
145-
// Pass the modified options to IExecWeb3mail
146-
const invalidWeb3mail = new IExecWeb3mail(ethProvider, options);
147-
let error: WorkflowError | undefined;
148-
149-
try {
150-
await invalidWeb3mail.fetchMyContacts();
151-
} catch (err) {
152-
error = err as WorkflowError;
153-
}
154-
155-
expect(error).toBeInstanceOf(WorkflowError);
156-
expect(error?.message).toBe('Failed to fetch user contacts');
157-
expect(error?.isProtocolError).toBe(false);
158-
},
159-
2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME
160-
);
116+
const contactUser2 = await web3mail.fetchUserContacts({
117+
userAddress: user2,
118+
});
119+
expect(contactUser1).not.toEqual(contactUser2);
120+
},
121+
MAX_EXPECTED_WEB2_SERVICES_TIME
122+
);
123+
124+
it(
125+
'Test that the protected data can be accessed by authorized user',
126+
async () => {
127+
const userWithAccess = Wallet.createRandom().address;
128+
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
129+
expect(defaultConfig).not.toBeNull();
130+
const authorizedApp = defaultConfig!.dappAddress;
131+
132+
await dataProtector.grantAccess({
133+
authorizedApp: authorizedApp,
134+
protectedData: protectedData1.address,
135+
authorizedUser: userWithAccess,
136+
});
137+
const contacts = await web3mail.fetchUserContacts({
138+
userAddress: userWithAccess,
139+
});
140+
expect(contacts.length).toBeGreaterThan(0);
141+
},
142+
MAX_EXPECTED_WEB2_SERVICES_TIME
143+
);
144+
});
145+
146+
describe('when iexec market API is not reachable', () => {
147+
it(
148+
'should throw a protocol error',
149+
async () => {
150+
// Call getTestConfig to get the default configuration
151+
const [ethProvider, defaultOptions] = getTestConfig(wallet.privateKey);
152+
const user1 = Wallet.createRandom().address;
153+
154+
const options = {
155+
...defaultOptions,
156+
iexecOptions: {
157+
...defaultOptions.iexecOptions,
158+
iexecGatewayURL: 'https://test',
159+
},
160+
};
161+
162+
// Pass the modified options to IExecWeb3mail
163+
const invalidWeb3mail = new IExecWeb3mail(ethProvider, options);
164+
let error: WorkflowError | undefined;
165+
166+
try {
167+
await invalidWeb3mail.fetchUserContacts({
168+
userAddress: user1,
169+
});
170+
} catch (err) {
171+
error = err as WorkflowError;
172+
}
173+
174+
expect(error).toBeInstanceOf(WorkflowError);
175+
expect(error?.message).toBe(
176+
"A service in the iExec protocol appears to be unavailable. You can retry later or contact iExec's technical support for help."
177+
);
178+
expect(error?.isProtocolError).toBe(true);
179+
},
180+
2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME
181+
);
182+
});
183+
184+
describe('when subgraph is not reachable', () => {
185+
it(
186+
'should throw a fetchUserContacts error',
187+
async () => {
188+
// Call getTestConfig to get the default configuration
189+
const [ethProvider, defaultOptions] = getTestConfig(wallet.privateKey);
190+
191+
const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID);
192+
expect(defaultConfig).not.toBeNull();
193+
const authorizedApp = defaultConfig!.dappAddress;
194+
195+
await dataProtector.grantAccess({
196+
authorizedApp: authorizedApp,
197+
protectedData: protectedData1.address,
198+
authorizedUser: ethProvider.address,
199+
});
200+
201+
const options = {
202+
...defaultOptions,
203+
dataProtectorSubgraph: 'https://test',
204+
};
205+
206+
// Pass the modified options to IExecWeb3mail
207+
const invalidWeb3mail = new IExecWeb3mail(ethProvider, options);
208+
let error: WorkflowError | undefined;
209+
210+
try {
211+
await invalidWeb3mail.fetchMyContacts();
212+
} catch (err) {
213+
error = err as WorkflowError;
214+
}
215+
216+
expect(error).toBeInstanceOf(WorkflowError);
217+
expect(error?.message).toBe('Failed to fetch user contacts');
218+
expect(error?.isProtocolError).toBe(false);
219+
},
220+
2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME
221+
);
222+
});
161223
});

0 commit comments

Comments
 (0)