open-consul/ui/packages/consul-ui/tests/lib/page-object/visitable.js

105 lines
3.3 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { getContext } from '@ember/test-helpers';
import { getExecutionContext } from 'ember-cli-page-object/-private/execution_context';
import createQueryParams from 'consul-ui/utils/http/create-query-params';
const assign = Object.assign;
const QueryParams = {
stringify: createQueryParams(),
};
function fillInDynamicSegments(path, params, encoder) {
return path
.split('/')
.map(function (segment) {
let match = segment.match(/^:(.+)$/);
if (match) {
let [, key] = match;
let value = params[key];
if (typeof value === 'undefined') {
throw new Error(`Missing parameter for '${key}'`);
}
// Remove dynamic segment key from params
delete params[key];
return encoder(value);
}
return segment;
})
.join('/');
}
function appendQueryParams(path, queryParams) {
if (Object.keys(queryParams).length > 0) {
return `${path}?${QueryParams.stringify(queryParams)}`;
}
return path;
}
/**
* Custom implementation of `visitable`
* Currently aims to be compatible and as close as possible to the
* actual `ember-cli-page-object` version
*
* Additions:
* 1. Injectable encoder, for when you don't want your segments to be encoded
* or you have specific encoding needs
* Specifically in my case for KV urls where the `Key`/Slug shouldn't be encoded,
* defaults to the browsers `encodeURIComponent` for compatibility and ease.
* 2. `path` can be an array of (string) paths OR a string for compatibility.
* If a path cannot be generated due to a lack of properties on the
* dynamic segment params, if will keep trying 'path' in the array
* until it finds one that it can construct. This follows the same thinking
* as 'if you don't specify an item, then we are looking to create one'
*/
export function visitable(path, encoder = encodeURIComponent) {
return {
isDescriptor: true,
value(dynamicSegmentsAndQueryParams = {}) {
let executionContext = getExecutionContext(this);
return executionContext.runAsync((context) => {
let params;
let fullPath = (function _try(paths) {
let path = paths.shift();
if (typeof dynamicSegmentsAndQueryParams.nspace !== 'undefined') {
path = `/:nspace${path}`;
}
params = assign({}, dynamicSegmentsAndQueryParams);
let fullPath;
try {
fullPath = fillInDynamicSegments(path, params, encoder);
} catch (e) {
if (paths.length > 0) {
fullPath = _try(paths);
} else {
throw e;
}
}
return fullPath;
})(typeof path === 'string' ? [path] : path.slice(0));
fullPath = appendQueryParams(fullPath, params);
const container = getContext().owner;
const locationType = container.lookup('service:env').var('locationType');
const location = container.lookup(`location:${locationType}`);
// look for a visit on the current location first before just using
// visit on the current context/app
if (typeof location.visit === 'function') {
return location.visit(fullPath);
} else {
return context.visit(fullPath);
}
});
},
};
}