diff --git a/v-next/core/src/global-dir.ts b/v-next/core/src/global-dir.ts index f385a009ce..baef8a250f 100644 --- a/v-next/core/src/global-dir.ts +++ b/v-next/core/src/global-dir.ts @@ -22,6 +22,21 @@ export async function getCacheDir(): Promise { return cache; } +/** + * Returns the path to the telemetry directory for the specified package. + * If no package name is provided, the default package name "hardhat" is used. + * Ensures that the directory exists before returning the path. + * + * @param packageName - The name of the package to get the telemetry directory for. Defaults to "hardhat". + * + * @returns A promise that resolves to the path of the telemetry directory. + */ +export async function getTelemetryDir(packageName?: string): Promise { + const { data } = await generatePaths(packageName); + await ensureDir(data); + return data; +} + async function generatePaths(packageName = "hardhat") { const { default: envPaths } = await import("env-paths"); return envPaths(packageName); diff --git a/v-next/hardhat/src/internal/cli/telemetry/analytics/analytics.ts b/v-next/hardhat/src/internal/cli/telemetry/analytics/analytics.ts new file mode 100644 index 0000000000..e55ddb090d --- /dev/null +++ b/v-next/hardhat/src/internal/cli/telemetry/analytics/analytics.ts @@ -0,0 +1,133 @@ +import type { + EventNames, + Payload, + TaskParams, + TelemetryConsentPayload, +} from "./types.js"; + +import os from "node:os"; + +import { spawnDetachedSubProcess } from "@ignored/hardhat-vnext-utils/subprocess"; +import debug from "debug"; + +import { getHardhatVersion } from "../../../utils/package.js"; +import { + isTelemetryAllowedInEnvironment, + isTelemetryAllowed, +} from "../telemetry-permissions.js"; + +import { getAnalyticsClientId } from "./utils.js"; + +const log = debug("hardhat:cli:telemetry:analytics"); + +const SESSION_ID = Math.random().toString(); +const ENGAGEMENT_TIME_MSEC = "10000"; + +// Return a boolean for testing purposes to verify that analytics are not sent in CI environments +export async function sendTelemetryConsentAnalytics( + consent: boolean, +): Promise { + // This is a special scenario where only the consent is sent, all the other analytics info + // (like node version, hardhat version, etc.) are stripped. + + if (!isTelemetryAllowedInEnvironment()) { + return false; + } + + const payload: TelemetryConsentPayload = { + client_id: "hardhat_telemetry_consent", + user_id: "hardhat_telemetry_consent", + user_properties: {}, + events: [ + { + name: "TelemetryConsentResponse", + params: { + userConsent: consent ? "yes" : "no", + }, + }, + ], + }; + + await createSubprocessToSendAnalytics(payload); + + return true; +} + +export async function sendTaskAnalytics(taskId: string[]): Promise { + const eventParams: TaskParams = { + task: taskId.join(", "), + }; + + return sendAnalytics("task", eventParams); +} + +// Return a boolean for testing purposes to confirm whether analytics were sent based on the consent value and not in CI environments +async function sendAnalytics( + eventName: EventNames, + eventParams: TaskParams, +): Promise { + if (!(await isTelemetryAllowed())) { + return false; + } + + const payload = await buildPayload(eventName, eventParams); + + await createSubprocessToSendAnalytics(payload); + + return true; +} + +async function createSubprocessToSendAnalytics( + payload: TelemetryConsentPayload | Payload, +): Promise { + log( + `Sending analytics for '${payload.events[0].name}'. Payload: ${JSON.stringify(payload)}`, + ); + + // The HARDHAT_TEST_SUBPROCESS_RESULT_PATH env variable is used in the tests to instruct the subprocess to write the payload to a file + // instead of sending it. + // During testing, the subprocess file is a ts file, whereas in production, it is a js file (compiled code). + // The following lines adjust the file extension based on whether the environment is for testing or production. + const fileExt = + process.env.HARDHAT_TEST_SUBPROCESS_RESULT_PATH !== undefined ? "ts" : "js"; + const subprocessFile = `${import.meta.dirname}/subprocess.${fileExt}`; + + const env: Record = {}; + if (process.env.HARDHAT_TEST_SUBPROCESS_RESULT_PATH !== undefined) { + // ATTENTION: only for testing + env.HARDHAT_TEST_SUBPROCESS_RESULT_PATH = + process.env.HARDHAT_TEST_SUBPROCESS_RESULT_PATH; + } + + await spawnDetachedSubProcess(subprocessFile, [JSON.stringify(payload)], env); + + log("Payload sent to detached subprocess"); +} + +async function buildPayload( + eventName: EventNames, + eventParams: TaskParams, +): Promise { + const clientId = await getAnalyticsClientId(); + + return { + client_id: clientId, + user_id: clientId, + user_properties: { + projectId: { value: "hardhat-project" }, + hardhatVersion: { value: await getHardhatVersion() }, + operatingSystem: { value: os.platform() }, + nodeVersion: { value: process.version }, + }, + events: [ + { + name: eventName, + params: { + engagement_time_msec: ENGAGEMENT_TIME_MSEC, + session_id: SESSION_ID, + ...eventParams, + }, + }, + ], + }; +} diff --git a/v-next/hardhat/src/internal/cli/telemetry/analytics/subprocess.ts b/v-next/hardhat/src/internal/cli/telemetry/analytics/subprocess.ts new file mode 100644 index 0000000000..08c15355a7 --- /dev/null +++ b/v-next/hardhat/src/internal/cli/telemetry/analytics/subprocess.ts @@ -0,0 +1,22 @@ +import { writeJsonFile } from "@ignored/hardhat-vnext-utils/fs"; +import { postJsonRequest } from "@ignored/hardhat-vnext-utils/request"; + +// These keys are expected to be public +// TODO: replace with prod values +const ANALYTICS_URL = "https://www.google-analytics.com/mp/collect"; +const API_SECRET = "iXzTRik5RhahYpgiatSv1w"; +const MEASUREMENT_ID = "G-ZFZWHGZ64H"; + +const payload = JSON.parse(process.argv[2]); + +if (process.env.HARDHAT_TEST_SUBPROCESS_RESULT_PATH === undefined) { + await postJsonRequest(ANALYTICS_URL, payload, { + queryParams: { + api_secret: API_SECRET, + measurement_id: MEASUREMENT_ID, + }, + }); +} else { + // ATTENTION: only for testing + await writeJsonFile(process.env.HARDHAT_TEST_SUBPROCESS_RESULT_PATH, payload); +} diff --git a/v-next/hardhat/src/internal/cli/telemetry/analytics/types.ts b/v-next/hardhat/src/internal/cli/telemetry/analytics/types.ts new file mode 100644 index 0000000000..63f205c33f --- /dev/null +++ b/v-next/hardhat/src/internal/cli/telemetry/analytics/types.ts @@ -0,0 +1,63 @@ +export interface AnalyticsFile { + analytics: { + clientId: string; + }; +} + +/* eslint-disable @typescript-eslint/naming-convention -- these payload is formatted based on what google analytics expects*/ +export interface BasePayload { + client_id: string; + user_id: string; + user_properties: {}; + events: Array<{ + name: string; + params: { + // From the GA docs: amount of time someone spends with your web + // page in focus or app screen in the foreground. + // The parameter has no use for our app, but it's required in order + // for user activity to display in standard reports like Realtime. + engagement_time_msec?: string; + session_id?: string; + }; + }>; +} + +export interface TelemetryConsentPayload extends BasePayload { + events: Array<{ + name: "TelemetryConsentResponse"; + params: { + userConsent: "yes" | "no"; + session_id?: string; + }; + }>; +} + +export type EventNames = "task"; + +export interface TaskParams { + task: string; +} + +export interface Payload extends BasePayload { + user_properties: { + projectId: { + value: string; + }; + hardhatVersion: { + value: string; + }; + operatingSystem: { + value: string; + }; + nodeVersion: { + value: string; + }; + }; + events: Array<{ + name: EventNames; + params: { + engagement_time_msec: string; + session_id: string; + } & TaskParams; + }>; +} diff --git a/v-next/hardhat/src/internal/cli/telemetry/analytics/utils.ts b/v-next/hardhat/src/internal/cli/telemetry/analytics/utils.ts new file mode 100644 index 0000000000..444af3aeeb --- /dev/null +++ b/v-next/hardhat/src/internal/cli/telemetry/analytics/utils.ts @@ -0,0 +1,58 @@ +import type { AnalyticsFile } from "./types.js"; + +import path from "node:path"; + +import { getTelemetryDir } from "@ignored/hardhat-vnext-core/global-dir"; +import { + exists, + readJsonFile, + writeJsonFile, +} from "@ignored/hardhat-vnext-utils/fs"; +import debug from "debug"; + +const log = debug("hardhat:cli:telemetry:analytics:utils"); + +const ANALYTICS_FILE_NAME = "analytics.json"; + +export async function getAnalyticsClientId(): Promise { + let clientId = await readAnalyticsClientId(); + + if (clientId === undefined) { + log("Client Id not found, generating a new one"); + + clientId = crypto.randomUUID(); + await writeAnalyticsClientId(clientId); + } + + return clientId; +} + +async function readAnalyticsClientId(): Promise { + const globalTelemetryDir = await getTelemetryDir(); + const filePath = path.join(globalTelemetryDir, ANALYTICS_FILE_NAME); + + log(`Looking up Client Id at '${filePath}'`); + + if ((await exists(filePath)) === false) { + return undefined; + } + + const data: AnalyticsFile = await readJsonFile(filePath); + const clientId = data.analytics.clientId; + + log(`Client Id found: ${clientId}`); + + return clientId; +} + +async function writeAnalyticsClientId(clientId: string): Promise { + const globalTelemetryDir = await getTelemetryDir(); + const filePath = path.join(globalTelemetryDir, ANALYTICS_FILE_NAME); + await writeJsonFile(filePath, { + analytics: { + clientId, + }, + }); + + log(`Stored clientId '${clientId}'`); +} diff --git a/v-next/hardhat/src/internal/cli/telemetry/telemetry-permissions.ts b/v-next/hardhat/src/internal/cli/telemetry/telemetry-permissions.ts index 3ec868a34f..ea77cda5db 100644 --- a/v-next/hardhat/src/internal/cli/telemetry/telemetry-permissions.ts +++ b/v-next/hardhat/src/internal/cli/telemetry/telemetry-permissions.ts @@ -7,9 +7,14 @@ import { readJsonFile, writeJsonFile, } from "@ignored/hardhat-vnext-utils/fs"; +import debug from "debug"; import { confirmationPromptWithTimeout } from "../prompt/prompt.js"; +import { sendTelemetryConsentAnalytics } from "./analytics/analytics.js"; + +const log = debug("hardhat:cli:telemetry:telemetry-permissions"); + interface TelemetryConsent { consent: boolean; } @@ -22,6 +27,8 @@ interface TelemetryConsent { * @returns True if the user consents to telemetry and if current environment supports telemetry, false otherwise. */ export async function ensureTelemetryConsent(): Promise { + log("Ensuring that user has provided telemetry consent"); + if (!isTelemetryAllowedInEnvironment()) { return false; } @@ -45,17 +52,47 @@ export async function isTelemetryAllowed(): Promise { return false; } + // ATTENTION: only for testing + if (process.env.HARDHAT_TEST_TELEMETRY_CONSENT_VALUE !== undefined) { + return process.env.HARDHAT_TEST_TELEMETRY_CONSENT_VALUE === "true" + ? true + : false; + } + const consent = await getTelemetryConsent(); + log(`Telemetry consent value: ${consent}`); + return consent !== undefined ? consent : false; } +/** + * Determines if telemetry is allowed in the current environment. + * This function checks various environmental factors to decide if telemetry data can be collected. + * It verifies that the environment is not a CI environment, that the terminal is interactive, + * and that telemetry has not been explicitly disabled through an environment variable. + * + * @returns True if telemetry is allowed in the environment, false otherwise. + */ +export function isTelemetryAllowedInEnvironment(): boolean { + const allowed = + (!isCi() && + process.stdout.isTTY === true && + process.env.HARDHAT_DISABLE_TELEMETRY_PROMPT !== "true") || + // ATTENTION: used in tests to force telemetry execution + process.env.HARDHAT_TEST_INTERACTIVE_ENV === "true"; + + log(`Telemetry is allowed in the current environment: ${allowed}`); + + return allowed; +} + /** * Retrieves the user's telemetry consent status from the consent file. * * @returns True if the user consents to telemetry, false if they do not consent, * and undefined if no consent has been provided. */ -export async function getTelemetryConsent(): Promise { +async function getTelemetryConsent(): Promise { const telemetryConsentFilePath = await getTelemetryConsentFilePath(); if (await exists(telemetryConsentFilePath)) { @@ -67,23 +104,6 @@ export async function getTelemetryConsent(): Promise { return undefined; } -/** - * Determines if telemetry is allowed in the current environment. - * This function checks various environmental factors to decide if telemetry data can be collected. - * It verifies that the environment is not a continuous integration (CI) environment, that the terminal is interactive, - * and that telemetry has not been explicitly disabled through an environment variable. - * - * @returns True if telemetry is allowed in the environment, false otherwise. - */ -export function isTelemetryAllowedInEnvironment(): boolean { - return ( - (!isCi() && - process.stdout.isTTY === true && - process.env.HARDHAT_DISABLE_TELEMETRY_PROMPT !== "true") || - process.env.HARDHAT_ENABLE_TELEMETRY_IN_TEST === "true" // Used in tests to force telemetry execution - ); -} - async function getTelemetryConsentFilePath() { const configDir = await getConfigDir(); return path.join(configDir, "telemetry-consent.json"); @@ -97,19 +117,17 @@ async function requestTelemetryConsent(): Promise { } // Store user's consent choice + log(`Storing telemetry consent with value: ${consent}`); await writeJsonFile(await getTelemetryConsentFilePath(), { consent }); - // TODO: this will be enabled in a following PR as soon as the function to send telemetry is implemented - // const subprocessFilePath = path.join( - // path.dirname(fileURLToPath(import.meta.url)), - // "report-telemetry-consent.js", - // ); - // await spawnDetachedSubProcess(subprocessFilePath, [consent ? "yes" : "no"]); + await sendTelemetryConsentAnalytics(consent); return consent; } async function confirmTelemetryConsent(): Promise { + log("Prompting user for telemetry consent"); + return confirmationPromptWithTimeout( "telemetryConsent", "Help us improve Hardhat with anonymous crash reports & basic usage data?", diff --git a/v-next/hardhat/test/internal/cli/telemetry/analytics/analytics.ts b/v-next/hardhat/test/internal/cli/telemetry/analytics/analytics.ts new file mode 100644 index 0000000000..854db6f394 --- /dev/null +++ b/v-next/hardhat/test/internal/cli/telemetry/analytics/analytics.ts @@ -0,0 +1,143 @@ +import type { Payload } from "../../../../../src/internal/cli/telemetry/analytics/types.js"; + +import assert from "node:assert/strict"; +import path from "node:path"; +import { after, afterEach, before, beforeEach, describe, it } from "node:test"; + +import { readJsonFile, remove } from "@ignored/hardhat-vnext-utils/fs"; + +import { + sendTaskAnalytics, + sendTelemetryConsentAnalytics, +} from "../../../../../src/internal/cli/telemetry/analytics/analytics.js"; +import { getHardhatVersion } from "../../../../../src/internal/utils/package.js"; +import { + checkIfSubprocessWasExecuted, + ROOT_PATH_TO_FIXTURE, +} from "../helpers.js"; + +// +// TEST EXPLANATION: When setting the environment variable HARDHAT_TEST_SUBPROCESS_RESULT_PATH, +// the subprocess writes the payload to the specified file instead of sending it to a remote server. +// This allows us to verify that the payload is formatted correctly. +// + +const PATH_TO_FIXTURE = path.join(ROOT_PATH_TO_FIXTURE, "analytics"); +const RESULT_FILE_PATH = path.join(PATH_TO_FIXTURE, "result.json"); + +describe("analytics", () => { + beforeEach(async () => { + process.env.HARDHAT_TEST_TELEMETRY_CONSENT_VALUE = "true"; + }); + + afterEach(async () => { + delete process.env.HARDHAT_TEST_TELEMETRY_CONSENT_VALUE; + }); + + describe("running in non interactive environment", () => { + it("should not send consent because the environment is non interactive", async () => { + const wasSent = await sendTelemetryConsentAnalytics(true); + assert.equal(wasSent, false); + }); + + it("should not send analytics because the environment is not interactive", async () => { + const wasSent = await sendTaskAnalytics(["task", "subtask"]); + assert.equal(wasSent, false); + }); + }); + + describe("running in an interactive environment (simulated with ENV variables)", () => { + before(() => { + process.env.HARDHAT_TEST_INTERACTIVE_ENV = "true"; + process.env.HARDHAT_TEST_SUBPROCESS_RESULT_PATH = RESULT_FILE_PATH; + }); + + after(() => { + delete process.env.HARDHAT_TEST_INTERACTIVE_ENV; + }); + + beforeEach(async () => { + await remove(RESULT_FILE_PATH); + }); + + afterEach(async () => { + await remove(RESULT_FILE_PATH); + }); + + it("should create the correct payload for the telemetry consent (positive consent)", async () => { + await sendTelemetryConsentAnalytics(true); + + await checkIfSubprocessWasExecuted(RESULT_FILE_PATH, true); + + const result = await readJsonFile(RESULT_FILE_PATH); + + assert.deepEqual(result, { + client_id: "hardhat_telemetry_consent", + user_id: "hardhat_telemetry_consent", + user_properties: {}, + events: [ + { + name: "TelemetryConsentResponse", + params: { + userConsent: "yes", + }, + }, + ], + }); + }); + + it("should create the correct payload for the telemetry consent (negative consent)", async () => { + await sendTelemetryConsentAnalytics(false); + + await checkIfSubprocessWasExecuted(RESULT_FILE_PATH, true); + + const result = await readJsonFile(RESULT_FILE_PATH); + + assert.deepEqual(result, { + client_id: "hardhat_telemetry_consent", + user_id: "hardhat_telemetry_consent", + user_properties: {}, + events: [ + { + name: "TelemetryConsentResponse", + params: { + userConsent: "no", + }, + }, + ], + }); + }); + + it("should create the correct payload for the task analytics", async () => { + const wasSent = await sendTaskAnalytics(["task", "subtask"]); + + await checkIfSubprocessWasExecuted(RESULT_FILE_PATH, true); + + const result: Payload = await readJsonFile(RESULT_FILE_PATH); + + assert.equal(wasSent, true); + + // Check payload properties + assert.notEqual(result.client_id, undefined); + assert.notEqual(result.user_id, undefined); + assert.equal(result.user_properties.projectId.value, "hardhat-project"); + assert.equal( + result.user_properties.hardhatVersion.value, + await getHardhatVersion(), + ); + assert.notEqual(result.user_properties.operatingSystem.value, undefined); + assert.notEqual(result.user_properties.nodeVersion.value, undefined); + assert.equal(result.events[0].name, "task"); + assert.equal(result.events[0].params.engagement_time_msec, "10000"); + assert.notEqual(result.events[0].params.session_id, undefined); + assert.equal(result.events[0].params.task, "task, subtask"); + }); + + it("should not send analytics because the consent is not given", async () => { + process.env.HARDHAT_TEST_TELEMETRY_CONSENT_VALUE = "false"; + + const wasSent = await sendTaskAnalytics(["task", "subtask"]); + assert.equal(wasSent, false); + }); + }); +}); diff --git a/v-next/hardhat/test/internal/cli/telemetry/analytics/utils.ts b/v-next/hardhat/test/internal/cli/telemetry/analytics/utils.ts new file mode 100644 index 0000000000..53c7075acf --- /dev/null +++ b/v-next/hardhat/test/internal/cli/telemetry/analytics/utils.ts @@ -0,0 +1,69 @@ +import type { AnalyticsFile } from "../../../../../src/internal/cli/telemetry/analytics/types.js"; + +import assert from "node:assert/strict"; +import path from "node:path"; +import { afterEach, beforeEach, describe, it } from "node:test"; + +import { getTelemetryDir } from "@ignored/hardhat-vnext-core/global-dir"; +import { + readJsonFile, + remove, + writeJsonFile, +} from "@ignored/hardhat-vnext-utils/fs"; + +import { getAnalyticsClientId } from "../../../../../src/internal/cli/telemetry/analytics/utils.js"; + +const CLIENT_ID = "test-client-id"; + +async function createClientIdFile() { + const filePath = await getFilePath(); + await writeJsonFile(filePath, { + analytics: { + clientId: CLIENT_ID, + }, + }); +} + +async function getClientIdFromFile() { + const filePath = await getFilePath(); + const data: AnalyticsFile = await readJsonFile(filePath); + return data.analytics.clientId; +} + +async function deleteClientIdFile() { + const filePath = await getFilePath(); + await remove(filePath); +} + +async function getFilePath() { + return path.join(await getTelemetryDir(), "analytics.json"); +} + +describe("telemetry/analytics/utils", () => { + describe("analyticsClientId", () => { + beforeEach(async () => { + await deleteClientIdFile(); + }); + + afterEach(async () => { + await deleteClientIdFile(); + }); + + it("should generate a new analytics clientId because the clientId is not yet defined", async () => { + const analyticsClientId = await getAnalyticsClientId(); + + // The analyticsClientId should be generate as uuid + assert.notEqual(analyticsClientId, undefined); + assert.notEqual(analyticsClientId, CLIENT_ID); + // The analyticsClientId should also be saved in the file + assert.equal(analyticsClientId, await getClientIdFromFile()); + }); + + it("should get the analyticsClientId from the file because it already exists", async () => { + await createClientIdFile(); + const analyticsClientId = await getClientIdFromFile(); + + assert.equal(analyticsClientId, CLIENT_ID); + }); + }); +}); diff --git a/v-next/hardhat/test/internal/cli/telemetry/helpers.ts b/v-next/hardhat/test/internal/cli/telemetry/helpers.ts new file mode 100644 index 0000000000..14fdd287e4 --- /dev/null +++ b/v-next/hardhat/test/internal/cli/telemetry/helpers.ts @@ -0,0 +1,58 @@ +import path from "node:path"; + +import { + exists, + readJsonFile, + readUtf8File, +} from "@ignored/hardhat-vnext-utils/fs"; + +export const ROOT_PATH_TO_FIXTURE: string = path.join( + process.cwd(), + "test", + "fixture-projects", + "cli", + "telemetry", +); + +export const TELEMETRY_FOLDER_PATH: string = path.join( + process.cwd(), + "src", + "internal", + "cli", + "telemetry", +); + +export async function checkIfSubprocessWasExecuted( + resultFilePath: string, + isJsonFile: boolean = false, +): Promise { + // Checks if the subprocess was executed by waiting for a file to be created. + // Uses an interval to periodically check for the file. If the file isn't found + // within a specified number of attempts, an error is thrown, indicating a failure in subprocess execution. + const MAX_COUNTER = 20; + + return new Promise((resolve, reject) => { + let counter = 0; + + const intervalId = setInterval(async () => { + counter++; + + if (await exists(resultFilePath)) { + try { + // Wait for the file to be readable. The file could exist but the writing could be in progress. + if (isJsonFile) { + await readJsonFile(resultFilePath); + } else { + await readUtf8File(resultFilePath); + } + + clearInterval(intervalId); + resolve(true); + } catch (_err) {} + } else if (counter > MAX_COUNTER) { + clearInterval(intervalId); + reject("Subprocess was not executed in the expected time"); + } + }, 50); + }); +} diff --git a/v-next/hardhat/test/internal/cli/telemetry/telemetry-permissions.ts b/v-next/hardhat/test/internal/cli/telemetry/telemetry-permissions.ts index e27eeb9ea0..130a4f169a 100644 --- a/v-next/hardhat/test/internal/cli/telemetry/telemetry-permissions.ts +++ b/v-next/hardhat/test/internal/cli/telemetry/telemetry-permissions.ts @@ -5,10 +5,7 @@ import { afterEach, beforeEach, describe, it } from "node:test"; import { getConfigDir } from "@ignored/hardhat-vnext-core/global-dir"; import { remove, writeJsonFile } from "@ignored/hardhat-vnext-utils/fs"; -import { - getTelemetryConsent, - isTelemetryAllowed, -} from "../../../../src/internal/cli/telemetry/telemetry-permissions.js"; +import { isTelemetryAllowed } from "../../../../src/internal/cli/telemetry/telemetry-permissions.js"; async function setTelemetryConsentFile(consent: boolean) { const configDir = await getConfigDir(); @@ -24,27 +21,27 @@ async function deleteTelemetryConsentFile() { describe("telemetry-permissions", () => { beforeEach(async () => { - delete process.env.HARDHAT_ENABLE_TELEMETRY_IN_TEST; + delete process.env.HARDHAT_TEST_INTERACTIVE_ENV; await deleteTelemetryConsentFile(); }); afterEach(async () => { - delete process.env.HARDHAT_ENABLE_TELEMETRY_IN_TEST; + delete process.env.HARDHAT_TEST_INTERACTIVE_ENV; await deleteTelemetryConsentFile(); }); describe("isTelemetryAllowed", () => { it("should return false because not an interactive environment", async () => { - await setTelemetryConsentFile(true); // Needed to be sure that the file is not read and the process exits before + await setTelemetryConsentFile(true); const res = await isTelemetryAllowed(); assert.equal(res, false); }); it("should return false because the user did not give telemetry consent", async () => { - process.env.HARDHAT_ENABLE_TELEMETRY_IN_TEST = "true"; + process.env.HARDHAT_TEST_INTERACTIVE_ENV = "true"; await setTelemetryConsentFile(false); const res = await isTelemetryAllowed(); @@ -52,27 +49,18 @@ describe("telemetry-permissions", () => { }); it("should return false because the telemetry consent is not set", async () => { - process.env.HARDHAT_ENABLE_TELEMETRY_IN_TEST = "true"; + process.env.HARDHAT_TEST_INTERACTIVE_ENV = "true"; const res = await isTelemetryAllowed(); assert.equal(res, false); }); it("should return true because the user gave telemetry consent", async () => { - process.env.HARDHAT_ENABLE_TELEMETRY_IN_TEST = "true"; + process.env.HARDHAT_TEST_INTERACTIVE_ENV = "true"; await setTelemetryConsentFile(true); const res = await isTelemetryAllowed(); assert.equal(res, true); }); }); - - it("should return undefined because the telemetry consent is not set", async () => { - // All other possible results are tested in the previous tests, they are included in the the function 'isTelemetryAllowed' - process.env.HARDHAT_ENABLE_TELEMETRY_IN_TEST = "true"; - - const res = await getTelemetryConsent(); - - assert.equal(res, undefined); - }); });