diff --git a/src/Lunr/Vortex/JPush/JPushPayload.php b/src/Lunr/Vortex/JPush/JPushPayload.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7f48cdf3fabd53a99c0f003c12c8e107596bfa5
--- /dev/null
+++ b/src/Lunr/Vortex/JPush/JPushPayload.php
@@ -0,0 +1,274 @@
+<?php
+
+/**
+ * This file contains functionality to generate JPush Notification payloads.
+ *
+ * @package    Lunr\Vortex\JPush
+ * @author     Sean Molenaar <s.molenaar@m2mobi.com>
+ * @copyright  2020, M2Mobi BV, Amsterdam, The Netherlands
+ * @license    http://lunr.nl/LICENSE MIT License
+ */
+
+namespace Lunr\Vortex\JPush;
+
+use ReflectionClass;
+
+/**
+ * JPush Notification Payload Generator.
+ */
+class JPushPayload
+{
+
+    /**
+     * Array of Push Notification elements.
+     * @var array
+     */
+    protected $elements;
+
+    /**
+     * Supported push platforms
+     * @var array
+     */
+    const PLATFORMS = ['ios', 'android'];
+
+    /**
+     * Constructor.
+     */
+    public function __construct()
+    {
+        $this->elements = [];
+
+        $this->elements['platform']     = self::PLATFORMS;
+        $this->elements['audience']     = [];
+        $this->elements['notification'] = [];
+
+        $this->set_priority(JPushPriority::HIGH);
+    }
+
+    /**
+     * Destructor.
+     */
+    public function __destruct()
+    {
+        unset($this->elements);
+    }
+
+    /**
+     * Construct the payload for the push notification.
+     *
+     * @return array JPushPayload
+     */
+    public function get_payload()
+    {
+        return $this->elements;
+    }
+
+    /**
+     * Sets the notification targets by notification ID.
+     *
+     * @param string[] $ids The endpoint IDs
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_registration_ids($ids)
+    {
+        $this->elements['audience']['registration_id'] = $ids;
+
+        return $this;
+    }
+
+    /**
+     * Sets the notification identifier.
+     *
+     * @param string $identifier The notification identifier
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_notification_identifier($identifier)
+    {
+        $this->elements['cid'] = $identifier;
+
+        return $this;
+    }
+
+    /**
+     * Sets the notification message payload.
+     *
+     * @param string $message The notification body
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_body($message)
+    {
+        return $this->set_notification_data('alert', $message);
+    }
+
+    /**
+     * Sets the notification title payload.
+     *
+     * @param string $message The notification title
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_title($message)
+    {
+        return $this->set_notification_data('title', $message);
+    }
+
+    /**
+     * Sets the payload key data.
+     *
+     * The fields of data represent the key-value pairs of the message's payload data.
+     *
+     * @param array $data The actual notification information
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_data($data)
+    {
+        return $this->set_notification_data('extras', $data);
+    }
+
+    /**
+     * Sets the payload category data.
+     *
+     * @param string category The notification category
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_category($category)
+    {
+        return $this->set_notification_data('category', $category);
+    }
+
+    /**
+     * Sets the payload sound data.
+     *
+     * @param string category The notification sound
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_sound($sound)
+    {
+        return $this->set_notification_data('sound', $sound);
+    }
+
+    /**
+     * Sets the notification as providing content.
+     *
+     * @param boolean $val Value for the "content_available" field.
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_content_available($val)
+    {
+        return $this->set_notification_data('content-available', $val, ['ios']);
+    }
+
+    /**
+     * Mark the notification as mutable.
+     *
+     * @param boolean $mutable Notification mutable_content value.
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_mutable_content($mutable)
+    {
+        return $this->set_notification_data('mutable-content', $mutable, ['ios']);
+    }
+
+    /**
+     * Mark the notification priority.
+     *
+     * @param JPushPriority $priority Notification priority value.
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_priority($priority)
+    {
+        $priority_class = new ReflectionClass('\Lunr\Vortex\JPush\JPushPriority');
+        $priorities     = array_values($priority_class->getConstants());
+        if (in_array($priority, $priorities, TRUE))
+        {
+            $this->set_notification_data('priority', $priority);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Sets the payload key time_to_live.
+     *
+     * It defines how long (in seconds) the message should be kept on JPush storage,
+     * if the device is offline.
+     *
+     * @param integer $ttl The time in seconds for the notification to stay alive
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_time_to_live($ttl)
+    {
+        $this->set_options('time_to_live', $ttl);
+
+        return $this;
+    }
+
+    /**
+     * Sets the payload key collapse_key.
+     *
+     * An arbitrary string that is used to collapse a group of alike messages
+     * when the device is offline, so that only the last message gets sent to the client.
+     *
+     * @param string $key The notification collapse key identifier
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_collapse_key($key)
+    {
+        $this->set_options('apns_collapse_id', $key);
+
+        return $this;
+    }
+
+    /**
+     * Set additional JPush values in the 'options' key.
+     *
+     * @param string $key   Options key.
+     * @param string $value Options value.
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_options($key, $value)
+    {
+        if (!isset($this->elements['options']))
+        {
+            $this->elements['options'] = [];
+        }
+
+        $this->elements['options'][$key] = $value;
+
+        return $this;
+    }
+
+    /**
+     * Set notification value for one or more platforms.
+     *
+     * @param string   $key       The key in the notification->platform object.
+     * @param mixed    $value     The value accompanying that key.
+     * @param string[] $platforms The platforms to apply this to.
+     *
+     * @return JPushPayload Self Reference
+     */
+    public function set_notification_data($key, $value, $platforms = self::PLATFORMS)
+    {
+        foreach ($platforms as $platform)
+        {
+            $this->elements['notification'][$platform][$key] = $value;
+        }
+
+        return $this;
+    }
+
+}
+
+?>
diff --git a/src/Lunr/Vortex/JPush/JPushPriority.php b/src/Lunr/Vortex/JPush/JPushPriority.php
new file mode 100644
index 0000000000000000000000000000000000000000..06200552482706e683758ec7666c86d4b41de403
--- /dev/null
+++ b/src/Lunr/Vortex/JPush/JPushPriority.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * This file contains priority types for delivering JPush Notifications.
+ *
+ * @package    Lunr\Vortex\JPush
+ * @author     Sean Molenaar <s.molenaar@m2mobi.com>
+ * @copyright  2020, M2Mobi BV, Amsterdam, The Netherlands
+ * @license    http://lunr.nl/LICENSE MIT License
+ */
+
+namespace Lunr\Vortex\JPush;
+
+/**
+ * JPush Notification Priority Types.
+ */
+class JPushPriority
+{
+
+    /**
+     * Deliver notification immediately.
+     * @var string
+     */
+    const HIGH = 2;
+
+    /**
+     * Deliver notification with medium priority.
+     * @var string
+     */
+    const MEDIUM = 1;
+
+    /**
+     * Deliver notification with normal priority.
+     * @var string
+     */
+    const NORMAL = 0;
+
+    /**
+     * Deliver notification with low priority.
+     * @var string
+     */
+    const LOW = -1;
+
+    /**
+     * Deliver notification with no priority.
+     * @var string
+     */
+    const NONE = -2;
+
+}
+
+?>
diff --git a/src/Lunr/Vortex/JPush/Tests/JPushPayloadBaseTest.php b/src/Lunr/Vortex/JPush/Tests/JPushPayloadBaseTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ce1874366d6d2b0967b37bad9e81435b3d1de02
--- /dev/null
+++ b/src/Lunr/Vortex/JPush/Tests/JPushPayloadBaseTest.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * This file contains the JPushPayloadBaseTest class.
+ *
+ * @package    Lunr\Vortex\JPush
+ * @author     Sean Molenaar <s.molenaar@m2mobi.com>
+ * @copyright  2020, M2Mobi BV, Amsterdam, The Netherlands
+ * @license    http://lunr.nl/LICENSE MIT License
+ */
+
+namespace Lunr\Vortex\JPush\Tests;
+
+/**
+ * This class contains the Base tests of the JPushPayload class.
+ *
+ * @covers \Lunr\Vortex\JPush\JPushPayload
+ */
+class JPushPayloadBaseTest extends JPushPayloadTest
+{
+
+    /**
+     * Test elements is initialized with high priority.
+     */
+    public function testElementsIsInitializedWithHighPriority(): void
+    {
+        $this->assertPropertySame('elements', [
+            'platform' => [ 'ios', 'android' ],
+            'audience' => [],
+            'notification' => [
+                'ios' => [ 'priority' => 2 ],
+                'android' => [ 'priority' => 2 ],
+            ]
+        ]);
+    }
+
+}
+
+?>
diff --git a/src/Lunr/Vortex/JPush/Tests/JPushPayloadGetTest.php b/src/Lunr/Vortex/JPush/Tests/JPushPayloadGetTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6271e085af72c929740170f878a272b1ee20e88
--- /dev/null
+++ b/src/Lunr/Vortex/JPush/Tests/JPushPayloadGetTest.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * This file contains the JPushPayloadGetTest class.
+ *
+ * @package    Lunr\Vortex\JPush
+ * @author     Sean Molenaar <s.molenaar@m2mobi.com>
+ * @copyright  2020, M2Mobi BV, Amsterdam, The Netherlands
+ * @license    http://lunr.nl/LICENSE MIT License
+ */
+
+namespace Lunr\Vortex\JPush\Tests;
+
+/**
+ * This class contains tests for the getters of the JPushPayload class.
+ *
+ * @covers \Lunr\Vortex\JPush\JPushPayload
+ */
+class JPushPayloadGetTest extends JPushPayloadTest
+{
+
+    /**
+     * Test get_payload() with collapse_key being present.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::get_payload
+     */
+    public function testGetPayloadWithCollapseKey(): void
+    {
+        $file     = TEST_STATICS . '/Vortex/gcm/collapse_key.json';
+        $elements = [ 'collapse_key' => 'test' ];
+
+        $this->set_reflection_property_value('elements', $elements);
+
+        $this->assertStringMatchesFormatFile($file, json_encode($this->class->get_payload()));
+    }
+
+    /**
+     * Test get_payload() with data being present.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::get_payload
+     */
+    public function testGetPayloadWithData(): void
+    {
+        $file     = TEST_STATICS . '/Vortex/gcm/data.json';
+        $elements = [
+            'data' => [
+                'key1' => 'value1',
+                'key2' => 'value2',
+            ],
+        ];
+
+        $this->set_reflection_property_value('elements', $elements);
+
+        $this->assertStringMatchesFormatFile($file, json_encode($this->class->get_payload()));
+    }
+
+    /**
+     * Test get_payload() with time_to_live being present.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::get_payload
+     */
+    public function testGetPayloadWithTimeToLive(): void
+    {
+        $file     = TEST_STATICS . '/Vortex/gcm/time_to_live.json';
+        $elements = [ 'time_to_live' => 10 ];
+
+        $this->set_reflection_property_value('elements', $elements);
+
+        $this->assertStringMatchesFormatFile($file, json_encode($this->class->get_payload()));
+    }
+
+    /**
+     * Test get_payload() with everything being present.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::get_payload
+     */
+    public function testGetPayload(): void
+    {
+        $file     = TEST_STATICS . '/Vortex/gcm/gcm.json';
+        $elements = [
+            'registration_ids' => [ 'one', 'two', 'three' ],
+            'collapse_key'     => 'test',
+            'data'             => [
+                'key1' => 'value1',
+                'key2' => 'value2',
+            ],
+            'time_to_live'     => 10,
+        ];
+
+        $this->set_reflection_property_value('elements', $elements);
+
+        $this->assertStringMatchesFormatFile($file, json_encode($this->class->get_payload()));
+    }
+
+}
+
+?>
diff --git a/src/Lunr/Vortex/JPush/Tests/JPushPayloadSetTest.php b/src/Lunr/Vortex/JPush/Tests/JPushPayloadSetTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..cc405eb55bb1f203b6e9e1c7471046027f12f8ad
--- /dev/null
+++ b/src/Lunr/Vortex/JPush/Tests/JPushPayloadSetTest.php
@@ -0,0 +1,365 @@
+<?php
+
+/**
+ * This file contains the JPushPayloadSetTest class.
+ *
+ * @package    Lunr\Vortex\JPush
+ * @author     Sean Molenaar <s.molenaar@m2mobi.com>
+ * @copyright  2020, M2Mobi BV, Amsterdam, The Netherlands
+ * @license    http://lunr.nl/LICENSE MIT License
+ */
+
+namespace Lunr\Vortex\JPush\Tests;
+
+/**
+ * This class contains tests for the setters of the JPushPayload class.
+ *
+ * @covers \Lunr\Vortex\JPush\JPushPayload
+ */
+class JPushPayloadSetTest extends JPushPayloadTest
+{
+
+    /**
+     * Test set_collapse_key() works correctly.
+     *
+     * @covers Lunr\Vortex\JPush\JPushPayload::set_collapse_key
+     */
+    public function testSetCollapseKey(): void
+    {
+        $this->class->set_collapse_key('test');
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('apns_collapse_id', $value['options']);
+        $this->assertEquals('test', $value['options']['apns_collapse_id']);
+    }
+
+    /**
+     * Test fluid interface of set_collapse_key().
+     *
+     * @covers Lunr\Vortex\JPush\JPushPayload::set_collapse_key
+     */
+    public function testSetCollapseKeyReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_collapse_key('collapse_key'));
+    }
+
+    /**
+     * Test set_time_to_live() works correctly.
+     *
+     * @covers Lunr\Vortex\JPush\JPushPayload::set_time_to_live
+     */
+    public function testSetTimeToLive(): void
+    {
+        $this->class->set_time_to_live(5);
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('time_to_live', $value['options']);
+        $this->assertEquals(5, $value['options']['time_to_live']);
+    }
+
+    /**
+     * Test fluid interface of set_time_to_live().
+     *
+     * @covers Lunr\Vortex\JPush\JPushPayload::set_time_to_live
+     */
+    public function testSetTimeToLiveReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_time_to_live('time_to_live'));
+    }
+
+    /**
+     * Test set_priority() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_priority
+     */
+    public function testSetPriority(): void
+    {
+        $this->class->set_priority(1);
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('priority', $value['notification']['android']);
+        $this->assertEquals(1, $value['notification']['android']['priority']);
+    }
+
+    /**
+     * Test set_priority() works correctly with an invalid priority.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_priority
+     */
+    public function testSetPriorityInvalid(): void
+    {
+        $this->class->set_priority('cow');
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('priority', $value['notification']['android']);
+        $this->assertEquals(2, $value['notification']['android']['priority']);
+    }
+
+    /**
+     * Test fluid interface of set_priority().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_priority
+     */
+    public function testSetPriorityReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_priority('high'));
+    }
+
+    /**
+     * Test set_mutable_content() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_mutable_content
+     */
+    public function testSetMutableContent(): void
+    {
+        $this->class->set_mutable_content(TRUE);
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('mutable-content', $value['notification']['ios']);
+        $this->assertEquals(TRUE, $value['notification']['ios']['mutable-content']);
+    }
+
+    /**
+     * Test fluid interface of set_mutable_content().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_mutable_content
+     */
+    public function testSetMutableContentReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_mutable_content(TRUE));
+    }
+
+    /**
+     * Test set_data() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_data
+     */
+    public function testSetData(): void
+    {
+        $this->class->set_data([ 'key' => 'value' ]);
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('extras', $value['notification']['android']);
+        $this->assertEquals([ 'key' => 'value' ], $value['notification']['android']['extras']);
+    }
+
+    /**
+     * Test fluid interface of set_data().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_data
+     */
+    public function testSetDataReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_data('data'));
+    }
+
+    /**
+     * Test set_content_available() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_content_available
+     */
+    public function testSetContentAvailable(): void
+    {
+        $this->class->set_content_available(TRUE);
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('content-available', $value['notification']['ios']);
+        $this->assertEquals(TRUE, $value['notification']['ios']['content-available']);
+    }
+
+    /**
+     * Test fluid interface of set_content_available().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_content_available
+     */
+    public function testSetContentAvailableReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_content_available(TRUE));
+    }
+
+    /**
+     * Test set_notification_identifier() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_notification_identifier
+     */
+    public function testSetNotificationIdentifier(): void
+    {
+        $this->class->set_notification_identifier('ID');
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('cid', $value);
+        $this->assertEquals('ID', $value['cid']);
+    }
+
+    /**
+     * Test fluid interface of set_notification_identifier().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_notification_identifier
+     */
+    public function testSetNotificationIdentifierReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_notification_identifier('ID'));
+    }
+
+    /**
+     * Test set_registration_ids() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_registration_ids
+     */
+    public function testSetRegistrationIDs(): void
+    {
+        $this->class->set_registration_ids(['ID']);
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('registration_id', $value['audience']);
+        $this->assertEquals(['ID'], $value['audience']['registration_id']);
+    }
+
+    /**
+     * Test fluid interface of set_registration_ids().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_registration_ids
+     */
+    public function testSetRegistrationIDsReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_registration_ids(['ID']));
+    }
+
+    /**
+     * Test set_body() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_body
+     */
+    public function testSetBody(): void
+    {
+        $this->class->set_body('BODY');
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('alert', $value['notification']['android']);
+        $this->assertEquals('BODY', $value['notification']['android']['alert']);
+    }
+
+    /**
+     * Test fluid interface of set_body().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_body
+     */
+    public function testSetBodyReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_body('body'));
+    }
+
+    /**
+     * Test set_title() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_title
+     */
+    public function testSetTitle(): void
+    {
+        $this->class->set_title('Title');
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('title', $value['notification']['android']);
+        $this->assertEquals('Title', $value['notification']['android']['title']);
+    }
+
+    /**
+     * Test fluid interface of set_title().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_title
+     */
+    public function testSetTitleReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_title('title'));
+    }
+
+    /**
+     * Test set_category() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_category
+     */
+    public function testSetCategory(): void
+    {
+        $this->class->set_category('cats');
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('category', $value['notification']['android']);
+        $this->assertEquals('cats', $value['notification']['android']['category']);
+    }
+
+    /**
+     * Test fluid interface of set_category().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_category
+     */
+    public function testSetCategoryReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_category('cats'));
+    }
+
+    /**
+     * Test set_sound() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_sound
+     */
+    public function testSetSound(): void
+    {
+        $this->class->set_sound('sound');
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('sound', $value['notification']['android']);
+        $this->assertEquals('sound', $value['notification']['android']['sound']);
+    }
+
+    /**
+     * Test fluid interface of set_sound().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_sound
+     */
+    public function testSetSoundReturnsSelfReference(): void
+    {
+        $this->assertSame($this->class, $this->class->set_sound('sound'));
+    }
+
+    /**
+     * Test set_content_available() works correctly.
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_content_available
+     */
+    public function testSetOptions()
+    {
+        $this->class->set_options('analytics_label', 'fooBar');
+
+        $value = $this->get_reflection_property_value('elements');
+
+        $this->assertArrayHasKey('options', $value);
+        $this->assertArrayHasKey('analytics_label', $value['options']);
+        $this->assertEquals('fooBar', $value['options']['analytics_label']);
+    }
+
+    /**
+     * Test fluid interface of set_content_available().
+     *
+     * @covers \Lunr\Vortex\JPush\JPushPayload::set_content_available
+     */
+    public function testSetOptionsReturnsSelfReference()
+    {
+        $this->assertSame($this->class, $this->class->set_options('analytics_label', 'fooBar'));
+    }
+
+}
+
+?>
diff --git a/src/Lunr/Vortex/JPush/Tests/JPushPayloadTest.php b/src/Lunr/Vortex/JPush/Tests/JPushPayloadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ad34def199939ee7082c520cb85a813778151ddf
--- /dev/null
+++ b/src/Lunr/Vortex/JPush/Tests/JPushPayloadTest.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * This file contains the JPushPayloadTest class.
+ *
+ * @package    Lunr\Vortex\JPush
+ * @author     Sean Molenaar <s.molenaar@m2mobi.com>
+ * @copyright  2020, M2Mobi BV, Amsterdam, The Netherlands
+ * @license    http://lunr.nl/LICENSE MIT License
+ */
+
+namespace Lunr\Vortex\JPush\Tests;
+
+use Lunr\Halo\LunrBaseTest;
+use ReflectionClass;
+
+/**
+ * This class contains common setup routines, providers
+ * and shared attributes for testing the JPushPayload class.
+ *
+ * @covers Lunr\Vortex\JPush\JPushPayload
+ */
+class JPushPayloadTest extends LunrBaseTest
+{
+
+    /**
+     * Sample payload json
+     * @var string
+     */
+    protected $payload;
+
+    /**
+     * Testcase Constructor.
+     */
+    public function setUp(): void
+    {
+        $elements_array = [
+            'registration_ids' => [ 'one', 'two', 'three' ],
+            'collapse_key'     => 'test',
+            'data'             => [
+                'key1' => 'value1',
+                'key2' => 'value2',
+            ],
+            'time_to_live'     => 10,
+        ];
+
+        $this->payload = json_encode($elements_array);
+
+        $this->class = $this->getMockBuilder('Lunr\Vortex\JPush\JPushPayload')
+                            ->getMockForAbstractClass();
+
+        $this->reflection = new ReflectionClass('Lunr\Vortex\JPush\JPushPayload');
+    }
+
+    /**
+     * Testcase Destructor.
+     */
+    public function tearDown(): void
+    {
+        unset($this->payload);
+        unset($this->class);
+        unset($this->reflection);
+    }
+
+}
+
+?>
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index 0aa5ffccb95840e401a8347a2435c9d1b05f0f79..38d9942241065ffa4d8320ab8926f0241648d360 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -320,6 +320,9 @@
             <file>../src/Lunr/Vortex/FCM/Tests/FCMDispatcherBaseTest.php</file>
             <file>../src/Lunr/Vortex/FCM/Tests/FCMDispatcherSetTest.php</file>
             <file>../src/Lunr/Vortex/FCM/Tests/FCMDispatcherPushTest.php</file>
+            <file>../src/Lunr/Vortex/JPush/Tests/JPushPayloadBaseTest.php</file>
+            <file>../src/Lunr/Vortex/JPush/Tests/JPushPayloadGetTest.php</file>
+            <file>../src/Lunr/Vortex/JPush/Tests/JPushPayloadSetTest.php</file>
             <file>../src/Lunr/Vortex/MPNS/Tests/MPNSPayloadTest.php</file>
             <file>../src/Lunr/Vortex/MPNS/Tests/MPNSPayloadSetTest.php</file>
             <file>../src/Lunr/Vortex/MPNS/Tests/MPNSPayloadGetTest.php</file>
@@ -389,6 +392,7 @@
                 <directory>../src/Lunr/Vortex/APNS/ApnsPHP/Tests/</directory>
                 <directory>../src/Lunr/Vortex/Email/Tests/</directory>
                 <directory>../src/Lunr/Vortex/FCM/Tests/</directory>
+                <directory>../src/Lunr/Vortex/JPush/Tests/</directory>
                 <directory>../src/Lunr/Vortex/Email/Tests/</directory>
                 <directory>../src/Lunr/Vortex/MPNS/Tests/</directory>
                 <directory>../src/Lunr/Vortex/WNS/Tests/</directory>
