Skip to content

Commit

Permalink
feat(core): Server level configuration (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
offirgolan authored Sep 12, 2018
1 parent ec62fc0 commit 0f32d9b
Show file tree
Hide file tree
Showing 21 changed files with 483 additions and 171 deletions.
109 changes: 101 additions & 8 deletions docs/server/route-handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@ server
.on('request', () => {/* Do something else */});
```

### once

Register a one-time [event](server/events-and-middleware) handler.

?> __Tip:__ You can attach multiple handlers to a single event. Handlers will be
called in the order they were declared.

| Param | Type | Description |
| --- | --- | --- |
| eventName | `String` | The event name |
| handler | `Function` | The event handler |

__Example__

```js
server
.get('/session')
.once('request', req => {
req.headers['X-AUTH'] = '<ACCESS_TOKEN>';
req.query.email = '[email protected]';
})
.once('request', () => {/* Do something else */});
```

### off

Un-register an [event](server/events-and-middleware) handler. If no handler
Expand Down Expand Up @@ -59,9 +83,8 @@ server

Register an intercept handler. Once set, the [request](server/request) will
never go to server but instead defer to the provided handler to handle
the [response](server/response).

!> __NOTE:__ This method is not available when using `server.any()`.
the [response](server/response). If multiple intercept handlers have been
registered, each handler will be called in the order in which it was registered.

| Param | Type | Description |
| --- | --- | --- |
Expand All @@ -70,6 +93,10 @@ the [response](server/response).
__Example__

```js
server
.any('/session')
.intercept((req, res) => res.sendStatus(200));

server
.get('/session/:id')
.intercept((req, res, interceptor) => {
Expand Down Expand Up @@ -131,14 +158,80 @@ server

### passthrough

The server passthrough handler. Use this to declare a route as a passthrough
meaning any request that matches that route will directly use the native
implementation. Passthrough requests will not be recorded.
Declare a route as a passthrough meaning any request that matches that route
will directly use the native implementation. Passthrough requests will not be
recorded.

| Param | Type | Description |
| --- | --- | --- |
| passthrough | `boolean` | Enable or disable the passthrough. Defaults to `true` |

__Example__

```js
server
.any('/session')
.passthrough();

server
.get('/session/1')
.passthrough(false);
```

### recordingName

Override the recording name for the given route. This allows for grouping common
requests to share a single recording which can drastically help de-clutter test
recordings.

For example, if your tests always make a `/users` or `/session` call, instead of
having each of those requests be recorded for every single test, you can use
this to create a common recording file for them.

| Param | Type | Description |
| --- | --- | --- |
| recordingName | `String` | Name of the [recording](api#recordingName) to store the recordings under. |

__Example__

```js
server
.any('/session')
.recordingName('User Session');

server
.get('/users/:id')
.recordingName('User Data');

server
.get('/users/1')
.recordingName(); /* Fallback to the polly instance's recording name */
```

### configure

!> __NOTE:__ This method is not available when using `server.any()`.
Override configuration options for the given route. All matching middleware and route level configs are merged together and the overrides are applied to the current
Polly instance's config.

!> The following options are not supported to be overriden via the server API:
`mode`, `adapters`, `adapterOptions`, `persister`, `persisterOptions`

| Param | Type | Description |
| --- | --- | --- |
| config | `Object` | [Configuration](configuration) object |

__Example__

```js
server.get('/session').passthrough();
server
.any('/session')
.configure({ recordFailedRequests: true });

server
.get('/users/:id')
.configure({ timing: Timing.relative(3.0) });

server
.get('/users/1')
.configure({ logging: true });
```
10 changes: 5 additions & 5 deletions packages/@pollyjs/adapter/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export default class Adapter {
}
}

shouldReRecord(recordingEntry) {
const { config } = this.polly;
shouldReRecord(pollyRequest, recordingEntry) {
const { config } = pollyRequest;

if (isExpired(recordingEntry.startedDateTime, config.expiresIn)) {
if (!config.recordIfExpired) {
Expand Down Expand Up @@ -80,7 +80,7 @@ export default class Adapter {
}

timeout(pollyRequest, { time }) {
const { timing } = this.polly.config;
const { timing } = pollyRequest.config;

if (typeof timing === 'function') {
return timing(time);
Expand Down Expand Up @@ -168,13 +168,13 @@ export default class Adapter {
}

async replay(pollyRequest) {
const { config } = this.polly;
const { config } = pollyRequest;
const recordingEntry = await this.persister.findEntry(pollyRequest);

if (recordingEntry) {
await pollyRequest._emit('beforeReplay', recordingEntry);

if (this.shouldReRecord(recordingEntry)) {
if (this.shouldReRecord(pollyRequest, recordingEntry)) {
return this.record(pollyRequest);
}

Expand Down
39 changes: 21 additions & 18 deletions packages/@pollyjs/core/src/-private/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const FORMATTED_ACTIONS = {
export default class Logger {
constructor(polly) {
this.polly = polly;
this.recordingName = null;
this.groupName = null;
}

get enabled() {
Expand All @@ -30,40 +30,43 @@ export default class Logger {

console(method, ...args) {
if (this.enabled) {
this.groupStart();
this.groupStart(this.polly.recordingName);
console[method].apply(console, args);
}
}

groupStart() {
// If the recording name has changed, end the current group so a new one
groupStart(groupName) {
// If the provided groupName is different, end the current group so a new one
// can be started.
if (this.recordingName && this.recordingName !== this.polly.recordingName) {
if (this.groupName && this.groupName !== groupName) {
this.groupEnd();
this.recordingName = null;
this.groupName = null;
}

// Create a new console group for the current recording name if one
// Create a new console group for the provided groupName if one
// doesn't already exist.
if (!this.recordingName) {
this.recordingName = this.polly.recordingName;
console.group(this.recordingName);
if (!this.groupName) {
this.groupName = groupName;
console.group(this.groupName);
}
}

groupEnd() {
if (this.recordingName) {
console.groupEnd(this.recordingName);
if (this.groupName) {
console.groupEnd(this.groupName);
}
}

logRequest(request) {
this.log(
`${FORMATTED_ACTIONS[request.action]}${request.method} ${
request.url
} ${request.response.statusCode}${request.responseTime}ms`,
request
);
if (request.config.logging) {
this.groupStart(request.recordingName);
console.log(
`${FORMATTED_ACTIONS[request.action]}${request.method} ${
request.url
} ${request.response.statusCode}${request.responseTime}ms`,
request
);
}
}

log() {
Expand Down
37 changes: 32 additions & 5 deletions packages/@pollyjs/core/src/-private/request.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import md5 from 'blueimp-md5';
import stringify from 'fast-json-stable-stringify';
import mergeOptions from 'merge-options';
import PollyResponse from './response';
import NormalizeRequest from '../utils/normalize-request';
import parseUrl from '../utils/parse-url';
import serializeRequestBody from '../utils/serialize-request-body';
import guidForRecording from '../utils/guid-for-recording';
import defer from '../utils/deferred-promise';
import isAbsoluteUrl from 'is-absolute-url';
import { URL, assert, timestamp } from '@pollyjs/utils';
import HTTPBase from './http-base';
import { URL, assert, timestamp } from '@pollyjs/utils';
import {
validateRecordingName,
validateRequestConfig
} from '../utils/validators';

const { keys, freeze } = Object;

Expand Down Expand Up @@ -41,6 +47,16 @@ export default class PollyRequest extends HTTPBase {

// Lookup the associated route for this request
this[ROUTE] = polly.server.lookup(this.method, this.url);

// Handle config overrides defined by the route
this._configure(this[ROUTE].config());

// Handle recording name override defined by the route
const recordingName = this[ROUTE].recordingName();

if (recordingName) {
this._overrideRecordingName(recordingName);
}
}

get url() {
Expand Down Expand Up @@ -96,11 +112,11 @@ export default class PollyRequest extends HTTPBase {
}

get shouldPassthrough() {
return this[ROUTE].handler.get('passthrough') === true;
return this[ROUTE].shouldPassthrough();
}

get shouldIntercept() {
return typeof this[ROUTE].handler.get('intercept') === 'function';
return this[ROUTE].shouldIntercept();
}

async setup() {
Expand Down Expand Up @@ -158,6 +174,17 @@ export default class PollyRequest extends HTTPBase {
return serializeRequestBody(this.body);
}

_overrideRecordingName(recordingName) {
validateRecordingName(recordingName);
this.recordingName = recordingName;
this.recordingId = guidForRecording(recordingName);
}

_configure(config) {
validateRequestConfig(config);
this.config = mergeOptions(this[POLLY].config, this.config || {}, config);
}

_intercept() {
return this[ROUTE].intercept(this, this.response, ...arguments);
}
Expand All @@ -168,8 +195,8 @@ export default class PollyRequest extends HTTPBase {

_identify() {
const polly = this[POLLY];
const { _requests: requests, config } = polly;
const { matchRequestsBy } = config;
const { _requests: requests } = polly;
const { matchRequestsBy } = this.config;
const identifiers = {};

// Iterate through each normalizer
Expand Down
2 changes: 1 addition & 1 deletion packages/@pollyjs/core/src/-private/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ export default class PollyResponse extends HTTPBase {
this.status(status);
this.type('text/plain');

return this.send(status);
return this.send(this.statusText);
}
}
6 changes: 3 additions & 3 deletions packages/@pollyjs/core/src/defaults/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export default {
adapters: [],
adapterOptions: {},

persister: null,
persisterOptions: {},

logging: false,

recordIfMissing: true,
Expand All @@ -16,9 +19,6 @@ export default {
expiresIn: null,
timing: Timing.fixed(0),

persister: null,
persisterOptions: {},

matchRequestsBy: {
method: true,
headers: true,
Expand Down
Loading

0 comments on commit 0f32d9b

Please sign in to comment.