diff --git a/tests/unit/Newsletter/Links/LinksTest.php b/tests/unit/Newsletter/Links/LinksTest.php
new file mode 100644
index 0000000000..7fbb4d47aa
--- /dev/null
+++ b/tests/unit/Newsletter/Links/LinksTest.php
@@ -0,0 +1,105 @@
+some site http://link2.com
';
+ $result = Links::extract($template);
+
+ expect($result[0])->equals(
+ array(
+ 'html' => 'href="http://link1.com"',
+ 'link' => 'http://link1.com'
+ )
+ );
+ }
+
+ function testItCanExtactLinkShortcodes() {
+ $template = '[notlink:shortcode] [link:some_link_shortcode]';
+ $result = Links::extract($template);
+
+ expect($result[0])->equals(
+ array(
+ 'html' => '[link:some_link_shortcode]',
+ 'link' => '[link:some_link_shortcode]'
+ )
+ );
+ }
+
+ function testItHashesAndReplacesLinks() {
+ $template = 'some site [link:some_link_shortcode]';
+ list($updated_content, $hashed_links) = Links::process($template);
+
+ // 2 links were hashed
+ expect(count($hashed_links))->equals(2);
+ // links in returned content were replaced with hashes
+ expect($updated_content)
+ ->contains(Links::DATA_TAG_CLICK . '-' . $hashed_links[0]['hash']);
+ expect($updated_content)
+ ->contains(Links::DATA_TAG_CLICK . '-' . $hashed_links[1]['hash']);
+ expect($updated_content)->notContains('link');
+ }
+
+ function testItReplacesHashedLinksWithSubscriberData() {
+ $subscriber = Subscriber::create();
+ $subscriber->hydrate(Fixtures::get('subscriber_template'));
+ $subscriber->save();
+ $queue = SendingQueue::create();
+ $queue->newsletter_id = 1;
+ $queue->save();
+ $template = 'some site
';
+ $result = Links::replaceSubscriberData($subscriber->id, $queue->id, $template);
+
+ // there are no click/open data tags
+ expect($result)->notContains(Links::DATA_TAG_CLICK);
+ expect($result)->notContains(Links::DATA_TAG_OPEN);
+
+ // data tags were converted to URLs
+ expect($result)
+ ->regExp('//');
+
+ // data was base64encoded, serialized and contains an array of variables
+ preg_match_all('/data=(?P.*?)"/', $result, $result);
+ foreach($result['data'] as $data) {
+ $data = unserialize(base64_decode($data));
+ expect($data['subscriber_id'])->equals($subscriber->id);
+ expect($data['queue_id'])->equals($queue->id);
+ expect(isset($data['subscriber_token']))->true();
+ }
+ }
+
+ function testItCanSaveLinks() {
+ $links = array(
+ array(
+ 'url' => 'http://example.com',
+ 'hash' => 123
+ )
+ );
+ Links::save(
+ $links,
+ $newletter_id = 1,
+ $queue_id = 1
+ );
+
+ // 1 database record was created
+ $newsltter_link = NewsletterLink::where('newsletter_id', 1)
+ ->where('queue_id', 1)
+ ->findOne();
+ expect($newsltter_link->hash)->equals(123);
+ expect($newsltter_link->url)->equals('http://example.com');
+ }
+
+ function _after() {
+ ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
+ ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
+ ORM::raw_execute('TRUNCATE ' . NewsletterLink::$_table);
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php
index b282bf6d30..2dd0a2ac87 100644
--- a/tests/unit/_bootstrap.php
+++ b/tests/unit/_bootstrap.php
@@ -35,3 +35,12 @@ Fixtures::add(
'newsletter_subject_template',
'Newsletter for [subscriber:firstname]'
);
+
+Fixtures::add(
+ 'subscriber_template',
+ array(
+ 'first_name' => 'John',
+ 'last_name' => 'John',
+ 'email' => 'john.doe@example.com'
+ )
+);
\ No newline at end of file