15067: Adds tests for vocabulary functions. 15067-tag-editing-by-ids
authorLucas Di Pentima <lucas@di-pentima.com.ar>
Thu, 14 Nov 2019 18:45:14 +0000 (15:45 -0300)
committerLucas Di Pentima <lucas@di-pentima.com.ar>
Thu, 14 Nov 2019 18:45:14 +0000 (15:45 -0300)
Fixed a couple of bugs in the process.

Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima@veritasgenetics.com>

src/models/vocabulary.test.ts [new file with mode: 0644]
src/models/vocabulary.ts

diff --git a/src/models/vocabulary.test.ts b/src/models/vocabulary.test.ts
new file mode 100644 (file)
index 0000000..87a8dfb
--- /dev/null
@@ -0,0 +1,148 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as Vocabulary from './vocabulary';
+import { pipe } from 'lodash/fp';
+
+describe('Vocabulary', () => {
+    let vocabulary: Vocabulary.Vocabulary;
+
+    beforeEach(() => {
+        vocabulary = {
+            strict_tags: false,
+            tags: {
+                IDKEYCOMMENT: {
+                    labels: []
+                },
+                IDKEYANIMALS: {
+                    strict: false,
+                    labels: [
+                        {label: "Animal" },
+                        {label: "Creature"}
+                    ],
+                    values: {
+                        IDVALANIMALS1: {
+                            labels: [
+                                {label: "Human"},
+                                {label: "Homo sapiens"}
+                            ]
+                        },
+                        IDVALANIMALS2: {
+                            labels: [
+                                {label: "Dog"},
+                                {label: "Canis lupus familiaris"}
+                            ]
+                        },
+                    }
+                },
+                IDKEYSIZES: {
+                    labels: [{label: "Sizes"}],
+                    values: {
+                        IDVALSIZES1: {
+                            labels: [{label: "Small"}]
+                        },
+                        IDVALSIZES2: {
+                            labels: [{label: "Medium"}]
+                        },
+                        IDVALSIZES3: {
+                            labels: [{label: "Large"}]
+                        },
+                        IDVALSIZES4: {
+                            labels: []
+                        }
+                    }
+                }
+            }
+        }
+    });
+
+    it('returns the list of tag keys', () => {
+        const tagKeys = Vocabulary.getTags(vocabulary);
+        // Alphabetically ordered by label
+        expect(tagKeys).toEqual([
+            {id: "IDKEYANIMALS", label: "Animal"},
+            {id: "IDKEYANIMALS", label: "Creature"},
+            {id: "IDKEYCOMMENT", label: "IDKEYCOMMENT"},
+            {id: "IDKEYSIZES", label: "Sizes"},
+        ]);
+    });
+
+    it('returns the tag values for a given key', () => {
+        const tagValues = Vocabulary.getTagValues('IDKEYSIZES', vocabulary);
+        // Alphabetically ordered by label
+        expect(tagValues).toEqual([
+            {id: "IDVALSIZES4", label: "IDVALSIZES4"},
+            {id: "IDVALSIZES3", label: "Large"},
+            {id: "IDVALSIZES2", label: "Medium"},
+            {id: "IDVALSIZES1", label: "Small"},
+        ])
+    });
+
+    it('returns an empty list of values for an non-existent key', () => {
+        const tagValues = Vocabulary.getTagValues('IDNONSENSE', vocabulary);
+        expect(tagValues).toEqual([]);
+    });
+
+    it('returns a key id for a given key label', () => {
+        const testCases = [
+            // Two labels belonging to the same ID
+            {keyLabel: 'Animal', expected: 'IDKEYANIMALS'},
+            {keyLabel: 'Creature', expected: 'IDKEYANIMALS'},
+            // Non-existent label returns empty string
+            {keyLabel: 'ThisKeyLabelDoesntExist', expected: ''},
+        ]
+        testCases.forEach(tc => {
+            const tagValueID = Vocabulary.getTagKeyID(tc.keyLabel, vocabulary);
+            expect(tagValueID).toEqual(tc.expected);
+        });
+    });
+
+    it('returns an key label for a given key id', () => {
+        const testCases = [
+            // ID with many labels return the first one
+            {keyID: 'IDKEYANIMALS', expected: 'Animal'},
+            // Key IDs without any labels or unknown keys should return the literal
+            // key from the API's response (that is, the key 'id')
+            {keyID: 'IDKEYCOMMENT', expected: 'IDKEYCOMMENT'},
+            {keyID: 'FOO', expected: 'FOO'},
+        ]
+        testCases.forEach(tc => {
+            const tagValueID = Vocabulary.getTagKeyLabel(tc.keyID, vocabulary);
+            expect(tagValueID).toEqual(tc.expected);
+        });
+    });
+
+    it('returns a value id for a given key id and value label', () => {
+        const testCases = [
+            // Key ID and value label known
+            {keyID: 'IDKEYANIMALS', valueLabel: 'Human', expected: 'IDVALANIMALS1'},
+            {keyID: 'IDKEYANIMALS', valueLabel: 'Homo sapiens', expected: 'IDVALANIMALS1'},
+            // Key ID known, value label unknown
+            {keyID: 'IDKEYANIMALS', valueLabel: 'Dinosaur', expected: ''},
+            // Key ID unknown
+            {keyID: 'IDNONSENSE', valueLabel: 'Does not matter', expected: ''},
+        ]
+        testCases.forEach(tc => {
+            const tagValueID = Vocabulary.getTagValueID(tc.keyID, tc.valueLabel, vocabulary);
+            expect(tagValueID).toEqual(tc.expected);
+        });
+    });
+
+    it('returns a value label for a given key & value id pair', () => {
+        const testCases = [
+            // Known key & value ids with multiple value labels: returns the first label
+            {keyId: 'IDKEYANIMALS', valueId: 'IDVALANIMALS1', expected: 'Human'},
+            // Values without label or unknown values should return the literal value from
+            // the API's response (that is, the value 'id')
+            {keyId: 'IDKEYSIZES', valueId: 'IDVALSIZES4', expected: 'IDVALSIZES4'},
+            {keyId: 'IDKEYCOMMENT', valueId: 'FOO', expected: 'FOO'},
+            {keyId: 'IDKEYANIMALS', valueId: 'BAR', expected: 'BAR'},
+            {keyId: 'IDKEYNONSENSE', valueId: 'FOOBAR', expected: 'FOOBAR'},
+        ]
+        testCases.forEach(tc => {
+            const tagValueLabel = Vocabulary.getTagValueLabel(tc.keyId, tc.valueId, vocabulary);
+            expect(tagValueLabel).toEqual(tc.expected);
+        });
+    });
+});
index ebef70f025defdfd8573da8d85a1779ddcd09742..03f28c07bf9c5edc21de1e1996c52f28156c5f89 100644 (file)
@@ -25,8 +25,8 @@ export interface Tag {
 }
 
 export interface PropFieldSuggestion {
-    "id": string;
-    "label": string;
+    id: string;
+    label: string;
 }
 
 const VOCABULARY_VALIDATORS = [
@@ -68,7 +68,7 @@ export const getTagValues = (tagKeyID: string, vocabulary: Vocabulary) => {
     const tag = vocabulary.tags[tagKeyID];
     const ret = tag && tag.values
         ? Object.keys(tag.values).map(
-            tagValueID => tag.values![tagValueID].labels
+            tagValueID => tag.values![tagValueID].labels && tag.values![tagValueID].labels.length > 0
                 ? tag.values![tagValueID].labels.map(
                     lbl => Object.assign({}, {"id": tagValueID, "label": lbl.label}))
                 : [{"id": tagValueID, "label": tagValueID}])
@@ -81,7 +81,7 @@ export const getTagValues = (tagKeyID: string, vocabulary: Vocabulary) => {
 export const getTags = ({ tags }: Vocabulary) => {
     const ret = tags && Object.keys(tags)
         ? Object.keys(tags).map(
-            tagID => tags[tagID].labels
+            tagID => tags[tagID].labels && tags[tagID].labels.length > 0
                 ? tags[tagID].labels.map(
                     lbl => Object.assign({}, {"id": tagID, "label": lbl.label}))
                 : [{"id": tagID, "label": tagID}])