Skip to content

Commit

Permalink
Add some basic tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pcboy committed Jan 28, 2021
1 parent c84d6cd commit 6c36913
Show file tree
Hide file tree
Showing 16 changed files with 2,789 additions and 174 deletions.
2 changes: 2 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"mobx-deep-action",
"emotion",
"@babel/plugin-transform-runtime",
"@babel/plugin-transform-typescript",
"babel-plugin-styled-components",
"lodash",
[
"babel-plugin-closure-elimination",
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ jobs:
uses: actions/checkout@v2
with:
persist-credentials: false

- name: Install and Build
- name: Install, Test, and Build
run: |
yarn install
yarn test
yarn build
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@f8bad71bf44bc9e98b4f1a7cc52ff005129068f6
if: github.ref == 'refs/heads/master'
with:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
Expand Down
14 changes: 9 additions & 5 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React, { Component } from "react";
import ReactDOM from "react-dom";

import { Component } from "react";
import * as React from "react";
import Calculator from "./components/Calculator";
import { CalcStoreContext } from "./stores/CalculatorStore";

const App = () => <Calculator />;
const App = ({ store }: { store: any }) => (
<CalcStoreContext.Provider value={store}>
<Calculator />
</CalcStoreContext.Provider>
);

ReactDOM.render(<App />, document.getElementById("root"));
export default App;
126 changes: 126 additions & 0 deletions __tests__/Calculator.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import * as React from "react";
import { mount } from "enzyme";
import Calculator from "../components/Calculator";
import calculatorStore, { CalculatorStore } from "../stores/CalculatorStore";
import { getSnapshot } from "mobx-state-tree";
import App from "../App";

describe("Calculator", () => {
let store: ReturnType<typeof CalculatorStore.create>;
beforeEach(() => {
store = CalculatorStore.create({
recipeName: "Bread Baking Calculator",
flours: [{ name: "Bread Flour", dosage: 100 }],
ingredients: [{ name: "Salt", dosage: 3 }],
waterPerc: 75,
totalWeight: 800,
starterPerc: 20,
starterFlourIndex: 0,
});
});

it("renders without crashing", () => {
const app = mount(<App store={store} />);

expect(app.find({ "data-testid": "recipeName" }).text()).toEqual(
store.recipeName
);
});

it("can add other flours", () => {
const app = mount(<App store={store} />);

app
.find({ "data-testid": "addAnotherFlour" })
.find("button")
.simulate("click");

expect(store.flours.length).toBe(2);
expect(app.find({ "data-testid": "flour" }).length).toEqual(
store.flours.length
);
});

it("can add other ingredients", () => {
const app = mount(<App store={store} />);

app
.find({ "data-testid": "addIngredient" })
.find("button")
.simulate("click");

expect(store.ingredients.length).toBe(2);

expect(app.find({ "data-testid": "ingredient" }).length).toEqual(
store.ingredients.length
);
});

it("flours grams are recomputed properly", () => {
const localStore = CalculatorStore.create({
recipeName: "Bread Baking Calculator",
flours: [{ name: "Bread Flour", dosage: 100 }],
ingredients: [{ name: "Salt", dosage: 3 }],
waterPerc: 75,
totalWeight: 800,
starterPerc: 20,
starterFlourIndex: 0,
});

const app = mount(<App store={localStore} />);

app
.find({ "data-testid": "addAnotherFlour" })
.find("button")
.simulate("click");

const previousValue = localStore.flourWeight(
0,
localStore.flours[0].dosage
);
localStore.replaceFlour(1, { name: "testFlour", dosage: 60 });

expect(localStore.flours.length).toEqual(2);
expect(localStore.flourWeight(0, localStore.flours[0].dosage)).toBeLessThan(
previousValue
);

localStore.removeFlour(1);
expect(localStore.flourWeight(0, localStore.flours[0].dosage)).toEqual(
previousValue
);

localStore.addIngredient();
localStore.replaceIngredient(1, { name: "ingredient1", dosage: 2 });
expect(localStore.flourWeight(0, localStore.flours[0].dosage)).toBeLessThan(
previousValue
);
});

it("Can reflect the used flours in the levain selection", () => {
const localStore = CalculatorStore.create({
recipeName: "Bread Baking Calculator",
flours: [
{ name: "Bread Flour", dosage: 100 },
{ name: "Whole wheat", dosage: 10 },
],
ingredients: [{ name: "Salt", dosage: 3 }],
waterPerc: 75,
totalWeight: 800,
starterPerc: 20,
starterFlourIndex: 0,
});

const app = mount(<App store={localStore} />);

const options = app
.find({ "data-testid": "starterFlourSelect" })
.find("option");

expect(options.length).toEqual(2);
expect(options.map((x) => x.text())).toEqual([
"Bread Flour",
"Whole wheat",
]);
});
});
26 changes: 16 additions & 10 deletions components/Calculator/Flours.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@ import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";

import { observer } from "mobx-react";
import ContentEditable from "react-contenteditable";
import { calculatorStore } from "../../stores/CalculatorStore";
import { CalcStoreContext } from "../../stores/CalculatorStore";
import { sanitizedNumber, sanitizedString, AddButton } from "./Utils";

export const Flours = observer(() => {
const calcstore = React.useContext(CalcStoreContext);

return (
<div className="columns is-multiline is-mobile">
{calculatorStore.flours.map((ingredient, index) => (
{calcstore.flours.map((ingredient, index) => (
<React.Fragment key={`flour_${index}`}>
<div className="column is-half" style={{ position: "relative" }}>
<div
className="column is-half"
style={{ position: "relative" }}
data-testid="flour"
>
{index != 0 && (
<IconButton
aria-label="delete"
Expand All @@ -24,7 +30,7 @@ export const Flours = observer(() => {
left: "-2rem",
marginTop: "0.4rem",
}}
onClick={() => calculatorStore.removeFlour(index)}
onClick={() => calcstore.removeFlour(index)}
>
<RemoveCircleIcon fontSize="inherit" />
</IconButton>
Expand All @@ -35,22 +41,23 @@ export const Flours = observer(() => {
disabled={false}
onChange={(e) => {
const ingr = sanitizedString(e);
calculatorStore.replaceFlour(index, {
calcstore.replaceFlour(index, {
name: ingr,
dosage: ingredient.dosage,
});
}}
/>
</div>
<div className="column is-half">
<div className="column is-half" data-testid="flourValue">
<Input
type="number"
style={{ width: "100%" }}
value={ingredient.dosage}
onClick={(e) => (e.target as HTMLInputElement)?.select()}
onChange={(e) => {
const num = sanitizedNumber(e);
calculatorStore.replaceFlour(index, {

calcstore.replaceFlour(index, {
name: ingredient.name,
dosage: num,
});
Expand All @@ -59,14 +66,13 @@ export const Flours = observer(() => {
/>

<div className="weight">
{calculatorStore.flourWeight(index, ingredient.dosage)}{" "}
grams
{calcstore.flourWeight(index, ingredient.dosage)} grams
</div>
</div>
</React.Fragment>
))}
<div className="column is-12 has-text-centered">
<AddButton onClick={() => calculatorStore.addFlour()}>
<AddButton data-testid="addAnotherFlour" onClick={() => calcstore.addFlour()}>
<AddCircleIcon style={{ marginRight: ".5rem" }} />
Add Another Flour
</AddButton>
Expand Down
25 changes: 17 additions & 8 deletions components/Calculator/Ingredients.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@ import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";
import { observer } from "mobx-react";
import ContentEditable from "react-contenteditable";

import { calculatorStore } from "../../stores/CalculatorStore";
import { CalcStoreContext } from "../../stores/CalculatorStore";

import { sanitizedNumber, sanitizedString, AddButton } from "./Utils";

export const Ingredients = observer(() => {
const calcstore = React.useContext(CalcStoreContext);

return (
<div className="columns is-multiline is-mobile">
{calculatorStore.ingredients.map((ingredient, index) => (
{calcstore.ingredients.map((ingredient, index) => (
<React.Fragment key={`ingredient_${index}`}>
<div className="column is-half" style={{ position: "relative" }}>
<div
data-testid="ingredient"
className="column is-half"
style={{ position: "relative" }}
>
{index != 0 && (
<IconButton
aria-label="delete"
Expand All @@ -24,7 +30,7 @@ export const Ingredients = observer(() => {
left: "-2rem",
marginTop: "0.4rem",
}}
onClick={() => calculatorStore.removeIngredient(index)}
onClick={() => calcstore.removeIngredient(index)}
>
<RemoveCircleIcon fontSize="inherit" />
</IconButton>
Expand All @@ -35,7 +41,7 @@ export const Ingredients = observer(() => {
disabled={false}
onChange={(e) => {
const ingr = sanitizedString(e);
calculatorStore.replaceIngredient(index, {
calcstore.replaceIngredient(index, {
name: ingr,
dosage: ingredient.dosage,
});
Expand All @@ -50,21 +56,24 @@ export const Ingredients = observer(() => {
onClick={(e) => (e.target as HTMLInputElement)?.select()}
onChange={(e) => {
const weight = sanitizedNumber(e);
calculatorStore.replaceIngredient(index, {
calcstore.replaceIngredient(index, {
name: ingredient.name,
dosage: weight,
});
}}
endAdornment={<InputAdornment position="end">%</InputAdornment>}
/>
<div className="weight">
{calculatorStore.computeWeight(ingredient.dosage)} grams
{calcstore.computeWeight(ingredient.dosage)} grams
</div>
</div>
</React.Fragment>
))}
<div className="column is-12 has-text-centered">
<AddButton onClick={() => calculatorStore.addIngredient()}>
<AddButton
data-testid="addIngredient"
onClick={() => calcstore.addIngredient()}
>
<AddCircleIcon style={{ marginRight: ".5rem" }} />
Add Other Ingredients
</AddButton>
Expand Down
Loading

0 comments on commit 6c36913

Please sign in to comment.