1
+ import type { HardhatRuntimeEnvironment } from "hardhat/types/hre" ;
2
+
1
3
import assert from "node:assert/strict" ;
2
4
import path from "node:path" ;
3
- import { before , describe , it } from "node:test" ;
5
+ import { before , beforeEach , describe , it } from "node:test" ;
4
6
5
7
import { useFixtureProject } from "@nomicfoundation/hardhat-test-utils" ;
6
8
import {
@@ -10,30 +12,61 @@ import {
10
12
} from "@nomicfoundation/hardhat-utils/fs" ;
11
13
import { createHardhatRuntimeEnvironment } from "hardhat/hre" ;
12
14
15
+ // Read the contract factory from the generated types
16
+ async function readContractFactory ( contractName : string ) {
17
+ const potentialPaths = [
18
+ `${ process . cwd ( ) } /types/ethers-contracts/factories/${ contractName } __factory.ts` ,
19
+ `${ process . cwd ( ) } /types/ethers-contracts/factories/${ contractName } .sol/${ contractName } __factory.ts` ,
20
+ ] ;
21
+ for ( const potentialPath of potentialPaths ) {
22
+ if ( await exists ( potentialPath ) ) {
23
+ return readUtf8File ( potentialPath ) ;
24
+ }
25
+ }
26
+ return undefined ;
27
+ }
28
+
29
+ // Check the contract is typed in hardhat.d.ts
30
+ function isContractTyped ( typeFileContents : string , contractName : string ) {
31
+ const lookupStrings = [
32
+ `getContractFactory(name: '${ contractName } '` ,
33
+ `getContractAt(name: '${ contractName } '` ,
34
+ `deployContract(name: '${ contractName } '` ,
35
+ ] ;
36
+ for ( const lookupString of lookupStrings ) {
37
+ if ( ! typeFileContents . includes ( lookupString ) ) {
38
+ return false ;
39
+ }
40
+ }
41
+ return true ;
42
+ }
43
+
13
44
describe ( "hardhat-typechain" , ( ) => {
14
45
describe ( "check that types are generated correctly" , ( ) => {
15
46
const projectFolder = "generate-types" ;
47
+ let hre : HardhatRuntimeEnvironment ;
48
+ let hardhatConfig : any ;
16
49
17
50
useFixtureProject ( projectFolder ) ;
18
51
19
- before ( async ( ) => {
52
+ beforeEach ( async ( ) => {
20
53
await remove ( `${ process . cwd ( ) } /types` ) ;
21
54
22
- const hardhatConfig = await import (
55
+ hardhatConfig = await import (
23
56
// eslint-disable-next-line import/no-relative-packages -- allow for fixture projects
24
57
`./fixture-projects/${ projectFolder } /hardhat.config.js`
25
58
) ;
26
59
27
- const hre = await createHardhatRuntimeEnvironment ( hardhatConfig . default ) ;
60
+ hre = await createHardhatRuntimeEnvironment ( hardhatConfig . default ) ;
28
61
29
62
assert . equal ( await exists ( `${ process . cwd ( ) } /types` ) , false ) ;
30
63
31
64
await hre . tasks . getTask ( "clean" ) . run ( ) ;
32
-
33
- await hre . tasks . getTask ( "compile" ) . run ( ) ;
34
65
} ) ;
35
66
36
67
it ( "should generate the types for the `hardhat.d.ts` file" , async ( ) => {
68
+ await hre . tasks . getTask ( "compile" ) . run ( ) ;
69
+
37
70
// Check that the types are generated with the expected addition of the "/index.js" extensions
38
71
// and the v3 modules
39
72
@@ -63,18 +96,24 @@ describe("hardhat-typechain", () => {
63
96
64
97
// The import from a npm package should have ".js" extensions
65
98
assert . equal ( content . includes ( `import { ethers } from 'ethers'` ) , true ) ;
99
+
100
+ for ( const contractName of [ "A" , "B" ] ) {
101
+ assert . ok (
102
+ ( await readContractFactory ( contractName ) ) !== undefined ,
103
+ `Factory for ${ contractName } doesnt exist` ,
104
+ ) ;
105
+ assert . equal ( isContractTyped ( content , contractName ) , true ) ;
106
+ }
66
107
} ) ;
67
108
68
109
it ( "should generated types for the contracts and add the support for the `attach` method" , async ( ) => {
69
- const content = await readUtf8File (
70
- path . join (
71
- process . cwd ( ) ,
72
- "types" ,
73
- "ethers-contracts" ,
74
- "factories" ,
75
- "A__factory.ts" ,
76
- ) ,
77
- ) ;
110
+ await hre . tasks . getTask ( "compile" ) . run ( ) ;
111
+
112
+ const content = await readContractFactory ( "A" ) ;
113
+
114
+ if ( content === undefined ) {
115
+ throw new Error ( "Factory for A.sol not found" ) ;
116
+ }
78
117
79
118
// The "Addressable" type should be imported
80
119
assert . equal (
@@ -88,6 +127,33 @@ describe("hardhat-typechain", () => {
88
127
true ,
89
128
) ;
90
129
} ) ;
130
+
131
+ it ( "doesnt lose types when compiling a subset of the contracts" , async ( ) => {
132
+ // First: compile only A.sol. Only A should be typed
133
+ await hre . tasks . getTask ( "compile" ) . run ( { files : [ "contracts/A.sol" ] } ) ;
134
+
135
+ assert . notEqual ( await readContractFactory ( "A" ) , undefined ) ;
136
+ assert . equal ( await readContractFactory ( "B" ) , undefined ) ;
137
+
138
+ let content = await readUtf8File (
139
+ path . join ( process . cwd ( ) , "types" , "ethers-contracts" , "hardhat.d.ts" ) ,
140
+ ) ;
141
+
142
+ assert . equal ( isContractTyped ( content , "A" ) , true ) ;
143
+ assert . equal ( isContractTyped ( content , "B" ) , false ) ;
144
+
145
+ // Second: compile only B.sol. Both A and B should be typed
146
+ await hre . tasks . getTask ( "compile" ) . run ( { files : [ "contracts/B.sol" ] } ) ;
147
+
148
+ assert . notEqual ( await readContractFactory ( "A" ) , undefined ) ;
149
+ assert . notEqual ( await readContractFactory ( "B" ) , undefined ) ;
150
+
151
+ content = await readUtf8File (
152
+ path . join ( process . cwd ( ) , "types" , "ethers-contracts" , "hardhat.d.ts" ) ,
153
+ ) ;
154
+ assert . equal ( isContractTyped ( content , "A" ) , true ) ;
155
+ assert . equal ( isContractTyped ( content , "B" ) , true ) ;
156
+ } ) ;
91
157
} ) ;
92
158
93
159
describe ( "typechain should not generate types during compilation" , ( ) => {
0 commit comments