chore: migrate tests to typescript

This commit is contained in:
Justin Starry 2021-03-15 13:08:10 +08:00 committed by Justin Starry
parent f912c63b22
commit 8ada44456d
27 changed files with 242 additions and 825 deletions

View File

@ -2,7 +2,6 @@
/coverage
/deploy
/doc
/flow-typed
/lib
/module.flow.js
/.eslintrc.js

View File

@ -1 +1,2 @@
test/dist
module.flow.js

View File

@ -8,8 +8,6 @@ test -r lib/index.iife.js
test -r lib/index.cjs.js
test -r lib/index.esm.js
npm run doc
npm run defs
npm run flow
npm run lint
npm run codecov
make -C examples/bpf-c-noop/

File diff suppressed because it is too large Load Diff

View File

@ -56,12 +56,8 @@
"codecov": "set -ex; npm run test:cover; cat ./coverage/lcov.info | codecov",
"dev": "cross-env NODE_ENV=development rollup -c",
"doc": "set -ex; typedoc",
"defs": "set -ex; flow check-contents < module.flow.js; tsc module.d.ts",
"doc:watch": "watch 'npm run doc' . --wait=1 --ignoreDirectoryPattern=/doc/",
"examples": "set -ex; for example in examples/*.js; do node $example; done",
"flow": "set -ex; flow stop; flow",
"flow:stop": "flow stop",
"flow:watch": "flow stop; watch 'flow' . --wait=1 --ignoreDirectoryPattern=/doc/",
"lint": "set -ex; npm run pretty; eslint . --ext .js,.ts",
"lint:fix": "npm run pretty:fix && eslint . --fix",
"lint:watch": "watch 'npm run lint:fix' . --wait=1 --ignoreDirectoryPattern=/doc/",
@ -69,13 +65,13 @@
"localnet:logs": "bin/localnet.sh logs -f",
"localnet:up": "bin/localnet.sh up",
"localnet:update": "bin/localnet.sh update",
"ok": "run-s lint flow test doc defs",
"ok": "run-s lint test doc",
"prepare": "run-s clean bpf-sdk:install bpf-sdk:remove-symlinks build",
"pretty": "prettier --check '{,{examples,src,test}/**/}*.{j,t}s'",
"pretty:fix": "prettier --write '{,{examples,src,test}/**/}*.{j,t}s'",
"re": "semantic-release --repository-url git@github.com:solana-labs/solana-web3.js.git",
"test": "npm run build:fixtures && mocha './test/**/*.test.js'",
"test:cover": "nyc --reporter=lcov mocha './test/**/*.test.js'",
"test": "npm run build:fixtures && mocha -r ts-node/register './test/**/*.test.ts'",
"test:cover": "nyc --reporter=lcov mocha './test/**/*.test.ts'",
"test:browser": "TEST_LIVE=1 npm run build:fixtures && npm run build:browser-test && mocha-headless-chrome -f http://localhost:8080/mocha.html --timeout 180000",
"test:browser-with-server": "start-server-and-test 'http-server -p 8080' 8080 test:browser",
"test:browser-with-test-validator": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health test:browser-with-server",
@ -116,9 +112,14 @@
"@solana/spl-token": "^0.0.13",
"@types/bn.js": "^5.1.0",
"@types/bs58": "^4.0.1",
"@types/chai": "^4.2.15",
"@types/chai-as-promised": "^7.1.3",
"@types/mocha": "^8.2.1",
"@types/mz": "^2.7.3",
"@types/node": "^14.14.26",
"@types/node-fetch": "^2.5.8",
"@types/secp256k1": "^4.0.1",
"@types/sinon": "^9.0.11",
"@typescript-eslint/eslint-plugin": "^4.14.2",
"@typescript-eslint/parser": "^4.14.2",
"chai": "^4.3.0",
@ -127,14 +128,10 @@
"cross-env": "7.0.3",
"eslint": "^7.19.0",
"eslint-config-prettier": "^8.0.0",
"eslint-plugin-flowtype": "^5.2.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-prettier": "^3.0.0",
"esm": "^3.2.25",
"flow-bin": "0.130.0",
"flow-remove-types": "^2.143.1",
"flow-typed": "3.3.1",
"flowgen": "^1.13.0",
"http-server": "^0.12.3",
"mocha": "^8.2.1",
@ -152,6 +149,7 @@
"semantic-release": "^17.0.2",
"sinon": "^9.2.4",
"start-server-and-test": "^1.12.0",
"ts-node": "^9.1.1",
"tslib": "^2.1.0",
"typedoc": "^0.20.31",
"typescript": "^4.1.5",

