Skip to content

Commit

Permalink
feat: 🎸 make client options configurable
Browse files Browse the repository at this point in the history
enable parallel execution possible by setting the cookie
  • Loading branch information
mdasberg committed Jul 9, 2020
1 parent c62b7ab commit fc799e3
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 53 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ Use **NG_API_MOCK_BASE_URL** with a string value of base url of your ng-apimock
```json
{
"env": {
"NG_API_MOCK_BASE_IDENTIFIER": "my-identifier", // optional: defaults to apimockId (the cookie identifier)
"NG_API_MOCK_BASE_URL": "http://localhost:3000",
"NG_API_MOCK_BASE_PATH": "myapimock", // optional: defaults to ngapimock (path on which ngapimock listens)
"NG_API_MOCK_ENABLE_LOGS": "false"
}
}
Expand All @@ -36,6 +38,11 @@ describe('Some test', () => {
### Available plugin functions
The following functions are available. Each plugin function returns a promise.

initializeNgApimock
##### initializeNgApimock(): Promise<any>;
Initializes apimock for concurrent testing. (sets a cookie)
[@ng-apimock/core](https://github.com/ng-apimock/core) uses a cookie to make sure that parallel tests don't intervene with each other).

##### selectScenario(name: string, scenario: string): Promise<any>;
Selects the given scenario (when calling this function without a scenario or with 'passThrough' as scenario name, the call will be passed through to the actual backend).

Expand Down
134 changes: 110 additions & 24 deletions src/cypress.plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,36 +37,82 @@ describe('CypressPlugin', () => {
});

describe('constructor', () => {
it('sets the baseUrl', () =>
expect(plugin.baseUrl).toBe('http://localhost:9000/ngapimock'));
describe('defaults', () => {
beforeEach(()=> {
(global as any)['Cypress'].env = (envName: string) => {
const envVars: { [key: string]: string } = {
'NG_API_MOCK_BASE_URL': 'http://localhost:9000'
};
return envVars[envName];
};
plugin = new CypressPlugin();
});

it('sets the logging option', () =>
expect(plugin.isLogsEnabled).toBe(false));
it('sets the apimock id', () => expect(plugin.ngApimockId).toBeDefined());

it('uses default logging option', () => {
(global as any)['Cypress'].env = (envName: string) => {
const envVars: { [key: string]: string } = {
'NG_API_MOCK_BASE_URL': 'http://localhost:9000'
};
return envVars[envName];
};
plugin = new CypressPlugin();
expect(plugin.isLogsEnabled).toBe(true);
it('sets the baseUrl', () =>
expect(plugin.baseUrl).toBe('http://localhost:9000/ngapimock'));

it('sets the logging option', () =>
expect(plugin.isLogsEnabled).toBe(true));

it('sets the https agent', () => expect((plugin as any).agent).toBeDefined());
});

it('throws on the wrong logging option', () => {
(global as any)['Cypress'].env = (envName: string) => {
const envVars: { [key: string]: string } = {
'NG_API_MOCK_BASE_URL': 'http://localhost:9000',
'NG_API_MOCK_ENABLE_LOGS': "fail"
describe('overrides', () => {
beforeEach(()=> {
(global as any)['Cypress'].env = (envName: string) => {
const envVars: { [key: string]: any } = {
'NG_API_MOCK_BASE_URL': 'http://localhost:9000',
'NG_API_MOCK_ENABLE_LOGS': false,
'NG_API_MOCK_BASE_PATH': 'myapimock'
};
return envVars[envName];
};
plugin = new CypressPlugin();
});

it('sets the apimock id', () => expect(plugin.ngApimockId).toBeDefined());

it('sets the baseUrl', () =>
expect(plugin.baseUrl).toBe('http://localhost:9000/myapimock'));

it('sets the logging option', () =>
expect(plugin.isLogsEnabled).toBe(false));

it('uses default logging option', () => {
(global as any)['Cypress'].env = (envName: string) => {
const envVars: { [key: string]: string } = {
'NG_API_MOCK_BASE_URL': 'http://localhost:9000'
};
return envVars[envName];
};
return envVars[envName];
};
try {
plugin = new CypressPlugin();
} catch (error) {
expect(error.message).toBe('Unexpected value for NG_API_MOCK_ENABLE_LOGS env var, please provide string value: "true" or "false"');
}
expect(plugin.isLogsEnabled).toBe(true);
});

it('sets the https agent', () => expect((plugin as any).agent).toBeDefined());
});

describe('invalid', () => {
beforeEach(()=> {
(global as any)['Cypress'].env = (envName: string) => {
const envVars: { [key: string]: any } = {
'NG_API_MOCK_BASE_URL': 'http://localhost:9000',
'NG_API_MOCK_ENABLE_LOGS': 'fail'
};
return envVars[envName];
};
});

it('throws on the wrong logging option', () => {
try {
plugin = new CypressPlugin();
fail();
} catch (error) {
expect(error.message).toBe('Unexpected value for NG_API_MOCK_ENABLE_LOGS env var, please provide string value: `true` or `false`');
}
});
});
});

Expand Down Expand Up @@ -362,6 +408,46 @@ describe('CypressPlugin', () => {
});
});

describe('setNgApimockCookie', () => {
describe('defaults', () => {
beforeEach(async () => {
requestFn.mockResolvedValue(Promise.resolve());
setCookieFn.mockResolvedValue(Promise.resolve());

await plugin.setNgApimockCookie();
});

it('opens the init url', () => expect(requestFn).toHaveBeenCalledWith('http://localhost:9000/ngapimock/init'));

it('sets the cookie', () => expect(setCookieFn).toHaveBeenCalledWith('apimockid', plugin.ngApimockId));
});

describe('override', () => {
beforeEach(async () => {
requestFn.mockResolvedValue(Promise.resolve());
setCookieFn.mockResolvedValue(Promise.resolve());

(global as any)['Cypress'].env = (envName: string) => {
const envVars: { [key: string]: any } = {
'NG_API_MOCK_BASE_IDENTIFIER': 'awesomemock',
'NG_API_MOCK_BASE_URL': 'http://localhost:9000',
'NG_API_MOCK_BASE_PATH': 'myapimock'
};
return envVars[envName];
};

plugin = new CypressPlugin();
plugin.ngApimockId = '123';

await plugin.setNgApimockCookie();
});

it('opens the init url', () => expect(requestFn).toHaveBeenCalledWith('http://localhost:9000/myapimock/init'));

it('sets the cookie', () => expect(setCookieFn).toHaveBeenCalledWith('awesomemock', plugin.ngApimockId));
});
});

describe('setVariable', () => {
let setVariablesFn: jest.Mock;

Expand Down
74 changes: 49 additions & 25 deletions src/cypress.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
import {Client} from '@ng-apimock/base-client';
import urljoin = require('url-join');
import {Client, Configuration, DefaultConfiguration} from '@ng-apimock/base-client';
import {RequestObject} from './request.object';
import * as https from 'https';
import * as uuid from 'uuid';
import urljoin = require('url-join');

/** Cypress plugin for ng-apimock. */
export class CypressPlugin implements Client {
public ngApimockId: string;
public baseUrl: string;
public isLogsEnabled = true;
public isLogsEnabled:boolean = true;
private agent: https.Agent;
private configuration: Configuration;

/**
* Constructor.
* @param {CypressPluginOptions} options The options.
*/
/** Constructor. */
constructor() {
this.baseUrl = urljoin(Cypress.env('NG_API_MOCK_BASE_URL'), 'ngapimock');
this.ngApimockId = uuid.v4();

this.configuration = {
...JSON.parse(JSON.stringify({
identifier: Cypress.env('NG_API_MOCK_BASE_IDENTIFIER') || 'apimockid',
baseUrl: Cypress.env('NG_API_MOCK_BASE_URL'),
basePath: Cypress.env('NG_API_MOCK_BASE_PATH') || '/ngapimock'
}))
};

this.baseUrl = urljoin(this.configuration.baseUrl, this.configuration.basePath);

if (Cypress.env('NG_API_MOCK_ENABLE_LOGS') != null) {
try {
this.isLogsEnabled = JSON.parse(Cypress.env('NG_API_MOCK_ENABLE_LOGS'));
} catch(e) {
throw Error('Unexpected value for NG_API_MOCK_ENABLE_LOGS env var, please provide string value: "true" or "false"');
this.isLogsEnabled = Boolean(JSON.parse(Cypress.env('NG_API_MOCK_ENABLE_LOGS')));
} catch (e) {
throw Error('Unexpected value for NG_API_MOCK_ENABLE_LOGS env var, please provide string value: `true` or `false`');
}
}

Expand Down Expand Up @@ -84,6 +94,7 @@ export class CypressPlugin implements Client {
url: url,
log: this.isLogsEnabled,
headers: {
Cookie: `${this.configuration.identifier}=${this.ngApimockId}`,
'Content-Type': 'application/json'
}
};
Expand Down Expand Up @@ -148,23 +159,36 @@ export class CypressPlugin implements Client {
.then(cy.wrap);
}

/**
* Sets the apimock cookie.
* @return {Promise} promise The promise.
*/
setNgApimockCookie(): Promise<any> {
return new Cypress.Promise((resolve, reject) => {
cy.request(urljoin(this.baseUrl, 'init'))
.then(() => cy.setCookie(this.configuration.identifier, this.ngApimockId))
.then(()=> resolve());
});
}

// Origin: https://github.com/NicholasBoll/cypress-promise/blob/master/index.js
private promisify(chain: any) {
return new Cypress.Promise((resolve, reject) => {
// We must subscribe to failures and bail. Without this, the Cypress runner would never stop
Cypress.on('fail', rejectPromise);

// // unsubscribe from test failure on both success and failure. This cleanup is essential
function resolvePromise(value: any) {
resolve(value);
Cypress.off('fail', rejectPromise);
}
function rejectPromise(error: any) {
reject(error);
Cypress.off('fail', rejectPromise);
}

chain.then(resolvePromise);
// We must subscribe to failures and bail. Without this, the Cypress runner would never stop
Cypress.on('fail', rejectPromise);

// // unsubscribe from test failure on both success and failure. This cleanup is essential
function resolvePromise(value: any) {
resolve(value);
Cypress.off('fail', rejectPromise);
}

function rejectPromise(error: any) {
reject(error);
Cypress.off('fail', rejectPromise);
}

chain.then(resolvePromise);
});
}
}
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ function load() {
plugin.getVariables();
});

Cypress.Commands.add("initializeNgApimock", () => {
plugin.setNgApimockCookie();
});

Cypress.Commands.add("recordRequests", (record: boolean) => {
plugin.recordRequests(record);
});
Expand Down
2 changes: 1 addition & 1 deletion src/request.object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export interface RequestObject {

/** Request headers. */
export interface RequestHeaders {
[key: string]: string;
[key: string]: any;
}
7 changes: 4 additions & 3 deletions test/step_definitions/client.steps.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {Given, When} from "cypress-cucumber-preprocessor/steps";
import {expect} from "chai";
import { Given, When } from 'cypress-cucumber-preprocessor/steps';
import { expect } from 'chai';

Given(/^ng-apimock has been initialized$/, () => cy.resetMocksToDefault());
Given(/^ng-apimock has been initialized$/, () => cy.initializeNgApimock()
.then(() => cy.resetMocksToDefault()));

Given(/^the following mocks state:$/, dataTable => cy
.then(() => {
Expand Down

0 comments on commit fc799e3

Please sign in to comment.