Skip to content

Commit

Permalink
♻️ refactoring code under the hood
Browse files Browse the repository at this point in the history
  • Loading branch information
francisashley committed Dec 16, 2019
1 parent e87d594 commit 6189634
Show file tree
Hide file tree
Showing 14 changed files with 345 additions and 298 deletions.
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,14 @@
"crel": "^4.2.0",
"crelns": "^1.0.1",
"lodash": "^4.17.15"
},
"jest": {
"moduleFileExtensions": [
"js"
],
"moduleDirectories": [
"node_modules",
"<rootDir>"
]
}
}
18 changes: 12 additions & 6 deletions src/features/action-bar/action-bar.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import ReloadButton from "../action-bar/reload-button";
import TrayButton from "../action-bar/tray-button";
import ReloadButton from "src/features/action-bar/reload-button";
import TrayButton from "src/features/action-bar/tray-button";
import crel from "crel";

export default function ActionBar({
actions = [],
corner,
showReload,
showTray,
shouldRefreshCache,
trayIsOpen,
onToggleTray = () => {}
Expand All @@ -15,7 +14,14 @@ export default function ActionBar({
return crel(
"div",
{ id: "mde-action-bar", "data-corner": corner },
showReload ? ReloadButton({ onClick: () => location.reload(shouldRefreshCache) }) : null,
showTray ? TrayButton({ isActive: trayIsOpen, onClick: onToggleTray }) : null
...actions.map(action => {
if (action === "reload") {
return ReloadButton({ onClick: () => location.reload(shouldRefreshCache) });
}
if (action === "toggle-tray") {
return TrayButton({ isActive: trayIsOpen, onClick: onToggleTray });
}
return null;
})
);
}
14 changes: 7 additions & 7 deletions src/features/action-bar/action-bar.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,31 @@ test("ActionBar renders properly", () => {
});

test("ActionBar shows reload button", () => {
const actionBar = ActionBar({ showReload: true });
const actionBar = ActionBar({ actions: ["reload"] });

expect(!!actionBar.querySelector("#mde-reload")).toBe(true);
});

test("ActionBar shows tray button", () => {
const actionBar = ActionBar({ showTray: true });
const actionBar = ActionBar({ actions: ["toggle-tray"] });

expect(!!actionBar.querySelector("#mde-toggle-tray")).toBe(true);
});

test("ActionBar tray button displays with `.active` class", () => {
const actionBar = ActionBar({ showTray: true, trayIsOpen: true });
const actionBar = ActionBar({ actions: ["toggle-tray"], trayIsOpen: true });

expect(!!actionBar.querySelector("#mde-toggle-tray.active")).toBe(true);
});

test("ActionBar tray button displays without `.active` class", () => {
const actionBar = ActionBar({ showTray: true });
const actionBar = ActionBar({ actions: ["toggle-tray"] });

expect(!!actionBar.querySelector("#mde-toggle-tray.active")).toBe(false);
});

test("ActionBar reloads page when ReloadButton clicked", () => {
const actionBar = ActionBar({ showReload: true });
const actionBar = ActionBar({ actions: ["reload"] });
delete window.location;
const reloadMock = jest.fn();
window.location = { reload: reloadMock };
Expand All @@ -45,7 +45,7 @@ test("ActionBar reloads page when ReloadButton clicked", () => {
});

test("ActionBar reloads page and cache when ReloadButton clicked", () => {
const actionBar = ActionBar({ showReload: true, shouldRefreshCache: true });
const actionBar = ActionBar({ actions: ["reload"], shouldRefreshCache: true });
delete window.location;
const reloadMock = jest.fn();
window.location = { reload: reloadMock };
Expand All @@ -58,7 +58,7 @@ test("ActionBar reloads page and cache when ReloadButton clicked", () => {

test("ActionBar calls onToggleTray", () => {
const onToggleTray = jest.fn();
const actionBar = ActionBar({ showTray: true, onToggleTray });
const actionBar = ActionBar({ actions: ["toggle-tray"], onToggleTray });

actionBar.querySelector("#mde-toggle-tray").click();

Expand Down
2 changes: 1 addition & 1 deletion src/features/action-bar/reload-button.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import ReloadIcon from "../icons/reload";
import ReloadIcon from "src/features/icons/reload";
import crel from "crel";

export default function ReloadButton({ onClick = () => {} } = {}) {
Expand Down
2 changes: 1 addition & 1 deletion src/features/action-bar/tray-button.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import TrayIcon from "../icons/tray";
import TrayIcon from "src/features/icons/tray";
import classnames from "classnames";
import crel from "crel";

Expand Down
125 changes: 125 additions & 0 deletions src/features/app/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import ActionBar from "src/features/action-bar/action-bar";
import Tray from "src/features/tray/tray";
import crel from "crel";
import limitTrayHeight from "src/utils/limit-tray-height";
import stateHandler from "src/utils/state";
import tracer from "src/utils/tracer.js";

export default function App({ root, stateId, actions, actionsCorner, hardReload }) {
const state = stateHandler(stateId);

// Default tray height
let trayHeight = state.getCache("tray-height", window.innerHeight * 0.25);
trayHeight = limitTrayHeight(trayHeight, !!state.get("actions"));

// SET STATE

state.set("log", []);
state.set("actions", actions);
state.set("actions-corner", actionsCorner);
state.set("reload-action-should-refresh-cache", hardReload);
state.setCache("tray-open", state.getCache("tray-open", true));
state.setCache("tray-height", trayHeight);

/**
* ACTIONS
*/

function toggleTray() {
state.setCache("tray-open", !state.getCache("tray-open"));
render();
}

function resizeTray(offset) {
const height = limitTrayHeight(state.getCache("tray-height") + offset, !!state.get("actions"));

if (height !== state.getCache("tray-height")) {
state.setCache("tray-height", height);
render();
}
}

function addLogEntry({ message, filePath, fileName, lineNumber, type } = {}) {
const log = state.get("log");
const entry = { message, filePath, fileName, lineNumber, type, amount: 1 };
const lastEntry = log[log.length - 1];

if (lastEntry && lastEntry.message === message) {
lastEntry.amount = lastEntry.amount + 1;
log[log.length - 1] = lastEntry;
} else {
log.push(entry);
}

state.set("log", log);
render();
}

// In the event the window is resized
window.addEventListener("resize", () => {
resizeTray(state.getCache("tray-height"));
});

// Display logs
const log = console.log;
console.log = message => {
log(message);
const { filePath, fileName, lineNumber } = tracer(new Error());
addLogEntry({ message, filePath, fileName, lineNumber });
};
const error = console.error;
console.error = message => {
error(message);
const { filePath, fileName, lineNumber } = tracer(new Error());
addLogEntry({ message, filePath, fileName, lineNumber, type: "error" });
};
const assert = console.assert;
console.assert = (assertion, message) => {
assert(assertion, message);

if (!assertion) {
message =
"Assertion failed: " + (typeof message !== "undefined" ? message : "console.assert");
const { filePath, fileName, lineNumber } = tracer(new Error());
addLogEntry({ message, filePath, fileName, lineNumber, type: "error" });
}
};

// Display error messages
window.onerror = (message, filePath, lineNumber) => {
addLogEntry({ message, filePath, fileName: "", lineNumber, type: "error" });
};

// render

function render() {
root.innerHTML = "";

// render action bar
crel(
root,
ActionBar({
actions,
corner: state.get("actions-corner"),
shouldRefreshCache: state.get("reload-action-should-refresh-cache"),
trayIsOpen: state.getCache("tray-open"),
onToggleTray: toggleTray
})
);

// render tray
if (state.get("actions").includes("toggle-tray")) {
crel(
root,
Tray({
state,
trayIsOpen: state.getCache("tray-open"),
trayHeight: state.getCache("tray-height"),
log: state.get("log"),
onResizeTray: resizeTray
})
);
}
}
render();
}
74 changes: 74 additions & 0 deletions src/features/app/app.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import App from "./app";
import crel from "crel";

beforeEach(() => crel(document.body, crel("div", { id: "mde" })));
afterEach(() => document.getElementById("mde").remove());

const generateApp = options => {
return App({
root: document.getElementById("mde"),
stateId: "global",
actions: ["reload", "toggle-tray"],
actionsCorner: "tr",
hardReload: true,
...options
});
};

test("App renders without crashing", () => {
generateApp();

expect(!!document.getElementById("mde-action-bar")).toBe(true);
expect(!!document.getElementById("mde-tray")).toBe(true);
});

test("MDE console logs to tray", () => {
generateApp();

console.log("works");

expect(document.querySelectorAll(".mde-log[data-type=string]").length).toBe(1);
expect(document.querySelector(".mde-log .mde-log-message").innerHTML).toBe("works");

console.log("works");

expect(document.querySelector(".mde-log[data-type=string] .mde-log-amount").innerHTML).toBe("2");
});

test("MDE console errors to tray", () => {
generateApp();

console.error("works");

expect(document.querySelectorAll(".mde-log[data-type=error]").length).toBe(1);
expect(document.querySelector(".mde-log .mde-log-message").innerHTML).toBe("works");

console.error("works");

expect(document.querySelector(".mde-log[data-type=error] .mde-log-amount").innerHTML).toBe("2");
});

test("MDE console asserts to tray", () => {
generateApp();

console.assert(false, "works");

expect(document.querySelectorAll(".mde-log[data-type=error]").length).toBe(1);
expect(document.querySelector(".mde-log .mde-log-message").innerHTML).toBe(
"Assertion failed: works"
);

console.assert(false);

expect(document.querySelectorAll(".mde-log[data-type=error]").length).toBe(2);
expect(document.querySelectorAll(".mde-log .mde-log-message")[1].innerHTML).toBe(
"Assertion failed: console.assert"
);

console.assert(false);

expect(
document.querySelectorAll(".mde-log[data-type=error]")[1].querySelector(".mde-log-amount")
.innerHTML
).toBe("2");
});
37 changes: 37 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { defaultTo, isElement } from "lodash";

import app from "src/features/app/app";

(function() {
"use strict";

function mobileDevEnvironment({ root, stateId, actions, actionsCorner, hardReload } = {}) {
if (!isElement(root)) {
throw "Could not start MDE because MDE requires a `root` element to attach to the DOM.";
}

// DEFAULT VARIABLES
stateId = defaultTo(stateId, "global");
actions = defaultTo(actions, ["reload", "toggle-tray"]);
actionsCorner = defaultTo(actionsCorner, "tr");
hardReload = defaultTo(hardReload, true);

// RUN

app({
root,
stateId,
actions,
actionsCorner,
hardReload
});
}

// Enable usage in the browser
window.mobileDevEnvironment = mobileDevEnvironment;

// Enable usage in Node
if (typeof module === "object" && typeof module.exports === "object") {
module.exports = mobileDevEnvironment;
}
})();
File renamed without changes.
Loading

0 comments on commit 6189634

Please sign in to comment.