JMAP::Tester - a JMAP client made for testing JMAP servers


version 0.026


Achtung! This library is in its really early days, so use it with that in mind.

JMAP::Tester is for testing JMAP servers. Okay? Okay!

JMAP::Tester calls the whole thing you get back from a JMAP server a "response" if it's an HTTP 200. Every JSON Array (of three entries -- go read the spec if you need to!) is called a Sentence. Runs of Sentences with the same client id are called Paragraphs.

You use the test client like this:

  my $jtest = JMAP::Tester->new({
    api_uri => 'https://jmap.local/account/123',

  my $response = $jtest->request([
    [ getMailboxes => {} ],
    [ getMessageUpdates => { sinceState => "123" } ],

  # This returns two Paragraph objects if there are exactly two paragraphs.
  # Otherwise, it throws an exception.
  my ($mbx_p, $msg_p) = $response->assert_n_paragraphs(2);

  # These get the single Sentence of each paragraph, asserting that there is
  # exactly one Sentence in each Paragraph, and that it's of the given type.
  my $mbx = $mbx_p->single('mailboxes');
  my $msg = $msg_p->single('messageUpdates');

  is( @{ $mbx->arguments->{list} }, 10, "we expect 10 mailboxes");
  ok( ! $msg->arguments->{hasMoreUpdates}, "we got all the msg updates needed");

By default, all the structures returned have been passed through JSON::Typist, so you may want to strip their type data before using normal Perl code on them. You can do that with:

  my $struct = $response->as_triples;  # gets the complete JSON data
  $jtest->strip_json_types( $struct ); # strips all the JSON::Typist types

Or more simply:

  my $struct = $response->as_stripped_triples;

There is also "as_stripped_pairs" in JMAP::Tester::Response.



This is an arrayref of strings that specify which capabilities the client wishes to use. (See for more info). By default, JMAP::Tester will not send a 'using' parameter.


This is a hashref of arguments to be put into each method call. It's especially useful for setting a default accountId. Values given in methods passed to request will override defaults. If the value is a reference to undef, then no value will be passed for that key.

In other words, in this situation:

  my $tester = JMAP::Tester->new({
    default_arguments => { a => 1, b => 2, c => 3 },

    [ eatPies => { a => 100, b => \undef } ],

The request will effectively be:

  [ [ "eatPies", { "a": 100, "c": 3 }, "a" ] ]


This method will return a list of pairs mapping accountIds to accounts as provided by the client session object if any have been configured.



  my $account_id = $tester->primary_account_for($using);

This returns the primary accountId to be used for the given capability, or undef if none is available. This is only useful if the tester has been configured from a client session.


  my $result = $jtest->request([
    [ methodOne => { ... } ],
    [ methodTwo => { ... } ],

This method accepts either an arrayref of method calls or a hashref with a methodCalls key. It sends the calls to the JMAP server and returns a result.

For each method call, if there's a third element (a client id) then it's left as-is. If no client id is given, one is generated. You can mix explicit and autogenerated client ids. They will never conflict.

The arguments to methods are JSON-encoded with a JSON::Typist-aware encoder, so JSON::Typist types can be used to ensure string or number types in the generated JSON. If an argument is a reference to undef, it will be removed before the method call is made. This lets you override a default by omission.

The return value is an object that does the JMAP::Tester::Result role, meaning it's got an is_success method that returns true or false. For now, at least, failures are JMAP::Tester::Result::Failure objects. More refined failure objects may exist in the future. Successful requests return JMAP::Tester::Response objects.

Before the JMAP request is made, each triple is passed to a method called munge_method_triple, which can tweak the method however it likes.


  my $result = $tester->upload(\%arg);

Required arguments are:

  accountId - the account for which we're uploading (no default)
  type      - the content-type we want to provide to the server
  blob      - the data to upload. Must be a reference to a string

This uploads the given blob.

The return value will either be a failure object or an upload result.


  my $result = $tester->download(\%arg);

Valid arguments are:

  blobId    - the blob to download (no default)
  accountId - the account for which we're downloading (no default)
  type      - the content-type we want the server to provide back (no default)
  name      - the name we want the server to provide back (default: "download")

If the download URI template has a blobId, accountId, or type placeholder but no argument for that is given to download, an exception will be thrown.

The return value will either be a failure object or an upload result.


  my $auth_struct = $tester->simple_auth($username, $password);



This method fetches the content at the authentication endpoint and uses it to configure the tester's target URIs and signing keys.



Given a client session object (like those stored in an Auth result), this reconfigures the testers access token, signing keys, URIs, and so forth. This method is used internally when logging in.



This method attempts to log out from the server by sending a DELETE request to the authentication URI.


Ricardo SIGNES <>


  • Alfie John <>

  • Matthew Horsfall <>

  • Matthew Horsfall <>

  • Michael McClimon <>


This software is copyright (c) 2016 by FastMail, Ltd.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.