Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8fed4e338 | ||
|
|
483973cf25 | ||
|
|
cc929f3714 | ||
|
|
5584886f0f | ||
|
|
0d2cd8b9b7 | ||
|
|
149030ddbe | ||
|
|
f08e6a6773 | ||
|
|
eed6a1dddd | ||
|
|
3b12a39ea2 | ||
|
|
591a28ed94 | ||
|
|
40f4568c95 | ||
|
|
a74fb90d95 | ||
|
|
689bee122b | ||
|
|
50b89fcdce | ||
|
|
40c6ff45df | ||
|
|
5b2bab5365 | ||
|
|
b75fb395b4 | ||
|
|
3217da9bc7 | ||
|
|
ae6b565ae6 | ||
|
|
26ca0e39b4 | ||
|
|
99388a79bb | ||
|
|
cf379d10e0 | ||
|
|
1d1faebe18 | ||
|
|
903a4c1bb0 | ||
|
|
126b4ec697 |
@@ -0,0 +1,6 @@
|
|||||||
|
coverage:
|
||||||
|
round: up
|
||||||
|
precision: 2
|
||||||
|
parsers:
|
||||||
|
javascript:
|
||||||
|
enable_partials: yes
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "**.js"
|
||||||
|
- "package.json"
|
||||||
|
- ".github/workflows/ci.yml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||||
|
node: ["15", "14", "12", engines]
|
||||||
|
exclude:
|
||||||
|
# On Windows, run tests with only the LTS environments.
|
||||||
|
- os: windows-latest
|
||||||
|
node: engines
|
||||||
|
- os: windows-latest
|
||||||
|
node: "14"
|
||||||
|
# On macOS, run tests with only the LTS environments.
|
||||||
|
- os: macOS-latest
|
||||||
|
node: engines
|
||||||
|
- os: macOS-latest
|
||||||
|
node: "14"
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get Node.JS version from package.json
|
||||||
|
if: matrix.node == 'engines'
|
||||||
|
id: get-version
|
||||||
|
run: echo ::set-output name=node::$(npx --q minimum-node-version)
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v2-beta
|
||||||
|
if: matrix.node != 'engines'
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node }}
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v2-beta
|
||||||
|
if: matrix.node == 'engines'
|
||||||
|
with:
|
||||||
|
node-version: ${{steps.get-version.outputs.node}}
|
||||||
|
|
||||||
|
- run: npm install
|
||||||
|
|
||||||
|
- run: npm run report -- --colors
|
||||||
|
|
||||||
|
- name: Upload coverage to Codecov
|
||||||
|
uses: codecov/codecov-action@v1
|
||||||
|
with:
|
||||||
|
file: ./coverage/coverage-final.json
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "**.js"
|
||||||
|
- "**eslint**"
|
||||||
|
- "package.json"
|
||||||
|
- ".github/workflows/lint.yml"
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js
|
||||||
|
uses: actions/setup-node@v2-beta
|
||||||
|
with:
|
||||||
|
node-version: 14
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run lint
|
||||||
@@ -63,3 +63,4 @@ typings/
|
|||||||
.env
|
.env
|
||||||
|
|
||||||
index.d.ts
|
index.d.ts
|
||||||
|
from.d.ts
|
||||||
|
|||||||
-13
@@ -1,13 +0,0 @@
|
|||||||
language: node_js
|
|
||||||
|
|
||||||
node_js:
|
|
||||||
- "lts/*"
|
|
||||||
- "node"
|
|
||||||
|
|
||||||
script:
|
|
||||||
- npm run lint
|
|
||||||
- npm run coverage
|
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- node_modules
|
|
||||||
@@ -1,6 +1,25 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
## next
|
||||||
|
- Fixed a bug where in BlobDataItem when the file was empty (#86)
|
||||||
|
|
||||||
|
## v2.1.2
|
||||||
|
- Fixed a bug where `start` in BlobDataItem was undefined (#85)
|
||||||
|
|
||||||
|
## v2.1.1
|
||||||
|
- Add nullish values checking in Symbol.hasInstance (#82)
|
||||||
|
- Add generated typings for from.js file (#80)
|
||||||
|
- Updated dev dependencies
|
||||||
|
|
||||||
|
## v2.1.0
|
||||||
|
- Fix: .slice has an implementation bug (#54).
|
||||||
|
- Added blob backed up by filesystem (#55)
|
||||||
|
|
||||||
|
## v2.0.1
|
||||||
|
|
||||||
|
- Fix: remove upper bound for node engine semver (#49).
|
||||||
|
|
||||||
## v2.0.0
|
## v2.0.0
|
||||||
|
|
||||||
> Note: This release was previously published as `1.0.7`, but as it contains breaking changes, we renamed it to `2.0.0`.
|
> Note: This release was previously published as `1.0.7`, but as it contains breaking changes, we renamed it to `2.0.0`.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# fetch-blob
|
# fetch-blob
|
||||||
|
|
||||||
[![npm version][npm-image]][npm-url]
|
[![npm version][npm-image]][npm-url]
|
||||||
[![build status][travis-image]][travis-url]
|
[![build status][ci-image]][ci-url]
|
||||||
[![coverage status][codecov-image]][codecov-url]
|
[![coverage status][codecov-image]][codecov-url]
|
||||||
[![install size][install-size-image]][install-size-url]
|
[![install size][install-size-image]][install-size-url]
|
||||||
|
|
||||||
@@ -27,12 +27,30 @@ fetch('https://httpbin.org/post', {
|
|||||||
.then(json => console.log(json));
|
.then(json => console.log(json));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Blob part backed up by filesystem
|
||||||
|
To use, install [domexception](https://github.com/jsdom/domexception).
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install fetch-blob domexception
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
const blobFrom = require('fetch-blob/from.js');
|
||||||
|
const blob1 = blobFrom('./2-GiB-file.bin');
|
||||||
|
const blob2 = blobFrom('./2-GiB-file.bin');
|
||||||
|
|
||||||
|
// Not a 4 GiB memory snapshot, just holds 3 references
|
||||||
|
// points to where data is located on the disk
|
||||||
|
const blob = new Blob([blob1, blob2]);
|
||||||
|
console.log(blob.size) // 4 GiB
|
||||||
|
```
|
||||||
|
|
||||||
See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and [tests](https://github.com/node-fetch/fetch-blob/blob/master/test.js) for more details.
|
See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and [tests](https://github.com/node-fetch/fetch-blob/blob/master/test.js) for more details.
|
||||||
|
|
||||||
[npm-image]: https://flat.badgen.net/npm/v/fetch-blob
|
[npm-image]: https://flat.badgen.net/npm/v/fetch-blob
|
||||||
[npm-url]: https://www.npmjs.com/package/fetch-blob
|
[npm-url]: https://www.npmjs.com/package/fetch-blob
|
||||||
[travis-image]: https://flat.badgen.net/travis/node-fetch/fetch-blob
|
[ci-image]: https://github.com/node-fetch/fetch-blob/workflows/CI/badge.svg
|
||||||
[travis-url]: https://travis-ci.org/node-fetch/fetch-blob
|
[ci-url]: https://github.com/node-fetch/fetch-blob/actions
|
||||||
[codecov-image]: https://flat.badgen.net/codecov/c/github/node-fetch/fetch-blob/master
|
[codecov-image]: https://flat.badgen.net/codecov/c/github/node-fetch/fetch-blob/master
|
||||||
[codecov-url]: https://codecov.io/gh/node-fetch/fetch-blob
|
[codecov-url]: https://codecov.io/gh/node-fetch/fetch-blob
|
||||||
[install-size-image]: https://flat.badgen.net/packagephobia/install/fetch-blob
|
[install-size-image]: https://flat.badgen.net/packagephobia/install/fetch-blob
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
const {statSync, createReadStream} = require('fs');
|
||||||
|
const Blob = require('./index.js');
|
||||||
|
const DOMException = require('domexception');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} path filepath on the disk
|
||||||
|
* @returns {Blob}
|
||||||
|
*/
|
||||||
|
function blobFrom(path) {
|
||||||
|
const {size, mtime} = statSync(path);
|
||||||
|
const blob = new BlobDataItem({path, size, mtime});
|
||||||
|
|
||||||
|
return new Blob([blob]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a blob backed up by a file on the disk
|
||||||
|
* with minium requirement
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
class BlobDataItem {
|
||||||
|
constructor(options) {
|
||||||
|
this.size = options.size;
|
||||||
|
this.path = options.path;
|
||||||
|
this.start = options.start || 0;
|
||||||
|
this.mtime = options.mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slicing arguments is first validated and formated
|
||||||
|
// to not be out of range by Blob.prototype.slice
|
||||||
|
slice(start, end) {
|
||||||
|
return new BlobDataItem({
|
||||||
|
path: this.path,
|
||||||
|
start,
|
||||||
|
mtime: this.mtime,
|
||||||
|
size: end - start
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stream() {
|
||||||
|
if (statSync(this.path).mtime > this.mtime) {
|
||||||
|
throw new DOMException('The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.', 'NotReadableError');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.size) {
|
||||||
|
return new Blob().stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createReadStream(this.path, {
|
||||||
|
start: this.start,
|
||||||
|
end: this.start + this.size - 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get [Symbol.toStringTag]() {
|
||||||
|
return 'Blob';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = blobFrom;
|
||||||
@@ -15,20 +15,6 @@ async function * read(parts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @template T
|
|
||||||
* @param {T} object
|
|
||||||
* @returns {T is Blob}
|
|
||||||
*/
|
|
||||||
const isBlob = object => {
|
|
||||||
return (
|
|
||||||
typeof object === 'object' &&
|
|
||||||
typeof object.stream === 'function' &&
|
|
||||||
typeof object.constructor === 'function' &&
|
|
||||||
/^(Blob|File)$/.test(object[Symbol.toStringTag])
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Blob {
|
class Blob {
|
||||||
/**
|
/**
|
||||||
* The Blob() constructor returns a new Blob object. The content
|
* The Blob() constructor returns a new Blob object. The content
|
||||||
@@ -38,23 +24,24 @@ class Blob {
|
|||||||
* @param {(ArrayBufferLike | ArrayBufferView | Blob | Buffer | string)[]} blobParts
|
* @param {(ArrayBufferLike | ArrayBufferView | Blob | Buffer | string)[]} blobParts
|
||||||
* @param {{ type?: string }} [options]
|
* @param {{ type?: string }} [options]
|
||||||
*/
|
*/
|
||||||
constructor(blobParts = [], options = {type: ''}) {
|
constructor(blobParts = [], options = {}) {
|
||||||
let size = 0;
|
let size = 0;
|
||||||
|
|
||||||
const parts = blobParts.map(element => {
|
const parts = blobParts.map(element => {
|
||||||
let buffer;
|
let buffer;
|
||||||
if (Buffer.isBuffer(element)) {
|
if (element instanceof Buffer) {
|
||||||
buffer = element;
|
buffer = element;
|
||||||
} else if (ArrayBuffer.isView(element)) {
|
} else if (ArrayBuffer.isView(element)) {
|
||||||
buffer = Buffer.from(element.buffer, element.byteOffset, element.byteLength);
|
buffer = Buffer.from(element.buffer, element.byteOffset, element.byteLength);
|
||||||
} else if (element instanceof ArrayBuffer) {
|
} else if (element instanceof ArrayBuffer) {
|
||||||
buffer = Buffer.from(element);
|
buffer = Buffer.from(element);
|
||||||
} else if (isBlob(element)) {
|
} else if (element instanceof Blob) {
|
||||||
buffer = element;
|
buffer = element;
|
||||||
} else {
|
} else {
|
||||||
buffer = Buffer.from(typeof element === 'string' ? element : String(element));
|
buffer = Buffer.from(typeof element === 'string' ? element : String(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line unicorn/explicit-length-check
|
||||||
size += buffer.length || buffer.size || 0;
|
size += buffer.length || buffer.size || 0;
|
||||||
return buffer;
|
return buffer;
|
||||||
});
|
});
|
||||||
@@ -152,7 +139,7 @@ class Blob {
|
|||||||
} else {
|
} else {
|
||||||
const chunk = part.slice(relativeStart, Math.min(size, relativeEnd));
|
const chunk = part.slice(relativeStart, Math.min(size, relativeEnd));
|
||||||
blobParts.push(chunk);
|
blobParts.push(chunk);
|
||||||
added += size;
|
added += ArrayBuffer.isView(chunk) ? chunk.byteLength : chunk.size;
|
||||||
relativeStart = 0; // All next sequental parts should start at 0
|
relativeStart = 0; // All next sequental parts should start at 0
|
||||||
|
|
||||||
// don't add the overflow to new blobParts
|
// don't add the overflow to new blobParts
|
||||||
@@ -162,11 +149,26 @@ class Blob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const blob = new Blob([], {type});
|
const blob = new Blob([], {type: String(type).toLowerCase()});
|
||||||
Object.assign(wm.get(blob), {size: span, parts: blobParts});
|
Object.assign(wm.get(blob), {size: span, parts: blobParts});
|
||||||
|
|
||||||
return blob;
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get [Symbol.toStringTag]() {
|
||||||
|
return 'Blob';
|
||||||
|
}
|
||||||
|
|
||||||
|
static [Symbol.hasInstance](object) {
|
||||||
|
return (
|
||||||
|
object &&
|
||||||
|
typeof object === 'object' &&
|
||||||
|
typeof object.stream === 'function' &&
|
||||||
|
object.stream.length === 0 &&
|
||||||
|
typeof object.constructor === 'function' &&
|
||||||
|
/^(Blob|File)$/.test(object[Symbol.toStringTag])
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperties(Blob.prototype, {
|
Object.defineProperties(Blob.prototype, {
|
||||||
@@ -175,11 +177,4 @@ Object.defineProperties(Blob.prototype, {
|
|||||||
slice: {enumerable: true}
|
slice: {enumerable: true}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Blob.prototype, Symbol.toStringTag, {
|
|
||||||
value: 'Blob',
|
|
||||||
writable: false,
|
|
||||||
enumerable: false,
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = Blob;
|
module.exports = Blob;
|
||||||
|
|||||||
+33
-16
@@ -1,18 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "fetch-blob",
|
"name": "fetch-blob",
|
||||||
"version": "2.0.0",
|
"version": "2.1.2",
|
||||||
"description": "A Blob implementation in Node.js, originally from node-fetch.",
|
"description": "A Blob implementation in Node.js, originally from node-fetch.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"files": [
|
"files": [
|
||||||
|
"from.js",
|
||||||
"index.js",
|
"index.js",
|
||||||
"index.d.ts"
|
"index.d.ts",
|
||||||
|
"from.d.ts"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "xo",
|
"lint": "xo",
|
||||||
"test": "xo && ava",
|
"test": "xo && ava",
|
||||||
"report": "nyc ava",
|
"report": "c8 --reporter json --reporter text ava",
|
||||||
"coverage": "nyc --reporter json --reporter text ava && codecov -f coverage/coverage-final.json",
|
"coverage": "c8 --reporter json --reporter text ava && codecov -f coverage/coverage-final.json",
|
||||||
"prepublishOnly": "tsc --declaration --emitDeclarationOnly --allowJs index.js"
|
"prepublishOnly": "tsc --declaration --emitDeclarationOnly --allowJs index.js from.js"
|
||||||
},
|
},
|
||||||
"repository": "https://github.com/node-fetch/fetch-blob.git",
|
"repository": "https://github.com/node-fetch/fetch-blob.git",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -20,7 +22,7 @@
|
|||||||
"node-fetch"
|
"node-fetch"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10.17.0"
|
"node": "^10.17.0 || >=12.3.0"
|
||||||
},
|
},
|
||||||
"author": "David Frank",
|
"author": "David Frank",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -28,16 +30,17 @@
|
|||||||
"url": "https://github.com/node-fetch/fetch-blob/issues"
|
"url": "https://github.com/node-fetch/fetch-blob/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/node-fetch/fetch-blob#readme",
|
"homepage": "https://github.com/node-fetch/fetch-blob#readme",
|
||||||
"devDependencies": {
|
|
||||||
"ava": "^3.8.2",
|
|
||||||
"codecov": "^3.7.0",
|
|
||||||
"get-stream": "^5.1.0",
|
|
||||||
"node-fetch": "^2.6.0",
|
|
||||||
"nyc": "^15.1.0",
|
|
||||||
"typescript": "^3.9.5",
|
|
||||||
"xo": "^0.32.0"
|
|
||||||
},
|
|
||||||
"xo": {
|
"xo": {
|
||||||
|
"rules": {
|
||||||
|
"unicorn/import-index": "off",
|
||||||
|
"import/extensions": [
|
||||||
|
"error",
|
||||||
|
"always",
|
||||||
|
{
|
||||||
|
"ignorePackages": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": "test.js",
|
"files": "test.js",
|
||||||
@@ -48,5 +51,19 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"peerDependenciesMeta": {
|
||||||
|
"domexception": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"ava": "^3.15.0",
|
||||||
|
"c8": "^7.7.1",
|
||||||
|
"codecov": "^3.8.1",
|
||||||
|
"domexception": "^2.0.1",
|
||||||
|
"get-stream": "^6.0.1",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"typescript": "^4.2.4",
|
||||||
|
"xo": "^0.38.2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
const fs = require('fs');
|
||||||
const test = require('ava');
|
const test = require('ava');
|
||||||
const Blob = require('.');
|
|
||||||
const getStream = require('get-stream');
|
const getStream = require('get-stream');
|
||||||
const {Response} = require('node-fetch');
|
const {Response} = require('node-fetch');
|
||||||
|
const {TextDecoder} = require('util');
|
||||||
|
const Blob = require('./index.js');
|
||||||
|
const blobFrom = require('./from.js');
|
||||||
|
|
||||||
test('new Blob()', t => {
|
test('new Blob()', t => {
|
||||||
const blob = new Blob(); // eslint-disable-line no-unused-vars
|
const blob = new Blob(); // eslint-disable-line no-unused-vars
|
||||||
@@ -113,6 +116,12 @@ test('Blob slice(0, -1)', async t => {
|
|||||||
t.is(await blob.text(), 'abcdefg');
|
t.is(await blob.text(), 'abcdefg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Blob(["hello ", "world"]).slice(5)', async t => {
|
||||||
|
const parts = ['hello ', 'world'];
|
||||||
|
const blob = new Blob(parts);
|
||||||
|
t.is(await blob.slice(5).text(), ' world');
|
||||||
|
});
|
||||||
|
|
||||||
test('throw away unwanted parts', async t => {
|
test('throw away unwanted parts', async t => {
|
||||||
const blob = new Blob(['a', 'b', 'c']).slice(1, 2);
|
const blob = new Blob(['a', 'b', 'c']).slice(1, 2);
|
||||||
t.is(await blob.text(), 'b');
|
t.is(await blob.text(), 'b');
|
||||||
@@ -135,3 +144,52 @@ test('Blob works with node-fetch Response.text()', async t => {
|
|||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
t.is(text, data);
|
t.is(text, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('blob part backed up by filesystem', async t => {
|
||||||
|
const blob = blobFrom('./LICENSE');
|
||||||
|
t.is(await blob.slice(0, 3).text(), 'MIT');
|
||||||
|
t.is(await blob.slice(4, 11).text(), 'License');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Reading after modified should fail', async t => {
|
||||||
|
const blob = blobFrom('./LICENSE');
|
||||||
|
await new Promise(resolve => {
|
||||||
|
setTimeout(resolve, 100);
|
||||||
|
});
|
||||||
|
const now = new Date();
|
||||||
|
// Change modified time
|
||||||
|
fs.utimesSync('./LICENSE', now, now);
|
||||||
|
const error = await blob.text().catch(error => error);
|
||||||
|
t.is(error.name, 'NotReadableError');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Reading from the stream created by blobFrom', async t => {
|
||||||
|
const blob = blobFrom('./LICENSE');
|
||||||
|
const expected = await fs.promises.readFile('./LICENSE', 'utf-8');
|
||||||
|
|
||||||
|
const actual = await getStream(blob.stream());
|
||||||
|
|
||||||
|
t.is(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Reading empty blobs', async t => {
|
||||||
|
const blob = blobFrom('./LICENSE').slice(0, 0);
|
||||||
|
const actual = await blob.text();
|
||||||
|
t.is(actual, '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Blob-ish class is an instance of Blob', t => {
|
||||||
|
class File {
|
||||||
|
stream() {}
|
||||||
|
|
||||||
|
get [Symbol.toStringTag]() {
|
||||||
|
return 'File';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.true(new File() instanceof Blob);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Instanceof check returns false for nullish values', t => {
|
||||||
|
t.false(null instanceof Blob);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user