You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ra...@apache.org on 2019/10/17 12:24:32 UTC

[cordova-cli] branch master updated: Add unit tests for the telemetry module (#471)

This is an automated email from the ASF dual-hosted git repository.

raphinesse pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cordova-cli.git


The following commit(s) were added to refs/heads/master by this push:
     new e6272d8  Add unit tests for the telemetry module (#471)
e6272d8 is described below

commit e6272d8e31f840bc98627ed92a945ed3e78dffbf
Author: Raphael von der GrĂ¼n <ra...@gmail.com>
AuthorDate: Thu Oct 17 14:24:23 2019 +0200

    Add unit tests for the telemetry module (#471)
    
    * Add unit tests for telemetry module
    
    * Remove old tests superseded by telemetry.spec
      - cli.spec#028 superseded by telemetry.spec.T017-T019
      - part of cli.spec#029 superseded by telemetry.spec.T020
      - cli.spec#031-032 superseded by telemetry.spec.T022-T023
---
 package.json           |   1 +
 spec/cli.spec.js       |  46 +-------
 spec/telemetry.spec.js | 290 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 292 insertions(+), 45 deletions(-)

diff --git a/package.json b/package.json
index 0ec7aec..e12793b 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
     "eslint-plugin-promise": "^4.0.1",
     "eslint-plugin-standard": "^4.0.0",
     "jasmine": "^3.3.1",
+    "mock-stdin": "^0.3.1",
     "nyc": "^14.1.1",
     "rewire": "^4.0.1"
   },
diff --git a/spec/cli.spec.js b/spec/cli.spec.js
index 59e8a91..ba47f3e 100644
--- a/spec/cli.spec.js
+++ b/spec/cli.spec.js
@@ -292,37 +292,10 @@ describe('cordova cli', () => {
             });
         });
 
-        it('Test#028 : opts-out if prompt times out AND it tracks opt-out', () => {
-            // Remove any optOut settings that might have been saved
-            // ... and force prompt to be shown
-            telemetry.clear();
-
-            // We override telemetry timeout here so we don't need to wait
-            // 30 seconds. 0s is impossible with the current implementation.
-            telemetry.timeoutInSecs = 0.01;
-
-            // Don't display the prompt
-            spyOn(process.stdout, 'write');
-
-            telemetry.isOptedIn.and.callThrough();
-            telemetry.showPrompt.and.callThrough();
-            telemetry.hasUserOptedInOrOut.and.returnValue(false);
-
-            return cli(['node', 'cordova', '--version']).then(() => {
-                if (process.env.CI) {
-                    expect(telemetry.isOptedIn()).toBeTruthy();
-                } else {
-                    expect(telemetry.isOptedIn()).toBeFalsy();
-                }
-                expect(telemetry.track).toHaveBeenCalledWith('telemetry', 'off', 'via-cli-prompt-choice', 'successful');
-            });
-        });
-
-        it("Test#029 : is NOT collected in CI environments and doesn't prompt", () => {
+        it('Test#029 : is NOT collected in CI environments', () => {
             telemetry.isCI.and.returnValue(true);
 
             return cli(['node', 'cordova', '--version']).then(() => {
-                expect(telemetry.showPrompt).not.toHaveBeenCalled();
                 expect(telemetry.track).not.toHaveBeenCalled();
             });
         });
@@ -336,23 +309,6 @@ describe('cordova cli', () => {
             });
         });
 