View File

@ -27,8 +27,8 @@ function generateConfig(configType, format) {
}),
generateTypescript
? typescript({
browserslist: false,
})
browserslist: false,
})
: undefined,
babel({
exclude: '**/node_modules/**',

View File

@ -55,6 +55,12 @@ const BufferFromRawAccountData = coerce(
value => Buffer.from(value[0], 'base64'),
);
/**
* Attempt to use a recent blockhash for up to 30 seconds
* @internal
*/
export const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000;
type RpcRequest = (methodName: string, args: Array<any>) => any;
export type TokenAccountsFilter =
@ -2578,8 +2584,6 @@ export class Connection {
while (this._pollingBlockhash) {
await sleep(100);
}
// Attempt to use a recent blockhash for up to 30 seconds
const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000;
const timeSinceFetch = Date.now() - this._blockhashInfo.lastFetch;
const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
if (this._blockhashInfo.recentBlockhash !== null && !expired) {

View File

@ -154,7 +154,7 @@ if (process.env.TEST_LIVE) {
const {signatures, message} = parsedTx.transaction;
expect(signatures[0]).to.eq(signature);
const ix = message.instructions[0];
if (ix.parsed) {
if ('parsed' in ix) {
expect('parsed' in ix).to.eq(false);
} else {
expect(ix.programId).to.eql(program.publicKey);

View File

@ -5,8 +5,7 @@ import {clusterApiUrl} from '../src/util/cluster';
describe('Cluster Util', () => {
it('invalid', () => {
expect(() => {
// $FlowExpectedError
clusterApiUrl('abc123');
clusterApiUrl('abc123' as any);
}).to.throw();
});

View File

@ -1,4 +1,5 @@
import bs58 from 'bs58';
import invariant from 'assert';
import {Buffer} from 'buffer';
import {Token, u64} from '@solana/spl-token';
import {expect, use} from 'chai';
@ -18,7 +19,17 @@ import {
} from '../src';
import {DEFAULT_TICKS_PER_SLOT, NUM_TICKS_PER_SECOND} from '../src/timing';
import {MOCK_PORT, url} from './url';
import {BLOCKHASH_CACHE_TIMEOUT_MS} from '../src/connection';
import {
BLOCKHASH_CACHE_TIMEOUT_MS,
Commitment,
CompiledInnerInstruction,
EpochInfo,
EpochSchedule,
InflationGovernor,
ParsedInnerInstruction,
ParsedInstruction,
SlotInfo,
} from '../src/connection';
import {sleep} from '../src/util/sleep';
import {
helpers,
@ -66,14 +77,15 @@ describe('Connection', () => {
connection = new Connection(url);
});
if (!process.env.TEST_LIVE) {
if (mockServer) {
const server = mockServer;
beforeEach(() => {
mockServer.start(MOCK_PORT);
server.start(MOCK_PORT);
stubRpcWebSocket(connection);
});
afterEach(() => {
mockServer.stop();
server.stop();
restoreRpcWebSocket(connection);
});
}
@ -289,14 +301,15 @@ describe('Connection', () => {
});
const inflation = await connection.getInflationGovernor();
for (const key of [
const inflationKeys: (keyof InflationGovernor)[] = [
'initial',
'terminal',
'taper',
'foundation',
'foundationTerm',
]) {
];
for (const key of inflationKeys) {
expect(inflation).to.have.property(key);
expect(inflation[key]).to.be.greaterThan(0);
}
@ -316,14 +329,15 @@ describe('Connection', () => {
});
const epochInfo = await connection.getEpochInfo('confirmed');
for (const key of [
const epochInfoKeys: (keyof EpochInfo)[] = [
'epoch',
'slotIndex',
'slotsInEpoch',
'absoluteSlot',
'blockHeight',
]) {
];
for (const key of epochInfoKeys) {
expect(epochInfo).to.have.property(key);
expect(epochInfo[key]).to.be.at.least(0);
}
@ -343,13 +357,14 @@ describe('Connection', () => {
});
const epochSchedule = await connection.getEpochSchedule();
for (const key of [
const epochScheduleKeys: (keyof EpochSchedule)[] = [
'firstNormalEpoch',
'firstNormalSlot',
'leaderScheduleSlotOffset',
'slotsPerEpoch',
]) {
];
for (const key of epochScheduleKeys) {
expect(epochSchedule).to.have.property('warmup');
expect(epochSchedule).to.have.property(key);
if (epochSchedule.warmup) {
@ -385,7 +400,7 @@ describe('Connection', () => {
});
const slot = await connection.getSlot();
if (!process.env.TEST_LIVE) {
if (mockServer) {
expect(slot).to.eq(123);
} else {
// No idea what the correct slot value should be on a live cluster, so
@ -402,7 +417,7 @@ describe('Connection', () => {
});
const slotLeader = await connection.getSlotLeader();
if (!process.env.TEST_LIVE) {
if (mockServer) {
expect(slotLeader).to.eq('11111111111111111111111111111111');
} else {
// No idea what the correct slotLeader value should be on a live cluster, so
@ -427,7 +442,7 @@ describe('Connection', () => {
});
const clusterNodes = await connection.getClusterNodes();
if (!process.env.TEST_LIVE) {
if (mockServer) {
expect(clusterNodes).to.have.length(1);
expect(clusterNodes[0].pubkey).to.eq('11111111111111111111111111111111');
expect(typeof clusterNodes[0].gossip).to.eq('string');
@ -564,8 +579,8 @@ describe('Connection', () => {
// Find a block that has a transaction, usually Block 1
let slot = 0;
let address: ?PublicKey;
let expectedSignature: ?string;
let address: PublicKey | undefined;
let expectedSignature: string | undefined;
while (!address || !expectedSignature) {
slot++;
const block = await connection.getConfirmedBlock(slot);
@ -628,7 +643,7 @@ describe('Connection', () => {
{limit: 1},
);
expect(confirmedSignatures2).to.have.length(1);
if (!process.env.TEST_LIVE) {
if (mockServer) {
expect(confirmedSignatures2[0].signature).to.eq(expectedSignature);
expect(confirmedSignatures2[0].slot).to.eq(slot);
expect(confirmedSignatures2[0].err).to.be.null;
@ -699,7 +714,7 @@ describe('Connection', () => {
// Find a block that has a transaction, usually Block 1
let slot = 0;
let confirmedTransaction: ?string;
let confirmedTransaction: string | undefined;
while (!confirmedTransaction) {
slot++;
const block = await connection.getConfirmedBlock(slot);
@ -791,12 +806,12 @@ describe('Connection', () => {
expect(nullResponse).to.be.null;
});
if (!process.env.TEST_LIVE) {
if (mockServer) {
it('get parsed confirmed transaction coerces public keys of inner instructions', async () => {
const confirmedTransaction: TransactionSignature =
'4ADvAUQYxkh4qWKYE9QLW8gCLomGG94QchDLG4quvpBz1WqARYvzWQDDitKduAKspuy1DjcbnaDAnCAfnKpJYs48';
function getMockData(inner) {
function getMockData(inner: any) {
return {
slot: 353050305,
transaction: {
@ -853,15 +868,10 @@ describe('Connection', () => {
confirmedTransaction,
);
if (
result !== null &&
result.meta &&
result.meta.innerInstructions !== undefined &&
result.meta.innerInstructions.length > 0
) {
expect(
result.meta.innerInstructions[0].instructions[0].programId,
).to.be.instanceOf(PublicKey);
if (result && result.meta && result.meta.innerInstructions) {
const innerInstructions = result.meta.innerInstructions;
const firstIx = innerInstructions[0].instructions[0];
expect(firstIx.programId).to.be.instanceOf(PublicKey);
}
await mockRpcResponse({
@ -877,15 +887,21 @@ describe('Connection', () => {
}),
});
//$FlowFixMe
const result2 = await connection.getParsedConfirmedTransaction(
confirmedTransaction,
);
let instruction = result2.meta.innerInstructions[0].instructions[0];
expect(instruction.programId).to.be.instanceOf(PublicKey);
expect(instruction.accounts[0]).to.be.instanceOf(PublicKey);
expect(instruction.accounts[1]).to.be.instanceOf(PublicKey);
if (result2 && result2.meta && result2.meta.innerInstructions) {
const innerInstructions = result2.meta.innerInstructions;
const instruction = innerInstructions[0].instructions[0];
expect(instruction.programId).to.be.instanceOf(PublicKey);
if ('accounts' in instruction) {
expect(instruction.accounts[0]).to.be.instanceOf(PublicKey);
expect(instruction.accounts[1]).to.be.instanceOf(PublicKey);
} else {
expect('accounts' in instruction).to.be.true;
}
}
});
}
@ -998,7 +1014,8 @@ describe('Connection', () => {
});
it('get recent blockhash', async () => {
for (const commitment of ['processed', 'confirmed', 'finalized']) {
const commitments: Commitment[] = ['processed', 'confirmed', 'finalized'];
for (const commitment of commitments) {
const {blockhash, feeCalculator} = await helpers.recentBlockhash({
connection,
commitment,
@ -1189,7 +1206,7 @@ describe('Connection', () => {
testOwner = accountOwner;
testToken = token;
testTokenAccount = tokenAccount;
testTokenAccount = tokenAccount as PublicKey;
});
it('get token supply', async () => {
@ -1229,7 +1246,7 @@ describe('Connection', () => {
const {signatures, message} = parsedTx.transaction;
expect(signatures[0]).to.eq(testSignature);
const ix = message.instructions[0];
if (ix.parsed) {
if ('parsed' in ix) {
expect(ix.program).to.eq('spl-token');
expect(ix.programId).to.eql(TOKEN_PROGRAM_ID);
} else {
@ -1456,11 +1473,11 @@ describe('Connection', () => {
});
}
if (!process.env.TEST_LIVE) {
if (mockServer) {
it('stake activation should only accept state with valid string literals', async () => {
const publicKey = new Account().publicKey;
const addStakeActivationMock = async state => {
const addStakeActivationMock = async (state: any) => {
await mockRpcResponse({
method: 'getStakeActivation',
params: [publicKey.toBase58(), {}],
@ -1567,7 +1584,7 @@ describe('Connection', () => {
if (parsedAccountInfo === null) {
expect(parsedAccountInfo).not.to.be.null;
return;
} else if (parsedAccountInfo.data.parsed) {
} else if ('parsed' in parsedAccountInfo.data) {
expect(parsedAccountInfo.data.parsed).not.to.be.ok;
return;
}
@ -1616,6 +1633,7 @@ describe('Connection', () => {
).value;
expect(confirmResult.err).to.eql(expectedErr);
invariant(transaction.signature);
const signature = bs58.encode(transaction.signature);
await mockRpcResponse({
method: 'getSignatureStatuses',
@ -1814,7 +1832,7 @@ describe('Connection', () => {
});
// it('account change notification', async () => {
// if (!process.env.TEST_LIVE) {
// if (mockServer) {
// console.log('non-live test skipped');
// return;
// }
@ -1939,7 +1957,7 @@ describe('Connection', () => {
});
it('slot notification', async () => {
let notifiedSlotInfo;
let notifiedSlotInfo: SlotInfo | undefined;
const subscriptionId = connection.onSlotChange(slotInfo => {
notifiedSlotInfo = slotInfo;
});
@ -1963,7 +1981,7 @@ describe('Connection', () => {
});
it('root notification', async () => {
let roots = [];
let roots: number[] = [];
const subscriptionId = connection.onRootChange(root => {
roots.push(root);
});

View File

@ -1,20 +1,21 @@
import bs58 from 'bs58';
import BN from 'bn.js';
import invariant from 'assert';
import * as mockttp from 'mockttp';
import {mockRpcMessage} from './rpc-websockets';
import {Account, Connection, PublicKey, Transaction} from '../../src';
import type {Commitment} from '../../src/connection';
export const mockServer: mockttp.Mockttp =
process.env.TEST_LIVE || mockttp.getLocal();
export const mockServer: mockttp.Mockttp | undefined =
process.env.TEST_LIVE === undefined ? mockttp.getLocal() : undefined;
let uniqueCounter = 0;
export const uniqueSignature = () => {
return bs58.encode(new BN(++uniqueCounter).toArray(null, 64));
return bs58.encode(new BN(++uniqueCounter).toArray(undefined, 64));
};
export const uniqueBlockhash = () => {
return bs58.encode(new BN(++uniqueCounter).toArray(null, 32));
return bs58.encode(new BN(++uniqueCounter).toArray(undefined, 32));
};
export const mockErrorMessage = 'Invalid';
@ -30,13 +31,13 @@ export const mockRpcResponse = async ({
error,
withContext,
}: {
method: string,
params: Array<any>,
value?: any,
error?: any,
withContext?: boolean,
method: string;
params: Array<any>;
value?: any;
error?: any;
withContext?: boolean;
}) => {
if (process.env.TEST_LIVE) return;
if (!mockServer) return;
let result = value;
if (withContext) {
@ -70,8 +71,8 @@ const recentBlockhash = async ({
connection,
commitment,
}: {
connection: Connection,
commitment?: Commitment,
connection: Connection;
commitment?: Commitment;
}) => {
const blockhash = uniqueBlockhash();
const params = [];
@ -101,17 +102,18 @@ const processTransaction = async ({
commitment,
err,
}: {
connection: Connection,
transaction: Transaction,
signers: Array<Account>,
commitment: Commitment,
err?: any,
connection: Connection;
transaction: Transaction;
signers: Array<Account>;
commitment: Commitment;
err?: any;
}) => {
const blockhash = (await recentBlockhash({connection})).blockhash;
transaction.recentBlockhash = blockhash;
transaction.sign(...signers);
const encoded = transaction.serialize().toString('base64');
invariant(transaction.signature !== null);
const signature = bs58.encode(transaction.signature);
await mockRpcResponse({
method: 'sendTransaction',
@ -146,9 +148,9 @@ const airdrop = async ({
address,
amount,
}: {
connection: Connection,
address: PublicKey,
amount: number,
connection: Connection;
address: PublicKey;
amount: number;
}) => {
await mockRpcResponse({
method: 'requestAirdrop',

View File

@ -5,15 +5,15 @@ import sinon from 'sinon';
import {Connection} from '../../src';
type RpcRequest = {
method: string,
params?: Array<any>,
method: string;
params?: Array<any>;
};
type RpcResponse = {
context: {
slot: number,
},
value: any,
slot: number;
};
value: any;
};
const mockRpcSocket: Array<[RpcRequest, RpcResponse]> = [];
@ -24,9 +24,9 @@ export const mockRpcMessage = ({
params,
result,
}: {
method: string,
params: Array<any>,
result: any,
method: string;
params: Array<any>;
result: any;
}) => {
mockRpcSocket.push([
{method, params},
@ -46,9 +46,11 @@ export const stubRpcWebSocket = (connection: Connection) => {
sandbox.stub(rpcWebSocket, 'close').callsFake(() => {
mockClient.close();
});
sandbox.stub(rpcWebSocket, 'call').callsFake((method, params) => {
return mockClient.call(method, params);
});
sandbox
.stub(rpcWebSocket, 'call')
.callsFake((method: string, params: any) => {
return mockClient.call(method, params);
});
};
export const restoreRpcWebSocket = (connection: Connection) => {
@ -85,7 +87,10 @@ class MockClient {
call(method: string, params: Array<any>): Promise<Object> {
expect(mockRpcSocket.length).to.be.at.least(1);
const [mockRequest, mockResponse] = mockRpcSocket.shift();
const [mockRequest, mockResponse] = mockRpcSocket.shift() as [
RpcRequest,
RpcResponse,
];
expect(method).to.eq(mockRequest.method);
expect(params).to.eql(mockRequest.params);

View File

@ -31,14 +31,15 @@ describe('Nonce', () => {
connection = new Connection(url);
});
if (!process.env.TEST_LIVE) {
if (mockServer) {
const server = mockServer;
beforeEach(() => {
mockServer.start(MOCK_PORT);
server.start(MOCK_PORT);
stubRpcWebSocket(connection);
});
afterEach(() => {
mockServer.stop();
server.stop();
restoreRpcWebSocket(connection);
});
}

View File

@ -1,17 +1,18 @@
import alias from '@rollup/plugin-alias';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import flowRemoveTypes from 'flow-remove-types';
import json from '@rollup/plugin-json';
import multi from '@rollup/plugin-multi-entry';
import nodeResolve from '@rollup/plugin-node-resolve';
import nodePolyfills from 'rollup-plugin-node-polyfills';
import replace from '@rollup/plugin-replace';
const extensions = ['.js', '.ts'];
export default {
input: {
include: ['test/**/*.test.js'],
exclude: ['test/agent-manager.test.js', 'test/bpf-loader.test.js'],
include: ['test/**/*.test.ts'],
exclude: ['test/agent-manager.test.ts', 'test/bpf-loader.test.ts'],
},
external: ['node-forge', 'http2', '_stream_wrap'],
output: {
@ -20,16 +21,17 @@ export default {
sourcemap: true,
},
plugins: [
flow(),
multi(),
commonjs(),
nodeResolve({
browser: true,
preferBuiltins: false,
extensions,
dedupe: ['bn.js', 'buffer'],
}),
babel({
exclude: '**/node_modules/**',
extensions,
babelHelpers: 'runtime',
plugins: ['@babel/plugin-transform-runtime'],
}),
@ -54,18 +56,6 @@ export default {
}
},
treeshake: {
moduleSideEffects: path => path.endsWith('test.js'),
moduleSideEffects: path => path.endsWith('test.ts'),
},
};
// Using this instead of rollup-plugin-flow due to
// https://github.com/leebyron/rollup-plugin-flow/issues/5
function flow() {
return {
name: 'flow-remove-types',
transform: code => ({
code: flowRemoveTypes(code).toString(),
map: null,
}),
};
}

View File

@ -21,7 +21,7 @@ function checkEncodedArray(
describe('shortvec', () => {
it('decodeLength', () => {
let array = [];
let array: number[] = [];
checkDecodedArray(array, 0);
array = [5];
@ -47,7 +47,7 @@ describe('shortvec', () => {
});
it('encodeLength', () => {
let array = [];
let array: number[] = [];
let prevLength = 1;
checkEncodedArray(array, 0, prevLength, 1, [0]);
@ -63,7 +63,7 @@ describe('shortvec', () => {
checkEncodedArray(array, 0x7fff, (prevLength += 3), 3, [0xff, 0xff, 0x01]);
prevLength = checkEncodedArray(array, 0x200000, (prevLength += 4), 4, [
checkEncodedArray(array, 0x200000, (prevLength += 4), 4, [
0x80,
0x80,
0x80,

View File

@ -1,4 +1,5 @@
import base58 from 'bs58';
import invariant from 'assert';
import {expect} from 'chai';
import {
@ -18,14 +19,15 @@ describe('Transaction Payer', () => {
connection = new Connection(url);
});
if (!process.env.TEST_LIVE) {
if (mockServer) {
const server = mockServer;
beforeEach(() => {
mockServer.start(MOCK_PORT);
server.start(MOCK_PORT);
stubRpcWebSocket(connection);
});
afterEach(() => {
mockServer.stop();
server.stop();
restoreRpcWebSocket(connection);
});
}
@ -76,6 +78,7 @@ describe('Transaction Payer', () => {
commitment: 'confirmed',
});
invariant(transaction.signature);
const signature = base58.encode(transaction.signature);
await mockRpcResponse({

View File

@ -1,4 +1,5 @@
import bs58 from 'bs58';
import invariant from 'assert';
import {Buffer} from 'buffer';
import nacl from 'tweetnacl';
import {expect} from 'chai';
@ -9,6 +10,7 @@ import {Transaction} from '../src/transaction';
import {StakeProgram} from '../src/stake-program';
import {SystemProgram} from '../src/system-program';
import {Message} from '../src/message';
import {toBuffer} from '../src/util/to-buffer';
describe('Transaction', () => {
describe('compileMessage', () => {
@ -160,22 +162,17 @@ describe('Transaction', () => {
expect(partialTransaction).to.eql(transaction);
if (
partialTransaction.signatures[0].signature != null /* <-- pacify flow */
) {
partialTransaction.signatures[0].signature[0] = 0;
expect(() =>
partialTransaction.serialize({requireAllSignatures: false}),
).to.throw();
expect(() =>
partialTransaction.serialize({
verifySignatures: false,
requireAllSignatures: false,
}),
).not.to.throw();
} else {
throw new Error('unreachable');
}
invariant(partialTransaction.signatures[0].signature);
partialTransaction.signatures[0].signature[0] = 0;
expect(() =>
partialTransaction.serialize({requireAllSignatures: false}),
).to.throw();
expect(() =>
partialTransaction.serialize({
verifySignatures: false,
requireAllSignatures: false,
}),
).not.to.throw();
});
describe('dedupe', () => {
@ -261,7 +258,6 @@ describe('Transaction', () => {
const newTransaction = new Transaction({
recentBlockhash: orgTransaction.recentBlockhash,
feePayer: orgTransaction.feePayer,
signatures: orgTransaction.signatures,
}).add(transfer1, transfer2);
@ -451,7 +447,7 @@ describe('Transaction', () => {
// Serializing the message is allowed when signature array has null signatures
expectedTransaction.serializeMessage();
expectedTransaction.feePayer = null;
expectedTransaction.feePayer = undefined;
expectedTransaction.setSigners(sender.publicKey);
expect(expectedTransaction.signatures).to.have.length(1);
@ -510,7 +506,7 @@ describe('Transaction', () => {
tx.setSigners(from.publicKey);
const tx_bytes = tx.serializeMessage();
const signature = nacl.sign.detached(tx_bytes, from.secretKey);
tx.addSignature(from.publicKey, signature);
tx.addSignature(from.publicKey, toBuffer(signature));
expect(tx.verifySignatures()).to.be.true;
});
@ -532,7 +528,7 @@ describe('Transaction', () => {
tx.feePayer = from.publicKey;
const tx_bytes = tx.serializeMessage();
const signature = nacl.sign.detached(tx_bytes, from.secretKey);
tx.addSignature(from.publicKey, signature);
tx.addSignature(from.publicKey, toBuffer(signature));
expect(tx.verifySignatures()).to.be.true;
});
});

View File

@ -16,7 +16,11 @@
"isolatedModules": true,
"baseUrl": "src",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true
"noImplicitReturns": true,
"paths": {
// This is needed so that @solana/spl-token's @solana/web3.js doesn't conflict
"@solana/web3.js": ["."]
}
},
"include": ["src"]
}