Skip to content

Commit

Permalink
feat: adding support for har file format
Browse files Browse the repository at this point in the history
  • Loading branch information
divdavem committed Jul 18, 2022
1 parent f043eb1 commit 832ec14
Show file tree
Hide file tree
Showing 34 changed files with 3,107 additions and 187 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -32,3 +32,5 @@ coverage-e2e/
# Mac OSX Finder files.
**/.DS_Store
.DS_Store

__ws__
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -58,6 +58,7 @@ Check [_Getting started_](./doc/getting-started.md) to learn more.
- can optionally act as the browser proxy
- generate TLS certificates on the fly to intercept HTTPS communications (as a man-in-the-middle)
- integrates nicely into your editor and source control: a simple hierarchy of files is generated in a clean way for inspection, edition, diffing, etc.
- supports the [HAR format](http://www.softwareishard.com/blog/har-12-spec/) to record and replay mocks

## Installation

Expand Down
41 changes: 37 additions & 4 deletions doc/api.md
Expand Up @@ -312,19 +312,23 @@ Most of the APIs accept and return a wrapped payload, which has the following pr

<a id="markdown-managing-local-files" name="managing-local-files"></a>

## Managing local files
## Managing local mocks

### Existence

- `async hasLocalFiles()`: return `true` if there are persisted local files under the mock instance's path, otherwise `false`
- `async hasNoLocalFiles()`: the opposite of `hasLocalFiles`, for convenience
- `async hasLocalMock()`: return `true` if there are persisted local files under the mock instance's path, otherwise `false`
- `async hasNoLocalMock()`: the opposite of `hasLocalMock`, for convenience

### Read/Write

- `async readLocalPayload()`: return a wrapped payload built from data persisted in local files. If no local files are present, return `undefined`
- `async persistPayload(wrappedPayload)`: take the given wrapped payload and persist it in local files

### List of generated files
### List of generated files (when `mocksFormat` is `folder`)

kassette can store mocks in two different formats: `folder` or `har`.

When `mocksFormat` is `folder`, it stores each request with its response in one folder containing up to 7 files, as described below.

In below file names, `[ext]` is an extension computed based on the actual type of the content in the file. If no extension could be determined, the file will actual drop the `.[ext]` part.

Expand All @@ -345,6 +349,35 @@ Forwarded request (from proxy to backend), for debug:

Checksum: as described in dedicated section, if a checksum was computed, the content generated to compute it will be output in a file named `checkum`.

Apart from the two first files from this list (`data.json` and `body.[ext]`), which are mandatory to be able to replay mocks, the generation of all the other files is mostly only useful to debug and can be disabled, either globally (in the configuration file, or through the command line) or per request (with a setter on the `mock` instance in the `hook` function) with the following settings:

- `saveInputRequestData`
- `saveInputRequestBody`
- `saveForwardedRequestData`
- `saveForwardedRequestBody`
- `saveChecksumContent`

The `saveDetailedTimings` setting can also be used to control whether detailed timings (`blocked`, `dns`, `connect`, `send`, `wait`, `receive`, `ssl`) are stored in the `timings` field in the `data.json` file (in addition to the global `time` field).

### Generated har file (when `mocksFormat` is `har`)

As mentioned in the previous section, kassette can store mocks in two different formats: `folder` or `har`.

When `mocksFormat` is `har`, kassette mostly follows the [har format specification](http://www.softwareishard.com/blog/har-12-spec/).

Some parts of the specification are not implemented and some custom fields are added, as described in the [API reference](https://amadeusitgroup.github.io/kassette/kassette.harformatentry.html).

kassette can store several requests/responses in the same har file.

As with the `folder` format, it is possible to control what is included in the har file through the following settings (either set globally or per-request):

- `saveInputRequestData`
- `saveInputRequestBody`
- `saveForwardedRequestData`
- `saveForwardedRequestBody`
- `saveChecksumContent`
- `saveDetailedTimings`

<a id="markdown-processing" name="processing"></a>

## Processing
Expand Down
21 changes: 20 additions & 1 deletion doc/getting-started.md
Expand Up @@ -10,6 +10,7 @@ Table of contents:
- [Run with an advanced hook](#run-with-an-advanced-hook)
- [Override configuration file options with CLI options](#override-configuration-file-options-with-cli-options)
- [Run as a browser proxy](#run-as-a-browser-proxy)
- [Record and replay mocks in a HAR file (as a browser proxy)](#record-replay-har-browser-proxy)
- [Filter TLS connections to intercept as a browser proxy](#filter-tls-connections-to-intercept-as-a-browser-proxy)
- [Get help in the terminal](#get-help-in-the-terminal)
- [Run with no option](#run-with-no-option)
Expand Down Expand Up @@ -151,7 +152,7 @@ exports.getConfiguration = async () => {
// (you can later on fill/alter its manually if you will)
//////////////////////////////////////////////////////////////////////////

if (await mock.hasLocalFiles()) { return; }
if (await mock.hasLocalMock()) { return; }

mock.setMode('manual');
let wrappedPayload = await mock.downloadPayload();
Expand Down Expand Up @@ -227,6 +228,24 @@ Once kassette is started, you have to configure your browser to use kassette as
npx playwright cr --proxy-server=http://127.0.0.1:8080 --ignore-https-errors
```

<a id="markdown-record-replay-har-browser-proxy" name="record-replay-har-browser-proxy"></a>

## Record and replay mocks in a HAR file (as a browser proxy)

Run `kassette --har-file mocks.har`.

This will start kassette as a browser proxy on port 8080 in the `local_or_download` mode and store all new requests in the `mocks.har` file.

In the `local_or_download` mode, existing requests are served from the HAR file instead of calling the remote server. To find a matching request, kassette by default only uses the HTTP method and the full URL (ignoring any header and the request body). This can be changed by using a configuration file and calling `setMockHarKey` in the `hook` function.

To only replay mocks from the HAR file without changing it and without calling the remote server (answering with a 404 error when there is no matching request in the HAR file), start kassette in the `local` mode instead: `kassette --har-file mocks.har -m local`

Once kassette is started, as explained in the previous example, configure your browser to use kassette as its proxy. You can use playwright:

```sh
npx playwright cr --proxy-server=http://127.0.0.1:8080 --ignore-https-errors
```

<a id="markdown-filter-tls-connections-to-intercept-as-a-browser-proxy" name="filter-tls-connections-to-intercept-as-a-browser-proxy"></a>

## Filter TLS connections to intercept as a browser proxy
Expand Down
111 changes: 111 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -27,6 +27,7 @@
"server",
"mock",
"mocking",
"har",
"http",
"https",
"proxy",
Expand Down Expand Up @@ -54,6 +55,7 @@
"@commitlint/config-conventional": "^17.0.3",
"@microsoft/api-documenter": "^7.18.0",
"@microsoft/api-extractor": "^7.28.2",
"@rollup/plugin-replace": "^4.0.0",
"@rollup/plugin-typescript": "^8.3.3",
"@types/jest": "^28.1.4",
"@types/koa": "^2.13.4",
Expand Down Expand Up @@ -83,6 +85,7 @@
"dependencies": {
"date-fns": "^2.28.0",
"interpret": "^3.1.1",
"istextorbinary": "^6.0.0",
"mime-types": "^2.1.35",
"node-forge": "^1.3.1",
"picocolors": "^1.0.0",
Expand Down

0 comments on commit 832ec14

Please sign in to comment.