From 946481be9da37a888af8e5859a1be433fb3fc6f9 Mon Sep 17 00:00:00 2001 From: Aleksander Heintz Date: Wed, 24 May 2017 23:39:08 +0200 Subject: [PATCH] Build: Improve coverage by adding more tests (#3) * Add tests for isTrue and isFalse * Add sinon bindings * Add more tests * Make assertions async * Add more tests and remove regex assert --- .gitignore | 5 +- .../Fable.Ava.Test/__snapshots__/spec.js.snap | 19 + build.js | 7 + package.json | 4 +- src/Fable.Ava/assert.fs | 99 ++--- src/Fable.Ava/bindings.fs | 51 +-- src/Fable.Ava/spec.fs | 108 +++++- src/Fable.Sinon/Fable.Sinon.fsproj | 19 + src/Fable.Sinon/bindings.fs | 146 +++++++ src/Fable.Sinon/paket.references | 3 + test/Fable.Ava.Test/Fable.Ava.Test.fsproj | 3 +- test/Fable.Ava.Test/spec.fs | 356 ++++++++++++++++++ test/Fable.Ava.Test/test.fs | 10 - yarn.lock | 53 ++- 14 files changed, 790 insertions(+), 93 deletions(-) create mode 100644 bin/js/test/Fable.Ava.Test/__snapshots__/spec.js.snap create mode 100644 src/Fable.Sinon/Fable.Sinon.fsproj create mode 100644 src/Fable.Sinon/bindings.fs create mode 100644 src/Fable.Sinon/paket.references create mode 100644 test/Fable.Ava.Test/spec.fs delete mode 100644 test/Fable.Ava.Test/test.fs diff --git a/.gitignore b/.gitignore index 3675486..0bbdaec 100644 --- a/.gitignore +++ b/.gitignore @@ -29,9 +29,12 @@ coverage/ [Dd]ebug/ [Rr]elease/ x64/ -[Bb]in/ +[Bb]in/* [Oo]bj/ +# Snapshots +![Bb]in/**/__snapshots__/* + # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* diff --git a/bin/js/test/Fable.Ava.Test/__snapshots__/spec.js.snap b/bin/js/test/Fable.Ava.Test/__snapshots__/spec.js.snap new file mode 100644 index 0000000..762048f --- /dev/null +++ b/bin/js/test/Fable.Ava.Test/__snapshots__/spec.js.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`snapshot 1`] = ` +Object { + "kind": "snapshot", + "num": 1, + "test": true, + "with": "ava", +} +`; + +exports[`snapshot 2`] = ` +Object { + "kind": "snapshot", + "num": 1, + "test": true, + "with": "ava", +} +`; diff --git a/build.js b/build.js index b1ec10a..ac3be13 100644 --- a/build.js +++ b/build.js @@ -5,6 +5,7 @@ const babel = require('babel-core'); const client = require('fable-utils/client'); const babelPlugins = require('fable-utils/babel-plugins'); const istanbul = require('babel-plugin-istanbul').default; +const sourcemap = require('convert-source-map'); const pkg = require('./package.json'); const instrument = process.env.INSTRUMENT_CODE; @@ -89,6 +90,12 @@ const main = async (argv) => { const outFile = path.join(outDir, replaceExt(relPath, '.js')); const outFileDir = path.dirname(outFile); + if (transformed.map) { + const relSrcPath = path.relative(outFileDir, fsFile); + const map = sourcemap.fromObject(transformed.map).setProperty('sources', [relSrcPath]); + transformed.code += '\n\n' + map.toComment() + '\n'; + } + await fs.mkdirp(outFileDir); await fs.writeFile(outFile, transformed.code, { encoding: 'utf-8' }); } catch (e) { diff --git a/package.json b/package.json index ed587d2..582f3be 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,13 @@ "babel-plugin-istanbul": "^4.1.3", "babel-preset-env": "^1.5.1", "codecov": "^2.2.0", + "convert-source-map": "^1.5.0", "fable-utils": "^1.0.0", "fs-extra": "^3.0.1", "glob": "^7.1.2", "mkdirp": "^0.5.1", - "nyc": "^10.3.2" + "nyc": "^10.3.2", + "sinon": "^2.3.1" }, "scripts": { "test": "nyc ava bin/js/test/**/*.js", diff --git a/src/Fable.Ava/assert.fs b/src/Fable.Ava/assert.fs index a0a6600..2b9be5e 100644 --- a/src/Fable.Ava/assert.fs +++ b/src/Fable.Ava/assert.fs @@ -3,61 +3,64 @@ namespace Fable.Ava open Fable.Core open Fable.Import.Ava +type Asserter = { + pass: string option -> unit + fail: string option -> unit + isTruthy: obj -> string option -> unit + isFalsy: obj -> string option -> unit + isTrue: bool -> string option -> unit + isFalse: bool -> string option -> unit + isSame: obj -> obj -> string option -> unit + isNotSame: obj -> obj -> string option -> unit + isDeepEqual: obj -> obj -> string option -> unit + isNotDeepEqual: obj -> obj -> string option -> unit + throws: (unit -> unit) -> string option -> unit + doesNotThrow: (unit -> unit) -> string option -> unit + asyncThrows: (unit -> Async) -> string option -> Async + doesNotAsyncThrow: (unit -> Async) -> string option -> Async + //matches: string -> System.Text.RegularExpressions.Regex -> string option -> unit + ifError: obj -> string option -> unit + snapshot: obj -> string option -> unit +} + module Assert = - type Assert<'t> = + type Assert = | Pass of message: string option | Fail of message: string option - | Truthy of value: 't * message: string option - | Falsy of value: 't * message: string option + | Truthy of value: obj * message: string option + | Falsy of value: obj * message: string option | True of value: bool * message: string option | False of value: bool * message: string option - | Is of value: 't * expected: 't * message: string option - | Not of value: 't * expected: 't * message: string option - | DeepEqual of value: 't * expected: 't * message: string option - | NotDeepEqual of value: 't * expected: 't * message: string option + | Is of value: obj * expected: obj * message: string option + | Not of value: obj * expected: obj * message: string option + | DeepEqual of value: obj * expected: obj * message: string option + | NotDeepEqual of value: obj * expected: obj * message: string option | Throws of fn: (unit -> unit) * message: string option | NotThrows of fn: (unit -> unit) * message: string option | AsyncThrows of fn: (unit -> Async) * message: string option | NotAsyncThrows of fn: (unit -> Async) * message: string option - | Regex of value: string * regex: Fable.Import.JS.RegExp * message: string option + //| Regex of value: string * regex: System.Text.RegularExpressions.Regex * message: string option | IfError of error: obj * message: string option | Snapshot of value: obj * message: string option - let internal run (t: IAsserter) = function - | Pass None -> t.Pass () - | Pass (Some s) -> t.Pass s - | Fail None -> t.Fail () - | Fail (Some s) -> t.Fail s - | Truthy (v, None) -> t.Truthy v - | Truthy (v, Some s) -> t.Truthy (v, s) - | Falsy (v, None) -> t.Falsy v - | Falsy (v, Some s) -> t.Falsy (v, s) - | True (v, None) -> t.True v - | True (v, Some s) -> t.True (v, s) - | False (v, None) -> t.False v - | False (v, Some s) -> t.False (v, s) - | Is (v, e, None) -> t.Is (v, e) - | Is (v, e, Some s) -> t.Is (v, e, s) - | Not (v, e, None) -> t.Not (v, e) - | Not (v, e, Some s) -> t.Not (v, e, s) - | DeepEqual (v, e, None) -> t.DeepEqual (v, e) - | DeepEqual (v, e, Some s) -> t.DeepEqual (v, e, s) - | NotDeepEqual (v, e, None) -> t.NotDeepEqual (v, e) - | NotDeepEqual (v, e, Some s) -> t.NotDeepEqual (v, e, s) - | Throws (f, None) -> t.Throws f - | Throws (f, Some s) -> t.Throws (f, s) - | NotThrows (f, None) -> t.NotThrows f - | NotThrows (f, Some s) -> t.NotThrows (f, s) - | AsyncThrows (f, None) -> t.Throws (f >> Async.StartAsPromise) - | AsyncThrows (f, Some s) -> t.Throws (f >> Async.StartAsPromise, s) - | NotAsyncThrows (f, None) -> t.NotThrows (f >> Async.StartAsPromise) - | NotAsyncThrows (f, Some s) -> t.NotThrows (f >> Async.StartAsPromise, s) - | Regex (v, r, None) -> t.Regex (v, r) - | Regex (v, r, Some s) -> t.Regex (v, r, s) - | IfError (e, None) -> t.IfError e - | IfError (e, Some s) -> t.IfError (e, s) - | Snapshot (v, None) -> t.Snapshot v - | Snapshot (v, Some s) -> t.Snapshot (v, s) + let run (a: Asserter) = function + | Pass (s) -> a.pass s; async.Return () + | Fail (s) -> a.fail s; async.Return () + | Truthy (v, s) -> a.isTruthy v s; async.Return () + | Falsy (v, s) -> a.isFalsy v s; async.Return () + | True (v, s) -> a.isTrue v s; async.Return () + | False (v, s) -> a.isFalse v s; async.Return () + | Is (v, e, s) -> a.isSame v e s; async.Return () + | Not (v, e, s) -> a.isNotSame v e s; async.Return () + | DeepEqual (v, e, s) -> a.isDeepEqual v e s; async.Return () + | NotDeepEqual (v, e, s) -> a.isNotDeepEqual v e s; async.Return () + | Throws (f, s) -> a.throws f s; async.Return () + | NotThrows (f, s) -> a.doesNotThrow f s; async.Return () + | AsyncThrows (f, s) -> a.asyncThrows f s + | NotAsyncThrows (f, s) -> a.doesNotAsyncThrow f s + //| Regex (v, r, s) -> a.matches v r s; async.Return () + | IfError (e, s) -> a.ifError e s; async.Return () + | Snapshot (v, s) -> a.snapshot v s; async.Return () let internal setMessage msg = function | Pass (Some s) @@ -74,7 +77,7 @@ module Assert = | NotThrows (_, Some s) | AsyncThrows (_, Some s) | NotAsyncThrows (_, Some s) - | Regex (_, _, Some s) + //| Regex (_, _, Some s) | IfError (_, Some s) | Snapshot (_, Some s) -> failwithf "Message already set: %s" s | Pass (None) -> Pass (Some msg) @@ -91,7 +94,7 @@ module Assert = | NotThrows (f, None) -> NotThrows (f, Some msg) | AsyncThrows (f, None) -> AsyncThrows (f, Some msg) | NotAsyncThrows (f, None) -> NotAsyncThrows (f, Some msg) - | Regex (v, r, None) -> Regex (v, r, Some msg) + //| Regex (v, r, None) -> Regex (v, r, Some msg) | IfError (e, None) -> IfError (e, Some msg) | Snapshot (v, None) -> Snapshot (v, Some msg) @@ -106,10 +109,10 @@ module Assert = let isDeepEqual v e = DeepEqual (v, e, None) let isNotDeepEqual v e = NotDeepEqual (v, e, None) let throws f = Throws (f, None) - let notThrows f = NotThrows (f, None) + let doesNotThrow f = NotThrows (f, None) let asyncThrows f = AsyncThrows (f, None) - let notAsyncThrows f = NotAsyncThrows (f, None) - let matches v r = Regex (v, r, None) + let doesNotAsyncThrow f = NotAsyncThrows (f, None) + //let matches v r = Regex (v, r, None) let ifError e = IfError (e, None) let snapshot v = Snapshot (v, None) diff --git a/src/Fable.Ava/bindings.fs b/src/Fable.Ava/bindings.fs index b6f772a..31274da 100644 --- a/src/Fable.Ava/bindings.fs +++ b/src/Fable.Ava/bindings.fs @@ -3,46 +3,47 @@ module Fable.Import.Ava open Fable.Core open Fable.Import.JS -type IAsserter = +[] +type TestContext internal () = + [] + member x.Plan (n: int): unit = jsNative [] - abstract Pass: ?msg: string -> unit + member x.Pass (?msg: string): unit = jsNative [] - abstract Fail: ?msg: string -> unit + member x.Fail (?msg: string): unit = jsNative [] - abstract Truthy: value: 'a * ?msg: string -> unit + member x.Truthy (value: obj, ?msg: string): unit = jsNative [] - abstract Falsy: value: 'a * ?msg: string -> unit + member x.Falsy (value: obj, ?msg: string): unit = jsNative [] - abstract True: value: bool * ?msg: string -> unit + member x.True (value: bool, ?msg: string): unit = jsNative [] - abstract False: value: bool * ?msg: string -> unit + member x.False (value: bool, ?msg: string): unit = jsNative [] - abstract Is: value: 'a * expected: 'a * ?msg: string -> unit + member x.Is (value: 'a, expected: 'a, ?msg: string): unit = jsNative [] - abstract Not: value: 'a * expected: 'a * ?msg: string -> unit + member x.Not (value: 'a, expected: 'a, ?msg: string): unit = jsNative [] - abstract DeepEqual: value: 'a * expected: 'a * ?msg: string -> unit + member x.DeepEqual (value: 'a, expected: 'a, ?msg: string): unit = jsNative [] - abstract NotDeepEqual: value: 'a * expected: 'a * ?msg: string -> unit + member x.NotDeepEqual (value: 'a, expected: 'a, ?msg: string): unit = jsNative [] - abstract Throws: fn: (unit -> unit) * ?msg: string -> unit + member x.Throws (fn: (unit -> unit), ?msg: string): unit = jsNative [] - abstract Throws: fn: (unit -> Promise) * ?msg: string -> unit - [] - abstract NotThrows: fn: (unit -> unit) * ?msg: string -> unit - [] - abstract NotThrows: fn: (unit -> Promise) * ?msg: string -> unit - [] - abstract Regex: value: string * test: RegExp * ?msg: string -> unit + member x.Throws (promise: Promise, ?msg: string): Promise = jsNative + [] + member x.NotThrows (fn: (unit -> unit), ?msg: string): unit = jsNative + [] + member x.NotThrows (promise: Promise, ?msg: string): Promise = jsNative + // TODO: Bug weird bug with regex + //[] + //member x.Regex (value: string, test: System.Text.RegularExpressions.Regex, ?msg: string): unit = jsNative [] - abstract IfError: error: obj * ?msg: string -> unit + member x.IfError (error: obj, ?msg: string): unit = jsNative [] - abstract Snapshot: error: obj * ?msg: string -> unit + member x.Snapshot (error: obj, ?msg: string): unit = jsNative -type ITestContext = - inherit IAsserter - -type TestImpl = ITestContext -> Promise +type TestImpl = TestContext -> Promise //[] module Test = diff --git a/src/Fable.Ava/spec.fs b/src/Fable.Ava/spec.fs index 5b2e4bc..c905028 100644 --- a/src/Fable.Ava/spec.fs +++ b/src/Fable.Ava/spec.fs @@ -3,8 +3,99 @@ namespace Fable.Ava open Fable.Core open Fable.Import.Ava -[] -type Spec<'t> = SpecWrapper of (ITestContext -> Async<'t>) +type SpecContext internal (context: TestContext) = + let asserter = { + pass = fun s -> + match s with + | None -> context.Pass () + | Some s -> context.Pass s + + fail = fun s -> + match s with + | None -> context.Fail () + | Some s -> context.Pass s + + isTruthy = fun v s -> + match s with + | None -> context.Truthy v + | Some s -> context.Truthy (v, s) + + isFalsy = fun v s -> + match s with + | None -> context.Falsy v + | Some s -> context.Falsy (v, s) + + isTrue = fun v s -> + match s with + | None -> context.True v + | Some s -> context.True (v, s) + + isFalse = fun v s -> + match s with + | None -> context.False v + | Some s -> context.False (v, s) + + isSame = fun v e s -> + match s with + | None -> context.Is (v, e) + | Some s -> context.Is (v, e, s) + + isNotSame = fun v e s -> + match s with + | None -> context.Not (v, e) + | Some s -> context.Not (v, e, s) + + isDeepEqual = fun v e s -> + match s with + | None -> context.DeepEqual (v, e) + | Some s -> context.DeepEqual (v, e, s) + + isNotDeepEqual = fun v e s -> + match s with + | None -> context.NotDeepEqual (v, e) + | Some s -> context.NotDeepEqual (v, e, s) + + throws = fun f s -> + match s with + | None -> context.Throws f + | Some s -> context.Throws (f, s) + + doesNotThrow = fun f s -> + match s with + | None -> context.NotThrows f + | Some s -> context.NotThrows (f, s) + + asyncThrows = fun f s -> + match s with + | None -> context.Throws (f () |> Async.StartAsPromise) |> Async.AwaitPromise + | Some s -> context.Throws (f () |> Async.StartAsPromise, s) |> Async.AwaitPromise + + doesNotAsyncThrow = fun f s -> + match s with + | None -> context.NotThrows (f () |> Async.StartAsPromise) |> Async.AwaitPromise + | Some s -> context.NotThrows (f () |> Async.StartAsPromise, s) |> Async.AwaitPromise + + // matches = fun v r s -> + // match s with + // | None -> context.Regex (v, r) + // | Some s -> context.Regex (v, r, s) + + ifError = fun e s -> + match s with + | None -> context.IfError e + | Some s -> context.IfError (e, s) + + snapshot = fun v s -> + match s with + | None -> context.Snapshot v + | Some s -> context.Snapshot (v, s) + } + + member c.Asserter = asserter + member c.Plan n = context.Plan n + +//[] +type Spec<'t> = SpecWrapper of (SpecContext -> Async<'t>) [] module Spec = @@ -14,9 +105,9 @@ module Spec = let createAsync fn = SpecWrapper fn - let createAssert a = create (fun t -> Assert.run t a) + let createAssert a = createAsync (fun t -> Assert.run t.Asserter a) - let zero = create <| fun _ -> () + let zero = create <| ignore let unit x = create <| fun _ -> x @@ -24,6 +115,13 @@ module Spec = let bind ma f = createAsync <| fun t -> async.Bind (run ma t, fun a -> run (f a) t) + let plan n = create <| fun t -> t.Plan n + + let toTest (spec: Spec): TestImpl = + fun t -> + let context = SpecContext t + run spec context |> Async.StartAsPromise + [] module SpecBuilder = type SpecBuilderImpl () = @@ -31,8 +129,8 @@ module SpecBuilder = member __.Return x = Spec.unit x member __.Return asyncX = Spec.asyncUnit asyncX member __.Bind (ma, f) = Spec.bind ma f + member __.Bind (asyncA, f) = Spec.bind (Spec.asyncUnit asyncA) f member __.Bind (ma, f) = Spec.bind (Spec.createAssert ma) f - member __.Run ma = Spec.run ma >> Async.StartAsPromise [] module SpecBuilderInst = diff --git a/src/Fable.Sinon/Fable.Sinon.fsproj b/src/Fable.Sinon/Fable.Sinon.fsproj new file mode 100644 index 0000000..8a3f6e7 --- /dev/null +++ b/src/Fable.Sinon/Fable.Sinon.fsproj @@ -0,0 +1,19 @@ + + + + netstandard1.6 + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Fable.Sinon/bindings.fs b/src/Fable.Sinon/bindings.fs new file mode 100644 index 0000000..6876e2b --- /dev/null +++ b/src/Fable.Sinon/bindings.fs @@ -0,0 +1,146 @@ +module Fable.Import.Sinon + +open Fable.Core +open Fable.Import.JS + +[] +type SpyCall internal () = + [] + member call.CalledOn (obj: obj): bool = jsNative + + [] + member call.CalledWith (args: obj list): bool = jsNative + + [] + member call.CalledWithExactly (args: obj list): bool = jsNative + + [] + member call.NotCalledWith (args: obj list): bool = jsNative + + [] + member call.Threw (): bool = jsNative + + [] + member call.Threw (typeName: string): bool = jsNative + + [] + member call.Threw (error: obj): bool = jsNative + + [] + member call.ThisValue: obj = jsNative + + [] + member call.Args: obj list = jsNative + + [] + member call.Exception: exn option = jsNative + + [] + member call.ReturnValue: obj = jsNative + +[] +type Spy internal () = + [] + member spy.CallCount: int = jsNative + + [] + member spy.Called: bool = jsNative + + [] + member spy.CalledBefore (other: Spy): bool = jsNative + + [] + member spy.CalledAfter (other: Spy): bool = jsNative + + [] + member spy.CalledImmediatelyBefore (other: Spy): bool = jsNative + + [] + member spy.CalledImmediatelyAfter (other: Spy): bool = jsNative + + [] + member spy.GetCall (index: int): SpyCall = jsNative + + [] + member spy.Reset (): unit = jsNative + +[] +type Spy1<'a, 'b> internal () = + inherit Spy () + + [] + member spy.Apply (a: 'a): 'b = jsNative + +[] +type Spy2<'a, 'b, 'c> internal () = + inherit Spy () + + [] + member spy.Apply (a: 'a) (b: 'b): 'c = jsNative + +[] +type Spy3<'a, 'b, 'c, 'd> internal () = + inherit Spy () + + [] + member spy.Apply (a: 'a) (b: 'b) (c: 'c): 'd = jsNative + +[] +type Stub internal () = + inherit Spy () + + [] + member stub.ResetBehavior (): unit = jsNative + + [] + member stub.ResetHistory (): unit = jsNative + +[] +type Stub1<'a, 'b> internal () = + inherit Stub () + + [] + member stub.Apply (a: 'a): 'b = jsNative + + [] + member stub.Returns (ret: 'b): unit = jsNative + +[] +type Stub2<'a, 'b, 'c> internal () = + inherit Stub () + + [] + member stub.Apply (a: 'a) (b: 'b): 'c = jsNative + + [] + member stub.Returns (ret: 'c): unit = jsNative + +[] +type Stub3<'a, 'b, 'c, 'd> internal () = + inherit Stub () + + [] + member stub.Apply (a: 'a) (b: 'b) (c: 'c): 'd = jsNative + + [] + member stub.Returns (ret: 'd): unit = jsNative + +[] +module Sinon = + [] + let spy<'a, 'b> : Spy1<'a, 'b> = jsNative + + [] + let spy2<'a, 'b, 'c> : Spy2<'a, 'b, 'c> = jsNative + + [] + let spy3<'a, 'b, 'c, 'd> : Spy3<'a, 'b, 'c, 'd> = jsNative + + [] + let stub<'a, 'b> : Stub1<'a, 'b> = jsNative + + [] + let stub2<'a, 'b, 'c> : Stub2<'a, 'b, 'c> = jsNative + + [] + let stub3<'a, 'b, 'c, 'd> : Stub3<'a, 'b, 'c, 'd> = jsNative diff --git a/src/Fable.Sinon/paket.references b/src/Fable.Sinon/paket.references new file mode 100644 index 0000000..e6c60aa --- /dev/null +++ b/src/Fable.Sinon/paket.references @@ -0,0 +1,3 @@ +FSharp.Core +Fable.Core +Fable.PowerPack \ No newline at end of file diff --git a/test/Fable.Ava.Test/Fable.Ava.Test.fsproj b/test/Fable.Ava.Test/Fable.Ava.Test.fsproj index 2f7c0cd..6501f95 100644 --- a/test/Fable.Ava.Test/Fable.Ava.Test.fsproj +++ b/test/Fable.Ava.Test/Fable.Ava.Test.fsproj @@ -5,7 +5,7 @@ true - + @@ -13,6 +13,7 @@ + \ No newline at end of file diff --git a/test/Fable.Ava.Test/spec.fs b/test/Fable.Ava.Test/spec.fs new file mode 100644 index 0000000..291392f --- /dev/null +++ b/test/Fable.Ava.Test/spec.fs @@ -0,0 +1,356 @@ +module Test + +open Fable.Core +open Fable.Core.JsInterop +open Fable.Import.Sinon +open Fable.Import.Ava +open Fable.Ava + +let getCall (spy: Spy) (name: string) = spec { + do! Assert.isDeepEqual spy.CallCount 1 sprintf "%s should be called once" name + return spy.GetCall 0 +} + +let checkCall (spy: Spy) (name: string) (args: obj list) = spec { + let! call = getCall spy name + do! Assert.isTrue (call.CalledWithExactly args) sprintf "%s should be called with %A" name args +} + +// TODO: Create test mock so we can inspect actual assert calls +type AsserterMock () = + let passSpy = Sinon.spy + let failSpy = Sinon.spy + let truthySpy = Sinon.spy2 + let falsySpy = Sinon.spy2 + let trueSpy = Sinon.spy2 + let falseSpy = Sinon.spy2 + let isSpy = Sinon.spy3 + let notSpy = Sinon.spy3 + let deepEqualSpy = Sinon.spy3 + let notDeepEqualSpy = Sinon.spy3 + let throwsSpy = Sinon.spy2 + let notThrowsSpy = Sinon.spy2 + let throwsAsyncSpy = + let stub = Sinon.stub2 + stub.Returns <| async.Zero () + stub + let notThrowsAsyncSpy = + let stub = Sinon.stub2 + stub.Returns <| async.Zero () + stub + let regexSpy = Sinon.spy3 + let ifErrorSpy = Sinon.spy2 + let snapshotSpy = Sinon.spy2 + + let asserter = { + pass = passSpy.Apply + fail = failSpy.Apply + isTruthy = truthySpy.Apply + isFalsy = falsySpy.Apply + isTrue = trueSpy.Apply + isFalse = falseSpy.Apply + isSame = isSpy.Apply + isNotSame = notSpy.Apply + isDeepEqual = deepEqualSpy.Apply + isNotDeepEqual = notDeepEqualSpy.Apply + throws = throwsSpy.Apply + doesNotThrow = notThrowsSpy.Apply + asyncThrows = throwsAsyncSpy.Apply + doesNotAsyncThrow = notThrowsAsyncSpy.Apply + //matches = regexSpy.Apply + ifError = ifErrorSpy.Apply + snapshot = snapshotSpy.Apply + } + + member mock.Asserter = asserter + member private x._passSpy = passSpy + member private x._failSpy = failSpy + member private x._truthySpy = truthySpy + member private x._falsySpy = falsySpy + member private x._trueSpy = trueSpy + member private x._falseSpy = falseSpy + member private x._isSpy = isSpy + member private x._notSpy = notSpy + member private x._deepEqualSpy = deepEqualSpy + member private x._notDeepEqualSpy = notDeepEqualSpy + member private x._throwsSpy = throwsSpy + member private x._notThrowsSpy = notThrowsSpy + member private x._throwsAsyncSpy = throwsAsyncSpy + member private x._notThrowsAsyncSpy = notThrowsAsyncSpy + member private x._regexSpy = regexSpy + member private x._ifErrorSpy = ifErrorSpy + member private x._snapshotSpy = snapshotSpy + + static member pass (s: string option) (m: AsserterMock) = checkCall m._passSpy "pass" [s] + static member fail (s: string option) (m: AsserterMock) = checkCall m._failSpy "fail" [s] + static member isTruthy (v: obj, s: string option) (m: AsserterMock) = checkCall m._truthySpy "truthy" [v; s] + static member isFalsy (v: obj, s: string option) (m: AsserterMock) = checkCall m._falsySpy "falsy" [v; s] + static member isTrue (v: bool, s: string option) (m: AsserterMock) = checkCall m._trueSpy "true" [v; s] + static member isFalse (v: bool, s: string option) (m: AsserterMock) = checkCall m._falseSpy "false" [v; s] + static member isSame (v: obj, e: obj, s: string option) (m: AsserterMock) = checkCall m._isSpy "isSame" [v; e; s] + static member isNotSame (v: obj, e: obj, s: string option) (m: AsserterMock) = checkCall m._notSpy "isNotSame" [v; e; s] + static member isDeepEqual (v: obj, e: obj, s: string option) (m: AsserterMock) = checkCall m._deepEqualSpy "isDeepEqual" [v; e; s] + static member isNotDeepEqual (v: obj, e: obj, s: string option) (m: AsserterMock) = checkCall m._notDeepEqualSpy "isNotDeepEqual" [v; e; s] + static member throws (f: (unit -> unit), s: string option) (m: AsserterMock) = checkCall m._throwsSpy "throws" [f; s] + static member doesNotThrow (f: (unit -> unit), s: string option) (m: AsserterMock) = checkCall m._notThrowsSpy "doesNotThrow" [f; s] + static member asyncThrows (f: (unit -> Async), s: string option) (m: AsserterMock) = checkCall m._throwsAsyncSpy "asyncThrows" [f; s] + static member doesNotAsyncThrow (f: (unit -> Async), s: string option) (m: AsserterMock) = checkCall m._notThrowsAsyncSpy "doesNotAsyncThrow" [f; s] + static member matches (v: string, r: System.Text.RegularExpressions.Regex, s: string option) (m: AsserterMock) = checkCall m._regexSpy "matches" [v; r; s] + static member ifError (e: obj, s: string option) (m: AsserterMock) = checkCall m._ifErrorSpy "ifError" [e; s] + static member snapshot (v: obj, s: string option) (m: AsserterMock) = checkCall m._snapshotSpy "snapshot" [v; s] + +let mockCall (a: Assert.Assert) (check: AsserterMock -> Spec): Spec = spec { + let mock = AsserterMock () + do! Assert.run mock.Asserter a + do! check mock +} + +let messageTwiceFails (a: Assert.Assert) = spec { + do! Assert.throws <| fun () -> a "msg1" "msg2" |> ignore +} + +spec { + do! Spec.plan 9 + + do! messageTwiceFails Assert.pass + do! Assert.isDeepEqual (Assert.pass) (Assert.Pass None) + do! Assert.isDeepEqual (Assert.pass "foo") (Assert.Pass (Some "foo")) + do! mockCall (Assert.pass) (AsserterMock.pass None) + do! mockCall (Assert.pass "foo") (AsserterMock.pass (Some "foo")) + + do! Assert.pass + do! Assert.pass "pass" +} |> Spec.toTest |> Test.create "pass" + +spec { + do! Spec.plan 7 + + do! messageTwiceFails Assert.fail + do! Assert.isDeepEqual (Assert.fail) (Assert.Fail None) + do! Assert.isDeepEqual (Assert.fail "foo") (Assert.Fail (Some "foo")) + do! mockCall (Assert.fail) (AsserterMock.fail None) + do! mockCall (Assert.fail "foo") (AsserterMock.fail (Some "foo")) + + // Assert.fail can't be used +} |> Spec.toTest |> Test.create "fail" + +spec { + do! Spec.plan 9 + + do! messageTwiceFails (Assert.isTruthy true) + do! Assert.isDeepEqual (Assert.isTruthy true) (Assert.Truthy (true, None)) + do! Assert.isDeepEqual (Assert.isTruthy false "foo") (Assert.Truthy (false, Some "foo")) + do! mockCall (Assert.isTruthy true) (AsserterMock.isTruthy (true, None)) + do! mockCall (Assert.isTruthy false "foo") (AsserterMock.isTruthy (false, Some "foo")) + + do! Assert.isTruthy true + do! Assert.isTruthy true "isTruthy" +} |> Spec.toTest |> Test.create "isTruthy" + +spec { + do! Spec.plan 9 + + do! messageTwiceFails (Assert.isFalsy true) + do! Assert.isDeepEqual (Assert.isFalsy true) (Assert.Falsy (true, None)) + do! Assert.isDeepEqual (Assert.isFalsy false "foo") (Assert.Falsy (false, Some "foo")) + do! mockCall (Assert.isFalsy true) (AsserterMock.isFalsy (true, None)) + do! mockCall (Assert.isFalsy false "foo") (AsserterMock.isFalsy (false, Some "foo")) + + do! Assert.isFalsy false + do! Assert.isFalsy false "isFalsy" +} |> Spec.toTest |> Test.create "isFalsy" + +spec { + do! Spec.plan 9 + + do! messageTwiceFails (Assert.isTrue true) + do! Assert.isDeepEqual (Assert.isTrue true) (Assert.True (true, None)) + do! Assert.isDeepEqual (Assert.isTrue false "foo") (Assert.True (false, Some "foo")) + do! mockCall (Assert.isTrue true) (AsserterMock.isTrue (true, None)) + do! mockCall (Assert.isTrue false "foo") (AsserterMock.isTrue (false, Some "foo")) + + do! Assert.isTrue true + do! Assert.isTrue true "isTrue" +} |> Spec.toTest |> Test.create "isTrue" + +spec { + do! Spec.plan 9 + + do! messageTwiceFails (Assert.isFalse true) + do! Assert.isDeepEqual (Assert.isFalse true) (Assert.False (true, None)) + do! Assert.isDeepEqual (Assert.isFalse false "foo") (Assert.False (false, Some "foo")) + do! mockCall (Assert.isFalse true) (AsserterMock.isFalse (true, None)) + do! mockCall (Assert.isFalse false "foo") (AsserterMock.isFalse (false, Some "foo")) + + do! Assert.isFalse false + do! Assert.isFalse false "isTrue" +} |> Spec.toTest |> Test.create "isFalse" + +spec { + do! Spec.plan 9 + + let obj1 = createObj [ "obj1" ==> true ] + let obj2 = createObj [ "obj2" ==> true ] + + do! messageTwiceFails (Assert.isSame obj1 obj2) + do! Assert.isDeepEqual (Assert.isSame obj1 obj2) (Assert.Is (obj1, obj2, None)) + do! Assert.isDeepEqual (Assert.isSame obj1 obj1 "foo") (Assert.Is (obj1, obj1, Some "foo")) + do! mockCall (Assert.isSame obj1 obj2) (AsserterMock.isSame (obj1, obj2, None)) + do! mockCall (Assert.isSame obj1 obj1 "foo") (AsserterMock.isSame (obj1, obj1, Some "foo")) + + do! Assert.isSame obj1 obj1 + do! Assert.isSame obj1 obj1 "isSame" +} |> Spec.toTest |> Test.create "isSame" + +spec { + do! Spec.plan 9 + + let obj1 = createObj [ "obj1" ==> true ] + let obj2 = createObj [ "obj2" ==> true ] + + do! messageTwiceFails (Assert.isNotSame obj1 obj2) + do! Assert.isDeepEqual (Assert.isNotSame obj1 obj2) (Assert.Not (obj1, obj2, None)) + do! Assert.isDeepEqual (Assert.isNotSame obj1 obj1 "foo") (Assert.Not (obj1, obj1, Some "foo")) + do! mockCall (Assert.isNotSame obj1 obj2) (AsserterMock.isNotSame (obj1, obj2, None)) + do! mockCall (Assert.isNotSame obj1 obj1 "foo") (AsserterMock.isNotSame (obj1, obj1, Some "foo")) + + do! Assert.isNotSame obj1 obj2 + do! Assert.isNotSame obj1 obj2 "isNotSame" +} |> Spec.toTest |> Test.create "isNotSame" + +spec { + do! Spec.plan 9 + + let obj1 = createObj [ "test" ==> true ] + let obj2 = createObj [ "test" ==> true ] + + do! messageTwiceFails (Assert.isDeepEqual obj1 obj2) + do! Assert.isDeepEqual (Assert.isDeepEqual obj1 obj2) (Assert.DeepEqual (obj1, obj2, None)) + do! Assert.isDeepEqual (Assert.isDeepEqual obj1 obj1 "foo") (Assert.DeepEqual (obj1, obj1, Some "foo")) + do! mockCall (Assert.isDeepEqual obj1 obj2) (AsserterMock.isDeepEqual (obj1, obj2, None)) + do! mockCall (Assert.isDeepEqual obj1 obj1 "foo") (AsserterMock.isDeepEqual (obj1, obj1, Some "foo")) + + do! Assert.isDeepEqual obj1 obj2 + do! Assert.isDeepEqual obj1 obj2 "isDeepEqual" +} |> Spec.toTest |> Test.create "isDeepEqual" + +spec { + do! Spec.plan 9 + + let obj1 = createObj [ "obj1" ==> true ] + let obj2 = createObj [ "obj2" ==> true ] + + do! messageTwiceFails (Assert.isNotDeepEqual obj1 obj2) + do! Assert.isDeepEqual (Assert.isNotDeepEqual obj1 obj2) (Assert.NotDeepEqual (obj1, obj2, None)) + do! Assert.isDeepEqual (Assert.isNotDeepEqual obj1 obj1 "foo") (Assert.NotDeepEqual (obj1, obj1, Some "foo")) + do! mockCall (Assert.isNotDeepEqual obj1 obj2) (AsserterMock.isNotDeepEqual (obj1, obj2, None)) + do! mockCall (Assert.isNotDeepEqual obj1 obj1 "foo") (AsserterMock.isNotDeepEqual (obj1, obj1, Some "foo")) + + do! Assert.isNotDeepEqual obj1 obj2 + do! Assert.isNotDeepEqual obj1 obj2 "isNotDeepEqual" +} |> Spec.toTest |> Test.create "isNotDeepEqual" + +spec { + do! Spec.plan 9 + + let fn = fun () -> failwith "my message" + + do! messageTwiceFails (Assert.throws fn) + do! Assert.isDeepEqual (Assert.throws fn) (Assert.Throws (fn, None)) + do! Assert.isDeepEqual (Assert.throws fn "foo") (Assert.Throws (fn, Some "foo")) + do! mockCall (Assert.throws fn) (AsserterMock.throws (fn, None)) + do! mockCall (Assert.throws fn "foo") (AsserterMock.throws (fn, Some "foo")) + + do! Assert.throws fn + do! Assert.throws fn "throws" +} |> Spec.toTest |> Test.create "throws" + +spec { + do! Spec.plan 9 + + let fn = fun () -> () + + do! messageTwiceFails (Assert.doesNotThrow fn) + do! Assert.isDeepEqual (Assert.doesNotThrow fn) (Assert.NotThrows (fn, None)) + do! Assert.isDeepEqual (Assert.doesNotThrow fn "foo") (Assert.NotThrows (fn, Some "foo")) + do! mockCall (Assert.doesNotThrow fn) (AsserterMock.doesNotThrow (fn, None)) + do! mockCall (Assert.doesNotThrow fn "foo") (AsserterMock.doesNotThrow (fn, Some "foo")) + + do! Assert.doesNotThrow fn + do! Assert.doesNotThrow fn "doesNotThrow" +} |> Spec.toTest |> Test.create "doesNotThrow" + +spec { + do! Spec.plan 9 + + let fn = fun () -> async { failwith "my message" } + + do! messageTwiceFails (Assert.asyncThrows fn) + do! Assert.isDeepEqual (Assert.asyncThrows fn) (Assert.AsyncThrows (fn, None)) + do! Assert.isDeepEqual (Assert.asyncThrows fn "foo") (Assert.AsyncThrows (fn, Some "foo")) + do! mockCall (Assert.asyncThrows fn) (AsserterMock.asyncThrows (fn, None)) + do! mockCall (Assert.asyncThrows fn "foo") (AsserterMock.asyncThrows (fn, Some "foo")) + + do! Assert.asyncThrows fn + do! Assert.asyncThrows fn "asyncThrows" +} |> Spec.toTest |> Test.create "asyncThrows" + +spec { + do! Spec.plan 9 + + let fn = fun () -> async.Return () + + do! messageTwiceFails (Assert.doesNotAsyncThrow fn) + do! Assert.isDeepEqual (Assert.doesNotAsyncThrow fn) (Assert.NotAsyncThrows (fn, None)) + do! Assert.isDeepEqual (Assert.doesNotAsyncThrow fn "foo") (Assert.NotAsyncThrows (fn, Some "foo")) + do! mockCall (Assert.doesNotAsyncThrow fn) (AsserterMock.doesNotAsyncThrow (fn, None)) + do! mockCall (Assert.doesNotAsyncThrow fn "foo") (AsserterMock.doesNotAsyncThrow (fn, Some "foo")) + + do! Assert.doesNotAsyncThrow fn + do! Assert.doesNotAsyncThrow fn "doesNotAsyncThrow" +} |> Spec.toTest |> Test.create "doesNotAsyncThrow" + +// spec { +// do! Spec.plan 9 + +// let regex = System.Text.RegularExpressions.Regex "^ab*c?$" + +// do! messageTwiceFails (Assert.matches "abc" regex) +// do! Assert.isDeepEqual (Assert.matches "abc" regex) (Assert.Regex ("abc", regex, None)) +// do! Assert.isDeepEqual (Assert.matches "abc" regex "foo") (Assert.Regex ("abc", regex, Some "foo")) +// do! mockCall (Assert.matches "abc" regex) (AsserterMock.matches ("abc", regex, None)) +// do! mockCall (Assert.matches "abc" regex "foo") (AsserterMock.matches ("abc", regex, Some "foo")) + +// do! Assert.matches "abc" regex +// do! Assert.matches "abc" regex "matches" +// } |> Spec.toTest |> Test.create "matches" + +spec { + do! Spec.plan 9 + + let err = null + + do! messageTwiceFails (Assert.ifError err) + do! Assert.isDeepEqual (Assert.ifError err) (Assert.IfError (err, None)) + do! Assert.isDeepEqual (Assert.ifError err "foo") (Assert.IfError (err, Some "foo")) + do! mockCall (Assert.ifError err) (AsserterMock.ifError (err, None)) + do! mockCall (Assert.ifError err "foo") (AsserterMock.ifError (err, Some "foo")) + + do! Assert.ifError err + do! Assert.ifError err "ifError" +} |> Spec.toTest |> Test.create "ifError" + +spec { + do! Spec.plan 9 + + let obj = createObj [ "test" ==> true; "kind" ==> "snapshot"; "with" ==> "ava"; "num" ==> 1 ] + + do! messageTwiceFails (Assert.snapshot obj) + do! Assert.isDeepEqual (Assert.snapshot obj) (Assert.Snapshot (obj, None)) + do! Assert.isDeepEqual (Assert.snapshot obj "foo") (Assert.Snapshot (obj, Some "foo")) + do! mockCall (Assert.snapshot obj) (AsserterMock.snapshot (obj, None)) + do! mockCall (Assert.snapshot obj "foo") (AsserterMock.snapshot (obj, Some "foo")) + + do! Assert.snapshot obj + do! Assert.snapshot obj "snapshot with name" +} |> Spec.toTest |> Test.create "snapshot" diff --git a/test/Fable.Ava.Test/test.fs b/test/Fable.Ava.Test/test.fs deleted file mode 100644 index 34fc9c2..0000000 --- a/test/Fable.Ava.Test/test.fs +++ /dev/null @@ -1,10 +0,0 @@ -module Test - -open Fable.Import.Ava -open Fable.Ava - -spec { - do! Assert.isTrue true "true is true" - do! Assert.isFalse false "false is false" - do! Assert.isTruthy true "true should not be falsy :P" -} |> Test.create "test" \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bfca50a..5e34e1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1075,7 +1075,7 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" -convert-source-map@^1.1.0, convert-source-map@^1.2.0, convert-source-map@^1.3.0: +convert-source-map@^1.1.0, convert-source-map@^1.2.0, convert-source-map@^1.3.0, convert-source-map@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" @@ -1190,7 +1190,7 @@ diff-match-patch@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.0.tgz#1cc3c83a490d67f95d91e39f6ad1f2e086b63048" -diff@^3.0.0, diff@^3.0.1: +diff@^3.0.0, diff@^3.0.1, diff@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" @@ -1393,6 +1393,12 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" +formatio@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb" + dependencies: + samsam "1.x" + fs-extra@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" @@ -1843,6 +1849,10 @@ is-utf8@^0.2.0, is-utf8@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -2141,6 +2151,10 @@ lodash@^4.2.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +lolex@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6" + longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" @@ -2295,6 +2309,10 @@ nan@^2.3.0: version "2.6.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" +native-promise-only@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2547,6 +2565,12 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -2913,6 +2937,10 @@ safe-buffer@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" +samsam@1.x, samsam@^1.1.3: + version "1.2.1" + resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.2.1.tgz#edd39093a3184370cb859243b2bdf255e7d8ea67" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -2939,6 +2967,19 @@ signal-exit@^3.0.0, signal-exit@^3.0.1, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" +sinon@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.3.1.tgz#48c9c758b4d0bb86327486833f1c4298919ce9ee" + dependencies: + diff "^3.1.0" + formatio "1.2.0" + lolex "^1.6.0" + native-promise-only "^0.8.1" + path-to-regexp "^1.7.0" + samsam "^1.1.3" + text-encoding "0.6.4" + type-detect "^4.0.0" + slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -3147,6 +3188,10 @@ test-exclude@^4.1.0: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" +text-encoding@0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -3203,6 +3248,10 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" +type-detect@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.3.tgz#0e3f2670b44099b0b46c284d136a7ef49c74c2ea" + uglify-js@^2.6: version "2.8.27" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.27.tgz#47787f912b0f242e5b984343be8e35e95f694c9c"