-        it('Test#031 : is NOT collected if user opted out', () => {
-            telemetry.isOptedIn.and.returnValue(false);
-            telemetry.hasUserOptedInOrOut.and.returnValue(true);
-
-            return cli(['node', 'cordova', '--version']).then(() => {
-                expect(telemetry.showPrompt).not.toHaveBeenCalled();
-                expect(telemetry.track).not.toHaveBeenCalled();
-            });
-        });
-
-        it('Test#032 : is collected if user opted in', () => {
-            return cli(['node', 'cordova', '--version']).then(() => {
-                expect(telemetry.showPrompt).not.toHaveBeenCalled();
-                expect(telemetry.track).toHaveBeenCalled();
-            });
-        });
-
         it("Test#033 : track opt-out that happened via 'cordova telemetry off' even if user is NOT opted-in ", () => {
             telemetry.isOptedIn.and.returnValue(false);
 
diff --git a/spec/telemetry.spec.js b/spec/telemetry.spec.js
new file mode 100644
index 0000000..e3349a9
--- /dev/null
+++ b/spec/telemetry.spec.js
@@ -0,0 +1,290 @@
+/*!
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF 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.
+*/
+
+const rewire = require('rewire');
+const Insight = require('insight');
+const mockStdin = require('mock-stdin');
+
+function restoreAfterEach (obj, prop) {
+    const originalValue = obj[prop];
+    const restoreProp = Object.prototype.hasOwnProperty.call(obj, prop)
+        ? () => { obj[prop] = originalValue; }
+        : () => { delete obj[prop]; };
+
+    afterEach(restoreProp);
+}
+
+describe('telemetry', () => {
+    let telemetry, insight;
+
+    beforeEach(() => {
+        telemetry = rewire('../src/telemetry');
+        insight = telemetry.__get__('insight');
+
+        // Prevent any settings from being persisted during testing
+        insight.config = {
+            get: jasmine.createSpy('insight.config.get'),
+            set: jasmine.createSpy('insight.config.set')
+        };
+
+        // Prevent tracking anything during testing
+        spyOn(Insight.prototype, '_save');
+
+        // Prevent prompts during testing
+        spyOn(Insight.prototype, 'askPermission');
+    });
+
+    describe('hasUserOptedInOrOut', () => {
+        it('is false if insight.optOut is unset [T001]', () => {
+            expect(telemetry.hasUserOptedInOrOut()).toBe(false);
+            expect(insight.config.get).toHaveBeenCalledWith('optOut');
+        });
+
+        it('is true if insight.optOut is set [T002]', () => {
+            insight.config.get.and.returnValues(
+                false, true, 0, 1, '', 'xxx', null
+            );
+            for (let i = 0; i < 7; i++) {
+                expect(telemetry.hasUserOptedInOrOut()).toBe(true);
+            }
+            expect(insight.config.get).toHaveBeenCalledTimes(7);
+        });
+    });
+
+    describe('isOptedIn', () => {
+        it('is the inverse of insight.optOut [T003]', () => {
+            insight.config.get.and.returnValues(false, true);
+
+            expect(telemetry.isOptedIn()).toBe(true);
+            expect(telemetry.isOptedIn()).toBe(false);
+            expect(insight.config.get).toHaveBeenCalledTimes(2);
+        });
+
+        it('is true if user did not yet decide [T004]', () => {
+            expect(telemetry.isOptedIn()).toBe(true);
+            expect(insight.config.get).toHaveBeenCalledWith('optOut');
+        });
+    });
+
+    describe('clear', () => {
+        it('clears telemetry setting [T005]', () => {
+            telemetry.clear();
+            expect(insight.config.set)
+                .toHaveBeenCalledWith('optOut', undefined);
+        });
+    });
+
+    describe('turnOn', () => {
+        it('enables the telemetry setting [T006]', () => {
+            telemetry.turnOn();
+            expect(insight.config.set)
+                .toHaveBeenCalledWith('optOut', false);
+        });
+    });
+
+    describe('turnOff', () => {
+        it('disables the telemetry setting [T007]', () => {
+            telemetry.turnOff();
+            expect(insight.config.set)
+                .toHaveBeenCalledWith('optOut', true);
+        });
+    });
+
+    describe('track', () => {
+        beforeEach(() => {
+            spyOn(Insight.prototype, 'track');
+        });
+
+        it('calls insight.track [T008]', () => {
+            telemetry.track();
+            expect(insight.track).toHaveBeenCalled();
+        });
+
+        it('passes its arguments to insight.track [T009]', () => {
+            const args = ['foo', 'bar', 42];
+            telemetry.track(...args);
+            expect(insight.track).toHaveBeenCalledWith(...args);
+        });
+
+        // FIXME filtering is currently broken
+        xit('filters falsy and empty arguments [T010]', () => {
+            const args = [null, [23], [], 42, ''];
+            telemetry.track(...args);
+            expect(insight.track).toHaveBeenCalledWith([23], 42);
+        });
+    });
+
+    describe('showPrompt', () => {
+        let response;
+
+        beforeEach(() => {
+            spyOn(console, 'log');
+            spyOn(telemetry, 'track');
+            response = Symbol('response');
+            insight.askPermission.and.callFake((_, cb) => cb(null, response));
+        });
+
+        it('calls insight.askPermission [T011]', () => {
+            return telemetry.showPrompt().then(_ => {
+                expect(insight.askPermission).toHaveBeenCalled();
+            });
+        });
+
+        it('returns a promise resolved to the user response [T012]', () => {
+            return telemetry.showPrompt().then(result => {
+                expect(result).toBe(response);
+            });
+        });
+
+        describe('when user opts in', () => {
+            beforeEach(() => {
+                response = true;
+            });
+
+            it('thanks the user [T013]', () => {
+                return telemetry.showPrompt().then(_ => {
+                    expect(console.log).toHaveBeenCalledWith(
+                        jasmine.stringMatching(/thanks/i)
+                    );
+                });
+            });
+
+            it('tracks the user decision [T014]', () => {
+                return telemetry.showPrompt().then(_ => {
+                    expect(telemetry.track).toHaveBeenCalledWith(
+                        'telemetry', 'on', 'via-cli-prompt-choice', 'successful'
+                    );
+                });
+            });
+        });
+
+        describe('when user declines', () => {
+            beforeEach(() => {
+                response = false;
+            });
+
+            it('returns a resolved promise if the user response was negative [T015]', () => {
+                return telemetry.showPrompt().then(result => {
+                    expect(result).toBe(false);
+                });
+            });
+
+            it('informs the user [T016]', () => {
+                return telemetry.showPrompt().then(_ => {
+                    expect(console.log).toHaveBeenCalledWith(
+                        jasmine.stringMatching(/opted out of telemetry.* cordova telemetry on/i)
+                    );
+                });
+            });
+
+            it('tracks the user decision [T017]', () => {
+                return telemetry.showPrompt().then(_ => {
+                    expect(telemetry.track).toHaveBeenCalledWith(
+                        'telemetry', 'off', 'via-cli-prompt-choice', 'successful'
+                    );
+                });
+            });
+        });
+
+        describe('gory details', () => {
+            let stdin;
+            beforeEach(() => {
+                // Ensure that insight really shows a prompt
+                delete process.env.CI;
+                process.stdout.isTTY = true;
+                insight.askPermission.and.callThrough();
+
+                stdin = mockStdin.stdin();
+
+                // To silence the prompts by insight
+                spyOn(process.stdout, 'write');
+
+                // Ensure that prompts are shown for 10ms at most
+                telemetry.timeoutInSecs = 0.01;
+            });
+            afterEach(() => {
+                stdin.restore();
+            });
+            restoreAfterEach(process.env, 'CI');
+            restoreAfterEach(process.stdout, 'isTTY');
+
+            it('actually shows a prompt [T025]', () => {
+                return telemetry.showPrompt().then(() => {
+                    expect(process.stdout.write).toHaveBeenCalled();
+                });
+            });
+
+            it('saves the user response [T018]', () => {
+                process.nextTick(_ => stdin.send('y\n'));
+                return telemetry.showPrompt().then(result => {
+                    expect(result).toBe(true);
+                    expect(insight.config.set)
+                        .toHaveBeenCalledWith('optOut', false);
+                });
+            });
+
+            it('is counted as a negative response if user does not decide [T019]', () => {
+                return telemetry.showPrompt().then(result => {
+                    expect(result).toBe(false);
+                    expect(insight.config.set)
+                        .toHaveBeenCalledWith('optOut', true);
+                });
+            });
+
+            it('does NOT show prompt when running on a CI [T020]', () => {
+                process.env.CI = 1;
+                return telemetry.showPrompt().then(result => {
+                    expect(result).toBe(false);
+                    expect(insight.config.set).not.toHaveBeenCalled();
+                    expect(process.stdout.write).not.toHaveBeenCalled();
+                });
+            });
+        });
+    });
+    describe('insight.track', () => {
+        it('tracks without user choice [T021]', () => {
+            insight.track();
+            expect(insight._save).toHaveBeenCalled();
+        });
+
+        it('tracks with user consent [T022]', () => {
+            insight.config.get.and.returnValue(false);
+            insight.track();
+            expect(insight._save).toHaveBeenCalled();
+        });
+
+        it('does NOT track when user opted out [T023]', () => {
+            insight.config.get.and.returnValue(true);
+            insight.track();
+            expect(insight._save).not.toHaveBeenCalled();
+        });
+
+        describe('on CI', () => {
+            beforeEach(() => {
+                process.env.CI = 1;
+            });
+            restoreAfterEach(process.env, 'CI');
+
+            it('does still track [T024]', () => {
+                insight.track();
+                expect(insight._save).toHaveBeenCalled();
+            });
+        });
+    });
+});


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org