diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..d5214117 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: Node CI + +on: [push, pull_request] + +jobs: + test: + name: NodeJS ${{ matrix.node-version }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + node-version: [18.x, 20.x, 22.x] + os: [ubuntu-latest] + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Environment Information + run: | + node --version + npm --version + + - name: npm install & test + run: npm it + env: + CI: true + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/hooks/afterPrepareHook.js b/hooks/afterPrepareHook.js index 8dd348e3..7dd191cc 100644 --- a/hooks/afterPrepareHook.js +++ b/hooks/afterPrepareHook.js @@ -5,13 +5,14 @@ It will inject required preferences in the platform-specific projects, based on data you have specified in the projects config.xml file. */ -var configParser = require('./lib/configXmlParser.js'); +const path = require('node:path'); + var androidManifestWriter = require('./lib/android/manifestWriter.js'); var androidWebHook = require('./lib/android/webSiteHook.js'); var iosProjectEntitlements = require('./lib/ios/projectEntitlements.js'); var iosAppSiteAssociationFile = require('./lib/ios/appleAppSiteAssociationFile.js'); -var ANDROID = 'android'; -var IOS = 'ios'; +const ExtendedConfigParser = require('./lib/ExtendedConfigParser.js'); +const { CONFIG_FILE_NAME, PLATFORM_ANDROID, PLATFORM_IOS } = require('./lib/constants.js') module.exports = function(ctx) { run(ctx); @@ -23,32 +24,30 @@ module.exports = function(ctx) { * @param {Object} cordovaContext - cordova context object */ function run(cordovaContext) { - var pluginPreferences = configParser.readPreferences(cordovaContext); + const configFilePath = path.join(cordovaContext.opts.projectRoot, CONFIG_FILE_NAME); + const configFile = new ExtendedConfigParser(configFilePath); + const pluginPreferences = configFile.getUniversalLinks(); var platformsList = cordovaContext.opts.platforms; // if no preferences are found - exit - if (pluginPreferences == null) { + if (!pluginPreferences) { return; } // if no host is defined - exit - if (pluginPreferences.hosts == null || pluginPreferences.hosts.length == 0) { + if (pluginPreferences.hosts === null || pluginPreferences.hosts.length === 0) { console.warn('No host is specified in the config.xml. Universal Links plugin is not going to work.'); return; } platformsList.forEach(function(platform) { switch (platform) { - case ANDROID: - { + case PLATFORM_ANDROID: activateUniversalLinksInAndroid(cordovaContext, pluginPreferences); break; - } - case IOS: - { + case PLATFORM_IOS: activateUniversalLinksInIos(cordovaContext, pluginPreferences); break; - } } }); } @@ -74,7 +73,6 @@ function activateUniversalLinksInAndroid(cordovaContext, pluginPreferences) { * @param {Object} pluginPreferences - plugin preferences from the config.xml file. Basically, content from tag. */ function activateUniversalLinksInIos(cordovaContext, pluginPreferences) { - // generate entitlements file iosProjectEntitlements.generateAssociatedDomainsEntitlements(cordovaContext, pluginPreferences); diff --git a/hooks/beforePluginInstallHook.js b/hooks/beforePluginInstallHook.js deleted file mode 100644 index c4385df9..00000000 --- a/hooks/beforePluginInstallHook.js +++ /dev/null @@ -1,55 +0,0 @@ -/** -Hook is executed when plugin is added to the project. -It will check all necessary module dependencies and install the missing ones locally. -*/ - -var path = require('path'); -var fs = require('fs'); -var spawnSync = require('child_process').spawnSync; -var pluginNpmDependencies = require('../package.json').dependencies; -var INSTALLATION_FLAG_FILE_NAME = '.npmInstalled'; - -// region mark that we installed npm packages -/** - * Check if we already executed this hook. - * - * @param {Object} ctx - cordova context - * @return {Boolean} true if already executed; otherwise - false - */ -function isInstallationAlreadyPerformed(ctx) { - var pathToInstallFlag = path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, INSTALLATION_FLAG_FILE_NAME); - try { - fs.accessSync(pathToInstallFlag, fs.F_OK); - return true; - } catch (err) { - return false; - } -} - -/** - * Create empty file - indicator, that we tried to install dependency modules after installation. - * We have to do that, or this hook is gonna be called on any plugin installation. - */ -function createPluginInstalledFlag(ctx) { - var pathToInstallFlag = path.join(ctx.opts.projectRoot, 'plugins', ctx.opts.plugin.id, INSTALLATION_FLAG_FILE_NAME); - - fs.closeSync(fs.openSync(pathToInstallFlag, 'w')); -} -// endregion - -module.exports = function(ctx) { - if (isInstallationAlreadyPerformed(ctx)) { - return; - } - - console.log('Installing dependency packages: '); - console.log(JSON.stringify(pluginNpmDependencies, null, 2)); - - var npm = (process.platform === "win32" ? "npm.cmd" : "npm"); - var result = spawnSync(npm, ['install', '--production'], { cwd: './plugins/' + ctx.opts.plugin.id }); - if (result.error) { - throw result.error; - } - - createPluginInstalledFlag(ctx); -}; diff --git a/hooks/iosBeforePrepareHook.js b/hooks/iosBeforePrepareHook.js deleted file mode 100644 index f58a4b99..00000000 --- a/hooks/iosBeforePrepareHook.js +++ /dev/null @@ -1,74 +0,0 @@ -/* -Hook executed before the 'prepare' stage. Only for iOS project. -It will check if project name has changed. If so - it will change the name of the .entitlements file to remove that file duplicates. -If file name has no changed - hook will do nothing. -*/ - -var path = require('path'); -var fs = require('fs'); -var ConfigXmlHelper = require('./lib/configXmlHelper.js'); - -module.exports = function(ctx) { - run(ctx); -}; - -/** - * Run the hook logic. - * - * @param {Object} ctx - cordova context object - */ -function run(ctx) { - var projectRoot = ctx.opts.projectRoot; - var iosProjectFilePath = path.join(projectRoot, 'platforms', 'ios'); - var configXmlHelper = new ConfigXmlHelper(ctx); - var newProjectName = configXmlHelper.getProjectName(); - - var oldProjectName = getOldProjectName(iosProjectFilePath); - - // if name has not changed - do nothing - if (oldProjectName.length && oldProjectName === newProjectName) { - return; - } - - console.log('Project name has changed. Renaming .entitlements file.'); - - // if it does - rename it - var oldEntitlementsFilePath = path.join(iosProjectFilePath, oldProjectName, 'Resources', oldProjectName + '.entitlements'); - var newEntitlementsFilePath = path.join(iosProjectFilePath, oldProjectName, 'Resources', newProjectName + '.entitlements'); - - try { - fs.renameSync(oldEntitlementsFilePath, newEntitlementsFilePath); - } catch (err) { - console.warn('Failed to rename .entitlements file.'); - console.warn(err); - } -} - -// region Private API - -/** - * Get old name of the project. - * Name is detected by the name of the .xcodeproj file. - * - * @param {String} projectDir absolute path to ios project directory - * @return {String} old project name - */ -function getOldProjectName(projectDir) { - var files = []; - try { - files = fs.readdirSync(projectDir); - } catch (err) { - return ''; - } - - var projectFile = ''; - files.forEach(function(fileName) { - if (path.extname(fileName) === '.xcodeproj') { - projectFile = path.basename(fileName, '.xcodeproj'); - } - }); - - return projectFile; -} - -// endregion diff --git a/hooks/lib/ExtendedConfigParser.js b/hooks/lib/ExtendedConfigParser.js new file mode 100644 index 00000000..2dd2e875 --- /dev/null +++ b/hooks/lib/ExtendedConfigParser.js @@ -0,0 +1,67 @@ +const { ConfigParser } = require('cordova-common'); + +const { DEFAULT_SCHEME, PLATFORM_ANDROID, PLATFORM_IOS } = require('./constants.js') + +class ExtendedConfigParser extends ConfigParser { + getPackageName (platform) { + let packageName; + + switch (platform) { + case PLATFORM_ANDROID: + packageName = this.android_packageName(); + break; + case PLATFORM_IOS: + packageName = this.ios_CFBundleIdentifier(); + break; + } + + if (packageName === undefined || packageName.length == 0) { + packageName = this.packageName(); + } + + return packageName; + } + + /** + * Returns the privacy manifest node, if available. + * Otherwise `null` is returned. + */ + getUniversalLinks () { + const universalLinks = this.doc.find('./universal-links'); + + if (!universalLinks) { + console.warn(' tag is not set in the config.xml. Universal Links plugin is not going to work.'); + return; + } + + const iosTeamIdEl = universalLinks.find('./ios-team-id'); + const iosTeamId = iosTeamIdEl && iosTeamIdEl.attrib.value || null; + + const hosts = universalLinks.findall('./host').map(host => ({ + scheme: host.attrib.scheme || DEFAULT_SCHEME, + name: host.attrib.name || '', + paths: extractPathUrlsFromHost(host) + })); + + return { hosts, iosTeamId } + } +} + +function extractPathUrlsFromHost(host) { + const paths = host.findall('./path'); + + if (paths.length === 0) { + return ['*']; + } + + const urls = paths.map(path => path.attrib.url) + .filter(path => !!path); + + if (urls.includes('*')) { + return ['*']; + } + + return urls; +} + +module.exports = ExtendedConfigParser; diff --git a/hooks/lib/android/manifestWriter.js b/hooks/lib/android/manifestWriter.js index 7371da60..d1968e5f 100644 --- a/hooks/lib/android/manifestWriter.js +++ b/hooks/lib/android/manifestWriter.js @@ -2,9 +2,9 @@ Class injects plugin preferences into AndroidManifest.xml file. */ -var path = require('path'); +var path = require('node:path'); var xmlHelper = require('../xmlHelper.js'); -var fs = require('fs'); +var fs = require('node:fs'); module.exports = { writePreferences: writePreferences diff --git a/hooks/lib/android/webSiteHook.js b/hooks/lib/android/webSiteHook.js index 33f360ca..7e67d637 100644 --- a/hooks/lib/android/webSiteHook.js +++ b/hooks/lib/android/webSiteHook.js @@ -7,15 +7,16 @@ More documentation on that can be found here: https://developer.android.com/training/app-indexing/enabling-app-indexing.html */ -var fs = require('fs'); -var path = require('path'); -var mkpath = require('mkpath'); -var ConfigXmlHelper = require('../configXmlHelper.js'); +var fs = require('node:fs'); +var path = require('node:path'); var WEB_HOOK_FILE_PATH = path.join('ul_web_hooks', 'android', 'android_web_hook.html'); -var WEB_HOOK_TPL_FILE_PATH = path.join('plugins', 'cordova-universal-links-plugin', 'ul_web_hooks', 'android_web_hook_tpl.html'); +var WEB_HOOK_TPL_FILE_PATH = path.join('plugins/@gedysintraware/cordova-universal-links-plugin/ul_web_hooks/android_web_hook_tpl.html'); var LINK_PLACEHOLDER = '[__LINKS__]'; var LINK_TEMPLATE = ''; +const ExtendedConfigParser = require('../ExtendedConfigParser.js'); +const { CONFIG_FILE_NAME, PLATFORM_ANDROID } = require('../constants.js'); + module.exports = { generate: generateWebHook }; @@ -30,8 +31,10 @@ module.exports = { */ function generateWebHook(cordovaContext, pluginPreferences) { var projectRoot = cordovaContext.opts.projectRoot; - var configXmlHelper = new ConfigXmlHelper(cordovaContext); - var packageName = configXmlHelper.getPackageName('android'); + + const configFilePath = path.join(projectRoot, CONFIG_FILE_NAME); + const configFile = new ExtendedConfigParser(configFilePath); + var packageName = configFile.getPackageName(PLATFORM_ANDROID); var template = readTemplate(projectRoot); // if template was not found - exit @@ -153,7 +156,7 @@ function saveWebHook(projectRoot, hookContent) { */ function createDirectoryIfNeeded(dir) { try { - mkpath.sync(dir); + fs.mkdirSync(dir, { recursive: true }); } catch (err) { console.log(err); } diff --git a/hooks/lib/configXmlHelper.js b/hooks/lib/configXmlHelper.js deleted file mode 100644 index 10c0eef6..00000000 --- a/hooks/lib/configXmlHelper.js +++ /dev/null @@ -1,117 +0,0 @@ -/* -Helper class to read data from config.xml file. -*/ -var path = require('path'); -var xmlHelper = require('./xmlHelper.js'); -var ANDROID = 'android'; -var IOS = 'ios'; -var CONFIG_FILE_NAME = 'config.xml'; -var context; -var projectRoot; - -module.exports = ConfigXmlHelper; - -// region public API - -/** - * Constructor. - * - * @param {Object} cordovaContext - cordova context object - */ -function ConfigXmlHelper(cordovaContext) { - context = cordovaContext; - projectRoot = context.opts.projectRoot; -} - -/** - * Read config.xml data as JSON object. - * - * @return {Object} JSON object with data from config.xml - */ -ConfigXmlHelper.prototype.read = function() { - var filePath = getConfigXmlFilePath(); - - return xmlHelper.readXmlAsJson(filePath); -} - -/** - * Get package name for the application. Depends on the platform. - * - * @param {String} platform - 'ios' or 'android'; for what platform we need a package name - * @return {String} package/bundle name - */ -ConfigXmlHelper.prototype.getPackageName = function(platform) { - var configFilePath = getConfigXmlFilePath(); - var config = getCordovaConfigParser(configFilePath); - var packageName; - - switch (platform) { - case ANDROID: - { - packageName = config.android_packageName(); - break; - } - case IOS: - { - packageName = config.ios_CFBundleIdentifier(); - break; - } - } - if (packageName === undefined || packageName.length == 0) { - packageName = config.packageName(); - } - - return packageName; -} - -/** - * Get name of the current project. - * - * @return {String} name of the project - */ -ConfigXmlHelper.prototype.getProjectName = function() { - return getProjectName(); -} - -// endregion - -// region Private API - -/** - * Get config parser from cordova library. - * - * @param {String} configFilePath absolute path to the config.xml file - * @return {Object} - */ -function getCordovaConfigParser(configFilePath) { - var ConfigParser; - - // If we are running Cordova 5.4 or abova - use parser from cordova-common. - // Otherwise - from cordova-lib. - try { - ConfigParser = context.requireCordovaModule('cordova-common/src/ConfigParser/ConfigParser'); - } catch (e) { - ConfigParser = context.requireCordovaModule('cordova-lib/src/configparser/ConfigParser') - } - - return new ConfigParser(configFilePath); -} - -/** - * Get absolute path to the config.xml. - */ -function getConfigXmlFilePath() { - return path.join(projectRoot, CONFIG_FILE_NAME); -} - -/** - * Get project name from config.xml - */ -function getProjectName() { - var configFilePath = getConfigXmlFilePath(); - var config = getCordovaConfigParser(configFilePath); - - return config.name(); -} - -// endregion diff --git a/hooks/lib/configXmlParser.js b/hooks/lib/configXmlParser.js deleted file mode 100644 index 3e71e54b..00000000 --- a/hooks/lib/configXmlParser.js +++ /dev/null @@ -1,145 +0,0 @@ -/* -Parser for config.xml file. Read plugin-specific preferences (from tag) as JSON object. -*/ -var path = require('path'); -var ConfigXmlHelper = require('./configXmlHelper.js'); -var DEFAULT_SCHEME = 'http'; - -module.exports = { - readPreferences: readPreferences -}; - -// region Public API - -/** - * Read plugin preferences from the config.xml file. - * - * @param {Object} cordovaContext - cordova context object - * @return {Array} list of host objects - */ -function readPreferences(cordovaContext) { - // read data from projects root config.xml file - var configXml = new ConfigXmlHelper(cordovaContext).read(); - if (configXml == null) { - console.warn('config.xml not found! Please, check that it exist\'s in your project\'s root directory.'); - return null; - } - - // look for data from the tag - var ulXmlPreferences = configXml.widget['universal-links']; - if (ulXmlPreferences == null || ulXmlPreferences.length == 0) { - console.warn(' tag is not set in the config.xml. Universal Links plugin is not going to work.'); - return null; - } - - var xmlPreferences = ulXmlPreferences[0]; - - // read hosts - var hosts = constructHostsList(xmlPreferences); - - // read ios team ID - var iosTeamId = getTeamIdPreference(xmlPreferences); - - return { - 'hosts': hosts, - 'iosTeamId': iosTeamId - }; -} - -// endregion - -// region Private API - -function getTeamIdPreference(xmlPreferences) { - if (xmlPreferences.hasOwnProperty('ios-team-id')) { - return xmlPreferences['ios-team-id'][0]['$']['value']; - } - - return null; -} - -/** - * Construct list of host objects, defined in xml file. - * - * @param {Object} xmlPreferences - plugin preferences from config.xml as JSON object - * @return {Array} array of JSON objects, where each entry defines host data from config.xml. - */ -function constructHostsList(xmlPreferences) { - var hostsList = []; - - // look for defined hosts - var xmlHostList = xmlPreferences['host']; - if (xmlHostList == null || xmlHostList.length == 0) { - return []; - } - - xmlHostList.forEach(function(xmlElement) { - var host = constructHostEntry(xmlElement); - if (host) { - hostsList.push(host); - } - }); - - return hostsList; -} - -/** - * Construct host object from xml data. - * - * @param {Object} xmlElement - xml data to process. - * @return {Object} host entry as JSON object - */ -function constructHostEntry(xmlElement) { - var host = { - scheme: DEFAULT_SCHEME, - name: '', - paths: [] - }; - var hostProperties = xmlElement['$']; - - if (hostProperties == null || hostProperties.length == 0) { - return null; - } - - // read host name - host.name = hostProperties.name; - - // read scheme if defined - if (hostProperties['scheme'] != null) { - host.scheme = hostProperties.scheme; - } - - // construct paths list, defined for the given host - host.paths = constructPaths(xmlElement); - - return host; -} - -/** - * Construct list of path objects from the xml data. - * - * @param {Object} xmlElement - xml data to process - * @return {Array} list of path entries, each on is a JSON object - */ -function constructPaths(xmlElement) { - if (xmlElement['path'] == null) { - return ['*']; - } - - var paths = []; - xmlElement.path.some(function(pathElement) { - var url = pathElement['$']['url']; - - // Ignore explicit paths if '*' is defined - if (url === '*') { - paths = ['*']; - return true; - } - - paths.push(url); - }); - - return paths; -} - -// endregion diff --git a/hooks/lib/constants.js b/hooks/lib/constants.js new file mode 100644 index 00000000..d9144560 --- /dev/null +++ b/hooks/lib/constants.js @@ -0,0 +1,6 @@ +module.exports = { + DEFAULT_SCHEME: 'http', + CONFIG_FILE_NAME: 'config.xml', + PLATFORM_ANDROID: 'android', + PLATFORM_IOS: 'ios' +}; diff --git a/hooks/lib/ios/appleAppSiteAssociationFile.js b/hooks/lib/ios/appleAppSiteAssociationFile.js index f12da711..1aa315ac 100644 --- a/hooks/lib/ios/appleAppSiteAssociationFile.js +++ b/hooks/lib/ios/appleAppSiteAssociationFile.js @@ -17,11 +17,12 @@ Additional documentation regarding apple-app-site-association file can be found */ -var path = require('path'); -var mkpath = require('mkpath'); -var fs = require('fs'); -var rimraf = require('rimraf'); -var ConfigXmlHelper = require('../configXmlHelper.js'); +var path = require('node:path'); +var fs = require('node:fs'); + +const ExtendedConfigParser = require('../ExtendedConfigParser.js'); +const { CONFIG_FILE_NAME, PLATFORM_IOS } = require('../constants.js'); + var IOS_TEAM_ID = ''; var ASSOCIATION_FILE_NAME = 'apple-app-site-association'; var bundleId; @@ -53,7 +54,7 @@ function generate(cordovaContext, pluginPreferences) { * Remove old files from ul_web_hooks/ios folder. */ function removeOldFiles() { - rimraf.sync(getWebHookDirectory()); + fs.rmSync(getWebHookDirectory(), { recursive: true, force: true }); } /** @@ -128,7 +129,7 @@ function saveContentToFile(filePrefix, content) { */ function createDirectoriesIfNeeded(dirPath) { try { - mkpath.sync(dirPath); + fs.mkdirSync(dirPath, { recursive: true }); } catch (err) { console.log(err); } @@ -163,8 +164,9 @@ function getProjectRoot() { */ function getBundleId() { if (bundleId === undefined) { - var configXmlHelper = new ConfigXmlHelper(context); - bundleId = configXmlHelper.getPackageName('ios'); + const configFilePath = path.join(getProjectRoot(), CONFIG_FILE_NAME); + const configFile = new ExtendedConfigParser(configFilePath); + bundleId = configFile.getPackageName(PLATFORM_IOS); } return bundleId; diff --git a/hooks/lib/ios/projectEntitlements.js b/hooks/lib/ios/projectEntitlements.js index 6d3f6160..b99d3682 100644 --- a/hooks/lib/ios/projectEntitlements.js +++ b/hooks/lib/ios/projectEntitlements.js @@ -6,10 +6,13 @@ Location: ProjectName/ Script only generates content. File it self is included in the xcode project in another hook: xcodePreferences.js. */ -var path = require('path'); -var fs = require('fs'); +var path = require('node:path'); +var fs = require('node:fs'); var plist = require('plist'); -var ConfigXmlHelper = require('../configXmlHelper.js'); + +const ExtendedConfigParser = require('../ExtendedConfigParser.js'); +const { CONFIG_FILE_NAME } = require('../constants.js'); + var ASSOCIATED_DOMAINS = 'com.apple.developer.associated-domains'; var context; var projectName; @@ -158,8 +161,9 @@ function getProjectRoot() { */ function getProjectName() { if (projectName === undefined) { - var configXmlHelper = new ConfigXmlHelper(context); - projectName = configXmlHelper.getProjectName(); + const configFilePath = path.join(getProjectRoot(), CONFIG_FILE_NAME); + const configFile = new ExtendedConfigParser(configFilePath); + projectName = configFile.name(); } return projectName; diff --git a/hooks/lib/xmlHelper.js b/hooks/lib/xmlHelper.js index a2c9bf02..06a482c7 100644 --- a/hooks/lib/xmlHelper.js +++ b/hooks/lib/xmlHelper.js @@ -2,7 +2,7 @@ Small helper class to read/write from/to xml file. */ -var fs = require('fs'); +var fs = require('node:fs'); var xml2js = require('xml2js'); module.exports = { diff --git a/package.json b/package.json index 99c3c017..558b94e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gedysintraware/cordova-universal-links-plugin", - "version": "1.2.1-GI", + "version": "2.0.0-GI", "description": "Cordova plugin to add in your application support for Universal Links (iOS 9) and Deep Links (Android). Basically, open application through the link in the browser.", "cordova": { "id": "cordova-universal-links-plugin", @@ -26,14 +26,15 @@ "android" ], "dependencies": { - "mkpath": ">=1.0.0", - "xml2js": ">=0.4", - "rimraf": ">=2.4", - "node-version-compare": ">=1.0.1", - "plist": ">=1.2.0" + "cordova-common": "^5.0.0", + "plist": "^3.1.0", + "xml2js": "^0.6.2" }, "author": "Nikolay Demyankov for Nordnet Bank AB", "license": "MIT", + "scripts": { + "test": "node --test tests/*.test.js" + }, "bugs": { "url": "https://github.com/gedysintraware/cordova-universal-links-plugin/issues" } diff --git a/plugin.xml b/plugin.xml index bc1a241c..c3e8eeb1 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,6 +1,6 @@ - + Universal Links Plugin @@ -25,11 +25,8 @@ - - - diff --git a/tests/ExtendedConfigParser.test.js b/tests/ExtendedConfigParser.test.js new file mode 100644 index 00000000..12a9061c --- /dev/null +++ b/tests/ExtendedConfigParser.test.js @@ -0,0 +1,109 @@ +const { describe, it } = require('node:test'); +const assert = require('node:assert'); +const path = require('node:path'); + +const ExtendedConfigParser = require('../hooks/lib/ExtendedConfigParser'); + +describe('ExtendedConfigParser test', async () => { + it('should return undefined when is missing', () => { + const mockConfig = path.join(__dirname, 'mock/no-configs.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.strictEqual(actual, undefined); + }); + + it('should return empty config block when exists but empty', () => { + const mockConfig = path.join(__dirname, 'mock/empty-universal-links.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.deepStrictEqual(actual, { hosts: [], iosTeamId: null }); + }); + + it('should set iosTeamID when has value', () => { + const mockConfig = path.join(__dirname, 'mock/ios-team-id.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.deepStrictEqual(actual, { hosts: [], iosTeamId: 'foobar' }); + }); + + it('should use default scheme & wildcard path when missing on ', () => { + const mockConfig = path.join(__dirname, 'mock/host-missing-scheme.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.deepStrictEqual(actual, { + hosts: [ + {name: '*.users.example.com', paths: ['*'], scheme: 'http'} + ], + iosTeamId: null + }); + }); + + it('should use set scheme to https when set on ', () => { + const mockConfig = path.join(__dirname, 'mock/host-https-scheme.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.deepStrictEqual(actual, { + hosts: [ + {name: '*.users.example.com', paths: ['*'], scheme: 'https'} + ], + iosTeamId: null + }); + }); + + it('should ... when event is set on ', { skip: true }, () => { + const mockConfig = path.join(__dirname, 'mock/host-event.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.deepStrictEqual(actual, { + hosts: [ + {name: '*.users.example.com', paths: ['*'], scheme: 'https'} + ], + iosTeamId: null + }); + }); + + it('should set path when is defined inside ', () => { + const mockConfig = path.join(__dirname, 'mock/host-defined-path.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.deepStrictEqual(actual, { + hosts: [ + {name: '*.users.example.com', paths: ['/some/path1'], scheme: 'https'} + ], + iosTeamId: null + }); + }); + + it('should set path to wildcard and and ignore other paths when wildcard exists', () => { + const mockConfig = path.join(__dirname, 'mock/host-defined-path-with-wildcard.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.deepStrictEqual(actual, { + hosts: [ + {name: '*.users.example.com', paths: ['*'], scheme: 'https'} + ], + iosTeamId: null + }); + }); + + it('should remove empty paths when url is missing.', () => { + const mockConfig = path.join(__dirname, 'mock/host-defined-path-missing-url.xml'); + const configParser = new ExtendedConfigParser(mockConfig); + + const actual = configParser.getUniversalLinks(); + assert.deepStrictEqual(actual, { + hosts: [ + {name: '*.users.example.com', paths: ['/some/path1', '/some/path3'], scheme: 'https'} + ], + iosTeamId: null + }); + }); +}); diff --git a/tests/mock/empty-universal-links.xml b/tests/mock/empty-universal-links.xml new file mode 100644 index 00000000..3cced13a --- /dev/null +++ b/tests/mock/empty-universal-links.xml @@ -0,0 +1,14 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + + + diff --git a/tests/mock/host-defined-path-missing-url.xml b/tests/mock/host-defined-path-missing-url.xml new file mode 100644 index 00000000..99a66ea2 --- /dev/null +++ b/tests/mock/host-defined-path-missing-url.xml @@ -0,0 +1,20 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + + + + + + + + + diff --git a/tests/mock/host-defined-path-with-wildcard.xml b/tests/mock/host-defined-path-with-wildcard.xml new file mode 100644 index 00000000..1e090015 --- /dev/null +++ b/tests/mock/host-defined-path-with-wildcard.xml @@ -0,0 +1,19 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + + + + + + + + diff --git a/tests/mock/host-defined-path.xml b/tests/mock/host-defined-path.xml new file mode 100644 index 00000000..f06bdb62 --- /dev/null +++ b/tests/mock/host-defined-path.xml @@ -0,0 +1,18 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + + + + + + + diff --git a/tests/mock/host-event.xml b/tests/mock/host-event.xml new file mode 100644 index 00000000..c2554e80 --- /dev/null +++ b/tests/mock/host-event.xml @@ -0,0 +1,16 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + + + + + diff --git a/tests/mock/host-https-scheme.xml b/tests/mock/host-https-scheme.xml new file mode 100644 index 00000000..d3a41b92 --- /dev/null +++ b/tests/mock/host-https-scheme.xml @@ -0,0 +1,16 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + + + + + diff --git a/tests/mock/host-missing-scheme.xml b/tests/mock/host-missing-scheme.xml new file mode 100644 index 00000000..e14adff5 --- /dev/null +++ b/tests/mock/host-missing-scheme.xml @@ -0,0 +1,16 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + + + + + diff --git a/tests/mock/ios-team-id.xml b/tests/mock/ios-team-id.xml new file mode 100644 index 00000000..ca813457 --- /dev/null +++ b/tests/mock/ios-team-id.xml @@ -0,0 +1,16 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + + + + + diff --git a/tests/mock/no-configs.xml b/tests/mock/no-configs.xml new file mode 100644 index 00000000..ed4bdc43 --- /dev/null +++ b/tests/mock/no-configs.xml @@ -0,0 +1,13 @@ + + + cordovaTest + Sample Config.xml to test universalLinksTest + Apache Cordova Team + + + +