import { getAccount, getAssociatedTokenAddress, TOKEN_PROGRAM_ID, } from '@solana/spl-token'; import { Connection, Keypair, PublicKey } from '@solana/web3.js'; import { AnchorProvider, BN, Program, Wallet } from '@staratlas/anchor'; import { CARGO_IDL, CargoPermissions, CargoPod, cargoPodDataEquals, CargoStatsDefinition, CargoType, } from '@staratlas/cargo'; import { CRAFTING_IDL, CraftingPermissions } from '@staratlas/crafting'; import { buildSendAndCheck, createTokenAccount, keypairToAsyncSigner, readFromRPCOrError, stringToByteArray, } from '@staratlas/data-source'; import { PLAYER_PROFILE_IDL } from '@staratlas/player-profile'; import { Faction, PROFILE_FACTION_IDL, ProfileFactionAccount, } from '@staratlas/profile-faction'; import { Game, GameState, SAGE_IDL, SagePermissions, SagePlayerProfile, Sector, SectorRing, Starbase, StarbasePlayer, } from '../src'; import { checkTokenBalance, createAndFundTokenAccounts, createCargoTypes, createManyMints, createProfile, SAGE_PROGRAM_ID, setupBaseCraftingAccounts, } from './helpers'; describe('Starbase Cargo', () => { const connection = new Connection('http://localhost:8899', 'confirmed'); const walletKeypair = Keypair.generate(); const walletSigner = keypairToAsyncSigner(walletKeypair); const provider = new AnchorProvider( connection, new Wallet(walletKeypair), AnchorProvider.defaultOptions(), ); const program = new Program(SAGE_IDL, SAGE_PROGRAM_ID, provider); const playerProfileProgram = new Program( PLAYER_PROFILE_IDL, new PublicKey('PprofUW1pURCnMW2si88GWPXEEK3Bvh9Tksy8WtnoYJ'), provider, ); const profileFactionProgram = new Program( PROFILE_FACTION_IDL, new PublicKey('pFACzkX2eSpAjDyEohD6i3VRJvREtH9ynbtM1DwVFsj'), provider, ); const craftingProgram = new Program( CRAFTING_IDL, new PublicKey('CRAFtUSjCW74gQtCS6LyJH33rhhVhdPhZxbPegE4Qwfq'), provider, ); const cargoProgram = new Program( CARGO_IDL, new PublicKey('CArGoi989iv3VL3xArrJXmYYDNhjwCX5ey5sY5KKwMG'), provider, ); const funder = keypairToAsyncSigner(Keypair.generate()); const authority = keypairToAsyncSigner(Keypair.generate()); const playerProfile = keypairToAsyncSigner(Keypair.generate()); // fleets stuff const _fleetSigner = keypairToAsyncSigner(Keypair.generate()); const _managePodSigner = keypairToAsyncSigner(Keypair.generate()); const _addRemoveCargoSigner = keypairToAsyncSigner(Keypair.generate()); let _sagePlayerProfileKey: PublicKey; let _starbaseKey: PublicKey; let _starbasePlayerKey: PublicKey; const FLEET_MANAGER = 2; const CARGO_POD_MANAGER = 1; const ADD_REMOVE_CARGO_MANAGER = 2; // Sector stuff const _game = keypairToAsyncSigner(Keypair.generate()); let _gameState: PublicKey; const _sectorProfile = keypairToAsyncSigner(Keypair.generate()); const _sectorSigner = keypairToAsyncSigner(Keypair.generate()); let _sectorKey: PublicKey; const SECTOR_MANAGER = 1; const _updatedRiskZones = { usturSecurityZone: { center: [new BN(-5), new BN(-5)], radius: new BN(1), } as never, oniSecurityZone: { center: [new BN(5), new BN(5)], radius: new BN(1), } as never, mudSecurityZone: { center: [new BN(1), new BN(1)], radius: new BN(1), } as never, highRiskZone: { center: [new BN(-1), new BN(-1)], radius: new BN(1), } as never, mediumRiskZone: { center: [new BN(0), new BN(0)], radius: new BN(20), } as never, }; // cargo stuff const _cargoStatsDefinitionSigner = keypairToAsyncSigner(Keypair.generate()); const _cargoMintKeys = [...Array(2).keys()].map(() => Keypair.generate()); let _starbasePod1: PublicKey; let _starbasePod2: PublicKey; const _cargoProfile = keypairToAsyncSigner(Keypair.generate()); const _definitionManagerKey = keypairToAsyncSigner(Keypair.generate()); const _cargoTypeManagerKey = keypairToAsyncSigner(Keypair.generate()); // crafting stuff const _craftingDomainSigner = keypairToAsyncSigner(Keypair.generate()); const _craftingFacilitySigner = keypairToAsyncSigner(Keypair.generate()); const _craftingProfile = keypairToAsyncSigner(Keypair.generate()); const _craftingSigner = keypairToAsyncSigner(Keypair.generate()); const CRAFTING_MANAGER = 1; const _createCargoStatsDefinition = async ( statsDefinitionSigner = _cargoStatsDefinitionSigner, ) => { await buildSendAndCheck( CargoStatsDefinition.initDefinition({ program: cargoProgram, profile: _cargoProfile.publicKey(), statsDefinition: statsDefinitionSigner, input: { cargoStats: 1, }, }), walletSigner, provider.connection, ); }; const _createGame = async () => { await buildSendAndCheck( Game.initGame(program, authority, _sectorProfile.publicKey(), _game), walletSigner, provider.connection, ); const game = await readFromRPCOrError( provider.connection, program, _game.publicKey(), Game, 'confirmed', ); const gameStateId = GameState.findAddress( program, _game.publicKey(), game.data.updateId.add(new BN(1)), ); _gameState = gameStateId[0]; const createGameStateIx = GameState.initGameState( program, _sectorSigner, _sectorProfile.publicKey(), _game.publicKey(), _gameState, { keyIndex: SECTOR_MANAGER, }, ); const updateGameIx = Game.updateGame( _game.publicKey(), program, _sectorSigner, _sectorProfile.publicKey(), SECTOR_MANAGER, undefined /** points */, undefined /** mints */, undefined /** vaults */, { domain: _craftingDomainSigner.publicKey() } /** crafting */, { statsDefinition: _cargoStatsDefinitionSigner.publicKey() } /** cargo */, _updatedRiskZones /** risk zones*/, ); const updateGameStateIx = GameState.updateGameState( program, _sectorSigner, _sectorProfile.publicKey(), _game.publicKey(), _gameState, SECTOR_MANAGER, { starbaseLevels: [ { starbaseLevelIndex: 6, faction: Faction.MUD as number, hp: new BN(1337), level: 6, sectorRingAvailable: SectorRing.Inner, recipeCategoryForLevel: PublicKey.default, oldRecipeForUpgrade: PublicKey.default, newRecipeForUpgrade: PublicKey.default, sp: new BN(7331), warpLaneMovementFee: new BN(7337), repairFee: new BN(999), repairEfficiency: 87, shieldRechargeRate: 78, shieldBreakDelay: 98, }, ], maxFleetSize: 64, } /** fleet */, ); const activateGameIx = GameState.activateGameState( program, _sectorSigner, _sectorProfile.publicKey(), _game.publicKey(), _gameState, { keyIndex: SECTOR_MANAGER, }, ); const sectorIx = Sector.registerSector( program, _sectorSigner, _sectorProfile.publicKey(), PublicKey.default /** TODO: what should this be? */, _game.publicKey(), [new BN(1), new BN(1)], 'Super Sector', SECTOR_MANAGER, ); _sectorKey = sectorIx.sectorKey[0]; await buildSendAndCheck( [ createGameStateIx, updateGameIx, updateGameStateIx, activateGameIx, sectorIx.instructions, ].flat(), walletSigner, provider.connection, ); }; const _createStarbase = async () => { const sectorAcc = await readFromRPCOrError( provider.connection, program, _sectorKey, Sector, 'confirmed', ); await buildSendAndCheck( Starbase.registerStarbase( program, _fleetSigner, _sectorProfile.publicKey(), _sectorKey, _game.publicKey(), _gameState, { name: stringToByteArray('Starbase Alpha', 64), subCoordinates: [new BN(1), new BN(1)], starbaseLevelIndex: 6, faction: Faction.MUD, sectorCoordinates: sectorAcc.data.coordinates as [BN, BN], keyIndex: FLEET_MANAGER, }, ), walletSigner, provider.connection, ); _starbaseKey = Starbase.findAddress( program, _game.publicKey(), sectorAcc.data.coordinates as [BN, BN], )[0]; }; const _createSagePlayerProfile = async () => { await buildSendAndCheck( SagePlayerProfile.registerSagePlayerProfile( program, playerProfile.publicKey(), _game.publicKey(), _gameState, ), walletSigner, provider.connection, ); _sagePlayerProfileKey = SagePlayerProfile.findAddress( program, playerProfile.publicKey(), _game.publicKey(), )[0]; }; const _createStarbasePlayer = async () => { const starbaseSeqId = 0; await buildSendAndCheck( StarbasePlayer.registerStarbasePlayer( program, ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _sagePlayerProfileKey, _starbaseKey, _game.publicKey(), _gameState, starbaseSeqId, ), walletSigner, provider.connection, ); _starbasePlayerKey = StarbasePlayer.findAddress( program, _starbaseKey, _sagePlayerProfileKey, starbaseSeqId, )[0]; }; beforeAll(async () => { const airdropTx = await connection.requestAirdrop( walletSigner.publicKey(), 500_000_000_000, ); await connection.confirmTransaction(airdropTx); const airdropTx2 = await connection.requestAirdrop( funder.publicKey(), 500_000_000_000, ); await connection.confirmTransaction(airdropTx2); // create mints await createManyMints( _cargoMintKeys, authority.publicKey(), walletSigner, provider.connection, ); // create player profile await createProfile( playerProfileProgram, profileFactionProgram, playerProfile, funder, [ { key: _managePodSigner.publicKey(), expireTime: null, scope: program.programId, permissions: SagePermissions.manageCargoPodPermissions(), }, { key: _addRemoveCargoSigner.publicKey(), expireTime: null, scope: program.programId, permissions: SagePermissions.addRemoveCargoPermissions(), }, ], provider.connection, authority, walletSigner, ); // create sector profile await createProfile( playerProfileProgram, profileFactionProgram, _sectorProfile, funder, [ { key: _sectorSigner.publicKey(), expireTime: null, scope: program.programId, permissions: SagePermissions.all(), }, { key: _fleetSigner.publicKey(), expireTime: null, scope: program.programId, permissions: SagePermissions.manageStarbasePermissions(), }, ], provider.connection, authority, walletSigner, ); // create crafting profile await createProfile( playerProfileProgram, profileFactionProgram, _craftingProfile, funder, [ { key: _craftingSigner.publicKey(), expireTime: null, scope: craftingProgram.programId, permissions: CraftingPermissions.all(), }, ], provider.connection, authority, walletSigner, ); // create cargo profile await createProfile( playerProfileProgram, profileFactionProgram, _cargoProfile, funder, [ { key: _definitionManagerKey.publicKey(), expireTime: null, scope: cargoProgram.programId, permissions: CargoPermissions.definitionPermissions(), }, { key: _cargoTypeManagerKey.publicKey(), expireTime: null, scope: cargoProgram.programId, permissions: CargoPermissions.cargoTypePermissions(), }, ], provider.connection, walletSigner, ); await _createCargoStatsDefinition(); await setupBaseCraftingAccounts( _craftingDomainSigner, _craftingFacilitySigner, walletSigner, [...Array(2).keys()].map(() => _craftingSigner), _craftingProfile.publicKey(), [...Array(2).keys()].map(() => CRAFTING_MANAGER), Starbase.findAddress(program, _game.publicKey(), [ new BN(1), new BN(1), ])[0], provider.connection, craftingProgram, ); await _createGame(); await _createStarbase(); await _createSagePlayerProfile(); await _createStarbasePlayer(); await createCargoTypes( _cargoMintKeys.map((it) => it.publicKey), _cargoStatsDefinitionSigner.publicKey(), _cargoTypeManagerKey, _cargoProfile.publicKey(), walletSigner, 0, { keyIndex: 2, values: [new BN(1)], }, provider.connection, cargoProgram, ); // create and fund admin wallet token accounts await Promise.all([ createAndFundTokenAccounts( authority, _cargoMintKeys.map((it) => [it.publicKey, 10000]), _addRemoveCargoSigner.publicKey(), funder, walletSigner, provider.connection, ), ]); }); it('can create cargo pod at Star Base', async function () { const podSeedBuffer = Keypair.generate().publicKey.toBuffer(); const podSeedBuffer2 = Keypair.generate().publicKey.toBuffer(); const podSeeds = Array.from(podSeedBuffer); const podSeeds2 = Array.from(podSeedBuffer2); const ix = StarbasePlayer.createCargoPod( program, cargoProgram, _starbasePlayerKey, _managePodSigner, playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _starbaseKey, _cargoStatsDefinitionSigner.publicKey(), _game.publicKey(), _gameState, { keyIndex: CARGO_POD_MANAGER, podSeeds, }, ); const ix2 = StarbasePlayer.createCargoPod( program, cargoProgram, _starbasePlayerKey, _managePodSigner, playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _starbaseKey, _cargoStatsDefinitionSigner.publicKey(), _game.publicKey(), _gameState, { keyIndex: CARGO_POD_MANAGER, podSeeds: podSeeds2, }, ); await buildSendAndCheck( [ix, ix2].flat(), walletSigner, provider.connection, ); const pod1AddressResults = CargoPod.findAddress( cargoProgram, podSeedBuffer, ); _starbasePod1 = pod1AddressResults[0]; const pod2AddressResults = CargoPod.findAddress( cargoProgram, podSeedBuffer2, ); _starbasePod2 = pod2AddressResults[0]; const cargoPod1 = await readFromRPCOrError( provider.connection, cargoProgram, _starbasePod1, CargoPod, 'confirmed', ); expect( cargoPodDataEquals(cargoPod1.data, { podSeeds, version: 0, statsDefinition: _cargoStatsDefinitionSigner.publicKey(), authority: _starbasePlayerKey, openTokenAccounts: 0, podBump: pod1AddressResults[1], seqId: 0, unupdatedTokenAccounts: 0, }), ).toBe(true); }); it('can add cargo to game', async function () { // create and fund pod token accounts await Promise.all([ createAndFundTokenAccounts( authority, _cargoMintKeys.map((it) => [it.publicKey, 0]), _starbasePod1, funder, walletSigner, provider.connection, ), ]); const mint = _cargoMintKeys[0]; if (mint) { const tokenFrom = await getAssociatedTokenAddress( mint.publicKey, _addRemoveCargoSigner.publicKey(), true, ); const tokenTo = await getAssociatedTokenAddress( mint.publicKey, _starbasePod1, true, ); const amount = new BN(10); const ix = StarbasePlayer.depositCargoToGame( program, cargoProgram, _starbasePlayerKey, _addRemoveCargoSigner, playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _starbaseKey, _starbasePod1, CargoType.findAddress( cargoProgram, _cargoStatsDefinitionSigner.publicKey(), mint.publicKey, 0, )[0], _cargoStatsDefinitionSigner.publicKey(), tokenFrom, tokenTo, _game.publicKey(), _gameState, { amount, keyIndex: ADD_REMOVE_CARGO_MANAGER, }, ); await buildSendAndCheck(ix, walletSigner, provider.connection); await checkTokenBalance( tokenFrom, new BN(10000).sub(amount), provider.connection, ); await checkTokenBalance( tokenTo, new BN(0).add(amount), provider.connection, ); } else { throw 'mint does not exist'; } }); it('cannot add cargo to an auxiliary token account', async () => { const mint = _cargoMintKeys[0]; if (!mint) { throw 'mint does not exist'; } // create auxiliary token account owned by `_starbasePod1` const auxTokenTo = keypairToAsyncSigner(Keypair.generate()); await buildSendAndCheck( createTokenAccount(auxTokenTo, _starbasePod1, mint.publicKey), walletSigner, provider.connection, ); // confirm token account exists const axuTokenAccount = await getAccount( connection, auxTokenTo.publicKey(), 'confirmed', TOKEN_PROGRAM_ID, ); expect(axuTokenAccount.mint.equals(mint.publicKey)).toBe(true); expect(axuTokenAccount.owner.equals(_starbasePod1)).toBe(true); // confirm that deposit fails const tokenFrom = await getAssociatedTokenAddress( mint.publicKey, _addRemoveCargoSigner.publicKey(), true, ); let success = true; try { await buildSendAndCheck( StarbasePlayer.depositCargoToGame( program, cargoProgram, _starbasePlayerKey, _addRemoveCargoSigner, playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _starbaseKey, _starbasePod1, CargoType.findAddress( cargoProgram, _cargoStatsDefinitionSigner.publicKey(), mint.publicKey, 0, )[0], _cargoStatsDefinitionSigner.publicKey(), tokenFrom, auxTokenTo.publicKey(), _game.publicKey(), _gameState, { amount: new BN(1), keyIndex: ADD_REMOVE_CARGO_MANAGER, }, ), walletSigner, provider.connection, ); } catch (err) { expect(JSON.stringify(err as Error)).toContain('AddressMismatch'); success = false; } expect(success).toBe(false); }); it('can transfer cargo between Starbase pods', async function () { // create and fund pod token accounts await Promise.all([ createAndFundTokenAccounts( authority, _cargoMintKeys.map((it) => [it.publicKey, 0]), _starbasePod2, funder, walletSigner, provider.connection, ), ]); const mint = _cargoMintKeys[0]; if (mint) { const tokenFrom = await getAssociatedTokenAddress( mint.publicKey, _starbasePod1, true, ); const tokenTo = await getAssociatedTokenAddress( mint.publicKey, _starbasePod2, true, ); const amount = new BN(10); const ix = StarbasePlayer.transferCargoAtStarbase( program, cargoProgram, _starbasePlayerKey, _managePodSigner, funder.publicKey(), playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _starbaseKey, _starbasePod1, _starbasePod2, CargoType.findAddress( cargoProgram, _cargoStatsDefinitionSigner.publicKey(), mint.publicKey, 0, )[0], _cargoStatsDefinitionSigner.publicKey(), tokenFrom, tokenTo, mint.publicKey, _game.publicKey(), _gameState, { amount, keyIndex: CARGO_POD_MANAGER, }, ); await buildSendAndCheck(ix, walletSigner, provider.connection); await checkTokenBalance( tokenTo, new BN(0).add(amount), provider.connection, ); let success = true; try { await checkTokenBalance( tokenFrom, new BN(0).sub(amount), provider.connection, ); } catch (err) { expect((err as Error).message).toContain( 'failed to get token account balance: Invalid param: could not find account', ); success = false; } expect(success).toBe(false); } else { throw 'mint does not exist'; } }); it('cannot transfer cargo to an auxiliary token account', async () => { const mint = _cargoMintKeys[0]; if (!mint) { throw 'mint does not exist'; } // create and fund _starbasePod1 token account (tokenFrom) that was deleted in previous test await Promise.all([ createAndFundTokenAccounts( authority, [[mint.publicKey, 0]], _starbasePod1, funder, walletSigner, provider.connection, ), ]); // create auxiliary token account owned by `_starbasePod2` const auxTokenTo = keypairToAsyncSigner(Keypair.generate()); await buildSendAndCheck( createTokenAccount(auxTokenTo, _starbasePod2, mint.publicKey), walletSigner, provider.connection, ); // confirm token account exists const axuTokenAccount = await getAccount( connection, auxTokenTo.publicKey(), 'confirmed', TOKEN_PROGRAM_ID, ); expect(axuTokenAccount.mint.equals(mint.publicKey)).toBe(true); expect(axuTokenAccount.owner.equals(_starbasePod2)).toBe(true); // confirm that transfer fails const tokenFrom = await getAssociatedTokenAddress( mint.publicKey, _starbasePod1, true, ); let success = true; try { await buildSendAndCheck( StarbasePlayer.transferCargoAtStarbase( program, cargoProgram, _starbasePlayerKey, _managePodSigner, funder.publicKey(), playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _starbaseKey, _starbasePod1, _starbasePod2, CargoType.findAddress( cargoProgram, _cargoStatsDefinitionSigner.publicKey(), mint.publicKey, 0, )[0], _cargoStatsDefinitionSigner.publicKey(), tokenFrom, auxTokenTo.publicKey(), mint.publicKey, _game.publicKey(), _gameState, { amount: new BN(1), keyIndex: CARGO_POD_MANAGER, }, ), walletSigner, provider.connection, ); } catch (err) { expect(JSON.stringify(err as Error)).toContain('AddressMismatch'); success = false; } expect(success).toBe(false); }); it('can remove cargo from game', async function () { const mint = _cargoMintKeys[0]; if (mint) { const tokenFrom = await getAssociatedTokenAddress( mint.publicKey, _starbasePod2, true, ); const tokenTo = await getAssociatedTokenAddress( mint.publicKey, _addRemoveCargoSigner.publicKey(), true, ); const amount = new BN(10); const ix = StarbasePlayer.withdrawCargoFromGame( program, cargoProgram, _starbasePlayerKey, _addRemoveCargoSigner, funder.publicKey(), playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _starbaseKey, _starbasePod2, CargoType.findAddress( cargoProgram, _cargoStatsDefinitionSigner.publicKey(), mint.publicKey, 0, )[0], _cargoStatsDefinitionSigner.publicKey(), tokenFrom, tokenTo, mint.publicKey, _game.publicKey(), _gameState, { amount, keyIndex: ADD_REMOVE_CARGO_MANAGER, }, ); await buildSendAndCheck(ix, walletSigner, provider.connection); await checkTokenBalance(tokenTo, new BN(10000), provider.connection); let success = true; try { await checkTokenBalance( tokenFrom, new BN(0).sub(amount), provider.connection, ); } catch (err) { expect((err as Error).message).toContain( 'failed to get token account balance: Invalid param: could not find account', ); success = false; } expect(success).toBe(false); } else { throw 'mint does not exist'; } }); it('can close token account owned by Starbase cargo pod', async function () { const mint = _cargoMintKeys[0]; if (mint) { const auxToken = keypairToAsyncSigner(Keypair.generate()); await buildSendAndCheck( [ createTokenAccount(auxToken, _starbasePod2, mint.publicKey), StarbasePlayer.closeStarbaseCargoTokenAccount( program, cargoProgram, _starbasePlayerKey, _addRemoveCargoSigner, funder.publicKey(), playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], _starbaseKey, _starbasePod2, CargoType.findAddress( cargoProgram, _cargoStatsDefinitionSigner.publicKey(), mint.publicKey, 0, )[0], _cargoStatsDefinitionSigner.publicKey(), auxToken.publicKey(), mint.publicKey, _game.publicKey(), _gameState, { keyIndex: ADD_REMOVE_CARGO_MANAGER, }, ), ], walletSigner, provider.connection, ); const tokenInfo = await connection.getAccountInfo( auxToken.publicKey(), 'processed', ); expect(tokenInfo).toBeNull(); } else { throw 'mint does not exist'; } }); it('can remove cargo pod at Star Base', async function () { const ixs = [_starbasePod1, _starbasePod2].map((it) => StarbasePlayer.removeCargoPod( program, cargoProgram, _starbasePlayerKey, _managePodSigner, playerProfile.publicKey(), ProfileFactionAccount.findAddress( profileFactionProgram, playerProfile.publicKey(), )[0], funder.publicKey(), _starbaseKey, it, _game.publicKey(), _gameState, { keyIndex: CARGO_POD_MANAGER, }, ), ); await buildSendAndCheck( (await Promise.all(ixs)).flat(), walletSigner, provider.connection, ); const accounts = await Promise.all( [_starbasePod1, _starbasePod2].map((it) => provider.connection.getAccountInfo(it, 'confirmed'), ), ); for (let index = 0; index < accounts.length; index++) { const element = accounts[index]; expect(element).toBeNull; } }); });