From 4dd667542c6fbe6d25292eb52cf97395eb39e57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Fri, 27 Sep 2019 23:42:46 +0000 Subject: [PATCH 1/7] [Common Recorder] Updated README Fixes #4961 --- sdk/test-utils/recorder/README.md | 449 +++++++++++++++++++- sdk/test-utils/recorder/src/baseRecorder.ts | 2 +- sdk/test-utils/recorder/src/index.ts | 2 +- 3 files changed, 447 insertions(+), 6 deletions(-) diff --git a/sdk/test-utils/recorder/README.md b/sdk/test-utils/recorder/README.md index 8ad88a86848c..bc752f1b7d0f 100644 --- a/sdk/test-utils/recorder/README.md +++ b/sdk/test-utils/recorder/README.md @@ -1,9 +1,450 @@ -## Test Utils - Record and Playback +## Azure SDK for JavaScript's test-utils-recorder -This library provides interfaces and helper methods to equip the sdks in the azure-sdk-for-js repo with the recording and playback capabilities for the tests, it targets HTTP requests in both Node.js and the Browsers. +The Azure SDK for JavaScript is composed of a multitude of repositories that +attempt to deliver a common, homogenous SDK to make use of all of the services +that Azure can provide. Among the challenges of such a goal, we have some that +are specific to tests, some of which we can summarize in the following +questions: -As a "test-utils" library, it is supposed to be added only as a devDependency and should be used only for the tests of an sdk. +- How to write live tests that can work as unit tests? +- How to ensure that tests are as fast as they can be? +- How to avoid wrting mocked versions of our HTTP API? +- How to protect sensitive data from our live tests? +- How to write tests that support parallelism? +- How to write isomorphic tests for NodeJS and the Browsers? -This library assumes that the tests rely on mocha test framework(and karma test runner for browser tests). +Our test-utils-recorder attempts to provide an answer for those questions, +as you'll be able to see throughout this README. + +This library provides interfaces and helper methods to equip the sdks in the +azure-sdk-for-js repo with the recording and playback capabilities for the +tests, it targets HTTP requests in both Node.js and the Browsers. + +test-utils-recorder, as part of the Test Utils available in this repository, it +is supposed to be added only as a devDependency and should be used only for the +tests of an sdk. + +## Index + +- [Key concepts](#key-concepts). +- [Getting started](#getting-started). + - [Installing the package](#installing-the-package). + - [Configuring your project](#configuring-your-project). +- [Examples](#examples). + - [How to record](#how-to-record). + - [How to playback](#how-to-playback). + - [Updating exisitng recordings](#updating-existing-recordings). + - [Skipping tests](#skipping-tests). + - [Securing sensitive data](#securing-sensitive-data). + - [Ever-changing tests](#ever-changing-tests). + - [Supporting parallelism](#supporting-parallelism). + - [Isomorphic tests](#isomorphic-tests). +- [Troubleshooting](#troubleshooting). +- [Next steps](#next-steps). +- [Contributing](#contributing). + +## Key concepts + +- To **record** means to intercept any HTTP request, store it in a file, then + store the response received from the live resource that was originally + targetted. We use a couple of mechanisms to do this for NodeJS and the + browser. The output files are stored in `recordings/node/*` and in + `recordings/browser/*`, which are relative to the root of the project you're + be working on. +- To **playback** means to intercept any HTTP request and to respond it with the + stored response of a previously recorded matching request. + +## Getting started + +We're about to go through how to set up your project to use the test-utils-recorder. +We'll be using git and [rush](https://rushjs.io). We understand that both tools +can be challenging to use, but we expect you to know how to use them by the +time you decide to use this package. If you encounter any problem with these +tools, pleae make sure to check at their documentation first, but we're also +happy to answer any question! We appreciate that you're reading this 💙 + +Keep in mind that test-utils-recorder is not a published package. It is only intended to be used +by our libraries (at least for now). + +### Installing the package + +To install the test-utils-recorder package, you'll need to start by cloning our +azure-sdk-for-js repository. One way of doing this is by using the git command +line interface, as follows: + + cd /path/to/my/github/repositories + git clone https://github.com/Azure/azure-sdk-for-js/ + +Having cloned this repository, let's set it up by running the following rush commands: + + cd azure-sdk-for-js + rush update + rush install + rush build + +This will optimistically asume you're in a fresh clone. + +From this point forward, we'll assume that you're developing (perhaps +contributing!) to one of our libraries. So, your next step is to change +directory to the path relevant to your project. Let's say you want to add +test-utils-recorder to the package `@azure/keyvault-keys` (it already uses test-utils-recorder, +but bear with us), you'll be doing the following: + + cd sdk/keyvault/keyvault-keys + +One there, you can add the test-utils-recorder package by running the following rush command: + + rush add -p @azure/test-utils-recorder + +And you're ready! Now you can use the common recorder in your code, as shown below: + +```typescript +import * as commonRecorder from "@azure/test-utils-recorder"; +``` + +The common recorder provides the following public methods and properties: + +- `record`: Which deals with recording and playing back the network requests, + depending on the value assigned to the `TEST_MODE` environment variable. + If `TEST_MODE` equals to `record`, it will automatically store every network + request in a plain text file in the folder `recordings` at the root of your + repository (which for our example case is the root of the + `@azure/keyvault/keyvault-keys` repository). It must be used inside of Mocha's + tests, since it uses [nise](https://www.npmjs.com/package/nise) under the hood. + It also returns an object with a method `stop()`, which will allow you to control when + you want the recorder to stop re-routing your http requests. +- `env`, which exposes the environment variable's object from either NodeJS or + the browser (useful on isomorphic tests). +- `delay`, which is an asynchronous funtion that will resolve once the given milliseconds have elapsed, + but only whie the `TEST_MODE` is not `playback`, since you want to make sure you can run the playback tests + as fast as posible. +- `isRecordMode`, which is a shorthand for checking if the environment variable + `TEST_MODE` is set to `record`. +- `isPlaybackMode`, which is a shorthand for checking if the environment + variable `TEST_MODE` is set to `playback`. +- `setReplaceableVariables`, which will allow you to hide sensitive content + from the environment variables (more on that later). +- `setReplacements`, which will allow you to hide sensitive content by doing + pattern matching in the output files. +- `skipQueryParams`, since query parameters may contain sensitive information, + the array provided to method will signal what query parameters to remove from + the recordings. + +### Configuring your project + +Having the common recorder as a dependency means that you'll be able to start +recording tests right away by using the exported method `record`. We'll get +into the details further down this document. This function will do recordings, +or will play back previous recordings, depending on an environment variable: +`TEST_MODE`. If the environment variable `TEST_MODE` is empty, `record` (and most +of the functions provided by test-utils-recorder) won't be doing anything. You'll need +to set this environment variable to `record` to start recording, and then to +`playback` to play the recordings back at your code. + +#### package.json scripts + +You can write scripts in your `package.json` to +make it easier to switch from record mode to playback mode, on a meaningful context, as follows: + + "integration-test:node": "mocha myNodeTests.js", + "unit-test:node": "TEST_MODE=playback npm run integration-test:node", + "test:node:record": "TEST_MODE=record npm run integration-test:node" + + +Once your tests run, new files will be created in the `recordings/*` folder. +These files will have names that are relative to the tests that you have. +There might be cases in which the recordins get outdated with the test files, so you might also want to +add a way to clear the recordings on your `package.json`, like the following one: + + "clear-recordings": "rm -fr recordings", + +#### Karma configuration + +To make sure you're able to do record and playback on your browser tests, make +sure to configure Karma properly. + +The recordingds are separated between NodeJS recordings and browser recordings, +so to use them on Karma, YOu'll at least need to add the recordings to your +`files` array in your `karma.conf.js`, as follows: + + files: [ + // ... you might have other things here. Keep them. + "recordings/browsers/**/*.json" + ], + +Same goes on the `preprocessors` array: + + preprocessors: { + // ... you might have other things here. Keep them. + "recordings/browsers/**/*.json": ["json"] + }, + +You can also tell Karma to hide console.logs in during the playbacks in the browsers by adding +the following configuration property: + + browserConsoleLogOptions: { + terminal: process.env.TEST_MODE !== "record" + }, + +#### Environment variables + +Since we make use of the `TEST_MODE` environment variables, we recommend you to +take control of how you deal with environment variables for your tests. One way +of doing this is with the [dotenv](https://www.npmjs.com/package/dotenv) +project, which is what we mostly use in our packages. dotenv comes with its own +issues, since it might act unexpectedly in relation with already assigned +environment variables. dotenv doesn't replace any environment variable that is +set by another source, so keep that in mind. + +For how to hide sensitive information related to environment variables, check +out our example called [Securing sensitive data](#securing-sensitive-data). + +## Examples + +### How to record + +To record your tests, make sure to call to the `record` function exported from +the test-utils-recorder, then call it before the http request you want to make +happens. In the following example, we'll be starting to record before +authenticating our KeyVault client: + +```typescript +import { env, record, Recorder } from "@azure/test-utils-recorder"; +import { KeysClient } from "@azure/keyvault-keys"; + +describe("My test", () => { + let recorder: Recorder; + let client: KeysClient; + + beforeEach(async function() { + recorder = record(that); + const credential = await new ClientSecretCredential( + env.AZURE_TENANT_ID, + env.AZURE_CLIENT_ID, + env.AZURE_CLIENT_SECRET + ); + + const keyVaultUrl = "https://myKeyVault.vault.azure.net"; + client = new KeysClient(keyVaultUrl, credential); + }); + + afterEach(function () { + recorder.stop(); + }); +}); +``` + +If you run the previous test with Mocha, and you set the `TEST_MODE` +environment variable to `record`, the common recorder will create a recording file located in +`recordings/node/my_test/recording_before_each_hook.js` with the contents of the HTTP request +as well as the contents of the HTTP response. + +You'll see in the code above that we're calling to `recorder.stop`. This is so +that, after each test, we can stop recording and the test file can be +generated. We recommend creating new recorders on `beforeEach` and stopping the +recorder on `afterEach` to make sure that the generated files are smaller and +easier to understand than by having them all in one chunk. + +> **Note:** By this point you might have noticed that the values in the environment variables will be stored in the recordings. +> We'll make sure this doesn't happen in the [Securing sensitive data](#securing-sensitive-data) example. + +To add recorded tests, feel free to extend this file with as many subsequent +`it()` calls as you need, each one of them is going to end up in their appropriate file. + +```typescript + beforeEach(async function() { + recorder = record(that); + const credential = await new ClientSecretCredential( + env.AZURE_TENANT_ID, + env.AZURE_CLIENT_ID, + env.AZURE_CLIENT_SECRET + ); + + const keyVaultUrl = "https://myKeyVault.vault.azure.net"; + client = new KeysClient(keyVaultUrl, credential); + }); + + afterEach(function () { + recorder.stop(); + }); + + it("my first test", async function() { + const result = await client.createKey("First key", "RSA"); + assert.equal(result.name, "First key"); + }); + + it("my second test", async function() { + const result = await client.createKey("Second key", "RSA"); + assert.equal(result.name, "Second key"); + }); + + // And so on... +}); +``` + +### How to playback + +Once you have recorded something, you can run your tests again with `TEST_MODE` +set to `playback`. You'll notice how they pass much faster. This time, they +will not reach out to the remote address, but instead they will respond every +request accoding to their matching copy stored in the recordings. + +### Update existing recordings + +Once you have your recorded files, to update them after changing one of the tests, simply +re-run the tests with `TEST_MODE` set to `record`. This will overwrite previously existing files. + +> **Note:** If you rename the file of the test, or the name of the test, the path +> of the recording will change. If you do these kind of changes, make sure to delete your recordings folder. +> The common recorder will re-generate only the updated tests. + +### Skipping tests + +Writing live tests can take considerable time, specially since each time you +want to check that everything works fine, you potentially need to run again +every test. With the common recorder, you can specify what test to run by following Mocha's +approach of setting certain tests to `it.only`, and also to skip specific tests +with `it.skip`. If you launch the recorder in record mode with some of these +changes (and given that you activate the recorder on `beforeEach`), only the +files that relate to the changed tests will be updated. Skipped tests won't +update their recordings. This way, you can focus on fixing a specific set of +test with `.only`, then remove all the `.only` calls and trust that the playback will +keep confirming that the unaffected tests are fine and green. + +### Securing sensitive data + +Live tests need to do sensitive operations, like authenticating with your Azure +credentials. To protect this information from the recordings, the +test-utils-recorder provides the following functions: + +- `setReplaceableVariables`, which will allow you to hide sensitive content + from the environment variables (more on that later). +- `setReplacements`, which will allow you to hide sensitive content by doing + pattern matching in the output files. +- `skipQueryParams`, since query parameters may contain sensitive information, + the array provided to method will signal what query parameters to remove from + the recordings. + +Let's see some examples. + +#### setReplaceableVariables + +This method will allow you to specify what environment variables have sensitive information. +Give to this function a plain object composed of the names of the environment +variables that can't be stored in the recordings, with the values you want to +store instead. To solve this issue in our previous example test, you may do the following: + +```typescript +// You'll be most certainly importing more than this method. +import { setReplaceableVariables } from "@azure/test-utils-recorder"; + +// Do this inside of the beforeEach, before you start recording. +setReplaceableVariables({ + AZURE_CLIENT_ID: "azure_client_id", + AZURE_CLIENT_SECRET: "azure_client_secret", + AZURE_TENANT_ID: "azure_tenant_id", + KEYVAULT_NAME: "keyvault_name" +}); +``` + +If you record the tests with that change, you should see the values of those +environment variables replaced with their safe counterpart. + +#### setReplacements + +A more generic way to clean up your recordings is by providing you with the +final string of the recording, to which you'll be able to make arbitrary +changes. The `setReplacements` method expects to receive an array of functions, all of which will receive +the recorded string and return a string. + +Let's say your project can't include the word `mango`. You will be able to get rid of it with the following code inside your `beforeEach`: + +```typescript +setReplacements([ + (recording: string): string => + recording.replace(/mango/g, "bananas"), +]); +``` + +#### skipQueryParams + +Some HTTP requests migth have parameters with sensitive information. To get +them out of your recordings, you can call to `skipQueryParams` with a key-value +plain object where you speify the name of the query parametert you want to replace, +and the value you want to end up storing, as follows: + +```typescript +skipQueryParams({ + myQueryParameter: "theValueIWantStoredInMyRecordings", + anotherQueryParameter: "theOtherValueIWantStoredInMyRecordings", +}); +``` + +### Ever-changing tests + +Sometimes, your tests will do requests with unpredictable code. +The best way to ensure that your ever-changing tests pass on playback mode is to +use `setReplacements` or `skipQueryParams` to avoid having the changing contents +as part of your recordings. + +### Supporting parallelism + +A common issue while running integration tests is that, sometimes two persons +or machines might try to run the same set of tests against the same resource. +This is not directly related to the test-utils-recorder package, but if you're +getting into issues because of concurrent conflicting requests, we understand, +and we might be able to help by providing you with the following suggestions: + +1. Use randomly generated strings as prefixes or suffixes for the resources you +create. This will help you, but it will also only work so far, since new +resources are likely to get accumulated, even if you set code to delete them in +between tests, since some tests will eventually fail and crash your program. +2. Set up a separate program as part of your CI to automatically create and +destroy new resources each time you run a test. It doesn't sound easy, but it +might be a better solution. You'll need to make sure to clear resources in +case this program fails. + +These ideas come with their own issue and things to consider, so please take them +as ideas. We understand that might not be an easy problem to fix. + +### Isomorphic tests + +The test-utils-recorder does support running in the browser. If you use Karma, +as long as your karma configuration is correct, your tests should work both on +NodeJS and in the browsers! + +## Troubleshooting + +Besides the usual debugging of your code and tests, if you ever encounter a +problem while recording your tests, make sure to read the output in the +recordings. If the output is not what you expected, please follow up the +[contributing](#contributing) guidelines on how to write an issue for us. We'll +make sure to handle it as soon as we find the time. + +## Next steps + +The common recorder might not be used yet in each one of our libraries (we're working on it). +In the mean time, an easy way to find where we're using this package is by going through the following search link: + + +## Contributing + +This project welcomes contributions and suggestions. Please read the +[contributing guidelines](https://github.com/Azure/azure-sdk-for-js/blob/master/CONTRIBUTING.md) +for detailed information about how to contribute and what to expect while contributing. + + +### Testing + +To run our tests, first install the dependencies (with `npm install` or `rush install`), +then run the unit tests with: `npm run unit-test`. + +--- + +Thank you for your time! + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js/sdk/test-utils/recorder/README.png) diff --git a/sdk/test-utils/recorder/src/baseRecorder.ts b/sdk/test-utils/recorder/src/baseRecorder.ts index 620748b2a8fb..5c4626dc706d 100644 --- a/sdk/test-utils/recorder/src/baseRecorder.ts +++ b/sdk/test-utils/recorder/src/baseRecorder.ts @@ -43,7 +43,7 @@ export function skipQueryParams(params: string[]): void { queryParameters = params; } -export function setEnviromentOnLoad() { +export function setEnvironmentOnLoad() { if (!isBrowser() && (isRecordMode || isPlaybackMode)) { nock = require("nock"); } diff --git a/sdk/test-utils/recorder/src/index.ts b/sdk/test-utils/recorder/src/index.ts index 568f0b8791d0..4a45762896c5 100644 --- a/sdk/test-utils/recorder/src/index.ts +++ b/sdk/test-utils/recorder/src/index.ts @@ -6,6 +6,6 @@ export { env, delay, isPlaybackMode, isRecordMode } from "./utils"; export { setReplaceableVariables, setReplacements, - setEnviromentOnLoad, + setEnvironmentOnLoad, skipQueryParams } from "./baseRecorder"; From 167c76bee85a8919b1d308e1ee01962d8eac5e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Fri, 27 Sep 2019 23:47:46 +0000 Subject: [PATCH 2/7] typo fixes --- sdk/test-utils/recorder/README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sdk/test-utils/recorder/README.md b/sdk/test-utils/recorder/README.md index bc752f1b7d0f..79af9f67f378 100644 --- a/sdk/test-utils/recorder/README.md +++ b/sdk/test-utils/recorder/README.md @@ -8,7 +8,7 @@ questions: - How to write live tests that can work as unit tests? - How to ensure that tests are as fast as they can be? -- How to avoid wrting mocked versions of our HTTP API? +- How to avoid writing mocked versions of our HTTP API? - How to protect sensitive data from our live tests? - How to write tests that support parallelism? - How to write isomorphic tests for NodeJS and the Browsers? @@ -16,7 +16,7 @@ questions: Our test-utils-recorder attempts to provide an answer for those questions, as you'll be able to see throughout this README. -This library provides interfaces and helper methods to equip the sdks in the +This library provides interfaces and helper methods to equip the SDKs in the azure-sdk-for-js repo with the recording and playback capabilities for the tests, it targets HTTP requests in both Node.js and the Browsers. @@ -33,7 +33,7 @@ tests of an sdk. - [Examples](#examples). - [How to record](#how-to-record). - [How to playback](#how-to-playback). - - [Updating exisitng recordings](#updating-existing-recordings). + - [Updating existing recordings](#updating-existing-recordings). - [Skipping tests](#skipping-tests). - [Securing sensitive data](#securing-sensitive-data). - [Ever-changing tests](#ever-changing-tests). @@ -47,7 +47,7 @@ tests of an sdk. - To **record** means to intercept any HTTP request, store it in a file, then store the response received from the live resource that was originally - targetted. We use a couple of mechanisms to do this for NodeJS and the + targeted. We use a couple of mechanisms to do this for NodeJS and the browser. The output files are stored in `recordings/node/*` and in `recordings/browser/*`, which are relative to the root of the project you're be working on. @@ -60,7 +60,7 @@ We're about to go through how to set up your project to use the test-utils-recor We'll be using git and [rush](https://rushjs.io). We understand that both tools can be challenging to use, but we expect you to know how to use them by the time you decide to use this package. If you encounter any problem with these -tools, pleae make sure to check at their documentation first, but we're also +tools, please make sure to check at their documentation first, but we're also happy to answer any question! We appreciate that you're reading this 💙 Keep in mind that test-utils-recorder is not a published package. It is only intended to be used @@ -82,7 +82,7 @@ Having cloned this repository, let's set it up by running the following rush com rush install rush build -This will optimistically asume you're in a fresh clone. +This will optimistically assume you're in a fresh clone. From this point forward, we'll assume that you're developing (perhaps contributing!) to one of our libraries. So, your next step is to change @@ -115,9 +115,9 @@ The common recorder provides the following public methods and properties: you want the recorder to stop re-routing your http requests. - `env`, which exposes the environment variable's object from either NodeJS or the browser (useful on isomorphic tests). -- `delay`, which is an asynchronous funtion that will resolve once the given milliseconds have elapsed, - but only whie the `TEST_MODE` is not `playback`, since you want to make sure you can run the playback tests - as fast as posible. +- `delay`, which is an asynchronous function that will resolve once the given milliseconds have elapsed, + but only while the `TEST_MODE` is not `playback`, since you want to make sure you can run the playback tests + as fast as possible. - `isRecordMode`, which is a shorthand for checking if the environment variable `TEST_MODE` is set to `record`. - `isPlaybackMode`, which is a shorthand for checking if the environment @@ -163,8 +163,8 @@ add a way to clear the recordings on your `package.json`, like the following one To make sure you're able to do record and playback on your browser tests, make sure to configure Karma properly. -The recordingds are separated between NodeJS recordings and browser recordings, -so to use them on Karma, YOu'll at least need to add the recordings to your +The recordings are separated between NodeJS recordings and browser recordings, +so to use them on Karma, You'll at least need to add the recordings to your `files` array in your `karma.conf.js`, as follows: files: [ @@ -287,7 +287,7 @@ To add recorded tests, feel free to extend this file with as many subsequent Once you have recorded something, you can run your tests again with `TEST_MODE` set to `playback`. You'll notice how they pass much faster. This time, they will not reach out to the remote address, but instead they will respond every -request accoding to their matching copy stored in the recordings. +request according to their matching copy stored in the recordings. ### Update existing recordings @@ -370,7 +370,7 @@ setReplacements([ Some HTTP requests migth have parameters with sensitive information. To get them out of your recordings, you can call to `skipQueryParams` with a key-value -plain object where you speify the name of the query parametert you want to replace, +plain object where you specify the name of the query parameter you want to replace, and the value you want to end up storing, as follows: ```typescript From 95de747a00f02ed5d587084558bcf7801e246c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Wed, 2 Oct 2019 01:58:26 +0000 Subject: [PATCH 3/7] feedback --- sdk/test-utils/recorder/README.md | 245 +++++++++++++++++++----------- 1 file changed, 159 insertions(+), 86 deletions(-) diff --git a/sdk/test-utils/recorder/README.md b/sdk/test-utils/recorder/README.md index 79af9f67f378..6002831d223f 100644 --- a/sdk/test-utils/recorder/README.md +++ b/sdk/test-utils/recorder/README.md @@ -13,9 +13,9 @@ questions: - How to write tests that support parallelism? - How to write isomorphic tests for NodeJS and the Browsers? -Our test-utils-recorder attempts to provide an answer for those questions, -as you'll be able to see throughout this README. - +Our NPM package `@azure/test-utils-recorder` attempts to provide an answer for +those questions, as you'll be able to see throughout this README. + This library provides interfaces and helper methods to equip the SDKs in the azure-sdk-for-js repo with the recording and playback capabilities for the tests, it targets HTTP requests in both Node.js and the Browsers. @@ -45,32 +45,39 @@ tests of an sdk. ## Key concepts -- To **record** means to intercept any HTTP request, store it in a file, then - store the response received from the live resource that was originally +- To **record** means to intercept any HTTP request (specifically, every + http.request call and browser's XMLHttpRequest calls), store it in a file, + then store the response received from the live resource that was originally targeted. We use a couple of mechanisms to do this for NodeJS and the browser. The output files are stored in `recordings/node/*` and in `recordings/browser/*`, which are relative to the root of the project you're - be working on. + working on. - To **playback** means to intercept any HTTP request and to respond it with the stored response of a previously recorded matching request. +- **Sensitive information** means content that should not be shared publicly. + Content like passwords, unique identifiers or personal information should be + cleaned up from the recordings. Some functionality is provided to fix this + problem. You can read more at [Securing sensitive data](#securing-sensitive-data). ## Getting started -We're about to go through how to set up your project to use the test-utils-recorder. -We'll be using git and [rush](https://rushjs.io). We understand that both tools -can be challenging to use, but we expect you to know how to use them by the -time you decide to use this package. If you encounter any problem with these -tools, please make sure to check at their documentation first, but we're also -happy to answer any question! We appreciate that you're reading this 💙 +We're about to go through how to set up your project to use the +`@azure/test-utils-recorder` package. We'll be using git and +[rush](https://rushjs.io). We understand that both tools can be challenging to +use, but we expect you to know how to use them by the time you decide to use +this package. If you encounter any problem with these tools, please let us know +by filing an issue [here](https://github.com/Azure/azure-sdk-for-js/issues). If +you have ideas about how we can make them better, we'd love to hear from you. -Keep in mind that test-utils-recorder is not a published package. It is only intended to be used -by our libraries (at least for now). +Keep in mind that `@azure/test-utils-recorder` is not a published package. It +is only intended to be used by the libraries in the azure-sdk-for-js repository +(at least for now). ### Installing the package -To install the test-utils-recorder package, you'll need to start by cloning our -azure-sdk-for-js repository. One way of doing this is by using the git command -line interface, as follows: +To install the `@azure/test-utils-recorder` package, you'll need to start by +cloning our azure-sdk-for-js repository. One way of doing this is by using the +git command line interface, as follows: cd /path/to/my/github/repositories git clone https://github.com/Azure/azure-sdk-for-js/ @@ -85,14 +92,15 @@ Having cloned this repository, let's set it up by running the following rush com This will optimistically assume you're in a fresh clone. From this point forward, we'll assume that you're developing (perhaps -contributing!) to one of our libraries. So, your next step is to change -directory to the path relevant to your project. Let's say you want to add -test-utils-recorder to the package `@azure/keyvault-keys` (it already uses test-utils-recorder, -but bear with us), you'll be doing the following: +contributing!) to one of the azure-sdk-for-js's libraries. So, your next step +is to change directory to the path relevant to your project. Let's say you want +to add the `@azure/test-utils-recorder` package to `@azure/keyvault-keys` (it +already uses test-utils-recorder, but bear with us), you'll be doing the +following: cd sdk/keyvault/keyvault-keys -One there, you can add the test-utils-recorder package by running the following rush command: +Once there, you can add the test-utils-recorder package by running the following rush command: rush add -p @azure/test-utils-recorder @@ -102,17 +110,27 @@ And you're ready! Now you can use the common recorder in your code, as shown bel import * as commonRecorder from "@azure/test-utils-recorder"; ``` +Or, if you know what functions you want to import, you can also do the following: + +```typescript +import { record, env, delay } from "@azure/test-utils-recorder"; +``` + The common recorder provides the following public methods and properties: - `record`: Which deals with recording and playing back the network requests, - depending on the value assigned to the `TEST_MODE` environment variable. - If `TEST_MODE` equals to `record`, it will automatically store every network - request in a plain text file in the folder `recordings` at the root of your + depending on the value assigned to the `TEST_MODE` environment variable. If + `TEST_MODE` equals to `record`, it will automatically store network requests + in a plain text file in the folder `recordings` at the root of your repository (which for our example case is the root of the - `@azure/keyvault/keyvault-keys` repository). It must be used inside of Mocha's - tests, since it uses [nise](https://www.npmjs.com/package/nise) under the hood. - It also returns an object with a method `stop()`, which will allow you to control when - you want the recorder to stop re-routing your http requests. + `@azure/keyvault/keyvault-keys` repository). + This package assumes that the tests in the sdk are leveraging + [mocha](https://mochajs.org/) and [rollup](https://rollupjs.org/guide/en/) + (and [karma](https://karma-runner.github.io/latest/index.html) test runner + for browser tests) as suggested by the [template](https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/template/template) + package in the repo. It also returns an object with a method `stop()`, which + will allow you to control when you want the recorder to stop re-routing your + http requests. - `env`, which exposes the environment variable's object from either NodeJS or the browser (useful on isomorphic tests). - `delay`, which is an asynchronous function that will resolve once the given milliseconds have elapsed, @@ -132,7 +150,7 @@ The common recorder provides the following public methods and properties: ### Configuring your project -Having the common recorder as a dependency means that you'll be able to start +Having the common recorder as a devDependency means that you'll be able to start recording tests right away by using the exported method `record`. We'll get into the details further down this document. This function will do recordings, or will play back previous recordings, depending on an environment variable: @@ -153,11 +171,20 @@ make it easier to switch from record mode to playback mode, on a meaningful cont Once your tests run, new files will be created in the `recordings/*` folder. These files will have names that are relative to the tests that you have. -There might be cases in which the recordins get outdated with the test files, so you might also want to +There might be cases in which the recordings get outdated with the test files, so you might also want to add a way to clear the recordings on your `package.json`, like the following one: "clear-recordings": "rm -fr recordings", +#### Environment variables + +Since we make use of the `TEST_MODE` environment variables, we recommend you to +take control of how you deal with environment variables for your tests. If you +don't want to set environment variables, you can use a tool like +[dotenv](https://www.npmjs.com/package/dotenv) to set them for you. Remember to +do one or the other, not both, as dotenv will not overwrite your existing +environment variables. + #### Karma configuration To make sure you're able to do record and playback on your browser tests, make @@ -167,45 +194,69 @@ The recordings are separated between NodeJS recordings and browser recordings, so to use them on Karma, You'll at least need to add the recordings to your `files` array in your `karma.conf.js`, as follows: - files: [ - // ... you might have other things here. Keep them. - "recordings/browsers/**/*.json" - ], +```typescript +config.set({ + // ... more configuration properties here + files: [ + // ... you might have other things here. Keep them. + "recordings/browsers/**/*.json" + ], + // ... more configuration properties here +}); +``` Same goes on the `preprocessors` array: - preprocessors: { - // ... you might have other things here. Keep them. - "recordings/browsers/**/*.json": ["json"] - }, +```typescript +config.set({ + // ... more configuration properties here + preprocessors: { + // ... you might have other things here. Keep them. + "recordings/browsers/**/*.json": ["json"] + }, + // ... more configuration properties here +}); +``` -You can also tell Karma to hide console.logs in during the playbacks in the browsers by adding -the following configuration property: +You will also need to set the following configuration so that Karma passes the +correct environment variables to the browser runtime: - browserConsoleLogOptions: { - terminal: process.env.TEST_MODE !== "record" - }, +```typescript +config.set({ + // ... more configuration properties here + envPreprocessor: [ + // ... you might have other things here. Keep them. + "TEST_MODE" + ], + // ... more configuration properties here +}); +``` -#### Environment variables +As an optional step, you can also tell Karma to hide console.logs in during the +playbacks in the browsers by adding the following configuration property: -Since we make use of the `TEST_MODE` environment variables, we recommend you to -take control of how you deal with environment variables for your tests. One way -of doing this is with the [dotenv](https://www.npmjs.com/package/dotenv) -project, which is what we mostly use in our packages. dotenv comes with its own -issues, since it might act unexpectedly in relation with already assigned -environment variables. dotenv doesn't replace any environment variable that is -set by another source, so keep that in mind. +```typescript +config.set({ + // ... more configuration properties here + browserConsoleLogOptions: { + terminal: process.env.TEST_MODE !== "record" + }, + // ... more configuration properties here +}); +``` -For how to hide sensitive information related to environment variables, check -out our example called [Securing sensitive data](#securing-sensitive-data). +For a more detailed and opinionated approach, please check out the following +section of our guidelines: +[Setting up karma.conf.js file in the SDK](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/test-utils/recorder/GUIDELINES.md#setting-up-karmaconfjs-file-in-the-sdk). ## Examples ### How to record -To record your tests, make sure to call to the `record` function exported from -the test-utils-recorder, then call it before the http request you want to make -happens. In the following example, we'll be starting to record before +To record your tests, make sure to set the environment variable `TEST_MODE` to +`record`, then in your code, call to the `record` function exported from +`@azure/test-utils-recorder`, then call it before the http request you want to +make. In the following example, we'll invoke the `record()` method before authenticating our KeyVault client: ```typescript @@ -217,13 +268,16 @@ describe("My test", () => { let client: KeysClient; beforeEach(async function() { - recorder = record(that); + recorder = record(this); + + // This is an example of how the environment variables are used const credential = await new ClientSecretCredential( env.AZURE_TENANT_ID, env.AZURE_CLIENT_ID, env.AZURE_CLIENT_SECRET ); + // This example also shows that HTTP requests must be made after the record() method is called. const keyVaultUrl = "https://myKeyVault.vault.azure.net"; client = new KeysClient(keyVaultUrl, credential); }); @@ -234,12 +288,12 @@ describe("My test", () => { }); ``` -If you run the previous test with Mocha, and you set the `TEST_MODE` -environment variable to `record`, the common recorder will create a recording file located in -`recordings/node/my_test/recording_before_each_hook.js` with the contents of the HTTP request -as well as the contents of the HTTP response. +After running this test with the `TEST_MODE` environment variable set to +`record`, the common recorder will create a recording file located in +`recordings/node/my_test/recording_before_each_hook.js` with the contents of +the HTTP request as well as the contents of the HTTP response. -You'll see in the code above that we're calling to `recorder.stop`. This is so +You'll see in the code above that we're invoking `recorder.stop`. This is so that, after each test, we can stop recording and the test file can be generated. We recommend creating new recorders on `beforeEach` and stopping the recorder on `afterEach` to make sure that the generated files are smaller and @@ -249,7 +303,8 @@ easier to understand than by having them all in one chunk. > We'll make sure this doesn't happen in the [Securing sensitive data](#securing-sensitive-data) example. To add recorded tests, feel free to extend this file with as many subsequent -`it()` calls as you need, each one of them is going to end up in their appropriate file. +`it()` calls as you need. Any HTTP request in these tests will be added to the +recordings. ```typescript beforeEach(async function() { @@ -294,9 +349,11 @@ request according to their matching copy stored in the recordings. Once you have your recorded files, to update them after changing one of the tests, simply re-run the tests with `TEST_MODE` set to `record`. This will overwrite previously existing files. -> **Note:** If you rename the file of the test, or the name of the test, the path -> of the recording will change. If you do these kind of changes, make sure to delete your recordings folder. -> The common recorder will re-generate only the updated tests. +> **Note:** If you rename the file of the test, or the name of the test, the +> path of the recording will change. Make sure to delete the recordings +> corresponding to the deleted tests. If at any point in time you lose your +> recordings, don't worry. Running your tests with `TEST_MODE=recording` will +> re-generate them. ### Skipping tests @@ -311,16 +368,23 @@ update their recordings. This way, you can focus on fixing a specific set of test with `.only`, then remove all the `.only` calls and trust that the playback will keep confirming that the unaffected tests are fine and green. +You can also skip specific tests with `recorder.skip(runtime?: "node" | "browser")`, +which will skip the test in node or browser runtimes based on the `{runtime}` +argument. If the `{runtime}` is undefined, the test will be skipped in both the +node and browser runtimes. This method has no effect if the TEST_MODE +environment variable is neither "record" nor "playback". You can read more +about this feature [here](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/test-utils/recorder/GUIDELINES.md#skipping-a-test). + ### Securing sensitive data Live tests need to do sensitive operations, like authenticating with your Azure -credentials. To protect this information from the recordings, the -test-utils-recorder provides the following functions: +credentials. To protect this information from the recordings, +`@azure/test-utils-recorder` provides the following functions: - `setReplaceableVariables`, which will allow you to hide sensitive content from the environment variables (more on that later). - `setReplacements`, which will allow you to hide sensitive content by doing - pattern matching in the output files. + pattern matching in the recordings of the tests' HTTP requests. - `skipQueryParams`, since query parameters may contain sensitive information, the array provided to method will signal what query parameters to remove from the recordings. @@ -366,18 +430,21 @@ setReplacements([ ]); ``` +This lets you have control over the generated recordings and filter any +sensitive information even before checking them in a pull request. + #### skipQueryParams Some HTTP requests migth have parameters with sensitive information. To get -them out of your recordings, you can call to `skipQueryParams` with a key-value -plain object where you specify the name of the query parameter you want to replace, -and the value you want to end up storing, as follows: +them out of your recordings, you can call to `skipQueryParams` with an array of strings +where you specify the names of the query parameter you want to remove. + +For example, give nthat we find this query parameters in our recordings: +`?sv=2018-11-09&sr=c&sig=&sktid=&skv=2018-11-09&se=2019-08-07T07%3A00%3A00Z&sp=rwdl`, +if we don't want the parameters "sr", "sig" and "sp" to appear in these files, we can do the following: ```typescript -skipQueryParams({ - myQueryParameter: "theValueIWantStoredInMyRecordings", - anotherQueryParameter: "theOtherValueIWantStoredInMyRecordings", -}); +skipQueryParams(["sr", "sig", "sp"]) ``` ### Ever-changing tests @@ -391,9 +458,10 @@ as part of your recordings. A common issue while running integration tests is that, sometimes two persons or machines might try to run the same set of tests against the same resource. -This is not directly related to the test-utils-recorder package, but if you're -getting into issues because of concurrent conflicting requests, we understand, -and we might be able to help by providing you with the following suggestions: +This is not directly related to the `@azure/test-utils-recorder` package, but +if you're getting into issues because of concurrent conflicting requests, we +understand, and we might be able to help by providing you with the following +suggestions: 1. Use randomly generated strings as prefixes or suffixes for the resources you create. This will help you, but it will also only work so far, since new @@ -409,9 +477,9 @@ as ideas. We understand that might not be an easy problem to fix. ### Isomorphic tests -The test-utils-recorder does support running in the browser. If you use Karma, -as long as your karma configuration is correct, your tests should work both on -NodeJS and in the browsers! +`@azure/test-utils-recorder` does support running in the browser. If you use +Karma, as long as your karma configuration is correct, your tests should work +both on NodeJS and in the browsers! ## Troubleshooting @@ -423,8 +491,10 @@ make sure to handle it as soon as we find the time. ## Next steps -The common recorder might not be used yet in each one of our libraries (we're working on it). -In the mean time, an easy way to find where we're using this package is by going through the following search link: +The common recorder might not be used yet in each one of the libraries in the +azure-sdk-for-js repository (we're working on it). In the mean time, an easy +way to find where we're using this package is by going through the following +search link: ## Contributing @@ -441,7 +511,10 @@ then run the unit tests with: `npm run unit-test`. --- -Thank you for your time! +We appreciate feedback on how well this tool works for you. Please write to us +[here](https://github.com/Azure/azure-sdk-for-js/issues). + +--- This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or From 2c21db1e4c69070c0c612e7ff79deb972d64c8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Wed, 2 Oct 2019 20:52:54 +0000 Subject: [PATCH 4/7] recent feedback --- sdk/test-utils/recorder/README.md | 54 ++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/sdk/test-utils/recorder/README.md b/sdk/test-utils/recorder/README.md index 6002831d223f..f656a664d777 100644 --- a/sdk/test-utils/recorder/README.md +++ b/sdk/test-utils/recorder/README.md @@ -63,11 +63,10 @@ tests of an sdk. We're about to go through how to set up your project to use the `@azure/test-utils-recorder` package. We'll be using git and -[rush](https://rushjs.io). We understand that both tools can be challenging to -use, but we expect you to know how to use them by the time you decide to use -this package. If you encounter any problem with these tools, please let us know -by filing an issue [here](https://github.com/Azure/azure-sdk-for-js/issues). If -you have ideas about how we can make them better, we'd love to hear from you. +[rush](https://rushjs.io) in this readme. Please read their documentation. If +you have ideas about how we can make them better, we'd love to hear from you! +Please let us know by filing an issue +[here](https://github.com/Azure/azure-sdk-for-js/issues). Keep in mind that `@azure/test-utils-recorder` is not a published package. It is only intended to be used by the libraries in the azure-sdk-for-js repository @@ -79,15 +78,19 @@ To install the `@azure/test-utils-recorder` package, you'll need to start by cloning our azure-sdk-for-js repository. One way of doing this is by using the git command line interface, as follows: - cd /path/to/my/github/repositories - git clone https://github.com/Azure/azure-sdk-for-js/ +```bash +cd /path/to/my/github/repositories +git clone https://github.com/Azure/azure-sdk-for-js/ +``` Having cloned this repository, let's set it up by running the following rush commands: - cd azure-sdk-for-js - rush update - rush install - rush build +```bash +cd azure-sdk-for-js +rush update +rush install +rush build +``` This will optimistically assume you're in a fresh clone. @@ -98,11 +101,15 @@ to add the `@azure/test-utils-recorder` package to `@azure/keyvault-keys` (it already uses test-utils-recorder, but bear with us), you'll be doing the following: - cd sdk/keyvault/keyvault-keys +```bash +cd sdk/keyvault/keyvault-keys +``` Once there, you can add the test-utils-recorder package by running the following rush command: - rush add -p @azure/test-utils-recorder +```bash +rush add -p @azure/test-utils-recorder +``` And you're ready! Now you can use the common recorder in your code, as shown below: @@ -164,17 +171,28 @@ to set this environment variable to `record` to start recording, and then to You can write scripts in your `package.json` to make it easier to switch from record mode to playback mode, on a meaningful context, as follows: - "integration-test:node": "mocha myNodeTests.js", - "unit-test:node": "TEST_MODE=playback npm run integration-test:node", - "test:node:record": "TEST_MODE=record npm run integration-test:node" - +```json +{ + // ... your package.json properties + "integration-test:node": "mocha myNodeTests.js", + "unit-test:node": "TEST_MODE=playback npm run integration-test:node", + "test:node:record": "TEST_MODE=record npm run integration-test:node", + // ... more of your package.json properties +} +``` Once your tests run, new files will be created in the `recordings/*` folder. These files will have names that are relative to the tests that you have. There might be cases in which the recordings get outdated with the test files, so you might also want to add a way to clear the recordings on your `package.json`, like the following one: - "clear-recordings": "rm -fr recordings", +```json +{ + // ... your package.json properties + "clear-recordings": "rm -fr recordings", + // ... more of your package.json properties +} +``` #### Environment variables From 12b6598221385011e8fa64cd0608b46e09b5403d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Wed, 2 Oct 2019 20:58:42 +0000 Subject: [PATCH 5/7] simplified the paragraph --- sdk/test-utils/recorder/README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sdk/test-utils/recorder/README.md b/sdk/test-utils/recorder/README.md index f656a664d777..af1db95ecf3a 100644 --- a/sdk/test-utils/recorder/README.md +++ b/sdk/test-utils/recorder/README.md @@ -62,11 +62,9 @@ tests of an sdk. ## Getting started We're about to go through how to set up your project to use the -`@azure/test-utils-recorder` package. We'll be using git and -[rush](https://rushjs.io) in this readme. Please read their documentation. If -you have ideas about how we can make them better, we'd love to hear from you! -Please let us know by filing an issue -[here](https://github.com/Azure/azure-sdk-for-js/issues). +`@azure/test-utils-recorder` package. + +This document assumes familiarity with [git](https://git-scm.com) and [rush](https://rushjs.io). Keep in mind that `@azure/test-utils-recorder` is not a published package. It is only intended to be used by the libraries in the azure-sdk-for-js repository From 2ca05439a456e9a7b5e5b9c39ccb4b6c1ee6fc47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Thu, 3 Oct 2019 19:00:07 +0000 Subject: [PATCH 6/7] feedback --- sdk/test-utils/recorder/README.md | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/sdk/test-utils/recorder/README.md b/sdk/test-utils/recorder/README.md index af1db95ecf3a..da0592ce4044 100644 --- a/sdk/test-utils/recorder/README.md +++ b/sdk/test-utils/recorder/README.md @@ -13,8 +13,8 @@ questions: - How to write tests that support parallelism? - How to write isomorphic tests for NodeJS and the Browsers? -Our NPM package `@azure/test-utils-recorder` attempts to provide an answer for -those questions, as you'll be able to see throughout this README. +Our non-published package `@azure/test-utils-recorder` attempts to provide an +answer for those questions, as you'll be able to see throughout this README. This library provides interfaces and helper methods to equip the SDKs in the azure-sdk-for-js repo with the recording and playback capabilities for the @@ -65,6 +65,10 @@ We're about to go through how to set up your project to use the `@azure/test-utils-recorder` package. This document assumes familiarity with [git](https://git-scm.com) and [rush](https://rushjs.io). +You can read more about how we use rush in the following links: + +- Rush used for [Project Orchestration](https://github.com/sadasant/azure-sdk-for-js/blob/master/CONTRIBUTING.md#project-orchestration). +- [Rush for NPM users](https://github.com/sadasant/azure-sdk-for-js/blob/master/CONTRIBUTING.md#rush-for-npm-users). Keep in mind that `@azure/test-utils-recorder` is not a published package. It is only intended to be used by the libraries in the azure-sdk-for-js repository @@ -136,6 +140,14 @@ The common recorder provides the following public methods and properties: package in the repo. It also returns an object with a method `stop()`, which will allow you to control when you want the recorder to stop re-routing your http requests. +- `Recorder`: The return of `record` is going to be an instance of the + `Recorder`, which has some useful functions: `stop`, `skip`, `getUniqueName`, + and `newDate`. `stop` will stop the recorder from storing a copy of the HTTP + requests and responses. `skip` will pause the recorder only during the test + from which skip was called. `getUniqueName` allows you to get unique strings, + which you can use to create unique resources, so that you can run the same + set of live tests in parallel without colliding. And `newDate` will allow you + to generate dates that don't change during playback. - `env`, which exposes the environment variable's object from either NodeJS or the browser (useful on isomorphic tests). - `delay`, which is an asynchronous function that will resolve once the given milliseconds have elapsed, @@ -194,7 +206,7 @@ add a way to clear the recordings on your `package.json`, like the following one #### Environment variables -Since we make use of the `TEST_MODE` environment variables, we recommend you to +Since we make use of the `TEST_MODE` environment variable, we recommend you to take control of how you deal with environment variables for your tests. If you don't want to set environment variables, you can use a tool like [dotenv](https://www.npmjs.com/package/dotenv) to set them for you. Remember to @@ -451,7 +463,7 @@ sensitive information even before checking them in a pull request. #### skipQueryParams -Some HTTP requests migth have parameters with sensitive information. To get +Some HTTP requests might have parameters with sensitive information. To get them out of your recordings, you can call to `skipQueryParams` with an array of strings where you specify the names of the query parameter you want to remove. @@ -493,9 +505,9 @@ as ideas. We understand that might not be an easy problem to fix. ### Isomorphic tests -`@azure/test-utils-recorder` does support running in the browser. If you use -Karma, as long as your karma configuration is correct, your tests should work -both on NodeJS and in the browsers! +`@azure/test-utils-recorder` does support running tests in the browser. If you +use Karma, as long as your karma configuration is correct, your tests should +work both on NodeJS and in the browsers! ## Troubleshooting From 4c32175ec9925b5af4a7d91c99667e4122065118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Thu, 3 Oct 2019 19:05:11 +0000 Subject: [PATCH 7/7] rush add doesnt work --- sdk/test-utils/recorder/README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/sdk/test-utils/recorder/README.md b/sdk/test-utils/recorder/README.md index da0592ce4044..ed396011ecab 100644 --- a/sdk/test-utils/recorder/README.md +++ b/sdk/test-utils/recorder/README.md @@ -107,10 +107,25 @@ following: cd sdk/keyvault/keyvault-keys ``` -Once there, you can add the test-utils-recorder package by running the following rush command: +Once there, you can add the test-utils-recorder package by changing your package.json +to include the following line in the devDependencies: ```bash -rush add -p @azure/test-utils-recorder +{ + // ... your package.json properties + "devDependencies": { + // ... your devDependencies + "@azure/test-utils-recorder": "1.0.0", + // ... more of your devDependencies + }, + // ... more of your package.json properties +} +``` + +After that, we recommend you to update rush and install the dependencies again, as follows: + +```bash +rush update && rush install ``` And you're ready! Now you can use the common recorder in your code, as shown below: