Skip to content

Commit

Permalink
feat: use fake post() instead of fetch()
Browse files Browse the repository at this point in the history
  • Loading branch information
FutureDuck authored and lfilho committed Jun 15, 2020
1 parent 67d7b72 commit eb05825
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 27 deletions.
8 changes: 7 additions & 1 deletion src/background/request_listener.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import RequestMatcher from './request_matcher.js';
import MetricService from '../shared/metric_service.js';
import Metric from '../shared/model/metric.js';
import Logger from '../shared/util/logger.js';

export default async function requestListener(requestDetails) {
const url = requestDetails.url;
Expand All @@ -9,7 +10,12 @@ export default async function requestListener(requestDetails) {

if (isUrlDenied) {
const metric = new Metric(Metric.dimensions.REQUEST_BLOCKED, url);
await MetricService.emit(metric);
try {
const response = await MetricService.emit(metric);
Logger.debug(`Metric sent! Server returned status: ${response.status}`);
} catch (error) {
Logger.error(error);
}
}

return blockingReponse;
Expand Down
28 changes: 6 additions & 22 deletions src/shared/metric_service.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,33 @@
import Metric from './model/metric.js';
import fetch from './util/fake_fetch.js';
import { post } from './util/fake_fetch.js';
import { METRIC_ENDPOINT } from './config.js';
import Logger from './util/logger.js';
import {
InvalidMetricTypeError,
ErrorSendingMetric,
} from '../shared/model/error.js';
import { InvalidMetricTypeError } from '../shared/model/error.js';

export default class MetricService {
static async emit(metric) {
static emit(metric) {
if (!(metric instanceof Metric)) {
throw new InvalidMetricTypeError();
}

const metricPayload = getMetricPayload(metric);
const metricJson = getMetricJson(metricPayload);
const metricString = `${metric.dimension}=${metric.value}`;

// Here we would make a `fetch` request to our metric service
// For now, let's just log mimic an async request
return fetch(metricJson)
.then((response) => {
Logger.debug(`Metric sent! Server returned status: ${response.status}`);
Logger.info(metricString);
})
.catch((error) => {
Logger.error(new ErrorSendingMetric(error));
});
Logger.debug(`Sending metric: ${metricString}`);
return post(METRIC_ENDPOINT, metricPayload);
}
}

// when are private fields and methods coming? :-(
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields

function getMetricPayload(metric) {
const timestamp = new Date().toISOString();

const payload = {
timestamp,
dimension: metric.dimension,
value: metric.value,
};

return payload;
}

function getMetricJson(payload) {
return JSON.stringify(payload);
}
4 changes: 2 additions & 2 deletions src/shared/model/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export class InvalidMetricTypeError extends DDGError {
message = t('Invalid metric. Metric must be an instance of Metric');
}

export class ErrorSendingMetric extends DDGError {
message = t('Error while sending metric. Did you pay your internet bill?');
export class RequestSendingError extends DDGError {
message = t('Error sending your message. Did you pay your internet bill?');
}

export class MetricInitializationError extends DDGError {
Expand Down
29 changes: 27 additions & 2 deletions src/shared/util/fake_fetch.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
import { FEEDBACK_ENDPOINT } from '../config.js';
import { RequestSendingError } from '../model/error.js';

export function post(url, payload) {
const timestamp = new Date().toISOString();
const timestampedPayload = { ...payload, timestamp };

return fetch(url, {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'application/json' },
redirect: 'follow',
referrerPolicy: 'no-referrer',
body: JSON.stringify(timestampedPayload),
});
}

// A simple `fetch` mock so we can unit test via node without extra dependencies
// With some hardcoded logic just to help with local manual testing ;-)
// After using a isomorphic fetch library + snowpack/webpack we can unmock this function
function fetch(url, payload) {
const success = Promise.resolve({ status: 200 });
const fail = Promise.reject(new RequestSendingError({ status: 400 }));

export default async function fetch() {
return Promise.resolve({ status: 200 });
if (url === FEEDBACK_ENDPOINT) {
const feedback = JSON.parse(payload.body).feedback;
return feedback === 'fail' ? fail : success;
}
return success;
}

0 comments on commit eb05825

Please sign in to comment.