Skip to content

Commit

Permalink
Merge pull request Expensify#13961 from margelo/hanno-andrew-mock-api…
Browse files Browse the repository at this point in the history
…-responses

Mocking API responses (for CI/CD perf regression tests)
  • Loading branch information
tgolen authored Jan 5, 2023
2 parents 7ac39f0 + fdabd83 commit 64b9717
Show file tree
Hide file tree
Showing 9 changed files with 2,942 additions and 9 deletions.
17 changes: 17 additions & 0 deletions metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,32 @@

const {getDefaultConfig} = require('metro-config');
const _ = require('underscore');
require('dotenv').config();

/* eslint arrow-body-style: 0 */
module.exports = (() => {
const isUsingMockAPI = process.env.E2E_TESTING === 'true';
if (isUsingMockAPI) {
// eslint-disable-next-line no-console
console.warn('⚠️ Using mock API');
}

return getDefaultConfig()
.then((config) => {
return {
resolver: {
assetExts: _.filter(config.resolver.assetExts, ext => ext !== 'svg'),
sourceExts: ['jsx', 'js', 'ts', 'tsx', 'json', 'svg'],
resolveRequest: (context, moduleName, platform) => {
const resolution = context.resolveRequest(context, moduleName, platform);
if (isUsingMockAPI && moduleName.includes('/API')) {
return {
...resolution,
filePath: resolution.filePath.replace(/src\/libs\/API.js/, 'src/libs/E2E/API.mock.js'),
};
}
return resolution;
},
},
transformer: {
getTransformOptions: () => ({
Expand Down
35 changes: 27 additions & 8 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
"babel-polyfill": "^6.26.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
"dotenv": "^8.2.0",
"expensify-common": "git+https://github.com/Expensify/expensify-common.git#e67235baa887dcbe9dc4bf41ddf1925f19a1e8ad",
"fbjs": "^3.0.2",
"file-loader": "^6.0.0",
Expand Down Expand Up @@ -162,6 +161,7 @@
"copy-webpack-plugin": "^6.4.1",
"css-loader": "^5.2.4",
"diff-so-fancy": "^1.3.0",
"dotenv": "^16.0.3",
"electron": "^21.2.2",
"electron-builder": "23.5.0",
"electron-notarize": "^1.2.1",
Expand Down
95 changes: 95 additions & 0 deletions src/libs/E2E/API.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* eslint-disable rulesdir/no-api-in-views */
import _ from 'underscore';
import Onyx from 'react-native-onyx';
import Log from '../Log';

/**
* A dictionary which has the name of a API command as key, and a function which
* receives the api command parameters as value and is expected to return a response
* object.
*/
const mocks = {
BeginSignIn: ({email}) => {
const response = require('../E2E/apiMocks/beginSignin.json');
response.onyxData.forEach((data) => {
if (data.key !== 'credentials') {
return;
}
// eslint-disable-next-line no-param-reassign
data.value.login = email;
});
return response;
},
SigninUser: ({email}) => {
const response = require('../E2E/apiMocks/signinUser.json');
response.onyxData.forEach((data) => {
if (data.key !== 'session') {
return;
}
// eslint-disable-next-line no-param-reassign
data.value.email = email;
});
return response;
},
OpenApp: () => require('../E2E/apiMocks/openApp.json'),
OpenReport: () => require('../E2E/apiMocks/openReport.json'),
AuthenticatePusher: () => require('../E2E/apiMocks/authenticatePusher.json'),
};

function mockCall(command, apiCommandParameters, tag) {
const mockResponse = mocks[command] && mocks[command](apiCommandParameters);
if (!mockResponse || !_.isArray(mockResponse.onyxData)) {
Log.warn(`[${tag}] for command ${command} is not mocked yet!`);
return;
}

return Onyx.update(mockResponse.onyxData);
}

/**
* All calls to API.write() will be persisted to disk as JSON with the params, successData, and failureData.
* This is so that if the network is unavailable or the app is closed, we can send the WRITE request later.
*
* @param {String} command - Name of API command to call.
* @param {Object} apiCommandParameters - Parameters to send to the API.
*
* @returns {Promise}
*/
function write(command, apiCommandParameters = {}) {
return mockCall(command, apiCommandParameters, 'API.write');
}

/**
* For commands where the network response must be accessed directly or when there is functionality that can only
* happen once the request is finished (eg. calling third-party services like Onfido and Plaid, redirecting a user
* depending on the response data, etc.).
* It works just like API.read(), except that it will return a promise.
* Using this method is discouraged and will throw an ESLint error. Use it sparingly and only when all other alternatives have been exhausted.
* It is best to discuss it in Slack anytime you are tempted to use this method.
*
* @param {String} command - Name of API command to call.
* @param {Object} apiCommandParameters - Parameters to send to the API.
*
* @returns {Promise}
*/
function makeRequestWithSideEffects(command, apiCommandParameters = {}) {
return mockCall(command, apiCommandParameters, 'API.makeRequestWithSideEffects');
}

/**
* Requests made with this method are not be persisted to disk. If there is no network connectivity, the request is ignored and discarded.
*
* @param {String} command - Name of API command to call.
* @param {Object} apiCommandParameters - Parameters to send to the API.
*
* @returns {Promise}
*/
function read(command, apiCommandParameters) {
return mockCall(command, apiCommandParameters, 'API.read');
}

export {
write,
makeRequestWithSideEffects,
read,
};
6 changes: 6 additions & 0 deletions src/libs/E2E/apiMocks/authenticatePusher.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"auth": "auth",
"shared_secret": "secret",
"jsonCode": 200,
"requestID": "783ef7fc3991969a-SJC"
}
27 changes: 27 additions & 0 deletions src/libs/E2E/apiMocks/beginSignin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"onyxData": [
{
"onyxMethod": "merge",
"key": "credentials",
"value": {
"login": "thisemailwillgetreplaced@duringsign.com"
}
},
{
"onyxMethod": "merge",
"key": "account",
"value": {
"validated": true
}
},
{
"onyxMethod": "set",
"key": "betas",
"value": [
"passwordless"
]
}
],
"jsonCode": 200,
"requestID": "783e54ef4b38cff5-SJC"
}
Loading

0 comments on commit 64b9717

Please sign in to comment.