Testing TypeScript Server Runtime Code with Jest #
This guide shows you how to configure and write tests for your TypeScript server runtime code using the popular Jest JavaScript Testing framework.
Writing tests for your code ensures that your code behaves as expected and safe guards you from making breaking changes in the future without realizing.
Configuring your TypeScript server project for Jest #
To write Jest tests you need to install a few different packages.
|
|
In your tsconfig.json
file add the following to your compilerOptions
section:
|
|
In your package.json
add a new "test"
script:
|
|
Also add a new section for "jest"
:
|
|
Finally create a jest-config.ts
in the root of your project (or the path specified in the "setupFiles"
section of your config).
|
|
Writing a testable RPC #
This is an example RPC that a player might call to add an item to their inventory. The inventory in this case is an entry in the Nakama Storage Engine.
The code will check the incoming payload to ensure it meets specific criteria and at all potential failure points the RPC will log the error and return an appropriate failure response to the user.
Create a file called rpc-add-item.ts
.
|
|
Writing the first test #
Create a file called rpc-add-item.test.ts
with the following imports.
|
|
These imports allow you to create mocks of the Nakama server runtime types and functions. This allows you to test your code in isolation and under carefully crafted scenarios, without interacting with Nakama.
Create a describe
block which allows you to group together related tests. Inside, define variables for the various mock objects we need to call our RPC.
|
|
Next create a beforeEach
block. The function you pass in will be run before each test. This is useful if you need to do some setup before a test. Here you will use this to configure the mock objects you defined earlier.
|
|
The createMock
function takes a generic type using the <>
syntax to determine what type the mock should be. It will then proceed to create an object of that type with default/empty values for all of that type’s properties. You can override specific property values by passing an object into the function, such as the userId
property above.
You will notice that you configured 3 specific functions to act as Jest mock functions (using the On
function made available via ts-auto-mock/extension
): logger.error
, nk.storageRead
and nk.storageWrite
.
This is so that you can verify that these functions have been called with specific values depending on the test scenario.
Now you will write your first test. This test will check to make sure that the RPC returns a failure response with a specific error message when the payload passed to it is null
.
|
|
Here you:
- Call the
AddItemRpc
function, passing in the mocked objects you defined andsnull
for the payload - Get the result as a JSON object using
JSON.parse
- Define the expected error response string
Using the expect
function you then verify that the:
resultPayload.success
value isfalse
resultPayload.error
value is the expected error string'no payload provided'
logger.error
function was called with the same error message
To run your tests:
|
|
If you run this test you should see that it passes.
You can verify that this test is indeed working by changing the expectedError
value to something else and re-running the test. For example, changing the value to 'payload provided'
will result in the following Jest output.
|
|
Mocking the return value of Nakama functions #
Often when writing tests you will want to mock the return value of a particular function in order to change the outcome of the code being tested. With Jest this is possible through the use of various mockReturnValue
functions.
In the following test, the mockReturnValueOnce
function is used on the mockNkStorageWrite
(as a jest.Mock
type) function to force it to return null
. This in turn means that the AddItemRpc
function should fail and return a failure response.
|
|
The mockReturnValueOnce
function can be used to return any value from the mocked function and can therefore be used to completely change the result of the test.
Consider the following two examples:
|
|
|
|
In the first, the response of the nk.storageRead
call is mocked to return no results, effectively emulating a response from Nakama that no storage objects exist for the specified collection, key, and user.
The second returns an array with a single object, indicating that the player’s current inventory contains 3 Diamond Pickaxes.
This is useful as it allows you to test how the RPC behaves when the player’s inventory is in different states.
Full example #
Below is the full code for the rpc-add-item.test.ts
file covering various different success and failure scenarios.
|
|