diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 033bf31..8d3008e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -16,10 +16,10 @@ jobs: name: Node ${{ matrix.node-version }} steps: - name: Check out - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -29,13 +29,12 @@ jobs: - name: Lint working-directory: ./dtool-lookup-webapp - run: npm run lint + run: npm run lint src - name: Build working-directory: ./dtool-lookup-webapp run: npm run build - # needs true tests first: - # - name: Run tests - # working-directory: ./dtool-lookup-webapp - # run: npm test + - name: Run tests + working-directory: ./dtool-lookup-webapp + run: npm run test:unit diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 06a2a79..5756345 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,11 +10,21 @@ This change log uses principles from `keep a changelog `_ -2. `token-generator-ldap `_ +1. dtool-lookup-server: https://github.com/jic-dtool/dtool-lookup-server - Provides a means to search and display dataset metadata. +2. token-generator-ldap: https://github.com/jic-dtool/token-generator-ldap - Facilitates user authentication. -The first provides a means to search and display dataset metadata. -The latter provides a means to authenticate users. +Setup +----- -Preamble -------- +Navigate to the `dtool-lookup-webapp` directory: -:: +.. code-block:: bash cd dtool-lookup-webapp +Create a `.env` file in the `dtool-lookup-webapp` directory with the following contents: -Create a file `.env` in the `dtool-lookup-webapp` directory with the following contents: +.. code-block:: bash -``` -VUE_APP_DTOOL_LOOKUP_SERVER_URL="http://localhost:5000" -VUE_APP_DTOOL_LOOKUP_SERVER_TOKEN_GENERATOR_URL="http://localhost:5001/token" -``` + VUE_APP_DTOOL_LOOKUP_SERVER_URL="http://localhost:5000" + VUE_APP_DTOOL_LOOKUP_SERVER_TOKEN_GENERATOR_URL="http://localhost:5001/token" For deployment, replace these URLs with the actual endpoints of the lookup server and the token generator. +Customization options for the landing page are available through the following environment variables in the `.env` file: + +.. code-block:: text + + VUE_APP_FIRST_CONTAINER_TITLE=Log in + VUE_APP_SECOND_CONTAINER_TITLE=dserver + VUE_APP_SECOND_CONTAINER_MESSAGE=Welcome to dserver's webapp. + VUE_APP_THIRD_CONTAINER_HEADING=Access + VUE_APP_THIRD_CONTAINER_MESSAGE=Some notes on how to gain access. + VUE_APP_FOURTH_CONTAINER_HEADING=Docs + VUE_APP_FOURTH_CONTAINER_INTRO=Some notes on how to find help. The following list may contain an arbitrary number of links. + VUE_APP_FOURTH_CONTAINER_RESOURCES=[{"text": "dtool-lookup-webapp repository", "url": "https://github.com/jic-dtool/dtool-lookup-webapp"}] + VUE_APP_LANDING_PAGE_ICON_PATH=/icons/128x128/dtool_logo.png + +Customization options for the upper right corner drop-down menu in the app are available through the following environment variables in the `.env` file: + +.. code-block:: text -Start a development server --------------------------- + VUE_APP_OFFER_DTOOL_README_YAML_DOWNLOAD=true + VUE_APP_OFFER_DTOOL_JSON_DOWNLOAD=true + VUE_APP_SHOW_INFO_MENU_ENTRY=true + VUE_APP_DTOOL_JSON_PATH=/data/templates/dtool.json + VUE_APP_DTOOL_README_YAML_PATH=/data/templates/dtool_readme.yml + VUE_APP_INFO_CONTENT="dtool.json is you local dtool client's configuration file. Place it at ~/.config/dtool/dtool.json, where ~ is your home directoy, and create the directories if they do not exist.

