{"action":"created","comment":{"url":"https://api.github.com/repos/google/ggrc-core/pulls/comments/191425541","pull_request_review_id":123858150,"id":191425541,"diff_hunk":"@@ -68,26 +673,1070 @@ describe('GGRC.Components.assessmentInfoPane', function () {\n \n       it(`returns false if there is audit\n         but it is not allowed to read instance.audit`, ()=> {\n-          vm.attr('instance.audit', {});\n-          spyOn(Permission, 'is_allowed_for').and.returnValue(false);\n+        vm.attr('instance.audit', {});\n+        spyOn(Permission, 'is_allowed_for').and.returnValue(false);\n \n-          let result = vm.attr('isAllowedToMap');\n+        let result = vm.attr('isAllowedToMap');\n \n-          expect(result).toBe(false);\n-        });\n+        expect(result).toBe(false);\n+      });\n     });\n   });\n \n-  describe('onStateChange() method', () => {\n-    let method;\n+  describe('afterCreate() method', () => {\n+    let event;\n+    let type;\n+    let items;\n \n-    beforeEach(() => {\n-      method = vm.onStateChange.bind(vm);\n-      spyOn(tracker, 'start').and.returnValue(() => {});\n+    beforeEach(function () {\n+      type = 'type';\n+      const commonStamp = [{}, {}];\n+      const beforeCreate = [{\n+        data: 'Fake data 1',\n+        isDraft: false,\n+        _stamp: commonStamp[0],\n+      }, {\n+        data: 'Fake data 2',\n+        isDraft: false,\n+        _stamp: commonStamp[1],\n+      }, {\n+        data: 'Fake data 3',\n+        isDraft: false,\n+        _stamp: {},\n+      }];\n+      vm.attr(type, beforeCreate);\n+      items = new can.List([{\n+        data: 'Important data 1',\n+        isDraft: true,\n+        _stamp: vm\n+          .attr(type)[1]\n+          .attr('_stamp'),\n+      }, {\n+        data: 'Important data 2',\n+        isDraft: true,\n+        _stamp: vm\n+          .attr(type)[0]\n+          .attr('_stamp'),\n+      }, {\n+        data: 'Important data 3',\n+        isDraft: true,\n+        _stamp: {},\n+      }]);\n+      event = {\n+        items,\n+        success: true,\n+      };\n+    });\n+\n+    it('sets \"isUpdating{<passed capitalized type>}\" property to false',\n+      function () {\n+        const expectedProp = `isUpdating${can.capitalize(type)}`;\n+        vm.attr(expectedProp, true);\n+        vm.afterCreate(event, type);\n+        expect(vm.attr(expectedProp)).toBe(false);\n+      });\n+\n+    it('sets new items only if each item from them is saved', function () {\n+      const expectedResult = [{\n+        data: 'Fake data 3',\n+        isDraft: false,\n+        _stamp: {},\n+      }];\n+      event.success = false;\n+      vm.afterCreate(event, type);\n+      expect(vm.attr(type).attr()).toEqual(expectedResult);\n+    });\n+\n+    describe('if some item from passed items has the same _stamp field value ' +\n+    'as some item from original items array', () => {\n+      it('removes _stamp and isDraft props from passed items placed in event ' +\n+      'object', function () {\n+        const expected = [{\n+          data: 'Important data 1',\n+        }, {\n+          data: 'Important data 2',\n+        }, {\n+          data: 'Important data 3',\n+          isDraft: true,\n+          _stamp: {},\n+        }];\n+        vm.afterCreate(event, type);\n+        expect(items.serialize()).toEqual(expected);\n+      });\n+\n+      it('sets the flag isNotSaved to true for item from passed items if ' +\n+      'event.success is false', function () {\n+        const expected = [{\n+          data: 'Important data 1',\n+          isNotSaved: true,\n+        }, {\n+          data: 'Important data 2',\n+          isNotSaved: true,\n+        }, {\n+          data: 'Important data 3',\n+          isDraft: true,\n+          _stamp: {},\n+        }];\n+        event.success = false;\n+        vm.afterCreate(event, type);\n+        expect(items.serialize()).toEqual(expected);\n+      });\n+    });\n+  });\n+\n+  describe('addItems() method', () => {\n+    let type;\n+    let event;\n+\n+    beforeEach(function () {\n+      type = 'Type';\n+      event = {\n+        items: [1, 2, 3],\n+      };\n+      vm.attr(type, [4, 5, 6]);\n+    });\n+\n+    it('pushes items from event into beginning of the list with name from ' +\n+    'type param', function () {\n+      const beforeInvoke = vm.attr(type).serialize();\n+      const expectedResult = event.items.concat(beforeInvoke);\n+      vm.addItems(event, type);\n+      expect(vm.attr(type).attr()).toEqual(expectedResult);\n+    });\n+\n+    it('sets \"isUpdating{<passed capitalized type>}\" property to true',\n+      function () {\n+        const expectedProp = `isUpdating${can.capitalize(type)}`;\n+        vm.attr(expectedProp, false);\n+\n+        vm.addItems(event, type);\n+        expect(vm.attr(expectedProp)).toBe(true);\n+      });\n+\n+    it('makes array from event.items if it is array-like object', function () {\n+      const beforeInvoke = vm.attr(type).serialize();\n+      const expectedResult = event.items.concat(beforeInvoke);\n+\n+      event.items = new can.List(event.items);\n+      vm.addItems(event, type);\n+\n+      expect(vm\n+        .attr(type)\n+        .serialize()\n+      ).toEqual(expectedResult);\n+    });\n+  });\n+\n+  describe('addAction() method', () => {\n+    let actionType;\n+    let related;\n+    let actionsRoot;\n+\n+    beforeEach(function () {\n+      const instanceName = 'instance';\n+\n+      actionsRoot = `${instanceName}.actions`;\n+      actionType = 'actionType';\n+      related = {\n+        data: 'Important data',\n+      };\n+      vm.attr(instanceName, {});\n+    });\n \n+    it('sets instance.actions to empty object if there are no actions',\n+      function () {\n+        vm.addAction(actionType, related);\n+        expect(vm.attr(actionsRoot).attr()).toBeDefined();\n+      });\n+\n+    it('pushes into actions.{<passed actionType>} passed related item if ' +\n+    'there is actions.{<passed actionType>}', function () {\n+      const itemsPath = `${actionsRoot}.${actionType}`;\n+\n+      vm.attr(actionsRoot, {});\n+      vm.attr(itemsPath, [{}]);\n+      vm.addAction(actionType, related);\n+\n+      const last = vm.attr(itemsPath).pop();\n+      expect(last.serialize()).toEqual(related);\n+    });\n+\n+    it('creates actions.{<passed actionType>} list for instance with passed ' +\n+    'related item', function () {\n+      const expected = [related];\n+      const itemsPath = `${actionsRoot}.${actionType}`;\n+      vm.addAction(actionType, related);\n+      expect(vm\n+        .attr(itemsPath)\n+        .serialize()\n+      ).toEqual(expected);\n+    });\n+  });\n+\n+  describe('addRelatedItem() method', () => {\n+    let assessment;\n+    let event;\n+    let type;\n+    let related;\n+    let dfd;\n+\n+    beforeEach(function () {\n+      dfd = can.Deferred();\n+      type = 'type';\n+      event = {\n+        item: new can.Map({\n+          id: 1,\n+          type: 'Type',\n+        }),\n+      };\n+      related = {\n+        id: event.item.attr('id'),\n+        type: event.item.attr('type'),\n+      };\n+      assessment = new can.Map({\n+        actions: [],\n+      });\n+\n+      vm.attr('instance', {});\n+      vm.attr('instance').dispatch = jasmine.createSpy('dispatch');\n+      vm.attr('deferredSave', {\n+        push: jasmine.createSpy('push').and.returnValue(dfd),\n+      });\n+\n+      spyOn(vm, 'addAction');\n+      spyOn(vm, 'afterCreate');\n+    });\n+\n+    it('pushes into deferredSave transaction queue a function', function () {\n+      const dfdQueue = vm.attr('deferredSave');\n+      vm.addRelatedItem(event, type);\n+      expect(dfdQueue.push).toHaveBeenCalledWith(jasmine.any(Function));\n+    });\n+\n+    describe('pushed function into deferredSave', () => {\n+      let pushedFunc;\n+\n+      beforeEach(function () {\n+        vm.addRelatedItem(event, type);\n+        pushedFunc = vm.attr('deferredSave').push.calls.argsFor(0)[0];\n+      });\n+\n+      it('adds add_related action with related object', function () {\n+        pushedFunc();\n+        expect(vm.addAction).toHaveBeenCalledWith(\n+          'add_related',\n+          related\n+        );\n+      });\n+    });\n+\n+    describe('resolves deferredSave', () => {\n+      beforeEach(function () {\n+        dfd.resolve(assessment);\n+      });\n+\n+      it('calls afterCreate with appropriate params with success equals ' +\n+      'to true', function (done) {\n+        vm.addRelatedItem(event, type);\n+        dfd.then(() => {\n+          expect(vm.afterCreate.calls.count()).toBe(1);\n+          expect(vm.afterCreate).toHaveBeenCalledWith({\n+            items: [event.item],\n+            success: true,\n+          }, type);\n+          done();\n+        });\n+      });\n+    });\n+\n+    describe('rejects deferredSave', () => {\n+      beforeEach(function () {\n+        dfd.reject(assessment);\n+      });\n+\n+      it('calls afterCreate with appropriate params with success equals to ' +\n+      'false', function (done) {\n+        dfd.reject(assessment);\n+        vm.addRelatedItem(event, type);\n+        dfd.fail(() => {\n+          expect(vm.afterCreate.calls.count()).toBe(1);\n+          expect(vm.afterCreate).toHaveBeenCalledWith({\n+            items: [event.item],\n+            success: false,\n+          }, type);\n+          done();\n+        });\n+      });\n+    });\n+\n+    describe('executes always after deferredSave resolving or rejecting',\n+      () => {\n+        it('removes actions for assessment from response after resolve',\n+          function (done) {\n+            dfd.resolve(assessment);\n+            vm.addRelatedItem(event, type);\n+            dfd.always(() => {\n+              expect(assessment.attr('actions')).toBeUndefined();\n+              done();\n+            });\n+          });\n+\n+        it('removes actions for assessment from response after reject',\n+          function (done) {\n+            dfd.reject(assessment);\n+            vm.addRelatedItem(event, type);\n+            dfd.always(() => {\n+              expect(assessment.attr('actions')).toBeUndefined();\n+              done();\n+            });\n+          });\n+      });\n+  });\n+\n+  describe('removeRelatedItem() method', () => {\n+    let dfd;\n+    let type;\n+    let item;\n+    let items;\n+    let related;\n+    let assessment;\n+\n+    beforeEach(function () {\n+      const countOfItems = 3;\n+      dfd = can.Deferred();\n+      type = 'type';\n+      items = new can.List(\n+        Array(countOfItems)\n+      ).map((item, index) => {\n+        return {\n+          id: index,\n+          type: 'Awesome type',\n+        };\n+      });\n+      item = items.attr(countOfItems - 1);\n+      related = {\n+        id: item.attr('id'),\n+        type: item.attr('type'),\n+      };\n+      assessment = new can.Map({\n+        actions: [],\n+      });\n+      vm.attr(type, items);\n+      vm.attr('deferredSave', {\n+        push: jasmine.createSpy('push').and.returnValue(dfd),\n+      });\n+\n+      spyOn(vm, 'addAction');\n+      spyOn(GGRC.Errors, 'notifier');\n+      spyOn(vm, 'refreshCounts');\n+    });\n+\n+    it('sets \"isUpdating{<passed capitalized type>}\" property to true ' +\n+    'before resolving a deferredSave', function () {\n+      const expectedProp = `isUpdating${can.capitalize(type)}`;\n+      vm.removeRelatedItem(item, type);\n+      expect(vm.attr(expectedProp)).toBe(true);\n+    });\n+\n+    it('removes passed item from {<passed type>} list', function () {\n+      vm.removeRelatedItem(item, type);\n+      expect(items.indexOf(item)).toBe(-1);\n+    });\n+\n+    describe('pushed function into deferredSave', () => {\n+      let pushedFunc;\n+\n+      beforeEach(function () {\n+        vm.removeRelatedItem(item, type);\n+        pushedFunc = vm.attr('deferredSave').push.calls.argsFor(0)[0];\n+      });\n+\n+      it('adds remove_related action with related object', function () {\n+        pushedFunc();\n+        expect(vm.addAction).toHaveBeenCalledWith(\n+          'remove_related',\n+          related\n+        );\n+      });\n+    });\n+\n+    describe('rejects deferredSave', () => {\n+      beforeEach(function () {\n+        dfd.reject(assessment);\n+      });\n+\n+      it('shows error', function (done) {\n+        vm.removeRelatedItem(item, type);\n+        dfd.fail(() => {\n+          expect(GGRC.Errors.notifier).toHaveBeenCalledWith(\n+            'error',\n+            'Unable to remove URL.'\n+          );\n+          done();\n+        });\n+      });\n+\n+      it('inserts removed item from {<passed type>} list at previous place',\n+        function (done) {\n+          vm.removeRelatedItem(item, type);\n+          dfd.fail(() => {\n+            expect(items.indexOf(item)).not.toBe(-1);\n+            done();\n+          });\n+        });\n+    });\n+\n+    describe('executes always after deferredSave resolving or rejecting',\n+      () => {\n+        it('sets \"isUpdating{<passed capitalized type>}\" property to false ' +\n+        'after resolve', function (done) {\n+          const expectedProp = `isUpdating${can.capitalize(type)}`;\n+\n+          dfd.resolve(assessment);\n+          vm.removeRelatedItem(item, type);\n+\n+          dfd.always(() => {\n+            expect(vm.attr(expectedProp)).toBe(false);\n+            done();\n+          });\n+        });\n+\n+        it('removes actions for assessment from response after resolve',\n+          function (done) {\n+            dfd.resolve(assessment);\n+            vm.removeRelatedItem(item, type);\n+\n+            dfd.always(() => {\n+              expect(assessment.attr('actions')).toBeUndefined();\n+              done();\n+            });\n+          });\n+\n+        it('sets \"isUpdating{<passed capitalized type>}\" property to false ' +\n+        'after reject', function (done) {\n+          const expectedProp = `isUpdating${can.capitalize(type)}`;\n+\n+          dfd.reject(assessment);\n+          vm.removeRelatedItem(item, type);\n+\n+          dfd.always(() => {\n+            expect(vm.attr(expectedProp)).toBe(false);\n+            done();\n+          });\n+        });\n+\n+        it('removes actions for assessment from response after reject',\n+          function (done) {\n+            dfd.reject(assessment);\n+            vm.removeRelatedItem(item, type);\n+\n+            dfd.always(() => {\n+              expect(assessment.attr('actions')).toBeUndefined();\n+              done();\n+            });\n+          });\n+      });\n+  });\n+\n+  describe('updateRelatedItems() method', () => {\n+    let dfd;\n+\n+    beforeEach(function () {\n+      dfd = can.Deferred();\n+      vm.attr('instance', {});\n+      vm.attr('instance').getRelatedObjects =\n+        jasmine.createSpy('getRelatedObjects').and.returnValue(dfd);\n+    });\n+\n+    it('sets isUpdatingRelatedItems property to true', function () {\n+      const prop = 'isUpdatingRelatedItems';\n+      vm.attr(prop, false);\n+      vm.updateRelatedItems();\n+      expect(vm.attr(prop)).toBe(true);\n+    });\n+\n+    describe('when related objects were received successfully', () => {\n+      let data;\n+\n+      beforeEach(() => {\n+        data = {};\n+        dfd.resolve(data);\n+      });\n+\n+      it('replaces mappedSnapshots list with loaded mapped snapshots',\n+        function () {\n+          data.Snapshot = {data: '1'};\n+          vm.updateRelatedItems();\n+          expect(vm.attr('mappedSnapshots').attr()).toEqual([\n+            data.Snapshot,\n+          ]);\n+        });\n+\n+      it('replaces comments list with loaded comments', function () {\n+        data.Comment = {data: '1'};\n+        vm.updateRelatedItems();\n+        expect(vm.attr('comments').attr()).toEqual([data.Comment]);\n+      });\n+\n+      it('replaces files list with loaded files', function () {\n+        data['Evidence:FILE'] = {data: '1'};\n+        vm.updateRelatedItems();\n+        expect(vm.attr('files').attr()).toEqual([\n+          data['Evidence:FILE'],\n+        ]);\n+      });\n+\n+      it('replaces urls list with loaded urls', function () {\n+        data['Evidence:URL'] = {data: '1'};\n+        vm.updateRelatedItems();\n+        expect(vm.attr('urls').attr()).toEqual([\n+          data['Evidence:URL'],\n+        ]);\n+      });\n+\n+      it('sets isUpdatingRelatedItems to false', function () {\n+        vm.updateRelatedItems();\n+        expect(vm.attr('isUpdatingRelatedItems')).toBe(false);\n+      });\n+\n+      it('dispatches RELATED_ITEMS_LOADED for the instance', function () {\n+        const dispatchSpy = jasmine.createSpy('dispatch');\n+        vm.attr('instance').dispatch = dispatchSpy;\n+        vm.updateRelatedItems();\n+        expect(dispatchSpy).toHaveBeenCalledWith(RELATED_ITEMS_LOADED);\n+      });\n+    });\n+  });\n+\n+  describe('initializeFormFields() method', () => {\n+    let results;\n+\n+    beforeEach(function () {\n+      vm.attr({\n+        formFields: [],\n+        instance: {},\n+      });\n+      results = [1, 2, 3];\n+      spyOn(caUtils, 'getCustomAttributes');\n+      spyOn(caUtils, 'convertValuesToFormFields');\n+    });\n+\n+    it('gets CA with help GGRC.Utils.CustomAttributes.getCustomAttributes',\n+      function () {\n+        vm.initializeFormFields();\n+        expect(caUtils.getCustomAttributes).toHaveBeenCalledWith(\n+          vm.attr('instance'), caUtils.CUSTOM_ATTRIBUTE_TYPE.LOCAL\n+        );\n+      });\n+\n+    it('converts CA values to form fields', function () {\n+      caUtils.getCustomAttributes.and.returnValue(results);\n+      vm.initializeFormFields();\n+      expect(caUtils.convertValuesToFormFields).toHaveBeenCalledWith(results);\n+    });\n+\n+    it('sets form fields to converted CA values', function () {\n+      caUtils.convertValuesToFormFields.and.returnValue(results);\n+      vm.initializeFormFields();\n+      expect(\n+        vm.attr('formFields').serialize()\n+      ).toEqual(results);\n+    });\n+  });\n+\n+  describe('initGlobalAttributes() method', () => {\n+    beforeEach(function () {\n+      vm.attr('instance', {\n+        customAttr: jasmine.createSpy('customAttr'),\n+      });\n+    });\n+\n+    it('sets global custom attributes', function () {\n+      const expectedResult = new can.List([]);\n+      const customAttr = vm.attr('instance').customAttr;\n+      customAttr.and.returnValue(expectedResult);\n+\n+      vm.initGlobalAttributes();\n+\n+      expect(customAttr).toHaveBeenCalledWith({\n+        type: CUSTOM_ATTRIBUTE_TYPE.GLOBAL,\n+      });\n+      expect(vm.attr('globalAttributes')).toBe(expectedResult);\n+    });\n+  });\n+\n+  describe('initializeDeferredSave() method', () => {\n+    beforeEach(function () {\n+      vm.attr('deferredSave', {});\n+    });\n+\n+    it('sets for deferredSave a DeferredTransaction instance', function () {\n+      vm.initializeDeferredSave();\n+      expect(vm.attr('deferredSave')).toEqual(jasmine.any(\n+        DeferredTransactionUtil.default\n+      ));\n+    });\n+\n+    describe('calls a DeferredTransaction constructor for deferredSave namely',\n+      () => {\n+        let args;\n+        let ARGS_ORDER;\n+\n+        beforeAll(function () {\n+          ARGS_ORDER = {\n+            CALLBACK: 0,\n+            TIMEOUT: 1,\n+          };\n+        });\n+\n+        beforeEach(function () {\n+          const dfdT = spyOn(DeferredTransactionUtil, 'default');\n+          vm.initializeDeferredSave();\n+          args = dfdT.calls.argsFor(0);\n+        });\n+\n+        it('sets completeTransaction param as a function', function () {\n+          expect(\n+            args[ARGS_ORDER.CALLBACK]\n+          ).toEqual(jasmine.any(Function));\n+        });\n+\n+        it('sets 1000ms execution delay with help timeout param', function () {\n+          expect(\n+            args[ARGS_ORDER.TIMEOUT]\n+          ).toBe(1000);\n+        });\n+\n+        describe('sets completeTransaction function which', () => {\n+          let completeTransaction;\n+          let resolveFunc;\n+          let rejectFunc;\n+          let dfd;\n+\n+          beforeEach(() => {\n+            dfd = can.Deferred();\n+            completeTransaction = args[ARGS_ORDER.CALLBACK];\n+            vm.attr('instance', {\n+              save: jasmine.createSpy('save').and.returnValue(dfd),\n+            });\n+            resolveFunc = jasmine.createSpy('resolveFunc');\n+            rejectFunc = jasmine.createSpy('rejectFunc');\n+          });\n+\n+          it('saves instance', function () {\n+            completeTransaction();\n+            expect(vm.attr('instance').save).toHaveBeenCalled();\n+          });\n+\n+          it('calls passed resolve function if the saving was resolved',\n+            function (done) {\n+              dfd.resolve();\n+              completeTransaction(resolveFunc, rejectFunc);\n+              dfd.done(() => {\n+                expect(resolveFunc).toHaveBeenCalled();\n+                expect(rejectFunc).not.toHaveBeenCalled();\n+                done();\n+              });\n+            });\n+\n+          it('calls passed reject function if the saving was rejected',\n+            function (done) {\n+              dfd.reject();\n+              completeTransaction(resolveFunc, rejectFunc);\n+              dfd.fail(function () {\n+                expect(rejectFunc).toHaveBeenCalled();\n+                expect(resolveFunc).not.toHaveBeenCalled();\n+                done();\n+              });\n+            });\n+        });\n+      });\n+  });\n+\n+  describe('saveGlobalAttributes() method', () => {\n+    let event;\n+\n+    beforeEach(function () {\n+      event = {\n+        globalAttributes: [],\n+      };\n+      vm.attr('instance', {});\n+    });\n+\n+    it('adds deferred transaction', function () {\n+      const push = jasmine.createSpy('push');\n+      vm.attr('deferredSave', {push});\n+      vm.saveGlobalAttributes(event);\n+      expect(push).toHaveBeenCalledWith(jasmine.any(Function));\n+    });\n+\n+    describe('added deferred transaction', function () {\n+      let action;\n+      let customAttr;\n+\n+      beforeEach(function () {\n+        const push = jasmine.createSpy('push');\n+        customAttr = jasmine.createSpy('customAttr');\n+        vm.attr('instance', {customAttr});\n+        vm.attr('deferredSave', {push});\n+        vm.saveGlobalAttributes(event);\n+        action = push.calls.argsFor(0)[0];\n+      });\n+\n+      it('sets global custom attributes from passed event object', function () {\n+        event.globalAttributes = new can.Map({\n+          '123': 'Value',\n+          '2': 'Value2',\n+        });\n+        action();\n+        expect(customAttr).toHaveBeenCalledWith('123', 'Value');\n+        expect(customAttr).toHaveBeenCalledWith('2', 'Value2');\n+      });\n+    });\n+  });\n+\n+  describe('showRequiredInfoModal() method', () => {\n+    let event;\n+\n+    beforeEach(function () {\n+      const field = new can.Map({\n+        title: 'Perfect Title',\n+        type: 'Perfect Type',\n+        options: [],\n+        value: {},\n+        errorsMap: {\n+          error1: true,\n+          error2: false,\n+          error3: false,\n+        },\n+        saveDfd: {},\n+      });\n+      event = {field};\n+    });\n+\n+    describe('sets modal.content namely', () => {\n+      let field;\n+\n+      beforeEach(function () {\n+        field = event.field;\n+      });\n+\n+      it('sets \"options\" field', function () {\n+        const expectedResult = field.attr('options');\n+        vm.showRequiredInfoModal(event);\n+        expect(vm.attr('modal.content.options')).toBe(expectedResult);\n+      });\n+\n+      it('sets \"contextScope\" field', function () {\n+        const expectedResult = field;\n+        vm.showRequiredInfoModal(event);\n+        expect(vm.attr('modal.content.contextScope')).toBe(expectedResult);\n+      });\n+\n+      it('sets \"fields\" field', function () {\n+        const errors = field.errorsMap;\n+        const expectedResult = can.Map.keys(errors)\n+          .map((error) => errors[error] ? error : null)\n+          .filter((errorCode) => !!errorCode);\n+        vm.showRequiredInfoModal(event);\n+        expect(vm.attr('modal.content.fields').attr()).toEqual(expectedResult);\n+      });\n+\n+      it('sets \"value\" field', function () {\n+        const expectedResult = field.attr('value');\n+        vm.showRequiredInfoModal(event);\n+        expect(vm.attr('modal.content.value')).toBe(expectedResult);\n+      });\n+\n+      it('sets \"title\" field', function () {\n+        const expectedResult = field.attr('title');\n+        vm.showRequiredInfoModal(event);\n+        expect(vm.attr('modal.content.title')).toBe(expectedResult);\n+      });\n+\n+      it('sets \"type\" field', function () {\n+        const expectedResult = field.attr('type');\n+        vm.showRequiredInfoModal(event);\n+        expect(vm.attr('modal.content.type')).toBe(expectedResult);\n+      });\n+\n+      it('sets \"saveDfd\" field', function () {\n+        const expectedResult = can.Deferred();\n+        event.saveDfd = expectedResult;\n+        vm.showRequiredInfoModal(event);\n+        expect(vm.attr('modal.content.saveDfd')).toBe(expectedResult);\n+      });\n+    });\n+\n+    it('sets modal.modalTitle though getLCAPopupTitle', () => {\n+      const title = 'something';\n+      const expectedResult = `Required ${title}`;\n+      spyOn(caUtils, 'getLCAPopupTitle').and.returnValue(title);\n+      vm.showRequiredInfoModal(event);\n+      expect(vm.attr('modal.modalTitle')).toBe(expectedResult);\n+      expect(caUtils.getLCAPopupTitle).toHaveBeenCalledWith(\n+        event.field.attr('errorsMap'));\n+    });\n+\n+    describe('sets modal.state namely', () => {\n+      it('sets \"open\" field to true', function () {\n+        vm.showRequiredInfoModal(event);\n+        expect(vm.attr('modal.state.open')).toBe(true);\n+      });\n+    });\n+  });\n+\n+  describe('setVerifierRoleId() method', () => {\n+    beforeEach(function () {\n+      spyOn(aclUtils, 'getRole');\n+    });\n+\n+    it('sets verifier role to null if there is no role for ' +\n+    'Assessment.Verifiers', function () {\n+      aclUtils.getRole.and.returnValue(undefined);\n+      vm.setVerifierRoleId();\n+      expect(vm.attr('_verifierRoleId')).toBeNull();\n+    });\n+\n+    it('sets verifier role to verifier id if there is role for ' +\n+    'Assessment.Verifiers', function () {\n+      const verifierRole = {id: 1};\n+      aclUtils.getRole.and.returnValue(verifierRole);\n+      vm.setVerifierRoleId();\n+      expect(vm.attr('_verifierRoleId')).toBe(verifierRole.id);\n+    });\n+  });\n+\n+  describe('extraClass() helper method', () => {\n+    let helper;\n+\n+    beforeEach(function () {\n+      helper = Component.prototype.helpers.extraClass.bind(vm);\n+    });\n+\n+    it('returns \"inline-reverse\" string if passed type function returns ' +\n+    'checkbox string', function () {\n+      const result = helper(_.constant('checkbox'));\n+      expect(result).toBe('inline-reverse');\n+    });\n+\n+    it('returns empty string if passed type function returns unknown string',\n+      function () {\n+        const result = helper(_.constant('unknownType'));\n+        expect(result).toBe('');\n+      });\n+  });\n+\n+  describe('component scope', () => {\n+    let fakeComponent;\n+\n+    beforeEach(function () {\n+      fakeComponent = {viewModel: vm};\n+    });\n+\n+    describe('init() method', () => {\n+      let init;\n+\n+      beforeEach(function () {\n+        init = Component.prototype.init.bind(fakeComponent);\n+        spyOn(vm, 'initializeFormFields');\n+        spyOn(vm, 'initGlobalAttributes');\n+        spyOn(vm, 'updateRelatedItems');\n+        spyOn(vm, 'initializeDeferredSave');\n+        spyOn(vm, 'setVerifierRoleId');\n+      });\n+\n+      it('calls vm.initializeFormFields method', function () {\n+        init();\n+        expect(vm.initializeFormFields).toHaveBeenCalled();\n+      });\n+\n+      it('calls vm.initGlobalAttributes method', function () {\n+        init();\n+        expect(vm.initGlobalAttributes).toHaveBeenCalled();\n+      });\n+\n+      it('calls vm.updateRelatedItems method', function () {\n+        init();\n+        expect(vm.updateRelatedItems).toHaveBeenCalled();\n+      });\n+\n+      it('calls initializeDeferredSave method', function () {\n+        init();\n+        expect(vm.initializeDeferredSave).toHaveBeenCalled();\n+      });\n+\n+      it('calls setVerifierRoleId method', function () {\n+        init();\n+        expect(vm.setVerifierRoleId).toHaveBeenCalled();\n+      });\n+    });\n+\n+    describe('\"{vm.instance} ${REFRESH_MAPPING.type}\"() event handler',\n+      () => {\n+        let event;\n+        let snapshots;\n+        let evObject;\n+\n+        beforeEach(function () {\n+          const eventName = `{viewModel.instance} ${REFRESH_MAPPING.type}`;\n+          event = Component.prototype.events[eventName].bind(fakeComponent);\n+          snapshots = {\n+            data: 'Important data',\n+          };\n+          spyOn(vm, 'loadSnapshots').and.returnValue(snapshots);\n+          vm.attr('instance', {});\n+          evObject = {};\n+        });\n+\n+        it('loads snapshots with help vm.loadSnapshots method ',","path":"src/ggrc-client/js/components/assessment/info-pane/tests/info-pane_spec.js","position":null,"original_position":1607,"commit_id":"202142b40f1fd40be475080d90fa69f066e5b336","original_commit_id":"08f9f30402eb0a3b3c086f513ff444f3f570ac2e","user":{"login":"iSokrat","id":13063442,"avatar_url":"https://avatars2.githubusercontent.com/u/13063442?v=4","gravatar_id":"","url":"https://api.github.com/users/iSokrat","html_url":"https://github.com/iSokrat","followers_url":"https://api.github.com/users/iSokrat/followers","following_url":"https://api.github.com/users/iSokrat/following{/other_user}","gists_url":"https://api.github.com/users/iSokrat/gists{/gist_id}","starred_url":"https://api.github.com/users/iSokrat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iSokrat/subscriptions","organizations_url":"https://api.github.com/users/iSokrat/orgs","repos_url":"https://api.github.com/users/iSokrat/repos","events_url":"https://api.github.com/users/iSokrat/events{/privacy}","received_events_url":"https://api.github.com/users/iSokrat/received_events","type":"User","site_admin":false},"body":"Yep, we can merge them.","created_at":"2018-05-29T13:36:38Z","updated_at":"2018-05-29T13:53:34Z","html_url":"https://github.com/google/ggrc-core/pull/7845#discussion_r191425541","pull_request_url":"https://api.github.com/repos/google/ggrc-core/pulls/7845","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/google/ggrc-core/pulls/comments/191425541"},"html":{"href":"https://github.com/google/ggrc-core/pull/7845#discussion_r191425541"},"pull_request":{"href":"https://api.github.com/repos/google/ggrc-core/pulls/7845"}},"in_reply_to_id":191210913},"pull_request":{"url":"https://api.github.com/repos/google/ggrc-core/pulls/7845","id":190499417,"html_url":"https://github.com/google/ggrc-core/pull/7845","diff_url":"https://github.com/google/ggrc-core/pull/7845.diff","patch_url":"https://github.com/google/ggrc-core/pull/7845.patch","issue_url":"https://api.github.com/repos/google/ggrc-core/issues/7845","number":7845,"state":"open","locked":false,"title":"QUICK-FIX Cover assessment-info-pane component with unit tests","user":{"login":"iSokrat","id":13063442,"avatar_url":"https://avatars2.githubusercontent.com/u/13063442?v=4","gravatar_id":"","url":"https://api.github.com/users/iSokrat","html_url":"https://github.com/iSokrat","followers_url":"https://api.github.com/users/iSokrat/followers","following_url":"https://api.github.com/users/iSokrat/following{/other_user}","gists_url":"https://api.github.com/users/iSokrat/gists{/gist_id}","starred_url":"https://api.github.com/users/iSokrat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iSokrat/subscriptions","organizations_url":"https://api.github.com/users/iSokrat/orgs","repos_url":"https://api.github.com/users/iSokrat/repos","events_url":"https://api.github.com/users/iSokrat/events{/privacy}","received_events_url":"https://api.github.com/users/iSokrat/received_events","type":"User","site_admin":false},"body":"<!-- If your PR depends on other tickets or PRs, you can list them here\r\n# Dependencies\r\n\r\nThis PR is `on hold` until the dependencies are merged:\r\n\r\n- [ ] GGRC-1234\r\n- [ ] #1234\r\n-->\r\n\r\n# Issue description\r\n\r\nUnit tests were written  for `assessment-info-pane` component.\r\n\r\n# Steps to test the changes\r\n\r\n*Include steps to test or reproduce (in case of a bugfix) the changes in the pull request. This section should help the reviewer verify your changes.*\r\n\r\n# Solution description\r\n\r\n*Briefly explain the solution or add a link to the technical design document (this will help the reviewer confirm the code does what you intend). Feel free to also mention alternative approaches that didn't work out.*\r\n\r\n# Sanity checklist\r\n\r\n- [ ] I have clicked through the app to make sure my changes work and not break the app.\r\n- [x] I have applied the correct milestone and labels.\r\n- [ ] My changes fix the issue described in the description (and do nothing else). 🤞\r\n- [x] My changes are covered by tests.\r\n- [x] My changes follow our [performance guidelines](https://github.com/google/ggrc-core/blob/dev/docs/source/contributing/performance.rst).\r\n- [x] My changes follow our [js](https://github.com/google/ggrc-core/blob/dev/docs/source/contributing/javascript.rst) and/or [python](https://github.com/google/ggrc-core/blob/dev/docs/source/contributing/python.rst) guidelines.\r\n- [x] My commits follow our [commit guidelines](https://github.com/google/ggrc-core/blob/dev/docs/source/contributing/git/how_to_write_a_commit_message.rst).\r\n\r\n<!-- If your PR includes a migration include the additional checklist items\r\n# Migration checklist\r\n- [ ] Migration passes all checks from our [PR review guidelines](https://github.com/google/ggrc-core/blob/dev/docs/source/contributing/git/reviewing_pull_requests.rst#reviewing-a-pr-containing-database-migration-scripts)\r\n-->\r\n\r\n# PR Review checklist\r\n\r\n- [ ] The changes fix the issue and don't cause any apparent regressions.\r\n- [ ] Labels and milestone are correctly set.\r\n- [ ] The solution description matches the changes in the code.\r\n- [ ] There is no apparent way to improve the performance & design of the new code.\r\n- [ ] The pull request is opened against the correct base branch.\r\n- [ ] Upon merging, the Jira ticket's fixversion is correctly set and the ticket is moved to \"QA - In Progress\".\r\n\r\n<!-- If your code is not finished yet can include a TODO check list\r\n# TODO\r\n\r\n- [ ] First item on the TODO\r\n-->\r\n","created_at":"2018-05-25T07:09:27Z","updated_at":"2018-05-29T13:53:34Z","closed_at":null,"merged_at":null,"merge_commit_sha":"10ceaa4c45aff4a7827df021db76e75fb4acff4d","assignee":{"login":"Klim711","id":10946494,"avatar_url":"https://avatars1.githubusercontent.com/u/10946494?v=4","gravatar_id":"","url":"https://api.github.com/users/Klim711","html_url":"https://github.com/Klim711","followers_url":"https://api.github.com/users/Klim711/followers","following_url":"https://api.github.com/users/Klim711/following{/other_user}","gists_url":"https://api.github.com/users/Klim711/gists{/gist_id}","starred_url":"https://api.github.com/users/Klim711/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Klim711/subscriptions","organizations_url":"https://api.github.com/users/Klim711/orgs","repos_url":"https://api.github.com/users/Klim711/repos","events_url":"https://api.github.com/users/Klim711/events{/privacy}","received_events_url":"https://api.github.com/users/Klim711/received_events","type":"User","site_admin":false},"assignees":[{"login":"Klim711","id":10946494,"avatar_url":"https://avatars1.githubusercontent.com/u/10946494?v=4","gravatar_id":"","url":"https://api.github.com/users/Klim711","html_url":"https://github.com/Klim711","followers_url":"https://api.github.com/users/Klim711/followers","following_url":"https://api.github.com/users/Klim711/following{/other_user}","gists_url":"https://api.github.com/users/Klim711/gists{/gist_id}","starred_url":"https://api.github.com/users/Klim711/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Klim711/subscriptions","organizations_url":"https://api.github.com/users/Klim711/orgs","repos_url":"https://api.github.com/users/Klim711/repos","events_url":"https://api.github.com/users/Klim711/events{/privacy}","received_events_url":"https://api.github.com/users/Klim711/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":653911749,"url":"https://api.github.com/repos/google/ggrc-core/labels/cla:%20yes","name":"cla: yes","color":"ededed","default":false},{"id":86898803,"url":"https://api.github.com/repos/google/ggrc-core/labels/needs%20work","name":"needs work","color":"f9d0c4","default":false}],"milestone":{"url":"https://api.github.com/repos/google/ggrc-core/milestones/91","html_url":"https://github.com/google/ggrc-core/milestone/91","labels_url":"https://api.github.com/repos/google/ggrc-core/milestones/91/labels","id":3360601,"number":91,"title":"1.12.0-Strawberry","description":"","creator":{"login":"zidarsk8","id":566311,"avatar_url":"https://avatars2.githubusercontent.com/u/566311?v=4","gravatar_id":"","url":"https://api.github.com/users/zidarsk8","html_url":"https://github.com/zidarsk8","followers_url":"https://api.github.com/users/zidarsk8/followers","following_url":"https://api.github.com/users/zidarsk8/following{/other_user}","gists_url":"https://api.github.com/users/zidarsk8/gists{/gist_id}","starred_url":"https://api.github.com/users/zidarsk8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zidarsk8/subscriptions","organizations_url":"https://api.github.com/users/zidarsk8/orgs","repos_url":"https://api.github.com/users/zidarsk8/repos","events_url":"https://api.github.com/users/zidarsk8/events{/privacy}","received_events_url":"https://api.github.com/users/zidarsk8/received_events","type":"User","site_admin":false},"open_issues":37,"closed_issues":39,"state":"open","created_at":"2018-05-21T07:43:45Z","updated_at":"2018-05-29T13:43:21Z","due_on":"2018-05-28T07:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/google/ggrc-core/pulls/7845/commits","review_comments_url":"https://api.github.com/repos/google/ggrc-core/pulls/7845/comments","review_comment_url":"https://api.github.com/repos/google/ggrc-core/pulls/comments{/number}","comments_url":"https://api.github.com/repos/google/ggrc-core/issues/7845/comments","statuses_url":"https://api.github.com/repos/google/ggrc-core/statuses/202142b40f1fd40be475080d90fa69f066e5b336","head":{"label":"iSokrat:asmt-test","ref":"asmt-test","sha":"202142b40f1fd40be475080d90fa69f066e5b336","user":{"login":"iSokrat","id":13063442,"avatar_url":"https://avatars2.githubusercontent.com/u/13063442?v=4","gravatar_id":"","url":"https://api.github.com/users/iSokrat","html_url":"https://github.com/iSokrat","followers_url":"https://api.github.com/users/iSokrat/followers","following_url":"https://api.github.com/users/iSokrat/following{/other_user}","gists_url":"https://api.github.com/users/iSokrat/gists{/gist_id}","starred_url":"https://api.github.com/users/iSokrat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iSokrat/subscriptions","organizations_url":"https://api.github.com/users/iSokrat/orgs","repos_url":"https://api.github.com/users/iSokrat/repos","events_url":"https://api.github.com/users/iSokrat/events{/privacy}","received_events_url":"https://api.github.com/users/iSokrat/received_events","type":"User","site_admin":false},"repo":{"id":99347941,"name":"ggrc-core","full_name":"iSokrat/ggrc-core","owner":{"login":"iSokrat","id":13063442,"avatar_url":"https://avatars2.githubusercontent.com/u/13063442?v=4","gravatar_id":"","url":"https://api.github.com/users/iSokrat","html_url":"https://github.com/iSokrat","followers_url":"https://api.github.com/users/iSokrat/followers","following_url":"https://api.github.com/users/iSokrat/following{/other_user}","gists_url":"https://api.github.com/users/iSokrat/gists{/gist_id}","starred_url":"https://api.github.com/users/iSokrat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iSokrat/subscriptions","organizations_url":"https://api.github.com/users/iSokrat/orgs","repos_url":"https://api.github.com/users/iSokrat/repos","events_url":"https://api.github.com/users/iSokrat/events{/privacy}","received_events_url":"https://api.github.com/users/iSokrat/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/iSokrat/ggrc-core","description":"GGRC Core","fork":true,"url":"https://api.github.com/repos/iSokrat/ggrc-core","forks_url":"https://api.github.com/repos/iSokrat/ggrc-core/forks","keys_url":"https://api.github.com/repos/iSokrat/ggrc-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/iSokrat/ggrc-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/iSokrat/ggrc-core/teams","hooks_url":"https://api.github.com/repos/iSokrat/ggrc-core/hooks","issue_events_url":"https://api.github.com/repos/iSokrat/ggrc-core/issues/events{/number}","events_url":"https://api.github.com/repos/iSokrat/ggrc-core/events","assignees_url":"https://api.github.com/repos/iSokrat/ggrc-core/assignees{/user}","branches_url":"https://api.github.com/repos/iSokrat/ggrc-core/branches{/branch}","tags_url":"https://api.github.com/repos/iSokrat/ggrc-core/tags","blobs_url":"https://api.github.com/repos/iSokrat/ggrc-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/iSokrat/ggrc-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/iSokrat/ggrc-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/iSokrat/ggrc-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/iSokrat/ggrc-core/statuses/{sha}","languages_url":"https://api.github.com/repos/iSokrat/ggrc-core/languages","stargazers_url":"https://api.github.com/repos/iSokrat/ggrc-core/stargazers","contributors_url":"https://api.github.com/repos/iSokrat/ggrc-core/contributors","subscribers_url":"https://api.github.com/repos/iSokrat/ggrc-core/subscribers","subscription_url":"https://api.github.com/repos/iSokrat/ggrc-core/subscription","commits_url":"https://api.github.com/repos/iSokrat/ggrc-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/iSokrat/ggrc-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/iSokrat/ggrc-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/iSokrat/ggrc-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/iSokrat/ggrc-core/contents/{+path}","compare_url":"https://api.github.com/repos/iSokrat/ggrc-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/iSokrat/ggrc-core/merges","archive_url":"https://api.github.com/repos/iSokrat/ggrc-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/iSokrat/ggrc-core/downloads","issues_url":"https://api.github.com/repos/iSokrat/ggrc-core/issues{/number}","pulls_url":"https://api.github.com/repos/iSokrat/ggrc-core/pulls{/number}","milestones_url":"https://api.github.com/repos/iSokrat/ggrc-core/milestones{/number}","notifications_url":"https://api.github.com/repos/iSokrat/ggrc-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/iSokrat/ggrc-core/labels{/name}","releases_url":"https://api.github.com/repos/iSokrat/ggrc-core/releases{/id}","deployments_url":"https://api.github.com/repos/iSokrat/ggrc-core/deployments","created_at":"2017-08-04T13:56:38Z","updated_at":"2017-08-04T13:56:46Z","pushed_at":"2018-05-29T13:52:54Z","git_url":"git://github.com/iSokrat/ggrc-core.git","ssh_url":"git@github.com:iSokrat/ggrc-core.git","clone_url":"https://github.com/iSokrat/ggrc-core.git","svn_url":"https://github.com/iSokrat/ggrc-core","homepage":null,"size":75204,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":0,"open_issues":0,"watchers":0,"default_branch":"dev"}},"base":{"label":"google:dev","ref":"dev","sha":"836235fb109d1949dc9f24a504b91c937d496000","user":{"login":"google","id":1342004,"avatar_url":"https://avatars1.githubusercontent.com/u/1342004?v=4","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"repo":{"id":9304637,"name":"ggrc-core","full_name":"google/ggrc-core","owner":{"login":"google","id":1342004,"avatar_url":"https://avatars1.githubusercontent.com/u/1342004?v=4","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/google/ggrc-core","description":"GGRC Core","fork":false,"url":"https://api.github.com/repos/google/ggrc-core","forks_url":"https://api.github.com/repos/google/ggrc-core/forks","keys_url":"https://api.github.com/repos/google/ggrc-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/google/ggrc-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/google/ggrc-core/teams","hooks_url":"https://api.github.com/repos/google/ggrc-core/hooks","issue_events_url":"https://api.github.com/repos/google/ggrc-core/issues/events{/number}","events_url":"https://api.github.com/repos/google/ggrc-core/events","assignees_url":"https://api.github.com/repos/google/ggrc-core/assignees{/user}","branches_url":"https://api.github.com/repos/google/ggrc-core/branches{/branch}","tags_url":"https://api.github.com/repos/google/ggrc-core/tags","blobs_url":"https://api.github.com/repos/google/ggrc-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/google/ggrc-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/google/ggrc-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/google/ggrc-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/google/ggrc-core/statuses/{sha}","languages_url":"https://api.github.com/repos/google/ggrc-core/languages","stargazers_url":"https://api.github.com/repos/google/ggrc-core/stargazers","contributors_url":"https://api.github.com/repos/google/ggrc-core/contributors","subscribers_url":"https://api.github.com/repos/google/ggrc-core/subscribers","subscription_url":"https://api.github.com/repos/google/ggrc-core/subscription","commits_url":"https://api.github.com/repos/google/ggrc-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/google/ggrc-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/google/ggrc-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/google/ggrc-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/google/ggrc-core/contents/{+path}","compare_url":"https://api.github.com/repos/google/ggrc-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/google/ggrc-core/merges","archive_url":"https://api.github.com/repos/google/ggrc-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/google/ggrc-core/downloads","issues_url":"https://api.github.com/repos/google/ggrc-core/issues{/number}","pulls_url":"https://api.github.com/repos/google/ggrc-core/pulls{/number}","milestones_url":"https://api.github.com/repos/google/ggrc-core/milestones{/number}","notifications_url":"https://api.github.com/repos/google/ggrc-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/google/ggrc-core/labels{/name}","releases_url":"https://api.github.com/repos/google/ggrc-core/releases{/id}","deployments_url":"https://api.github.com/repos/google/ggrc-core/deployments","created_at":"2013-04-08T19:16:28Z","updated_at":"2018-05-29T13:43:31Z","pushed_at":"2018-05-29T13:52:57Z","git_url":"git://github.com/google/ggrc-core.git","ssh_url":"git@github.com:google/ggrc-core.git","clone_url":"https://github.com/google/ggrc-core.git","svn_url":"https://github.com/google/ggrc-core","homepage":null,"size":77449,"stargazers_count":285,"watchers_count":285,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":215,"mirror_url":null,"archived":false,"open_issues_count":44,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":215,"open_issues":44,"watchers":285,"default_branch":"dev"}},"_links":{"self":{"href":"https://api.github.com/repos/google/ggrc-core/pulls/7845"},"html":{"href":"https://github.com/google/ggrc-core/pull/7845"},"issue":{"href":"https://api.github.com/repos/google/ggrc-core/issues/7845"},"comments":{"href":"https://api.github.com/repos/google/ggrc-core/issues/7845/comments"},"review_comments":{"href":"https://api.github.com/repos/google/ggrc-core/pulls/7845/comments"},"review_comment":{"href":"https://api.github.com/repos/google/ggrc-core/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/google/ggrc-core/pulls/7845/commits"},"statuses":{"href":"https://api.github.com/repos/google/ggrc-core/statuses/202142b40f1fd40be475080d90fa69f066e5b336"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"iSokrat"}}