@graphprotocol/graph-cli 0.32.0 → 0.34.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/README.md +1 -1
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/ethereum.ts +200 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/global/global.ts +28 -28
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/methods.txt +18 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/package.json +1 -1
- package/examples/basic-event-handlers/node_modules/keccak/build/Makefile +342 -0
- package/examples/basic-event-handlers/node_modules/keccak/build/Release/.deps/Release/obj.target/keccak/src/addon.o.d.raw +69 -0
- package/examples/basic-event-handlers/node_modules/keccak/build/binding.Makefile +6 -0
- package/examples/basic-event-handlers/node_modules/keccak/build/config.gypi +27 -11
- package/examples/basic-event-handlers/node_modules/keccak/build/gyp-mac-tool +772 -0
- package/examples/basic-event-handlers/node_modules/keccak/build/keccak.target.mk +207 -0
- package/examples/basic-event-handlers/node_modules/websocket/build/Makefile +347 -0
- package/examples/basic-event-handlers/node_modules/websocket/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d.raw +67 -0
- package/examples/basic-event-handlers/node_modules/websocket/build/binding.Makefile +6 -0
- package/examples/basic-event-handlers/node_modules/websocket/build/bufferutil.target.mk +190 -0
- package/examples/basic-event-handlers/node_modules/websocket/build/config.gypi +23 -7
- package/examples/basic-event-handlers/node_modules/websocket/build/gyp-mac-tool +772 -0
- package/examples/basic-event-handlers/node_modules/websocket/build/validation.target.mk +190 -0
- package/examples/basic-event-handlers/package.json +1 -1
- package/examples/basic-event-handlers/yarn.lock +4 -4
- package/examples/example-subgraph/package.json +1 -1
- package/examples/example-subgraph/yarn.lock +4 -4
- package/package.json +1 -1
- package/src/codegen/template.js +8 -1
- package/src/codegen/types/conversions.js +103 -2
- package/src/codegen/types/index.test.js +347 -0
- package/src/command-helpers/abi.js +3 -0
- package/src/command-helpers/jsonrpc.js +5 -1
- package/src/command-helpers/scaffold.js +43 -14
- package/src/command-helpers/studio.js +1 -1
- package/src/commands/add.js +2 -1
- package/src/commands/init.js +6 -6
- package/src/commands/test.js +5 -9
- package/src/migrations/mapping_api_version_0_0_4.js +1 -1
- package/src/migrations/mapping_api_version_0_0_5.js +1 -1
- package/src/protocols/index.js +4 -4
- package/src/protocols/ipfs/codegen/file_template.js +40 -0
- package/src/scaffold/ethereum.test.js +259 -0
- package/src/scaffold/index.js +16 -1
- package/src/scaffold/tests.js +196 -0
- package/src/subgraph.js +10 -4
|
@@ -243,6 +243,265 @@ export function handleExampleEvent1(event: ExampleEvent1Event): void {
|
|
|
243
243
|
entity.a = event.params.a
|
|
244
244
|
entity.save()
|
|
245
245
|
}
|
|
246
|
+
`)
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
test('Test Files (default)', () => {
|
|
250
|
+
const files = scaffoldWithIndexEvents.generateTests()
|
|
251
|
+
const testFile = files['contract.test.ts']
|
|
252
|
+
const utilsFile = files['contract-utils.ts']
|
|
253
|
+
expect(testFile).toEqual(`\
|
|
254
|
+
import {
|
|
255
|
+
assert,
|
|
256
|
+
describe,
|
|
257
|
+
test,
|
|
258
|
+
clearStore,
|
|
259
|
+
beforeAll,
|
|
260
|
+
afterAll
|
|
261
|
+
} from \"matchstick-as/assembly/index\"
|
|
262
|
+
import { BigInt, Bytes } from \"@graphprotocol/graph-ts\"
|
|
263
|
+
import { ExampleEvent } from \"../generated/schema\"
|
|
264
|
+
import { ExampleEvent as ExampleEventEvent } from \"../generated/Contract/Contract\"
|
|
265
|
+
import { handleExampleEvent } from \"../src/contract\"
|
|
266
|
+
import { createExampleEventEvent } from \"./contract-utils\"
|
|
267
|
+
|
|
268
|
+
// Tests structure (matchstick-as >=0.5.0)
|
|
269
|
+
// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0
|
|
270
|
+
|
|
271
|
+
describe(\"Describe entity assertions\", () => {
|
|
272
|
+
beforeAll(() => {
|
|
273
|
+
let a = BigInt.fromI32(234)
|
|
274
|
+
let b = [Bytes.fromI32(1234567890)]
|
|
275
|
+
let param2 = \"Example string value\"
|
|
276
|
+
let c = \"ethereum.Tuple Not implemented\"
|
|
277
|
+
let d = \"Example string value\"
|
|
278
|
+
let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d)
|
|
279
|
+
handleExampleEvent(newExampleEventEvent)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
afterAll(() => {
|
|
283
|
+
clearStore()
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
// For more test scenarios, see:
|
|
287
|
+
// https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test
|
|
288
|
+
|
|
289
|
+
test(\"ExampleEvent created and stored\", () => {
|
|
290
|
+
assert.entityCount(\"ExampleEvent\", 1)
|
|
291
|
+
|
|
292
|
+
// 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function
|
|
293
|
+
assert.fieldEquals(
|
|
294
|
+
\"ExampleEvent\",
|
|
295
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
296
|
+
\"a\",
|
|
297
|
+
\"234\"
|
|
298
|
+
)
|
|
299
|
+
assert.fieldEquals(
|
|
300
|
+
\"ExampleEvent\",
|
|
301
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
302
|
+
\"b\",
|
|
303
|
+
\"[1234567890]\"
|
|
304
|
+
)
|
|
305
|
+
assert.fieldEquals(
|
|
306
|
+
\"ExampleEvent\",
|
|
307
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
308
|
+
\"param2\",
|
|
309
|
+
\"Example string value\"
|
|
310
|
+
)
|
|
311
|
+
assert.fieldEquals(
|
|
312
|
+
\"ExampleEvent\",
|
|
313
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
314
|
+
\"c\",
|
|
315
|
+
\"ethereum.Tuple Not implemented\"
|
|
316
|
+
)
|
|
317
|
+
assert.fieldEquals(
|
|
318
|
+
\"ExampleEvent\",
|
|
319
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
320
|
+
\"d\",
|
|
321
|
+
\"Example string value\"
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
// More assert options:
|
|
325
|
+
// https://thegraph.com/docs/en/developer/matchstick/#asserts
|
|
326
|
+
})
|
|
327
|
+
})
|
|
328
|
+
`)
|
|
329
|
+
expect(utilsFile).toEqual(`\
|
|
330
|
+
import { newMockEvent } from \"matchstick-as\"
|
|
331
|
+
import { ethereum, BigInt, Bytes } from \"@graphprotocol/graph-ts\"
|
|
332
|
+
import { ExampleEvent, ExampleEvent1 } from \"../generated/Contract/Contract\"
|
|
333
|
+
|
|
334
|
+
export function createExampleEventEvent(
|
|
335
|
+
a: BigInt,
|
|
336
|
+
b: Array<Bytes>,
|
|
337
|
+
param2: string,
|
|
338
|
+
c: ethereum.Tuple,
|
|
339
|
+
d: string
|
|
340
|
+
): ExampleEvent {
|
|
341
|
+
let exampleEventEvent = changetype<ExampleEvent>(newMockEvent())
|
|
342
|
+
|
|
343
|
+
exampleEventEvent.parameters = new Array()
|
|
344
|
+
|
|
345
|
+
exampleEventEvent.parameters.push(
|
|
346
|
+
new ethereum.EventParam(\"a\", ethereum.Value.fromUnsignedBigInt(a))
|
|
347
|
+
)
|
|
348
|
+
exampleEventEvent.parameters.push(
|
|
349
|
+
new ethereum.EventParam(\"b\", ethereum.Value.fromBytesArray(b))
|
|
350
|
+
)
|
|
351
|
+
exampleEventEvent.parameters.push(
|
|
352
|
+
new ethereum.EventParam(\"param2\", ethereum.Value.fromString(param2))
|
|
353
|
+
)
|
|
354
|
+
exampleEventEvent.parameters.push(
|
|
355
|
+
new ethereum.EventParam(\"c\", ethereum.Value.fromTuple(c))
|
|
356
|
+
)
|
|
357
|
+
exampleEventEvent.parameters.push(
|
|
358
|
+
new ethereum.EventParam(\"d\", ethereum.Value.fromString(d))
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
return exampleEventEvent
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function createExampleEvent1Event(a: Bytes): ExampleEvent1 {
|
|
365
|
+
let exampleEvent1Event = changetype<ExampleEvent1>(newMockEvent())
|
|
366
|
+
|
|
367
|
+
exampleEvent1Event.parameters = new Array()
|
|
368
|
+
|
|
369
|
+
exampleEvent1Event.parameters.push(
|
|
370
|
+
new ethereum.EventParam(\"a\", ethereum.Value.fromFixedBytes(a))
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
return exampleEvent1Event
|
|
374
|
+
}
|
|
375
|
+
`)
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
test('Test Files (for indexing events)', () => {
|
|
379
|
+
const files = scaffoldWithIndexEvents.generateTests()
|
|
380
|
+
const testFile = files['contract.test.ts']
|
|
381
|
+
const utilsFile = files['contract-utils.ts']
|
|
382
|
+
|
|
383
|
+
expect(testFile).toEqual(`\
|
|
384
|
+
import {
|
|
385
|
+
assert,
|
|
386
|
+
describe,
|
|
387
|
+
test,
|
|
388
|
+
clearStore,
|
|
389
|
+
beforeAll,
|
|
390
|
+
afterAll
|
|
391
|
+
} from \"matchstick-as/assembly/index\"
|
|
392
|
+
import { BigInt, Bytes } from \"@graphprotocol/graph-ts\"
|
|
393
|
+
import { ExampleEvent } from \"../generated/schema\"
|
|
394
|
+
import { ExampleEvent as ExampleEventEvent } from \"../generated/Contract/Contract\"
|
|
395
|
+
import { handleExampleEvent } from \"../src/contract\"
|
|
396
|
+
import { createExampleEventEvent } from \"./contract-utils\"
|
|
397
|
+
|
|
398
|
+
// Tests structure (matchstick-as >=0.5.0)
|
|
399
|
+
// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0
|
|
400
|
+
|
|
401
|
+
describe(\"Describe entity assertions\", () => {
|
|
402
|
+
beforeAll(() => {
|
|
403
|
+
let a = BigInt.fromI32(234)
|
|
404
|
+
let b = [Bytes.fromI32(1234567890)]
|
|
405
|
+
let param2 = \"Example string value\"
|
|
406
|
+
let c = \"ethereum.Tuple Not implemented\"
|
|
407
|
+
let d = \"Example string value\"
|
|
408
|
+
let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d)
|
|
409
|
+
handleExampleEvent(newExampleEventEvent)
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
afterAll(() => {
|
|
413
|
+
clearStore()
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
// For more test scenarios, see:
|
|
417
|
+
// https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test
|
|
418
|
+
|
|
419
|
+
test(\"ExampleEvent created and stored\", () => {
|
|
420
|
+
assert.entityCount(\"ExampleEvent\", 1)
|
|
421
|
+
|
|
422
|
+
// 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function
|
|
423
|
+
assert.fieldEquals(
|
|
424
|
+
\"ExampleEvent\",
|
|
425
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
426
|
+
\"a\",
|
|
427
|
+
\"234\"
|
|
428
|
+
)
|
|
429
|
+
assert.fieldEquals(
|
|
430
|
+
\"ExampleEvent\",
|
|
431
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
432
|
+
\"b\",
|
|
433
|
+
\"[1234567890]\"
|
|
434
|
+
)
|
|
435
|
+
assert.fieldEquals(
|
|
436
|
+
\"ExampleEvent\",
|
|
437
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
438
|
+
\"param2\",
|
|
439
|
+
\"Example string value\"
|
|
440
|
+
)
|
|
441
|
+
assert.fieldEquals(
|
|
442
|
+
\"ExampleEvent\",
|
|
443
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
444
|
+
\"c\",
|
|
445
|
+
\"ethereum.Tuple Not implemented\"
|
|
446
|
+
)
|
|
447
|
+
assert.fieldEquals(
|
|
448
|
+
\"ExampleEvent\",
|
|
449
|
+
\"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\",
|
|
450
|
+
\"d\",
|
|
451
|
+
\"Example string value\"
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
// More assert options:
|
|
455
|
+
// https://thegraph.com/docs/en/developer/matchstick/#asserts
|
|
456
|
+
})
|
|
457
|
+
})
|
|
458
|
+
`)
|
|
459
|
+
expect(utilsFile).toEqual(`\
|
|
460
|
+
import { newMockEvent } from \"matchstick-as\"
|
|
461
|
+
import { ethereum, BigInt, Bytes } from \"@graphprotocol/graph-ts\"
|
|
462
|
+
import { ExampleEvent, ExampleEvent1 } from \"../generated/Contract/Contract\"
|
|
463
|
+
|
|
464
|
+
export function createExampleEventEvent(
|
|
465
|
+
a: BigInt,
|
|
466
|
+
b: Array<Bytes>,
|
|
467
|
+
param2: string,
|
|
468
|
+
c: ethereum.Tuple,
|
|
469
|
+
d: string
|
|
470
|
+
): ExampleEvent {
|
|
471
|
+
let exampleEventEvent = changetype<ExampleEvent>(newMockEvent())
|
|
472
|
+
|
|
473
|
+
exampleEventEvent.parameters = new Array()
|
|
474
|
+
|
|
475
|
+
exampleEventEvent.parameters.push(
|
|
476
|
+
new ethereum.EventParam(\"a\", ethereum.Value.fromUnsignedBigInt(a))
|
|
477
|
+
)
|
|
478
|
+
exampleEventEvent.parameters.push(
|
|
479
|
+
new ethereum.EventParam(\"b\", ethereum.Value.fromBytesArray(b))
|
|
480
|
+
)
|
|
481
|
+
exampleEventEvent.parameters.push(
|
|
482
|
+
new ethereum.EventParam(\"param2\", ethereum.Value.fromString(param2))
|
|
483
|
+
)
|
|
484
|
+
exampleEventEvent.parameters.push(
|
|
485
|
+
new ethereum.EventParam(\"c\", ethereum.Value.fromTuple(c))
|
|
486
|
+
)
|
|
487
|
+
exampleEventEvent.parameters.push(
|
|
488
|
+
new ethereum.EventParam(\"d\", ethereum.Value.fromString(d))
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
return exampleEventEvent
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export function createExampleEvent1Event(a: Bytes): ExampleEvent1 {
|
|
495
|
+
let exampleEvent1Event = changetype<ExampleEvent1>(newMockEvent())
|
|
496
|
+
|
|
497
|
+
exampleEvent1Event.parameters = new Array()
|
|
498
|
+
|
|
499
|
+
exampleEvent1Event.parameters.push(
|
|
500
|
+
new ethereum.EventParam(\"a\", ethereum.Value.fromFixedBytes(a))
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
return exampleEvent1Event
|
|
504
|
+
}
|
|
246
505
|
`)
|
|
247
506
|
})
|
|
248
507
|
})
|
package/src/scaffold/index.js
CHANGED
|
@@ -15,6 +15,7 @@ const {
|
|
|
15
15
|
generateExampleEntityType,
|
|
16
16
|
} = require('./schema')
|
|
17
17
|
const { generateEventIndexingHandlers } = require('./mapping')
|
|
18
|
+
const { generateTestsFiles } = require('./tests')
|
|
18
19
|
const { getSubgraphBasename } = require('../command-helpers/subgraph')
|
|
19
20
|
|
|
20
21
|
module.exports = class Scaffold {
|
|
@@ -48,11 +49,13 @@ module.exports = class Scaffold {
|
|
|
48
49
|
`--node http://localhost:8020/ ` +
|
|
49
50
|
`--ipfs http://localhost:5001 ` +
|
|
50
51
|
this.subgraphName,
|
|
52
|
+
'test': 'graph test',
|
|
51
53
|
},
|
|
52
54
|
dependencies: {
|
|
53
55
|
'@graphprotocol/graph-cli': GRAPH_CLI_VERSION,
|
|
54
|
-
'@graphprotocol/graph-ts': `0.
|
|
56
|
+
'@graphprotocol/graph-ts': `0.28.0-alpha.0`,
|
|
55
57
|
},
|
|
58
|
+
devDependencies: this.protocol.hasEvents() ? { 'matchstick-as': `0.5.0`} : undefined,
|
|
56
59
|
}),
|
|
57
60
|
{ parser: 'json' },
|
|
58
61
|
)
|
|
@@ -137,6 +140,17 @@ dataSources:
|
|
|
137
140
|
: undefined
|
|
138
141
|
}
|
|
139
142
|
|
|
143
|
+
generateTests() {
|
|
144
|
+
const hasEvents = this.protocol.hasEvents()
|
|
145
|
+
const events = hasEvents
|
|
146
|
+
? abiEvents(this.abi).toJS()
|
|
147
|
+
: []
|
|
148
|
+
|
|
149
|
+
return events.length > 0
|
|
150
|
+
? generateTestsFiles(this.contractName, events, this.indexEvents)
|
|
151
|
+
: undefined
|
|
152
|
+
}
|
|
153
|
+
|
|
140
154
|
generate() {
|
|
141
155
|
return {
|
|
142
156
|
'package.json': this.generatePackageJson(),
|
|
@@ -145,6 +159,7 @@ dataSources:
|
|
|
145
159
|
'tsconfig.json': this.generateTsConfig(),
|
|
146
160
|
src: { [`${strings.kebabCase(this.contractName)}.ts`]: this.generateMapping() },
|
|
147
161
|
abis: this.generateABIs(),
|
|
162
|
+
tests: this.generateTests(),
|
|
148
163
|
}
|
|
149
164
|
}
|
|
150
165
|
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
const prettier = require('prettier')
|
|
2
|
+
const { strings } = require('gluegun')
|
|
3
|
+
const { ascTypeForEthereum, ethereumFromAsc } = require("../codegen/types")
|
|
4
|
+
|
|
5
|
+
const VARIABLES_VALUES = {
|
|
6
|
+
"i32": 123,
|
|
7
|
+
"BigInt": 234,
|
|
8
|
+
"Bytes": 1234567890,
|
|
9
|
+
"Address": "0x0000000000000000000000000000000000000001",
|
|
10
|
+
"string": "Example string value",
|
|
11
|
+
"bool": true,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const generateTestsFiles = (contract, events, indexEvents) => {
|
|
15
|
+
const eventsTypes = events
|
|
16
|
+
.flatMap(event =>
|
|
17
|
+
event
|
|
18
|
+
.inputs
|
|
19
|
+
.map(input => {
|
|
20
|
+
// If the asc type is Array<T> we need to check if T is a native type or a custom graph-ts type
|
|
21
|
+
// If we don't do that we may miss a type that should be imported from graph-ts
|
|
22
|
+
const ascType = ascTypeForEthereum(input.type)
|
|
23
|
+
const inner = fetchArrayInnerType(ascType)
|
|
24
|
+
return inner ? inner[1] : ascType
|
|
25
|
+
})
|
|
26
|
+
).filter(type => !type.startsWith("ethereum.") && !isNativeType(type))
|
|
27
|
+
const importTypes = [...new Set(eventsTypes)].join(', ')
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
[`${strings.kebabCase(contract)}.test.ts`]: prettier.format(generateExampleTest(contract, events[0], indexEvents, importTypes), { parser: 'typescript', semi: false }),
|
|
31
|
+
[`${strings.kebabCase(contract)}-utils.ts`]: prettier.format(generateTestHelper(contract, events, importTypes), { parser: 'typescript', semi: false }),
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
Generates the arguments that will be passed to the mock event function from the event inputs. Example:
|
|
37
|
+
let id = BigInt.fromI32(234)
|
|
38
|
+
let owner = Address.fromString("0x0000000000000000000000000000000000000001")
|
|
39
|
+
let displayName = "Example string value"
|
|
40
|
+
let imageUrl = "Example string value"
|
|
41
|
+
*/
|
|
42
|
+
const generateArguments = (eventInputs) => {
|
|
43
|
+
return eventInputs.map((input, index) => {
|
|
44
|
+
let ascType = ascTypeForEthereum(input.type)
|
|
45
|
+
return `let ${input.name || `param${index}`} = ${assignValue(ascType, input.name)}`
|
|
46
|
+
}).join('\n')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Generates the value that will be assigned to a variable in generateArguments()
|
|
50
|
+
const assignValue = (type) => {
|
|
51
|
+
switch (type) {
|
|
52
|
+
case "string":
|
|
53
|
+
return `"${VARIABLES_VALUES[type]}"`
|
|
54
|
+
case "BigInt":
|
|
55
|
+
return `BigInt.fromI32(${VARIABLES_VALUES[type]})`
|
|
56
|
+
case "Address":
|
|
57
|
+
return `Address.fromString("${VARIABLES_VALUES[type]}")`
|
|
58
|
+
case "Bytes":
|
|
59
|
+
return `Bytes.fromI32(${VARIABLES_VALUES[type]})`
|
|
60
|
+
case fetchArrayInnerType(type)?.input:
|
|
61
|
+
innerType = fetchArrayInnerType(type)[1]
|
|
62
|
+
return `[${assignValue(innerType)}]`
|
|
63
|
+
default:
|
|
64
|
+
let value = VARIABLES_VALUES[type]
|
|
65
|
+
return value ? value : `"${type} Not implemented"`
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/*
|
|
70
|
+
Generates the assert.fieldEquals() for a given entity and event inputs. Example:
|
|
71
|
+
assert.fieldEquals(
|
|
72
|
+
"ExampleEntity",
|
|
73
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a",
|
|
74
|
+
"owner",
|
|
75
|
+
"0x0000000000000000000000000000000000000001"
|
|
76
|
+
)
|
|
77
|
+
*/
|
|
78
|
+
const generateFieldsAssertions = (entity, eventInputs, indexEvents) => eventInputs.filter(input => input.name != "id").map((input, index) =>
|
|
79
|
+
`assert.fieldEquals(
|
|
80
|
+
"${entity}",
|
|
81
|
+
"0xa16081f360e3847006db660bae1c6d1b2e17ec2a${indexEvents ? "-1" : ""}",
|
|
82
|
+
"${input.name || `param${index}`}",
|
|
83
|
+
"${expectedValue(ascTypeForEthereum(input.type))}"
|
|
84
|
+
)`
|
|
85
|
+
).join('\n')
|
|
86
|
+
|
|
87
|
+
// Returns the expected value for a given type in generateFieldsAssertions()
|
|
88
|
+
const expectedValue = type => {
|
|
89
|
+
switch (type) {
|
|
90
|
+
case fetchArrayInnerType(type)?.input:
|
|
91
|
+
innerType = fetchArrayInnerType(type)[1]
|
|
92
|
+
return `[${expectedValue(innerType)}]`
|
|
93
|
+
default:
|
|
94
|
+
let value = VARIABLES_VALUES[type]
|
|
95
|
+
return value ? value : `${type} Not implemented`
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Checks if the type is a native AS type or should be imported from graph-ts
|
|
100
|
+
const isNativeType = type => {
|
|
101
|
+
let natives = [
|
|
102
|
+
/i32/,
|
|
103
|
+
/string/,
|
|
104
|
+
/boolean/
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
return natives.some(rx => rx.test(type));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const fetchArrayInnerType = type => type.match(/Array<(.*?)>/)
|
|
111
|
+
|
|
112
|
+
// Generates the example test.ts file
|
|
113
|
+
const generateExampleTest = (contract, event, indexEvents, importTypes) => {
|
|
114
|
+
const entity = indexEvents ? `${event._alias}` : 'ExampleEntity'
|
|
115
|
+
const eventInputs = event.inputs
|
|
116
|
+
const eventName = event._alias
|
|
117
|
+
|
|
118
|
+
return `
|
|
119
|
+
import { assert, describe, test, clearStore, beforeAll, afterAll } from "matchstick-as/assembly/index"
|
|
120
|
+
import { ${importTypes} } from "@graphprotocol/graph-ts"
|
|
121
|
+
import { ${entity} } from "../generated/schema"
|
|
122
|
+
import { ${indexEvents ? `${eventName} as ${eventName}Event` : eventName} } from "../generated/${contract}/${contract}"
|
|
123
|
+
import { handle${eventName} } from "../src/${strings.kebabCase(contract)}"
|
|
124
|
+
import { create${eventName}Event } from "./${strings.kebabCase(contract)}-utils"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
// Tests structure (matchstick-as >=0.5.0)
|
|
128
|
+
// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0
|
|
129
|
+
|
|
130
|
+
describe("Describe entity assertions", () => {
|
|
131
|
+
beforeAll(() => {
|
|
132
|
+
${generateArguments(eventInputs)}
|
|
133
|
+
let new${eventName}Event = create${eventName}Event(${eventInputs.map((input, index) => input.name || `param${index}`).join(', ')});
|
|
134
|
+
handle${eventName}(new${eventName}Event)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
afterAll(() => {
|
|
138
|
+
clearStore()
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
// For more test scenarios, see:
|
|
142
|
+
// https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test
|
|
143
|
+
|
|
144
|
+
test("${entity} created and stored", () => {
|
|
145
|
+
assert.entityCount('${entity}', 1)
|
|
146
|
+
|
|
147
|
+
// 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function
|
|
148
|
+
${generateFieldsAssertions(entity, eventInputs, indexEvents)}
|
|
149
|
+
|
|
150
|
+
// More assert options:
|
|
151
|
+
// https://thegraph.com/docs/en/developer/matchstick/#asserts
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
`
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Generates the utils helper file
|
|
158
|
+
const generateTestHelper = (contract, events, importTypes) => {
|
|
159
|
+
const eventsNames = events.map(event => event._alias)
|
|
160
|
+
|
|
161
|
+
return `
|
|
162
|
+
import { newMockEvent } from 'matchstick-as';
|
|
163
|
+
import { ethereum, ${importTypes} } from '@graphprotocol/graph-ts';
|
|
164
|
+
import { ${eventsNames.join(", ")} } from '../generated/${contract}/${contract}';
|
|
165
|
+
|
|
166
|
+
${generateMockedEvents(events).join("\n")}`
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const generateMockedEvents = events =>
|
|
170
|
+
events.reduce(
|
|
171
|
+
(acc, event) => acc.concat(generateMockedEvent(event)),
|
|
172
|
+
[],
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
const generateMockedEvent = event => {
|
|
176
|
+
const varName = `${strings.camelCase(event._alias)}Event`
|
|
177
|
+
const fnArgs = event.inputs.map((input, index) => `${input.name || `param${index}`}: ${ascTypeForEthereum(input.type)}`);
|
|
178
|
+
const ascToEth = event.inputs.map((input, index) => `${varName}.parameters.push(new ethereum.EventParam("${input.name || `param${index}`}", ${ethereumFromAsc(input.name || `param${index}`, input.type)}))`);
|
|
179
|
+
|
|
180
|
+
return `
|
|
181
|
+
export function create${event._alias}Event(${fnArgs.join(', ')}): ${event._alias} {
|
|
182
|
+
let ${varName} = changetype<${event._alias}>(newMockEvent());
|
|
183
|
+
|
|
184
|
+
${varName}.parameters = new Array();
|
|
185
|
+
|
|
186
|
+
${ascToEth.join('\n')}
|
|
187
|
+
|
|
188
|
+
return ${varName};
|
|
189
|
+
}
|
|
190
|
+
`
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
generateTestsFiles,
|
|
196
|
+
}
|
package/src/subgraph.js
CHANGED
|
@@ -216,20 +216,26 @@ More than one template named '${name}', template names must be unique.`,
|
|
|
216
216
|
static async load(filename, { protocol, skipValidation } = { skipValidation: false }) {
|
|
217
217
|
// Load and validate the manifest
|
|
218
218
|
let data = null
|
|
219
|
+
let has_file_data_sources = false
|
|
219
220
|
|
|
220
221
|
if (filename.match(/.js$/)) {
|
|
221
222
|
data = require(path.resolve(filename))
|
|
222
223
|
} else {
|
|
223
|
-
|
|
224
|
+
let raw_data = await fs.readFile(filename, 'utf-8')
|
|
225
|
+
has_file_data_sources = raw_data.includes('kind: file')
|
|
226
|
+
data = yaml.parse(raw_data)
|
|
224
227
|
}
|
|
225
228
|
|
|
226
229
|
// Helper to resolve files relative to the subgraph manifest
|
|
227
230
|
let resolveFile = maybeRelativeFile =>
|
|
228
231
|
path.resolve(path.dirname(filename), maybeRelativeFile)
|
|
229
232
|
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
+
// TODO: Validation for file data sources
|
|
234
|
+
if (!has_file_data_sources) {
|
|
235
|
+
let manifestErrors = await Subgraph.validate(data, protocol, { resolveFile })
|
|
236
|
+
if (manifestErrors.size > 0) {
|
|
237
|
+
throwCombinedError(filename, manifestErrors)
|
|
238
|
+
}
|
|
233
239
|
}
|
|
234
240
|
|
|
235
241
|
let manifest = immutable.fromJS(data)
|