Skip to content

Commit

Permalink
Add 'dataFactoryFor' function to help generate mock data (#428)
Browse files Browse the repository at this point in the history
## Summary:
This PR extracts 'getCreateMockData' from https://github.com/Khan/webapp/pull/8976 so that we can use it other repo than just 'webapp'.  This PR also:
- renames this function to 'dataFactoryFor'
- updates the examples in the documentation so that they show valid usage
- fixes a bug in the code that could've resulting in mutation of the partial object being passed to the data factory

Issue: None

## Test plan:
- yarn test

Author: kevinbarabash

Reviewers: kevinbarabash, somewhatabstract, jeresig

Required Reviewers:

Approved By: jeresig

Checks: ✅ codecov/project, ✅ Test (macOS-latest, 16.x), ✅ CodeQL, ✅ Lint, flow, and coverage check (ubuntu-latest, 16.x), ✅ Prime node_modules cache for primary configuration (ubuntu-latest, 16.x), ✅ gerald, ✅ Analyze (javascript), ⏭  dependabot

Pull Request URL: #428
  • Loading branch information
kevinbarabash authored Oct 13, 2022
1 parent d9ac970 commit 792686a
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/sharp-houses-sip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/wonder-stuff-testing": minor
---

Add 'dataFactoryFor' function to help generate mock data
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// @flow
import {dataFactoryFor} from "../data-factory-for.js";

describe("dataFactoryFor", () => {
describe("returns a function that", () => {
it("should return a clone of the default data", () => {
const BASE_OBJECT = {x: 5, y: 10};

const dataFactory = dataFactoryFor(BASE_OBJECT);

const data = dataFactory();
expect(data).toEqual(BASE_OBJECT);
expect(data).not.toBe(BASE_OBJECT);
});

it("should merge object passed to factory with the base object", () => {
const BASE_OBJECT = {x: 5, y: 10};

const dataFactory = dataFactoryFor(BASE_OBJECT);

const data = dataFactory({x: 100});
expect(data).toEqual({
x: 100,
y: 10,
});
});

it("should return a copy of the merged data", () => {
const BASE_OBJECT = {
p: {x: 5, y: 10},
q: {x: 0, y: 1},
};

const dataFactory = dataFactoryFor(BASE_OBJECT);

const p = {x: 20, y: 30};
const data = dataFactory({p});
data.p.x = 100;

expect(p).toEqual({x: 20, y: 30});
});
});
});
58 changes: 58 additions & 0 deletions packages/wonder-stuff-testing/src/data-factory-for.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// @flow
import {clone} from "@khanacademy/wonder-stuff-core";

/**
* dataFactoryFor(defaultObject)
*
* Returns a new factory function that returns can be called to obtain
* a copy of `defaultObject`. Optionally, the factory function can be
* passed a `partialObject` in which case it will return a copy of the
* merged object.
*
* Any properties appearing in `partialObject` must be complete
* objects. If you want to update a deeply nested property by
* itself, you can do so by directly modifying the object. This is
* safe because
*
* This
* can still be a bit awkward since there may be a number of optionals
* that you have to check before setting the value.
*
* Example (shallow override):
* const BASE_OBJECT = {
* student: { ... },
* teacher: { ... },
* };
* const dataFactory = dataFactoryFor(BASE_OBJECT);
* const data = dataFactory({
* student: {
* __typename: "User",
* id: "new_kaid",
* kaid: "new_kaid",
* ... other properties on `user`
* }
* });
*
* Example (deep update):
* const BASE_OBJECT = {
* student: { ... },
* teacher: { ... },
* };
* const dataFactory = dataFactoryFor(BASE_OBJECT);
* const data = dataFactory();
* if (data.user) {
* data.user.kaid = "new_kaid";
* data.user.id = "new_kaid";
* }
*/
export const dataFactoryFor =
<T>(baseObject: T): ((partialObject?: $Partial<T>) => T) =>
<T>(
// $FlowIgnore[incompatible-type]: Flow thinks that {} can't be assigned to Partial<T>
partialObject: $Partial<T> = Object.freeze({}),
): T => {
// NOTE: we clone the result to prevent tests from modifying
// either `defaultObject` or `partialObject` when performing
// deep updates on the return object returned by the factory.
return clone({...baseObject, ...partialObject});
};
1 change: 1 addition & 0 deletions packages/wonder-stuff-testing/src/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// @flow
export * as jest from "./jest/index.js";
export {dataFactoryFor} from "./data-factory-for.js";

0 comments on commit 792686a

Please sign in to comment.