diff --git a/.eslintrc.json b/.eslintrc.json
index 0f5dd91c..197d661f 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -4,7 +4,7 @@
"browser": true,
"commonjs": true,
"es6": true,
- "mocha": true,
+ "jest": true,
"node": true
},
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
@@ -15,7 +15,6 @@
"rules": {
"array-bracket-spacing": ["warn", "never"],
"arrow-body-style": ["warn", "as-needed"],
- "arrow-parens": ["warn", "as-needed"],
"arrow-spacing": "warn",
"brace-style": ["warn", "1tbs"],
"camelcase": "warn",
diff --git a/.github/workflows/browser.yml b/.github/workflows/browser.yml
new file mode 100644
index 00000000..0d60cb87
--- /dev/null
+++ b/.github/workflows/browser.yml
@@ -0,0 +1,31 @@
+name: Browser
+
+on: [push]
+
+jobs:
+ ci:
+
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ strategy:
+ matrix:
+ node-version: [12.x]
+ browser: [chrome, edge, firefox, ie, safari]
+
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ fetch-depth: 1
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v1
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: npm install
+ - name: Test ${{ matrix.node-version }}
+ run: npm run test:browser
+ env:
+ CI: true
+ BROWSER: ${{ matrix.browser }}
+ BROWSERSTACK_USER: ${{ secrets.BROWSERSTACK_USER }}
+ BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
diff --git a/.gitignore b/.gitignore
index af0ee801..3785d4a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,6 @@
node_modules
tmp
dist/
+# Browserstack
+browserstack.err
+local.log
diff --git a/README.md b/README.md
index 3369e69b..a5f81b20 100644
--- a/README.md
+++ b/README.md
@@ -80,6 +80,16 @@ uuid.v5('Hello, World!', MY_NAMESPACE); // ⇨ '630eb68f-e0fa-5ecc-887a-7c7a6261
```
+## Supported Platforms
+
+- Node.js: All LTS, i.e. 8.x, 10.x, 12.x
+- Browsers (with bundlers like webpack/rollup):
+ - Chrome: >= 49
+ - Safari: >= 10
+ - Firefox: >= 44
+ - Edge: >= 15
+ - IE: 11
+
## ECMAScript Modules / ESM
For usage in the browser `uuid` provides support for [ECMAScript
@@ -96,6 +106,12 @@ uuid(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'
There is experimental native ESM support for [the browser](./examples/browser-esmodules/) but it
should not be considered ready for production use and may change or disappear in future releases.
+To run the examples you must first build a dist package of this library in the module root:
+
+```
+npm run package
+```
+
## API
### Version 1 (Timestamp + Node)
diff --git a/README_js.md b/README_js.md
index a63d661d..dc670268 100644
--- a/README_js.md
+++ b/README_js.md
@@ -89,6 +89,16 @@ const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
uuid.v5('Hello, World!', MY_NAMESPACE); // RESULT
```
+## Supported Platforms
+
+- Node.js: All LTS, i.e. 8.x, 10.x, 12.x
+- Browsers (with bundlers like webpack/rollup):
+ - Chrome: >= 49
+ - Safari: >= 10
+ - Firefox: >= 44
+ - Edge: >= 15
+ - IE: 11
+
## ECMAScript Modules / ESM
For usage in the browser `uuid` provides support for [ECMAScript
@@ -105,6 +115,12 @@ uuid(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'
There is experimental native ESM support for [the browser](./examples/browser-esmodules/) but it
should not be considered ready for production use and may change or disappear in future releases.
+To run the examples you must first build a dist package of this library in the module root:
+
+```
+npm run package
+```
+
## API
### Version 1 (Timestamp + Node)
diff --git a/examples/browser-esmodules/package-lock.json b/examples/browser-esmodules/package-lock.json
index e7809454..78163da7 100644
--- a/examples/browser-esmodules/package-lock.json
+++ b/examples/browser-esmodules/package-lock.json
@@ -5,8 +5,7 @@
"requires": true,
"dependencies": {
"uuid": {
- "version": "github:ctavan/uuid-esm#d93bfcbfc22bfef4c5f021e855f8ceafc08d8f80",
- "from": "github:ctavan/uuid-esm#master"
+ "version": "file:../../dist"
}
}
}
diff --git a/examples/browser-esmodules/package.json b/examples/browser-esmodules/package.json
index cf82fdb5..57df9815 100644
--- a/examples/browser-esmodules/package.json
+++ b/examples/browser-esmodules/package.json
@@ -3,9 +3,10 @@
"version": "0.0.0",
"private": true,
"scripts": {
- "test": "npx http-server . -o"
+ "build": "true",
+ "start": "npm run build && npx http-server . -o"
},
"dependencies": {
- "uuid": "github:ctavan/uuid-esm#master"
+ "uuid": "file:../../dist"
}
}
diff --git a/examples/browser-rollup/README.md b/examples/browser-rollup/README.md
index dd51ee91..b1a3a578 100644
--- a/examples/browser-rollup/README.md
+++ b/examples/browser-rollup/README.md
@@ -2,10 +2,10 @@
```
npm install
-npm test
+npm start
```
-Then navigate to `example.html`.
+Then navigate to `example-*.html`.
The `example-v{1,4}.js` demonstrate that treeshaking works as expected:
diff --git a/examples/browser-rollup/example-all.html b/examples/browser-rollup/example-all.html
new file mode 100644
index 00000000..b82f17c0
--- /dev/null
+++ b/examples/browser-rollup/example-all.html
@@ -0,0 +1,9 @@
+
+
+
+ UUID esmodule webpack example
+
+
+
+
+
diff --git a/examples/browser-rollup/example-all.js b/examples/browser-rollup/example-all.js
index d63b6974..0a091bc2 100644
--- a/examples/browser-rollup/example-all.js
+++ b/examples/browser-rollup/example-all.js
@@ -1,43 +1,49 @@
import { v1 as uuidv1, v4 as uuidv4, v3 as uuidv3, v5 as uuidv5 } from 'uuid';
import * as uuid from 'uuid';
-console.log('uuidv1()', uuidv1());
-
-console.log('uuidv4()', uuidv4());
-
-// ... using predefined DNS namespace (for domain names)
-console.log('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
-
-// ... using predefined URL namespace (for, well, URLs)
-console.log('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
-
-// ... using a custom namespace
-//
-// Note: Custom namespaces should be a UUID string specific to your application!
-// E.g. the one here was generated using this modules `uuid` CLI.
-const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
-console.log('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
-
-// ... using predefined DNS namespace (for domain names)
-console.log('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
-
-// ... using predefined URL namespace (for, well, URLs)
-console.log('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
-
-// ... using a custom namespace
-//
-// Note: Custom namespaces should be a UUID string specific to your application!
-// E.g. the one here was generated using this modules `uuid` CLI.
-// const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
-console.log('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
-
-console.log('Same with default export');
-
-console.log('uuid.v1()', uuid.v1());
-console.log('uuid.v4()', uuid.v4());
-console.log('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
-console.log('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
-console.log('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
-console.log('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
-console.log('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
-console.log('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
+import testpage from '../utils/testpage';
+
+testpage(function(addTest, done) {
+ addTest('uuidv1()', uuidv1());
+
+ addTest('uuidv4()', uuidv4());
+
+ // ... using predefined DNS namespace (for domain names)
+ addTest('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
+
+ // ... using predefined URL namespace (for, well, URLs)
+ addTest('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
+
+ // ... using a custom namespace
+ //
+ // Note: Custom namespaces should be a UUID string specific to your application!
+ // E.g. the one here was generated using this modules `uuid` CLI.
+ const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
+ addTest('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
+
+ // ... using predefined DNS namespace (for domain names)
+ addTest('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
+
+ // ... using predefined URL namespace (for, well, URLs)
+ addTest('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
+
+ // ... using a custom namespace
+ //
+ // Note: Custom namespaces should be a UUID string specific to your application!
+ // E.g. the one here was generated using this modules `uuid` CLI.
+ // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
+ addTest('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
+
+ addTest('Same with default export');
+
+ addTest('uuid.v1()', uuid.v1());
+ addTest('uuid.v4()', uuid.v4());
+ addTest('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
+ addTest('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
+ addTest('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
+ addTest('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
+ addTest('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
+ addTest('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
+
+ done();
+});
diff --git a/examples/browser-rollup/example-v1.html b/examples/browser-rollup/example-v1.html
new file mode 100644
index 00000000..43c23162
--- /dev/null
+++ b/examples/browser-rollup/example-v1.html
@@ -0,0 +1,9 @@
+
+
+
+ UUID esmodule webpack example
+
+
+
+
+
diff --git a/examples/browser-rollup/example-v1.js b/examples/browser-rollup/example-v1.js
index 8e6206f5..2ea885ce 100644
--- a/examples/browser-rollup/example-v1.js
+++ b/examples/browser-rollup/example-v1.js
@@ -1,3 +1,8 @@
import { v1 as uuidv1 } from 'uuid';
-console.log('uuidv1()', uuidv1());
+import testpage from '../utils/testpage';
+
+testpage(function(addTest, done) {
+ addTest('uuidv1()', uuidv1());
+ done();
+});
diff --git a/examples/browser-rollup/example-v4.html b/examples/browser-rollup/example-v4.html
new file mode 100644
index 00000000..cc6d057a
--- /dev/null
+++ b/examples/browser-rollup/example-v4.html
@@ -0,0 +1,9 @@
+
+
+
+ UUID esmodule webpack example
+
+
+
+
+
diff --git a/examples/browser-rollup/example-v4.js b/examples/browser-rollup/example-v4.js
index 100be24b..833724ef 100644
--- a/examples/browser-rollup/example-v4.js
+++ b/examples/browser-rollup/example-v4.js
@@ -1,3 +1,8 @@
import { v4 as uuidv4 } from 'uuid';
-console.log('uuidv4()', uuidv4());
+import testpage from '../utils/testpage';
+
+testpage(function(addTest, done) {
+ addTest('uuidv4()', uuidv4());
+ done();
+});
diff --git a/examples/browser-rollup/package-lock.json b/examples/browser-rollup/package-lock.json
index ac174bc3..bbf6f5f8 100644
--- a/examples/browser-rollup/package-lock.json
+++ b/examples/browser-rollup/package-lock.json
@@ -98,8 +98,7 @@
}
},
"uuid": {
- "version": "github:ctavan/uuid-esm#8b1920cb00b55f72924888766df03b37b7f05a2d",
- "from": "github:ctavan/uuid-esm#master"
+ "version": "file:../../dist"
}
}
}
diff --git a/examples/browser-rollup/package.json b/examples/browser-rollup/package.json
index 2da786f2..ab40984a 100644
--- a/examples/browser-rollup/package.json
+++ b/examples/browser-rollup/package.json
@@ -3,10 +3,11 @@
"version": "0.0.0",
"private": true,
"scripts": {
- "test": "rm -rf dist && rollup -c && npx http-server . -o"
+ "build": "rm -rf dist && rollup -c",
+ "start": "npm run build && npx http-server . -o"
},
"dependencies": {
- "uuid": "github:ctavan/uuid-esm#master"
+ "uuid": "file:../../dist"
},
"devDependencies": {
"rollup": "^1.24.0",
diff --git a/examples/browser-webpack/README.md b/examples/browser-webpack/README.md
index 10bb98e9..ed445a00 100644
--- a/examples/browser-webpack/README.md
+++ b/examples/browser-webpack/README.md
@@ -2,10 +2,10 @@
```
npm install
-npm test
+npm start
```
-Then navigate to `example.html`.
+Then navigate to `example-*.html`.
The `example-v{1,4}.js` demonstrate that treeshaking works as expected (webpack output below):
diff --git a/examples/browser-webpack/example-all.html b/examples/browser-webpack/example-all.html
new file mode 100644
index 00000000..b82f17c0
--- /dev/null
+++ b/examples/browser-webpack/example-all.html
@@ -0,0 +1,9 @@
+
+
+
+ UUID esmodule webpack example
+
+
+
+
+
diff --git a/examples/browser-webpack/example-all.js b/examples/browser-webpack/example-all.js
index d63b6974..0a091bc2 100644
--- a/examples/browser-webpack/example-all.js
+++ b/examples/browser-webpack/example-all.js
@@ -1,43 +1,49 @@
import { v1 as uuidv1, v4 as uuidv4, v3 as uuidv3, v5 as uuidv5 } from 'uuid';
import * as uuid from 'uuid';
-console.log('uuidv1()', uuidv1());
-
-console.log('uuidv4()', uuidv4());
-
-// ... using predefined DNS namespace (for domain names)
-console.log('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
-
-// ... using predefined URL namespace (for, well, URLs)
-console.log('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
-
-// ... using a custom namespace
-//
-// Note: Custom namespaces should be a UUID string specific to your application!
-// E.g. the one here was generated using this modules `uuid` CLI.
-const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
-console.log('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
-
-// ... using predefined DNS namespace (for domain names)
-console.log('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
-
-// ... using predefined URL namespace (for, well, URLs)
-console.log('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
-
-// ... using a custom namespace
-//
-// Note: Custom namespaces should be a UUID string specific to your application!
-// E.g. the one here was generated using this modules `uuid` CLI.
-// const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
-console.log('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
-
-console.log('Same with default export');
-
-console.log('uuid.v1()', uuid.v1());
-console.log('uuid.v4()', uuid.v4());
-console.log('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
-console.log('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
-console.log('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
-console.log('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
-console.log('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
-console.log('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
+import testpage from '../utils/testpage';
+
+testpage(function(addTest, done) {
+ addTest('uuidv1()', uuidv1());
+
+ addTest('uuidv4()', uuidv4());
+
+ // ... using predefined DNS namespace (for domain names)
+ addTest('uuidv3() DNS', uuidv3('hello.example.com', uuidv3.DNS));
+
+ // ... using predefined URL namespace (for, well, URLs)
+ addTest('uuidv3() URL', uuidv3('http://example.com/hello', uuidv3.URL));
+
+ // ... using a custom namespace
+ //
+ // Note: Custom namespaces should be a UUID string specific to your application!
+ // E.g. the one here was generated using this modules `uuid` CLI.
+ const MY_NAMESPACE = '55238d15-c926-4598-b49d-cf4e913ba13c';
+ addTest('uuidv3() MY_NAMESPACE', uuidv3('Hello, World!', MY_NAMESPACE));
+
+ // ... using predefined DNS namespace (for domain names)
+ addTest('uuidv5() DNS', uuidv5('hello.example.com', uuidv5.DNS));
+
+ // ... using predefined URL namespace (for, well, URLs)
+ addTest('uuidv5() URL', uuidv5('http://example.com/hello', uuidv5.URL));
+
+ // ... using a custom namespace
+ //
+ // Note: Custom namespaces should be a UUID string specific to your application!
+ // E.g. the one here was generated using this modules `uuid` CLI.
+ // const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
+ addTest('uuidv5() MY_NAMESPACE', uuidv5('Hello, World!', MY_NAMESPACE));
+
+ addTest('Same with default export');
+
+ addTest('uuid.v1()', uuid.v1());
+ addTest('uuid.v4()', uuid.v4());
+ addTest('uuid.v3() DNS', uuid.v3('hello.example.com', uuid.v3.DNS));
+ addTest('uuid.v3() URL', uuid.v3('http://example.com/hello', uuid.v3.URL));
+ addTest('uuid.v3() MY_NAMESPACE', uuid.v3('Hello, World!', MY_NAMESPACE));
+ addTest('uuid.v5() DNS', uuid.v5('hello.example.com', uuid.v5.DNS));
+ addTest('uuid.v5() URL', uuid.v5('http://example.com/hello', uuid.v5.URL));
+ addTest('uuid.v5() MY_NAMESPACE', uuid.v5('Hello, World!', MY_NAMESPACE));
+
+ done();
+});
diff --git a/examples/browser-webpack/example-v1.html b/examples/browser-webpack/example-v1.html
new file mode 100644
index 00000000..43c23162
--- /dev/null
+++ b/examples/browser-webpack/example-v1.html
@@ -0,0 +1,9 @@
+
+
+
+ UUID esmodule webpack example
+
+
+
+
+
diff --git a/examples/browser-webpack/example-v1.js b/examples/browser-webpack/example-v1.js
index 8e6206f5..95e648df 100644
--- a/examples/browser-webpack/example-v1.js
+++ b/examples/browser-webpack/example-v1.js
@@ -1,3 +1,9 @@
import { v1 as uuidv1 } from 'uuid';
-console.log('uuidv1()', uuidv1());
+import testpage from '../utils/testpage';
+
+testpage(function(addTest, done) {
+ addTest('uuidv1()', uuidv1());
+
+ done();
+});
diff --git a/examples/browser-webpack/example-v4.html b/examples/browser-webpack/example-v4.html
new file mode 100644
index 00000000..cc6d057a
--- /dev/null
+++ b/examples/browser-webpack/example-v4.html
@@ -0,0 +1,9 @@
+
+
+
+ UUID esmodule webpack example
+
+
+
+
+
diff --git a/examples/browser-webpack/example-v4.js b/examples/browser-webpack/example-v4.js
index 100be24b..b43ed203 100644
--- a/examples/browser-webpack/example-v4.js
+++ b/examples/browser-webpack/example-v4.js
@@ -1,3 +1,9 @@
import { v4 as uuidv4 } from 'uuid';
-console.log('uuidv4()', uuidv4());
+import testpage from '../utils/testpage';
+
+testpage(function(addTest, done) {
+ addTest('uuidv4()', uuidv4());
+
+ done();
+});
diff --git a/examples/browser-webpack/package-lock.json b/examples/browser-webpack/package-lock.json
index 7ac8cdbe..00ec4ae3 100644
--- a/examples/browser-webpack/package-lock.json
+++ b/examples/browser-webpack/package-lock.json
@@ -3868,8 +3868,7 @@
"dev": true
},
"uuid": {
- "version": "github:ctavan/uuid-esm#d93bfcbfc22bfef4c5f021e855f8ceafc08d8f80",
- "from": "github:ctavan/uuid-esm#master"
+ "version": "file:../../dist"
},
"v8-compile-cache": {
"version": "2.0.3",
diff --git a/examples/browser-webpack/package.json b/examples/browser-webpack/package.json
index 58fb29cf..82f360e0 100644
--- a/examples/browser-webpack/package.json
+++ b/examples/browser-webpack/package.json
@@ -3,10 +3,11 @@
"version": "0.0.0",
"private": true,
"scripts": {
- "test": "rm -rf dist && webpack && npx http-server . -o"
+ "build": "rm -rf dist && webpack",
+ "start": "npm run build && npx http-server . -o"
},
"dependencies": {
- "uuid": "github:ctavan/uuid-esm#master"
+ "uuid": "file:../../dist"
},
"devDependencies": {
"webpack": "^4.40.2",
diff --git a/examples/browser-webpack/webpack.config.js b/examples/browser-webpack/webpack.config.js
index 8ce81b4d..d1711b25 100644
--- a/examples/browser-webpack/webpack.config.js
+++ b/examples/browser-webpack/webpack.config.js
@@ -1,4 +1,7 @@
module.exports = {
+ resolve: {
+ extensions: ['*', '.js'],
+ },
entry: {
all: './example-all.js',
v1: './example-v1.js',
diff --git a/examples/node-commonjs/package-lock.json b/examples/node-commonjs/package-lock.json
index c48e72fa..1c363b84 100644
--- a/examples/node-commonjs/package-lock.json
+++ b/examples/node-commonjs/package-lock.json
@@ -5,8 +5,7 @@
"requires": true,
"dependencies": {
"uuid": {
- "version": "github:ctavan/uuid-esm#4d60b66275298da97903e39b0b1e0114f40b1a07",
- "from": "github:ctavan/uuid-esm#master"
+ "version": "file:../../dist"
}
}
}
diff --git a/examples/node-commonjs/package.json b/examples/node-commonjs/package.json
index e4c69602..cd70d89e 100644
--- a/examples/node-commonjs/package.json
+++ b/examples/node-commonjs/package.json
@@ -6,6 +6,6 @@
"test": "node example.js"
},
"dependencies": {
- "uuid": "github:ctavan/uuid-esm#master"
+ "uuid": "file:../../dist"
}
}
diff --git a/examples/utils/testpage.js b/examples/utils/testpage.js
new file mode 100644
index 00000000..245c52f3
--- /dev/null
+++ b/examples/utils/testpage.js
@@ -0,0 +1,28 @@
+export default function test(callback) {
+ const ul = document.createElement('ul');
+ document.body.appendChild(ul);
+
+ function addTest(title, result) {
+ const li = document.createElement('li');
+
+ const h2 = document.createElement('h2');
+ h2.innerHTML = title;
+ li.appendChild(h2);
+
+ const p = document.createElement('p');
+ p.innerHTML = result;
+ li.appendChild(p);
+
+ ul.appendChild(li);
+ }
+
+ function done() {
+ const div = document.createElement('div');
+ div.id = 'done';
+ document.body.appendChild(div);
+ }
+
+ window.onload = function() {
+ callback(addTest, done);
+ };
+}
diff --git a/package-lock.json b/package-lock.json
index 253e354a..23415aa8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1728,6 +1728,15 @@
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==",
"dev": true
},
+ "agent-base": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+ "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+ "dev": true,
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ },
"aggregate-error": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
@@ -1896,6 +1905,15 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true
},
+ "async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
"async-each": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
@@ -2165,6 +2183,12 @@
}
}
},
+ "basic-auth": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
+ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=",
+ "dev": true
+ },
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
@@ -2254,6 +2278,18 @@
"node-releases": "^1.1.29"
}
},
+ "browserstack-local": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.2.tgz",
+ "integrity": "sha512-fRaynjF0MvtyyfPRy2NFnVwxLyNtD28K/v9xRsIjUVf7xLc80NIm7Nfr3KXlFmWizhG91PL/UAOXlHkoxQjaNw==",
+ "dev": true,
+ "requires": {
+ "https-proxy-agent": "^2.2.1",
+ "is-running": "^2.0.0",
+ "ps-tree": "=1.1.1",
+ "temp-fs": "^0.9.9"
+ }
+ },
"bser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
@@ -2596,6 +2632,12 @@
"integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=",
"dev": true
},
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true
+ },
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -3145,6 +3187,12 @@
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
+ "corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=",
+ "dev": true
+ },
"cosmiconfig": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
@@ -3523,6 +3571,12 @@
}
}
},
+ "duplexer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
+ "dev": true
+ },
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -3533,6 +3587,18 @@
"safer-buffer": "^2.1.0"
}
},
+ "ecstatic": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz",
+ "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==",
+ "dev": true,
+ "requires": {
+ "he": "^1.1.1",
+ "mime": "^1.6.0",
+ "minimist": "^1.1.0",
+ "url-join": "^2.0.5"
+ }
+ },
"electron-to-chromium": {
"version": "1.3.282",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.282.tgz",
@@ -3598,6 +3664,21 @@
"is-symbol": "^1.0.2"
}
},
+ "es6-promise": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+ "dev": true
+ },
+ "es6-promisify": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+ "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+ "dev": true,
+ "requires": {
+ "es6-promise": "^4.0.3"
+ }
+ },
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -3797,6 +3878,38 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
+ "event-stream": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+ "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
+ "dev": true,
+ "requires": {
+ "duplexer": "~0.1.1",
+ "from": "~0",
+ "map-stream": "~0.1.0",
+ "pause-stream": "0.0.11",
+ "split": "0.3",
+ "stream-combiner": "~0.0.4",
+ "through": "~2.3.1"
+ },
+ "dependencies": {
+ "split": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+ "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
+ "dev": true,
+ "requires": {
+ "through": "2"
+ }
+ }
+ }
+ },
+ "eventemitter3": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
+ "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==",
+ "dev": true
+ },
"exec-sh": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz",
@@ -4175,6 +4288,26 @@
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
"dev": true
},
+ "follow-redirects": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz",
+ "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==",
+ "dev": true,
+ "requires": {
+ "debug": "^3.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -4207,6 +4340,12 @@
"map-cache": "^0.2.2"
}
},
+ "from": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+ "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=",
+ "dev": true
+ },
"fs-access": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz",
@@ -5285,6 +5424,12 @@
}
}
},
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
"hosted-git-info": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz",
@@ -5300,6 +5445,35 @@
"whatwg-encoding": "^1.0.1"
}
},
+ "http-proxy": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz",
+ "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "http-server": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.0.tgz",
+ "integrity": "sha512-imGLDSTT1BZ0QG1rBFnaZ6weK5jeisUnCxZQI1cpYTdz0luPUM5e3s+WU5zRWEkiI6DQxL2p54oeKrDlzO6bRw==",
+ "dev": true,
+ "requires": {
+ "basic-auth": "^1.0.3",
+ "colors": "^1.3.3",
+ "corser": "^2.0.1",
+ "ecstatic": "^3.3.2",
+ "http-proxy": "^1.17.0",
+ "opener": "^1.5.1",
+ "optimist": "~0.6.1",
+ "portfinder": "^1.0.20",
+ "secure-compare": "3.0.1",
+ "union": "~0.5.0"
+ }
+ },
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@@ -5311,6 +5485,27 @@
"sshpk": "^1.7.0"
}
},
+ "https-proxy-agent": {
+ "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",
+ "debug": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
"husky": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/husky/-/husky-3.0.9.tgz",
@@ -5394,6 +5589,12 @@
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"dev": true
},
+ "immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=",
+ "dev": true
+ },
"import-fresh": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz",
@@ -5823,6 +6024,12 @@
"integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
"dev": true
},
+ "is-running": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz",
+ "integrity": "sha1-MKc/9cw4VOT8JUkICen1q/jeCeA=",
+ "dev": true
+ },
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
@@ -6612,6 +6819,18 @@
"verror": "1.10.0"
}
},
+ "jszip": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.2.tgz",
+ "integrity": "sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==",
+ "dev": true,
+ "requires": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "set-immediate-shim": "~1.0.1"
+ }
+ },
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
@@ -6646,6 +6865,15 @@
"type-check": "~0.3.2"
}
},
+ "lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "dev": true,
+ "requires": {
+ "immediate": "~3.0.5"
+ }
+ },
"lines-and-columns": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
@@ -7149,6 +7377,12 @@
"integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=",
"dev": true
},
+ "map-stream": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+ "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=",
+ "dev": true
+ },
"map-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
@@ -7158,6 +7392,12 @@
"object-visit": "^1.0.0"
}
},
+ "memorystream": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
+ "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
+ "dev": true
+ },
"meow": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz",
@@ -7208,6 +7448,12 @@
"to-regex": "^3.0.2"
}
},
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true
+ },
"mime-db": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
@@ -7414,6 +7660,36 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
+ "npm-run-all": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
+ "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "chalk": "^2.4.1",
+ "cross-spawn": "^6.0.5",
+ "memorystream": "^0.3.1",
+ "minimatch": "^3.0.4",
+ "pidtree": "^0.3.0",
+ "read-pkg": "^3.0.0",
+ "shell-quote": "^1.6.1",
+ "string.prototype.padend": "^3.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -7566,6 +7842,12 @@
"integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==",
"dev": true
},
+ "opener": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz",
+ "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==",
+ "dev": true
+ },
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
@@ -7675,6 +7957,12 @@
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
"dev": true
},
+ "pako": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
+ "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==",
+ "dev": true
+ },
"parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -7760,6 +8048,15 @@
"pify": "^3.0.0"
}
},
+ "pause-stream": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+ "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
+ "dev": true,
+ "requires": {
+ "through": "~2.3"
+ }
+ },
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -7772,6 +8069,12 @@
"integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==",
"dev": true
},
+ "pidtree": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz",
+ "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==",
+ "dev": true
+ },
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@@ -7877,6 +8180,28 @@
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
"dev": true
},
+ "portfinder": {
+ "version": "1.0.25",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz",
+ "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==",
+ "dev": true,
+ "requires": {
+ "async": "^2.6.2",
+ "debug": "^3.1.1",
+ "mkdirp": "^0.5.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ }
+ }
+ },
"posix-character-classes": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@@ -7952,6 +8277,15 @@
"sisteransi": "^1.0.3"
}
},
+ "ps-tree": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.1.tgz",
+ "integrity": "sha512-kef7fYYSKVqQffmzTMsVcUD1ObNJMp8sNSmHGlGKsZQyL/ht9MZKk86u0Rd1NhpTOAuhqwKCLLpktwkqz+MF8A==",
+ "dev": true,
+ "requires": {
+ "event-stream": "=3.3.4"
+ }
+ },
"psl": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz",
@@ -8259,6 +8593,12 @@
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
"resolve": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
@@ -8427,6 +8767,35 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true
},
+ "secure-compare": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
+ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=",
+ "dev": true
+ },
+ "selenium-webdriver": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz",
+ "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==",
+ "dev": true,
+ "requires": {
+ "jszip": "^3.1.3",
+ "rimraf": "^2.5.4",
+ "tmp": "0.0.30",
+ "xml2js": "^0.4.17"
+ },
+ "dependencies": {
+ "tmp": {
+ "version": "0.0.30",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
+ "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.1"
+ }
+ }
+ }
+ },
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
@@ -8445,6 +8814,12 @@
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true
},
+ "set-immediate-shim": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
+ "dev": true
+ },
"set-value": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
@@ -8483,6 +8858,12 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
+ "shell-quote": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
+ "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
+ "dev": true
+ },
"shellwords": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
@@ -9010,6 +9391,15 @@
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
"dev": true
},
+ "stream-combiner": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+ "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=",
+ "dev": true,
+ "requires": {
+ "duplexer": "~0.1.1"
+ }
+ },
"string-argv": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
@@ -9036,6 +9426,17 @@
"strip-ansi": "^4.0.0"
}
},
+ "string.prototype.padend": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz",
+ "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.4.3",
+ "function-bind": "^1.0.2"
+ }
+ },
"string.prototype.trimleft": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz",
@@ -9182,6 +9583,26 @@
}
}
},
+ "temp-fs": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz",
+ "integrity": "sha1-gHFzBDeHByDpQxUy/igUNk+IA9c=",
+ "dev": true,
+ "requires": {
+ "rimraf": "~2.5.2"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.5.4",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz",
+ "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=",
+ "dev": true,
+ "requires": {
+ "glob": "^7.0.5"
+ }
+ }
+ }
+ },
"test-exclude": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz",
@@ -9479,6 +9900,15 @@
"integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==",
"dev": true
},
+ "union": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
+ "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
+ "dev": true,
+ "requires": {
+ "qs": "^6.4.0"
+ }
+ },
"union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@@ -9553,6 +9983,12 @@
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
"dev": true
},
+ "url-join": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
+ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
+ "dev": true
+ },
"use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
@@ -9759,6 +10195,23 @@
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
"dev": true
},
+ "xml2js": {
+ "version": "0.4.22",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz",
+ "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==",
+ "dev": true,
+ "requires": {
+ "sax": ">=0.6.0",
+ "util.promisify": "~1.0.0",
+ "xmlbuilder": "~11.0.0"
+ }
+ },
+ "xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "dev": true
+ },
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
diff --git a/package.json b/package.json
index 22e0cc68..7740897a 100644
--- a/package.json
+++ b/package.json
@@ -27,22 +27,31 @@
"@commitlint/config-conventional": "~8.2.0",
"babel-eslint": "~10.0.3",
"babel-plugin-add-module-exports": "~1.0.2",
+ "browserstack-local": "~1.4.2",
"eslint": "~6.4.0",
"eslint-config-prettier": "~6.4.0",
"eslint-plugin-prettier": "~3.1.1",
"esm": "~3.2.25",
+ "http-server": "~0.12.0",
"husky": "~3.0.9",
"jest": "~24.9.0",
"lint-staged": "~9.4.3",
+ "npm-run-all": "~4.1.5",
"prettier": "~1.18.2",
"runmd": "1.2.1",
+ "selenium-webdriver": "~3.6.0",
"standard-version": "7.0.0"
},
"scripts": {
+ "examples:browser-webpack:build": "cd examples/browser-webpack && npm install && npm run build",
+ "examples:browser-rollup:build": "cd examples/browser-rollup && npm install && npm run build",
+ "examples:browser-esmodules:build": "cd examples/browser-esmodules && npm install && npm run build",
"lint": "npm run eslint:check && npm run prettier:check",
"eslint:check": "eslint src/ test/ examples/ *.js",
"eslint:fix": "eslint --fix src/ test/ examples/ *.js",
- "test": "BABEL_ENV=commonjs jest test/",
+ "test": "BABEL_ENV=commonjs jest test/unit/",
+ "pretest:browser": "npm run package && npm-run-all --parallel examples:**",
+ "test:browser": "BABEL_ENV=commonjs jest --forceExit --verbose test/browser/${BROWSER:-}*",
"prettier:check": "prettier --ignore-path .prettierignore --check '**/*.{js,jsx,json,md}'",
"prettier:fix": "prettier --ignore-path .prettierignore --write '**/*.{js,jsx,json,md}'",
"ci": "npm run lint && npm run test && npm run prettier:check && npm run docs:diff",
diff --git a/test/browser/browser-test.js b/test/browser/browser-test.js
new file mode 100644
index 00000000..0263795c
--- /dev/null
+++ b/test/browser/browser-test.js
@@ -0,0 +1,167 @@
+/* eslint-disable no-restricted-globals, camelcase */
+const { Builder, By, until } = require('selenium-webdriver');
+const browserstack = require('browserstack-local');
+const httpServer = require('http-server');
+
+const v1Regex = new RegExp(
+ /^[0-9A-F]{8}-[0-9A-F]{4}-1[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
+);
+const v4Regex = new RegExp(
+ /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
+);
+
+const v1 = (result) => expect(result).toMatch(v1Regex);
+const v4 = (result) => expect(result).toMatch(v4Regex);
+const v3dns = (result) => expect(result).toBe('9125a8dc-52ee-365b-a5aa-81b0b3681cf6');
+const v3url = (result) => expect(result).toBe('c6235813-3ba4-3801-ae84-e0a6ebb7d138');
+const v3custom = (result) => expect(result).toBe('f5a52d34-dcd7-30f7-b581-0112fab43d0c');
+const v5dns = (result) => expect(result).toBe('fdda765f-fc57-5604-a269-52a7df8164ec');
+const v5url = (result) => expect(result).toBe('3bbcee75-cecc-5b56-8031-b6641c1ed1f1');
+const v5custom = (result) => expect(result).toBe('c49c5142-4d9a-5940-a926-612ede0ec632');
+const ignore = (result) => true;
+
+const expectations = {
+ 'uuidv1()': v1,
+ 'uuidv4()': v4,
+ 'uuidv3() DNS': v3dns,
+ 'uuidv3() URL': v3url,
+ 'uuidv3() MY_NAMESPACE': v3custom,
+ 'uuidv5() DNS': v5dns,
+ 'uuidv5() URL': v5url,
+ 'uuidv5() MY_NAMESPACE': v5custom,
+ 'Same with default export': ignore,
+ 'uuid.v1()': v1,
+ 'uuid.v4()': v4,
+ 'uuid.v3() DNS': v3dns,
+ 'uuid.v3() URL': v3url,
+ 'uuid.v3() MY_NAMESPACE': v3custom,
+ 'uuid.v5() DNS': v5dns,
+ 'uuid.v5() URL': v5url,
+ 'uuid.v5() MY_NAMESPACE': v5custom,
+};
+const expectationTitles = Object.keys(expectations);
+
+const PROJECT = process.env.GITHUB_REPOSITORY || 'node-uuid';
+const GITHUB_SHA = process.env.GITHUB_SHA || '';
+const GITHUB_REF = process.env.GITHUB_REF || '';
+const BUILD = GITHUB_SHA || GITHUB_REF ? `${GITHUB_REF} ${GITHUB_SHA}` : 'manual build';
+
+module.exports = function(localIdentifier, PORT, capabilityMatrix) {
+ describe(`browser ${localIdentifier}`, () => {
+ jest.setTimeout(180000);
+
+ let server;
+ beforeAll((done) => {
+ server = httpServer.createServer({
+ root: `${__dirname}/../../examples`,
+ });
+ server.listen(PORT, '0.0.0.0', done);
+ });
+
+ let bsLocal;
+ beforeAll((done) => {
+ bsLocal = new browserstack.Local();
+ bsLocal.start(
+ {
+ key: process.env.BROWSERSTACK_ACCESS_KEY,
+ onlyAutomate: 'true',
+ verbose: 'true',
+ localIdentifier,
+ },
+ done,
+ );
+ });
+
+ afterAll((done) => {
+ bsLocal.stop(done);
+ });
+
+ afterAll(() => {
+ server.close();
+ });
+
+ capabilityMatrix.forEach((additionalCapabilities) => {
+ describe(Object.values(additionalCapabilities).join(' '), () => {
+ let browser;
+ beforeAll(async () => {
+ var capabilities = {
+ resolution: '1024x768',
+ 'browserstack.user': process.env.BROWSERSTACK_USER,
+ 'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY,
+ 'browserstack.local': true,
+ 'browserstack.localIdentifier': localIdentifier,
+ project: PROJECT,
+ build: BUILD,
+ name: 'browser test',
+ ...additionalCapabilities,
+ };
+ browser = await new Builder()
+ .usingServer('http://hub-cloud.browserstack.com/wd/hub')
+ .withCapabilities(capabilities)
+ .build();
+ });
+ afterAll(async () => {
+ try {
+ await browser.close();
+ } catch (error) {}
+ try {
+ await browser.quit();
+ } catch (error) {}
+ });
+
+ async function testExpectations(path, titleFilter) {
+ const url = `http://127.0.0.1:${PORT}/${path}`;
+ await browser.get(url);
+ await browser.wait(until.elementLocated(By.id('done')), 30000);
+ const elements = await browser.findElements(By.css('li'));
+
+ // Unfortunately the WebDriver API is not thread safe and we cannot use Promise.all() to
+ // query it in parallel:
+ // https://github.com/SeleniumHQ/selenium/issues/422#issuecomment-90629726
+ const titles = [];
+ for (let i = 0; i < elements.length; i++) {
+ const element = elements[i];
+ const h2 = await element.findElement(By.css('h2'));
+ const title = await h2.getText();
+ const p = await element.findElement(By.css('p'));
+ const result = await p.getText();
+ expectations[title](result);
+ titles.push(title);
+ }
+
+ expect(titles).toEqual(expectationTitles.filter(titleFilter));
+ }
+
+ describe('webpack', () => {
+ test('it renders all', async () =>
+ testExpectations('browser-webpack/example-all.html', () => true));
+
+ test('it renders v1 only', async () =>
+ testExpectations('browser-webpack/example-v1.html', (title) =>
+ title.includes('uuidv1'),
+ ));
+
+ test('it renders v4 only', async () =>
+ testExpectations('browser-webpack/example-v4.html', (title) =>
+ title.includes('uuidv4'),
+ ));
+ });
+
+ describe('rollup', () => {
+ test('it renders all', async () =>
+ testExpectations('browser-rollup/example-all.html', () => true));
+
+ test('it renders v1 only', async () =>
+ testExpectations('browser-rollup/example-v1.html', (title) =>
+ title.includes('uuidv1'),
+ ));
+
+ test('it renders v4 only', async () =>
+ testExpectations('browser-rollup/example-v4.html', (title) =>
+ title.includes('uuidv4'),
+ ));
+ });
+ });
+ });
+ });
+};
diff --git a/test/browser/chrome.test.js b/test/browser/chrome.test.js
new file mode 100644
index 00000000..94115c3b
--- /dev/null
+++ b/test/browser/chrome.test.js
@@ -0,0 +1,17 @@
+/* eslint-disable no-restricted-globals, camelcase */
+const browserTest = require('./browser-test');
+
+browserTest('chrome', 9000, [
+ {
+ browserName: 'Chrome',
+ browser_version: '79.0',
+ os: 'Windows',
+ os_version: '10',
+ },
+ {
+ browserName: 'Chrome',
+ browser_version: '49.0',
+ os: 'Windows',
+ os_version: '10',
+ },
+]);
diff --git a/test/browser/edge.test.js b/test/browser/edge.test.js
new file mode 100644
index 00000000..7c9a5bdf
--- /dev/null
+++ b/test/browser/edge.test.js
@@ -0,0 +1,23 @@
+/* eslint-disable no-restricted-globals, camelcase */
+const browserTest = require('./browser-test');
+
+browserTest('edge', 9001, [
+ {
+ browserName: 'Edge',
+ browser_version: '79.0 beta',
+ os: 'Windows',
+ os_version: '10',
+ },
+ {
+ browserName: 'Edge',
+ browser_version: '18.0',
+ os: 'Windows',
+ os_version: '10',
+ },
+ {
+ browserName: 'Edge',
+ browser_version: '15.0',
+ os: 'Windows',
+ os_version: '10',
+ },
+]);
diff --git a/test/browser/firefox.test.js b/test/browser/firefox.test.js
new file mode 100644
index 00000000..d417fc7c
--- /dev/null
+++ b/test/browser/firefox.test.js
@@ -0,0 +1,17 @@
+/* eslint-disable no-restricted-globals, camelcase */
+const browserTest = require('./browser-test');
+
+browserTest('firefox', 9002, [
+ {
+ browserName: 'Firefox',
+ browser_version: '70.0',
+ os: 'Windows',
+ os_version: '10',
+ },
+ {
+ browserName: 'Firefox',
+ browser_version: '44.0',
+ os: 'Windows',
+ os_version: '10',
+ },
+]);
diff --git a/test/browser/ie.test.js b/test/browser/ie.test.js
new file mode 100644
index 00000000..aba68721
--- /dev/null
+++ b/test/browser/ie.test.js
@@ -0,0 +1,17 @@
+/* eslint-disable no-restricted-globals, camelcase */
+const browserTest = require('./browser-test');
+
+browserTest('ie', 9003, [
+ {
+ browserName: 'IE',
+ browser_version: '11.0',
+ os: 'Windows',
+ os_version: '10',
+ },
+ {
+ browserName: 'IE',
+ browser_version: '11.0',
+ os: 'Windows',
+ os_version: '7',
+ },
+]);
diff --git a/test/browser/safari.test.js b/test/browser/safari.test.js
new file mode 100644
index 00000000..90ec0ca0
--- /dev/null
+++ b/test/browser/safari.test.js
@@ -0,0 +1,17 @@
+/* eslint-disable no-restricted-globals, camelcase */
+const browserTest = require('./browser-test');
+
+browserTest('safari', 9004, [
+ {
+ browserName: 'Safari',
+ browser_version: '13.0',
+ os: 'OS X',
+ os_version: 'Catalina',
+ },
+ {
+ browserName: 'Safari',
+ browser_version: '10.0',
+ os: 'OS X',
+ os_version: 'Sierra',
+ },
+]);
diff --git a/test/test.js b/test/unit/unit.test.js
similarity index 95%
rename from test/test.js
rename to test/unit/unit.test.js
index d6518ac8..c5b0d648 100644
--- a/test/test.js
+++ b/test/unit/unit.test.js
@@ -1,13 +1,13 @@
import assert from 'assert';
-import md5 from '../src/md5.js';
-import md5Browser from '../src/md5-browser.js';
-import rng from '../src/rng.js';
-import rngBrowser from '../src/rng-browser.js';
-import sha1 from '../src/sha1.js';
-import sha1Browser from '../src/sha1-browser.js';
-import v1 from '../src/v1.js';
-import v3 from '../src/v3.js';
-import v5 from '../src/v5.js';
+import md5 from '../../src/md5.js';
+import md5Browser from '../../src/md5-browser.js';
+import rng from '../../src/rng.js';
+import rngBrowser from '../../src/rng-browser.js';
+import sha1 from '../../src/sha1.js';
+import sha1Browser from '../../src/sha1-browser.js';
+import v1 from '../../src/v1.js';
+import v3 from '../../src/v3.js';
+import v5 from '../../src/v5.js';
describe('rng', () => {
test('nodeRNG', () => {