Repository: char0n/ramda-adjunct
Pull request #1143 (2019-10-23 21:17:51)

feat(string): added padCharsStart function
#1102 

M-ZubairAhmed: i am trying to fix tests for polyfill, which is giving me weird errors

Patch:
diff --git a/RELEASE.md b/RELEASE.md
index 4d3a37e03f..26822979de 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -48,6 +48,25 @@ github release, please refer to this [page](https://help.github.com/articles/cre
  $ npm publish
 ```
 
+## Publish to Github Package Registry
+
+Read [this document](https://help.github.com/en/github/managing-packages-with-github-package-registry/configuring-npm-for-use-with-github-package-registry) to understand how to configure your npm to publish to Github Package Registry.
+
+Temporarily add the following entry into the `package.json` file. This modifications will set tell npm that the primary 
+registry is Github Package Registry.
+
+```json
+"publishConfig": {
+  "registry": "https://npm.pkg.github.com/"
+}
+```
+
+Now publish to GitHub Package Registry:
+
+```sh
+ $ npm publish
+```
+
 ## Bump the version
 
 Bump the `package.json` and `package-lock.json` version by incrementing **MAJOR**, **MINOR** or **PATCH** part of the semver version.
diff --git a/package-lock.json b/package-lock.json
index 4eda9cdb9a..af3c5dd61e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1772,9 +1772,9 @@
       "dev": true
     },
     "acorn-jsx": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz",
-      "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz",
+      "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==",
       "dev": true
     },
     "add-stream": {
@@ -3083,6 +3083,12 @@
         "delayed-stream": "~1.0.0"
       }
     },
+    "command-exists": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.8.tgz",
+      "integrity": "sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==",
+      "dev": true
+    },
     "commander": {
       "version": "2.19.0",
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
@@ -4176,11 +4182,12 @@
       "dev": true
     },
     "dts-critic": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/dts-critic/-/dts-critic-2.0.0.tgz",
-      "integrity": "sha512-oYo69B8NcjUoDhKh8oUl58ljMsgyWnPR0Qf3QKJmKjm5LvkQ21v4SW+QCOleI1Cs0HRN6zEYllvQEORGd45wOQ==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/dts-critic/-/dts-critic-2.2.0.tgz",
+      "integrity": "sha512-QFVMR85VMyqI8zfnboyRGNvkf+NOk+i/13V09Z/M8Kh/WivOId8TIO6q0d3NAmGyRJXP5TjQmxadWmwTFn1HBQ==",
       "dev": true,
       "requires": {
+        "command-exists": "^1.2.8",
         "definitelytyped-header-parser": "^1.2.0",
         "download-file-sync": "^1.0.4",
         "semver": "^6.2.0",
@@ -4206,24 +4213,24 @@
       }
     },
     "dtslint": {
-      "version": "0.9.7",
-      "resolved": "https://registry.npmjs.org/dtslint/-/dtslint-0.9.7.tgz",
-      "integrity": "sha512-dZ6dplgDsXKkN9NNQUYjOVs2kHzesVR+rFQ/PTd9NhQH+tc5a6ipUKF1eGKQqeHSSrSGnDz4mRTIxsiYgVGwJg==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/dtslint/-/dtslint-1.0.2.tgz",
+      "integrity": "sha512-DumNrKbecCJuLgbkCMT2GOBf9GSpArcv+Mbd/xzdj5muSHQOpruudeVVEBo0r6veHxrg3g3jCAA2EqnhH1MybQ==",
       "dev": true,
       "requires": {
-        "definitelytyped-header-parser": "^3.7.2",
-        "dts-critic": "^2.0.0",
+        "definitelytyped-header-parser": "3.7.2",
+        "dts-critic": "^2.2.0",
         "fs-extra": "^6.0.1",
         "request": "^2.88.0",
         "strip-json-comments": "^2.0.1",
         "tslint": "5.14.0",
-        "typescript": "=3.7.0-dev.20190912"
+        "typescript": "=3.8.0-dev.20191031"
       },
       "dependencies": {
         "typescript": {
-          "version": "3.7.0-dev.20190912",
-          "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.0-dev.20190912.tgz",
-          "integrity": "sha512-5rAOCT1CLjQ2nYeKwa6SOnpSW8N+EEFE6WbNOLrzsSyZwYysE1oHCw4SYil3ZsBVtiEmCYnPWck525dOpgUHDg==",
+          "version": "3.8.0-dev.20191031",
+          "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.0-dev.20191031.tgz",
+          "integrity": "sha512-hnIkoA1tdqCoO71ocviQg+ojLPwuZw6IxUtW12hhI+0XCpqNinQOcvUJlak0pVRUKL6vMRjvmhMbE0+uDJp/sA==",
           "dev": true
         }
       }
@@ -4535,9 +4542,9 @@
       }
     },
     "eslint": {
-      "version": "6.5.1",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz",
-      "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==",
+      "version": "6.6.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.6.0.tgz",
+      "integrity": "sha512-PpEBq7b6qY/qrOmpYQ/jTMDYfuQMELR4g4WI1M/NaSDDD/bdcMb+dj4Hgks7p41kW2caXsPsEZAEAyAgjVVC0g==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
@@ -4547,9 +4554,9 @@
         "debug": "^4.0.1",
         "doctrine": "^3.0.0",
         "eslint-scope": "^5.0.0",
-        "eslint-utils": "^1.4.2",
+        "eslint-utils": "^1.4.3",
         "eslint-visitor-keys": "^1.1.0",
-        "espree": "^6.1.1",
+        "espree": "^6.1.2",
         "esquery": "^1.0.1",
         "esutils": "^2.0.2",
         "file-entry-cache": "^5.0.1",
@@ -4559,7 +4566,7 @@
         "ignore": "^4.0.6",
         "import-fresh": "^3.0.0",
         "imurmurhash": "^0.1.4",
-        "inquirer": "^6.4.1",
+        "inquirer": "^7.0.0",
         "is-glob": "^4.0.0",
         "js-yaml": "^3.13.1",
         "json-stable-stringify-without-jsonify": "^1.0.1",
@@ -4687,9 +4694,9 @@
       }
     },
     "eslint-config-prettier": {
-      "version": "6.4.0",
-      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.4.0.tgz",
-      "integrity": "sha512-YrKucoFdc7SEko5Sxe4r6ixqXPDP1tunGw91POeZTTRKItf/AMFYt/YLEQtZMkR2LVpAVhcAcZgcWpm1oGPW7w==",
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.5.0.tgz",
+      "integrity": "sha512-cjXp8SbO9VFGW/Z7mbTydqS9to8Z58E5aYhj3e1+Hx7lS9s6gL5ILKNpCqZAFOVYRcSkWPFYljHrEh8QFEK5EQ==",
       "dev": true,
       "requires": {
         "get-stdin": "^6.0.0"
@@ -4784,7 +4791,7 @@
         },
         "pify": {
           "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
           "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
           "dev": true
         },
@@ -4821,9 +4828,9 @@
       }
     },
     "eslint-plugin-mocha": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-6.2.0.tgz",
-      "integrity": "sha512-vE/+tHJVom2BkMOiwkOKcAM5YqGPk3C6gMvQ32DHihKkaXF6vmxtj3UEOg64wP3m8/Zk5V/UmQbFE5nqu1EXSg==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-6.2.1.tgz",
+      "integrity": "sha512-o3Ibhpczi5MjUVpnlnrpC/+oJYGoHKB5m4bQdRnaAOeFCN3HRkqBisQ2/h0hEuCR4lPxyHP1Qzyjpna8MsOdlA==",
       "dev": true,
       "requires": {
         "ramda": "^0.26.1"
@@ -4868,12 +4875,12 @@
       }
     },
     "eslint-utils": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz",
-      "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==",
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
+      "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
       "dev": true,
       "requires": {
-        "eslint-visitor-keys": "^1.0.0"
+        "eslint-visitor-keys": "^1.1.0"
       }
     },
     "eslint-visitor-keys": {
@@ -4883,13 +4890,13 @@
       "dev": true
     },
     "espree": {
-      "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz",
-      "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==",
+      "version": "6.1.2",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz",
+      "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==",
       "dev": true,
       "requires": {
-        "acorn": "^7.0.0",
-        "acorn-jsx": "^5.0.2",
+        "acorn": "^7.1.0",
+        "acorn-jsx": "^5.1.0",
         "eslint-visitor-keys": "^1.1.0"
       },
       "dependencies": {
@@ -6414,7 +6421,7 @@
         },
         "camelcase-keys": {
           "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+          "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
           "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
           "dev": true,
           "requires": {
@@ -6449,7 +6456,7 @@
         },
         "load-json-file": {
           "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+          "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
           "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
           "dev": true,
           "requires": {
@@ -6468,7 +6475,7 @@
         },
         "meow": {
           "version": "3.7.0",
-          "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+          "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
           "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
           "dev": true,
           "requires": {
@@ -6521,7 +6528,7 @@
         },
         "pify": {
           "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
           "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
           "dev": true
         },
@@ -6662,7 +6669,7 @@
       "dependencies": {
         "pify": {
           "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
           "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
           "dev": true
         }
@@ -7081,9 +7088,9 @@
       "dev": true
     },
     "https-proxy-agent": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
-      "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+      "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
       "dev": true,
       "requires": {
         "agent-base": "^4.3.0",
@@ -7413,26 +7420,35 @@
       "dev": true
     },
     "inquirer": {
-      "version": "6.5.2",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
-      "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz",
+      "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==",
       "dev": true,
       "requires": {
-        "ansi-escapes": "^3.2.0",
+        "ansi-escapes": "^4.2.1",
         "chalk": "^2.4.2",
-        "cli-cursor": "^2.1.0",
+        "cli-cursor": "^3.1.0",
         "cli-width": "^2.0.0",
         "external-editor": "^3.0.3",
-        "figures": "^2.0.0",
-        "lodash": "^4.17.12",
-        "mute-stream": "0.0.7",
+        "figures": "^3.0.0",
+        "lodash": "^4.17.15",
+        "mute-stream": "0.0.8",
         "run-async": "^2.2.0",
         "rxjs": "^6.4.0",
-        "string-width": "^2.1.0",
+        "string-width": "^4.1.0",
         "strip-ansi": "^5.1.0",
         "through": "^2.3.6"
       },
       "dependencies": {
+        "ansi-escapes": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz",
+          "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==",
+          "dev": true,
+          "requires": {
+            "type-fest": "^0.5.2"
+          }
+        },
         "ansi-regex": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
@@ -7450,6 +7466,78 @@
             "supports-color": "^5.3.0"
           }
         },
+        "cli-cursor": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+          "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+          "dev": true,
+          "requires": {
+            "restore-cursor": "^3.1.0"
+          }
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "figures": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz",
+          "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==",
+          "dev": true,
+          "requires": {
+            "escape-string-regexp": "^1.0.5"
+          }
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
+        },
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        },
+        "mimic-fn": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+          "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+          "dev": true
+        },
+        "onetime": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
+          "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
+          "dev": true,
+          "requires": {
+            "mimic-fn": "^2.1.0"
+          }
+        },
+        "restore-cursor": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+          "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+          "dev": true,
+          "requires": {
+            "onetime": "^5.1.0",
+            "signal-exit": "^3.0.2"
+          }
+        },
+        "string-width": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz",
+          "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^5.2.0"
+          }
+        },
         "strip-ansi": {
           "version": "5.2.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -7458,6 +7546,12 @@
           "requires": {
             "ansi-regex": "^4.1.0"
           }
+        },
+        "type-fest": {
+          "version": "0.5.2",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz",
+          "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==",
+          "dev": true
         }
       }
     },
@@ -9647,9 +9741,9 @@
       "dev": true
     },
     "mute-stream": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
-      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
       "dev": true
     },
     "nan": {
@@ -10979,7 +11073,7 @@
       "dependencies": {
         "jsesc": {
           "version": "0.5.0",
-          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+          "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
           "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
           "dev": true
         }
@@ -13160,9 +13254,9 @@
       }
     },
     "webpack-cli": {
-      "version": "3.3.9",
-      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.9.tgz",
-      "integrity": "sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A==",
+      "version": "3.3.10",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.10.tgz",
+      "integrity": "sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg==",
       "dev": true,
       "requires": {
         "chalk": "2.4.2",
@@ -13577,9 +13671,9 @@
       },
       "dependencies": {
         "camelcase": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
-          "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
+          "version": "5.3.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
           "dev": true
         },
         "find-up": {
@@ -13602,9 +13696,9 @@
           }
         },
         "p-limit": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz",
-          "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==",
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
+          "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
           "dev": true,
           "requires": {
             "p-try": "^2.0.0"
@@ -13620,9 +13714,9 @@
           }
         },
         "p-try": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
-          "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==",
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+          "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
           "dev": true
         },
         "yargs-parser": {
diff --git a/package.json b/package.json
index 4558b35620..35f2cf2b25 100644
--- a/package.json
+++ b/package.json
@@ -144,12 +144,12 @@
     "codecov": "3.6.1",
     "conventional-changelog-cli": "2.0.25",
     "docdash": "git+https://github.com/char0n/docdash.git#534b44382138a55dd8d93642c979e51e46471185",
-    "dtslint": "0.9.7",
-    "eslint": "6.5.1",
+    "dtslint": "=1.0.2",
+    "eslint": "6.6.0",
     "eslint-config-airbnb-base": "=14.0.0",
-    "eslint-config-prettier": "6.4.0",
+    "eslint-config-prettier": "6.5.0",
     "eslint-plugin-import": "2.18.2",
-    "eslint-plugin-mocha": "6.2.0",
+    "eslint-plugin-mocha": "6.2.1",
     "eslint-plugin-prettier": "3.1.1",
     "eslint-plugin-ramda": "2.5.1",
     "fantasy-land": "4.0.0",
@@ -178,7 +178,7 @@
     "tslint": "=5.14.0",
     "typescript": "=3.5.3",
     "webpack": "4.41.2",
-    "webpack-cli": "3.3.9"
+    "webpack-cli": "3.3.10"
   },
   "browserslist": "> 0.25%, ie 10, ie 11, not op_mini all",
   "tonicExampleFilename": "tonicExample.js",
diff --git a/src/index.js b/src/index.js
index b99ab646ae..930713f11b 100644
--- a/src/index.js
+++ b/src/index.js
@@ -163,6 +163,7 @@ export { default as spreadPath } from './spreadPath';
 export { default as flattenProp } from './flattenProp';
 export { default as flattenPath } from './flattenPath';
 export { default as unzipObjWith } from './unzipObjWith';
+export { default as zipObjWith } from './zipObjWith';
 // Relation
 export { default as lensEq } from './lensEq';
 export { default as lensNotEq } from './lensNotEq';
@@ -199,6 +200,7 @@ export { default as trimStart } from './trimStart';
 export { default as trimLeft } from './trimStart'; // alias of trimStart
 export { default as trimEnd } from './trimEnd';
 export { default as trimRight } from './trimEnd'; // alias of trimEnd
+export { default as padCharsStart } from './padCharsStart';
 export { default as padCharsEnd } from './padCharsEnd';
 export { default as padEnd } from './padEnd';
 // Types
diff --git a/src/internal/polyfills/String.padCharsEnd.js b/src/internal/polyfills/String.padEnd.js
similarity index 73%
rename from src/internal/polyfills/String.padCharsEnd.js
rename to src/internal/polyfills/String.padEnd.js
index 824a0b83d5..0f10f49b4c 100644
--- a/src/internal/polyfills/String.padCharsEnd.js
+++ b/src/internal/polyfills/String.padEnd.js
@@ -1,16 +1,16 @@
 import isFunction from '../../isFunction';
+import isNotUndefined from '../../isNotUndefined';
 import repeat from './String.repeat';
 
-const padCharsEndPolyfill = (padString, targetLength, value) => {
+const padEndPolyfill = (padString, targetLength, value) => {
   // eslint-disable-next-line no-bitwise
   let finalLength = targetLength >> 0;
-  let finalPadString = String(
-    typeof padString !== 'undefined' ? padString : ' '
-  );
+  let finalPadString = String(isNotUndefined(padString) ? padString : ' ');
 
   if (value.length > finalLength) {
     return String(value);
   }
+
   finalLength -= value.length;
   if (finalLength > finalPadString.length) {
     const remainingLength = finalLength / finalPadString.length;
@@ -22,4 +22,4 @@ const padCharsEndPolyfill = (padString, targetLength, value) => {
   return String(value) + finalPadString.slice(0, finalLength);
 };
 
-export default padCharsEndPolyfill;
+export default padEndPolyfill;
diff --git a/src/internal/polyfills/String.padStart.js b/src/internal/polyfills/String.padStart.js
new file mode 100644
index 0000000000..c14dd970b3
--- /dev/null
+++ b/src/internal/polyfills/String.padStart.js
@@ -0,0 +1,33 @@
+import isFunction from '../../isFunction';
+import stringRepeat from './String.repeat';
+
+// https://github.com/uxitten/polyfill/blob/master/string.polyfill.js
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
+const stringPadStartPolyfill = (padString, targetLength, value) => {
+  // eslint-disable-next-line no-bitwise
+  let finalLength = targetLength >> 0; // truncate if number, or convert non-number to 0;
+  let finalPadString = String(
+    typeof padString !== 'undefined' ? padString : ' '
+  );
+
+  // Return the original string, if targeted lenght is less than orignal strings lenght
+  if (value.length >= finalLength) {
+    return String(value);
+  }
+
+  finalLength -= value.length;
+
+  if (finalLength > finalPadString.length) {
+    const lenghtToPad = finalLength / finalPadString.length;
+
+    // append to original to ensure we are longer than needed
+    finalPadString += isFunction(String.prototype.repeat)
+      ? finalPadString.repeat(lenghtToPad)
+      : stringRepeat(finalPadString, lenghtToPad);
+  }
+
+  return finalPadString.slice(0, finalLength) + String(value);
+  // return finalPadString.slice(0, finalLength);
+};
+
+export default stringPadStartPolyfill;
diff --git a/src/padCharsEnd.js b/src/padCharsEnd.js
index 797e4ec83b..6552e27cb5 100644
--- a/src/padCharsEnd.js
+++ b/src/padCharsEnd.js
@@ -1,11 +1,11 @@
 import { curry, invoker, flip } from 'ramda';
 
-import polyfill from './internal/polyfills/String.padCharsEnd';
+import polyfill from './internal/polyfills/String.padEnd';
 import isFunction from './isFunction';
 
-export const padCharsEndStrPolyfill = curry(polyfill);
+export const padEndPolyfill = curry(polyfill);
 
-export const padCharsEndStrInvoker = flip(invoker(2, 'padEnd'));
+export const padEndInvoker = flip(invoker(2, 'padEnd'));
 
 /**
  * The function pads the current string with a given string
@@ -31,7 +31,7 @@ export const padCharsEndStrInvoker = flip(invoker(2, 'padEnd'));
  * RA.padCharsEnd('123456', 6, 'abc'); // => 'abc123'
  */
 const padCharsEnd = isFunction(String.prototype.padEnd)
-  ? padCharsEndStrInvoker
-  : padCharsEndStrPolyfill;
+  ? padEndInvoker
+  : padEndPolyfill;
 
 export default padCharsEnd;
diff --git a/src/padCharsStart.js b/src/padCharsStart.js
new file mode 100644
index 0000000000..573e121fee
--- /dev/null
+++ b/src/padCharsStart.js
@@ -0,0 +1,35 @@
+import { flip, invoker, curry } from 'ramda';
+
+import isFunction from './isFunction';
+import polyfill from './internal/polyfills/String.padStart';
+
+export const stringPadStartInvoker = flip(invoker(2, 'padStart'));
+export const stringPadStartPolyfill = curry(polyfill);
+
+/**
+ * The function pads the current string with a given string
+ * (repeated, if needed) so that the resulting string reaches a given length.
+ * The padding is applied from the end of the current string.
+ *
+ * @func padCharsStart
+ * @memberOf RA
+ * @since {@link https://char0n.github.io/ramda-adjunct/2.22.0|v2.22.0}
+ * @category String
+ * @sig String -> Number -> String -> String
+ * @param {string} padString The string to pad the current string with
+ * @param {number} targetLength The length of the resulting string once
+ * the current string has been padded
+ * @param {string} value String value to be padded
+ * @return {string} A new string of the specified length with the pad string on the start of current string
+ * @see {@link RA.padEnd|padEnd}, {@link RA.padCharsEnd|padCharsEnd}, {@link RA.padStart|padStart}
+ * @example
+ *
+ * RA.padCharsEnd('-', 3, 'a'); // => '--a'
+ * RA.padCharsEnd('foo', 10, 'abc'); // => 'foofoofabc'
+ * RA.padCharsEnd('123456', 6, 'abc'); // => '123abc'
+ */
+const padCharsStart = isFunction(String.prototype.padStart)
+  ? stringPadStartInvoker
+  : stringPadStartPolyfill;
+
+export default padCharsStart;
diff --git a/src/zipObjWith.js b/src/zipObjWith.js
new file mode 100644
index 0000000000..ba48062c0e
--- /dev/null
+++ b/src/zipObjWith.js
@@ -0,0 +1,31 @@
+import { apply, curryN, fromPairs, map, pipe, zip } from 'ramda';
+
+/**
+ * Creates a new object out of a list of keys and a list of values by applying the function
+ * to each equally-positioned pair in the lists.
+ * Key/value pairing is truncated to the length of the shorter of the two lists.
+ *
+ * @func zipObjWith
+ * @memberOf RA
+ * @category Object
+ * @since {@link https://char0n.github.io/ramda-adjunct/2.22.0|v2.22.0}
+ * @sig (b, a) -> [k, v] -> [a] -> [b] -> { k: v }
+ * @param {Function} fn The function to transform each value-key pair
+ * @param {Array} keys Array to transform into the properties on the output object
+ * @param {Array} values Array to transform into the values on the output object
+ * @return {Object}  The object made by pairing up and transforming same-indexed elements of `keys` and `values`.
+ * @see {@link https://ramdajs.com/docs/#zipObj|zipObj}, {@link RA.unzipObjWith|unzipObjWith}
+ * @example
+ *
+ * RA.zipObjWith((value, key) => [key, `${key}${value + 1}`]), ['a', 'b', 'c'], [1, 2, 3]);
+ *  // => { a: 'a2', b: 'b3', c: 'c4' }
+ */
+const zipObjWith = curryN(3, (fn, keys, values) =>
+  pipe(
+    zip,
+    map(apply(fn)),
+    fromPairs
+  )(values, keys)
+);
+
+export default zipObjWith;
diff --git a/types/index.d.ts b/types/index.d.ts
index 191c3f73de..838fab8933 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -820,6 +820,18 @@ declare namespace RamdaAdjunct {
         flattenProp(prop: string | number, obj: object): object;
         flattenProp(prop: string | number): (obj: object) => object;
 
+        /**
+         * Creates a new object out of a list of keys and a list of values by applying the function
+         * to each equally-positioned pair in the lists.
+         * Key/value pairing is truncated to the length of the shorter of the two lists.
+         */
+        zipObjWith<T, U, V>(fn: (value: T, key: U) => [string, V], keys: U[], values: T[]): { [k: string]: V };
+        zipObjWith<T, U, V>(fn: (value: T, key: U) => [string, V]): (keys: U[], values: T[]) => { [k: string]: V };
+        zipObjWith<T, U, V>(fn: (value: T, key: U) => [string, V]): {
+            (keys: U[], values: T[]): { [k: string]: V };
+            (keys: U[]): (values: T[]) => { [k: string]: V };
+        };
+
         /**
          * Creates a new list out of the supplied object by applying the function to each key/value pairing.
          */
@@ -1282,6 +1294,15 @@ declare namespace RamdaAdjunct {
          */
         padEnd(targetLength: number, value: string): string;
         padEnd(targetLength: number): (value: string) => string;
+
+        /**
+         * The function pads the current string with a given string
+         * (repeated, if needed) so that the resulting string reaches a given lenght.
+         * The padding is applied to the start of the current string.
+         */
+        padCharsStart(padString: string, targetLength: number, value: string): string;
+        padCharsStart(padString: string, targetLength: number): (value: string) => string;
+        padCharsStart(padString: string): (targetLength: number, value: string) => string;
     }
 }
 
diff --git a/types/tslint.json b/types/tslint.json
index e6b68356b5..a41732cd44 100644
--- a/types/tslint.json
+++ b/types/tslint.json
@@ -16,6 +16,7 @@
       "no-import-default-of-export-equals": [false],
       "no-relative-import-in-test": [false],
       "no-unnecessary-generics": [false],
+      "strict-export-declare-modifiers": [false],
       "interface-name": [true, "never-prefix"],
       "ban-types": [true, ["Object", "Use {} instead."], ["String"], ["Number"]],
       "member-ordering": false,


Test patch:
diff --git a/test/async.js b/test/async.js
index 506b7e2d9d..fd046ae093 100644
--- a/test/async.js
+++ b/test/async.js
@@ -1,7 +1,6 @@
 import * as R from 'ramda';
 import { assert } from 'chai';
 
-import eq from './shared/eq';
 import * as RA from '../src';
 
 describe('async', function() {
@@ -15,7 +14,7 @@ describe('async', function() {
       });
       const expected = await asyncFn(1, 2);
 
-      eq(expected, 3);
+      assert.strictEqual(expected, 3);
     });
 
     context('and the generator throw Error as the last statement', function() {
@@ -32,7 +31,7 @@ describe('async', function() {
           throw new Error('fulfilling should fail');
         } catch (error) {
           assert.instanceOf(error, Error);
-          eq(error.message, 'generator error');
+          assert.strictEqual(error.message, 'generator error');
         }
       });
     });
@@ -49,7 +48,7 @@ describe('async', function() {
           throw new Error('fulfilling should fail');
         } catch (error) {
           assert.instanceOf(error, Error);
-          eq(error.message, 'generator error');
+          assert.strictEqual(error.message, 'generator error');
         }
       });
     });
@@ -66,7 +65,7 @@ describe('async', function() {
           throw new Error('fulfilling should fail');
         } catch (error) {
           assert.instanceOf(error, Error);
-          eq(error.message, 'generator error');
+          assert.strictEqual(error.message, 'generator error');
         }
       });
     });
@@ -92,7 +91,7 @@ describe('async', function() {
             return c + 3;
           });
 
-          eq(await bar(1, 2), 9);
+          assert.strictEqual(await bar(1, 2), 9);
         });
       }
     );
@@ -116,7 +115,7 @@ describe('async', function() {
           return c + 3;
         });
 
-        eq(await bar(1, 2), 9);
+        assert.strictEqual(await bar(1, 2), 9);
       });
     });
   });
@@ -136,7 +135,7 @@ describe('async', function() {
       return c + 3;
     });
 
-    eq(await bar(1, 2), 6);
+    assert.strictEqual(await bar(1, 2), 6);
   });
 
   it('should support async delegation', async function() {
@@ -154,7 +153,7 @@ describe('async', function() {
       return c + 3;
     });
 
-    eq(await bar(1, 2), 6);
+    assert.strictEqual(await bar(1, 2), 6);
   });
 
   it('should support recursion delegation', async function() {
@@ -168,7 +167,7 @@ describe('async', function() {
       return yield newVal;
     });
 
-    eq(await async(10), 1);
+    assert.strictEqual(await async(10), 1);
   });
 
   it('should curry', async function() {
@@ -179,7 +178,7 @@ describe('async', function() {
     });
     const expected = await asyncFn();
 
-    eq(expected, 2);
+    assert.strictEqual(expected, 2);
   });
 
   context('given wrapping of generator with arity of 2', function() {
@@ -193,12 +192,12 @@ describe('async', function() {
     });
 
     specify('should translate generator arity to wrapper', function() {
-      eq(asyncFn.length, 2);
+      assert.strictEqual(asyncFn.length, 2);
     });
 
     specify('should curry wrapper to appropriate arity', async function() {
-      eq(await asyncFn(1, 2), 3);
-      eq(await asyncFn(1)(2), 3);
+      assert.strictEqual(await asyncFn(1, 2), 3);
+      assert.strictEqual(await asyncFn(1)(2), 3);
     });
   });
 
@@ -216,13 +215,13 @@ describe('async', function() {
       specify('should not support placeholder', async function() {
         const expected = await asyncFn(R.__);
 
-        eq(expected, 1);
+        assert.strictEqual(expected, 1);
       });
 
       specify('should support call without arguments', async function() {
         const expected = await asyncFn();
 
-        eq(expected, 1);
+        assert.strictEqual(expected, 1);
       });
     });
   });
diff --git a/test/ceil.js b/test/ceil.js
index 3929ddfa5c..15d0ce0841 100644
--- a/test/ceil.js
+++ b/test/ceil.js
@@ -2,42 +2,41 @@ import * as R from 'ramda';
 import { assert } from 'chai';
 
 import * as RA from '../src';
-import eq from './shared/eq';
 import Symbol from './shared/Symbol';
 
 describe('ceil', function() {
   it('should ceil float to nearest integer', function() {
-    eq(RA.ceil(0.9), 1);
-    eq(RA.ceil(5.95), 6);
-    eq(RA.ceil(5.5), 6);
-    eq(RA.ceil(5.05), 6);
-    eq(RA.ceil(-5.05), -5);
-    eq(RA.ceil(-5.5), -5);
-    eq(RA.ceil(-5.95), -5);
+    assert.strictEqual(RA.ceil(0.9), 1);
+    assert.strictEqual(RA.ceil(5.95), 6);
+    assert.strictEqual(RA.ceil(5.5), 6);
+    assert.strictEqual(RA.ceil(5.05), 6);
+    assert.strictEqual(RA.ceil(-5.05), -5);
+    assert.strictEqual(RA.ceil(-5.5), -5);
+    assert.strictEqual(RA.ceil(-5.95), -5);
   });
 
   context('given integer number', function() {
     specify('should return original integer number', function() {
-      eq(RA.ceil(0), 0);
-      eq(RA.ceil(1), 1);
-      eq(RA.ceil(-1), -1);
+      assert.strictEqual(RA.ceil(0), 0);
+      assert.strictEqual(RA.ceil(1), 1);
+      assert.strictEqual(RA.ceil(-1), -1);
     });
   });
 
   context('given value that is not a number', function() {
     specify('should return NaN', function() {
-      eq(RA.ceil(undefined), NaN);
-      eq(RA.ceil(NaN), NaN);
-      eq(RA.ceil({}), NaN);
-      eq(RA.ceil(/a/), NaN);
-      eq(RA.ceil('test'), NaN);
-      eq(RA.ceil(new Error()), NaN);
+      assert.isNaN(RA.ceil(undefined));
+      assert.isNaN(RA.ceil(NaN));
+      assert.isNaN(RA.ceil({}));
+      assert.isNaN(RA.ceil(/a/));
+      assert.isNaN(RA.ceil('test'));
+      assert.isNaN(RA.ceil(new Error()));
     });
   });
 
   context('given null', function() {
     specify('should return 0', function() {
-      eq(RA.ceil(null), 0);
+      assert.strictEqual(RA.ceil(null), 0);
     });
   });
 
@@ -61,21 +60,21 @@ describe('ceil', function() {
     specify(
       'should return the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC',
       function() {
-        eq(RA.ceil(new Date(2)), 2);
+        assert.strictEqual(RA.ceil(new Date(2)), 2);
       }
     );
   });
 
   context('given Infinity value', function() {
     specify('should return untouched Infinity value', function() {
-      eq(RA.ceil(Infinity), Infinity);
-      eq(RA.ceil(-Infinity), -Infinity);
+      assert.strictEqual(RA.ceil(Infinity), Infinity);
+      assert.strictEqual(RA.ceil(-Infinity), -Infinity);
     });
   });
 
   it('should support placeholder to specify "gaps"', function() {
     const ceil = RA.ceil(R.__);
 
-    eq(ceil(0.9), 1);
+    assert.strictEqual(ceil(0.9), 1);
   });
 });
diff --git a/test/compact.js b/test/compact.js
index da6b788ac5..59a6c592f3 100644
--- a/test/compact.js
+++ b/test/compact.js
@@ -2,18 +2,20 @@ import { assert } from 'chai';
 import * as R from 'ramda';
 
 import * as RA from '../src';
-import eq from './shared/eq';
 
 describe('compact', function() {
   context('given list contains falsy values', function() {
     specify('should filter them', function() {
-      eq(RA.compact([0, 1, false, 2, '', 3, null, undefined, NaN]), [1, 2, 3]);
+      assert.sameOrderedMembers(
+        RA.compact([0, 1, false, 2, '', 3, null, undefined, NaN]),
+        [1, 2, 3]
+      );
     });
   });
 
   context('given list contains truthy values only', function() {
     specify('should not filter anything', function() {
-      eq(RA.compact([1, 2, 3]), [1, 2, 3]);
+      assert.sameOrderedMembers(RA.compact([1, 2, 3]), [1, 2, 3]);
     });
 
     specify('should return new list with exactly same items', function() {
@@ -34,6 +36,6 @@ describe('compact', function() {
   it('should support placeholder to specify "gaps"', function() {
     const compact = RA.compact(R.__);
 
-    eq(compact([]), []);
+    assert.sameOrderedMembers(compact([]), []);
   });
 });
diff --git a/test/concatAll.js b/test/concatAll.js
index 2b0810a3c7..a7444bdb5e 100644
--- a/test/concatAll.js
+++ b/test/concatAll.js
@@ -3,24 +3,23 @@ import { NEL, Nil } from 'monet';
 import * as R from 'ramda';
 
 import * as RA from '../src';
-import eq from './shared/eq';
 
 describe('concatAll', function() {
   it('should concatenate arrays', function() {
-    eq(RA.concatAll([[1], [2], [3]]), [1, 2, 3]);
+    assert.sameOrderedMembers(RA.concatAll([[1], [2], [3]]), [1, 2, 3]);
   });
 
   it('should concatenate strings', function() {
-    eq(RA.concatAll(['1', '2', '3']), '123');
+    assert.strictEqual(RA.concatAll(['1', '2', '3']), '123');
   });
 
   it('should concatenate semigroups', function() {
-    eq(RA.concatAll([NEL(1), NEL(2)]), NEL(1, NEL(2, Nil)));
+    assert.deepEqual(RA.concatAll([NEL(1), NEL(2)]), NEL(1, NEL(2, Nil)));
   });
 
   context('given foldable is empty', function() {
     specify('should returns undefined', function() {
-      eq(RA.concatAll([]), undefined);
+      assert.isUndefined(RA.concatAll([]));
     });
   });
 
@@ -48,6 +47,6 @@ describe('concatAll', function() {
   it('should support placeholder to specify "gaps"', function() {
     const concatAll = RA.concatAll(R.__);
 
-    eq(concatAll(['1', '2', '3']), '123');
+    assert.strictEqual(concatAll(['1', '2', '3']), '123');
   });
 });
diff --git a/test/concatRight.js b/test/concatRight.js
index 6acef77936..70cd969865 100644
--- a/test/concatRight.js
+++ b/test/concatRight.js
@@ -1,7 +1,6 @@
 import * as R from 'ramda';
 import { assert } from 'chai';
 
-import eq from './shared/eq';
 import * as RA from '../src';
 
 describe('concatRight', function() {
@@ -14,31 +13,43 @@ describe('concatRight', function() {
   const z2 = { x: 'z2' };
 
   it('should add combines the elements of the two lists', function() {
-    eq(RA.concatRight(['a', 'b'], ['c', 'd']), ['c', 'd', 'a', 'b']);
-    eq(RA.concatRight([], ['c', 'd']), ['c', 'd']);
+    assert.sameOrderedMembers(RA.concatRight(['a', 'b'], ['c', 'd']), [
+      'c',
+      'd',
+      'a',
+      'b',
+    ]);
+    assert.sameOrderedMembers(RA.concatRight([], ['c', 'd']), ['c', 'd']);
   });
 
   it('should work on strings', function() {
-    eq(RA.concatRight('foo', 'bar'), 'barfoo');
-    eq(RA.concatRight('x', ''), 'x');
-    eq(RA.concatRight('', 'x'), 'x');
-    eq(RA.concatRight('', ''), '');
+    assert.strictEqual(RA.concatRight('foo', 'bar'), 'barfoo');
+    assert.strictEqual(RA.concatRight('x', ''), 'x');
+    assert.strictEqual(RA.concatRight('', 'x'), 'x');
+    assert.strictEqual(RA.concatRight('', ''), '');
   });
 
   it('should delegate to non-String object with a concat method, as first param', function() {
-    eq(RA.concatRight(z2, z1), 'z1 z2');
+    assert.strictEqual(RA.concatRight(z2, z1), 'z1 z2');
   });
 
   it('should be curried', function() {
     const conc123 = RA.concatRight([1, 2, 3]);
-    eq(conc123([4, 5, 6]), [4, 5, 6, 1, 2, 3]);
-    eq(conc123(['a', 'b', 'c']), ['a', 'b', 'c', 1, 2, 3]);
+    assert.sameOrderedMembers(conc123([4, 5, 6]), [4, 5, 6, 1, 2, 3]);
+    assert.sameOrderedMembers(conc123(['a', 'b', 'c']), [
+      'a',
+      'b',
+      'c',
+      1,
+      2,
+      3,
+    ]);
   });
 
   it('should be curried like a binary operator, that accepts an initial placeholder', function() {
     const appendBar = RA.concatRight(R.__, 'bar');
-    eq(typeof appendBar, 'function');
-    eq(appendBar('foo'), 'barfoo');
+    assert.strictEqual(typeof appendBar, 'function');
+    assert.strictEqual(appendBar('foo'), 'barfoo');
   });
 
   context('given attempting to combine an array with a non-array', function() {
@@ -57,7 +68,17 @@ describe('concatRight', function() {
   );
 
   it('should curry', function() {
-    eq(RA.concatRight(['a', 'b'], ['c', 'd']), ['c', 'd', 'a', 'b']);
-    eq(RA.concatRight(['a', 'b'])(['c', 'd']), ['c', 'd', 'a', 'b']);
+    assert.sameOrderedMembers(RA.concatRight(['a', 'b'], ['c', 'd']), [
+      'c',
+      'd',
+      'a',
+      'b',
+    ]);
+    assert.sameOrderedMembers(RA.concatRight(['a', 'b'])(['c', 'd']), [
+      'c',
+      'd',
+      'a',
+      'b',
+    ]);
   });
 });
diff --git a/test/contained.js b/test/contained.js
index 4ec1a58379..f271111d2f 100644
--- a/test/contained.js
+++ b/test/contained.js
@@ -1,24 +1,24 @@
 import * as R from 'ramda';
+import { assert } from 'chai';
 
 import * as RA from '../src';
-import eq from './shared/eq';
 
 describe('contained', function() {
   context('given element is in the list', function() {
     specify('should return true', function() {
-      eq(RA.contained([1, 2, 3, 9, 8, 7, 100, 200, 300], 7), true);
+      assert.isTrue(RA.contained([1, 2, 3, 9, 8, 7, 100, 200, 300], 7));
     });
   });
 
   context('given element is not in the list', function() {
     specify('should return false', function() {
-      eq(RA.contained([1, 2, 3, 9, 8, 7, 100, 200, 300], 99), false);
+      assert.isFalse(RA.contained([1, 2, 3, 9, 8, 7, 100, 200, 300], 99));
     });
   });
 
   context('given empty list', function() {
     specify('should return false', function() {
-      eq(RA.contained([], 1), false);
+      assert.isFalse(RA.contained([], 1));
     });
   });
 
@@ -30,20 +30,20 @@ describe('contained', function() {
       return x instanceof Just && R.equals(x.value, this.value);
     };
 
-    eq(RA.contained([-0], 0), false);
-    eq(RA.contained([0], -0), false);
-    eq(RA.contained([NaN], NaN), true);
-    eq(RA.contained([new Just([42])], new Just([42])), true);
+    assert.isFalse(RA.contained([-0], 0));
+    assert.isFalse(RA.contained([0], -0));
+    assert.isTrue(RA.contained([NaN], NaN));
+    assert.isTrue(RA.contained([new Just([42])], new Just([42])));
   });
 
   context('given substring is part of string', function() {
     it('should return true', function() {
-      eq(RA.contained('banana', 'ba'), true);
+      assert.isTrue(RA.contained('banana', 'ba'));
     });
   });
 
   it('should be curried', function() {
-    eq(RA.contained('abcd', 'b'), true);
-    eq(RA.contained('abcd')('b'), true);
+    assert.isTrue(RA.contained('abcd', 'b'));
+    assert.isTrue(RA.contained('abcd')('b'));
   });
 });
diff --git a/test/curryRight.js b/test/curryRight.js
index b9a98b1fe8..8deba16cab 100644
--- a/test/curryRight.js
+++ b/test/curryRight.js
@@ -1,7 +1,7 @@
 import * as R from 'ramda';
 import jsv from 'jsverify';
+import { assert } from 'chai';
 
-import eq from './shared/eq';
 import * as RA from '../src';
 
 describe('curryRight', function() {
@@ -10,7 +10,7 @@ describe('curryRight', function() {
       return (a + b * c) / d;
     }); // f(2, 6, 3, 10) == 2
     const g = f(10);
-    eq(g(3, 6, 2), 2);
+    assert.strictEqual(g(3, 6, 2), 2);
   });
 
   it('should curry multiple values', function() {
@@ -19,9 +19,9 @@ describe('curryRight', function() {
       return (a + b * c) / d;
     });
     const g = f(10, 3);
-    eq(g(6, 2), 2);
+    assert.strictEqual(g(6, 2), 2);
     const h = f(10, 3, 6);
-    eq(h(2), 2);
+    assert.strictEqual(h(2), 2);
   });
 
   it('should allow further currying of a curried function', function() {
@@ -30,22 +30,22 @@ describe('curryRight', function() {
       return (a + b * c) / d;
     });
     const g = f(10);
-    eq(g(3, 6, 2), 2);
+    assert.strictEqual(g(3, 6, 2), 2);
     const h = g(3);
-    eq(h(6, 2), 2);
-    eq(g(3, 6)(2), 2);
+    assert.strictEqual(h(6, 2), 2);
+    assert.strictEqual(g(3, 6)(2), 2);
   });
 
   it('should properly report the length of the curried function', function() {
     const f = RA.curryRight(function(a, b, c, d) {
       return (a + b * c) / d;
     });
-    eq(f.length, 4);
+    assert.strictEqual(f.length, 4);
     const g = f(10);
-    eq(g.length, 3);
+    assert.strictEqual(g.length, 3);
     const h = g(3);
-    eq(h.length, 2);
-    eq(g(3, 6).length, 1);
+    assert.strictEqual(h.length, 2);
+    assert.strictEqual(g(3, 6).length, 1);
   });
 
   it('should preserve context', function() {
@@ -55,8 +55,8 @@ describe('curryRight', function() {
     };
     const g = RA.curryRight(f);
 
-    eq(g.call(ctx, 2, 4), 24);
-    eq(g.call(ctx, 2).call(ctx, 4), 24);
+    assert.strictEqual(g.call(ctx, 2, 4), 24);
+    assert.strictEqual(g.call(ctx, 2).call(ctx, 4), 24);
   });
 
   it('should support R.__ placeholder', function() {
@@ -66,29 +66,29 @@ describe('curryRight', function() {
     const g = RA.curryRight(f);
     const _ = R.__;
 
-    eq(g(1)(2)(3), [3, 2, 1]);
-    eq(g(1)(2, 3), [3, 2, 1]);
-    eq(g(1, 2)(3), [3, 2, 1]);
-    eq(g(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, 3), [3, 2, 1]);
 
-    eq(g(_, 2, 3)(1), [3, 2, 1]);
-    eq(g(1, _, 3)(2), [3, 2, 1]);
-    eq(g(1, 2, _)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, 3)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, 3)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, _)(3), [3, 2, 1]);
 
-    eq(g(1, _, _)(2)(3), [3, 2, 1]);
-    eq(g(_, 2, _)(1)(3), [3, 2, 1]);
-    eq(g(_, _, 3)(1)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(1)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(1)(2), [3, 2, 1]);
 
-    eq(g(1, _, _)(2, 3), [3, 2, 1]);
-    eq(g(_, 2, _)(1, 3), [3, 2, 1]);
-    eq(g(_, _, 3)(1, 2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(1, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(1, 2), [3, 2, 1]);
 
-    eq(g(1, _, _)(_, 3)(2), [3, 2, 1]);
-    eq(g(_, 2, _)(_, 3)(1), [3, 2, 1]);
-    eq(g(_, _, 3)(_, 2)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(_, 3)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(_, 3)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(_, 2)(1), [3, 2, 1]);
 
-    eq(g(_, _, _)(_, _)(_)(1, 2, 3), [3, 2, 1]);
-    eq(g(_, _, _)(1, _, _)(_, _)(2, _)(_)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, _)(_, _)(_)(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, _)(1, _, _)(_, _)(2, _)(_)(3), [3, 2, 1]);
   });
 
   it('should support @@functional/placeholder', function() {
@@ -98,29 +98,29 @@ describe('curryRight', function() {
     const g = RA.curryRight(f);
     const _ = { '@@functional/placeholder': true, x: Math.random() };
 
-    eq(g(1)(2)(3), [3, 2, 1]);
-    eq(g(1)(2, 3), [3, 2, 1]);
-    eq(g(1, 2)(3), [3, 2, 1]);
-    eq(g(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, 3), [3, 2, 1]);
 
-    eq(g(_, 2, 3)(1), [3, 2, 1]);
-    eq(g(1, _, 3)(2), [3, 2, 1]);
-    eq(g(1, 2, _)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, 3)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, 3)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, _)(3), [3, 2, 1]);
 
-    eq(g(1, _, _)(2)(3), [3, 2, 1]);
-    eq(g(_, 2, _)(1)(3), [3, 2, 1]);
-    eq(g(_, _, 3)(1)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(1)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(1)(2), [3, 2, 1]);
 
-    eq(g(1, _, _)(2, 3), [3, 2, 1]);
-    eq(g(_, 2, _)(1, 3), [3, 2, 1]);
-    eq(g(_, _, 3)(1, 2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(1, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(1, 2), [3, 2, 1]);
 
-    eq(g(1, _, _)(_, 3)(2), [3, 2, 1]);
-    eq(g(_, 2, _)(_, 3)(1), [3, 2, 1]);
-    eq(g(_, _, 3)(_, 2)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(_, 3)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(_, 3)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(_, 2)(1), [3, 2, 1]);
 
-    eq(g(_, _, _)(_, _)(_)(1, 2, 3), [3, 2, 1]);
-    eq(g(_, _, _)(1, _, _)(_, _)(2, _)(_)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, _)(_, _)(_)(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, _)(1, _, _)(_, _)(2, _)(_)(3), [3, 2, 1]);
   });
 
   it('should forward extra arguments', function() {
@@ -130,11 +130,11 @@ describe('curryRight', function() {
     };
     const g = RA.curryRight(f);
 
-    eq(g(1, 2, 3), [3, 2, 1]);
-    eq(g(1, 2, 3, 4), [4, 3, 2, 1]);
-    eq(g(1, 2)(3, 4), [4, 3, 2, 1]);
-    eq(g(1)(2, 3, 4), [4, 3, 2, 1]);
-    eq(g(1)(2)(3, 4), [4, 3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, 3, 4), [4, 3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2)(3, 4), [4, 3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2, 3, 4), [4, 3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2)(3, 4), [4, 3, 2, 1]);
   });
 });
 
diff --git a/test/curryRightN.js b/test/curryRightN.js
index 7c1809a0b5..f217e65275 100644
--- a/test/curryRightN.js
+++ b/test/curryRightN.js
@@ -1,6 +1,6 @@
 import * as R from 'ramda';
+import { assert } from 'chai';
 
-import eq from './shared/eq';
 import * as RA from '../src';
 
 describe('curryRightN', function() {
@@ -11,20 +11,20 @@ describe('curryRightN', function() {
 
   it('should accept an arity', function() {
     const curried = RA.curryRightN(3, source);
-    eq(curried(1)(2)(3), 6);
-    eq(curried(1, 2)(3), 6);
-    eq(curried(1)(2, 3), 6);
-    eq(curried(1, 2, 3), 6);
+    assert.strictEqual(curried(1)(2)(3), 6);
+    assert.strictEqual(curried(1, 2)(3), 6);
+    assert.strictEqual(curried(1)(2, 3), 6);
+    assert.strictEqual(curried(1, 2, 3), 6);
   });
 
   it('should support partial application/currying', function() {
     const curryRight3 = RA.curryRightN(3);
     const curried = curryRight3(source);
-    eq(curried.length, 3);
-    eq(curried(1)(2)(3), 6);
-    eq(curried(1, 2)(3), 6);
-    eq(curried(1)(2, 3), 6);
-    eq(curried(1, 2, 3), 6);
+    assert.strictEqual(curried.length, 3);
+    assert.strictEqual(curried(1)(2)(3), 6);
+    assert.strictEqual(curried(1, 2)(3), 6);
+    assert.strictEqual(curried(1)(2, 3), 6);
+    assert.strictEqual(curried(1, 2, 3), 6);
   });
 
   it('should preserve context', function() {
@@ -34,8 +34,8 @@ describe('curryRightN', function() {
     };
     const g = RA.curryRightN(2, f);
 
-    eq(g.call(ctx, 2, 4), 24);
-    eq(g.call(ctx, 2).call(ctx, 4), 24);
+    assert.strictEqual(g.call(ctx, 2, 4), 24);
+    assert.strictEqual(g.call(ctx, 2).call(ctx, 4), 24);
   });
 
   it('should support R.__ placeholder', function() {
@@ -45,29 +45,29 @@ describe('curryRightN', function() {
     const g = RA.curryRightN(3, f);
     const _ = R.__;
 
-    eq(g(1)(2)(3), [3, 2, 1]);
-    eq(g(1)(2, 3), [3, 2, 1]);
-    eq(g(1, 2)(3), [3, 2, 1]);
-    eq(g(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, 3), [3, 2, 1]);
 
-    eq(g(_, 2, 3)(1), [3, 2, 1]);
-    eq(g(1, _, 3)(2), [3, 2, 1]);
-    eq(g(1, 2, _)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, 3)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, 3)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, _)(3), [3, 2, 1]);
 
-    eq(g(1, _, _)(2)(3), [3, 2, 1]);
-    eq(g(_, 2, _)(1)(3), [3, 2, 1]);
-    eq(g(_, _, 3)(1)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(1)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(1)(2), [3, 2, 1]);
 
-    eq(g(1, _, _)(2, 3), [3, 2, 1]);
-    eq(g(_, 2, _)(1, 3), [3, 2, 1]);
-    eq(g(_, _, 3)(1, 2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(1, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(1, 2), [3, 2, 1]);
 
-    eq(g(1, _, _)(_, 3)(2), [3, 2, 1]);
-    eq(g(_, 2, _)(_, 3)(1), [3, 2, 1]);
-    eq(g(_, _, 3)(_, 2)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(_, 3)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(_, 3)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(_, 2)(1), [3, 2, 1]);
 
-    eq(g(_, _, _)(_, _)(_)(1, 2, 3), [3, 2, 1]);
-    eq(g(_, _, _)(1, _, _)(_, _)(2, _)(_)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, _)(_, _)(_)(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, _)(1, _, _)(_, _)(2, _)(_)(3), [3, 2, 1]);
   });
 
   it('should support @@functional/placeholder', function() {
@@ -77,29 +77,29 @@ describe('curryRightN', function() {
     const g = RA.curryRightN(3, f);
     const _ = { '@@functional/placeholder': true, x: Math.random() };
 
-    eq(g(1)(2)(3), [3, 2, 1]);
-    eq(g(1)(2, 3), [3, 2, 1]);
-    eq(g(1, 2)(3), [3, 2, 1]);
-    eq(g(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, 3), [3, 2, 1]);
 
-    eq(g(_, 2, 3)(1), [3, 2, 1]);
-    eq(g(1, _, 3)(2), [3, 2, 1]);
-    eq(g(1, 2, _)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, 3)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, 3)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, _)(3), [3, 2, 1]);
 
-    eq(g(1, _, _)(2)(3), [3, 2, 1]);
-    eq(g(_, 2, _)(1)(3), [3, 2, 1]);
-    eq(g(_, _, 3)(1)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(2)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(1)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(1)(2), [3, 2, 1]);
 
-    eq(g(1, _, _)(2, 3), [3, 2, 1]);
-    eq(g(_, 2, _)(1, 3), [3, 2, 1]);
-    eq(g(_, _, 3)(1, 2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(1, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(1, 2), [3, 2, 1]);
 
-    eq(g(1, _, _)(_, 3)(2), [3, 2, 1]);
-    eq(g(_, 2, _)(_, 3)(1), [3, 2, 1]);
-    eq(g(_, _, 3)(_, 2)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, _, _)(_, 3)(2), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, 2, _)(_, 3)(1), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, 3)(_, 2)(1), [3, 2, 1]);
 
-    eq(g(_, _, _)(_, _)(_)(1, 2, 3), [3, 2, 1]);
-    eq(g(_, _, _)(1, _, _)(_, _)(2, _)(_)(3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, _)(_, _)(_)(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(_, _, _)(1, _, _)(_, _)(2, _)(_)(3), [3, 2, 1]);
   });
 
   it('should forward extra arguments', function() {
@@ -108,10 +108,10 @@ describe('curryRightN', function() {
     };
     const g = RA.curryRightN(3, f);
 
-    eq(g(1, 2, 3), [3, 2, 1]);
-    eq(g(1, 2, 3, 4), [4, 3, 2, 1]);
-    eq(g(1, 2)(3, 4), [4, 3, 2, 1]);
-    eq(g(1)(2, 3, 4), [4, 3, 2, 1]);
-    eq(g(1)(2)(3, 4), [4, 3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, 3), [3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2, 3, 4), [4, 3, 2, 1]);
+    assert.sameOrderedMembers(g(1, 2)(3, 4), [4, 3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2, 3, 4), [4, 3, 2, 1]);
+    assert.sameOrderedMembers(g(1)(2)(3, 4), [4, 3, 2, 1]);
   });
 });
diff --git a/test/defaultWhen.js b/test/defaultWhen.js
index 8cec57003c..d01c3b1cd0 100644
--- a/test/defaultWhen.js
+++ b/test/defaultWhen.js
@@ -1,20 +1,21 @@
+import { assert } from 'chai';
+
 import * as RA from '../src';
-import eq from './shared/eq';
 
 describe('defaultWhen', function() {
   it('should return default value', function() {
-    eq(RA.defaultWhen(RA.isNull, 1, null), 1);
-    eq(RA.defaultWhen(RA.isString, 2, ''), 2);
+    assert.strictEqual(RA.defaultWhen(RA.isNull, 1, null), 1);
+    assert.strictEqual(RA.defaultWhen(RA.isString, 2, ''), 2);
   });
 
   it('should return value', function() {
-    eq(RA.defaultWhen(RA.isNull, 1, undefined), undefined);
-    eq(RA.defaultWhen(RA.isString, 2, 3), 3);
+    assert.isUndefined(RA.defaultWhen(RA.isNull, 1, undefined));
+    assert.strictEqual(RA.defaultWhen(RA.isString, 2, 3), 3);
   });
 
   it('should curry', function() {
-    eq(RA.defaultWhen(RA.isNull)(1)(null), 1);
-    eq(RA.defaultWhen(RA.isNull, 1)(null), 1);
-    eq(RA.defaultWhen(RA.isNull, 1, null), 1);
+    assert.strictEqual(RA.defaultWhen(RA.isNull)(1)(null), 1);
+    assert.strictEqual(RA.defaultWhen(RA.isNull, 1)(null), 1);
+    assert.strictEqual(RA.defaultWhen(RA.isNull, 1, null), 1);
   });
 });
diff --git a/test/dispatch.js b/test/dispatch.js
index 533102c358..8fe6320fe2 100644
--- a/test/dispatch.js
+++ b/test/dispatch.js
@@ -3,7 +3,6 @@ import { assert } from 'chai';
 import sinon from 'sinon';
 
 import * as RA from '../src';
-import eq from './shared/eq';
 
 describe('dispatch', function() {
   it('should return first non-nil value', function() {
@@ -29,7 +28,7 @@ describe('dispatch', function() {
   it('should return curried function with max arity', function() {
     const fn = RA.dispatch([R.divide, R.identity]);
 
-    eq(fn.length, 2);
+    assert.strictEqual(fn.length, 2);
   });
 
   it('should act as switch', function() {
@@ -72,7 +71,7 @@ describe('dispatch', function() {
 
   context('given empty array provided as input', function() {
     specify('should return undefined', function() {
-      eq(RA.dispatch([]), undefined);
+      assert.isUndefined(RA.dispatch([]));
     });
   });
 
@@ -80,7 +79,7 @@ describe('dispatch', function() {
     specify('should return undefined', function() {
       const configuredDispatch = RA.dispatch([RA.stubUndefined, RA.stubNull]);
 
-      eq(configuredDispatch(), undefined);
+      assert.isUndefined(configuredDispatch());
     });
   });
 
@@ -90,7 +89,7 @@ describe('dispatch', function() {
       specify('should return undefined', function() {
         const configuredDispatch = RA.dispatch([() => {}, () => {}]);
 
-        eq(configuredDispatch(), undefined);
+        assert.isUndefined(configuredDispatch());
       });
     }
   );
@@ -98,6 +97,6 @@ describe('dispatch', function() {
   it('should support placeholder to specify "gaps"', function() {
     const dispatch = RA.dispatch(R.__);
 
-    eq(dispatch([RA.stubNull, R.always(1)])(), 1);
+    assert.strictEqual(dispatch([RA.stubNull, R.always(1)])(), 1);
   });
 });
diff --git a/test/mocha-testem.mustache b/test/mocha-testem.mustache
new file mode 100644
index 0000000000..c6a39f83a1
--- /dev/null
+++ b/test/mocha-testem.mustache
@@ -0,0 +1,20 @@
+<!doctype html>
+<html>
+<head>
+    <title>Test'em</title>
+    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/mocha/6.2.0/mocha.css">
+    <script src="//cdnjs.cloudflare.com/ajax/libs/mocha/6.2.0/mocha.js"></script>
+    <script src="//cdnjs.cloudflare.com/ajax/libs/chai/4.2.0/chai.js"></script>
+    <script src="/testem.js"></script>
+    <script>
+        mocha.setup('bdd');
+    </script>
+    <script src="../tmp-test-bundle.js"></script>
+</head>
+<body>
+<div id="mocha"></div>
+<script>
+    mocha.run();
+</script>
+</body>
+</html>
diff --git a/test/padCharsEnd.js b/test/padCharsEnd.js
index 952aa84cb0..8320669de5 100644
--- a/test/padCharsEnd.js
+++ b/test/padCharsEnd.js
@@ -1,8 +1,5 @@
 import * as RA from '../src';
-import {
-  padCharsEndStrInvoker,
-  padCharsEndStrPolyfill,
-} from '../src/padCharsEnd';
+import { padEndInvoker, padEndPolyfill } from '../src/padCharsEnd';
 import eq from './shared/eq';
 
 describe('padCharsEnd', function() {
@@ -69,26 +66,26 @@ describe('padCharsEnd', function() {
     eq(RA.padCharsEnd('*')(5)('abc'), 'abc**');
   });
 
-  context('padCharsEndStrInvoker', function() {
-    beforeEach(function() {
+  context('padEndInvoker', function() {
+    before(function() {
       if (RA.isNotFunction(String.prototype.padEnd)) {
         this.skip();
       }
     });
 
     specify('should pad string with given padString', function() {
-      eq(padCharsEndStrInvoker('-', 3, 'a'), 'a--');
+      eq(padEndInvoker('-', 3, 'a'), 'a--');
     });
 
     context('given targetLength as 0', function() {
       specify('should return original string', function() {
-        eq(padCharsEndStrInvoker('$', 0, 'abc'), 'abc');
+        eq(padEndInvoker('$', 0, 'abc'), 'abc');
       });
     });
 
     context('given targetLength less than string length', function() {
       specify('should return original string', function() {
-        eq(padCharsEndStrInvoker('$', 1, 'abc'), 'abc');
+        eq(padEndInvoker('$', 1, 'abc'), 'abc');
       });
     });
 
@@ -96,15 +93,15 @@ describe('padCharsEnd', function() {
       'given targetLength less than equal to padString length',
       function() {
         specify('should trim padString', function() {
-          eq(padCharsEndStrInvoker('123456', 6, 'abc'), 'abc123');
-          eq(padCharsEndStrInvoker('123456', 5, 'abc'), 'abc12');
+          eq(padEndInvoker('123456', 6, 'abc'), 'abc123');
+          eq(padEndInvoker('123456', 5, 'abc'), 'abc12');
         });
       }
     );
 
     context('given targetLength supplied as float', function() {
       specify('should convert targetLength to integer', function() {
-        eq(padCharsEndStrInvoker('$', 7.5, 'abc'), 'abc$$$$');
+        eq(padEndInvoker('$', 7.5, 'abc'), 'abc$$$$');
       });
     });
 
@@ -112,51 +109,51 @@ describe('padCharsEnd', function() {
       'given targetLength is a value coercible to valid integer number',
       function() {
         specify('should return padded string', function() {
-          eq(padCharsEndStrInvoker('*', '5', 'abc'), 'abc**');
+          eq(padEndInvoker('*', '5', 'abc'), 'abc**');
         });
       }
     );
 
     context('given targeLength is a negative number', function() {
       specify('should return original string', function() {
-        eq(padCharsEndStrInvoker('$', -10, 'abc'), 'abc');
+        eq(padEndInvoker('$', -10, 'abc'), 'abc');
       });
     });
 
     context('given padString set to undefined', function() {
       specify('should return string padded with spaces', function() {
-        eq(padCharsEndStrInvoker(undefined, 5, '200'), '200  ');
+        eq(padEndInvoker(undefined, 5, '200'), '200  ');
       });
     });
 
     context('given null padString', function() {
       specify('should convert null to string type', function() {
-        eq(padCharsEndStrInvoker(null, 5, 'abc'), 'abcnu');
+        eq(padEndInvoker(null, 5, 'abc'), 'abcnu');
       });
     });
 
     specify('should be curried', function() {
-      eq(padCharsEndStrInvoker('*', 5, 'abc'), 'abc**');
-      eq(padCharsEndStrInvoker('*', 5)('abc'), 'abc**');
-      eq(padCharsEndStrInvoker('*')(5, 'abc'), 'abc**');
-      eq(padCharsEndStrInvoker('*')(5)('abc'), 'abc**');
+      eq(padEndInvoker('*', 5, 'abc'), 'abc**');
+      eq(padEndInvoker('*', 5)('abc'), 'abc**');
+      eq(padEndInvoker('*')(5, 'abc'), 'abc**');
+      eq(padEndInvoker('*')(5)('abc'), 'abc**');
     });
   });
 
-  context('padCharsEndStrPolyfill', function() {
+  context('padEndPolyfill', function() {
     specify('should pad string with given padString', function() {
-      eq(padCharsEndStrPolyfill('-', 3, 'a'), 'a--');
+      eq(padEndPolyfill('-', 3, 'a'), 'a--');
     });
 
     context('given targetLength as 0', function() {
       specify('should return original string', function() {
-        eq(padCharsEndStrPolyfill('$', 0, 'abc'), 'abc');
+        eq(padEndPolyfill('$', 0, 'abc'), 'abc');
       });
     });
 
     context('given targetLength less than string length', function() {
       specify('should return original string', function() {
-        eq(padCharsEndStrPolyfill('$', 1, 'abc'), 'abc');
+        eq(padEndPolyfill('$', 1, 'abc'), 'abc');
       });
     });
 
@@ -164,15 +161,15 @@ describe('padCharsEnd', function() {
       'given targetLength less than equal to padString length',
       function() {
         specify('should trim padString', function() {
-          eq(padCharsEndStrPolyfill('123456', 6, 'abc'), 'abc123');
-          eq(padCharsEndStrPolyfill('123456', 5, 'abc'), 'abc12');
+          eq(padEndPolyfill('123456', 6, 'abc'), 'abc123');
+          eq(padEndPolyfill('123456', 5, 'abc'), 'abc12');
         });
       }
     );
 
     context('given targetLength supplied as float', function() {
       specify('should convert targetLength to integer', function() {
-        eq(padCharsEndStrPolyfill('$', 7.5, 'abc'), 'abc$$$$');
+        eq(padEndPolyfill('$', 7.5, 'abc'), 'abc$$$$');
       });
     });
 
@@ -180,34 +177,34 @@ describe('padCharsEnd', function() {
       'given targetLength is a value coercible to valid integer number',
       function() {
         specify('should return padded string', function() {
-          eq(padCharsEndStrPolyfill('*', '5', 'abc'), 'abc**');
+          eq(padEndPolyfill('*', '5', 'abc'), 'abc**');
         });
       }
     );
 
     context('given targeLength is a negative number', function() {
       specify('should return original string', function() {
-        eq(padCharsEndStrPolyfill('$', -10, 'abc'), 'abc');
+        eq(padEndPolyfill('$', -10, 'abc'), 'abc');
       });
     });
 
     context('given padString set to undefined', function() {
       specify('should return string padded with spaces', function() {
-        eq(padCharsEndStrPolyfill(undefined, 5, '200'), '200  ');
+        eq(padEndPolyfill(undefined, 5, '200'), '200  ');
       });
     });
 
     context('given null padString', function() {
       specify('should convert null to string type', function() {
-        eq(padCharsEndStrPolyfill(null, 5, 'abc'), 'abcnu');
+        eq(padEndPolyfill(null, 5, 'abc'), 'abcnu');
       });
     });
 
     specify('should be curried', function() {
-      eq(padCharsEndStrPolyfill('*', 5, 'abc'), 'abc**');
-      eq(padCharsEndStrPolyfill('*', 5)('abc'), 'abc**');
-      eq(padCharsEndStrPolyfill('*')(5, 'abc'), 'abc**');
-      eq(padCharsEndStrPolyfill('*')(5)('abc'), 'abc**');
+      eq(padEndPolyfill('*', 5, 'abc'), 'abc**');
+      eq(padEndPolyfill('*', 5)('abc'), 'abc**');
+      eq(padEndPolyfill('*')(5, 'abc'), 'abc**');
+      eq(padEndPolyfill('*')(5)('abc'), 'abc**');
     });
   });
 });
diff --git a/test/padCharsStart.js b/test/padCharsStart.js
new file mode 100644
index 0000000000..b04d3c3877
--- /dev/null
+++ b/test/padCharsStart.js
@@ -0,0 +1,215 @@
+import * as RA from '../src';
+import eq from './shared/eq';
+import {
+  stringPadStartInvoker,
+  stringPadStartPolyfill,
+} from '../src/padCharsStart';
+
+describe('padCharsStart', function() {
+  specify('should pad string with given padString', function() {
+    eq(RA.padCharsStart('-', 3, 'a'), '--a');
+  });
+
+  context('given targetLength as 0', function() {
+    specify('should return original string', function() {
+      eq(RA.padCharsStart('-', 0, 'abc'), 'abc');
+    });
+  });
+
+  context('given targetLength less than string length', function() {
+    specify('should return original string', function() {
+      eq(RA.padCharsStart('-', 1, 'abc'), 'abc');
+    });
+  });
+
+  context('given targetLength less than equal to padString length', function() {
+    specify('should trim padString', function() {
+      eq(RA.padCharsStart('123456', 6, 'abc'), '123abc');
+      eq(RA.padCharsStart('123456', 5, 'abc'), '12abc');
+    });
+  });
+
+  context('given targetLength supplied as float', function() {
+    specify('should convert targetLength to integer', function() {
+      eq(RA.padCharsStart('-', 7.5, 'abc'), '----abc');
+    });
+  });
+
+  context(
+    'given targetLength is a value coercible to valid integer number',
+    function() {
+      specify('should return padded string', function() {
+        eq(RA.padCharsStart('-', '5', 'abc'), '--abc');
+      });
+    }
+  );
+
+  context('given targeLength is a negative number', function() {
+    specify('should return original string', function() {
+      eq(RA.padCharsStart('-', -10, 'abc'), 'abc');
+    });
+  });
+
+  context('given padString set to undefined', function() {
+    specify('should return string padded with spaces', function() {
+      eq(RA.padCharsStart(undefined, 5, '200'), '  200');
+    });
+  });
+
+  context('given null padString', function() {
+    specify('should convert null to string type', function() {
+      eq(RA.padCharsStart(null, 5, 'abc'), 'nuabc');
+    });
+  });
+
+  specify('should be curried', function() {
+    eq(RA.padCharsStart('-', 5, 'abc'), '--abc');
+    eq(RA.padCharsStart('-', 5)('abc'), '--abc');
+    eq(RA.padCharsStart('-')(5, 'abc'), '--abc');
+    eq(RA.padCharsStart('-')(5)('abc'), '--abc');
+  });
+
+  //   Tests cases for invoker of native String.prototype.padStart
+  context('stringPadStartInvoker', function() {
+    beforeEach(function() {
+      if (RA.isNotFunction(String.prototype.padEnd)) {
+        this.skip();
+      }
+    });
+
+    specify('should pad string with given padString', function() {
+      eq(stringPadStartInvoker('-', 3, 'a'), '--a');
+    });
+
+    context('given targetLength as 0', function() {
+      specify('should return original string', function() {
+        eq(stringPadStartInvoker('-', 0, 'abc'), 'abc');
+      });
+    });
+
+    context('given targetLength less than string length', function() {
+      specify('should return original string', function() {
+        eq(stringPadStartInvoker('-', 1, 'abc'), 'abc');
+      });
+    });
+
+    context(
+      'given targetLength less than equal to padString length',
+      function() {
+        specify('should trim padString', function() {
+          eq(stringPadStartInvoker('123456', 6, 'abc'), '123abc');
+          eq(stringPadStartInvoker('123456', 5, 'abc'), '12abc');
+        });
+      }
+    );
+
+    context('given targetLength supplied as float', function() {
+      specify('should convert targetLength to integer', function() {
+        eq(stringPadStartInvoker('-', 7.5, 'abc'), '----abc');
+      });
+    });
+
+    context(
+      'given targetLength is a value coercible to valid integer number',
+      function() {
+        specify('should return padded string', function() {
+          eq(stringPadStartInvoker('-', '5', 'abc'), '--abc');
+        });
+      }
+    );
+
+    context('given targeLength is a negative number', function() {
+      specify('should return original string', function() {
+        eq(stringPadStartInvoker('-', -10, 'abc'), 'abc');
+      });
+    });
+
+    context('given padString set to undefined', function() {
+      specify('should return string padded with spaces', function() {
+        eq(stringPadStartInvoker(undefined, 5, '200'), '  200');
+      });
+    });
+
+    context('given null padString', function() {
+      specify('should convert null to string type', function() {
+        eq(stringPadStartInvoker(null, 5, 'abc'), 'nuabc');
+      });
+    });
+
+    specify('should be curried', function() {
+      eq(stringPadStartInvoker('-', 5, 'abc'), '--abc');
+      eq(stringPadStartInvoker('-', 5)('abc'), '--abc');
+      eq(stringPadStartInvoker('-')(5, 'abc'), '--abc');
+      eq(stringPadStartInvoker('-')(5)('abc'), '--abc');
+    });
+  });
+
+  //   Tests cases for String.prototype.padStart polyfil
+  context('stringPadStartPolyfill', function() {
+    specify('should pad string with given padString', function() {
+      eq(stringPadStartPolyfill('-', 3, 'a'), '--a');
+    });
+
+    context('given targetLength as 0', function() {
+      specify('should return original string', function() {
+        eq(stringPadStartPolyfill('-', 0, 'abc'), 'abc');
+      });
+    });
+
+    context('given targetLength less than string length', function() {
+      specify('should return original string', function() {
+        eq(stringPadStartPolyfill('-', 1, 'abc'), 'abc');
+      });
+    });
+
+    context(
+      'given targetLength less than equal to padString length',
+      function() {
+        specify('should trim padString', function() {
+          eq(stringPadStartPolyfill('123456', 6, 'abc'), '123abc');
+          eq(stringPadStartPolyfill('123456', 5, 'abc'), '12abc');
+        });
+      }
+    );
+
+    context('given targetLength supplied as float', function() {
+      specify('should convert targetLength to integer', function() {
+        eq(stringPadStartPolyfill('-', 7.5, 'abc'), '----abc');
+      });
+    });
+
+    context(
+      'given targetLength is a value coercible to valid integer number',
+      function() {
+        specify('should return padded string', function() {
+          eq(stringPadStartPolyfill('-', '5', 'abc'), '--abc');
+        });
+      }
+    );
+
+    context('given targeLength is a negative number', function() {
+      specify('should return original string', function() {
+        eq(stringPadStartPolyfill('-', -10, 'abc'), 'abc');
+      });
+    });
+
+    context('given padString set to undefined', function() {
+      specify('should return string padded with spaces', function() {
+        eq(stringPadStartPolyfill(undefined, 5, '200'), '  200');
+      });
+    });
+
+    context('given null padString', function() {
+      specify('should convert null to string type', function() {
+        eq(stringPadStartPolyfill(null, 5, 'abc'), 'nuabc');
+      });
+    });
+
+    specify('should be curried', function() {
+      eq(stringPadStartPolyfill('-', 5, 'abc'), '--abc');
+      eq(stringPadStartPolyfill('-', 5)('abc'), '--abc');
+      eq(stringPadStartPolyfill('-')(5, 'abc'), '--abc');
+      eq(stringPadStartPolyfill('-')(5)('abc'), '--abc');
+    });
+  });
+});
diff --git a/test/padEnd.js b/test/padEnd.js
index c13c5d772c..78495d0cba 100644
--- a/test/padEnd.js
+++ b/test/padEnd.js
@@ -39,7 +39,7 @@ describe('padEnd', function() {
     });
   });
 
-  specify('should be curried', function() {
+  specify('should curry', function() {
     eq(RA.padEnd(5, 'abc'), 'abc  ');
     eq(RA.padEnd(5)('abc'), 'abc  ');
   });
diff --git a/test/repeatStr.js b/test/repeatStr.js
index 8143b6c38f..7fc2764427 100644
--- a/test/repeatStr.js
+++ b/test/repeatStr.js
@@ -54,7 +54,7 @@ describe('repeatStr', function() {
   });
 
   context('repeatStrInvoker', function() {
-    beforeEach(function() {
+    before(function() {
       if (RA.isNotFunction(String.prototype.repeat)) {
         this.skip();
       }
diff --git a/test/replaceAll.js b/test/replaceAll.js
index 4e12413725..dc5fae05df 100644
--- a/test/replaceAll.js
+++ b/test/replaceAll.js
@@ -1,7 +1,7 @@
 import { assert } from 'chai';
 
 import * as RA from '../src';
-import { replaceAllPolyfill } from '../src/replaceAll';
+import { replaceAllPolyfill, replaceAllInvoker } from '../src/replaceAll';
 
 describe('replaceAll', function() {
   it('should replace all matches', function() {
@@ -36,6 +36,12 @@ describe('replaceAll', function() {
     assert.strictEqual(actual, expected);
   });
 
+  context('given searchValue is a non-global RegExp', function() {
+    specify('should throw Error', function() {
+      assert.throws(() => RA.replaceAll(/a/, 'c', 'abc'), TypeError);
+    });
+  });
+
   it('should curry', function() {
     assert.strictEqual(RA.replaceAll('a', 'c', 'aba'), 'cbc');
     assert.strictEqual(RA.replaceAll('a')('c', 'aba'), 'cbc');
@@ -43,72 +49,135 @@ describe('replaceAll', function() {
     assert.strictEqual(RA.replaceAll('a')('c')('aba'), 'cbc');
   });
 
-  context('given searchValue is a non-global RegExp', function() {
-    specify('should throw Error', function() {
-      assert.throws(() => RA.replaceAll(/a/, 'c', 'abc'), TypeError);
+  context('replaceAllInvoker', function() {
+    before(function() {
+      if (RA.isNotFunction(String.prototype.replaceAll)) {
+        this.skip();
+      }
     });
-  });
-});
 
-describe('replaceAllPolyfill', function() {
-  context('given searchValue is a non-global RegExp', function() {
-    specify('should throw Error', function() {
-      assert.throws(() => replaceAllPolyfill(/a/, 'c', 'abc'), TypeError);
+    context('given searchValue is a non-global RegExp', function() {
+      specify('should throw Error', function() {
+        assert.throws(() => replaceAllInvoker(/a/, 'c', 'abc'), TypeError);
+      });
     });
-  });
 
-  it('should support global RegExp searchValue', function() {
-    const value = 'xxx';
-    const actual = replaceAllPolyfill(/x/g, 'v', value);
-    const expected = 'vvv';
+    specify('should support global RegExp searchValue', function() {
+      const value = 'xxx';
+      const actual = replaceAllInvoker(/x/g, 'v', value);
+      const expected = 'vvv';
 
-    assert.strictEqual(actual, expected);
-  });
+      assert.strictEqual(actual, expected);
+    });
 
-  it('should support empty searchValue', function() {
-    const value = 'xxx';
-    const actual = replaceAllPolyfill('', '_', value);
-    const expected = '_x_x_x_';
+    specify('should support empty searchValue', function() {
+      const value = 'xxx';
+      const actual = replaceAllInvoker('', '_', value);
+      const expected = '_x_x_x_';
 
-    assert.strictEqual(actual, expected);
-  });
+      assert.strictEqual(actual, expected);
+    });
 
-  it('should replace all matches', function() {
-    const value = 'ab cd ab cd ab cd';
-    const actual = replaceAllPolyfill('ab', 'ef', value);
-    const expected = 'ef cd ef cd ef cd';
+    specify('should replace all matches', function() {
+      const value = 'ab cd ab cd ab cd';
+      const actual = replaceAllInvoker('ab', 'ef', value);
+      const expected = 'ef cd ef cd ef cd';
 
-    assert.strictEqual(actual, expected);
-  });
+      assert.strictEqual(actual, expected);
+    });
 
-  context('given empty string', function() {
-    specify('should return original value', function() {
-      assert.strictEqual(replaceAllPolyfill('a', 'c', ''), '');
+    context('given empty string', function() {
+      specify('should return original value', function() {
+        assert.strictEqual(replaceAllInvoker('a', 'c', ''), '');
+      });
     });
-  });
 
-  it('should support boxing wrappers', function() {
-    const value = new String('ab cd ab cd ab cd');
-    const searchValue = new String('ab');
-    const replaceValue = new String('ef');
-    const actual = replaceAllPolyfill(searchValue, replaceValue, value);
-    const expected = 'ef cd ef cd ef cd';
+    specify('should support boxing wrappers', function() {
+      const value = new String('ab cd ab cd ab cd');
+      const searchValue = new String('ab');
+      const replaceValue = new String('ef');
+      const actual = replaceAllInvoker(searchValue, replaceValue, value);
+      const expected = 'ef cd ef cd ef cd';
 
-    assert.strictEqual(actual, expected);
-  });
+      assert.strictEqual(actual, expected);
+    });
 
-  it('should replace in very big strings', function() {
-    const bigString = 'ab cd'.repeat(10000);
-    const expected = 'ab ef'.repeat(10000);
-    const actual = replaceAllPolyfill('cd', 'ef', bigString);
+    specify('should replace in very big strings', function() {
+      const bigString = 'ab cd'.repeat(10000);
+      const expected = 'ab ef'.repeat(10000);
+      const actual = replaceAllInvoker('cd', 'ef', bigString);
 
-    assert.strictEqual(actual, expected);
+      assert.strictEqual(actual, expected);
+    });
+
+    specify('should curry', function() {
+      assert.strictEqual(replaceAllInvoker('a', 'c', 'aba'), 'cbc');
+      assert.strictEqual(replaceAllInvoker('a')('c', 'aba'), 'cbc');
+      assert.strictEqual(replaceAllInvoker('a', 'c')('aba'), 'cbc');
+      assert.strictEqual(replaceAllInvoker('a')('c')('aba'), 'cbc');
+    });
   });
 
-  it('should curry', function() {
-    assert.strictEqual(replaceAllPolyfill('a', 'c', 'aba'), 'cbc');
-    assert.strictEqual(replaceAllPolyfill('a')('c', 'aba'), 'cbc');
-    assert.strictEqual(replaceAllPolyfill('a', 'c')('aba'), 'cbc');
-    assert.strictEqual(replaceAllPolyfill('a')('c')('aba'), 'cbc');
+  context('replaceAllPolyfill', function() {
+    context('given searchValue is a non-global RegExp', function() {
+      specify('should throw Error', function() {
+        assert.throws(() => replaceAllPolyfill(/a/, 'c', 'abc'), TypeError);
+      });
+    });
+
+    specify('should support global RegExp searchValue', function() {
+      const value = 'xxx';
+      const actual = replaceAllPolyfill(/x/g, 'v', value);
+      const expected = 'vvv';
+
+      assert.strictEqual(actual, expected);
+    });
+
+    specify('should support empty searchValue', function() {
+      const value = 'xxx';
+      const actual = replaceAllPolyfill('', '_', value);
+      const expected = '_x_x_x_';
+
+      assert.strictEqual(actual, expected);
+    });
+
+    specify('should replace all matches', function() {
+      const value = 'ab cd ab cd ab cd';
+      const actual = replaceAllPolyfill('ab', 'ef', value);
+      const expected = 'ef cd ef cd ef cd';
+
+      assert.strictEqual(actual, expected);
+    });
+
+    context('given empty string', function() {
+      specify('should return original value', function() {
+        assert.strictEqual(replaceAllPolyfill('a', 'c', ''), '');
+      });
+    });
+
+    specify('should support boxing wrappers', function() {
+      const value = new String('ab cd ab cd ab cd');
+      const searchValue = new String('ab');
+      const replaceValue = new String('ef');
+      const actual = replaceAllPolyfill(searchValue, replaceValue, value);
+      const expected = 'ef cd ef cd ef cd';
+
+      assert.strictEqual(actual, expected);
+    });
+
+    specify('should replace in very big strings', function() {
+      const bigString = 'ab cd'.repeat(10000);
+      const expected = 'ab ef'.repeat(10000);
+      const actual = replaceAllPolyfill('cd', 'ef', bigString);
+
+      assert.strictEqual(actual, expected);
+    });
+
+    specify('should curry', function() {
+      assert.strictEqual(replaceAllPolyfill('a', 'c', 'aba'), 'cbc');
+      assert.strictEqual(replaceAllPolyfill('a')('c', 'aba'), 'cbc');
+      assert.strictEqual(replaceAllPolyfill('a', 'c')('aba'), 'cbc');
+      assert.strictEqual(replaceAllPolyfill('a')('c')('aba'), 'cbc');
+    });
   });
 });
diff --git a/test/sign.js b/test/sign.js
index 4026bb9204..fccf103aed 100644
--- a/test/sign.js
+++ b/test/sign.js
@@ -87,7 +87,7 @@ describe('sign', function() {
   });
 
   context('signPolyfill', function() {
-    beforeEach(function() {
+    before(function() {
       if (RA.isNotFunction(Math.sign)) {
         this.skip();
       }
diff --git a/test/trimEnd.js b/test/trimEnd.js
index 17d8466294..de84cc942b 100644
--- a/test/trimEnd.js
+++ b/test/trimEnd.js
@@ -35,7 +35,7 @@ describe('trimEnd', function() {
   });
 
   context('trimEndInvoker', function() {
-    beforeEach(function() {
+    before(function() {
       if (RA.isNotFunction(String.prototype.trimEnd)) {
         this.skip();
       }
diff --git a/test/trimStart.js b/test/trimStart.js
index 7f5233a788..854103829b 100644
--- a/test/trimStart.js
+++ b/test/trimStart.js
@@ -38,7 +38,7 @@ describe('trimStart', function() {
   });
 
   context('trimStartInvoker', function() {
-    beforeEach(function() {
+    before(function() {
       if (RA.isNotFunction(String.prototype.trimStart)) {
         this.skip();
       }
diff --git a/test/trunc.js b/test/trunc.js
index 2aa47ff11f..f53323dff5 100644
--- a/test/trunc.js
+++ b/test/trunc.js
@@ -84,7 +84,7 @@ describe('trunc', function() {
   });
 
   context('truncPolyfill', function() {
-    beforeEach(function() {
+    before(function() {
       if (RA.isNotFunction(Math.trunc)) {
         this.skip();
       }
diff --git a/test/zipObjWith.js b/test/zipObjWith.js
new file mode 100644
index 0000000000..4dc570a210
--- /dev/null
+++ b/test/zipObjWith.js
@@ -0,0 +1,61 @@
+import { assert } from 'chai';
+import * as R from 'ramda';
+
+import * as RA from '../src';
+
+describe('zipObjWith', function() {
+  it('should zip a pair of lists into an object', function() {
+    const keys = ['packageA', 'packageB', 'packageC'];
+    const values = [
+      { name: 'packageA', version: '1.0.9' },
+      { name: 'packageB', version: '1.6.1' },
+      { name: 'packageC', version: '1.6.0' },
+    ];
+    const fn = (v, k) => [k, { version: v.version }];
+
+    const actual = RA.zipObjWith(fn, keys, values);
+
+    const expected = {
+      packageA: { version: '1.0.9' },
+      packageB: { version: '1.6.1' },
+      packageC: { version: '1.6.0' },
+    };
+
+    assert.deepEqual(actual, expected);
+  });
+
+  context('given empty key/value lists', function() {
+    specify('should return an empty object', function() {
+      const fn = (v, k) => [k, v];
+      const keys = [];
+      const values = [];
+      const expected = {};
+
+      assert.deepEqual(RA.zipObjWith(fn, keys, values), expected);
+    });
+  });
+
+  context('given key/value lists of unequal length', function() {
+    specify('should truncate to the length of the shortest list', function() {
+      const fn = (v, k) => [k, v];
+      const long = ['a', 'b', 'c'];
+      const short = ['x', 'y'];
+
+      assert.deepEqual(RA.zipObjWith(fn, long, short), { a: 'x', b: 'y' });
+      assert.deepEqual(RA.zipObjWith(fn, short, long), { x: 'a', y: 'b' });
+    });
+  });
+
+  it('should curry', function() {
+    const fn = (v, k) => [k, `${k}${v + 1}`];
+    const keys = ['a', 'b', 'c', 'd'];
+    const values = [1, 2, 3];
+    const expected = { a: 'a2', b: 'b3', c: 'c4' };
+
+    assert.deepEqual(RA.zipObjWith(fn, keys, values), expected);
+    assert.deepEqual(RA.zipObjWith(fn, keys)(values), expected);
+    assert.deepEqual(RA.zipObjWith(fn)(keys)(values), expected);
+    assert.deepEqual(RA.zipObjWith()(fn)(keys)(values), expected);
+    assert.deepEqual(RA.zipObjWith(fn)(R.__, values)(keys), expected);
+  });
+});
diff --git a/testem.json b/testem.json
index d0913d69a0..54d58e1142 100644
--- a/testem.json
+++ b/testem.json
@@ -1,13 +1,5 @@
 {
-  "framework": "mocha",
-  "cwd": ".",
-  "src_files": [
-    "src/*.js",
-    "test/*.js"
-  ],
-  "serve_files": [
-    "tmp-test-bundle.js"
-  ],
+  "test_page": "./test/mocha-testem.mustache",
   "before_tests": "npm run test:bundle-create",
   "after_tests": "npm run test:bundle-clean"
 }
diff --git a/types/test/padCharsStart.ts b/types/test/padCharsStart.ts
new file mode 100644
index 0000000000..9aece50f45
--- /dev/null
+++ b/types/test/padCharsStart.ts
@@ -0,0 +1,10 @@
+import * as RA from 'ramda-adjunct';
+
+RA.padCharsStart('-', 3, 'a'); // $ExpectType string
+RA.padCharsStart('$', 5)('abc'); // $ExpectType string
+RA.padCharsStart('*')(10, 'hello'); // $ExpectType string
+
+RA.padCharsStart(1, 2, '3'); // $ExpectError
+RA.padCharsStart('#', '10', 'afsd'); // $ExpectError
+RA.padCharsStart(undefined, '12', 54); // $ExpectError
+RA.padCharsStart(null, 12, 'hello'); // $ExpectError
diff --git a/types/test/zipObjWith.ts b/types/test/zipObjWith.ts
new file mode 100644
index 0000000000..ed674514bc
--- /dev/null
+++ b/types/test/zipObjWith.ts
@@ -0,0 +1,10 @@
+import * as RA from 'ramda-adjunct';
+
+RA.zipObjWith((v, t) => [t, 1], ['a'], [2]); // $ExpectType { [k: string]: number; }
+RA.zipObjWith((v, k) => ['a', 'b'])([1], ['b']); // $ExpectType { [k: string]: string; }
+RA.zipObjWith<string, boolean, number>((v, k) => ['a', 1], [true], ['b']); // $ExpectType { [k: string]: number; }
+
+RA.zipObjWith((v, k) => true, ['a'], [2]); // $ExpectError
+RA.zipObjWith((v, k) => [k, v], {}, false); // $ExpectError
+RA.zipObjWith<boolean, boolean, string>((v, k) => ['a', 1], [true], ['b']); // $ExpectError
+RA.zipObjWith((v, k) => [k, v], undefined, undefined); // $ExpectError