Skip to content

Commit 0c04fab

Browse files
committed
Add tests
Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com>
1 parent e5c893d commit 0c04fab

1 file changed

Lines changed: 177 additions & 0 deletions

File tree

src/SmartTransactionsController.test.ts

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,183 @@ describe('SmartTransactionsController', () => {
723723
});
724724
});
725725

726+
it('should acquire nonce for Swap transactions only', async () => {
727+
// Create a mock for getNonceLock
728+
const mockGetNonceLock = jest.fn().mockResolvedValue({
729+
nextNonce: 'nextNonce',
730+
nonceDetails: { test: 'details' },
731+
releaseLock: jest.fn(),
732+
});
733+
734+
await withController(
735+
{
736+
options: {
737+
getNonceLock: mockGetNonceLock,
738+
},
739+
},
740+
async ({ controller }) => {
741+
const signedTransaction = createSignedTransaction();
742+
const submitTransactionsApiResponse =
743+
createSubmitTransactionsApiResponse();
744+
745+
// First API mock for the case without nonce
746+
nock(API_BASE_URL)
747+
.post(
748+
`/networks/${ethereumChainIdDec}/submitTransactions?stxControllerVersion=${packageJson.version}`,
749+
)
750+
.reply(200, submitTransactionsApiResponse);
751+
752+
// Second API mock for the case with nonce
753+
nock(API_BASE_URL)
754+
.post(
755+
`/networks/${ethereumChainIdDec}/submitTransactions?stxControllerVersion=${packageJson.version}`,
756+
)
757+
.reply(200, submitTransactionsApiResponse);
758+
759+
// Case 1: Swap transaction without nonce (should call getNonceLock)
760+
const txParamsWithoutNonce = {
761+
...createTxParams(),
762+
nonce: undefined, // Explicitly undefined nonce
763+
};
764+
765+
await controller.submitSignedTransactions({
766+
signedTransactions: [signedTransaction],
767+
txParams: txParamsWithoutNonce,
768+
// No transactionMeta means type defaults to 'swap'
769+
});
770+
771+
// Verify getNonceLock was called for the Swap
772+
expect(mockGetNonceLock).toHaveBeenCalledTimes(1);
773+
expect(mockGetNonceLock).toHaveBeenCalledWith(
774+
txParamsWithoutNonce.from,
775+
NetworkType.mainnet,
776+
);
777+
778+
// Reset the mock
779+
mockGetNonceLock.mockClear();
780+
781+
// Case 2: Transaction with nonce already set (should NOT call getNonceLock)
782+
const txParamsWithNonce = createTxParams(); // This has nonce: '0'
783+
784+
await controller.submitSignedTransactions({
785+
signedTransactions: [signedTransaction],
786+
txParams: txParamsWithNonce,
787+
});
788+
789+
// Verify getNonceLock was NOT called for transaction with nonce
790+
expect(mockGetNonceLock).not.toHaveBeenCalled();
791+
},
792+
);
793+
});
794+
795+
it('should properly set nonce on txParams and mark transaction as swap type', async () => {
796+
// Mock with a specific nextNonce value we can verify
797+
const mockGetNonceLock = jest.fn().mockResolvedValue({
798+
nextNonce: 42,
799+
nonceDetails: { test: 'nonce details' },
800+
releaseLock: jest.fn(),
801+
});
802+
803+
await withController(
804+
{
805+
options: {
806+
getNonceLock: mockGetNonceLock,
807+
},
808+
},
809+
async ({ controller }) => {
810+
const signedTransaction = createSignedTransaction();
811+
const submitTransactionsApiResponse =
812+
createSubmitTransactionsApiResponse();
813+
nock(API_BASE_URL)
814+
.post(
815+
`/networks/${ethereumChainIdDec}/submitTransactions?stxControllerVersion=${packageJson.version}`,
816+
)
817+
.reply(200, submitTransactionsApiResponse);
818+
819+
// Create txParams without nonce
820+
const txParamsWithoutNonce = {
821+
...createTxParams(),
822+
nonce: undefined,
823+
from: addressFrom,
824+
};
825+
826+
await controller.submitSignedTransactions({
827+
signedTransactions: [signedTransaction],
828+
txParams: txParamsWithoutNonce,
829+
// No transactionMeta provided, should default to 'swap' type
830+
});
831+
832+
// Get the created smart transaction
833+
const createdSmartTransaction =
834+
controller.state.smartTransactionsState.smartTransactions[
835+
ChainId.mainnet
836+
][0];
837+
838+
// Verify nonce was set correctly on the txParams in the created transaction
839+
expect(createdSmartTransaction.txParams.nonce).toBe('0x42'); // 42 as a hex string
840+
841+
// Verify transaction type is set to 'swap' by default
842+
expect(createdSmartTransaction.type).toBe('swap');
843+
844+
// Verify nonceDetails were passed correctly
845+
expect(createdSmartTransaction.nonceDetails).toEqual({
846+
test: 'nonce details',
847+
});
848+
},
849+
);
850+
});
851+
852+
it('should handle errors when acquiring nonce lock', async () => {
853+
// Mock getNonceLock to reject with an error
854+
const mockError = new Error('Failed to acquire nonce');
855+
const mockGetNonceLock = jest.fn().mockRejectedValue(mockError);
856+
857+
// Spy on console.error to verify it's called
858+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
859+
860+
await withController(
861+
{
862+
options: {
863+
getNonceLock: mockGetNonceLock,
864+
},
865+
},
866+
async ({ controller }) => {
867+
const signedTransaction = createSignedTransaction();
868+
const submitTransactionsApiResponse =
869+
createSubmitTransactionsApiResponse();
870+
nock(API_BASE_URL)
871+
.post(
872+
`/networks/${ethereumChainIdDec}/submitTransactions?stxControllerVersion=${packageJson.version}`,
873+
)
874+
.reply(200, submitTransactionsApiResponse);
875+
876+
// Create txParams without nonce
877+
const txParamsWithoutNonce = {
878+
...createTxParams(),
879+
nonce: undefined,
880+
from: addressFrom,
881+
};
882+
883+
// Attempt to submit a transaction that will fail when acquiring nonce
884+
await expect(
885+
controller.submitSignedTransactions({
886+
signedTransactions: [signedTransaction],
887+
txParams: txParamsWithoutNonce,
888+
}),
889+
).rejects.toThrow('Failed to acquire nonce');
890+
891+
// Verify error was logged
892+
expect(consoleErrorSpy).toHaveBeenCalledWith(
893+
'Failed to acquire nonce lock:',
894+
mockError,
895+
);
896+
897+
// Cleanup spy
898+
consoleErrorSpy.mockRestore();
899+
},
900+
);
901+
});
902+
726903
it('submits a batch of signed transactions', async () => {
727904
await withController(async ({ controller }) => {
728905
const signedTransaction1 = createSignedTransaction();

0 commit comments

Comments
 (0)