This repository has been archived by the owner on Jan 4, 2024. It is now read-only.
/
index.js
164 lines (148 loc) 路 5.89 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
const AssertionError = require('assertion-error');
/* Creates a new assertion message, containing the passedAssertionMessage and
* the defaultAssertion message when passedAssertionMessage exists, otherwise
* just the default.
*/
createAssertionMessage = (passedMessage, defaultMessage) => {
let assertionMessage = defaultMessage;
if (passedMessage) {
assertionMessage = `${passedMessage} : ${defaultMessage}`;
}
return assertionMessage;
}
assertEventListNotEmpty = (list, passedMessage, defaultMessage) => {
const assertionMessage = createAssertionMessage(passedMessage, defaultMessage);
if (!Array.isArray(list) || list.length === 0) {
throw new AssertionError(assertionMessage);
}
}
assertEventListEmpty = (list, passedMessage, defaultMessage) => {
const assertionMessage = createAssertionMessage(passedMessage, defaultMessage);
if (Array.isArray(list) && list.length !== 0) {
throw new AssertionError(assertionMessage);
}
}
/* Returns event string in the form of EventType(arg1, arg2, ...) */
getPrettyEventString = (eventType, args) => {
let argString = '';
Object.entries(args).forEach(([key, value]) => {
argString += `, ${key}: ${value}`;
});
argString = argString.replace(', ', '');
return `${eventType}(${argString})`;
}
/* Returns a list of all emitted events in a transaction,
* using the format of getPrettyEventString
*/
getPrettyEmittedEventsString = (result) => {
if (result.logs.length === 0) {
return ` No events emitted in tx ${result.tx}\n`;
}
let string = ` Events emitted in tx ${result.tx}:\n`;
string += ` ----------------------------------------------------------------------------------------\n`;
for (const emittedEvent of result.logs) {
string += ` ${getPrettyEventString(emittedEvent.event, emittedEvent.args)}\n`;
}
string += ` ----------------------------------------------------------------------------------------\n`;
return string;
}
assertEventEmittedFromTxResult = (result, eventType, filter, message) => {
/* Filter correct event types */
const events = result.logs.filter((entry) => {
return entry.event === eventType;
});
//TODO: Move the getPrettyEmittedEventsString to the assertion functions
assertEventListNotEmpty(events, message, `Event of type ${eventType} was not emitted\n${getPrettyEmittedEventsString(result)}`);
/* Return if no filter function was provided */
if (filter === undefined || filter === null) {
return;
}
/* Filter correct arguments */
let eventArgs = events.map((entry) => {
return entry.args;
});
eventArgs = eventArgs.filter(filter);
assertEventListNotEmpty(eventArgs, message, `Event filter for ${eventType} returned no results\n${getPrettyEmittedEventsString(result)}`);
}
assertEventNotEmittedFromTxResult = (result, eventType, filter, message) => {
/* Filter correct event types */
const events = result.logs.filter((entry) => {
return entry.event === eventType;
});
/* Only check filtered events if there is no provided filter function */
if (filter == undefined || filter === null) {
assertEventListEmpty(events, message, `Event of type ${eventType} was emitted\n${getPrettyEmittedEventsString(result)}`);
return;
}
/* Filter correct arguments */
let eventArgs = events.map((entry) => {
return entry.args;
});
eventArgs = eventArgs.filter(filter);
assertEventListEmpty(eventArgs, message, `Event filter for ${eventType} returned results\n${getPrettyEmittedEventsString(result)}`);
}
createTransactionResult = async (contract, transactionHash) => {
const transactionReceipt = web3.eth.getTransactionReceipt(transactionHash);
const blockNumber = transactionReceipt.blockNumber;
/* Web3 1.x uses contract.getPastEvents, Web3 0.x uses contract.allEvents() */
/* TODO: truffle-assertions 1.0 will only support Web3 1.x / Truffle v5 */
if (contract.getPastEvents) {
const eventList = await contract.getPastEvents("allEvents", {fromBlock: blockNumber, toBlock: blockNumber});
return {
tx: transactionHash,
receipt: transactionReceipt,
logs: eventList.filter(ev => ev.transactionHash === transactionHash)
};
} else {
return new Promise((resolve, reject) => {
contract.allEvents({fromBlock: blockNumber, toBlock: blockNumber}).get((error, events) => {
if (error) reject(error);
resolve({
tx: transactionHash,
receipt: transactionReceipt,
logs: events.filter(ev => ev.transactionHash === transactionHash)
});
});
});
}
}
fails = async (asyncFn, errorType, reason, message) => {
try {
await asyncFn;
const assertionMessage = createAssertionMessage(message, 'Did not fail');
throw new AssertionError(assertionMessage);
} catch (error) {
if (errorType && !error.message.includes(errorType) ||
reason && !error.message.includes(reason)) {
const assertionMessage = createAssertionMessage(message, `Expected to fail with ${errorType}, but failed with: ${error}`);
throw new AssertionError(assertionMessage);
}
}
}
ErrorType = {
REVERT: "revert",
INVALID_OPCODE: "invalid opcode",
OUT_OF_GAS: "out of gas",
INVALID_JUMP: "invalid JUMP"
}
module.exports = {
eventEmitted: (result, eventType, filter, message) => {
assertEventEmittedFromTxResult(result, eventType, filter, message);
},
eventNotEmitted: (result, eventType, filter, message) => {
assertEventNotEmittedFromTxResult(result, eventType, filter, message);
},
prettyPrintEmittedEvents: (result) => {
console.log(getPrettyEmittedEventsString(result));
},
createTransactionResult: (contract, transactionHash) => {
return createTransactionResult(contract, transactionHash);
},
fails: async (asyncFn, errorType, reason, message) => {
return fails(asyncFn, errorType, reason, message);
},
reverts: async (asyncFn, reason, message) => {
return fails(asyncFn, ErrorType.REVERT, reason, message);
},
ErrorType: ErrorType
}