hirosystems / clarinet

Write, test and deploy high-quality smart contracts to the Stacks blockchain and Bitcoin.
https://hiro.so/clarinet
GNU General Public License v3.0
306 stars 141 forks source link

[BUG] `clarinet test` is not able to run 100% correct typescript code #393

Closed LNow closed 2 years ago

LNow commented 2 years ago

Together with @moodmosaic we're exploring the possibilities of adding property-based testing solutions to clarity world. Recently code that is 100% correct stopped working. At first we though that fast-check, a property-based testing library we use is at fault but I managed to eliminate this possibility. Same with recently updated deno_std library.

It looks like Deno runtime embedded in Clarinet is the root cause of our problems.

Sample repository: https://github.com/LNow/fast-check-test

When we run deno test everything works perfectly fine. When we run clarinet test it fails with following error:

TS7053 [ERROR]: Element implicitly has an 'any' type because expression of type 'unique symbol' can't be used to index type 'Record<symbol, unknown>'.
  Property '["https://deno.land/std@0.141.0/node/internal/crypto/_keys.ts".kKeyType]' does not exist on type 'Record<symbol, unknown>'.
    obj != null && (obj as Record<symbol, unknown>)[kKeyType] !== undefined
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/std@0.141.0/node/internal/crypto/_keys.ts:7:20

TS7053 [ERROR]: Element implicitly has an 'any' type because expression of type 'unique symbol' can't be used to index type 'Record<symbol, unknown>'.
  Property '["https://deno.land/std@0.141.0/node/internal/crypto/constants.ts".kKeyObject]' does not exist on type 'Record<symbol, unknown>'.
    obj != null && (obj as Record<symbol, unknown>)[kKeyObject] !== undefined
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/std@0.141.0/node/internal/crypto/_keys.ts:13:20

Found 2 errors.
lgalabru commented 2 years ago

We should be able to update the typescript transpiler being embedded in Clarinet.

moodmosaic commented 2 years ago

@lgalabru, @LNow, in case this helps to troubleshoot further, the following patch makes clarinet test to run successfully:

$ git diff
diff --git a/fast_check.ts b/fast_check.ts
index 9b1728f..968e4bd 100644
--- a/fast_check.ts
+++ b/fast_check.ts
@@ -1,2 +1,2 @@
-import * as fc from 'https://cdn.esm.sh/v78/fast-check@3.0.0'
-export default fc;
\ No newline at end of file
+import * as fc from 'https://cdn.skypack.dev/fast-check@3.0.0'
+export default fc;
diff --git a/tests/main.test.ts b/tests/main.test.ts
index 435349a..fff9c06 100644
--- a/tests/main.test.ts
+++ b/tests/main.test.ts
@@ -7,12 +7,12 @@ const contains = (text: string, pattern: string) => text.indexOf(pattern) >= 0;
 describe('properties', () => {
   // string text always contains itself
   it('should always contain itself', () => {
-    fc.assert(fc.property(fc.string(), (text) => contains(text, text)));
+    fc.assert(fc.property(fc.string(), (text: string) => contains(text, text)));
   });
   // string a + b + c always contains b, whatever the values of a, b and c
   it('should always contain its substrings', () => {
     fc.assert(
-      fc.property(fc.string(), fc.string(), fc.string(), (a, b, c) => {
+      fc.property(fc.string(), fc.string(), fc.string(), (a: string, b: string, c: string) => {
         // Alternatively: no return statement and direct usage of expect or assert
         return contains(a + b + c, b);
       })

Notice that I changed the CDN from esh.sh to skypack, and then I fixed the build errors:

error: TS7006 [ERROR]: Parameter 'text' implicitly has an 'any' type.
    fc.assert(fc.property(fc.string(), (text) => contains(text, text)));
                                        ~~~~
    at file:///C:/Snapshot/dev/pub/stacks/fast-check-test/tests/main.test.ts:10:41

TS7006 [ERROR]: Parameter 'a' implicitly has an 'any' type.
      fc.property(fc.string(), fc.string(), fc.string(), (a, b, c) => {
                                                          ^
    at file:///C:/Snapshot/dev/pub/stacks/fast-check-test/tests/main.test.ts:15:59

TS7006 [ERROR]: Parameter 'b' implicitly has an 'any' type.
      fc.property(fc.string(), fc.string(), fc.string(), (a, b, c) => {
                                                             ^
    at file:///C:/Snapshot/dev/pub/stacks/fast-check-test/tests/main.test.ts:15:62

TS7006 [ERROR]: Parameter 'c' implicitly has an 'any' type.
      fc.property(fc.string(), fc.string(), fc.string(), (a, b, c) => {
                                                                ^
    at file:///C:/Snapshot/dev/pub/stacks/fast-check-test/tests/main.test.ts:15:65

Found 4 errors.
moodmosaic commented 2 years ago

We should be able to update the typescript transpiler being embedded in Clarinet.

@lgalabru, if there's something we can look into, please let us know. Thank you!

lgalabru commented 2 years ago

Revisiting the priority of this issue after talking with @moodmosaic.

hugocaillard commented 2 years ago

@lgalabru You might want to consider using SWC instead of TSC https://choubey.gitbook.io/internals-of-deno/architecture/core/tsc https://github.com/denoland/deno/issues/11340

lgalabru commented 2 years ago

To be addressed in https://github.com/hirosystems/clarinet/pull/511.

moodmosaic commented 2 years ago

I just compiled clarinet via #511 and it seems that the error is gone.


However, if you run clarinet test on that branch, you might notice this:

$ clarinet test

ok | 0 passed | 0 failed (18ms)

error:: Modules imported via https are not allowed to import http modules.
  Importing: http://cdn.esm.sh/v78/fast-check@3.0.0/deno/fast-check.js
    at https://cdn.esm.sh/v78/fast-check@3.0.0:3:25

This looks more like a deno + esm.sh related error, not specific to that branch. Just import the .js manually and re-run:

$ git diff
diff --git a/fast_check.ts b/fast_check.ts
index 9b1728f..f36f775 100644
--- a/fast_check.ts
+++ b/fast_check.ts
@@ -1,2 +1,3 @@
-import * as fc from 'https://cdn.esm.sh/v78/fast-check@3.0.0'
-export default fc;
\ No newline at end of file
+/* esm.sh - fast-check@3.0.0 */
+export * from "http://cdn.esm.sh/v78/fast-check@3.0.0/es2022/fast-check.js";
+export { default } from "http://cdn.esm.sh/v78/fast-check@3.0.0/es2022/fast-check.js";
$ clarinet test
./tests/main.test.ts => properties should always contain itself ... ok (12ms)
./tests/main.test.ts => properties should always contain its substrings ... ok (5ms)

ok | 2 passed | 0 failed (52ms)

🚀