Browse Source

HUE-9009 [frontend] Add support for testing ko bindings

Johan Ahlen 6 years ago
parent
commit
a64fc69af6

+ 38 - 0
desktop/core/src/desktop/js/ko/bindings/test/ko.toogle.spec.js

@@ -0,0 +1,38 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import ko from 'knockout';
+import { koSetup } from 'spec/jasmineSetup';
+import '../ko.toggle';
+
+describe('ko.toggle.js', () => {
+  const setup = koSetup();
+
+  it('should toggle observable', async () => {
+    const viewModel = { testObservable: ko.observable(false) };
+    const wrapper = await setup.renderKo(
+      '<div class="toggle-test" data-bind="toggle: testObservable"></div>',
+      viewModel
+    );
+
+    expect(viewModel.testObservable()).toBeFalsy();
+
+    wrapper.querySelector('.toggle-test').click();
+    await setup.waitForKoUpdate();
+
+    expect(viewModel.testObservable()).toBeTruthy();
+  });
+});

+ 16 - 0
desktop/core/src/desktop/js/ko/components/spec/ko.sessionPanel.spec.js

@@ -1,3 +1,19 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 import huePubSub from 'utils/huePubSub';
 import sessionManager from 'apps/notebook2/execution/sessionManager';
 import { koSetup } from 'spec/jasmineSetup';

+ 9 - 0
desktop/core/src/desktop/js/spec/jasmineSetup.js

@@ -76,6 +76,15 @@ export const koSetup = () => {
         }, 0);
       }),
 
+    renderKo: async (html, viewModel) =>
+      new Promise(resolve => {
+        wrapper.innerHTML = html;
+        ko.applyBindings(viewModel, wrapper);
+        window.setTimeout(() => {
+          resolve(wrapper);
+        }, 0);
+      }),
+
     waitForKoUpdate: async () => {
       return new Promise(resolve => {
         window.setTimeout(resolve, 0);

+ 59 - 0
docs/docs-site/content/developer/development/_index.md

@@ -672,6 +672,65 @@ Optionally to use Karma and headless chrome for the tests you can run
 
 See ```desktop/core/src/desktop/js/spec/karma.config.js``` for various options
 
+#### Testing KO components and bindings
+
+jasmineSetup provides utilities to test knockout components and bindings using jsdom.
+
+An example of component test:
+
+```
+import { koSetup } from 'spec/jasmineSetup';
+
+describe('ko.someComponent.js', () => {
+  const setup = koSetup(); // Adds the necessary setup and teardown
+
+  it('should render component', async () => {
+    const someParams = {}
+
+    const wrapper = await setup.renderComponent('someComponent', someParams);
+
+    expect(wrapper.querySelector('[data-test="'some-test-id'"]')).toBeTruthy();
+  });
+
+  it('should change after observable update', async () => {
+    const someParams = { visible: ko.observable(false) };
+    const wrapper = await setup.renderComponent('someComponent', someParams);
+    expect(wrapper.querySelector('[data-test="some-test-id"]').style['display']).toEqual('none');
+
+    someParams.visible(true); // Or trigger some event on an elmement etc.
+    await setup.waitForKoUpdate(); // Waits for re-render
+
+    expect(wrapper.querySelector('[data-test="some-test-id"]').style['display']).toEqual('inline-block');
+  });
+});
+```
+
+An example of a binding test:
+
+```
+import ko from 'knockout';
+import { koSetup } from 'spec/jasmineSetup';
+import '../ko.myBinding';
+
+describe('ko.myBinding.js', () => {
+  const setup = koSetup();
+
+  it('should toggle observable', async () => {
+    const viewModel = { testObservable: ko.observable(false) };
+    const wrapper = await setup.renderKo(
+      '<div class="click-test" data-bind="myBinding: testObservable"></div>',
+      viewModel
+    );
+
+    expect(viewModel.testObservable()).toBeFalsy();
+
+    wrapper.querySelector('.click-test').click();
+    await setup.waitForKoUpdate();
+
+    expect(viewModel.testObservable()).toBeTruthy();
+  });
+});
+```
 
 #### Special environment variables
 

+ 36 - 9
docs/sdk/sdk.md

@@ -1237,7 +1237,7 @@ Add them in a "spec" subfolder relative to the file under test and the filename
 
     someFile.js              <- File under test
     ├── spec/
-    │   ├── someFileSpec.js  <- File containing tests    
+    │   ├── someFileSpec.js  <- File containing tests
 
 Run all the tests once with:
 
@@ -1249,9 +1249,11 @@ Optionally to use Karma and headless chrome for the tests you can run
 
 See ```desktop/core/src/desktop/js/spec/karma.config.js``` for various options
 
-#### Testing KO components
+#### Testing KO components and bindings
 
-jasmineSetup provides utilities to test knockout components using jsdom. A simple example:
+jasmineSetup provides utilities to test knockout components and bindings using jsdom.
+
+An example of component test:
 
 ```
 import { koSetup } from 'spec/jasmineSetup';
@@ -1261,26 +1263,51 @@ describe('ko.someComponent.js', () => {
 
   it('should render component', async () => {
     const someParams = {}
-    
+
     const wrapper = await setup.renderComponent('someComponent', someParams);
-    
+
     expect(wrapper.querySelector('[data-test="'some-test-id'"]')).toBeTruthy();
   });
 
   it('should change after observable update', async () => {
     const someParams = { visible: ko.observable(false) };
     const wrapper = await setup.renderComponent('someComponent', someParams);
-	expect(wrapper.querySelector('[data-test="some-test-id"]').style['display']).toEqual('none');
-    
-    someParams.visible(true);
+    expect(wrapper.querySelector('[data-test="some-test-id"]').style['display']).toEqual('none');
+
+    someParams.visible(true); // Or trigger some event on an elmement etc.
     await setup.waitForKoUpdate(); // Waits for re-render
 
     expect(wrapper.querySelector('[data-test="some-test-id"]').style['display']).toEqual('inline-block');
   });
 });
+```
+
+An example of a binding test:
 
+```
+import ko from 'knockout';
+import { koSetup } from 'spec/jasmineSetup';
+import '../ko.myBinding';
 
-``` 
+describe('ko.myBinding.js', () => {
+  const setup = koSetup();
+
+  it('should toggle observable', async () => {
+    const viewModel = { testObservable: ko.observable(false) };
+    const wrapper = await setup.renderKo(
+      '<div class="click-test" data-bind="myBinding: testObservable"></div>',
+      viewModel
+    );
+
+    expect(viewModel.testObservable()).toBeFalsy();
+
+    wrapper.querySelector('.click-test').click();
+    await setup.waitForKoUpdate();
+
+    expect(viewModel.testObservable()).toBeTruthy();
+  });
+});
+```
 
 
 ### Special environment variables