Loading client/src/components/Workflow/WorkflowDropdown.test.js +3 −2 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import { getLocalVue } from "jest/helpers"; import axios from "axios"; import MockAdapter from "axios-mock-adapter"; import flushPromises from "flush-promises"; import { ROOT_COMPONENT } from "utils/navigation"; const localVue = getLocalVue(true); Loading Loading @@ -41,8 +42,8 @@ describe("WorkflowDropdown.vue", () => { }); it("should not display source metadata if not present", async () => { expect(wrapper.find(".workflow-trs-icon").exists()).toBeFalsy(); expect(wrapper.find(".workflow-external-link").exists()).toBeFalsy(); expect(wrapper.find(ROOT_COMPONENT.workflows.trs_icon.selector).exists()).toBeFalsy(); expect(wrapper.find(ROOT_COMPONENT.workflows.external_link.selector).exists()).toBeFalsy(); }); it("should display name and description", async () => { Loading client/src/components/Workflow/WorkflowIndexActions.test.js +9 −3 Original line number Diff line number Diff line import WorkflowIndexActions from "./WorkflowIndexActions"; import { shallowMount } from "@vue/test-utils"; import { getLocalVue } from "jest/helpers"; import { ROOT_COMPONENT } from "utils/navigation"; import "jest-location-mock"; const localVue = getLocalVue(); const localVue = getLocalVue(true); describe("WorkflowIndexActions.vue", () => { let wrapper; Loading @@ -21,13 +22,18 @@ describe("WorkflowIndexActions.vue", () => { describe("naviation", () => { it("should create a workflow when create is clicked", async () => { await wrapper.find("#workflow-create").trigger("click"); await wrapper.find(ROOT_COMPONENT.workflows.new_button.selector).trigger("click"); expect(window.location).toBeAt("/root/workflows/create"); }); it("should import a workflow when create is clicked", async () => { await wrapper.find("#workflow-import").trigger("click"); await wrapper.find(ROOT_COMPONENT.workflows.import_button.selector).trigger("click"); expect(window.location).toBeAt("/root/workflows/import"); }); it("should localize button text", async () => { expect(wrapper.find(ROOT_COMPONENT.workflows.new_button.selector).text()).toBeLocalizationOf("Create"); expect(wrapper.find(ROOT_COMPONENT.workflows.import_button.selector).text()).toBeLocalizationOf("Import"); }); }); }); client/src/components/Workflow/WorkflowRunButton.test.js 0 → 100644 +29 −0 Original line number Diff line number Diff line import WorkflowRunButton from "./WorkflowRunButton"; import { shallowMount } from "@vue/test-utils"; import { getLocalVue } from "jest/helpers"; import { ROOT_COMPONENT } from "utils/navigation"; import "jest-location-mock"; const localVue = getLocalVue(true); const WORKFLOW_ID = "workflow_id123"; describe("WorkflowRunButton.vue", () => { let wrapper; beforeEach(async () => { const propsData = { root: "/root/", id: WORKFLOW_ID, }; wrapper = shallowMount(WorkflowRunButton, { propsData, localVue, }); }); it("should localize title text", async () => { const selector = ROOT_COMPONENT.workflows.run_button({ id: WORKFLOW_ID }).selector; expect(wrapper.find(selector).attributes("title")).toBeLocalizationOf("Run workflow"); }); }); client/src/components/Workflow/WorkflowRunButton.vue +1 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ <b-button v-b-tooltip.hover.bottom :title="title | localize" :data-workflow-run="id" class="workflow-run btn-sm btn-primary fa fa-play" @click.stop="executeWorkflow" /> </template> Loading client/src/utils/navigation/index.js 0 → 100644 +123 −0 Original line number Diff line number Diff line import NAVIGATION_DATA from "./navigation.yml"; function interpolate(template, properties) { let parsed = template; Object.keys(properties).forEach((key) => { const value = properties[key]; parsed = parsed.replace("${" + key + "}", value); }); return parsed; } class SelectorTemplate extends Function { constructor(selector, selectorType, props = {}, children = {}) { super(); if (selectorType == "data-description") { selectorType = "css"; selector = `[data-description="${selector}"]`; } this._selector = selector; this.selectorType = selectorType; this._props = props || {}; return new Proxy(this, { apply: (target, thisArg, args) => target._call(args), }); } _call(args) { const inputProps = args[0]; const allProps = { ...this._props, ...inputProps }; return new SelectorTemplate(this._selector, this.selectorType, allProps, this.children); } get description() { const selector = this.selector; let desc; if (this.selectorType == "css") { desc = `CSS selector [${selector}]`; } else if (this.selectorType == "xpath") { desc = `XPATH selector [${selector}]`; } else if (this.selectorType == "id") { desc = `DOM element with id [${selector}]`; } return desc; } get selector() { return interpolate(this._selector, this._props); } } function selectorTemplateFromObject(object, children = {}) { if (typeof object === "string" || object instanceof String) { const selector = object; return new SelectorTemplate(selector, "css", {}, children); } else { const selectorType = object.type || "css"; const selector = object.selector; return new SelectorTemplate(selector, selectorType, {}, children); } } function componentFromObject(name, object) { const selectors = {}; const subComponents = {}; Object.keys(object).forEach((key) => { const value = object[key]; if (key == "selectors") { let baseSelector = null; const hasBaseSelector = value["_"] !== undefined; if (hasBaseSelector) { baseSelector = value["_"]; delete value["_"]; } Object.keys(value).forEach((selectorKey) => { const selectorValue = value[selectorKey]; if (selectorValue == undefined) { throw `Problem with selectors value ${selectorValue}`; } selectors[selectorKey] = selectorTemplateFromObject(selectorValue); }); if (baseSelector) { selectors["_"] = selectorTemplateFromObject(baseSelector, selectors); } } else if (key == "labels") { // implement as needed } else if (key == "text") { // implement as needed } else { const component = componentFromObject(key, value); subComponents[key] = component; } }); return new Component(name, subComponents, selectors); } class Component { constructor(name, subComponents, selectors) { self._name = name; self._subComponents = subComponents; self._selectors = selectors; const component = this; Object.keys(subComponents).forEach((key) => { const value = subComponents[key]; component[key] = value; }); Object.keys(selectors).forEach((key) => { const value = selectors[key]; component[key] = value; }); } get selector() { if (hasOwnProperty("_")) { return this["_"]; } else { throw `No _ selector for [${this}]`; } } } export const ROOT_COMPONENT = componentFromObject("root", NAVIGATION_DATA); Loading
client/src/components/Workflow/WorkflowDropdown.test.js +3 −2 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import { getLocalVue } from "jest/helpers"; import axios from "axios"; import MockAdapter from "axios-mock-adapter"; import flushPromises from "flush-promises"; import { ROOT_COMPONENT } from "utils/navigation"; const localVue = getLocalVue(true); Loading Loading @@ -41,8 +42,8 @@ describe("WorkflowDropdown.vue", () => { }); it("should not display source metadata if not present", async () => { expect(wrapper.find(".workflow-trs-icon").exists()).toBeFalsy(); expect(wrapper.find(".workflow-external-link").exists()).toBeFalsy(); expect(wrapper.find(ROOT_COMPONENT.workflows.trs_icon.selector).exists()).toBeFalsy(); expect(wrapper.find(ROOT_COMPONENT.workflows.external_link.selector).exists()).toBeFalsy(); }); it("should display name and description", async () => { Loading
client/src/components/Workflow/WorkflowIndexActions.test.js +9 −3 Original line number Diff line number Diff line import WorkflowIndexActions from "./WorkflowIndexActions"; import { shallowMount } from "@vue/test-utils"; import { getLocalVue } from "jest/helpers"; import { ROOT_COMPONENT } from "utils/navigation"; import "jest-location-mock"; const localVue = getLocalVue(); const localVue = getLocalVue(true); describe("WorkflowIndexActions.vue", () => { let wrapper; Loading @@ -21,13 +22,18 @@ describe("WorkflowIndexActions.vue", () => { describe("naviation", () => { it("should create a workflow when create is clicked", async () => { await wrapper.find("#workflow-create").trigger("click"); await wrapper.find(ROOT_COMPONENT.workflows.new_button.selector).trigger("click"); expect(window.location).toBeAt("/root/workflows/create"); }); it("should import a workflow when create is clicked", async () => { await wrapper.find("#workflow-import").trigger("click"); await wrapper.find(ROOT_COMPONENT.workflows.import_button.selector).trigger("click"); expect(window.location).toBeAt("/root/workflows/import"); }); it("should localize button text", async () => { expect(wrapper.find(ROOT_COMPONENT.workflows.new_button.selector).text()).toBeLocalizationOf("Create"); expect(wrapper.find(ROOT_COMPONENT.workflows.import_button.selector).text()).toBeLocalizationOf("Import"); }); }); });
client/src/components/Workflow/WorkflowRunButton.test.js 0 → 100644 +29 −0 Original line number Diff line number Diff line import WorkflowRunButton from "./WorkflowRunButton"; import { shallowMount } from "@vue/test-utils"; import { getLocalVue } from "jest/helpers"; import { ROOT_COMPONENT } from "utils/navigation"; import "jest-location-mock"; const localVue = getLocalVue(true); const WORKFLOW_ID = "workflow_id123"; describe("WorkflowRunButton.vue", () => { let wrapper; beforeEach(async () => { const propsData = { root: "/root/", id: WORKFLOW_ID, }; wrapper = shallowMount(WorkflowRunButton, { propsData, localVue, }); }); it("should localize title text", async () => { const selector = ROOT_COMPONENT.workflows.run_button({ id: WORKFLOW_ID }).selector; expect(wrapper.find(selector).attributes("title")).toBeLocalizationOf("Run workflow"); }); });
client/src/components/Workflow/WorkflowRunButton.vue +1 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ <b-button v-b-tooltip.hover.bottom :title="title | localize" :data-workflow-run="id" class="workflow-run btn-sm btn-primary fa fa-play" @click.stop="executeWorkflow" /> </template> Loading
client/src/utils/navigation/index.js 0 → 100644 +123 −0 Original line number Diff line number Diff line import NAVIGATION_DATA from "./navigation.yml"; function interpolate(template, properties) { let parsed = template; Object.keys(properties).forEach((key) => { const value = properties[key]; parsed = parsed.replace("${" + key + "}", value); }); return parsed; } class SelectorTemplate extends Function { constructor(selector, selectorType, props = {}, children = {}) { super(); if (selectorType == "data-description") { selectorType = "css"; selector = `[data-description="${selector}"]`; } this._selector = selector; this.selectorType = selectorType; this._props = props || {}; return new Proxy(this, { apply: (target, thisArg, args) => target._call(args), }); } _call(args) { const inputProps = args[0]; const allProps = { ...this._props, ...inputProps }; return new SelectorTemplate(this._selector, this.selectorType, allProps, this.children); } get description() { const selector = this.selector; let desc; if (this.selectorType == "css") { desc = `CSS selector [${selector}]`; } else if (this.selectorType == "xpath") { desc = `XPATH selector [${selector}]`; } else if (this.selectorType == "id") { desc = `DOM element with id [${selector}]`; } return desc; } get selector() { return interpolate(this._selector, this._props); } } function selectorTemplateFromObject(object, children = {}) { if (typeof object === "string" || object instanceof String) { const selector = object; return new SelectorTemplate(selector, "css", {}, children); } else { const selectorType = object.type || "css"; const selector = object.selector; return new SelectorTemplate(selector, selectorType, {}, children); } } function componentFromObject(name, object) { const selectors = {}; const subComponents = {}; Object.keys(object).forEach((key) => { const value = object[key]; if (key == "selectors") { let baseSelector = null; const hasBaseSelector = value["_"] !== undefined; if (hasBaseSelector) { baseSelector = value["_"]; delete value["_"]; } Object.keys(value).forEach((selectorKey) => { const selectorValue = value[selectorKey]; if (selectorValue == undefined) { throw `Problem with selectors value ${selectorValue}`; } selectors[selectorKey] = selectorTemplateFromObject(selectorValue); }); if (baseSelector) { selectors["_"] = selectorTemplateFromObject(baseSelector, selectors); } } else if (key == "labels") { // implement as needed } else if (key == "text") { // implement as needed } else { const component = componentFromObject(key, value); subComponents[key] = component; } }); return new Component(name, subComponents, selectors); } class Component { constructor(name, subComponents, selectors) { self._name = name; self._subComponents = subComponents; self._selectors = selectors; const component = this; Object.keys(subComponents).forEach((key) => { const value = subComponents[key]; component[key] = value; }); Object.keys(selectors).forEach((key) => { const value = selectors[key]; component[key] = value; }); } get selector() { if (hasOwnProperty("_")) { return this["_"]; } else { throw `No _ selector for [${this}]`; } } } export const ROOT_COMPONENT = componentFromObject("root", NAVIGATION_DATA);