dtool_readme.yml is the metadata template used for documenting your datasets. Place it anywhere, but make sure that the entry DTOOL_README_TEMPLATE_FPATH within above's dtool.json points to the correct absolute path of your dtool_readme.yml. See Configuring a custom README template of dtool's documentation." -:: +All paths provided in these environment variables must be relative to this +repository's `dtool-lookup-webapp/public` as root. +Setting any of the `VUE_APP_OFFER_DTOOL_README_YAML_DOWNLOAD`, +`VUE_APP_OFFER_DTOOL_JSON_DOWNLOAD`, `VUE_APP_SHOW_INFO_MENU_ENTRY` to `true` +will show a download button for a `dtool_readme.yml` template, for a +`dtool.json` configuration file, and a button for displaying arbitrary +textual information configured with `VUE_APP_INFO_CONTENT`. +Per default, all these buttons are hidden. + +To apply changes to the `.env` file, execute: + +.. code-block:: bash + + npm install + +Development Server +------------------ + +To start a development server: + +.. code-block:: bash cd dtool-lookup-webapp npm run serve +Building for Production +----------------------- -Compile into a static single page website ------------------------------------------ +To compile the application into a static single-page website: -:: +.. code-block:: bash cd dtool-lookup-webapp npm run build +Fixing Broken Installations +--------------------------- + +To address issues with dependencies in a broken installation: + +.. code-block:: bash + + rm -rf dist/ node_modules/ + rm package-lock.json + +Then, reinstall the Vue CLI service and rebuild: + +.. code-block:: bash + + npm install @vue/cli-service + npm run build + +Testing +------- + +Testing requires the `jest.config.js` configuration file, which can be auto-generated by: + +.. code-block:: bash + + vue add unit-jest + +This step follows the global installation of the Vue CLI: + +.. code-block:: bash + + npm install -g @vue/cli -More information ----------------- +Additional Information +---------------------- -See dtool-lookup-webapp/README.md for more information about how to develop and build. -See provision/README.rst for instructions on how to deploy using Ansibl.e +For more details on development and build processes, refer to the `README.md` file within the `dtool-lookup-webapp` directory. For deployment instructions using Ansible, consult the `provision/README.rst`. diff --git a/dtool-lookup-webapp/jest.config.js b/dtool-lookup-webapp/jest.config.js new file mode 100644 index 0000000..0f95791 --- /dev/null +++ b/dtool-lookup-webapp/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: '@vue/cli-plugin-unit-jest' +} diff --git a/dtool-lookup-webapp/package.json b/dtool-lookup-webapp/package.json index e51415b..f944aff 100644 --- a/dtool-lookup-webapp/package.json +++ b/dtool-lookup-webapp/package.json @@ -5,19 +5,21 @@ "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", + "test:unit": "vue-cli-service test:unit", "lint": "vue-cli-service lint" }, "dependencies": { + "@popperjs/core": "^2.11.7", "@soerenmartius/vue3-clipboard": "^0.1.2", - "@vue/compat": "^3.2.31", + "@vue/compat": "^3.4.15", "axios": "^1.1.3", - "bootstrap": "^5.1.3", - "bootstrap-vue-3": "^0.3.12", + "bootstrap": "^5.3.2", + "bootstrap-vue-next": "^0.16.6", "core-js": "^3.21.1", - "filesize": "^8.0.7", + "filesize": "9.0.11", "json2yaml": "^1.1.0", "moment": "^2.24.0", - "vue": "^3.2.31", + "vue": "^3.2.26", "vue-axios": "^3.4.1", "vuex": "^4.0.2" }, @@ -26,11 +28,20 @@ "@babel/preset-react": "^7.16.7", "@vue/cli-plugin-babel": "^5.0.3", "@vue/cli-plugin-eslint": "^5.0.4", + "@vue/cli-plugin-unit-jest": "~5.0.0", "@vue/cli-service": "^5.0.4", - "@vue/compiler-sfc": "^3.2.31", - "@vue/eslint-config-prettier": "^7.0.0", + "@vue/compiler-sfc": "^3.4.15", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/test-utils": "^2.0.0-0", + "@vue/vue3-jest": "^27.0.0-alpha.1", + "babel-jest": "^27.0.6", + "deepmerge": "^4.3.1", "eslint": "^8.11.0", "eslint-plugin-vue": "^9.6.0", + "flush-promises": "^1.0.2", + "jest": "^27.0.5", + "sass": "^1.71.1", + "sass-loader": "^14.1.1", "webpack": "^5.7.0" } } diff --git a/dtool-lookup-webapp/public/data/templates/dtool.json b/dtool-lookup-webapp/public/data/templates/dtool.json new file mode 100644 index 0000000..a723636 --- /dev/null +++ b/dtool-lookup-webapp/public/data/templates/dtool.json @@ -0,0 +1,21 @@ + +{ + "DSERVER_TOKEN_GENERATOR_URL": "https://demo.dtool.dev/token", + "DSERVER_URL": "https://demo.dtool.dev/lookup", + "DSERVER_USERNAME": "testuser", + "DSERVER_VERIFY_SSL": "true", + "DTOOL_README_TEMPLATE_FPATH": "/path/to/.dtool_readme.yml", + "DTOOL_S3_ACCESS_KEY_ID_test-bucket": "testuser_access_key", + "DTOOL_S3_DATASET_PREFIX": "u/testuser/", + "DTOOL_S3_ENDPOINT_test-bucket": "http://demo.dtool.dev:9000", + "DTOOL_S3_SECRET_ACCESS_KEY_test-bucket": "testuser_secret_key", + "DTOOL_SMB_DOMAIN_test-share": "WORKGROUP", + "DTOOL_SMB_PASSWORD_test-share": "a-guest-needs-no-password", + "DTOOL_SMB_PATH_test-share": "dtool", + "DTOOL_SMB_SERVER_NAME_test-share": "demo.dtool.dev", + "DTOOL_SMB_SERVER_PORT_test-share": 445, + "DTOOL_SMB_SERVICE_NAME_test-share": "sambashare", + "DTOOL_SMB_USERNAME_test-share": "guest", + "DTOOL_USER_EMAIL": "you@your-dept.your-institution", + "DTOOL_USER_FULL_NAME": "Your full name" +} diff --git a/dtool-lookup-webapp/public/data/templates/dtool_readme.yml b/dtool-lookup-webapp/public/data/templates/dtool_readme.yml new file mode 100644 index 0000000..26271f3 --- /dev/null +++ b/dtool-lookup-webapp/public/data/templates/dtool_readme.yml @@ -0,0 +1,12 @@ +project: Project name +description: Short description +owners: + - name: {DTOOL_USER_FULL_NAME} + email: {DTOOL_USER_EMAIL} + username: {username} + orcid: Your orcid +funders: + - organization: Your funding organization + program: Your program + code: Program code +creation_date: '{date}' \ No newline at end of file diff --git a/dtool-lookup-webapp/public/dtool_logo.ico b/dtool-lookup-webapp/public/dtool_logo.ico new file mode 100644 index 0000000..645bb4c Binary files /dev/null and b/dtool-lookup-webapp/public/dtool_logo.ico differ diff --git a/dtool-lookup-webapp/public/favicon.ico b/dtool-lookup-webapp/public/favicon.ico deleted file mode 100644 index df36fcf..0000000 Binary files a/dtool-lookup-webapp/public/favicon.ico and /dev/null differ diff --git a/dtool-lookup-webapp/public/icons/128x128/dtool_logo.png b/dtool-lookup-webapp/public/icons/128x128/dtool_logo.png new file mode 100644 index 0000000..2482f02 Binary files /dev/null and b/dtool-lookup-webapp/public/icons/128x128/dtool_logo.png differ diff --git a/dtool-lookup-webapp/public/index.html b/dtool-lookup-webapp/public/index.html index ed955fe..804b0b0 100644 --- a/dtool-lookup-webapp/public/index.html +++ b/dtool-lookup-webapp/public/index.html @@ -4,7 +4,7 @@ - + dtool-lookup-webapp diff --git a/dtool-lookup-webapp/src/App.vue b/dtool-lookup-webapp/src/App.vue index 29af21e..94ab547 100644 --- a/dtool-lookup-webapp/src/App.vue +++ b/dtool-lookup-webapp/src/App.vue @@ -1,9 +1,43 @@ - + diff --git a/dtool-lookup-webapp/src/components/DatasetReadme.vue b/dtool-lookup-webapp/src/components/DatasetReadme.vue index a301cc5..2346416 100644 --- a/dtool-lookup-webapp/src/components/DatasetReadme.vue +++ b/dtool-lookup-webapp/src/components/DatasetReadme.vue @@ -1,19 +1,95 @@ - + diff --git a/dtool-lookup-webapp/src/components/DatasetSorting.vue b/dtool-lookup-webapp/src/components/DatasetSorting.vue new file mode 100644 index 0000000..4feb857 --- /dev/null +++ b/dtool-lookup-webapp/src/components/DatasetSorting.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/dtool-lookup-webapp/src/components/DatasetSummary.vue b/dtool-lookup-webapp/src/components/DatasetSummary.vue index ef39562..79b7289 100644 --- a/dtool-lookup-webapp/src/components/DatasetSummary.vue +++ b/dtool-lookup-webapp/src/components/DatasetSummary.vue @@ -4,10 +4,12 @@

