diff --git a/lib/private/Template/CSSResourceLocator.php b/lib/private/Template/CSSResourceLocator.php
index 087ddec38ef6bf2430ae71b98db40d720cd34068..3c30a9d33564afe35931b39084420f70d79666ef 100644
--- a/lib/private/Template/CSSResourceLocator.php
+++ b/lib/private/Template/CSSResourceLocator.php
@@ -76,6 +76,11 @@ class CSSResourceLocator extends ResourceLocator {
 			return;
 		}
 
+		// Account for the possibility of having symlinks in app path. Doing
+		// this here instead of above as an empty argument to realpath gets
+		// turned into cwd.
+		$app_path = realpath($app_path);
+
 		if(!$this->cacheAndAppendScssIfExist($app_path, $style.'.scss', $app)) {
 			$this->append($app_path, $style.'.css', $app_url);
 		}
diff --git a/lib/private/Template/JSResourceLocator.php b/lib/private/Template/JSResourceLocator.php
index 9a2e08482141176a1c0601eb3dd08d46709d15fa..d38488e46188de1e217c04cd6e823c8de7919d40 100644
--- a/lib/private/Template/JSResourceLocator.php
+++ b/lib/private/Template/JSResourceLocator.php
@@ -76,6 +76,13 @@ class JSResourceLocator extends ResourceLocator {
 		$app_path = \OC_App::getAppPath($app);
 		$app_url = \OC_App::getAppWebPath($app);
 
+		if ($app_path !== false) {
+			// Account for the possibility of having symlinks in app path. Only
+			// do this if $app_path is set, because an empty argument to realpath
+			// gets turned into cwd.
+			$app_path = realpath($app_path);
+		}
+
 		// missing translations files fill be ignored
 		if (strpos($script, 'l10n/') === 0) {
 			$this->appendIfExist($app_path, $script . '.js', $app_url);
diff --git a/tests/lib/Template/CSSResourceLocatorTest.php b/tests/lib/Template/CSSResourceLocatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a16cc18cb0a6676f4e2a49e83c172da107680091
--- /dev/null
+++ b/tests/lib/Template/CSSResourceLocatorTest.php
@@ -0,0 +1,150 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Kyle Fazzari <kyrofa@ubuntu.com>
+ *
+ * @author Kyle Fazzari <kyrofa@ubuntu.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as
+ *  published by the Free Software Foundation, either version 3 of the
+ *  License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\Template;
+
+use OC\Files\AppData\Factory;
+use OCP\ILogger;
+use OCP\IURLGenerator;
+use OCP\IConfig;
+use OCA\Theming\ThemingDefaults;
+use OCP\ICache;
+use OC\Template\SCSSCacher;
+use OC\Template\CSSResourceLocator;
+
+class CSSResourceLocatorTest extends \Test\TestCase {
+	/** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */
+	protected $appData;
+	/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
+	protected $urlGenerator;
+	/** @var SystemConfig|\PHPUnit_Framework_MockObject_MockObject */
+	protected $config;
+	/** @var ThemingDefaults|\PHPUnit_Framework_MockObject_MockObject */
+	protected $themingDefaults;
+	/** @var ICache|\PHPUnit_Framework_MockObject_MockObject */
+	protected $depsCache;
+	/** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
+	protected $logger;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$this->logger = $this->createMock(ILogger::class);
+		$this->appData = $this->createMock(IAppData::class);
+		$this->urlGenerator = $this->createMock(IURLGenerator::class);
+		$this->config = $this->createMock(IConfig::class);
+		$this->depsCache = $this->createMock(ICache::class);
+		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
+	}
+
+	private function cssResourceLocator() {
+		/** @var Factory|\PHPUnit_Framework_MockObject_MockObject $factory */
+                $factory = $this->createMock(Factory::class);
+                $factory->method('get')->with('css')->willReturn($this->appData);
+		$scssCacher = new SCSSCacher(
+			$this->logger,
+			$factory,
+			$this->urlGenerator,
+			$this->config,
+			$this->themingDefaults,
+			\OC::$SERVERROOT,
+			$this->depsCache
+		);
+		return new CSSResourceLocator(
+			$this->logger,
+			'theme',
+			array('core'=>'map'),
+			array('3rd'=>'party'),
+			$scssCacher
+		);
+	}
+
+	private function rrmdir($directory) {
+		$files = array_diff(scandir($directory), array('.','..'));
+		foreach ($files as $file) {
+			if (is_dir($directory . '/' . $file)) {
+				$this->rrmdir($directory . '/' . $file);
+			} else {
+				unlink($directory . '/' . $file);
+			}
+		}
+		return rmdir($directory);
+	}
+
+	private function randomString() {
+		return sha1(uniqid(mt_rand(), true));
+	}
+
+	public function testConstructor() {
+		$locator = $this->cssResourceLocator();
+		$this->assertAttributeEquals('theme', 'theme', $locator);
+		$this->assertAttributeEquals('core', 'serverroot', $locator);
+		$this->assertAttributeEquals(array('core'=>'map','3rd'=>'party'), 'mapping', $locator);
+		$this->assertAttributeEquals('3rd', 'thirdpartyroot', $locator);
+		$this->assertAttributeEquals('map', 'webroot', $locator);
+		$this->assertAttributeEquals(array(), 'resources', $locator);
+	}
+
+	public function testFindWithAppPathSymlink() {
+		// First create new apps path, and a symlink to it
+		$apps_dirname = $this->randomString();
+		$new_apps_path = sys_get_temp_dir() . '/' . $apps_dirname;
+		$new_apps_path_symlink = $new_apps_path . '_link';
+		mkdir($new_apps_path);
+		symlink($apps_dirname, $new_apps_path_symlink);
+
+		// Create an app within that path
+		mkdir($new_apps_path . '/' . 'test-css-app');
+
+		// Use the symlink as the app path
+		\OC::$APPSROOTS[] = [
+                        'path' => $new_apps_path_symlink,
+                        'url' => '/css-apps-test',
+                        'writable' => false,
+                ];
+
+		$locator = $this->cssResourceLocator();
+		$locator->find(array('test-css-app/test-file'));
+
+		$resources = $locator->getResources();
+		$this->assertCount(1, $resources);
+		$resource = $resources[0];
+		$this->assertCount(3, $resource);
+		$root = $resource[0];
+		$webRoot = $resource[1];
+		$file = $resource[2];
+
+		$expectedRoot = $new_apps_path . '/test-css-app';
+		$expectedWebRoot = \OC::$WEBROOT . '/css-apps-test/test-css-app';
+		$expectedFile = 'test-file.css';
+
+		$this->assertEquals($expectedRoot, $root,
+			'Ensure the app path symlink is resolved into the real path');
+		$this->assertEquals($expectedWebRoot, $webRoot);
+		$this->assertEquals($expectedFile, $file);
+
+		array_pop(\OC::$APPSROOTS);
+		unlink($new_apps_path_symlink);
+		$this->rrmdir($new_apps_path);
+	}
+}
diff --git a/tests/lib/Template/JSResourceLocatorTest.php b/tests/lib/Template/JSResourceLocatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6841ee2fee3b405dd2b225f6700095d89ac54f2a
--- /dev/null
+++ b/tests/lib/Template/JSResourceLocatorTest.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Kyle Fazzari <kyrofa@ubuntu.com>
+ *
+ * @author Kyle Fazzari <kyrofa@ubuntu.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as
+ *  published by the Free Software Foundation, either version 3 of the
+ *  License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Test\Template;
+
+use OC\Template\JSCombiner;
+use OCP\Files\IAppData;
+use OCP\IURLGenerator;
+use OCP\ICache;
+use OC\SystemConfig;
+use OCP\ILogger;
+use OC\Template\JSResourceLocator;
+
+class JSResourceLocatorTest extends \Test\TestCase {
+	/** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */
+	protected $appData;
+	/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
+	protected $urlGenerator;
+	/** @var SystemConfig|\PHPUnit_Framework_MockObject_MockObject */
+	protected $config;
+	/** @var ICache|\PHPUnit_Framework_MockObject_MockObject */
+	protected $depsCache;
+	/** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
+	protected $logger;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$this->appData = $this->createMock(IAppData::class);
+		$this->urlGenerator = $this->createMock(IURLGenerator::class);
+		$this->config = $this->createMock(SystemConfig::class);
+		$this->depsCache = $this->createMock(ICache::class);
+		$this->logger = $this->createMock(ILogger::class);
+	}
+
+	private function jsResourceLocator() {
+		$jsCombiner = new JSCombiner(
+			$this->appData,
+			$this->urlGenerator,
+			$this->depsCache,
+			$this->config,
+			$this->logger
+		);
+		return new JSResourceLocator(
+			$this->logger,
+			'theme',
+			array('core'=>'map'),
+			array('3rd'=>'party'),
+			$jsCombiner
+		);
+	}
+
+	private function rrmdir($directory) {
+		$files = array_diff(scandir($directory), array('.','..'));
+		foreach ($files as $file) {
+			if (is_dir($directory . '/' . $file)) {
+				$this->rrmdir($directory . '/' . $file);
+			} else {
+				unlink($directory . '/' . $file);
+			}
+		}
+		return rmdir($directory);
+	}
+
+	private function randomString() {
+		return sha1(uniqid(mt_rand(), true));
+	}
+
+
+	public function testConstructor() {
+		$locator = $this->jsResourceLocator();
+		$this->assertAttributeEquals('theme', 'theme', $locator);
+		$this->assertAttributeEquals('core', 'serverroot', $locator);
+		$this->assertAttributeEquals(array('core'=>'map','3rd'=>'party'), 'mapping', $locator);
+		$this->assertAttributeEquals('3rd', 'thirdpartyroot', $locator);
+		$this->assertAttributeEquals('map', 'webroot', $locator);
+		$this->assertAttributeEquals(array(), 'resources', $locator);
+	}
+
+	public function testFindWithAppPathSymlink() {
+		// First create new apps path, and a symlink to it
+		$apps_dirname = $this->randomString();
+		$new_apps_path = sys_get_temp_dir() . '/' . $apps_dirname;
+		$new_apps_path_symlink = $new_apps_path . '_link';
+		mkdir($new_apps_path);
+		symlink($apps_dirname, $new_apps_path_symlink);
+
+		// Create an app within that path
+		mkdir($new_apps_path . '/' . 'test-js-app');
+
+		// Use the symlink as the app path
+		\OC::$APPSROOTS[] = [
+                        'path' => $new_apps_path_symlink,
+                        'url' => '/js-apps-test',
+                        'writable' => false,
+                ];
+
+		$locator = $this->jsResourceLocator();
+		$locator->find(array('test-js-app/test-file'));
+
+		$resources = $locator->getResources();
+		$this->assertCount(1, $resources);
+		$resource = $resources[0];
+		$this->assertCount(3, $resource);
+		$root = $resource[0];
+		$webRoot = $resource[1];
+		$file = $resource[2];
+
+		$expectedRoot = $new_apps_path . '/test-js-app';
+		$expectedWebRoot = \OC::$WEBROOT . '/js-apps-test/test-js-app';
+		$expectedFile = 'test-file.js';
+
+		$this->assertEquals($expectedRoot, $root,
+			'Ensure the app path symlink is resolved into the real path');
+		$this->assertEquals($expectedWebRoot, $webRoot);
+		$this->assertEquals($expectedFile, $file);
+
+		array_pop(\OC::$APPSROOTS);
+		unlink($new_apps_path_symlink);
+		$this->rrmdir($new_apps_path);
+	}
+}