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