{{ dataset.name }}

Created by {{ dataset.creator_username }} on - {{ moment(dataset.created_at*1000).format("YYYY-MM-DD") }}, frozen on - {{ moment(dataset.frozen_at*1000).format("YYYY-MM-DD") }}{{ moment(dataset.created_at * 1000).format("YYYY-MM-DD") }}, frozen on + {{ moment(dataset.frozen_at * 1000).format("YYYY-MM-DD") }}  - {{ numItems }} items{{ numItems }} items  {{ filesize(total_size_in_bytes) @@ -16,109 +18,165 @@
{{ dataset.uri }} - - The command below copies the dataset to the working - directory - - - - - - - - - + + + + +
-
- diff --git a/dtool-lookup-webapp/src/components/DatasetTable.vue b/dtool-lookup-webapp/src/components/DatasetTable.vue index 5c7ac68..ed6a659 100644 --- a/dtool-lookup-webapp/src/components/DatasetTable.vue +++ b/dtool-lookup-webapp/src/components/DatasetTable.vue @@ -11,11 +11,8 @@ >
{{ dataset.name }}
- created: {{ - moment(dataset.created_at*1000).format("YYYY-MM-DD") - }} - frozen: {{ - moment(dataset.frozen_at*1000).format("YYYY-MM-DD") + {{ + moment(dataset.created_at * 1000).format("YYYY-MM-DD") }}
@@ -44,25 +41,26 @@ var moment = require("moment"); export default { name: "DatasetTable", props: { - datasetHits: Array + datasetHits: Array, + responseheaders: {}, }, - data: function() { + data: function () { return { - moment: moment + moment: moment, }; }, computed: { - selected: function() { + selected: function () { return this.$store.state.current_dataset_index; - } + }, }, methods: { - updateSelectedDataset: function(index) { + updateSelectedDataset: function (index) { this.$store.commit("update_current_dataset_index", index); this.$store.commit("update_current_dataset", this.datasetHits[index]); this.$emit("update-dataset"); - } - } + }, + }, }; diff --git a/dtool-lookup-webapp/src/components/NumDatasets.vue b/dtool-lookup-webapp/src/components/NumDatasets.vue index 31a6cdb..a78113f 100644 --- a/dtool-lookup-webapp/src/components/NumDatasets.vue +++ b/dtool-lookup-webapp/src/components/NumDatasets.vue @@ -2,37 +2,30 @@
-
  • -
    +
    + All - All - - - - {{ - summary_info["number_of_datasets"] + {{ + summary_info.number_of_datasets }}
    -
  • + -
  • -
  • +
    @@ -41,21 +34,24 @@ - + diff --git a/dtool-lookup-webapp/src/components/SignIn.vue b/dtool-lookup-webapp/src/components/SignIn.vue index f80038f..ba378ae 100644 --- a/dtool-lookup-webapp/src/components/SignIn.vue +++ b/dtool-lookup-webapp/src/components/SignIn.vue @@ -1,53 +1,106 @@ - diff --git a/dtool-lookup-webapp/src/components/SummaryInfo.vue b/dtool-lookup-webapp/src/components/SummaryInfo.vue index c3064cd..444a5f4 100644 --- a/dtool-lookup-webapp/src/components/SummaryInfo.vue +++ b/dtool-lookup-webapp/src/components/SummaryInfo.vue @@ -42,52 +42,64 @@ import NumDatasets from "./NumDatasets.vue"; import TagFilter from "./TagFilter.vue"; import BaseUriFilter from "./BaseUriFilter.vue"; import CreatorUsernameFilter from "./CreatorUsernameFilter.vue"; +import { getUsernameFromJwt } from "@/utils/jwtUtils"; + export default { name: "SummaryInfo", props: { lookup_url: String, - auth_str: String + auth_str: String, + token: String, }, - data: function() { + data: function () { return { summary_info: null, loading: true, - errored: false + errored: false, + username: "", }; }, computed: { - source: function() { - return this.lookup_url + "/dataset/summary"; - } + // Dynamically constructs the API endpoint URL using the provided username. + source: function () { + return this.lookup_url + "/users/" + this.username + "/summary"; + }, }, methods: { - load_summary: function() { + load_summary: function () { console.log("Loading summary info"); this.errored = false; this.loading = true; this.$http .get(this.source, { headers: { Authorization: this.auth_str } }) - .then(response => (this.summary_info = response.data)) - .catch(error => { + .then((response) => (this.summary_info = response.data)) + .catch((error) => { console.log(error); - console.log(error.response); this.errored = true; }) .finally(() => (this.loading = false)); }, - searchDatasets: function() { + searchDatasets: function () { + this.$store.state.current_pageNumber=1; // Resetting the page number to 1 if we make any changes in the filters. this.$emit("start-search"); - } + }, }, mounted() { + if (this.token) { + // Extracts username from the JWT token and initializes the component state + const username = getUsernameFromJwt(this.token); + + this.username = username; + this.$store.commit("updateUsername", username); + } this.load_summary(); }, components: { NumDatasets, TagFilter, BaseUriFilter, - CreatorUsernameFilter - } + CreatorUsernameFilter, + }, }; diff --git a/dtool-lookup-webapp/src/components/TemplateDownloader.vue b/dtool-lookup-webapp/src/components/TemplateDownloader.vue new file mode 100644 index 0000000..85b6c5a --- /dev/null +++ b/dtool-lookup-webapp/src/components/TemplateDownloader.vue @@ -0,0 +1,113 @@ +/** + * Component: TemplateDownloader + * Description: This component renders a button and a dropdown menu. The button is used for logout functionality, and the dropdown menu is used to download files and display information. + * + * Props: + * - None + * + * Data: + * - downloadReadmeYaml: A boolean indicating whether to offer the download of dtool_readme.yml file. + * - downloadReadmeJson: A boolean indicating whether to offer the download of dtool.json file. + * - showInfoMenuEntry: A boolean indicating whether to show the "Info" menu entry. + * - infoContent: A string containing the content to be displayed in the info modal. + * + * Events: + * - logoutAction: This event is emitted when the logout button is clicked. + * + * Methods: + * - logout: A method that emits the "logoutAction" event. + * - downloadFile: A method that downloads a file based on the provided file name. + * - showInfo: A method that shows the info modal. + * + */ + + + + + diff --git a/dtool-lookup-webapp/src/components/TextSearch.vue b/dtool-lookup-webapp/src/components/TextSearch.vue index 3c2f1bf..eeb3337 100644 --- a/dtool-lookup-webapp/src/components/TextSearch.vue +++ b/dtool-lookup-webapp/src/components/TextSearch.vue @@ -1,29 +1,111 @@ - + diff --git a/dtool-lookup-webapp/src/main.js b/dtool-lookup-webapp/src/main.js index ffa2a8d..be18e8c 100644 --- a/dtool-lookup-webapp/src/main.js +++ b/dtool-lookup-webapp/src/main.js @@ -1,20 +1,20 @@ -import { createApp } from "vue"; -import App from "./App.vue"; -import { store } from './store' +import { createApp } from 'vue'; +import App from './App.vue'; +import { store } from './store'; -import axios from "axios"; -import BootstrapVue3 from 'bootstrap-vue-3'; -import VueAxios from 'vue-axios' +import axios from 'axios'; +import { createBootstrap } from 'bootstrap-vue-next'; +import VueAxios from 'vue-axios'; import { VueClipboard } from '@soerenmartius/vue3-clipboard'; -import "bootstrap/dist/css/bootstrap.css"; -import "bootstrap-vue-3/dist/bootstrap-vue-3.css"; +import './assets/css/custom.scss'; +import 'bootstrap-vue-next/dist/bootstrap-vue-next.css'; const app = createApp(App); -app.use(BootstrapVue3); +app.use(createBootstrap()); app.use(VueClipboard); app.use(store); -app.use(VueAxios, axios) +app.use(VueAxios, axios); app.config.productionTip = false; -app.mount("#app"); +app.mount('#app'); diff --git a/dtool-lookup-webapp/src/store.js b/dtool-lookup-webapp/src/store.js index 5ef4be7..45d67ec 100644 --- a/dtool-lookup-webapp/src/store.js +++ b/dtool-lookup-webapp/src/store.js @@ -1,22 +1,31 @@ -import { createStore } from 'vuex' +import { createStore } from "vuex"; export const store = createStore({ state: { free_text: null, + mongo_text: null, creator_usernames: [], base_uris: [], tags: [], + username: null, current_dataset_index: 0, current_dataset: null, current_dataset_manifest: null, current_dataset_readme: null, current_dataset_annotations: null, - num_filtered: 0 + current_dataset_tags: null, + num_filtered: 0, + update_current_Per_Page: 10, + current_pageNumber:1, + selected_sort_option: "uri", }, mutations: { update_free_text(state, free_text) { state.free_text = free_text; }, + update_mongo_text(state, mongo_text) { + state.mongo_text = mongo_text; + }, update_creator_usernames(state, creator_usernames) { state.creator_usernames = creator_usernames; }, @@ -29,6 +38,9 @@ export const store = createStore({ update_current_dataset_index(state, index) { state.current_dataset_index = index; }, + update_current_pageNumber(state,pageNumber) { + state.current_pageNumber = pageNumber; + }, update_current_dataset(state, dataset) { state.current_dataset = dataset; }, @@ -41,15 +53,33 @@ export const store = createStore({ update_current_dataset_annotations(state, annotations) { state.current_dataset_annotations = annotations; }, + update_current_dataset_tags(state, tags) { + state.current_dataset_tags = tags; + }, update_num_filtered(state, num_filtered) { state.num_filtered = num_filtered; }, + update_current_Per_Page(state, perpage) { + state.update_current_Per_Page = perpage; + }, + updateUsername(state, username) { + state.username = username; + }, + update_selected_sort_option(state, selected_sort_option) { + state.selected_sort_option = selected_sort_option; + }, + clear_all(state) { + state.username = null; state.free_text = null; + state.mongo_text = null; state.creator_usernames = []; state.tags = []; state.base_uris = []; - } + + }, }, - actions: {} + actions: {}, }); + + diff --git a/dtool-lookup-webapp/src/utils/jwtUtils.js b/dtool-lookup-webapp/src/utils/jwtUtils.js new file mode 100644 index 0000000..3bcf1ed --- /dev/null +++ b/dtool-lookup-webapp/src/utils/jwtUtils.js @@ -0,0 +1,18 @@ +// jwtUtils.js + +// This function decodes a JWT token to extract the payload. +export function decodeJwt(token) { + const base64Url = token.split('.')[1]; + const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); + const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }).join('')); + + return JSON.parse(jsonPayload); +} + +// This function extracts the username (from the 'sub' field) from a decoded JWT token. +export function getUsernameFromJwt(token) { + const decodedToken = decodeJwt(token); + return decodedToken.sub; // 'sub' contains the username. +} diff --git a/dtool-lookup-webapp/tests/unit/jsontest.spec.js b/dtool-lookup-webapp/tests/unit/jsontest.spec.js new file mode 100644 index 0000000..9e99987 --- /dev/null +++ b/dtool-lookup-webapp/tests/unit/jsontest.spec.js @@ -0,0 +1,28 @@ +import { shallowMount } from '@vue/test-utils' +import TextSearch from '@/components/TextSearch.vue' + +describe('TextSearch', () => { + it('sets the "is-invalid" class if "isJson" is false', () => { + const wrapper = shallowMount(TextSearch, { + data() { + return { + textQuery: 'not a valid JSON Query', + } + }, + }) + const span = wrapper.find('.jsonChecker') + expect(span.classes()).toContain('is-invalid') + }) + + it('sets the "is-valid" class if "isJson" is true', () => { + const wrapper = shallowMount(TextSearch, { + data() { + return { + textQuery: '{"valid": "JSON Query"}', + } + }, + }) + const span = wrapper.find('.jsonChecker') + expect(span.classes()).toContain('is-valid') + }) +}) diff --git a/dtool-lookup-webapp/tests/unit/paginationtest.spec.js b/dtool-lookup-webapp/tests/unit/paginationtest.spec.js new file mode 100644 index 0000000..d72f7c6 --- /dev/null +++ b/dtool-lookup-webapp/tests/unit/paginationtest.spec.js @@ -0,0 +1,27 @@ +import { mount } from '@vue/test-utils'; +import Pagination from '@/App.vue'; +import { createStore } from "vuex"; + + +describe("Pagination", () => { + it("renders the pagination component when shouldShowPagination is true", () => { + const store = createStore({ + state: { + update_current_Per_Page: 10, + }, + }); + const wrapper = mount(Pagination, { + propsData: { + shouldShowPagination: false, + pagination: { + total: 30, + }, + }, + global: { + plugins: [store], + }, + }); + expect(wrapper.find('.pagination-component').exists()).toBe(false) + }); +}); + diff --git a/dtool-lookup-webapp/tests/unit/version.spec.js b/dtool-lookup-webapp/tests/unit/version.spec.js new file mode 100644 index 0000000..b83d92e --- /dev/null +++ b/dtool-lookup-webapp/tests/unit/version.spec.js @@ -0,0 +1,45 @@ +import { mount } from "@vue/test-utils"; +import DatasetReadme from "@/components/DatasetReadme.vue"; +import { createStore } from "vuex"; +const yaml = require("js-yaml"); + +describe("DatasetReadme", () => { + it("displays the current version readme when the current version is equal to the required version", () => { + const store = createStore({ + state: { + current_dataset_readme: "This is the current version readme", + current_required_version: "0.18.0", + }, + }); + const wrapper = mount(DatasetReadme, { + propsData: { + getinfo: { version: "0.18.0" }, + }, + global: { + plugins: [store], + }, + }); + expect(wrapper.find("pre").text()).toBe("This is the current version readme"); + }); + + it("displays the current version readme as YAML when the current version is less than the required version", () => { + const store = createStore({ + state: { + current_dataset_readme: "---\nThis is the current version readme", + current_required_version: "0.18.0", + }, + }); + const wrapper = mount(DatasetReadme, { + propsData: { + getinfo: { version: "0.17.0" }, + }, + global: { + plugins: [store], + }, + }); + const expected = "---\nThis is the current version readme"; + const received = wrapper.find("pre").text(); + + expect(received).toBe(expected); + }); +});