diff --git a/src/bee-debug.ts b/src/bee-debug.ts index 2b256056..8859b94a 100644 --- a/src/bee-debug.ts +++ b/src/bee-debug.ts @@ -60,7 +60,9 @@ export class BeeDebug { return connectivity.getPeers(this.url) } - async removePeer(peer: string): Promise { + async removePeer(peer: string | Address): Promise { + assertAddress(peer) + return connectivity.removePeer(this.url, peer) } @@ -68,7 +70,9 @@ export class BeeDebug { return connectivity.getTopology(this.url) } - async pingPeer(peer: string): Promise { + async pingPeer(peer: string | Address): Promise { + assertAddress(peer) + return connectivity.pingPeer(this.url, peer) } diff --git a/src/bee.ts b/src/bee.ts index c2b608b6..86080813 100644 --- a/src/bee.ts +++ b/src/bee.ts @@ -20,7 +20,20 @@ import { createFeedManifest } from './modules/feed' import { assertBeeUrl, stripLastSlash } from './utils/url' import { EthAddress, makeEthAddress, makeHexEthAddress } from './utils/eth' import { wrapBytesWithHelpers } from './utils/bytes' -import { assertBatchId, assertNonNegativeInteger, assertReference } from './utils/type' +import { + assertAddressPrefix, + assertBatchId, + assertCollectionUploadOptions, + assertData, + assertFileData, + assertFileUploadOptions, + assertNonNegativeInteger, + assertPssMessageHandler, + assertPublicKey, + assertReference, + assertUploadOptions, + isTag, +} from './utils/type' import { setJsonData, getJsonData } from './feed/json' import { makeCollectionFromFS, makeCollectionFromFileList } from './utils/collection' import { PostageBatchOptions, STAMPS_DEPTH_MAX, STAMPS_DEPTH_MIN } from './types' @@ -95,6 +108,9 @@ export class Bee { options?: UploadOptions, ): Promise { assertBatchId(postageBatchId) + assertData(data) + + if (options) assertUploadOptions(options) return bytes.upload(this.url, data, postageBatchId, options) } @@ -139,12 +155,19 @@ export class Bee { options?: FileUploadOptions, ): Promise { assertBatchId(postageBatchId) + assertFileData(data) + + if (options) assertFileUploadOptions(options) + + if (name && typeof name !== 'string') { + throw new TypeError('name has to be string or undefined!') + } if (isFile(data)) { const fileData = await fileArrayBuffer(data) - const fileName = name || data.name + const fileName = name ?? data.name const contentType = data.type - const fileOptions = options !== undefined ? { contentType, ...options } : { contentType } + const fileOptions = { contentType, ...options } return bzz.uploadFile(this.url, fileData, postageBatchId, fileName, fileOptions) } else { @@ -193,6 +216,9 @@ export class Bee { options?: CollectionUploadOptions, ): Promise { assertBatchId(postageBatchId) + + if (options) assertCollectionUploadOptions(options) + const data = await makeCollectionFromFileList(fileList) return bzz.uploadCollection(this.url, data, postageBatchId, options) @@ -215,6 +241,8 @@ export class Bee { options?: CollectionUploadOptions, ): Promise { assertBatchId(postageBatchId) + + if (options) assertCollectionUploadOptions(options) const data = await makeCollectionFromFS(dir) return bzz.uploadCollection(this.url, data, postageBatchId, options) @@ -233,6 +261,14 @@ export class Bee { * @param tagUid UID or tag object to be retrieved */ async retrieveTag(tagUid: number | Tag): Promise { + if (isTag(tagUid)) { + tagUid = tagUid.uid + } else if (typeof tagUid === 'number') { + assertNonNegativeInteger(tagUid, 'UID') + } else { + throw new TypeError('tagUid has to be either Tag or a number (UID)!') + } + return tag.retrieveTag(this.url, tagUid) } @@ -313,11 +349,23 @@ export class Bee { topic: string, target: AddressPrefix, data: string | Uint8Array, - recipient?: PublicKey, + recipient?: string | PublicKey, ): Promise { + assertData(data) assertBatchId(postageBatchId) + assertAddressPrefix(target) + + if (typeof topic !== 'string') { + throw new TypeError('topic has to be an string!') + } + + if (recipient) { + assertPublicKey(recipient) - return pss.send(this.url, topic, target, data, postageBatchId, recipient) + return pss.send(this.url, topic, target, data, postageBatchId, recipient) + } else { + return pss.send(this.url, topic, target, data, postageBatchId) + } } /** @@ -329,6 +377,12 @@ export class Bee { * @returns Subscription to a given topic */ pssSubscribe(topic: string, handler: PssMessageHandler): PssSubscription { + assertPssMessageHandler(handler) + + if (typeof topic !== 'string') { + throw new TypeError('topic has to be an string!') + } + const ws = pss.subscribe(this.url, topic) let cancelled = false @@ -386,6 +440,14 @@ export class Bee { * @returns Message in byte array */ async pssReceive(topic: string, timeoutMsec = 0): Promise { + if (typeof topic !== 'string') { + throw new TypeError('topic has to be an string!') + } + + if (typeof timeoutMsec !== 'number') { + throw new TypeError('timeoutMsc parameter has to be a number!') + } + return new Promise((resolve, reject) => { let timeout: number | undefined const subscription = this.pssSubscribe(topic, { @@ -523,7 +585,7 @@ export class Bee { const feedType = options?.type ?? DEFAULT_FEED_TYPE if (options?.signer && options?.address) { - return Promise.reject(new BeeError('Both options "signer" and "address" can not be specified at one time!')) + throw new BeeError('Both options "signer" and "address" can not be specified at one time!') } let address: EthAddress @@ -535,9 +597,9 @@ export class Bee { address = this.resolveSigner(options?.signer).address } catch (e) { if (e instanceof BeeError) { - return Promise.reject(new BeeError('Either address, signer or default signer has to be specified!')) + throw new BeeError('Either address, signer or default signer has to be specified!') } else { - return Promise.reject(e) + throw e } } } diff --git a/src/chunk/signer.ts b/src/chunk/signer.ts index 18afcbf5..b68eaafa 100644 --- a/src/chunk/signer.ts +++ b/src/chunk/signer.ts @@ -89,7 +89,7 @@ export function makePrivateKeySigner(privateKey: PrivateKeyBytes): Signer { } export function assertSigner(signer: unknown): asserts signer is Signer { - if (typeof signer !== 'object' || signer === null) { + if (typeof signer !== 'object' || signer === null || Array.isArray(signer)) { throw new TypeError('Signer must be an object or string!') } diff --git a/src/feed/json.ts b/src/feed/json.ts index bd83d717..1a2f2288 100644 --- a/src/feed/json.ts +++ b/src/feed/json.ts @@ -1,6 +1,5 @@ -import { FeedWriter, FeedReader, AnyJson, Address, Reference } from '../types' +import { FeedWriter, FeedReader, AnyJson, BatchId, Reference } from '../types' import { Bee } from '../bee' -import { assertAddress } from '../utils/type' function serializeJson(data: AnyJson): Uint8Array { try { @@ -23,11 +22,9 @@ export async function getJsonData(bee: Bee, reader: FeedReade export async function setJsonData( bee: Bee, writer: FeedWriter, - postageBatchId: string | Address, + postageBatchId: BatchId, data: AnyJson, ): Promise { - assertAddress(postageBatchId) - const serializedData = serializeJson(data) const reference = await bee.uploadData(postageBatchId, serializedData) diff --git a/src/feed/topic.ts b/src/feed/topic.ts index cff1d23e..7e8ed6e3 100644 --- a/src/feed/topic.ts +++ b/src/feed/topic.ts @@ -15,5 +15,9 @@ export function makeTopic(topic: Uint8Array | string): Topic { } export function makeTopicFromString(s: string): Topic { + if (typeof s !== 'string') { + throw new TypeError('topic has to be string!') + } + return bytesToHex(keccak256Hash(s), TOPIC_HEX_LENGTH) } diff --git a/src/modules/tag.ts b/src/modules/tag.ts index f49b7c61..60d717b0 100644 --- a/src/modules/tag.ts +++ b/src/modules/tag.ts @@ -22,10 +22,9 @@ export async function createTag(url: string): Promise { * Retrieve tag information from Bee node * * @param url Bee tag URL - * @param tag UID or tag object to be retrieved + * @param uid UID of tag to be retrieved */ -export async function retrieveTag(url: string, tag: Tag | number): Promise { - const uid = typeof tag === 'number' ? tag : tag?.uid +export async function retrieveTag(url: string, uid: number): Promise { const response = await safeAxios({ url: `${url}${endpoint}/${uid}`, }) diff --git a/src/types/debug.ts b/src/types/debug.ts index d65a409d..e0210181 100644 --- a/src/types/debug.ts +++ b/src/types/debug.ts @@ -1,3 +1,6 @@ +import { PublicKey } from './index' +import { HexEthAddress } from '../utils/eth' + export interface Settlements { peer: string received: bigint @@ -13,9 +16,9 @@ export interface AllSettlements { export interface NodeAddresses { overlay: string underlay: string[] - ethereum: string - publicKey: string - pssPublicKey: string + ethereum: HexEthAddress + publicKey: PublicKey + pssPublicKey: PublicKey } export interface Peer { diff --git a/src/types/index.ts b/src/types/index.ts index dd7a61d4..842597cb 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -14,6 +14,7 @@ export interface Dictionary { } export const ADDRESS_HEX_LENGTH = 64 +export const PUBKEY_HEX_LENGTH = 66 export const BATCH_ID_HEX_LENGTH = 64 export const REFERENCE_HEX_LENGTH = 64 export const ENCRYPTED_REFERENCE_HEX_LENGTH = 128 @@ -31,7 +32,7 @@ export const STAMPS_DEPTH_MIN = 16 export const STAMPS_DEPTH_MAX = 255 export type Reference = HexString | HexString -export type PublicKey = string +export type PublicKey = HexString export type Address = HexString diff --git a/src/utils/collection.ts b/src/utils/collection.ts index b379eb2f..725534f6 100644 --- a/src/utils/collection.ts +++ b/src/utils/collection.ts @@ -3,10 +3,7 @@ import { BeeArgumentError } from './error' import path from 'path' import fs from 'fs' import { fileArrayBuffer } from './file' - -function isUint8Array(obj: unknown): obj is Uint8Array { - return obj instanceof Uint8Array -} +import { isUint8Array } from './type' export function isCollection(data: unknown): data is Collection { if (!Array.isArray(data)) { @@ -29,6 +26,14 @@ export function assertCollection(data: unknown): asserts data is Collection> { + if (typeof dir !== 'string') { + throw new TypeError('dir has to be string!') + } + + if (dir === '') { + throw new TypeError('dir must not be empty string!') + } + return buildCollectionRelative(dir, '') } @@ -66,12 +71,16 @@ interface WebkitFile extends File { readonly webkitRelativePath?: string } -function filePath(file: WebkitFile) { +function makeFilePath(file: WebkitFile) { if (file.webkitRelativePath && file.webkitRelativePath !== '') { return file.webkitRelativePath.replace(/.*?\//i, '') } - return file.name + if (file.name) { + return file.name + } + + throw new TypeError('file is not valid File object') } export async function makeCollectionFromFileList(fileList: FileList | File[]): Promise> { @@ -82,7 +91,7 @@ export async function makeCollectionFromFileList(fileList: FileList | File[]): P if (file) { collection.push({ - path: filePath(file), + path: makeFilePath(file), data: new Uint8Array(await fileArrayBuffer(file)), }) } diff --git a/src/utils/hex.ts b/src/utils/hex.ts index 915477af..29c2c40b 100644 --- a/src/utils/hex.ts +++ b/src/utils/hex.ts @@ -152,20 +152,22 @@ export function isPrefixedHexString(s: unknown): s is PrefixedHexString { * * @param s string input * @param len expected length of the HexString + * @param name optional name for the asserted value * @returns HexString or throws error */ export function assertHexString( s: unknown, len?: number, + name = 'value', ): asserts s is HexString { if (!isHexString(s, len)) { if (isPrefixedHexString(s)) { - throw new TypeError(`Not valid non prefixed hex string (has 0x prefix): ${s}`) + throw new TypeError(`${name} not valid non prefixed hex string (has 0x prefix): ${s}`) } // Don't display length error if no length specified in order not to confuse user const lengthMsg = len ? ` of length ${len}` : '' - throw new TypeError(`Not valid hex string${lengthMsg}: ${s}`) + throw new TypeError(`${name} not valid hex string${lengthMsg}: ${s}`) } } @@ -174,10 +176,11 @@ export function assertHexString( * * @param s string input * @param len expected length of the HexString + * @param name optional name for the asserted value * @returns HexString or throws error */ -export function assertPrefixedHexString(s: string): asserts s is PrefixedHexString { +export function assertPrefixedHexString(s: string, name = 'value'): asserts s is PrefixedHexString { if (!isPrefixedHexString(s)) { - throw new TypeError(`Not valid prefixed hex string: ${s}`) + throw new TypeError(`${name} not valid prefixed hex string: ${s}`) } } diff --git a/src/utils/type.ts b/src/utils/type.ts index b318e1e3..475d3974 100644 --- a/src/utils/type.ts +++ b/src/utils/type.ts @@ -1,14 +1,38 @@ import { Address, ADDRESS_HEX_LENGTH, + AddressPrefix, BATCH_ID_HEX_LENGTH, BatchId, + CollectionUploadOptions, ENCRYPTED_REFERENCE_HEX_LENGTH, + FileUploadOptions, + PssMessageHandler, + PUBKEY_HEX_LENGTH, + PublicKey, Reference, REFERENCE_HEX_LENGTH, + Tag, + UploadOptions, } from '../types' import { assertHexString } from './hex' import { BeeArgumentError } from './error' +import { Readable } from 'stream' +import { isFile } from './file' + +export function isReadable(entry: unknown): entry is Readable { + return ( + typeof entry === 'object' && + entry !== null && + typeof (entry as Readable).pipe === 'function' && + (entry as Readable).readable && + typeof (entry as Readable)._read === 'function' + ) +} + +export function isUint8Array(obj: unknown): obj is Uint8Array { + return obj instanceof Uint8Array +} export function isInteger(value: unknown): value is number | bigint { return ( @@ -24,10 +48,10 @@ export function assertInteger(value: unknown): asserts value is number | bigint if (!isInteger(value)) throw new TypeError('value is not integer') } -export function assertNonNegativeInteger(value: unknown): asserts value is number | bigint { +export function assertNonNegativeInteger(value: unknown, name = 'Value'): asserts value is number | bigint { assertInteger(value) - if (value < 0) throw new BeeArgumentError('value has to be bigger or equal to zero', value) + if (value < 0) throw new BeeArgumentError(`${name} has to be bigger or equal to zero`, value) } export function assertReference(value: unknown): asserts value is Reference { @@ -39,9 +63,156 @@ export function assertReference(value: unknown): asserts value is Reference { } export function assertAddress(value: unknown): asserts value is Address { - assertHexString(value, ADDRESS_HEX_LENGTH) + assertHexString(value, ADDRESS_HEX_LENGTH, 'Address') } export function assertBatchId(value: unknown): asserts value is BatchId { - assertHexString(value, BATCH_ID_HEX_LENGTH) + assertHexString(value, BATCH_ID_HEX_LENGTH, 'BatchId') +} + +export function assertUploadOptions(value: unknown, name = 'UploadOptions'): asserts value is UploadOptions { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new TypeError(`${name} has to be an object!`) + } + + const options = value as UploadOptions + + if (options.pin && typeof options.pin !== 'boolean') { + throw new TypeError(`options.pin property in ${name} has to be boolean or undefined!`) + } + + if (options.encrypt && typeof options.encrypt !== 'boolean') { + throw new TypeError(`options.encrypt property in ${name} has to be boolean or undefined!`) + } + + if (options.tag) { + if (typeof options.tag !== 'number') { + throw new TypeError(`options.tag property in ${name} has to be number or undefined!`) + } + + assertNonNegativeInteger(options.tag, 'options.tag') + } + + if (options.axiosOptions && (typeof options.axiosOptions !== 'object' || Array.isArray(options.axiosOptions))) { + throw new TypeError(`options.axiosOptions property in ${name} has to be object or undefined!`) + } +} + +export function assertFileUploadOptions(value: unknown): asserts value is FileUploadOptions { + assertUploadOptions(value, 'FileUploadOptions') + + const options = value as FileUploadOptions + + if (options.size) { + if (typeof options.size !== 'number') { + throw new TypeError('tag property in FileUploadOptions has to be number or undefined!') + } + + assertNonNegativeInteger(options.size, 'options.size') + } + + if (options.contentType && typeof options.contentType !== 'string') { + throw new TypeError('contentType property in FileUploadOptions has to be string or undefined!') + } +} + +export function assertCollectionUploadOptions(value: unknown): asserts value is CollectionUploadOptions { + assertUploadOptions(value, 'CollectionUploadOptions') + + const options = value as CollectionUploadOptions + + if (options.indexDocument && typeof options.indexDocument !== 'string') { + throw new TypeError('indexDocument property in CollectionUploadOptions has to be string or undefined!') + } + + if (options.errorDocument && typeof options.errorDocument !== 'string') { + throw new TypeError('errorDocument property in CollectionUploadOptions has to be string or undefined!') + } +} + +export function isTag(value: unknown): value is Tag { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + return false + } + + const tag = value as Record + + const numberProperties = ['total', 'processed', 'synced', 'uid'] + const correctNumberProperties = numberProperties.every(numberProperty => typeof tag[numberProperty] === 'number') + + if (!correctNumberProperties || !tag.startedAt || typeof tag.startedAt !== 'string') { + return false + } + + return true +} + +export function assertTag(value: unknown): asserts value is Tag { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new TypeError('Tag is not an object!') + } + + const tag = value as Record + + const numberProperties = ['total', 'processed', 'synced', 'uid'] + for (const numberProperty of numberProperties) { + if (!tag[numberProperty]) { + throw new TypeError(`Tag's property '${numberProperty}' has to be specified!`) + } + + if (typeof tag[numberProperty] !== 'number') { + throw new TypeError(`Tag's property '${numberProperty}' has to be number!`) + } + } + + if (!tag.startedAt) { + throw new TypeError("Tag's property 'startedAt' has to be specified!") + } + + if (typeof tag.startedAt !== 'string') { + throw new TypeError("Tag's property 'startedAt' has to be string!") + } +} + +export function assertAddressPrefix(value: unknown): asserts value is AddressPrefix { + assertHexString(value, undefined, 'AddressPrefix') + + if (value.length > ADDRESS_HEX_LENGTH) { + throw new BeeArgumentError( + `AddressPrefix must have length of ${ADDRESS_HEX_LENGTH} at most! Got string with ${value.length}`, + value, + ) + } +} + +export function assertPssMessageHandler(value: unknown): asserts value is PssMessageHandler { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + throw new TypeError('PssMessageHandler has to be object!') + } + + const handler = value as PssMessageHandler + + if (typeof handler.onMessage !== 'function') { + throw new TypeError('onMessage property of PssMessageHandler has to be function!') + } + + if (typeof handler.onError !== 'function') { + throw new TypeError('onError property of PssMessageHandler has to be function!') + } +} + +export function assertPublicKey(value: unknown): asserts value is PublicKey { + assertHexString(value, PUBKEY_HEX_LENGTH, 'PublicKey') +} + +export function assertData(value: unknown): asserts value is string | Uint8Array { + if (typeof value !== 'string' && !(value instanceof Uint8Array)) { + throw new TypeError('Data must be either string or Uint8Array!') + } +} + +export function assertFileData(value: unknown): asserts value is string | Uint8Array | Readable | File { + if (typeof value !== 'string' && !(value instanceof Uint8Array) && !isFile(value) && !isReadable(value)) { + throw new TypeError('Data must be either string, Readable, Uint8Array or File!') + } } diff --git a/test/integration/modules/bzz.spec.ts b/test/integration/modules/bzz.spec.ts index a85958da..79460067 100644 --- a/test/integration/modules/bzz.spec.ts +++ b/test/integration/modules/bzz.spec.ts @@ -261,7 +261,7 @@ describe('modules/bzz', () => { const tag1 = await tag.createTag(BEE_URL) await bzz.uploadFile(BEE_URL, data, getPostageBatch(), filename, { tag: tag1.uid }) - const tag2 = await tag.retrieveTag(BEE_URL, tag1) + const tag2 = await tag.retrieveTag(BEE_URL, tag1.uid) expect(tag2.total).toEqual(EXPECTED_TAGS_COUNT) expect(tag2.processed).toEqual(EXPECTED_TAGS_COUNT) diff --git a/test/integration/modules/tag.spec.ts b/test/integration/modules/tag.spec.ts index 12446e5d..f785784e 100644 --- a/test/integration/modules/tag.spec.ts +++ b/test/integration/modules/tag.spec.ts @@ -16,7 +16,7 @@ describe('modules/tag', () => { it('should retrieve previously created empty tag', async () => { const tag1 = await tag.createTag(BEE_URL) - const tag2 = await tag.retrieveTag(BEE_URL, tag1) + const tag2 = await tag.retrieveTag(BEE_URL, tag1.uid) expect(tag1).toEqual(tag2) }) diff --git a/test/unit/assertions.ts b/test/unit/assertions.ts new file mode 100644 index 00000000..c25ee2ba --- /dev/null +++ b/test/unit/assertions.ts @@ -0,0 +1,376 @@ +/* eslint-disable */ +import { BeeArgumentError } from '../../src' +import { makeBytes } from '../../src/utils/bytes' + +export function testBatchIdAssertion(executor: (input: unknown) => void): void { + it('should throw exception for bad BatchId', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor('')).rejects.toThrow(TypeError) + + // Not an valid hexstring (ZZZ) + await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Prefixed hexstring is not accepted + await expect(() => executor('0x634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + }) +} + +export function testDataAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad Data', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + }) +} + +export function testFileDataAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad FileData', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor({ name: 'some file' })).rejects.toThrow(TypeError) + // eslint-disable-next-line @typescript-eslint/no-empty-function + await expect(() => executor({ pipe: () => {} })).rejects.toThrow(TypeError) + }) +} + +export function testUploadOptionsAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad UploadOptions', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor('string')).rejects.toThrow(TypeError) + + await expect(() => executor({ pin: 'plur' })).rejects.toThrow(TypeError) + await expect(() => executor({ pin: 1 })).rejects.toThrow(TypeError) + await expect(() => executor({ pin: {} })).rejects.toThrow(TypeError) + await expect(() => executor({ pin: [] })).rejects.toThrow(TypeError) + + await expect(() => executor({ encrypt: 'plur' })).rejects.toThrow(TypeError) + await expect(() => executor({ encrypt: 1 })).rejects.toThrow(TypeError) + await expect(() => executor({ encrypt: {} })).rejects.toThrow(TypeError) + await expect(() => executor({ encrypt: [] })).rejects.toThrow(TypeError) + + await expect(() => executor({ tag: 'plur' })).rejects.toThrow(TypeError) + await expect(() => executor({ tag: true })).rejects.toThrow(TypeError) + await expect(() => executor({ tag: {} })).rejects.toThrow(TypeError) + await expect(() => executor({ tag: [] })).rejects.toThrow(TypeError) + await expect(() => executor({ tag: -1 })).rejects.toThrow(BeeArgumentError) + + await expect(() => executor({ axiosOptions: 'plur' })).rejects.toThrow(TypeError) + await expect(() => executor({ axiosOptions: true })).rejects.toThrow(TypeError) + await expect(() => executor({ axiosOptions: [] })).rejects.toThrow(TypeError) + await expect(() => executor({ axiosOptions: -1 })).rejects.toThrow(TypeError) + }) +} + +export function testFileUploadOptionsAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad FileUploadOptions', async () => { + await expect(() => executor({ contentType: true })).rejects.toThrow(TypeError) + await expect(() => executor({ contentType: 1 })).rejects.toThrow(TypeError) + await expect(() => executor({ contentType: {} })).rejects.toThrow(TypeError) + await expect(() => executor({ contentType: [] })).rejects.toThrow(TypeError) + + await expect(() => executor({ size: 'plur' })).rejects.toThrow(TypeError) + await expect(() => executor({ size: true })).rejects.toThrow(TypeError) + await expect(() => executor({ size: {} })).rejects.toThrow(TypeError) + await expect(() => executor({ size: [] })).rejects.toThrow(TypeError) + await expect(() => executor({ size: -1 })).rejects.toThrow(BeeArgumentError) + }) +} + +export function testCollectionUploadOptionsAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad CollectionUploadOptions', async () => { + await expect(() => executor({ indexDocument: true })).rejects.toThrow(TypeError) + await expect(() => executor({ indexDocument: 1 })).rejects.toThrow(TypeError) + await expect(() => executor({ indexDocument: {} })).rejects.toThrow(TypeError) + await expect(() => executor({ indexDocument: [] })).rejects.toThrow(TypeError) + + await expect(() => executor({ errorDocument: true })).rejects.toThrow(TypeError) + await expect(() => executor({ errorDocument: 1 })).rejects.toThrow(TypeError) + await expect(() => executor({ errorDocument: {} })).rejects.toThrow(TypeError) + await expect(() => executor({ errorDocument: [] })).rejects.toThrow(TypeError) + }) +} + +export function testReferenceAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad Reference', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor('')).rejects.toThrow(TypeError) + + // Not an valid hexstring (ZZZ) + await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Prefixed hexstring is not accepted + await expect(() => executor('0x634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Length mismatch + await expect(() => executor('4fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + }) +} + +export function testAddressPrefixAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad AddressPrefix', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor('')).rejects.toThrow(TypeError) + + // Not an valid hexstring (ZZZ) + await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Prefixed hexstring is not accepted + await expect(() => executor('0x634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Too long hexstring + await expect(() => executor('123634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + BeeArgumentError, + ) + }) +} + +export function testPublicKeyAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad PublicKey', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + + // Not an valid hexstring (ZZZ) + await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Prefixed hexstring is not accepted + await expect(() => executor('0x634fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Length mismatch + await expect(() => executor('4fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + }) +} + +export function testPssMessageHandlerAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad PssMessageHandler', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor('')).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onMessage() {} }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onMessage() {}, onError: '' }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onMessage() {}, onError: [] }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onMessage() {}, onError: {} }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onMessage() {}, onError: true }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onError() {}, onMessage: true }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onError() {}, onMessage: {} }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onError() {}, onMessage: [] }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onError() {}, onMessage: '' }) + }).rejects.toThrow(TypeError) + + await expect(() => { + return executor({ onError() {}, onMessage: 1 }) + }).rejects.toThrow(TypeError) + }) +} + +export function testTopicAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad Topic', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + }) +} + +export function testFeedTopicAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad Topic', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + + // Not an valid hexstring (ZZZ) + await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Length mismatch + await expect(() => executor('4fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + }) +} + +export function testEthAddressAssertions(executor: (input: unknown) => void): void { + it('should throw exception for bad EthAddress', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + + // Not an valid hexstring (ZZZ) + await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Length mismatch + await expect(() => executor('4fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Bytes length mismatch + await expect(() => executor(makeBytes(19))).rejects.toThrow(TypeError) + }) +} + +export function testMakeSignerAssertions(executor: (input: unknown) => void, optionals = true): void { + it('should throw exception for bad Signer', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + + if (optionals) { + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + } + + // Not an valid hexstring (ZZZ) + await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Hex Length mismatch + await expect(() => executor('4fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Bytes Length mismatch + await expect(() => executor(makeBytes(31))).rejects.toThrow(TypeError) + + await expect(() => executor({ address: makeBytes(19), sign: () => {} })).rejects.toThrow(TypeError) + await expect(() => executor({ address: '', sign: () => {} })).rejects.toThrow(TypeError) + await expect(() => executor({ address: undefined, sign: () => {} })).rejects.toThrow(TypeError) + await expect(() => executor({ address: null, sign: () => {} })).rejects.toThrow(TypeError) + await expect(() => executor({ address: [], sign: () => {} })).rejects.toThrow(TypeError) + await expect(() => executor({ address: {}, sign: () => {} })).rejects.toThrow(TypeError) + await expect(() => executor({ address: makeBytes(20), sign: null })).rejects.toThrow(TypeError) + await expect(() => executor({ address: makeBytes(20), sign: undefined })).rejects.toThrow(TypeError) + await expect(() => executor({ address: makeBytes(20), sign: 'asd' })).rejects.toThrow(TypeError) + await expect(() => executor({ address: makeBytes(20), sign: [] })).rejects.toThrow(TypeError) + await expect(() => executor({ address: makeBytes(20), sign: {} })).rejects.toThrow(TypeError) + }) +} + +export function testFeedTypeAssertions(executor: (input: unknown) => void, optionals = true): void { + it('should throw exception for bad FeedType', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor('asd')).rejects.toThrow(TypeError) + + if (optionals) { + await expect(() => executor('')).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + } + }) +} + +export function testAddressAssertions(executor: (input: unknown) => void, optionals = true): void { + it('should throw exception for bad Address', async () => { + await expect(() => executor(1)).rejects.toThrow(TypeError) + await expect(() => executor(true)).rejects.toThrow(TypeError) + await expect(() => executor({})).rejects.toThrow(TypeError) + await expect(() => executor([])).rejects.toThrow(TypeError) + await expect(() => executor('asd')).rejects.toThrow(TypeError) + + // Not an valid hexstring (ZZZ) + await expect(() => executor('ZZZfb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + // Hex Length mismatch + await expect(() => executor('4fb5a872396d9693e5c9f9d7233cfa93f395c093371017ff44aa9ae6564cdd')).rejects.toThrow( + TypeError, + ) + + if (optionals) { + await expect(() => executor('')).rejects.toThrow(TypeError) + await expect(() => executor(null)).rejects.toThrow(TypeError) + await expect(() => executor(undefined)).rejects.toThrow(TypeError) + } + }) +} diff --git a/test/unit/bee-class.spec.ts b/test/unit/bee-class.spec.ts index e44b4e73..aa1d416f 100644 --- a/test/unit/bee-class.spec.ts +++ b/test/unit/bee-class.spec.ts @@ -1,7 +1,33 @@ import { assertAllIsDone, createPostageBatchMock, downloadDataMock, fetchFeedUpdateMock, MOCK_SERVER_URL } from './nock' -import { Bee, BeeArgumentError, ReferenceResponse } from '../../src' -import { testIdentity, testJsonHash, testJsonPayload, testJsonStringPayload } from '../utils' +import { + BatchId, + Bee, + BeeArgumentError, + CollectionUploadOptions, + PssMessageHandler, + ReferenceResponse, + UploadOptions, +} from '../../src' +import { testBatchId, testIdentity, testJsonHash, testJsonPayload, testJsonStringPayload } from '../utils' import { makeTopicFromString } from '../../src/feed/topic' +import { + testAddressPrefixAssertions, + testBatchIdAssertion, + testCollectionUploadOptionsAssertions, + testDataAssertions, + testFileDataAssertions, + testFileUploadOptionsAssertions, + testPssMessageHandlerAssertions, + testPublicKeyAssertions, + testReferenceAssertions, + testTopicAssertions, + testUploadOptionsAssertions, + testFeedTypeAssertions, + testFeedTopicAssertions, + testEthAddressAssertions, + testMakeSignerAssertions, +} from './assertions' +import { FeedType } from '../../src/feed/type' const TOPIC = 'some=very%nice#topic' const HASHED_TOPIC = makeTopicFromString(TOPIC) @@ -34,6 +60,369 @@ describe('Bee class', () => { testUrl('javascript:console.log()') testUrl('ws://localhost:1633') + describe('uploadData', () => { + testBatchIdAssertion(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadData(input as BatchId, '') + }) + + testDataAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadData(testBatchId, input as string) + }) + + testUploadOptionsAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadData(testBatchId, '', input as UploadOptions) + }) + }) + + describe('downloadData', () => { + testReferenceAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.downloadData(input as string) + }) + }) + + describe('downloadReadableData', () => { + testReferenceAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.downloadReadableData(input as string) + }) + }) + + describe('uploadFile', () => { + testBatchIdAssertion(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFile(input as BatchId, '') + }) + + testFileDataAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFile(testBatchId, input as string) + }) + + testUploadOptionsAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFile(testBatchId, '', undefined, input as UploadOptions) + }) + + testFileUploadOptionsAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFile(testBatchId, '', undefined, input as UploadOptions) + }) + }) + + describe('downloadFile', () => { + testReferenceAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.downloadFile(input as string) + }) + }) + + describe('downloadReadableFile', () => { + testReferenceAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.downloadReadableFile(input as string) + }) + }) + + describe('uploadFiles', () => { + // eslint-disable-next-line @typescript-eslint/no-empty-function + const files = [{ name: 'some name', arrayBuffer() {} }] as File[] + + testBatchIdAssertion(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFiles(input as BatchId, files) + }) + + testUploadOptionsAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFiles(testBatchId, files, input as UploadOptions) + }) + + testCollectionUploadOptionsAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFiles(testBatchId, files, input as UploadOptions) + }) + }) + + describe('uploadFilesFromDirectory', () => { + testBatchIdAssertion(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFilesFromDirectory(input as BatchId, 'some path') + }) + + testUploadOptionsAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFilesFromDirectory(testBatchId, 'some path', input as CollectionUploadOptions) + }) + + testCollectionUploadOptionsAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.uploadFilesFromDirectory(testBatchId, 'some path', input as CollectionUploadOptions) + }) + + it('should throw exception for bad Dir', async () => { + const bee = new Bee(MOCK_SERVER_URL) + + await expect(bee.uploadFilesFromDirectory(testBatchId, '')).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, true)).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, 1)).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, [])).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, {})).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, null)).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, undefined)).rejects.toThrow(TypeError) + }) + }) + + describe('retrieveTag', () => { + it('should throw exception for bad Tag', async () => { + const bee = new Bee(MOCK_SERVER_URL) + + await expect(bee.uploadFilesFromDirectory(testBatchId, '')).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, true)).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, -1)).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, [])).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, {})).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, null)).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, undefined)).rejects.toThrow(TypeError) + + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, { total: 'asd' })).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, { total: true })).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.uploadFilesFromDirectory(testBatchId, { total: null })).rejects.toThrow(TypeError) + }) + }) + + describe('pin', () => { + testReferenceAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.pin(input as string) + }) + }) + + describe('unpin', () => { + testReferenceAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.unpin(input as string) + }) + }) + + describe('getPin', () => { + testReferenceAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.getPin(input as string) + }) + }) + + describe('reuploadPinnedData', () => { + testReferenceAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.reuploadPinnedData(input as string) + }) + }) + + describe('pssSend', () => { + testBatchIdAssertion(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.pssSend(input as BatchId, 'topic', '123', 'data') + }) + + testDataAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.pssSend(testBatchId, 'topic', '123', input as string) + }) + + testAddressPrefixAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.pssSend(testBatchId, 'topic', input as string, '123') + }) + + testPublicKeyAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.pssSend(testBatchId, 'topic', '123', 'data', input as string) + }) + + testTopicAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.pssSend(testBatchId, input as string, '123', 'data') + }) + }) + + describe('pssSubscribe', () => { + testPssMessageHandlerAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.pssSubscribe('topic', input as PssMessageHandler) + }) + + testTopicAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + const handler = { + // eslint-disable-next-line @typescript-eslint/no-empty-function + onMessage() {}, + // eslint-disable-next-line @typescript-eslint/no-empty-function + onError() {}, + } + + return bee.pssSubscribe(input as string, handler) + }) + }) + + describe('pssReceive', () => { + testTopicAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.pssReceive(input as string) + }) + + it('should throw exception for bad Timeout', async () => { + const bee = new Bee(MOCK_SERVER_URL) + + // @ts-ignore: Type testing + await expect(bee.pssReceive('topic', true)).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.pssReceive('topic', 'asd')).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.pssReceive('topic', [])).rejects.toThrow(TypeError) + // @ts-ignore: Type testing + await expect(bee.pssReceive('topic', {})).rejects.toThrow(TypeError) + }) + }) + + describe('createFeedManifest', () => { + testBatchIdAssertion(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.createFeedManifest(input as BatchId, 'epoch', '123', testIdentity.address) + }) + + testFeedTypeAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.createFeedManifest(testBatchId, input as FeedType, '123', testIdentity.address) + }) + + testFeedTopicAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.createFeedManifest(testBatchId, 'epoch', input as string, testIdentity.address) + }) + + testEthAddressAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.createFeedManifest(testBatchId, 'epoch', '123', input as string) + }) + }) + + describe('makeFeedReader', () => { + testFeedTypeAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.makeFeedReader(input as FeedType, '123', testIdentity.address) + }) + + testFeedTopicAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.makeFeedReader('epoch', input as string, testIdentity.address) + }) + + testEthAddressAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.makeFeedReader('epoch', '123', input as string) + }) + }) + + describe('makeFeedWriter', () => { + testFeedTypeAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.makeFeedWriter(input as FeedType, '123', testIdentity.privateKey) + }) + + testFeedTopicAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.makeFeedWriter('epoch', input as string, testIdentity.privateKey) + }) + + testMakeSignerAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.makeFeedWriter('epoch', '123', input as string) + }) + }) + + describe('setJsonFeed', () => { + testBatchIdAssertion(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.setJsonFeed(input as BatchId, 'epoch', '123', { signer: testIdentity.privateKey }) + }) + + testFeedTypeAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.setJsonFeed(testBatchId, '123', 'data', { type: input as FeedType, signer: testIdentity.privateKey }) + }, false) + + testTopicAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.setJsonFeed('epoch', input as string, 'data', { signer: testIdentity.privateKey }) + }) + + testMakeSignerAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.setJsonFeed('epoch', '123', 'data', { signer: input as string }) + }) + }) + describe('getJsonFeed', () => { it('should fetch with specified address', async () => { downloadDataMock(testJsonHash).reply(200, testJsonStringPayload) @@ -121,6 +510,22 @@ describe('Bee class', () => { }) }) + describe('makeSOCReader', () => { + testEthAddressAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.makeSOCReader(input as string) + }) + }) + + describe('makeSOCWriter', () => { + testMakeSignerAssertions(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.makeSOCWriter(input as string) + }, false) + }) + describe('createPostageBatch', () => { const BATCH_ID = '36b7efd913ca4cf880b8eeac5093fa27b0825906c600685b6abdd6566e6cfe8f' const BATCH_RESPONSE = { @@ -169,4 +574,12 @@ describe('Bee class', () => { await expect(bee.createPostageBatch(BigInt('10'), 256)).rejects.toThrow(BeeArgumentError) }) }) + + describe('getPostageBatch', () => { + testBatchIdAssertion(async (input: unknown) => { + const bee = new Bee(MOCK_SERVER_URL) + + return bee.getPostageBatch(input as BatchId) + }) + }) }) diff --git a/test/unit/bee-debug-class.spec.ts b/test/unit/bee-debug-class.spec.ts index 993be624..3562288f 100644 --- a/test/unit/bee-debug-class.spec.ts +++ b/test/unit/bee-debug-class.spec.ts @@ -1,6 +1,7 @@ import { assertAllIsDone, cashoutLastChequeMock, depositTokensMock, MOCK_SERVER_URL, withdrawTokensMock } from './nock' import { BeeArgumentError, BeeDebug } from '../../src' import { testAddress } from '../utils' +import { testAddressAssertions } from './assertions' describe('BeeDebug class', () => { function testUrl(url: unknown): void { @@ -30,6 +31,62 @@ describe('BeeDebug class', () => { testUrl('javascript:console.log()') testUrl('ws://localhost:1633') + describe('removePeer', () => { + testAddressAssertions(async (input: unknown) => { + const bee = new BeeDebug(MOCK_SERVER_URL) + + return bee.removePeer(input as string) + }) + }) + + describe('pingPeer', () => { + testAddressAssertions(async (input: unknown) => { + const bee = new BeeDebug(MOCK_SERVER_URL) + + return bee.pingPeer(input as string) + }) + }) + + describe('getPeerBalance', () => { + testAddressAssertions(async (input: unknown) => { + const bee = new BeeDebug(MOCK_SERVER_URL) + + return bee.getPeerBalance(input as string) + }) + }) + + describe('getPastDueConsumptionPeerBalance', () => { + testAddressAssertions(async (input: unknown) => { + const bee = new BeeDebug(MOCK_SERVER_URL) + + return bee.getPastDueConsumptionPeerBalance(input as string) + }) + }) + + describe('getLastChequesForPeer', () => { + testAddressAssertions(async (input: unknown) => { + const bee = new BeeDebug(MOCK_SERVER_URL) + + return bee.getLastChequesForPeer(input as string) + }) + }) + + describe('getLastCashoutAction', () => { + testAddressAssertions(async (input: unknown) => { + const bee = new BeeDebug(MOCK_SERVER_URL) + + return bee.getLastCashoutAction(input as string) + }) + }) + + describe('getSettlements', () => { + testAddressAssertions(async (input: unknown) => { + const bee = new BeeDebug(MOCK_SERVER_URL) + + return bee.getSettlements(input as string) + }) + }) + describe('cashoutLastCheque', () => { const TRANSACTION_HASH = '36b7efd913ca4cf880b8eeac5093fa27b0825906c600685b6abdd6566e6cfe8f' const CASHOUT_RESPONSE = { @@ -64,21 +121,10 @@ describe('BeeDebug class', () => { assertAllIsDone() }) - it('should throw error if passed wrong address', async () => { + testAddressAssertions(async (input: unknown) => { const bee = new BeeDebug(MOCK_SERVER_URL) - // @ts-ignore: Input testing - await expect(bee.cashoutLastCheque(true)).rejects.toThrow(TypeError) - - // @ts-ignore: Input testing - await expect(bee.cashoutLastCheque(11)).rejects.toThrow(TypeError) - // @ts-ignore: Input testing - await expect(bee.cashoutLastCheque(null)).rejects.toThrow(TypeError) - // @ts-ignore: Input testing - await expect(bee.cashoutLastCheque()).rejects.toThrow(TypeError) - - await expect(bee.cashoutLastCheque('')).rejects.toThrow(TypeError) - await expect(bee.cashoutLastCheque('asd')).rejects.toThrow(TypeError) + return bee.cashoutLastCheque(input as string) }) it('should throw error if passed wrong gas price input', async () => { diff --git a/test/unit/feed/json.spec.ts b/test/unit/feed/json.spec.ts index dacf1b93..0b62166c 100644 --- a/test/unit/feed/json.spec.ts +++ b/test/unit/feed/json.spec.ts @@ -1,6 +1,6 @@ import { Arg, Substitute } from '@fluffy-spoon/substitute' import { AnyJson, Bee, FeedWriter, Reference } from '../../../src' -import { testAddress, testChunkHash } from '../../utils' +import { testAddress, testBatchId, testChunkHash } from '../../utils' import { getJsonData, setJsonData } from '../../../src/feed/json' import { FetchFeedUpdateResponse } from '../../../src/modules/feed' import { wrapBytesWithHelpers } from '../../../src/utils/bytes' @@ -68,6 +68,6 @@ describe('JsonFeed', () => { circularReference.myself = circularReference // @ts-ignore: Circular references are detected with TS, so we have to ts-ignore to test it. - await expect(setJsonData(bee, writer, circularReference)).rejects.toThrow(TypeError) + await expect(setJsonData(bee, writer, testBatchId, circularReference)).rejects.toThrow(TypeError) }) }) diff --git a/test/utils.ts b/test/utils.ts index e608df83..e56ff1e6 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -258,6 +258,7 @@ export const testChunkData = new Uint8Array([...testChunkSpan, ...testChunkPaylo // the hash is hardcoded because we would need the bmt hasher otherwise export const testChunkHash = 'ca6357a08e317d15ec560fef34e4c45f8f19f01c372aa70f1da72bfa7f1a4338' as Reference export const testAddress = 'ca6357a08e317d15ec560fef34e4c45f8f19f01c372aa70f1da72bfa7f1a4338' as Address +export const testBatchId = 'ca6357a08e317d15ec560fef34e4c45f8f19f01c372aa70f1da72bfa7f1a4338' as BatchId export const testJsonPayload = [{ some: 'object' }] export const testJsonStringPayload = JSON.stringify(testJsonPayload)